/*
* 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 : OUNITM.CPP
//Description : Object Unit movement
//Owner : Alex
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef NO_DEBUG_UNIT
#undef err_when
#undef err_here
#undef err_if
#undef err_else
#undef err_now
#define err_when(cond)
#define err_here()
#define err_if(cond)
#define err_else
#define err_now(msg)
#undef DEBUG
#endif
//-*********** simulate aat ************-//
#ifdef DEBUG
#include
#endif
//-*********** simulate aat ************-//
//--- Define no. of pixels per direction move (N, NE, E, SE, S, SW, W, NW) ---//
static short move_x_pixel_array[] = { 0, ZOOM_LOC_WIDTH, ZOOM_LOC_WIDTH, ZOOM_LOC_WIDTH, 0, -ZOOM_LOC_WIDTH, -ZOOM_LOC_WIDTH, -ZOOM_LOC_WIDTH };
static short move_y_pixel_array[] = { -ZOOM_LOC_HEIGHT, -ZOOM_LOC_HEIGHT, 0, ZOOM_LOC_HEIGHT, ZOOM_LOC_HEIGHT, ZOOM_LOC_HEIGHT, 0, -ZOOM_LOC_HEIGHT };
static short cycle_wait_unit_index;
static short *cycle_wait_unit_array;
static short cycle_wait_unit_array_def_size;
static short cycle_wait_unit_array_multipler;
static char move_action_call_flag=0; // avoid calling move_to_my_loc() if this function is called from move_to() chain
//--------- Begin of function Unit::reset_action_para ---------//
// reset action parameters when action is finished or cancelled
// for action_mode
//
void Unit::reset_action_para()
{
action_mode = ACTION_STOP;
action_x_loc = action_y_loc = -1;
action_para = 0;
}
//----------- End of function Unit::reset_action_para -----------//
//--------- Begin of function Unit::reset_action_para2 ---------//
// reset action parameters when action is finished or cancelled
//
// keepMode - use to keep action
//
void Unit::reset_action_para2(int keepMode)
{
if(keepMode!=KEEP_DEFENSE_MODE || !in_any_defense_mode())
{
action_mode2 = ACTION_STOP;
action_para2 = 0;
action_x_loc2 = action_y_loc2 = -1;
}
else
{
switch(unit_mode)
{
case UNIT_MODE_DEFEND_TOWN:
if(action_mode2!=ACTION_AUTO_DEFENSE_DETECT_TARGET)
defend_town_detect_target();
break;
case UNIT_MODE_REBEL:
if(action_mode2!=ACTION_DEFEND_TOWN_DETECT_TARGET)
defense_detect_target();
break;
case UNIT_MODE_MONSTER:
if(action_mode2!=ACTION_MONSTER_DEFEND_DETECT_TARGET)
monster_defend_detect_target();
break;
}
}
}
//----------- End of function Unit::reset_action_para2 -----------//
//--------- Begin of function Unit::reset_action_misc_para ---------//
// reset miscellaneous action parameters
//
void Unit::reset_action_misc_para()
{
action_misc = ACTION_MISC_STOP;
action_misc_para = 0;
}
//----------- End of function Unit::reset_action_misc_para -----------//
//--------- Begin of function Unit::stop ---------//
// stop unit action
//
// [int] preserveAction - preserve the current action or not.
// (default: 0)
//
void Unit::stop(int preserveAction)
{
//------------- reset vars ------------//
if(action_mode2!=ACTION_MOVE)
reset_way_point_array();
reset_path();
err_when(result_node_array!=NULL);
//-------------- keep action or not --------------//
switch(preserveAction)
{
case 0: case KEEP_DEFENSE_MODE:
reset_action_para();
range_attack_x_loc = range_attack_y_loc = -1; // should set here or reset for attack
break;
case KEEP_PRESERVE_ACTION:
break;
/*case 3: err_when(action_mode!=ACTION_ATTACK_UNIT);
go_x = next_x; // combine move_to_attack() into move_to()
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
return;*/
}
waiting_term = 0; // for idle_detect_attack(), oscillate between 0 and 1
err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
err_when(final_dir<0 || final_dir>MAX_SPRITE_DIR_TYPE);
UnitMarine *shipPtr;
//----------------- update parameters ----------------//
switch( cur_action )
{
//----- if the unit is moving right now, ask it to stop as soon as possible -----//
case SPRITE_READY_TO_MOVE:
set_idle();
break;
case SPRITE_TURN:
case SPRITE_WAIT:
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
final_dir = cur_dir;
turn_delay = 0;
set_idle();
break;
case SPRITE_SHIP_EXTRA_MOVE:
shipPtr = (UnitMarine*) this;
switch(shipPtr->extra_move_in_beach)
{
case NO_EXTRA_MOVE:
if(cur_x==next_x && cur_y==next_y)
{
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
set_idle();
return;
}
break;
case EXTRA_MOVING_IN:
if(cur_x==next_x && cur_y==next_y && (cur_x!=go_x || cur_y!=go_y))
{
shipPtr->extra_move_in_beach = NO_EXTRA_MOVE; // not yet move although location is chosed
err_when(next_x_loc()%2 || next_y_loc()%2); // in even location
}
else
err_when(next_x_loc()%2==0 && next_y_loc()%2==0); // in even location
break;
case EXTRA_MOVING_OUT:
if(cur_x==next_x && cur_y==next_y && (cur_x!=go_x || cur_y!=go_y))
{
shipPtr->extra_move_in_beach = EXTRA_MOVE_FINISH; // not yet move although location is chosed
err_when(next_x_loc()%2==0 && next_y_loc()%2==0); // not in even location
}
else
err_when(next_x_loc()%2 || next_y_loc()%2); // in even location
break;
case EXTRA_MOVE_FINISH:
break;
}
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
break;
case SPRITE_MOVE:
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
if(cur_x==next_x && cur_y==next_y)
set_idle();
break;
//--- if its current action is SPRITE_ATTACK, stop immediately ---//
case SPRITE_ATTACK:
set_next(cur_x, cur_y, 0, 1); //********** BUGHERE
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
set_idle();
#ifdef DEBUG
char h, w, blocked=0;
short x, y;
for(h=0, y=next_y_loc(); hloc_height&&!blocked; h++, y++)
{
for(w=0, x=next_x_loc(); wloc_width&&!blocked; w++, x++)
err_when(world.get_unit_recno(x, y, mobile_type) != sprite_recno);
}
#endif
cur_frame = 1;
break;
}
}
//----------- End of function Unit::stop -----------//
//--------- Begin of function Unit::stop2 ---------//
// stop unit action
//
// preserverAction can be
// 0, KEEP_PRESERVE_ACTION, KEEP_DEFENSE_MODE (default 0)
//
void Unit::stop2(int preserveAction)
{
stop(preserveAction);
reset_action_para2(preserveAction);
//----------------------------------------------------------//
// set the original location of the attacking target when
// the attack() function is called, action_x_loc2 & action_y_loc2
// will change when the unit move, but these two will not.
//----------------------------------------------------------//
//##### begin trevor 13/10 #####//
force_move_flag = 0;
ai_no_suitable_action = 0;
if( preserveAction==0 )
{
original_action_mode = 0;
ai_original_target_x_loc = -1;
if( ai_action_id )
nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
}
//##### end trevor 13/10 #####//
}
//----------- End of function Unit::stop2 -----------//
//######## begin trevor 26/4 ###########//
//--------- Begin of function Unit::set_search_tries ---------//
// used to limit the number of nodes in searching
//
// tries - number of nodes used in searhcing
//
void Unit::set_search_tries(int tries)
{
unit_search_tries = tries;
unit_search_tries_flag++;
}
//----------- End of function Unit::set_search_tries -----------//
//--------- Begin of function Unit::reset_search_tries ---------//
// reset the number of node to default value
//
void Unit::reset_search_tries()
{
unit_search_tries = 0; // 0 for reset
unit_search_tries_flag = 0;
}
//----------- End of function Unit::reset_search_tries -----------//
//######## end trevor 26/4 ###########//
//-------- Begin of function Unit::abort_searching --------//
//
// reuseSetNext - condition flag for updating parameters
// of path_reuse
//
void Unit::abort_searching(int reuseSetNext)
{
if(reuseSetNext) // to avoid error in path-reuse
seek_path_reuse.set_next_cur_path_num();
if(unit_search_tries_flag)
reset_search_tries();
}
//-------- End of function Unit::abort_searching ---------//
//--------- Begin of function Unit::enable_force_move ---------//
void Unit::enable_force_move()
{
force_move_flag = 1;
}
//-------- End of function Unit::enable_force_move ---------//
//--------- Begin of function Unit::disable_force_move ---------//
void Unit::disable_force_move()
{
force_move_flag = 0;
}
//-------- End of function Unit::disable_force_move ---------//
//--------- Begin of function Unit::move_to ---------//
// Main function for action_mode = ACTION_MOVE
//
// Order the unit to move to a specific location following the shortest path.
//
// destX - x location of the destination
// destY - y location of the destination
// [int] preserveAction - preserve the current action or not (default: 0)
// [short] searchMode - the search mode used (default: SEARCH_MODE_IN_A_GROUP)
// [short] miscNo - = target record no if search_mode=SEARCH_MODE_TO_ATTACK
// = firm ID if search_mode=SEARCH_MODE_TO_FIRM (default: 0)
// [short] numOfPath - num of path, used in path reuse, (default: 1)
// [short] reuseMode - path reuse mode (default: GENERAL_GROUP_MOVEMENT)
// [short] pathReuseStatus - path reuse status (default: 0)
//
void Unit::move_to(int destX, int destY, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
{
err_when(destX<0 || destX>=MAX_WORLD_X_LOC || destY<0 || destY>=MAX_WORLD_Y_LOC);
if(!seek_path.total_node_avail)
{
//-------- insufficient nodes for searching, return now ----------//
stop(KEEP_PRESERVE_ACTION);
action_mode = action_mode2 = ACTION_MOVE;
action_para = action_para2 = 0;
action_x_loc = action_x_loc2 = destX;
action_y_loc = action_y_loc2 = destY;
return; // for later searching
}
//int useClosestNode = (seek_path.total_node_avail>=MIN_BACKGROUND_NODE_USED_UP);
//---------- reset way point array since new action is assigned --------//
if(way_point_count)
{
ResultNode *nodePtr = way_point_array;
if(nodePtr->node_x!=destX || nodePtr->node_y!=destY)
reset_way_point_array();
}
//----------------------------------------------------------------//
// calculate new destination if trying to move to different territory
//----------------------------------------------------------------//
int curXLoc = next_x_loc();
int curYLoc = next_y_loc();
Location *locPtr = world.get_loc(curXLoc, curYLoc);
Location *destLocPtr = world.get_loc(destX, destY);
int destXLoc = destX;
int destYLoc = destY;
if(locPtr->region_id!=destLocPtr->region_id && mobile_type!=UNIT_AIR) // different territory
different_territory_destination(destXLoc, destYLoc);
//----------------------------------------------------------------//
// for path_reuse initialization
//----------------------------------------------------------------//
if(numOfPath!=1 && pathReuseStatus==REUSE_PATH_INITIAL) // for path-reuse only
{
search(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
return;
}
//----------------------------------------------------------------//
// return if the unit is dead
//----------------------------------------------------------------//
if(is_unit_dead())
{
abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
return;
}
//-----------------------------------------------------------------------------------//
// The codes here is used to check for equal action in movement.
//
// mainly checked by action_mode2. If previous action is ACTION_MOVE, action_mode2,
// action_para2, action_x_loc2 and action_x_loc2 need to be kept for this checking.
//
// If calling from unit_array.move_to(), action_mode is set to ACTION_MOVE, action_para
// is set to 0 while action_x_loc and action_y_loc are kept as original value for checking.
// Meanwhile, action_mode2, action_para2, action_x_loc2 and action_y_loc2 are kept if
// the condition is fulfilled (action_mode2==ACTION_MOVE)
//-----------------------------------------------------------------------------------//
if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
{
//------ previous action is ACTION_MOVE -------//
err_when(action_para2 || action_para);
if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
{
//-------- equal order --------//
action_x_loc = action_x_loc2;
action_y_loc = action_y_loc2;
if(cur_action!=SPRITE_IDLE)
{
//-------- the old order is processing --------//
abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
if(result_node_array==NULL) // cannot move
{
err_when(result_path_dist);
if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
{
if(cur_action!=SPRITE_SHIP_EXTRA_MOVE)
{
err_when(result_node_count || result_node_recno);
if(cur_x!=next_x || cur_y!=next_y)
set_move();
else
set_idle();
}
//else keep extra_moving
}
else
{
err_when(result_node_count || result_node_recno);
if(cur_x!=next_x || cur_y!=next_y)
set_move();
else
set_idle();
}
}
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
return;
}//else action is hold due to some problems, re-activiate again
}
}//else, new order or searching is required
move_action_call_flag++; // set flag to avoid calling move_to_my_loc()
seek_path_reuse.set_status(PATH_WAIT);
err_when(seek_path_reuse.get_reuse_path_status()==REUSE_PATH_INCOMPLETE_SEARCH);
action_mode2 = ACTION_MOVE;
action_para2 = 0;
int enoughNode = search(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
move_action_call_flag = 0; // clear the flag
//----------------------------------------------------------------//
// store new order in action parameters
//----------------------------------------------------------------//
action_mode = ACTION_MOVE;
action_para = 0;
if(!enoughNode || (searchMode==SEARCH_MODE_REUSE && seek_path_reuse.get_reuse_path_status()==REUSE_PATH_INCOMPLETE_SEARCH))
{
action_x_loc = action_x_loc2 = destXLoc;
action_y_loc = action_y_loc2 = destYLoc;
}
else // enough node for search
{
action_x_loc = action_x_loc2 = move_to_x_loc;
action_y_loc = action_y_loc2 = move_to_y_loc;
}
#ifdef DEBUG
if(result_node_array && result_node_count)
{
ResultNode *debugPtr = result_node_array + result_node_count - 1;
err_when(debugPtr->node_x != move_to_x_loc || debugPtr->node_y != move_to_y_loc);
}
else
{
UnitInfo* unitInfo = unit_res[unit_id];
if( unitInfo->unit_class == UNIT_CLASS_SHIP )
{
UnitMarine *shipPtr = (UnitMarine*) this;
if(shipPtr->extra_move_in_beach==NO_EXTRA_MOVE)
err_when(curXLoc!=move_to_x_loc || curYLoc!=move_to_y_loc);
}
else
{
err_when(curXLoc!=move_to_x_loc || curYLoc!=move_to_y_loc);
}
}
#endif
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
err_when(action_mode2==ACTION_MOVE && (action_x_loc2==-1 || action_y_loc2==-1));
}
//----------- End of function Unit::move_to -----------//
//--------- Begin of function Unit::search ---------//
// This function is only used to find the shorest path for
// searching. Action parameters should not be changed in
// this function.
//
// destX - x coordinate of destination
// destY - y coordinate of destination
// preserveAction - used to keep action in calling stop()
// searchMode - search mode being used
// miscNo - see move_to()
// numOfPath - num of path
// reuseMode - path reuse mode being used
// pathReuseStatus - path reuse status
//
// return 1 for normal operation process
// return 0 otherwise or there is not enough node for searching
//
int Unit::search(int destXLoc, int destYLoc, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
{
#ifdef DEBUG
err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
err_when(searchMode==SEARCH_MODE_TO_FIRM && miscNo!=FIRM_HARBOR && mobile_type!=UNIT_AIR &&
world.get_loc(next_x_loc(), next_y_loc())->region_id!=world.get_loc(destXLoc, destYLoc)->region_id);
err_when(hit_points<=0 || action_mode==ACTION_DIE || cur_action==SPRITE_DIE);
#else
if(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC || hit_points<=0 ||
action_mode==ACTION_DIE || cur_action==SPRITE_DIE || searchMode<=0 || searchMode>MAX_SEARCH_MODE_TYPE)
{
stop2(KEEP_DEFENSE_MODE); //-********** BUGHERE, err_handling for retailed version
return 1;
}
#endif
//----------------------------------------------------------------//
// for path_reuse initialization
//----------------------------------------------------------------//
if(numOfPath!=1 && pathReuseStatus==REUSE_PATH_INITIAL) // for path-reuse only
{
seek_path_reuse.seek(next_x_loc(), next_y_loc(), move_to_x_loc, move_to_y_loc, sprite_info->loc_width,
unit_group_id, mobile_type, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
return 1;
}
int result=0;
if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
{
UnitMarine *shipPtr = (UnitMarine*) this;
switch(shipPtr->extra_move_in_beach)
{
case NO_EXTRA_MOVE:
result = searching(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
break;
case EXTRA_MOVING_IN:
err_when(next_x_loc()%2==0 && next_y_loc()%2==0);
if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
seek_path_reuse.set_next_cur_path_num();
return 0;
case EXTRA_MOVING_OUT:
err_when(next_x_loc()%2 || next_y_loc()%2);
if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
seek_path_reuse.set_next_cur_path_num();
return 0;
case EXTRA_MOVE_FINISH:
err_when(next_x_loc()%2==0 && next_y_loc()%2==0);
if(pathReuseStatus==REUSE_PATH_SEARCH || pathReuseStatus==REUSE_PATH_FIRST_SEEK)
seek_path_reuse.set_next_cur_path_num();
ship_leave_beach(next_x_loc(), next_y_loc());
break;
default: err_here();
break;
}
}
else
result = searching(destXLoc, destYLoc, preserveAction, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
if(way_point_count && !result_node_array) // can move no more
reset_way_point_array();
if(!result)
return 0; // not enough node or extra_move_in_beach!=NO_EXTRA_MOVE
else
return 1;
}
//----------- End of function Unit::search -----------//
//--------- Begin of function Unit::select_search_sub_mode ---------//
// select searching sub_mode
//
// sx - start location x
// sy - start location y
// dx - x coordinate of destination
// dy - y coordinate of destination
// nationRecno - nation recno of the unit
// searchMode - search mode being used
//
void Unit::select_search_sub_mode(int sx, int sy, int dx, int dy, short nationRecno, short searchMode)
{
//seek_path.set_sub_mode(); // cancel the selection
//return;
err_when(mobile_type!=UNIT_LAND);
if(!nation_recno || ignore_power_nation)
{
seek_path.set_sub_mode(); // always using normal mode for independent unit
seek_path_reuse.set_sub_mode();
return;
}
//--------------------------------------------------------------------------------//
// Checking for starting location and destination to determine sub_mode used
// N - not hostile, H - hostile
// 1) N -> N, using normal mode
// 2) N -> H, H -> N, H -> H, using sub_mode SEARCH_SUB_MODE_PASSABLE
//--------------------------------------------------------------------------------//
Location *startLocPtr = world.get_loc(sx, sy);
Location *destLocPtr = world.get_loc(dx, dy);
Nation *nationPtr = nation_array[nationRecno];
int subModeOn = 1;
if((startLocPtr->power_nation_recno && !nationPtr->get_relation_passable(startLocPtr->power_nation_recno)) ||
(destLocPtr->power_nation_recno && !nationPtr->get_relation_passable(destLocPtr->power_nation_recno)))
subModeOn = 0;
if(subModeOn) // true only when both start and end locations are passable for this nation
{
seek_path.set_nation_passable(nationPtr->relation_passable_array);
seek_path.set_sub_mode(SEARCH_SUB_MODE_PASSABLE);
}
else
seek_path.set_sub_mode(); //----- normal sub mode, normal searching
//----------- set sub_mode of path-reuse if more than one unit are selected -----------//
if(subModeOn && searchMode==SEARCH_MODE_REUSE)
{
seek_path_reuse.set_nation_passable(nationPtr->relation_passable_array);
seek_path_reuse.set_sub_mode(SEARCH_SUB_MODE_PASSABLE);
}
else
seek_path_reuse.set_sub_mode();
}
//----------- End of function Unit::select_search_sub_mode -----------//
//--------- Begin of function Unit::searching ---------//
int Unit::searching(int destXLoc, int destYLoc, int preserveAction, short searchMode, short miscNo, short numOfPath, short reuseMode, short pathReuseStatus)
{
stop(preserveAction); // stop the unit as soon as possible
int startXLocLoc=next_x_loc(); // next location the sprite is moving towards
int startYLocLoc=next_y_loc();
int totalAvailableNode = seek_path.total_node_avail;
if(!avail_node_enough_for_search(startXLocLoc, startYLocLoc, destXLoc, destYLoc))
{
abort_searching(searchMode==4 && numOfPath>1);
return 0; // not enough node for searching
}
//stop(preserveAction); // stop the unit as soon as possible
//---------------------------------------------------------------------------//
// adjust the destination for unit size
//---------------------------------------------------------------------------//
/*err_when(sprite_info->loc_width!=sprite_info->loc_height);
if(sprite_info->loc_width>1) // not size 1x1
{
destXLoc = move_to_x_loc = MIN(destXLoc, MAX_WORLD_X_LOC-sprite_info->loc_width);
destYLoc = move_to_y_loc = MIN(destYLoc, MAX_WORLD_Y_LOC-sprite_info->loc_height);
}
else
{*/
move_to_x_loc = destXLoc;
move_to_y_loc = destYLoc;
//}
//------------------------------------------------------------//
// fast checking for destination == current location
//------------------------------------------------------------//
//if(startXLocLoc==move_to_x_loc && startYLocLoc==move_to_y_loc) // already here
if(startXLocLoc==destXLoc && startYLocLoc==destYLoc) // already here
{
if(cur_x!=next_x || cur_y!=next_y)
set_move();
else
set_idle();
err_when(move_to_x_loc!=startXLocLoc || move_to_y_loc!=startYLocLoc);
err_when(result_node_array!=NULL);
abort_searching(searchMode==SEARCH_MODE_REUSE && numOfPath>1);
return 1;
}
//------------------------ find the shortest path --------------------------//
//
// Note: seek() will never return PATH_SEEKING as the maxTries==max_node in
// calling seek()
//
// decide the searching to use according to the unit size
// assume the unit size is always 1x1, 2x2, 3x3 and so on
// i.e. sprite_info->loc_width == sprite_info->loc_height
//--------------------------------------------------------------------------//
result_node_recno = result_node_count = 0;
err_when(result_node_array!=NULL);
seek_path.set_nation_recno(nation_recno);
int seekResult;
#ifdef DEBUG
unsigned long seekPathStartTime = misc.get_time();
#endif
/*switch(sprite_info->loc_width)
{
case 1:*/
if(searchMode!=SEARCH_MODE_REUSE || numOfPath==1) // no need to call path_reuse
{
if(mobile_type==UNIT_LAND)
select_search_sub_mode(startXLocLoc, startYLocLoc, destXLoc, destYLoc, nation_recno, searchMode);
seekResult = seek_path.seek(startXLocLoc, startYLocLoc, destXLoc, destYLoc, unit_group_id,
mobile_type, searchMode, miscNo, numOfPath, unit_search_tries);
result_node_array = seek_path.get_result(result_node_count, result_path_dist);
seek_path.set_sub_mode(); // reset sub_mode searching
}
else // use path_reuse
{
err_when(reuseMode!=GENERAL_GROUP_MOVEMENT);
seekResult = seek_path_reuse.seek(startXLocLoc, startYLocLoc, destXLoc, destYLoc, 1, unit_group_id,
mobile_type, searchMode, miscNo, numOfPath, reuseMode, pathReuseStatus);
result_node_array = seek_path_reuse.get_result(result_node_count, result_path_dist);
}
#ifdef DEBUG
seek_path_profile_time = misc.get_time() - seekPathStartTime;
#endif
/* break;
default: err_here();
break;
}*/
if(seekResult==PATH_IMPOSSIBLE)
{
reset_path();
err_when(result_node_array || result_node_count);
}
//####### begin trevor 15/10 ########//
//-----------------------------------------------------------------------//
// update ignore_power_nation,seek_path_fail_count
//-----------------------------------------------------------------------//
if(ai_unit)
{
//----- set seek_path_fail_count ------//
if( seekResult==PATH_IMPOSSIBLE ||
(seekResult==PATH_NODE_USED_UP && // if all the nodes have been used up and the number of nodes original available is >= VALID_BACKGROUND_SEARCH_NODE
totalAvailableNode >= VALID_BACKGROUND_SEARCH_NODE) )
{
if( seek_path_fail_count < 100 ) // prevent numeric overflow
seek_path_fail_count++;
}
else
seek_path_fail_count=0;
//------- set ignore_power_nation -------//
if( seekResult==PATH_IMPOSSIBLE )
{
switch(ignore_power_nation)
{
case 0: ignore_power_nation = 1;
break;
case 1: ignore_power_nation = 2;
break;
case 2: break;
default: err_here();
break;
}
}
else
{
if( ignore_power_nation==1 )
ignore_power_nation = 0;
}
}
//######## end trevor 15/10 ########//
//-----------------------------------------------------------------------//
// if closest node is returned, the destination should not be the real
// location to go to. Thus, move_to_?_loc should be adjusted
//-----------------------------------------------------------------------//
if(result_node_array && result_node_count)
{
ResultNode* lastNode = result_node_array + result_node_count - 1;
move_to_x_loc = lastNode->node_x; // adjust move_to_?_loc
move_to_y_loc = lastNode->node_y;
result_node_recno = 1; // skip the first node which is the current location
if(cur_action != SPRITE_MOVE) // check if the unit is moving right now, wait until it reaches the nearest complete tile.
{
err_when(cur_action!=SPRITE_SHIP_EXTRA_MOVE && (cur_x!=next_x || cur_y!=next_y));
#ifdef DEBUG
int moveToXLoc = move_to_x_loc;
int moveToYLoc = move_to_y_loc;
#endif
ResultNode *nextNode = result_node_array + 1;
//set_dir(next_x_loc(), next_y_loc(), nextNode->node_x, nextNode->node_y);
set_dir(startXLocLoc, startYLocLoc, nextNode->node_x, nextNode->node_y);
next_move();
#ifdef DEBUG
err_when(move_action_call_flag && (moveToXLoc!=move_to_x_loc || moveToYLoc!=move_to_y_loc));
#endif
}
}
else // stay in the current location
{
err_when(result_node_array!=NULL);
move_to_x_loc = startXLocLoc; // adjust move_to_?_loc
move_to_y_loc = startYLocLoc;
err_when(move_to_x_loc!=startXLocLoc || move_to_y_loc!=startYLocLoc);
if(cur_x!=next_x || cur_y!=next_y)
set_move();
else
set_idle();
}
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
//-------------------------------------------------------//
// PATH_NODE_USED_UP happens when:
// Exceed the object's MAX's node limitation, the closest path
// is returned. Get to the closest path first and continue
// to seek the path in the background.
//-------------------------------------------------------//
return 1;
}
//----------- End of function Unit::searching -----------//
//--------- Begin of function Unit::move_to_firm_surround ---------//
// order unit to move to firm surrounding
//
// destXLoc, destYLoc - destination
// width - unit width
// height - unit height
// miscNo - the firm id (default 0)
// readyDist - similar to that in set_move_to_surround()
// (default 0)
//
// Note: the firm should exist in the location (destXloc, destYLoc)
// this function can be called by unit with size 1x1, 2x2,
//
void Unit::move_to_firm_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
{
err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
//----------------------------------------------------------------//
// calculate new destination if trying to move to different territory
//----------------------------------------------------------------//
Location *locPtr = world.get_loc(destXLoc, destYLoc);
if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP && miscNo==FIRM_HARBOR)
{
err_when(!locPtr->is_firm());
Firm *firmPtr = firm_array[locPtr->firm_recno()];
FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=harborPtr->sea_region_id)
{
move_to(destXLoc, destYLoc);
return;
}
}
else
{
if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
{
move_to(destXLoc, destYLoc);
return;
}
}
//----------------------------------------------------------------//
// return if the unit is dead
//----------------------------------------------------------------//
if(is_unit_dead())
return;
//----------------------------------------------------------------//
// check for equal actions
//----------------------------------------------------------------//
if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
{
//------ previous action is ACTION_MOVE -------//
err_when(action_para2 || action_para);
if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
{
//-------- equal order --------//
action_x_loc = action_x_loc2;
action_y_loc = action_y_loc2;
if(cur_action!=SPRITE_IDLE)
{
//-------- the old order is processing --------//
if(result_node_array==NULL) // cannot move
{
err_when(result_node_count || result_node_recno);
set_idle();
}
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
return;
}//else action is hold due to some problems, re-activiate again
}
}//else, new order or searching is required
int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
FirmInfo *firmInfo = firm_res[miscNo];
stop();
set_move_to_surround(destX, destY, firmInfo->loc_width, firmInfo->loc_height, BUILDING_TYPE_FIRM_MOVE_TO, miscNo);
//----------------------------------------------------------------//
// store new order in action parameters
//----------------------------------------------------------------//
action_mode = action_mode2 = ACTION_MOVE;
action_para = action_para2 = 0;
action_x_loc = action_x_loc2 = move_to_x_loc;
action_y_loc = action_y_loc2 = move_to_y_loc;
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
#ifdef DEBUG
if(unit_res[unit_id]->unit_class!=UNIT_CLASS_SHIP || ((UnitMarine*)this)->extra_move_in_beach==NO_EXTRA_MOVE)
err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
#endif
}
//----------- End of function Unit::move_to_firm_surround -----------//
//--------- Begin of function Unit::move_to_town_surround ---------//
// move to town surrounding
//
// destXLoc, destYLoc - destination
// width - unit width
// height - unit height
// miscNo - reserved (default 0)
// readyDist - similar to that in set_move_to_surround()
// (default 0)
//
// Note: assume the town exists
// this function can be called by unit with size 1x1, 2x2,
//
void Unit::move_to_town_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
{
err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
//----------------------------------------------------------------//
// calculate new destination if trying to move to different territory
//----------------------------------------------------------------//
Location *locPtr = world.get_loc(destXLoc, destYLoc);
if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
{
move_to(destXLoc, destYLoc);
return;
}
//----------------------------------------------------------------//
// return if the unit is dead
//----------------------------------------------------------------//
if(is_unit_dead())
return;
//----------------------------------------------------------------//
// check for equal actions
//----------------------------------------------------------------//
if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
{
//------ previous action is ACTION_MOVE -------//
err_when(action_para2 || action_para);
if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
{
//-------- equal order --------//
action_x_loc = action_x_loc2;
action_y_loc = action_y_loc2;
if(cur_action!=SPRITE_IDLE)
{
//-------- the old order is processing --------//
if(result_node_array==NULL) // cannot move
{
err_when(result_node_count || result_node_recno);
set_idle();
}
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
return;
}//else action is hold due to some problems, re-activiate again
}
}//else, new order or searching is required
int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
stop();
set_move_to_surround(destX, destY, STD_TOWN_LOC_WIDTH, STD_TOWN_LOC_HEIGHT, BUILDING_TYPE_TOWN_MOVE_TO);
//----------------------------------------------------------------//
// store new order in action parameters
//----------------------------------------------------------------//
action_mode = action_mode2 = ACTION_MOVE;
action_para = action_para2 = 0;
action_x_loc = action_x_loc2 = move_to_x_loc;
action_y_loc = action_y_loc2 = move_to_y_loc;
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
}
//----------- End of function Unit::move_to_town_surround -----------//
//--------- Begin of function Unit::move_to_wall_surround ---------//
// move to wall surrounding
//
// destXLoc, destYLoc - destination
// width - unit width
// height - unit height
// miscNo - reserved (default 0)
// readyDist - similar to that in set_move_to_surround()
// (default 0)
//
// Note: assume the wall exists
// this function can be called by unit with size 1x1, 2x2,
//
void Unit::move_to_wall_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
{
err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
//----------------------------------------------------------------//
// calculate new destination if trying to move to different territory
//----------------------------------------------------------------//
Location *locPtr = world.get_loc(destXLoc, destYLoc);
if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
{
move_to(destXLoc, destYLoc);
return;
}
//----------------------------------------------------------------//
// return if the unit is dead
//----------------------------------------------------------------//
if(is_unit_dead())
return;
//----------------------------------------------------------------//
// check for equal actions
//----------------------------------------------------------------//
if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
{
//------ previous action is ACTION_MOVE -------//
err_when(action_para2 || action_para);
if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
{
//-------- equal order --------//
action_x_loc = action_x_loc2;
action_y_loc = action_y_loc2;
if(cur_action!=SPRITE_IDLE)
{
//-------- the old order is processing --------//
if(result_node_array==NULL) // cannot move
{
err_when(result_node_count || result_node_recno);
set_idle();
}
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
return;
}//else action is hold due to some problems, re-activiate again
}
}//else, new order or searching is required
int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
stop();
set_move_to_surround(destX, destY, 1, 1, BUILDING_TYPE_WALL);
//----------------------------------------------------------------//
// store new order in action parameters
//----------------------------------------------------------------//
action_mode = action_mode2 = ACTION_MOVE;
action_para = action_para2 = 0;
action_x_loc = action_x_loc2 = move_to_x_loc;
action_y_loc = action_y_loc2 = move_to_y_loc;
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
}
//----------- End of function Unit::move_to_wall_surround -----------//
//--------- Begin of function Unit::move_to_unit_surround ---------//
// move to unit surrounding
//
// destXLoc, destYLoc - destination
// width - unit width
// height - unit height
// miscNo - vehicle unit_recno (default 0)
// readyDist - similar to that in set_move_to_surround()
// (default 0)
//
// Note: assume the vehicle exists
// this function can be called by unit with size 1x1, 2x2,
//
void Unit::move_to_unit_surround(int destXLoc, int destYLoc, int width, int height, int miscNo, int readyDist)
{
err_when(destXLoc<0 || destXLoc>=MAX_WORLD_X_LOC || destYLoc<0 || destYLoc>=MAX_WORLD_Y_LOC);
//----------------------------------------------------------------//
// calculate new destination if trying to move to different territory
//----------------------------------------------------------------//
Location *locPtr = world.get_loc(destXLoc, destYLoc);
if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
{
move_to(destXLoc, destYLoc);
return;
}
//----------------------------------------------------------------//
// return if the unit is dead
//----------------------------------------------------------------//
if(is_unit_dead())
return;
//----------------------------------------------------------------//
// check for equal actions
//----------------------------------------------------------------//
if(action_mode2==ACTION_MOVE && action_mode==ACTION_MOVE)
{
//------ previous action is ACTION_MOVE -------//
err_when(action_para2 || action_para);
if(action_x_loc2==destXLoc && action_y_loc2==destYLoc)
{
//-------- equal order --------//
action_x_loc = action_x_loc2;
action_y_loc = action_y_loc2;
if(cur_action!=SPRITE_IDLE)
{
//-------- the old order is processing --------//
if(result_node_array==NULL) // cannot move
{
err_when(result_node_count || result_node_recno);
set_idle();
}
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
return;
}//else action is hold due to some problems, re-activiate again
}
}//else, new order or searching is required
int destX = MAX(0, ((width>1) ? destXLoc : destXLoc - width + 1));
int destY = MAX(0, ((height>1) ? destYLoc : destYLoc - height + 1));
err_when(unit_array.is_deleted(miscNo));
Unit *unitPtr = unit_array[miscNo];
SpriteInfo *spriteInfo = unitPtr->sprite_info;
stop();
set_move_to_surround(destX, destY, spriteInfo->loc_width, spriteInfo->loc_height, BUILDING_TYPE_VEHICLE);
//----------------------------------------------------------------//
// store new order in action parameters
//----------------------------------------------------------------//
action_mode = action_mode2 = ACTION_MOVE;
action_para = action_para2 = 0;
action_x_loc = action_x_loc2 = move_to_x_loc;
action_y_loc = action_y_loc2 = move_to_y_loc;
err_when(action_mode==ACTION_MOVE && (action_x_loc==-1 || action_y_loc==-1));
err_when(move_to_x_loc<0 || move_to_x_loc>=MAX_WORLD_X_LOC || move_to_y_loc<0 || move_to_y_loc>=MAX_WORLD_Y_LOC);
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
err_when(result_node_array==NULL && (next_x!=go_x || next_y!=go_y));
}
//----------- End of function Unit::move_to_unit_surround -----------//
//--------- Begin of function Unit::different_territory_destination ---------//
// calculate a reachable destination if the unit is ordered to move to unreachable
// location on different territory
//
// destX, destY - reference to return destination
//
void Unit::different_territory_destination(int& destX, int& destY)
{
int curXLoc = next_x_loc();
int curYLoc = next_y_loc();
Location *locPtr = world.get_loc(curXLoc, curYLoc);
int regionId = locPtr->region_id;
int xStep = destX-curXLoc;
int yStep = destY-curYLoc;
int absXStep = abs(xStep);
int absYStep = abs(yStep);
int count = (absXStep>=absYStep) ? absXStep : absYStep;
int x, y;
long int sameTerr = 0;
//------------------------------------------------------------------------------//
// draw a line from the unit location to the destination, find the last location
// with the same region id.
//------------------------------------------------------------------------------//
for(long int i=1; i<=count; i++)
{
x = curXLoc + int((i*xStep)/count);
y = curYLoc + int((i*yStep)/count);
locPtr = world.get_loc(x, y);
if(locPtr->region_id==regionId)
sameTerr = i;
}
if(sameTerr)
{
destX = curXLoc + int((sameTerr*xStep)/count);
destY = curYLoc + int((sameTerr*yStep)/count);
}
else
{
destX = curXLoc;
destY = curYLoc;
}
}
//----------- End of function Unit::different_territory_destination -----------//
//--------- Begin of function Unit::next_move ---------//
//
// If there is unprocessed node(s) in the result_node_array,
// then next unprocessed node will be set to be the next location
// to move to. (i.e. go_? = location of the unprocessed node)
//
void Unit::next_move()
{
if(result_node_array == NULL || !result_node_count || !result_node_recno)
return;
if( ++result_node_recno > result_node_count )
{
//------------ all nodes are visited --------------//
err_when(cur_x!=next_x || cur_y!=next_y);
err_when(next_x_loc()!=move_to_x_loc || next_y_loc()!=move_to_y_loc);
mem_del(result_node_array);
result_node_array = NULL;
set_idle();
if(action_mode2==ACTION_MOVE) //--------- used to terminate action_mode==ACTION_MOVE
{
force_move_flag = 0;
//------- reset ACTION_MOVE parameters ------//
reset_action_para();
if(move_to_x_loc==action_x_loc2 && move_to_y_loc==action_y_loc2)
reset_action_para2();
}
return;
}
//---- order the unit to move to the next checkpoint following the path ----//
ResultNode* resultNode = result_node_array+result_node_recno-1;
#ifdef DEBUG
err_when(cur_x==move_to_x_loc*ZOOM_LOC_WIDTH && cur_y==move_to_y_loc*ZOOM_LOC_HEIGHT);
err_when(!resultNode);
#endif
sprite_move( resultNode->node_x*ZOOM_LOC_WIDTH, resultNode->node_y*ZOOM_LOC_HEIGHT );
err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
}
//----------- End of function Unit::next_move -----------//
//--------- Begin of function Unit::reset_path ---------//
// Cancel all movement.
//
void Unit::reset_path()
{
if( result_node_array )
{
mem_del(result_node_array);
result_node_array = NULL;
}
result_path_dist = result_node_count = result_node_recno = 0;
}
//----------- End of function Unit::reset_path -----------//
//--------- Begin of function Unit::pre_process ---------//
// process unit's action
//
void Unit::pre_process()
{
//-*********** simulate aat ************-//
#ifdef DEBUG
if(debug_sim_game_type==2)
{
if(hit_points!=max_hit_points)
hit_points = max_hit_points;
Nation *nationPtr = nation_array[nation_recno];
if(nationPtr->cash<4000)
nationPtr->cash += 10000;
if(nationPtr->food<4000)
nationPtr->food += 10000;
}
#endif
//-*********** simulate aat ************-//
#if defined(DEBUG) && defined(ENABLE_LOG)
String logStr;
logStr = " begin unit ";
logStr += sprite_recno;
// ########## begin Gilbert 6/9 #######//
logStr += " nation=";
logStr += nation_recno;
logStr += "(";
logStr += true_nation_recno();
logStr += ")";
// ########## end Gilbert 6/9 #######//
logStr += " pre_process(), action_mode=";
logStr += action_mode;
logStr += " action_mode2=";
logStr += action_mode2;
LOG_MSG(logStr);
logStr = "action_para=";
logStr += action_para;
logStr += " action_para2=";
logStr += action_para2;
logStr += " cur_action=";
logStr += cur_action;
logStr += " cur_x/y=";
logStr += cur_x;
logStr += "/";
logStr += cur_y;
logStr += " next_x/y=";
logStr += next_x;
logStr += "/";
logStr += next_y;
LOG_MSG(logStr);
#endif
//------ if all the hit points are lost, die now ------//
if(hit_points <= 0 && action_mode != ACTION_DIE)
{
set_die();
if(ai_action_id)
nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
return;
}
#ifdef DEBUG
int debugActionMode = action_mode;
int debugActionPatra = action_para;
int debugCurAction = cur_action;
#endif
if( config.fog_of_war )
{
if( is_own() ||
(nation_recno && nation_array[nation_recno]->is_allied_with_player) )
{
world.visit(next_x_loc(), next_y_loc(), next_x_loc()+sprite_info->loc_width-1,
next_y_loc()+sprite_info->loc_height-1, unit_res[unit_id]->visual_range,
unit_res[unit_id]->visual_extend);
}
}
//--------- process action corresponding to action_mode ----------//
#ifdef DEBUG
unsigned long startTime;
#endif
switch(action_mode)
{
case ACTION_ATTACK_UNIT:
#ifdef DEBUG
startTime = misc.get_time();
#endif
//------------------------------------------------------------------//
// if unit is in defense mode, check situation to follow the target
// or return back to camp
//------------------------------------------------------------------//
if(action_mode!=action_mode2)
{
if(action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
{
if(!defense_follow_target()) // false if abort attacking
break; // cancel attack and go back to military camp
}
else if(action_mode2==ACTION_DEFEND_TOWN_ATTACK_TARGET)
{
if(!defend_town_follow_target())
break;
}
else if(action_mode2==ACTION_MONSTER_DEFEND_ATTACK_TARGET)
{
if(!monster_defend_follow_target())
break;
}
else
err_here();
}
process_attack_unit();
#ifdef DEBUG
unit_attack_profile_time += misc.get_time() - startTime;
#endif
break;
case ACTION_ATTACK_FIRM:
process_attack_firm();
break;
case ACTION_ATTACK_TOWN:
process_attack_town();
break;
case ACTION_ATTACK_WALL:
process_attack_wall();
break;
case ACTION_ASSIGN_TO_FIRM:
case ACTION_ASSIGN_TO_TOWN:
case ACTION_ASSIGN_TO_VEHICLE:
#ifdef DEBUG
startTime = misc.get_time();
#endif
process_assign();
#ifdef DEBUG
unit_assign_profile_time += misc.get_time() - startTime;
#endif
break;
case ACTION_ASSIGN_TO_SHIP:
process_assign_to_ship();
break;
case ACTION_BUILD_FIRM:
process_build_firm();
break;
case ACTION_BURN:
process_burn();
break;
case ACTION_SETTLE:
process_settle();
break;
case ACTION_SHIP_TO_BEACH:
process_ship_to_beach();
break;
case ACTION_GO_CAST_POWER:
process_go_cast_power();
break;
}
//-****** don't add code here, the unit may be removed after the above function call*******-//
// ###### begin Gilbert 20/6 ########//
#ifdef DEBUG
// do not read data member
LOG_MSG( " end Unit::pre_process()" );
LOG_MSG( misc.get_random_seed() );
#endif
// ###### end Gilbert 20/6 ########//
}
//----------- End of function Unit::pre_process -----------//
//--------- Begin of function Unit::process_die ---------//
// process unit die
//
// return 1 if die frame is counting
// return 0 otherwise
//
int Unit::process_die()
{
//-*********** simulate aat ************-//
#ifdef DEBUG
if(debug_sim_game_type)
{
cur_action = SPRITE_IDLE;
hit_points = max_hit_points;
stop2();
return 0;
}
#endif
//-*********** simulate aat ************-//
//--------- voice ------------//
se_res.sound(cur_x_loc(), cur_y_loc(), cur_frame, 'S',sprite_id,"DIE");
// ####### begin Gilbert 14/7 ###########//
//------------- add die effect on first frame --------- //
if( cur_frame == 1 && unit_res[unit_id]->die_effect_id)
{
Effect::create(unit_res[unit_id]->die_effect_id, cur_x, cur_y,
SPRITE_DIE, cur_dir, mobile_type == UNIT_AIR ? 8 : 2, 0);
}
// ####### end Gilbert 14/7 ###########//
//--------- next frame ---------//
if( ++cur_frame > sprite_info->die.frame_count )
return 1;
return 0;
}
//----------- End of function Unit::process_die -----------//
//--------- Begin of function Unit::process_rebel ---------//
//
// Unit::process_rebel() is in OREBEL.CPP
//
//----------- End of function Unit::process_rebel ---------//
//--------- Begin of function Unit::avail_node_enough_for_search --------//
// decide whether the available number of nodes enough for a valid path searching
//
// x1, y1 - start location
// x2, y2 - end location
//
// return 1 if num of nodes is enough
// return 0 otherwise
//
int Unit::avail_node_enough_for_search(short x1, short y1, short x2, short y2)
{
short dispX = abs(x1-x2);
short dispY = abs(y1-y2);
short majDist = dispX>dispY ? dispX : dispY;
short minDist = abs(dispX-dispY);
int nodeRequire = MIN(VALID_BACKGROUND_SEARCH_NODE, majDist<<5); // *32
int totalNode = seek_path.total_node_avail;
if(totalNode < nodeRequire)
{
if(totalNode>=MIN_BACKGROUND_NODE_USED_UP)
seek_path.total_node_avail = MIN_BACKGROUND_NODE_USED_UP-1;
return 0;
}
return 1;
}
//----------- End of function Unit::avail_node_enough_for_search -----------//
//--------- Begin of function Unit::process_move --------//
// process unit movement
//
void Unit::process_move()
{
//----- if the sprite has reach the destintion ----//
//--------------------------------------------------------//
// if the unit reach its destination, then
// cur_? == next_? == go_?
//--------------------------------------------------------//
err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
if(cur_x==go_x && cur_y==go_y)
{
if(result_node_array)
{
next_move();
if( cur_action != SPRITE_MOVE ) // if next_move() is not successful, the movement has been stopped
return;
//---------------------------------------------------------------------------//
// If (1) the unit is blocked at cur_? == go_? and go_? != destination and
// (2) a new path is generated if calling the previous next_move(),
// then cur_? still equal to go_?.
//
// The following Sprite::process_move() call will set the unit to SPRITE_IDLE
// since cur_? == go_?. Thus, the unit terminates its move although it has not
// reached its destination.
//
// (note: if it has reached its destination, cur_? == go_? and cur_action =
// SPRITE_IDLE)
//
// if the unit is still moving and cur_? == go_?, call next_move() again to reset
// the go_?.
//---------------------------------------------------------------------------//
if(cur_action==SPRITE_MOVE && cur_x==go_x && cur_y==go_y)
next_move();
}
}
err_when(result_node_array && result_node_count==result_node_recno &&
(result_node_array[result_node_count-1].node_x!=go_x>>ZOOM_X_SHIFT_COUNT ||
result_node_array[result_node_count-1].node_y!=go_y>>ZOOM_Y_SHIFT_COUNT));
//--------- process the move, update sprite position ---------//
//--------------------------------------------------------//
// if the unit is moving, cur_?!=go_? and
// if next_? != cur_?, the direction from cur_? to next_?
// should equal to that from cur_? to go_?
//--------------------------------------------------------//
err_when((cur_x%ZOOM_LOC_WIDTH==0 && cur_y%ZOOM_LOC_HEIGHT==0) && (cur_x!=next_x || cur_y!=next_y) &&
((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, next_x, next_y))));
#ifdef DEBUG
int debugCurX = cur_x;
int debugCurY = cur_y;
int debugNextX = next_x;
int debugNextY = next_y;
int debugGoX = go_x;
int debugGoY = go_y;
#endif
err_when(cur_x-next_x!=0 && cur_y-next_y!=0 && abs(next_x-cur_x)!=abs(next_y-cur_y));
err_when(result_path_dist && result_node_array==NULL);
Sprite::process_move();
err_when( cur_x < 0 || cur_y < 0 || cur_x >= ZOOM_X_PIXELS || cur_y >= ZOOM_Y_PIXELS );
if(cur_x==go_x && cur_y==go_y && cur_action==SPRITE_IDLE) // the sprite has reached its destination
{
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
}
//--------------------------------------------------------//
// after Sprite::process_move(), if the unit is blocked, its
// cur_action is set to SPRITE_WAIT. Otherwise, its cur_action
// is still SPRITE_MOVE. Then cur_? != next_? if the unit
// has not reached its destination.
//--------------------------------------------------------//
err_when(cur_action==SPRITE_MOVE && (cur_x!=go_x || cur_y!=go_y) && (cur_x==next_x && cur_y==next_y));
}
//---------- End of function Unit::process_move ----------//
//--------- Begin of function Unit::process_wait ---------//
// process unit's waiting
//
void Unit::process_wait()
{
err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
if(!match_dir())
return;
//-----------------------------------------------------//
// If the unit is moving to the destination and was
// blocked by something. If it is now no longer blocked,
// continue the movement.
//-----------------------------------------------------//
//
// When this funciton is called:
//
// (next_x, next_y)==(cur_x, cur_y), it's the location of the sprite.
//
//-----------------------------------------------------//
//--- find out the next location which the sprite should be moving towards ---//
//-----------------------------------------------------//
// If the unit is waiting,
// go_? != cur_?
// go_? != next_?
//
// If the unit is not under swapping, the next_?_loc()
// is always the move_to_?_loc. Thus, the unit is ordered
// to stop.
//-----------------------------------------------------//
err_when( (go_x>>ZOOM_X_SHIFT_COUNT!=move_to_x_loc || go_y>>ZOOM_Y_SHIFT_COUNT!=move_to_y_loc) &&
( (cur_x==go_x && cur_y==go_y) || (cur_x!=next_x || cur_y!=next_y) ) );
if(next_x_loc()==move_to_x_loc && next_y_loc()==move_to_y_loc && !swapping)
{
terminate_move();
return; // terminate since already in destination
}
int stepMagn = move_step_magn();
int nextX = cur_x+stepMagn*move_x_pixel_array[final_dir];
int nextY = cur_y+stepMagn*move_y_pixel_array[final_dir];
/*short w, h, blocked=0;
short x, y, blockedX, blockedY;
Location* locPtr;
//---------- check whether the unit is blocked -----------//
for(h=0, y=nextY>>ZOOM_Y_SHIFT_COUNT; hloc_height && !blocked; h++, y++)
{
for(w=0, x=nextX>>ZOOM_X_SHIFT_COUNT; wloc_width && !blocked; w++, x++)
{
locPtr = world.get_loc(x, y);
blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
locPtr->unit_recno(mobile_type)!=sprite_recno) );
if(blocked)
{
blockedX = x;
blockedY = y;
}
}
}*/
short x = nextX>>ZOOM_X_SHIFT_COUNT;
short y = nextY>>ZOOM_Y_SHIFT_COUNT;
Location *locPtr = world.get_loc(x, y);
short blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
locPtr->unit_recno(mobile_type)!=sprite_recno) );
if(!blocked || move_action_call_flag)
{
//--------- not blocked, continue to move --------//
waiting_term = 0;
set_move();
cur_frame = 1;
set_next(nextX, nextY, -stepMagn, 1);
}
else
{
//------- blocked, call handle_blocked_move() ------//
//locPtr = world.get_loc(blockedX, blockedY);
err_when(cur_x!=next_x || cur_y!=next_y);
handle_blocked_move(locPtr);
}
err_when(cur_action==SPRITE_MOVE && (cur_x!=go_x || cur_y!=go_y) && (cur_x==next_x && cur_y==next_y));
err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
}
//----------- End of function Unit::process_wait -----------//
//--------- Begin of function Unit::set_next --------//
// set the next coordinates to move to
//
// newNextX, newNextY - next coordinate to move to
// para - used to count the result_path_dist
// blockedChecked - whether the next location specified is checked to be
// non-blocked. 1 checked for non-blocked, 0 for not checked
//
void Unit::set_next(int newNextX, int newNextY, int para, int blockedChecked)
{
int curNextXLoc = next_x_loc();
int curNextYLoc = next_y_loc();
int newNextXLoc = newNextX >> ZOOM_X_SHIFT_COUNT;
int newNextYLoc = newNextY >> ZOOM_Y_SHIFT_COUNT;
#ifdef DEBUG
int debugStepMagn = move_step_magn();
err_when(abs(curNextXLoc-newNextXLoc)>debugStepMagn || abs(curNextYLoc-newNextYLoc)>debugStepMagn);
#endif
if(curNextXLoc!=newNextXLoc || curNextYLoc!=newNextYLoc)
{
if(!match_dir())
{
set_wait();
return;
}
}
//short w, h, blocked=0;
//short x, y, blockedX, blockedY;
short w, h, blocked=0;
short x, y;
#ifdef DEBUG
for(h=0, y=curNextYLoc; hloc_height; h++, y++)
for(w=0, x=curNextXLoc; wloc_width; w++, x++)
err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno ); // it must be 0 to put the sprite in this location
#endif
if( curNextXLoc != newNextXLoc || curNextYLoc != newNextYLoc )
{
//------- if the next location is blocked ----------//
Location* locPtr;
if(!blockedChecked)
{
/*for(h=0, y=newNextYLoc; hloc_height && !blocked; h++, y++)
{
for(w=0, x=newNextXLoc; wloc_width && !blocked; w++, x++)
{
locPtr = world.get_loc(x, y);
blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
locPtr->unit_recno(mobile_type)!=sprite_recno) );
if(blocked)
{
blockedX = x;
blockedY = y;
}
}
}*/
x = newNextXLoc;
y = newNextYLoc;
locPtr = world.get_loc(x, y);
blocked = ( (!locPtr->is_accessible(mobile_type)) || (locPtr->has_unit(mobile_type) &&
locPtr->unit_recno(mobile_type)!=sprite_recno) );
}//else, then blockedChecked = 0
//--- no change to next_x & next_y if the new next location is blocked ---//
if(blocked)
{
set_cur(next_x, next_y); // align the sprite to 32x32 location when it stops
//------ avoid infinitely looping in calling handle_blocked_move() ------//
if(blocked_by_member || move_action_call_flag)
{
set_wait();
blocked_by_member = 0;
}
else
{
locPtr = world.get_loc(x, y);
handle_blocked_move(locPtr);
}
#ifdef DEBUG
for(h=0, y=next_y_loc(); hloc_height; h++, y++)
{
for(w=0, x=next_x_loc(); wloc_width; w++, x++)
err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno ); // it must be 0 to put the sprite in this location
}
#endif
}
else
{
err_when(mobile_type!=UNIT_LAND && (abs(para)!=2 || result_path_dist%2));
if(para)
{
#ifdef DEBUG
int count=0, ii;
int dist;
int curXLoc = next_x_loc();
int curYLoc = next_y_loc();
ResultNode *curNode = result_node_array + result_node_recno -1;
ResultNode *nextNode;
dist = misc.points_distance(curXLoc, curYLoc, curNode->node_x, curNode->node_y);
if(result_node_recno>1)
count += dist;
else
count -= dist;
for(ii=result_node_recno, nextNode=curNode+1; iinode_x, nextNode->node_y, curNode->node_x, curNode->node_y);
count += dist;
}
err_when(result_path_dist!=count);
#endif
//----------------------------------------------------------------------------//
// calculate the result_path_dist as the unit move from one tile to another
//----------------------------------------------------------------------------//
result_path_dist += para;
}
next_x = newNextX;
next_y = newNextY;
swapping = blocked_by_member = 0;
//---- move sprite_recno to the next location ------//
for(h=0, y=curNextYLoc; hloc_height; h++, y++)
{
for(w=0, x=curNextXLoc; wloc_width; w++, x++)
world.set_unit_recno(x, y, mobile_type, 0);
}
for(h=0, y=next_y_loc(); hloc_height; h++, y++)
{
for(w=0, x=next_x_loc(); wloc_width; w++, x++)
world.set_unit_recno(x, y, mobile_type, sprite_recno);
}
//--------- explore land ----------//
// ###### begin Gilbert 24/5 ######//
if( !config.explore_whole_map && is_own() )
// ###### end Gilbert 24/5 ######//
{
int xLoc1 = MAX(0,newNextXLoc-EXPLORE_RANGE);
int yLoc1 = MAX(0,newNextYLoc-EXPLORE_RANGE);
int xLoc2 = MIN(MAX_WORLD_X_LOC-1, newNextXLoc+EXPLORE_RANGE);
int yLoc2 = MIN(MAX_WORLD_Y_LOC-1, newNextYLoc+EXPLORE_RANGE);
int exploreWidth = move_step_magn()-1;
if( newNextYLoc < curNextYLoc ) // if move upwards, explore upper area
world.explore(xLoc1, yLoc1, xLoc2, yLoc1+exploreWidth);
else if( newNextYLoc > curNextYLoc ) // if move downwards, explore lower area
world.explore(xLoc1, yLoc2-exploreWidth, xLoc2, yLoc2);
if( newNextXLoc < curNextXLoc ) // if move towards left, explore left area
world.explore(xLoc1, yLoc1, xLoc1+exploreWidth, yLoc2);
else if( newNextXLoc > curNextXLoc ) // if move towards right, explore right area
world.explore(xLoc2-exploreWidth, yLoc1, xLoc2, yLoc2);
}
}
}
err_when(cur_x!=next_x && cur_y!=next_y && // is not blocked
(check_unit_dir1=get_dir(cur_x, cur_y, next_x, next_y))!=(check_unit_dir2=get_dir(cur_x, cur_y, go_x, go_y)));
}
//---------- End of function Unit::set_next ----------//
//------ Begin of function Unit::blocked_move_new_handle -------//
/*int Unit::blocked_move_new_handle()
{
//------------------------------------------------------------------//
// new handling for blocked move
//------------------------------------------------------------------//
static int counter = 0;
int checkXLoc1, checkYLoc1, checkXLoc2, checkYLoc2;
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
Location *locPtr;
counter++;
switch(final_dir)
{
case DIR_N:
checkXLoc1 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
checkYLoc1 = checkYLoc2 = MAX(curYLoc-1, 0);
checkXLoc2 = MAX(curXLoc-1, 0);
break;
case DIR_NE:
checkXLoc1 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
checkYLoc1 = curYLoc;
checkXLoc2 = curXLoc;
checkYLoc2 = MAX(curYLoc-1, 0);
break;
case DIR_E:
checkXLoc1 = checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
checkYLoc1 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
checkYLoc2 = MAX(curYLoc-1, 0);
break;
case DIR_SE:
checkXLoc1 = curXLoc;
checkYLoc1 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
checkYLoc2 = curYLoc;
break;
case DIR_S:
checkXLoc1 = MAX(curXLoc-1, 0);
checkYLoc1 = checkYLoc2 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
checkXLoc2 = MIN(curXLoc+1, MAX_WORLD_X_LOC-1);
break;
case DIR_SW:
checkXLoc1 = MAX(curXLoc-1, 0);
checkYLoc1 = curYLoc;
checkXLoc2 = curXLoc;
checkYLoc2 = MIN(curYLoc, MAX_WORLD_Y_LOC-1);
break;
case DIR_W:
checkXLoc1 = checkXLoc2 = MAX(curXLoc-1, 0);
checkYLoc1 = MAX(curYLoc-1, 0);
checkYLoc2 = MIN(curYLoc+1, MAX_WORLD_Y_LOC-1);
break;
case DIR_NW:
checkXLoc1 = curXLoc;
checkYLoc1 = MAX(curYLoc-1, 0);
checkXLoc2 = MAX(curXLoc-1, 0);
checkYLoc2 = curYLoc;
break;
}
locPtr = world.get_loc(checkXLoc1, checkYLoc1);
if(locPtr->can_move(mobile_type))
set_path_to(checkXLoc1, checkYLoc1);
else
{
locPtr = world.get_loc(checkXLoc2, checkYLoc2);
if(locPtr->can_move(mobile_type))
set_path_to(checkXLoc2, checkYLoc2);
else
return 0;
}
return 1;
}*/
//------- End of function Unit::blocked_move_new_handle --------//
//------ Begin of function Unit::set_path_to -------//
/*void Unit::set_path_to(int destXLoc, int destYLoc)
{
//reset_path();
terminate_move();
result_node_array = (ResultNode*) mem_add(2*sizeof(ResultNode));
ResultNode *curNodePtr = result_node_array;
curNodePtr->node_x = next_x_loc();
curNodePtr->node_y = next_y_loc();
curNodePtr++;
curNodePtr->node_x = destXLoc;
curNodePtr->node_y = destYLoc;
result_node_count = 2;
result_node_recno = 1;
result_path_dist = 1;
move_to_x_loc = destXLoc;
move_to_y_loc = destYLoc;
go_x = destXLoc*ZOOM_LOC_WIDTH;
go_y = destYLoc*ZOOM_LOC_HEIGHT;
//set_dir(cur_x, cur_y, go_x, go_y);
//set_wait();
next_move();
}*/
//------- End of function Unit::set_path_to --------//
//------ Begin of function Unit::handle_blocked_move -------//
// Note: it assumes the given location is blocked, it makes no
// further attempt to verify it.
//
// blockedLoc - blocked location
//
// return : 1 - handled successfully
// 0 - cannot be handled, the movement must be terminated
//
void Unit::handle_blocked_move(Location* blockedLoc)
{
//--- check if the tile we are moving at is blocked by a building ---//
if(blockedLoc->is_firm() || blockedLoc->is_town() || blockedLoc->is_wall())
{
//------------------------------------------------//
// firm/town/wall is on the blocked location
//------------------------------------------------//
reset_path();
search_or_stop(move_to_x_loc, move_to_y_loc, 1);
//search(move_to_x_loc, move_to_y_loc, 1);
return;
}
if(next_x_loc()==move_to_x_loc && next_y_loc()==move_to_y_loc && !swapping)
{
terminate_move(); // terminate since already reaching destination
return;
}
if(!blockedLoc->is_accessible(mobile_type))
{
terminate_move(); // the location is not accessible
err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
return;
}
//-----------------------------------------------------------------------------------//
// there is another sprite on the move_to location, check the combination of both sizes
//-----------------------------------------------------------------------------------//
blocked_by_member = 1;
err_when(!blockedLoc->unit_recno(mobile_type));
Unit* unitPtr = unit_array[blockedLoc->unit_recno(mobile_type)];
//if(unitPtr->sprite_info->loc_width>1 || sprite_info->loc_width>1)
//{
// set_wait();
// return;
//}
//else
handle_blocked_move_s11(unitPtr); //------ both units size 1x1
err_when(cur_x==go_x && cur_y==go_y && (cur_x!=next_x || cur_y!=next_y));
return;
}
//------- End of function Unit::handle_blocked_move --------//
//------ Begin of function Unit::handle_blocked_by_idle_unit ---------//
// handle the case blocked by idle unit
//
// unitPtr - the unit blocking this unit
//
void Unit::handle_blocked_by_idle_unit(Unit *unitPtr)
{
#define TEST_DIMENSION 10
#define TEST_LIMIT TEST_DIMENSION*TEST_DIMENSION
char notLandUnit = (mobile_type!=UNIT_LAND);
int unitXLoc = unitPtr->next_x_loc();
int unitYLoc = unitPtr->next_y_loc();
int xShift, yShift;
int checkXLoc, checkYLoc;
Location *locPtr;
int xSign = misc.random(2) ? 1 : -1;
int ySign = misc.random(2) ? 1 : -1;
for(int i=2; i<=TEST_LIMIT; i++)
{
misc.cal_move_around_a_point(i, TEST_DIMENSION, TEST_DIMENSION, xShift, yShift);
xShift *= xSign;
yShift *= ySign;
if(notLandUnit)
{
checkXLoc = unitXLoc + xShift*2;
checkYLoc = unitYLoc + yShift*2;
}
else
{
checkXLoc = unitXLoc + xShift;
checkYLoc = unitYLoc + yShift;
}
if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
continue;
locPtr = world.get_loc(checkXLoc , checkYLoc);
if(!locPtr->can_move(unitPtr->mobile_type))
continue;
if(on_my_path(checkXLoc, checkYLoc))
continue;
unitPtr->move_to(checkXLoc, checkYLoc);
set_wait();
return;
}
stop(KEEP_DEFENSE_MODE);
//--------------------------------------------------------------------------------//
// improved version!!!
//--------------------------------------------------------------------------------//
/*int testResult = 0, worstCase=0;
int worstXLoc=-1, worstYLoc=-1;
int startCount, endCount;
int i, j;
for(j=0; j<2; j++)
{
//----------- set the startCount and endCount ------------//
if(j==0)
{
startCount = 2;
endCount = 9;
}
else
{
startCount = 10;
endCount = TEST_LIMIT;
}
for(i=startCount; i<=endCount; i++)
{
misc.cal_move_around_a_point(i, TEST_DIMENSION, TEST_DIMENSION, xShift, yShift);
if(notLandUnit)
{
checkXLoc = unitXLoc + xShift*2;
checkYLoc = unitYLoc + yShift*2;
}
else
{
checkXLoc = unitXLoc + xShift;
checkYLoc = unitYLoc + yShift;
}
if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
continue;
locPtr = world.get_loc(checkXLoc , checkYLoc);
if(!locPtr->can_move(unitPtr->mobile_type))
continue;
//-------------------------------------------------------------------//
// a possible location
//-------------------------------------------------------------------//
testResult = on_my_path(checkXLoc, checkYLoc);
if(testResult)
{
if(j==0 && !worstCase)
{
worstCase++;
worstXLoc = checkXLoc;
worstYLoc = checkYLoc;
}
continue;
}
unitPtr->move_to(checkXLoc, checkYLoc):
set_wait();
return;
}
}
//-------------------------------------------------------------------//
if(worstCase)
{
unitPtr->move_to(worstXLoc, worstYLoc);
set_wait();
}
else
stop(KEEP_DEFENSE_MODE);*/
}
//------- End of function Unit::handle_blocked_by_idle_unit --------//
//------ Begin of function Unit::on_my_path ---------//
// This function is used to check whether a location
// (checkXLoc, checkYLoc) is on the unit path, result_node_array.
//
// return 1 if true
// return 0 otherwise
//
int Unit::on_my_path(short checkXLoc, short checkYLoc)
{
err_when(result_node_count<2);
ResultNode* curNodePtr = result_node_array+result_node_recno-2;
ResultNode* nextNodePtr = curNodePtr+1;
for(int i=result_node_recno-1; inode_x-checkXLoc)*(checkYLoc-nextNodePtr->node_y)==
(curNodePtr->node_y-checkYLoc)*(checkXLoc-nextNodePtr->node_x)) // point of division
return 1;
}
return 0;
}
//------- End of function Unit::on_my_path --------//
//------ Begin of function Unit::handle_blocked_wait ---------//
//
// this function is worked for unit size 1x1 only to handle case that
// blocked by waiting unit
//
// unitPtr - unit blocking this unit
//
void Unit::handle_blocked_wait(Unit* unitPtr)
{
err_when(sprite_info->loc_width>1 || unitPtr->sprite_info->loc_width>1);
int stepMagn = move_step_magn();
short cycleWait = 0;
Location *locPtr;
if(is_dir_correct())
{
Unit *blockedUnitPtr = unitPtr;
SpriteInfo *unitSpriteInfo = unitPtr->sprite_info;
int nextX, nextY, loop = 0, i;
short blocked=0;
//---------------------------------------------------------------//
// construct a cycle_waiting array to store the sprite_recno of
// those units in cycle_waiting in order to prevent forever looping
// in the checking
//---------------------------------------------------------------//
int arraySize = 20;
cycle_wait_unit_array_def_size = arraySize;
cycle_wait_unit_index = 0;
cycle_wait_unit_array_multipler = 1;
cycle_wait_unit_array = (short*)mem_add(sizeof(short)*cycle_wait_unit_array_def_size);
memset(cycle_wait_unit_array, 0, sizeof(short)*cycle_wait_unit_array_def_size);
//---------------------------------------------------------------//
// don't handle the case blocked by size 2x2 unit in this moment
//---------------------------------------------------------------//
while(!cycleWait && blockedUnitPtr->cur_action==SPRITE_WAIT)
{
if(unitSpriteInfo->loc_width>1)
break; // don't handle unit size > 1
if(!blockedUnitPtr->is_dir_correct())
break;
//----------------------------------------------------------------------------------------//
// cur_x, cur_y of unit pointed by blockedUnitPtr should be exactly inside a tile
//----------------------------------------------------------------------------------------//
nextX = blockedUnitPtr->cur_x+stepMagn*move_x_pixel_array[blockedUnitPtr->final_dir];
nextY = blockedUnitPtr->cur_y+stepMagn*move_y_pixel_array[blockedUnitPtr->final_dir];
//---------- calculate location blocked unit attempts to move to ---------//
nextX >>= ZOOM_X_SHIFT_COUNT;
nextY >>= ZOOM_Y_SHIFT_COUNT;
locPtr = world.get_loc(nextX, nextY);
blocked = locPtr->has_unit(mobile_type);
//---------------- the unit is also waiting ---------------//
if(blocked && (blockedUnitPtr->move_to_x_loc!=blockedUnitPtr->cur_x_loc() ||
blockedUnitPtr->move_to_y_loc!=blockedUnitPtr->cur_y_loc()))
{
if(locPtr->unit_recno(mobile_type) == sprite_recno)
cycleWait = 1;
else
{
for(i=0; isprite_recno)
{
loop = 1;
break;
}
}
if(loop)
break;
//------------------------------------------------------//
// resize array if required size is larger than arraySize
//------------------------------------------------------//
if(cycle_wait_unit_index >= arraySize)
{
cycle_wait_unit_array_multipler++;
arraySize = cycle_wait_unit_array_def_size*cycle_wait_unit_array_multipler;
cycle_wait_unit_array = (short*) mem_resize(cycle_wait_unit_array, sizeof(short)*arraySize);
}
else
{
//-------- store recno of next blocked unit ----------//
cycle_wait_unit_array[cycle_wait_unit_index++] = blockedUnitPtr->sprite_recno;
locPtr = world.get_loc(nextX, nextY);
err_when(blockedUnitPtr->mobile_type!=mobile_type);
blockedUnitPtr = unit_array[locPtr->unit_recno(mobile_type)];
unitSpriteInfo = blockedUnitPtr->sprite_info;
}
}
}
else
break;
}
//---------- deinit data structure -------//
mem_del(cycle_wait_unit_array);
cycle_wait_unit_array = NULL;
}
if(cycleWait)
{
//----------------------------------------------------------------------//
// shift the recno of all the unit in the cycle
//----------------------------------------------------------------------//
err_when(!is_dir_correct());
short backupSpriteRecno;
world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, 0); // empty the firt node in the cycle
cycle_wait_shift_recno(this, unitPtr); // shift all the unit in the cycle
backupSpriteRecno = world.get_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type);
world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, sprite_recno);
set_next(unitPtr->cur_x, unitPtr->cur_y, -stepMagn, 1);
set_move();
world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, sprite_recno);
world.set_unit_recno(cur_x_loc(), cur_y_loc(), mobile_type, backupSpriteRecno);
swapping = 1;
}
else // not in a cycle
{
set_wait();
//if(waiting_term>=MAX_WAITING_TERM_SAME)
if(waiting_term>=MAX_WAITING_TERM_SAME*move_step_magn())
{
//-----------------------------------------------------------------//
// codes used to speed up frame rate
//-----------------------------------------------------------------//
locPtr = world.get_loc(move_to_x_loc, move_to_y_loc);
if(!locPtr->can_move(mobile_type) && action_mode2!=ACTION_MOVE)
stop(KEEP_PRESERVE_ACTION); // let reactivate..() call searching later
else
search_or_wait();
waiting_term = 0;
}
}
}
//-------- End of function Unit::handle_blocked_wait ---------//
//------ Begin of function Unit::cycle_wait_shift_recno ---------//
// copy recno of curUnit to location where nextUnit on
//
// curUnit -
// nextUnit -
//
void Unit::cycle_wait_shift_recno(Unit* curUnit, Unit* nextUnit)
{
err_when(!curUnit->is_dir_correct() || !nextUnit->is_dir_correct());
int stepMagn = move_step_magn();
Unit *blockedUnitPtr;
Location *locPtr;
//----------- find the next location ------------//
int nextX = nextUnit->cur_x+stepMagn*move_x_pixel_array[nextUnit->final_dir];
int nextY = nextUnit->cur_y+stepMagn*move_y_pixel_array[nextUnit->final_dir];
nextX >>= ZOOM_X_SHIFT_COUNT;
nextY >>= ZOOM_Y_SHIFT_COUNT;
if(nextX != cur_x_loc() || nextY != cur_y_loc())
{
locPtr = world.get_loc(nextX, nextY);
blockedUnitPtr = unit_array[locPtr->unit_recno(nextUnit->mobile_type)];
}
else
blockedUnitPtr = this;
err_when(!blockedUnitPtr);
if(blockedUnitPtr != this)
{
cycle_wait_shift_recno(nextUnit, blockedUnitPtr);
nextUnit->set_next(blockedUnitPtr->cur_x, blockedUnitPtr->cur_y, -stepMagn, 1);
nextUnit->set_move();
world.set_unit_recno(blockedUnitPtr->cur_x_loc(), blockedUnitPtr->cur_y_loc(), nextUnit->mobile_type, nextUnit->sprite_recno);
world.set_unit_recno(nextUnit->cur_x_loc(), nextUnit->cur_y_loc(), nextUnit->mobile_type, 0);
nextUnit->swapping = 1;
}
else // the cycle shift is ended
{
err_when(blockedUnitPtr != this);
err_when(nextUnit->cur_x!=nextUnit->next_x || nextUnit->cur_y!=nextUnit->next_y);
err_when(nextUnit->cur_action != SPRITE_WAIT);
nextUnit->set_next(cur_x, cur_y, -stepMagn, 1);
nextUnit->set_move();
world.set_unit_recno(cur_x_loc(), cur_y_loc(), nextUnit->mobile_type, nextUnit->sprite_recno);
world.set_unit_recno(nextUnit->cur_x_loc(), nextUnit->cur_y_loc(), nextUnit->mobile_type, 0);
nextUnit->swapping = 1;
}
}
//-------- End of function Unit::cycle_wait_shift_recno ---------//
//------ Begin of function Unit::opposite_direction_blocked ---------//
// the two units are oppositely blocked, handle swapping
//
void Unit::opposite_direction_blocked(short vecX, short vecY, short unitPtrVecX, short unitPtrVecY, Unit* unitPtr)
{
//---------------------------------------------------------------------------//
// processing swapping only when both units are exactly in the tiles
//---------------------------------------------------------------------------//
if(unitPtr->cur_action!=SPRITE_IDLE)
{
if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
{
int stepMagn = move_step_magn();
world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, 0);
err_when(!is_dir_correct());
set_next(unitPtr->cur_x, unitPtr->cur_y, -stepMagn, -1);
world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, unitPtr->sprite_recno);
world.set_unit_recno(cur_x_loc(), cur_y_loc(), unitPtr->mobile_type, 0);
err_when(!unitPtr->is_dir_correct());
unitPtr->set_next(cur_x, cur_y, -stepMagn, 1);
world.set_unit_recno(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(), mobile_type, sprite_recno);
world.set_unit_recno(cur_x_loc(), cur_y_loc(), unitPtr->mobile_type, unitPtr->sprite_recno);
set_move();
unitPtr->set_move();
swapping = 1;
unitPtr->swapping = 1;
#ifdef DEBUG
ResultNode* curNode;
curNode = result_node_array + result_node_count - 1;
err_when(curNode->node_x!=move_to_x_loc || curNode->node_y!=move_to_y_loc);
curNode = unitPtr->result_node_array + unitPtr->result_node_count - 1;
err_when(curNode->node_x!=unitPtr->move_to_x_loc || curNode->node_y!=unitPtr->move_to_y_loc);
#endif
}
else
terminate_move();
}
else
{
//----------------------------------------------------------------------//
// If the unit pointed by unitPtr (unit B) has the same unit_id, rank_id
// and both are in the same group, this unit will order the other unit to
// move to its location and this unit will occupy the location of the unit B.
//
// If the above condition is not fulfilled, swapping is processed.
//----------------------------------------------------------------------//
if(unit_id!=unitPtr->unit_id || rank_id!=unitPtr->rank_id || unit_group_id!=unitPtr->unit_group_id)
{
if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
{
//----------------- process swapping ---------------//
set_wait();
unitPtr->set_dir(unitPtr->next_x, unitPtr->next_y, next_x, next_y);
set_dir(next_x, next_y, unitPtr->next_x, unitPtr->next_y);
err_when(unitPtr->result_node_array!=NULL);
unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*2);
ResultNode* nodePtr = unitPtr->result_node_array;
err_when(next_x_loc()!= cur_x_loc() || next_y_loc()!=cur_y_loc());
nodePtr->node_x = next_x_loc();
nodePtr->node_y = next_y_loc();
nodePtr++;
nodePtr->node_x = unitPtr->next_x_loc();
nodePtr->node_y = unitPtr->next_y_loc();
unitPtr->result_node_count = 2;
unitPtr->result_node_recno = 1;
unitPtr->set_wait();
unitPtr->go_x = next_x;
unitPtr->go_y = next_y;
unitPtr->result_path_dist = 2;
err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
swapping = 1;
unitPtr->swapping = 1;
}
else
terminate_move();
}
else
{
//------------ process move_to_my_loc or terminate the movement -----------//
if(unitPtr->move_to_x_loc!=move_to_x_loc || unitPtr->move_to_y_loc!=move_to_y_loc)
move_to_my_loc(unitPtr);
else
terminate_move();
}
#ifdef DEBUG
ResultNode* curNode;
if(result_node_array!=NULL)
{
curNode = result_node_array + result_node_count - 1;
err_when(curNode->node_x!=move_to_x_loc || curNode->node_y!=move_to_y_loc);
}
if(unitPtr->result_node_array!=NULL)
{
curNode = unitPtr->result_node_array + unitPtr->result_node_count - 1;
err_when(curNode->node_x!=unitPtr->move_to_x_loc || curNode->node_y!=unitPtr->move_to_y_loc);
}
#endif
}
}
//-------- End of function Unit::opposite_direction_blocked ---------//
//------ Begin of function Unit::terminate_move -------//
//
// When the sprite has finished moving the next tile in
// the path. If the following tile is blocked and the whole
// movement need to be terminated, this function is called.
//
// When SPRITE_IDLE:
//
// (next_x, next_y) must be == (cur_x, cur_y), it's the location of the sprite.
//
void Unit::terminate_move()
{
#ifdef DEBUG
err_when( next_x != cur_x || next_y != cur_y );
short h, y;
for(h=0, y=cur_y_loc(); hloc_height; h++, y++)
for(short w=0, x=cur_x_loc(); wloc_width; w++, x++)
err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno );
#endif
go_x = next_x;
go_y = next_y;
move_to_x_loc = next_x_loc();
move_to_y_loc = next_y_loc();
#ifdef DEBUG
char blocked=0;
for(h=0, y=next_y_loc(); hloc_height&&!blocked; h++, y++)
for(short w=0, x=next_x_loc(); wloc_width&&!blocked; w++, x++)
blocked = world.get_unit_recno(x,y,mobile_type) != sprite_recno;
err_when(blocked);
#endif
cur_frame = 1;
reset_path();
set_idle();
err_when(result_node_array!=NULL);
}
//------- End of function Unit::terminate_move --------//
//------------- Begin of function Unit::move_to_my_loc --------------//
//
// This function is used as this unit Unit A is blocked by another
// IDLE unit Unit B. Then Unit A will move to the location of Unit B
// and Unit B will move to the location of Unit A want to move to.
//
// Note: action_?_loc2 of both units can be different from their
// move_to_?_loc
//
void Unit::move_to_my_loc(Unit* unitPtr)
{
int unitDestX, unitDestY;
if(unitPtr->action_mode2==ACTION_MOVE)
{
unitDestX = unitPtr->action_x_loc2;
unitDestY = unitPtr->action_y_loc2;
err_when(unitDestX==-1 || unitDestY==-1);
}
else
{
unitDestX = unitPtr->move_to_x_loc;
unitDestY = unitPtr->move_to_y_loc;
}
//--------------- init parameters ---------------//
int unitCurX = unitPtr->next_x_loc();
int unitCurY = unitPtr->next_y_loc();
int destX = action_x_loc2;
int destY = action_y_loc2;
int curX = next_x_loc();
int curY = next_y_loc();
int moveScale = move_step_magn();
err_when(curX != cur_x_loc() || curY != cur_y_loc());
err_when(mobile_type!=unitPtr->mobile_type);
//------------------------------------------------------------------//
// setting for unit pointed by unitPtr
//------------------------------------------------------------------//
if(result_node_array==NULL) //************BUGHERE
{
err_when(unitPtr->cur_action!=SPRITE_IDLE);
unitPtr->move_to(destX, destY, 1); // unit pointed by unitPtr is idle before calling searching
err_when(unitPtr->cur_action!=SPRITE_DIE && unitPtr->action_mode2!=ACTION_MOVE);
}
else
{
err_when(result_node_recno<1 || unitPtr->result_node_array!=NULL);
ResultNode* resultNode = result_node_array+result_node_recno-1;
if(go_x == unitPtr->next_x && go_y == unitPtr->next_y)
{
//------ Unit B is in one of the node of the result_node_array ---//
unitPtr->result_node_count = result_node_count-result_node_recno+1; // at least there are 2 nodes
unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*(unitPtr->result_node_count));
memcpy(unitPtr->result_node_array, resultNode, sizeof(ResultNode)*(unitPtr->result_node_count));
}
else
{
//----- Unit B is in the middle of two nodes in the result_node_array -----//
unitPtr->result_node_count = result_node_count-result_node_recno+2;
unitPtr->result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*(unitPtr->result_node_count));
ResultNode* curNode = unitPtr->result_node_array;
curNode->node_x = unitCurX;
curNode->node_y = unitCurY;
curNode++;
memcpy(curNode, resultNode, sizeof(ResultNode)*(unitPtr->result_node_count-1));
}
err_when(unitPtr->result_node_count<2);
//--------------- set unit action ---------------//
if(unitPtr->action_mode2==ACTION_STOP || unitPtr->action_mode2==ACTION_MOVE) // unitPtr is idle now
{
//---------- activate unit pointed by unitPtr now ------------//
unitPtr->action_mode = unitPtr->action_mode2 = ACTION_MOVE;
unitPtr->action_para = unitPtr->action_para2 = 0;
if(destX!=-1 && destY!=-1)
{
unitPtr->action_x_loc = unitPtr->action_x_loc2 = destX;
unitPtr->action_y_loc = unitPtr->action_y_loc2 = destY;
}
else
{
ResultNode *lastNodePtr = unitPtr->result_node_array + unitPtr->result_node_count - 1;
unitPtr->action_x_loc = unitPtr->action_x_loc2 = lastNodePtr->node_x;
unitPtr->action_y_loc = unitPtr->action_y_loc2 = lastNodePtr->node_y;
}
}
//----------------- set unit movement parameters -----------------//
unitPtr->result_node_recno = 1;
unitPtr->result_path_dist = result_path_dist-moveScale;
unitPtr->move_to_x_loc = move_to_x_loc;
unitPtr->move_to_y_loc = move_to_y_loc;
err_when( next_x != cur_x || next_y != cur_y );
unitPtr->next_move();
#ifdef DEBUG
if(unitPtr->result_node_array!=NULL)
{
ResultNode* curNode1 = unitPtr->result_node_array + unitPtr->result_node_recno - 1;
err_when(curNode1->node_x!=unitPtr->go_x>>ZOOM_X_SHIFT_COUNT || curNode1->node_y!=unitPtr->go_y>>ZOOM_Y_SHIFT_COUNT);
}
#endif
}
//------------------------------------------------------------------//
// setting for this unit
//------------------------------------------------------------------//
int shouldWait = 0;
if(next_x==unitPtr->cur_x && next_y==unitPtr->cur_y)
{
reset_path();
result_path_dist = 0;
}
else
{
terminate_move();
shouldWait++;
result_path_dist = moveScale;
}
go_x = unitPtr->cur_x;
go_y = unitPtr->cur_y;
move_to_x_loc = unitCurX;
move_to_y_loc = unitCurY;
if(action_mode2==ACTION_MOVE)
{
action_x_loc = action_x_loc2 = unitDestX;
action_y_loc = action_y_loc2 = unitDestY;
}
//---------- note: the cur_dir is already the correct direction ---------------//
err_when(result_node_array!=NULL);
result_node_array = (ResultNode*)mem_add(sizeof(ResultNode)*2);
ResultNode* nodePtr = result_node_array;
nodePtr->node_x = curX;
nodePtr->node_y = curY;
nodePtr++;
nodePtr->node_x = unitCurX;
nodePtr->node_y = unitCurY;
result_node_count = 2;
result_node_recno = 2;
if(shouldWait)
set_wait(); // wait for the blocking unit to move first
#ifdef DEBUG
if(result_node_array!=NULL)
{
ResultNode* curNode2 = result_node_array + result_node_recno - 1;
err_when(curNode2->node_x!=go_x>>ZOOM_X_SHIFT_COUNT || curNode2->node_y!=go_y>>ZOOM_Y_SHIFT_COUNT);
}
#endif
err_when(cur_action==SPRITE_IDLE && (move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc()));
err_when(cur_action==SPRITE_IDLE && (cur_x!=next_x || cur_y!=next_y));
err_when(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->move_to_x_loc!=unitPtr->next_x_loc() ||
unitPtr->move_to_y_loc!=unitPtr->next_y_loc()));
}
//----------------- End of function Unit::move_to_my_loc ----------------//
//###### begin trevor 25/6 #######//
/*
//------------- Begin of function Unit::change_relation --------------//
void Unit::change_relation(short nation1, short nation2, int relationType)
{
if(!nation1 || !nation2 || nation1==nation2)
return; // return if either is neutral nation or same nation
nation_array[nation1]->set_relation_status(nation2, relationType);
}
//----------------- End of function Unit::change_relation ----------------//
*/
//####### end trevor 25/6 ########//
//------------- Begin of function Unit::set_idle --------------//
// set parameters for unit idle
//
void Unit::set_idle()
{
/*err_when(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP &&
(((UnitMarine*)this)->extra_move_in_beach==EXTRA_MOVING_IN ||
((UnitMarine*)this)->extra_move_in_beach==EXTRA_MOVING_OUT));*/
err_when(cur_x<0);
err_when(move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc());
err_when(cur_x!=next_x || cur_y!=next_y || next_x!=go_x || next_y!=go_y);
err_when(cur_x%ZOOM_LOC_WIDTH || cur_y%ZOOM_LOC_HEIGHT);
err_when(result_path_dist || result_node_array);
err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
final_dir = cur_dir;
turn_delay = 0;
cur_action = SPRITE_IDLE;
}
//----------------- End of function Unit::set_idle ----------------//
//------------- Begin of function Unit::set_ready --------------//
// set parameters for unit ready to move
//
void Unit::set_ready()
{
err_when(cur_x<0);
err_when(move_to_x_loc!=next_x_loc() || move_to_y_loc!=next_y_loc());
err_when(cur_x!=next_x || cur_y!=next_y || next_x!=go_x || next_y!=go_y);
err_when(cur_x%ZOOM_LOC_WIDTH || cur_y%ZOOM_LOC_HEIGHT);
err_when(cur_dir<0 || cur_dir>MAX_SPRITE_DIR_TYPE);
final_dir = cur_dir;
turn_delay = 0;
cur_action = SPRITE_READY_TO_MOVE;
}
//----------------- End of function Unit::set_ready ----------------//
//------------- Begin of function Unit::set_move --------------//
// set parameters for unit movement
//
void Unit::set_move()
{
err_when(cur_x<0);
err_when(cur_dir!=final_dir);
cur_action = SPRITE_MOVE;
}
//----------------- End of function Unit::set_move ----------------//
//------------- Begin of function Unit::set_wait --------------//
// Set the unit to waiting status.
// When SPRITE_WAIT:
// (next_x, next_y) must be == (cur_x, cur_y), it's the location of the sprite.
//
void Unit::set_wait()
{
err_when(cur_x<0);
#ifdef DEBUG
err_when(go_x==cur_x && go_y==cur_y);
err_when( next_x != cur_x || next_y != cur_y );
short w, h, x, y;
for(h=0, y=cur_y_loc(); hloc_height; h++, y++)
for(w=0, x=cur_x_loc(); wloc_width; w++, x++)
err_when( world.get_unit_recno(x, y, mobile_type) != sprite_recno );
err_when((check_unit_dir1=get_dir(cur_x, cur_y, go_x, go_y))!=final_dir);
#endif
cur_action = SPRITE_WAIT;
cur_frame = 1;
waiting_term++;
}
//----------------- End of function Unit::set_wait ----------------//
//------------- Begin of function Unit::set_attack --------------//
// set parameters for unit attack
//
void Unit::set_attack()
{
err_when(cur_x<0);
err_when(next_x!=cur_x || next_y!=cur_y);
err_when(cur_dir<0 || cur_dir>=MAX_SPRITE_DIR_TYPE || turn_delay);
final_dir = cur_dir;
turn_delay = 0;
cur_action = SPRITE_ATTACK;
}
//----------------- End of function Unit::set_attack ----------------//
//------------- Begin of function Unit::set_turn --------------//
// set parameters for unit turning
//
void Unit::set_turn()
{
err_when(cur_x<0);
err_when(next_x!=cur_x || next_y!=cur_y);
cur_action = SPRITE_TURN;
}
//----------------- End of function Unit::set_turn ----------------//
//------------- Begin of function Unit::set_ship_extra_move --------------//
// set parameters for ship extra moving in inlet
//
void Unit::set_ship_extra_move()
{
err_when(cur_x<0);
cur_action = SPRITE_SHIP_EXTRA_MOVE;
}
//----------------- End of function Unit::set_ship_extra_move ----------------//
//------------- Begin of function Unit::set_die --------------//
// set parameters for unit die
//
void Unit::set_die()
{
if( action_mode == ACTION_DIE )
return;
err_when(hit_points>0);
action_mode = ACTION_DIE;
cur_action = SPRITE_DIE;
cur_frame = 1;
//##### begin trevor 19/7 #####//
//---- if this unit is led by a leader, only mobile units has leader_unit_recno assigned to a leader -----//
if( leader_unit_recno && !unit_array.is_deleted(leader_unit_recno) ) // the leader unit may have been killed at the same time
{
unit_array[leader_unit_recno]->del_team_member(sprite_recno);
leader_unit_recno = 0;
}
//##### end trevor 19/7 #####//
}
//----------------- End of function Unit::set_die ----------------//