// mons.h
#ifndef __mons_h__
#define __mons_h__

#ifndef __tags_h__
#include "tags.h"
#endif

#ifndef __BYTE_SWAPPING_H__
#include "byte_swapping.h"
#endif

#ifndef __ttageditform_h__
#include "TTagEditForm.h"
#endif

#ifndef __myth_defs_h__
#include "myth_defs.h"
#endif

#include "mesh.h"

/* ---------- constants */

enum
{
	MONSTER_DEFINITION_GROUP_TAG= 0x6d6f6e73, // 'mons' (looks like text)
	MONSTER_DEFINITION_VERSION_NUMBER= 1,
	
	MAXIMUM_MONSTER_DEFINITIONS_PER_MAP= 32
};

/* ---------- monster definition */

enum // constants
{
	MAXIMUM_NUMBER_OF_ATTACKS_PER_MONSTER= 4,

	_size_small= 0,
	_size_man_sized,
	_size_giant,
	NUMBER_OF_SIZE_VALUES,
	
	_visibility_nearsighted= 0,
	_visibility_farsighted,
	NUMBER_OF_VISIBILITY_TYPES,

	_monster_allegiance_light= 0,
	_monster_allegiance_dark,
	NUMBER_OF_MONSTER_ALLEGIANCES,

	_monster_class_melee= 0,
	_monster_class_missile,
	_monster_class_suicide,
	_monster_class_special,
	_monster_class_harmless,
	_monster_class_ambient_life,
	_monster_class_invisible_observer,
	NUMBER_OF_MONSTER_CLASSES
};

enum // monster sounds
{
	_monster_sound_attack_order,
	_monster_sound_multiple_attack_order,
	_monster_sound_unused1, //_monster_sound_attack_order_vs_undead,
	
	_monster_sound_move_order,
	_monster_sound_multiple_move_order,
	
	_monster_sound_selection,
	_monster_sound_multiple_selection,
	
	_monster_sound_hit_friendly_unit,
	_monster_sound_hit_by_friendly_unit,
	_monster_sound_attack_obstructed_by_friendly_unit,
	
	_monster_sound_unused2, //_monster_sound_attack_enemy_unit,
	_monster_sound_attack_enemy_with_friendly_units_nearby,

	_monster_sound_unused3, //_monster_sound_sprayed_by_gore,
	_monster_sound_caused_enemy_death,
	_monster_sound_caused_friendly_death,
	_monster_sound_caused_death_of_enemy_undead,
//	_monster_sound_caused_multiple_enemy_deaths,
	
	NUMBER_OF_MONSTER_DEFINITION_SOUNDS,
	MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SOUNDS= 10
};

enum // monster sequences (old-skool)
{
	_monster_sequence_idle,
	_monster_sequence_moving,
	_monster_sequence_placeholder,	
	_monster_sequence_pausing_for_obstacle, //_monster_sequence_contrail,
	_monster_sequence_turning, //_monster_sequence_dead,
	_monster_sequence_blocking,
	_monster_sequence_taking_damage,
	_monster_sequence_picking_up_object,
	_monster_sequence_head_shots,
	_monster_sequence_celebration,
	_monster_sequence_transition_to_secondary_idle,
	_monster_sequence_secondary_idle,
	_monster_sequence_transition_to_primary_idle,
	_monster_sequence_running,
	_monster_sequence_ammunition_icon,
	_monster_sequence_holding_for_attack,
	_monster_sequence_taunting,
	_monster_sequence_gliding,
	NUMBER_OF_MONSTER_DEFINITION_SEQUENCES, // <=MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SEQUENCES

	PRELOADED_MONSTER_SEQUENCES=
		FLAG(_monster_sequence_idle) | 
		FLAG(_monster_sequence_moving)|
		FLAG(_monster_sequence_secondary_idle) |
		FLAG(_monster_sequence_transition_to_secondary_idle)|
//		FLAG(_monster_sequence_pausing_for_obstacle) |
//		FLAG(_monster_sequence_holding_for_attack) |
		FLAG(_monster_sequence_turning),
	
	MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SEQUENCES= 32
};


enum // monster animation states (for m3 skeletal stuff)
{
	_monster_animstate_idle,
	_monster_animstate_alert,
	_monster_animstate_gesture,
	_monster_animstate_moving,
	_monster_animstate_running,
	_monster_animstate_turn_left,
	_monster_animstate_turn_right,
	_monster_animstate_pausing_for_obstacle,
	_monster_animstate_holding_for_attack,
	_monster_animstate_blocking,
	_monster_animstate_hit_soft_front,
	_monster_animstate_hit_soft_back,
	_monster_animstate_hit_hard_front,
	_monster_animstate_hit_hard_back,
	_monster_animstate_die_soft_front,
	_monster_animstate_die_soft_back,
	_monster_animstate_die_hard_front,
	_monster_animstate_die_hard_back,
	_monster_animstate_die_explosion,
	_monster_animstate_picking_up_object,
	_monster_animstate_setting_down_object,
	_monster_animstate_taunting,
	_monster_animstate_celebration,
	_monster_animstate_being_healed,
	_monster_animstate_enter_map,
	_monster_animstate_exit_map,
	_monster_animstate_aux1,
	_monster_animstate_aux2,
	NUMBER_OF_MONSTER_DEFINITION_ANIMATION_STATES,
	
	MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_ANIMATION_STATES = MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SEQUENCES
};

enum // monster attack flags
{
	_monster_attack_is_indirect_bit, // for unpowered projectiles uses angles >=45 degrees
	_monster_attack_does_not_require_solution_bit, // monster does not need targeting solution to attack
	_monster_attack_aimed_at_targets_feet_bit, // otherwise aimed at target centerpoint
	_monster_attack_leads_target_bit,

	_monster_attack_uses_ammunition_bit,
	_monster_attack_uses_carried_projectile_bit, // .projectile_tag is NONE
	_monster_attack_is_reflexive_bit, // damages the attacker
	_monster_attack_is_special_ability_bit,

	_monster_attack_cannot_be_aborted_bit,
	_monster_attack_is_primary_bit,
	_monster_attack_avoids_friendly_units_bit,
	
	_monster_attack_vs_giant_sized_bit,
	_monster_attack_prohibited_vs_giant_sized_bit,
	
	_monster_attack_is_fixed_pitch_bit,
	_monster_attack_dont_try_to_shoot_over_nearby_units_bit,
	_monster_attack_lob_to_hit_lower_nearby_units_bit,
	
	NUMBER_OF_MONSTER_ATTACK_DEFINITION_FLAGS, // <=16

	_monster_attack_is_indirect_flag= FLAG(_monster_attack_is_indirect_bit),
	_monster_attack_does_not_require_solution_flag= FLAG(_monster_attack_does_not_require_solution_bit),
	_monster_attack_aimed_at_targets_feet_flag= FLAG(_monster_attack_aimed_at_targets_feet_bit),
	_monster_attack_leads_target_flag= FLAG(_monster_attack_leads_target_bit),
	_monster_attack_uses_ammunition_flag= FLAG(_monster_attack_uses_ammunition_bit),
	_monster_attack_uses_carried_projectile_flag= FLAG(_monster_attack_uses_carried_projectile_bit),
	_monster_attack_is_reflexive_flag= FLAG(_monster_attack_is_reflexive_bit),
	_monster_attack_is_special_ability_flag= FLAG(_monster_attack_is_special_ability_bit),
	_monster_attack_cannot_be_aborted_flag= FLAG(_monster_attack_cannot_be_aborted_bit),
	_monster_attack_is_primary_flag= FLAG(_monster_attack_is_primary_bit),
	_monster_attack_avoids_friendly_units_flag= FLAG(_monster_attack_avoids_friendly_units_bit),
	_monster_attack_vs_giant_sized_flag= FLAG(_monster_attack_vs_giant_sized_bit),
	_monster_attack_prohibited_vs_giant_sized_flag= FLAG(_monster_attack_prohibited_vs_giant_sized_bit),
	_monster_attack_is_fixed_pitch_flag= FLAG(_monster_attack_is_fixed_pitch_bit),
	_monster_attack_dont_try_to_shoot_over_nearby_units_flag= FLAG(_monster_attack_dont_try_to_shoot_over_nearby_units_bit),
	_monster_attack_lob_to_hit_lower_nearby_units_flag= FLAG(_monster_attack_lob_to_hit_lower_nearby_units_bit),
	
	MAXIMUM_NUMBER_OF_ATTACK_SEQUENCES= 4
};

enum // monster attack extra flags
{
	_monster_attack_can_be_used_against_friendlies_extra_bit,
	_monster_attack_vs_small_sized_extra_bit,
	_monster_attack_prohibited_vs_small_sized_extra_bit,
	
	NUMBER_OF_MONSTER_ATTACK_DEFINITION_EXTRA_FLAGS, // <=16

	_monster_attack_can_be_used_against_friendlies_extra_flag= FLAG(_monster_attack_can_be_used_against_friendlies_extra_bit),
	_monster_attack_vs_small_sized_extra_flag= FLAG(_monster_attack_vs_small_sized_extra_bit),
	_monster_attack_prohibited_vs_small_sized_extra_flag= FLAG(_monster_attack_prohibited_vs_small_sized_extra_bit)
};

enum {
	_sequence_normal_bit, // may be used for "normal" (non-declinated, non-elevated) attacks
	_sequence_declinated_bit, // may be used for declinated (downward) attacks
	_sequence_elevated_bit, // may be used for elevated (upward) attacks	
	NUMBER_OF_MONSTER_ATTACK_SEQUENCE_FLAGS,

	_sequence_normal_flag= FLAG(_sequence_normal_bit),
	_sequence_declinated_flag= FLAG(_sequence_declinated_bit),
	_sequence_elevated_flag= FLAG(_sequence_elevated_bit)
};

struct monster_attack_sequence
{
	word flags;

	short sequence_index;
	fixed_fraction skip_fraction;

	short unused;
};

struct monster_attack_skelanim
{
	byte state_index;
};

#define SIZEOF_STRUCT_MONSTER_ATTACK_DEFINITION 64
struct monster_attack_definition
{	
	word flags;

	fixed_fraction miss_fraction;
	
	file_tag projectile_tag;
	
	short_world_distance minimum_range, maximum_range;
	
	union {
		struct monster_attack_sequence sequences[MAXIMUM_NUMBER_OF_ATTACK_SEQUENCES];
		struct monster_attack_skelanim skelanim;
	};

	short repetitions;

	short_world_distance initial_velocity_lower_bound, initial_velocity_delta;
	short_world_distance initial_velocity_error; // applied randomly in x, y, z
	
	short recovery_time;	
	short recovery_time_experience_delta;
	
	short_world_distance velocity_improvement_with_experience;
	short_fixed mana_cost;

	word extra_flags;

	// computed during postprocessing
	
	short projectile_type;
};

enum // monster flags
{
	_monster_translates_continuously_bit, // otherwise only on frame changes
	_monster_holds_with_clear_shot_bit, // why move when we can sit here and give it out
	_monster_floats_bit, // does not go under media, but stays above it
	_monster_flies_bit,
	
	_monster_allows_projectiles_to_pass_through_bit,
	_monster_experience_proportional_to_damage_bit,
	_monster_is_anti_missile_unit_bit,
	_monster_is_anti_missile_target_bit,
	
	_monster_turns_to_stone_when_killed_bit,
	_monster_concentrates_on_single_attacker_bit,
	_monster_is_undead_bit,
	_monster_cannot_be_autotargeted_bit,
	
	_monster_is_giant_sized_bit,
	_monster_does_not_respect_visibility_bit, // visible from anywhere on the map
	_monster_is_not_solid_bit,
	_monster_leaves_contrail_bit,
	
	_monster_invisible_on_overhead_map_bit,
	_monster_cannot_be_healed_bit,
	_monster_does_not_drop_ammo_when_dying_bit,
	_monster_is_inanimate_object_bit,
	
	_monster_is_skittish_bit,
	_monster_has_3d_model_bit,
	_monster_uses_small_radius_with_allies_bit,
	_monster_aligns_to_mesh_bit,
	
	_monster_immune_to_tain_bit,
	
	NUMBER_OF_MONSTER_DEFINITION_FLAGS, // <=32

	_monster_translates_continuously_flag= FLAG(_monster_translates_continuously_bit),
	_monster_holds_with_clear_shot_flag= FLAG(_monster_holds_with_clear_shot_bit),
	_monster_floats_flag= FLAG(_monster_floats_bit),
	_monster_flies_flag= FLAG(_monster_flies_bit),
	_monster_allows_projectiles_to_pass_through_flag= FLAG(_monster_allows_projectiles_to_pass_through_bit),
	_monster_experience_proportional_to_damage_flag= FLAG(_monster_experience_proportional_to_damage_bit),
	_monster_is_anti_missile_unit_flag= FLAG(_monster_is_anti_missile_unit_bit),
	_monster_is_anti_missile_target_flag= FLAG(_monster_is_anti_missile_target_bit),
	_monster_turns_to_stone_when_killed_flag= FLAG(_monster_turns_to_stone_when_killed_bit),
	_monster_concentrates_on_single_attacker_flag= FLAG(_monster_concentrates_on_single_attacker_bit),
	_monster_is_undead_flag= FLAG(_monster_is_undead_bit),
	_monster_cannot_be_autotargeted_flag= FLAG(_monster_cannot_be_autotargeted_bit),
	_monster_is_giant_sized_flag= FLAG(_monster_is_giant_sized_bit),
	_monster_does_not_respect_visibility_flag= FLAG(_monster_does_not_respect_visibility_bit),
	_monster_is_not_solid_flag= FLAG(_monster_is_not_solid_bit),
	_monster_leaves_contrail_flag= FLAG(_monster_leaves_contrail_bit),
	_monster_invisible_on_overhead_map_flag= FLAG(_monster_invisible_on_overhead_map_bit),
	_monster_cannot_be_healed_flag= FLAG(_monster_cannot_be_healed_bit),
	_monster_does_not_drop_ammo_when_dying_flag= FLAG(_monster_does_not_drop_ammo_when_dying_bit),
	_monster_is_inanimate_object_flag= FLAG(_monster_is_inanimate_object_bit),
	_monster_is_skittish_flag= FLAG(_monster_is_skittish_bit),
	_monster_has_3d_model_flag = FLAG(_monster_has_3d_model_bit),
	_monster_uses_small_radius_with_allies_flag = FLAG(_monster_uses_small_radius_with_allies_bit),
	_monster_aligns_to_mesh_flag = FLAG(_monster_aligns_to_mesh_bit),
	_monster_immune_to_tain_flag = FLAG(_monster_immune_to_tain_bit)
};

#define SIZEOF_STRUCT_MONSTER_DEFINITION 1024
struct monster_definition
{
	unsigned long flags;
	
	union {
		file_tag collection_tag;
		file_tag skelmodel_tag;
	};
	
	union {
		short sequence_indexes[MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SEQUENCES];
		short animation_states[MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_ANIMATION_STATES];
	};

	char terrain_costs[MAXIMUM_NUMBER_OF_TERRAIN_TYPES];
	word terrain_impassability_flags;
	short_world_distance pathfinding_radius;

	short_fixed_fraction movement_modifiers[MAXIMUM_NUMBER_OF_TERRAIN_TYPES];
	
	fixed_fraction absorbed_fraction;
	short_world_distance warning_distance; // used to awake nearby friends to new target
	short_world_distance critical_distance; // used for fight vs. flight
	short_fixed healing_fraction; // amount we can be healed, zero kills us
	short initial_ammunition_lower_bound, initial_ammunition_delta;
	short_world_distance activation_distance; // range of "sight and hearing" for automatic attack vs. retreat
	short_world_distance unused;
	angle turning_speed; // not a function of terrain
	short_world_distance base_movement_speed;

	fixed_fraction left_handed_fraction; // the fraction of this type that is left-handed
	short size;

	file_tag object_tag;

	short number_of_attacks;
	short desired_projectile_volume;

	struct monster_attack_definition attacks[MAXIMUM_NUMBER_OF_ATTACKS_PER_MONSTER];

	file_tag map_action_tag; // for ambient life

	short attack_frequency_lower_bound, attack_frequency_delta;

	file_tag exploding_projectile_group_tag;

	short unused4;
	short maximum_ammunition_count;

	fixed_fraction hard_death_system_shock, flinch_system_shock;
	
	file_tag melee_impact_projectile_group_tag;
	file_tag dying_projectile_group_tag;

	file_tag spelling_string_list_tag; // sigular and plural spelling
	file_tag names_string_list_tag; // common names for this monster
	file_tag flavor_string_list_tag; // flavor texts for this monster

	short unused3;
	
	short monster_class;
	short monster_allegiance;
	short experience_point_value;

	file_tag sound_tags[MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SOUNDS];

	file_tag blocked_impact_projectile_group_tag;
	file_tag absorbed_impact_projectile_group_tag;

	file_tag ammunition_projectile_tag;

	short visibility_type;
	
	short combined_power;
	short_world_distance longest_range;

	short cost;

	char sound_types[MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SOUNDS];
	word pad3;
	
	file_tag entrance_projectile_group_tag;
	file_tag local_projectile_group_tag;
	file_tag special_ability_string_list_tag;
	file_tag exit_projectile_group_tag;
	
	short_fixed maximum_mana;
	short_fixed mana_recharge_rate;

	fixed_fraction berserk_system_shock;
	fixed_fraction berserk_vitality;
	
	file_tag portrait_collection_tag;
	
	short kills_for_maximum_experience_bonus;
	short experience_bonus_size;
	short_world_distance experience_bonus_radius;
	fixed_fraction blocking_fraction;
	file_tag carrying_tag;
	
 	short unused2[204];

	// computed during postprocessing
	short carrying_collection_index;
	
	short portrait_collection_index;
	
	short next_name_string_index;
	
	short ammunition_projectile_type;

	short sound_indexes[MAXIMUM_NUMBER_OF_MONSTER_DEFINITION_SOUNDS];

	short spelling_string_list_index; // sigular and plural spelling
	short names_string_list_index; // common names for this monster
	short flavor_string_list_index; // flavor texts for this monster
	short special_ability_string_list_index;

	short exploding_projectile_group_type;
	short melee_impact_projectile_group_type;
	short dying_projectile_group_type;
	short blocked_impact_projectile_group_type;
	short absorbed_impact_projectile_group_type;
	short entrance_projectile_group_type, exit_projectile_group_type;
	short local_projectile_group_type;
	
	short skelmodel_index; // from skelmodel_tag
	short collection_index; // from collection_tag
	short object_type; // from object_tag
};



// =========================================================================================

bool read_monster_definition( monster_definition* def, tag id );
bool save_monster_definition( monster_definition* def, tag id );

bool read_monster_definition( monster_definition* def, tag_entry* e );
bool save_monster_definition( monster_definition* def, tag_entry* e );

class TmonsEditForm: public TTagEditForm {
	public:
							TmonsEditForm( struct tag_entry *e );
				
		DECLAREDISPATCH
		virtual long		DoControlClick( long arg, void *ptr );
		virtual long		DoListSelect( int arg, void * );
		
		virtual void		CommitToTag();
		virtual void		ReloadTag();
		virtual bool		NeedCommit();
		virtual void		DoFormInitialize();
		virtual void		EditAttack( int attack_index );
		virtual void		RebuildAttackList();
		
	protected:
		void				SetValues();
		void				GetValues();
		monster_definition	def;
};


#endif