/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OUNIT.H
//Description : Header file of Object Unit
#ifndef __OUNIT_H
#define __OUNIT_H
#ifndef __OSPRITE_H
#include
#endif
#ifndef __OSPATH_H
#include
#endif
//#ifndef __OSPATHS2_H
//#include
//#endif
#ifndef __OUNITRES_H
#include
#endif
#ifndef __OBUTTON_H
#include
#endif
#ifndef __OSKILL_H
#include
#endif
#ifndef __OSPREUSE_H
#include
#endif
#ifdef NO_DEBUG_UNIT
#undef DEBUG
#endif
#define GAME_FRAMES_PER_DAY 10
//-------- action code for action_mode ---------//
enum { ACTION_STOP,
ACTION_ATTACK_UNIT,
ACTION_ATTACK_FIRM,
ACTION_ATTACK_TOWN,
ACTION_ATTACK_WALL,
ACTION_ASSIGN_TO_FIRM,
ACTION_ASSIGN_TO_TOWN,
ACTION_ASSIGN_TO_VEHICLE,
ACTION_ASSIGN_TO_SHIP,
ACTION_SHIP_TO_BEACH, // used for UNIT_SEA only
ACTION_BUILD_FIRM,
ACTION_SETTLE,
ACTION_BURN,
ACTION_DIE,
ACTION_MOVE,
ACTION_GO_CAST_POWER, // for god only
//------------ used only for action_mode2 -----------------//
//------- put the following nine parameters together -------//
ACTION_AUTO_DEFENSE_ATTACK_TARGET, // move to target for attacking
ACTION_AUTO_DEFENSE_DETECT_TARGET, // is idle, detect target to attack or waiting for defense action, (detect range is larger as usual)
ACTION_AUTO_DEFENSE_BACK_CAMP, // go back to camp for training or ready for next defense action
ACTION_DEFEND_TOWN_ATTACK_TARGET,
ACTION_DEFEND_TOWN_DETECT_TARGET,
ACTION_DEFEND_TOWN_BACK_TOWN,
ACTION_MONSTER_DEFEND_ATTACK_TARGET,
ACTION_MONSTER_DEFEND_DETECT_TARGET,
ACTION_MONSTER_DEFEND_BACK_FIRM,
};
//-------- define action type for action_misc ----------//
enum { ACTION_MISC_STOP = 0,
ACTION_MISC_CAPTURE_TOWN_RECNO,
ACTION_MISC_DEFENSE_CAMP_RECNO,
ACTION_MISC_DEFEND_TOWN_RECNO,
ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO,
ACTION_MISC_PRE_SEARCH_NODE_USED_UP,
};
//--------- unit mode ------------//
enum { UNIT_MODE_OVERSEE=1, // unit_mode_para is the recno of the firm the unit is overseeing
UNIT_MODE_DEFEND_TOWN, // unit_mode_para is the recno of the town the unit is defending
UNIT_MODE_CONSTRUCT, // unit_mode_para is the recno of the firm the unit is constructing
UNIT_MODE_REBEL, // unit_mode_para is the recno of the rebel group the unit belongs to
UNIT_MODE_MONSTER, // unit_mode_para is the recno of the firm recno of the monster firm it belongs to
UNIT_MODE_ON_SHIP, // unit_mode_para is the recno of the ship unit this unit is on
UNIT_MODE_IN_HARBOR, // for ships only, unit_mode_para is the recno of the harbor this marine unit is in
UNIT_MODE_UNDER_TRAINING,
};
//-------------- unit rank -------------//
enum { MAX_RANK=3 };
enum { RANK_SOLDIER,
RANK_GENERAL,
RANK_KING,
};
//------------- unit salary -----------//
enum { SOLDIER_YEAR_SALARY = 10,
GENERAL_YEAR_SALARY = 50,
SPY_YEAR_SALARY = 100 };
//------- other constant ----------//
enum { EFFECTIVE_LEADING_DISTANCE = 10 };
enum { ATTACK_DIR = 8 }; // define number of attacking direction
enum { MAX_TEAM_MEMBER = 9 }; // maximum no. of units a general/king can lead
enum { MAX_NATION_CONTRIBUTION = 10000 }; // there is an upper limit nation_contribution as it is a
//---------- used in set_move_to_surround -----------//
enum { BUILDING_TYPE_FIRM_MOVE_TO, // firm already exists
BUILDING_TYPE_FIRM_BUILD, // no firm there
BUILDING_TYPE_TOWN_MOVE_TO, // town already exists
BUILDING_TYPE_SETTLE, // no town there
BUILDING_TYPE_VEHICLE, // location is blocked by the vehicle
BUILDING_TYPE_WALL, // location is occupied by the wall
};
//------------ define help mode ----------//
enum { HELP_NOTHING =0,
HELP_ATTACK_UNIT,
HELP_ATTACK_FIRM,
HELP_ATTACK_TOWN,
HELP_ATTACK_WALL,
};
//---------- misc constant parameters ----------//
enum { KEEP_PRESERVE_ACTION = 1, // used for stop2() to keep preserve action
KEEP_DEFENSE_MODE = 2, // used for stop2() to keep the defense mode
KEEP_DEFEND_TOWN_MODE = 3, // used for stop2() to keep the defend town mode
MAX_WAITING_TERM_SAME = 3, // wait for same nation, used in handle_blocked...()
MAX_WAITING_TERM_DIFF = 3, // wait for diff. nation, used in handle_blocked...()
ATTACK_DETECT_DISTANCE = 6,// the distance for the unit to detect target while idle
ATTACK_SEARCH_TRIES = 250, // the node no. used to process searching when target is close to this unit
ATTACK_WAITING_TERM = 10, // terms no. to wait before calling searching to attack target
//MAX_SEARCH_OR_STOP_WAIT_TERM = 15, // note: should be the largetest default value in waiting_term
AUTO_DEFENSE_STAY_OUTSIDE_COUNT = 4, //4 days
AUTO_DEFENSE_DETECT_COUNT = 3 + GAME_FRAMES_PER_DAY*AUTO_DEFENSE_STAY_OUTSIDE_COUNT,
EFFECTIVE_AUTO_DEFENSE_DISTANCE = 9,
AUTO_DEFENSE_SEARCH_TRIES = 100,
UNIT_DEFEND_TOWN_DISTANCE = 8,
UNIT_DEFEND_TOWN_STAY_OUTSIDE_COUNT = 4, // 4 days
UNIT_DEFEND_TOWN_DETECT_COUNT = 3 + GAME_FRAMES_PER_DAY*UNIT_DEFEND_TOWN_STAY_OUTSIDE_COUNT,
UNIT_DEFEND_TOWN_WAITING_TERM = 4,
EFFECTIVE_DEFEND_TOWN_DISTANCE = 9,
MONSTER_DEFEND_FIRM_DISTANCE = 8,
MONSTER_DEFEND_STAY_OUTSIDE_COUNT = 4, // 4 days
MONSTER_DEFEND_DETECT_COUNT = 3 + GAME_FRAMES_PER_DAY*MONSTER_DEFEND_STAY_OUTSIDE_COUNT,
EFFECTIVE_MONSTER_DEFEND_FIRM_DISTANCE = 9,
DO_CAST_POWER_RANGE = 3, // for god to cast power
};
//----------- Define TeamInfo -------------//
#pragma pack(1)
struct TeamInfo
{
TeamInfo();
char member_count;
short member_unit_array[MAX_TEAM_MEMBER];
int ai_last_request_defense_date;
};
#pragma pack()
//----------- Define class Unit -----------//
#pragma pack(1)
class Unit : public Sprite
{
public:
char unit_id;
char rank_id;
char race_id;
char nation_recno;
char ai_unit;
WORD name_id; // id. of the unit's name in RaceRes::first_name_array;
DWORD unit_group_id; // the group id this unit belong to if it is selected
DWORD team_id; // id. of defined team
char selected_flag; // whether the unit has been selected or not
char group_select_id; // id for group selection
char waiting_term; // for 2x2 unit only, the term to wait before recalling A* to get a new path
char blocked_by_member;
char swapping;
short leader_unit_recno; // recno of this unit's leader
int is_visible() { return cur_x >= 0; } // whether the unit is visible on the map, it is not invisable if cur_x == -1
virtual char* unit_name(int withTitle=1);
BYTE region_id();
//--------- action vars ------------//
char action_misc;
short action_misc_para;
char action_mode;
short action_para;
short action_x_loc;
short action_y_loc;
char action_mode2; // store the existing action for speeding up the performance if same action is ordered.
short action_para2; // to re-activiate the unit if its cur_action is idle
short action_x_loc2;
short action_y_loc2;
char blocked_edge[4]; // for calling searching in attacking
UCHAR attack_dir;
//------------ attack parameters -----------//
short range_attack_x_loc; // -1 for unable to do range_attack, use to store previous range attack location
short range_attack_y_loc; // -1 for unable to do range_attack, use to store previous range attack location
//------------- for unit movement ---------------//
short move_to_x_loc; // the location the unit should be moving to
short move_to_y_loc;
//---------- game vars -------------//
char loyalty;
char target_loyalty;
float hit_points;
short max_hit_points;
Skill skill;
char unit_mode;
short unit_mode_para; // if unit_mode==UNIT_MODE_REBEL, unit_mode_para is rebel_recno this unit belongs to
short rebel_recno() { return unit_mode==UNIT_MODE_REBEL ? unit_mode_para : 0; }
short spy_recno; // spy parameters
short nation_contribution; // contribution to the nation
short total_reward; // total amount of reward you have given to the unit
int commander_power();
//---- share the use of nation_contribution and total_reward ----//
int get_monster_id() { return nation_contribution; }
void set_monster_id(int monsterId) { nation_contribution = monsterId; }
int get_monster_soldier_id() { return total_reward; }
void set_monster_soldier_id(int monsterSoldierId) { total_reward = monsterSoldierId; }
int get_weapon_version() { return nation_contribution; }
void set_weapon_version(int weaponVersion) { nation_contribution = weaponVersion; }
int unit_power();
//------- attack parameters --------//
AttackInfo* attack_info_array;
char attack_count;
char attack_range;
short cur_power; // power for power attack
short max_power;
//------- path seeking vars --------//
ResultNode* result_node_array;
int result_node_count;
short result_node_recno;
short result_path_dist;
//----------- way points -----------//
enum { WAY_POINT_ADJUST_SIZE = 5};
ResultNode* way_point_array;
short way_point_array_size;
short way_point_count;
//--------- AI parameters ------------//
WORD ai_action_id; // an unique id. for locating the AI action node this unit belongs to in Nation::action_array
char original_action_mode;
short original_action_para;
short original_action_x_loc;
short original_action_y_loc;
short original_target_x_loc; // the original location of the attacking target when the attack() function is called
short original_target_y_loc; // action_x_loc2 & action_y_loc2 will change when the unit move, but these two will not.
short ai_original_target_x_loc; // for AI only
short ai_original_target_y_loc;
char ai_no_suitable_action;
//-------- defense blocking ability flag ----------//
char can_guard_flag; // bit0= standing guard, bit1=moving guard
// copy from sprite_info->can_guard_flag when skill.combat level is high enough
char can_attack_flag; // 1 able to attack, 0 unable to attack no matter what attack_count is
char force_move_flag;
short home_camp_firm_recno;
char aggressive_mode;
char seek_path_fail_count;
char ignore_power_nation;
//------ TeamInfo structure for general and king only ------//
TeamInfo* team_info;
int commanded_soldier_count();
public:
Unit();
virtual ~Unit();
//------- derived functions from Sprite ------//
virtual void init(int unitId, int nationRecno, int rankId=0, int unitLoyalty=0, int startX= -1, int startY= -1);
virtual void deinit();
virtual void init_derived() {;}
void init_sprite(int startXLoc, int startYLoc);
void deinit_sprite(int keepSelected=0);
void init_unit_id(int unitId);
void deinit_unit_id();
void deinit_unit_mode();
void del_team_member(int);
void validate_team();
void draw();
virtual void draw_outlined();
void draw_selected();
void draw_skill_icon();
void set_spy(int spyRecno);
void set_name(WORD newNameId);
void set_mode(char modeId, short modePara=0) { unit_mode=modeId; unit_mode_para=modePara; }
int is_shealth();
int is_civilian();
int is_own();
int is_own_spy();
int is_nation(int nationRecno);
int true_nation_recno(); // the true nation recno of the unit, taking care of the situation where the unit is a spy
virtual int is_ai_all_stop();
int get_cur_loc(short& xLoc, short& yLoc);
virtual void die() {;}
//-------------- AI functions -------------//
virtual void process_ai();
int think_king_action();
int think_general_action();
int think_leader_action();
int think_normal_human_action();
int think_weapon_action();
int think_ship_action();
int think_assign_weapon_to_camp();
int think_build_camp();
int think_reward();
void think_independent_unit();
void think_spy_action();
int think_king_flee();
int think_general_flee();
int think_stop_chase();
void ai_move_to_nearby_town();
int ai_escape_fire();
void ai_leader_being_attacked(int attackerUnitRecno);
int ai_build_camp();
int ai_settle_new_town();
int ai_handle_seek_path_fail();
//------- functions for unit AI mode ---------//
int think_aggressive_action();
int think_change_attack_target();
int think_resume_original_action();
void save_original_action();
void resume_original_action();
void resume_original_attack_action();
void ask_team_help_attack(Unit* attackerUnit);
//------------- processing functions --------------------//
virtual void pre_process();
virtual void process_idle(); // derived function of Sprite
virtual void process_move(); // derived function of Sprite
virtual void process_wait(); // derived function of Sprite
virtual void process_extra_move() {;}// derived function of Sprite, for ship only
virtual int process_die();
virtual void next_day();
void set_next(int nextX, int nextY, int para=0, int blockedChecked=0);
//------------------------------------//
virtual void disp_info(int refreshFlag);
virtual void disp_unit_profile(int dispY1, int refreshFlag);
virtual int detect_unit_profile();
virtual void detect_info();
int should_show_info();
int return_camp();
//----------- parameters reseting functions ------------//
virtual void stop(int preserveAction=0);
void stop2(int preserveAction=0);
void reset_action_para(); // reset action_mode parameters
void reset_action_para2(int keepMode=0); // reset action_mode2 parameters
void reset_action_misc_para();
//--------------- die actions --------------//
int is_unit_dead() { return (hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE); }
//------------ movement action -----------------//
virtual void move_to(int destX, int destY, int preserveAction=0, short searchMode=1, short miscNo=0, short numOfPath=1, short reuseMode=GENERAL_GROUP_MOVEMENT, short pathReuseStatus=0);
void move_to_unit_surround(int destXLoc, int destYLoc, int width, int height, int miscNo=0, int readyDist=0);
void move_to_firm_surround(int destXLoc, int destYLoc, int width, int height, int miscNo=0, int readyDist=0);
void move_to_town_surround(int destXLoc, int destYLoc, int width, int height, int miscNo=0, int readyDist=0);
void move_to_wall_surround(int destXLoc, int destYLoc, int width, int height, int miscNo=0, int readyDist=0);
void enable_force_move();
void disable_force_move();
void select_search_sub_mode(int sx, int sy, int dx, int dy, short nationRecno, short searchMode);
void different_territory_destination(int& destX, int& destY); // calculate new destination for move to location on different territory
//----------------- attack action ----------------//
void attack_unit(int targetXLoc, int targetYLoc, int xOffset=0, int yOffset=0, int resetBlockedEdge=1);
void attack_unit(short targetRecno, int xOffset=0, int yOffset=0, int resetBlockedEdge=1);
void attack_firm(int firmXLoc, int firmYLoc, int xOffset=0, int yOffset=0, int resetBlockedEdge=1);
void attack_town(int townXLoc, int townYLoc, int xOffset=0, int yOffset=0, int resetBlockedEdge=1);
void attack_wall(int wallXLoc, int wallYLoc, int xOffset=0, int yOffset=0, int resetBlockedEdge=1);
void hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage);
void hit_building(Unit* parentUnit, int targetXLoc, int targetYLoc, float attackDamage);
void hit_firm(Unit* parentUnit, int targetXLoc, int targetYLoc, float attackDamage);
void hit_town(Unit* parentUnit, int targetXLoc, int targetYLoc, float attackDamage);
void hit_wall(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage);
int max_attack_range();
void gain_experience();
virtual float actual_damage();
int nation_can_attack(short nationRecno); // can this nation be attacked, no if alliance or etc..
int independent_nation_can_attack(short nationRecno);
void cycle_eqv_attack();
int is_action_attack();
inline int can_attack() { return (can_attack_flag && attack_count); }
//----------------- defense actions ---------------------//
//========== unit's defense mode ==========//
void defense_attack_unit(short targetRecno);
void defense_attack_firm(int targetXLoc, int targetYLoc);
void defense_attack_town(int targetXLoc, int targetYLoc);
void defense_attack_wall(int targetXLoc, int targetYLoc);
void defense_detect_target();
int in_auto_defense_mode();
int in_defend_town_mode();
int in_monster_defend_mode();
void clear_unit_defense_mode();
void clear_town_defend_mode();
void clear_monster_defend_mode();
//---------- embark to ship and other ship functions ---------//
void assign_to_ship(int destX, int destY, short shipRecno, int miscNo=0);
void ship_to_beach(int destX, int destY, int& finalDestX, int& finalDestY); // for ship only
//----------- other main action functions -------------//
void build_firm(int buildXLoc, int buildYLoc, int firmId, char remoteAction);
void burn(int burnXLoc, int burnYLoc, char remoteAction);
void settle(int settleXLoc, int settleYLoc, short curSettleUnitNum=1);
void assign(int buildXLoc, int buildYLoc, short curAssignUnitNum=1);
void go_cast_power(int castXLoc, int castYLoc, char castPowerType, char remoteAction);
void add_way_point(short x, short y);
void reset_way_point_array();
void process_way_point();
//------------------------------------//
void change_nation(int newNationRecno);
void overseer_migrate(int destTownRecno);
int caravan_in_firm() { return cur_x==-2; }
void update_loyalty();
void set_combat_level(int);
void inc_minor_combat_level(int);
void inc_minor_skill_level(int);
void set_rank(int rankId);
virtual int can_resign();
void resign(int remoteAction);
void embark(int vehicleRecno);
void reward(int rewardNationRecno);
void transform();
void group_transform(char remoteAction, short *selectedArray=NULL, short selectedCount=0);
void spy_change_nation(int nationRecno, char remoteAction);
int can_spy_change_nation();
void change_hit_points(float changePoints);
void change_loyalty(int loyaltyChange);
int think_betray();
int betray(int newNationRecno);
int can_stand_guard() { return can_guard_flag & 1;}
int can_move_guard() { return can_guard_flag & 2;}
// #ifdef AMPLUS
int can_attack_guard() { return can_guard_flag & 4;}
// #endif
int firm_can_assign(short firmRecno);
void set_idle();
void set_ready();
void set_move();
void set_wait();
void set_attack();
void set_turn();
void set_ship_extra_move();
void set_die();
int write_file(File* filePtr);
int read_file(File* filePtr);
virtual int write_derived_file(File* filePtr);
virtual int read_derived_file(File* filePtr);
virtual void fix_attack_info(); // set attack_info_array appropriately
//-------------- multiplayer checking codes ---------------//
virtual UCHAR crc8();
virtual void clear_ptr();
private:
//------------------ idle functions -------------------//
int reactivate_idle_action();
int idle_detect_attack(int startLoc=0, int dimensionInput=0, char defenseMode=0); // detect target to attack
int idle_detect_choose_target(char defenseMode);
void idle_detect_helper_attack(short unitRecno);
int idle_detect_unit_checking(short targetRecno);
int idle_detect_firm_checking(short targetRecno);
int idle_detect_town_checking(short targetRecno);
int idle_detect_wall_checking(int targetXLoc, int targetYLoc);
//------------ movement action -----------------//
int search(int destX, int destY, int preserveAction=0, short searchMode=1, short miscNo=0, short numOfPath=1, short reuseMode=GENERAL_GROUP_MOVEMENT, short pathReuseStatus=0);
int searching(int destX, int destY, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus);
int set_move_to_surround(int buildXLoc, int buildYLoc, int width, int height, int buildingType, int miscNo=0, int readyDist=0, short curSettleUnitNum=1);
int edit_path_to_surround(int x1, int y1, int x2, int y2, int readyDist);
void search_or_stop(int destX, int destY, int preserveAction=0, short searchMode=1, short miscNo=0);
void search_or_wait();
//void move_to_surround_s2(int destXLoc, int destYLoc); // for 2x2 unit only
int move_to_range_attack(int targetXLoc, int targetYLoc, short miscNo, short searchMode, short maxRange); // move to target for using range attack
void abort_searching(int reuseSetNext);
void set_search_tries(int tries); // set parameters to limit the nodes used in searching
void reset_search_tries(); // reset parameters for using default nodes in searching
//---------------- handle blocked action ------------------//
void move_to_my_loc(Unit* unitPtr);
void handle_blocked_move(Location* blockedLoc); // used to determine unit size and call other handle_blocked_move.. functions
void handle_blocked_move_s11(Unit* unitPtr);
//void handle_blocked_move_s12(Unit* unitPtr);
//void handle_blocked_move_s21(Unit* unitPtr);
//void handle_blocked_move_s22(Unit* unitPtr);
//int blocked_move_new_handle();
//void set_path_to(int destXLoc, int destYLoc);
void handle_blocked_by_idle_unit(Unit *unitPtr);
int on_my_path(short checkXLoc, short checkYLoc);
void handle_blocked_wait(Unit* unitPtr);
void cycle_wait_shift_recno(Unit* curUnit, Unit* nextUnit);
void opposite_direction_blocked(short vecX, short vecY, short unitPtrVecX, short unitPtrVecY, Unit* unitPtr);
void handle_blocked_attack_unit(Unit *unitPtr, Unit *targetPtr);
void handle_blocked_attack_firm(Unit *unitPtr);
void handle_blocked_attack_town(Unit *unitPtr);
void handle_blocked_attack_wall(Unit *unitPtr);
void handle_blocked_same_target_attack(Unit* unitPtr, Unit* targetPtr);
//====== support functions for process_attack_unit()
void target_move(Unit* targetUnit);
void attack_target(Unit* targetUnit);
int on_way_to_attack(Unit* targetUnit);
int detect_surround_target();
int update_attack_path_dist();
void set_attack_dir(short curX, short curY, short targetX, short targetY);
//====== functions for attacking between UNIT_LAND, UNIT_SEA, UNIT_AIR
int move_try_to_range_attack(Unit* targetUnit);
//void move_to_range_attack(int targetXLoc, int targetYLoc, short miscNo, short searchMode, short maxRange); //---defined above
int can_attack_different_target_type();
int possible_place_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int maxRange);
//====== functions for reactivating idle units and blocked units that are ordered to attack
int space_for_attack(int targetXLoc, int targetYLoc, char targetMobileType, int targetWidth, int targetHeight);
int space_around_target(int squareXLoc, int squareYLoc, int width, int height);
int space_around_target_ver2(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight);
int ship_surr_has_free_land(int targetXLoc, int targetYLoc, UCHAR regionId);
int free_space_for_range_attack(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, int targetMobileType, int maxRange);
void choose_best_attack_mode(int attackDistance, char targetMobileType=UNIT_LAND);
void unit_auto_guarding(Unit *attackUnit);
void set_unreachable_location(int xLoc, int yLoc);
void check_self_surround();
int can_attack_with(int i); // 0 to attack_count-1
int can_attack_with(AttackInfo *attackInfo);
void get_hit_x_y(short *xPtr, short *yPtr);
void add_close_attack_effect();
//----------------- defense actions ---------------------//
//=========== unit's defend mode generalized functions ============//
int in_any_defense_mode();
void general_defend_mode_detect_target(int checkDefendMode=0);
int general_defend_mode_process_attack_target();
//========== unit's defense mode ==========//
void defense_back_camp(int targetXLoc, int targetYLoc);
void process_auto_defense_attack_target();
void process_auto_defense_detect_target();
void process_auto_defense_back_camp();
int defense_follow_target();
//========== town unit's defend mode ==========//
void defend_town_attack_unit(short targetRecno);
void defend_town_detect_target();
void defend_town_back_town(short townRecno);
void process_defend_town_attack_target();
void process_defend_town_detect_target();
void process_defend_town_back_town();
int defend_town_follow_target();
//========== monster unit's defend mode ==========//
void monster_defend_attack_unit(short targetRecno);
void monster_defend_attack_firm(int targetXLoc, int targetYLoc);
void monster_defend_attack_town(int targetXLoc, int targetYLoc);
void monster_defend_attack_wall(int targetXLoc, int targetYLoc);
void monster_defend_detect_target();
void monster_defend_back_firm(int targetXLoc, int targetYLoc);
void process_monster_defend_attack_target();
void process_monster_defend_detect_target();
void process_monster_defend_back_firm();
int monster_defend_follow_target();
//---------- embark to ship and other ship functions ---------//
int ship_to_beach_path_edit(int& resultXLoc, int& resultYLoc, UCHAR regionNo);
void ship_leave_beach(int shipOldXLoc, int shipOldYLoc);
//---------------- other functions -----------------//
int cal_distance(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight); // calculate distance from this unit(can be 1x1, 2x2) to a known size object
int is_in_surrounding(int checkXLoc, int checkYLoc, int width, int targetXLoc, int targetYLoc, int targetWidth, int targetHeight);
int avail_node_enough_for_search(short x1, short y1, short x2, short y2);
// int firm_can_assign(short firmRecno);
protected:
void disp_main_menu(int);
void detect_main_menu();
void disp_build_menu(int);
void detect_build_menu();
void disp_button(int dispY1);
void detect_button();
void disp_build(int);
void detect_build();
void disp_settle(int);
void detect_settle();
void disp_unit_info(int dispY1, int refreshFlag);
void disp_basic_info(int dispY1, int refreshFlag);
int detect_basic_info();
void disp_spy_menu(int dispY1, int refreshFlag);
void detect_spy_menu(int dispY1);
int spy_menu_height();
void disp_hit_point(int dispY1);
void process_attack_unit();
void process_attack_firm();
void process_build_firm();
void process_attack_town();
void process_attack_wall();
void process_assign();
void process_burn();
void process_settle();
void process_assign_to_ship();
void process_ship_to_beach();
void process_rebel();
void process_go_cast_power();
void next_move();
void terminate_move();
void reset_path();
void king_die();
void general_die();
void pay_expense();
void process_recover();
};
#pragma pack()
//--------------------------------------------------------------------------------------------//
//------- Define class UnitArray ---------//
class UnitArray : public SpriteArray
{
public:
short selected_recno;
short selected_count;
DWORD cur_group_id; // for Unit::unit_group_id
DWORD cur_team_id; // for Unit::team_id
short idle_blocked_unit_reset_count; // used to improve performance for searching related to attack
short visible_unit_count;
char mp_first_frame_to_select_caravan; // for multiplayer, true if 1st frame to select caravan
char mp_first_frame_to_select_ship; // ditto for ship
short mp_pre_selected_caravan_recno; // for multiplayer, 0 or recno that caravan selected in previous frame
short mp_pre_selected_ship_recno; // ditto for ship
static short selected_land_unit_count;
static short selected_sea_unit_count;
static short selected_air_unit_count;
static short *selected_land_unit_array;
static short *selected_sea_unit_array;
static short *selected_air_unit_array;
public:
UnitArray(int);
void init();
int add_unit(int unitId, int nationRecno, int rankId=0, int unitLoyalty=0, int startXLoc= -1, int startYLoc= -1);
Unit* create_unit(int unitId);
int unit_class_size(int);
void disappear_in_town(int unitRecno, int townRecno);
void disappear_in_firm(int unitRecno);
void die(int unitRecno);
void return_camp(int remoteAction, short* selectedUnitArray=NULL, int selectedCount=0);
void draw_dot();
void draw_profile();
void process();
void stop(short* selectedUnitArray, int selectedCount, char remoteAction);
void stop_all_war(short oldNationRecno);
void stop_war_between(short nationRecno1, short nationRecno2);
void stop_attack_unit(short unitRecno);
void stop_attack_firm(short firmRecno);
void stop_attack_town(short townRecno);
//---------- move main functions -------------//
void move_to(int destX, int destY, int divided, short* selectedUnitArray, int selectedCount, char remoteAction);
//------------- attack main functions ----------//
// ###### patch begin Gilbert 5/8 ######//
void attack(int destX, int destY, int divided, short* selectedUnitArray, int selectedCount, char remoteAction, int unitRecno);
// ###### patch end Gilbert 5/8 ######//
void attack_unit(int targetXLoc, int targetYLoc, short targetUnitRecno, short* selectedUnitArray, int selectedCount);
void attack_firm(int targetXLoc, int targetYLoc, short firmRecno, short* selectedUnitArray, int selectedCount);
void attack_town(int targetXLoc, int targetYLoc, short townRecno, short* selectedUnitArray, int selectedCount);
void attack_wall(int targetXLoc, int targetYLoc, short* selectedUnitArray, int selectedCount);
//---------- other actions functions -----------//
void assign(int destX, int destY, int divided, char remoteAction, short* selectedUnitArray=NULL, int selectedCount=0);
void assign_to_camp(int destX, int destY, char remoteAction, short* selectedUnitArray=NULL, int selectedCount=0);
void settle(int destX, int destY, int divided, char remoteAction, short *selectedUnitArray=NULL, int selectedCount=0);
// ##### patch begin Gilbert 5/8 ######//
void assign_to_ship(int shipXLoc, int shipYLoc, int divided, short* selectedArray, int selectedCount, char remoteAction, int shipRecno);
// ##### patch end Gilbert 5/8 ######//
void ship_to_beach(int destX, int destY, int divided, short* selectedArray, int selectedCount, char remoteAction);
void add_way_point(int pointX, int pointY, short* selectedArray, int selectedCount, char remoteAction);
//--------- unit filter function ----------//
int divide_attack_by_nation(short nationRecno, short *selectedArray, int selectedCount);
//--------- for multiplayers' caravan and ship ---------//
void mp_mark_selected_caravan();
int mp_get_selected_caravan_count();
void mp_reset_selected_caravan_count();
void mp_add_selected_caravan(short unitRecno);
int mp_is_selected_caravan(short unitRecno);
void mp_mark_selected_ship();
int mp_get_selected_ship_count();
void mp_reset_selected_ship_count();
void mp_add_selected_ship(short unitRecno);
int mp_is_selected_ship(short unitRecno);
void update_selected_trade_unit_info();
int write_file(File* filePtr);
int read_file(File* filePtr);
#ifdef DEBUG
Unit* operator[](int recNo);
#else
Unit* operator[](int recNo) { return (Unit*) get_ptr(recNo); }
#endif
int is_deleted(int recNo);
int is_truly_deleted(int recNo);
private:
void divide_array(int locX, int locY, short* selectedArray, int selectedCount, int excludeSelectedLocUnit=0);
void set_group_id(short* selectedArray, int selectedCount);
//------------ move sub-functions --------------//
void move_to_now_with_filter(int destX, int destY, short* selectedUnitArray, int selectedCount);
void move_to_now(int destX, int destY, short* selectedUnitArray, int selectedCount);
void construct_sorted_array(short* selectedUnitArray, int selectedCount);
void determine_position_to_construct_table(int selectedCount, int destXLoc, int destYLoc, char mobileType);
//-------------- attack sub-functions -----------//
// ###### patch begin Gilbert 5/8 #######//
void attack_call(int destX, int destY, char mobileType, char targetMobileType, int divided, short* selectedUnitArray, int selectedCount, int targetUnitRecno);
// ###### patch end Gilbert 5/8 #######//
void update_unreachable_table(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, char mobileType, int &analyseResult);
char get_target_surround_loc(int targetWidth, int targetHeight);
char* get_target_x_offset(int targetWidth, int targetHeight, char curDir);
char* get_target_y_offset(int targetWidth, int targetHeight, char curDir);
void arrange_units_in_group(int xLoc1, int yLoc1, int xLoc2, int yLoc2, short* selectedUnitArray, int selectedCount, DWORD unitGroupId, int targetType);
int analyse_surround_location(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight, char mobileType);
void check_nearby_location(int targetXLoc, int targetYLoc, char xOffset, char yOffset, int targetWidth, int targetHeight, char targetMobileType, int& analyzeResult);
void handle_attack_target_totally_blocked(int targetXLoc, int targetYLoc, short targetRecno, short *selectedUnitArray, short selectedCount, int targetType);
//---------- other actions functions -----------//
void group_assign(int destX, int destY, short* selectedArray, int selectedCount);
void group_settle(int destX, int destY, short* selectedArray, int selectedCount);
};
extern UnitArray unit_array;
extern int unit_search_node_used;
extern int unit_search_tries; // the number of tries used in the current searching
extern char unit_search_tries_flag; // indicate num of tries is set, reset after searching
#ifdef DEBUG
extern int check_unit_dir1, check_unit_dir2;
#endif
#endif