/*
* 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 : OUNITAAC.CPP
//Description : Object UnitArray - misc functions
#include
#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
//--------- Begin of function UnitArray::divide_array ---------//
// divide units into arrays by their mobile_type
//
// excludeSelectedLocUnit - (default 0)
//
void UnitArray::divide_array(int locX, int locY, short* selectedArray, int selectedCount, int excludeSelectedLocUnit)
{
err_when( selectedCount < 0 );
selected_land_unit_count = 0;
selected_sea_unit_count = 0;
selected_air_unit_count = 0;
selected_land_unit_array = NULL;
selected_sea_unit_array = NULL;
selected_air_unit_array = NULL;
int unitRecno;
if(excludeSelectedLocUnit)
{
Location *locPtr = world.get_loc(locX, locY);
short targetMobileType = locPtr->has_any_unit();
unitRecno = targetMobileType ? locPtr->unit_recno(targetMobileType) : 0;
}
selected_land_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
selected_sea_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
selected_air_unit_array = (short*) mem_add(sizeof(short)*selectedCount);
memset(selected_land_unit_array, 0, sizeof(short)*selectedCount);
memset(selected_sea_unit_array, 0, sizeof(short)*selectedCount);
memset(selected_air_unit_array, 0, sizeof(short)*selectedCount);
Unit *unitPtr;
int curRecno;
for(int i=0; imobile_type)
{
case UNIT_LAND:
selected_land_unit_array[selected_land_unit_count++] = curRecno;
break;
case UNIT_SEA:
selected_sea_unit_array[selected_sea_unit_count++] = curRecno;
break;
case UNIT_AIR:
selected_air_unit_array[selected_air_unit_count++] = curRecno;
break;
default: err_here();
break;
}
}
}
//----------- End of function UnitArray::divide_array -----------//
//--------- Begin of function UnitArray::set_group_id ---------//
// Set group id for the selected units
//
void UnitArray::set_group_id(short* selectedArray, int selectedCount)
{
//-------------------------------------------------//
// set unit cur_action and unit_group_id
//-------------------------------------------------//
DWORD curGroupId = unit_array.cur_group_id++;
for(int j=0; jis_visible());
err_when(unitPtr->hit_points<=0);
unitPtr->unit_group_id = curGroupId;
err_if(unitPtr->cur_action==SPRITE_IDLE && (unitPtr->cur_x!=unitPtr->next_x || unitPtr->cur_y!=unitPtr->next_y))
err_here();
if( unitPtr->cur_action == SPRITE_IDLE ) //**maybe need to include SPRITE_ATTACK as well
unitPtr->set_ready();
}
}
//----------- End of function UnitArray::set_group_id -----------//
//--------- Begin of function UnitArray::stop ---------//
//
// selectedUnitArray - an array of recno of selected units.
// (the array should be terminated with 0)
// selectedCount - no. of selected units.
// [char] remoteAction - whether this is an action carried out by a remote machine or not.
// (default: 0)
//
void UnitArray::stop(short* selectedUnitArray, int selectedCount, char remoteAction)
{
//-------- if it's a multiplayer game --------//
//
// Queue the action.
//
// Local: this action will be processed when all action messages of all
// remote players are ready from the next frame.
//
// Remote: this action will be processed when the remote has received
// frame sync notification from all other players.
//
//--------------------------------------------//
if( !remoteAction && remote.is_enable() )
{
short* shortPtr = (short*) remote.new_send_queue_msg(MSG_UNIT_STOP,
sizeof(short) * (1+selectedCount) );
shortPtr[0] = selectedCount;
memcpy( shortPtr+1, selectedUnitArray, sizeof(short) * selectedCount );
}
else
{
DWORD curGroupId = unit_array.cur_group_id++;
//-------------- stop now ---------------//
err_when( selectedCount > 10000 ); // error
Unit* unitPtr;
for( int i=0 ; iunit_group_id = curGroupId;
unitPtr->stop2();
}
}
}
//----------- End of function UnitArray::stop -----------//
//--------- Begin of function UnitArray::stop_all_war ---------//
// Stop all the units that is in war with the specified nation
// and stop all the units of the specified nation that is in war
// with other nations
//
// oldNationReno - the nation_renco of the specified nation
//
void UnitArray::stop_all_war(short oldNationRecno)
{
Unit *unitPtr, *targetUnit;
Firm *targetFirm;
Town *targetTown;
Location *targetLoc;
char targetType;
short targetRecno;
int targetXLoc, targetYLoc;
for(int i=size(); i>0; --i)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
if(!unitPtr->is_visible())
continue;
if(unitPtr->nation_recno==oldNationRecno)
{
//------ stop all attacking unit with nation_recno = oldNationRecno -----//
if(unitPtr->is_action_attack())
unitPtr->stop2(KEEP_DEFENSE_MODE);
}
else if(unitPtr->is_action_attack())
{
//---- stop all attacking unit with target's nation_recno = oldNationRecno ----//
if(unitPtr->action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
{
targetType = unitPtr->action_mode;
targetRecno = unitPtr->action_para;
targetXLoc = unitPtr->action_x_loc;
targetYLoc = unitPtr->action_y_loc;
}
else
{
targetType = unitPtr->action_mode2;
targetRecno = unitPtr->action_para2;
targetXLoc = unitPtr->action_x_loc2;
targetYLoc = unitPtr->action_y_loc2;
}
switch(targetType)
{
case ACTION_ATTACK_UNIT:
case ACTION_DEFEND_TOWN_ATTACK_TARGET:
case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
if(is_deleted(targetRecno))
continue;
targetUnit = operator[](targetRecno);
if(targetUnit->nation_recno==oldNationRecno)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_FIRM:
if(firm_array.is_deleted(targetRecno))
continue;
targetFirm = firm_array[targetRecno];
if(targetFirm->nation_recno==oldNationRecno)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_TOWN:
if(town_array.is_deleted(targetRecno))
continue;
targetTown = town_array[targetRecno];
if(targetTown->nation_recno==oldNationRecno)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_WALL:
targetLoc = world.get_loc(targetXLoc, targetYLoc);
if(targetLoc->wall_nation_recno()==oldNationRecno)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
}
}
}
}
//----------- End of function UnitArray::stop_all_war -----------//
//--------- Begin of function UnitArray::stop_war_between ---------//
// stop the war between the two nations specified
//
// nationReno1 - the nation_renco of one of the nation
// nationReno2 - the nation_renco of the other nation
//
void UnitArray::stop_war_between(short nationRecno1, short nationRecno2)
{
Unit *unitPtr, *targetUnit;
Firm *targetFirm;
Town *targetTown;
Location *targetLoc;
char targetType;
short targetRecno;
int targetXLoc, targetYLoc;
for(int i=size(); i>0; --i)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
if(!unitPtr->is_visible())
continue;
if(unitPtr->nation_recno!=nationRecno1 && unitPtr->nation_recno!=nationRecno2)
continue;
if(unitPtr->is_action_attack())
{
//---- stop all attacking unit with target's nation_recno = oldNationRecno ----//
if(unitPtr->action_mode2==ACTION_AUTO_DEFENSE_ATTACK_TARGET)
{
targetType = unitPtr->action_mode;
targetRecno = unitPtr->action_para;
targetXLoc = unitPtr->action_x_loc;
targetYLoc = unitPtr->action_y_loc;
}
else
{
targetType = unitPtr->action_mode2;
targetRecno = unitPtr->action_para2;
targetXLoc = unitPtr->action_x_loc2;
targetYLoc = unitPtr->action_y_loc2;
}
switch(targetType)
{
case ACTION_ATTACK_UNIT:
case ACTION_DEFEND_TOWN_ATTACK_TARGET:
case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
if(is_deleted(targetRecno))
continue;
targetUnit = operator[](targetRecno);
if(targetUnit->nation_recno==nationRecno1 || targetUnit->nation_recno==nationRecno2)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_FIRM:
if(firm_array.is_deleted(targetRecno))
continue;
targetFirm = firm_array[targetRecno];
if(targetFirm->nation_recno==nationRecno1 || targetFirm->nation_recno==nationRecno2)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_TOWN:
if(town_array.is_deleted(targetRecno))
continue;
targetTown = town_array[targetRecno];
if(targetTown->nation_recno==nationRecno1 || targetTown->nation_recno==nationRecno2)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
case ACTION_ATTACK_WALL:
targetLoc = world.get_loc(targetXLoc, targetYLoc);
if(targetLoc->wall_nation_recno()==nationRecno1 || targetLoc->wall_nation_recno()==nationRecno2)
unitPtr->stop2(KEEP_DEFENSE_MODE);
break;
}
}
}
}
//----------- End of function UnitArray::stop_war_between -----------//
//--------- Begin of function UnitArray::stop_attack_unit ---------//
// stop all units that is attacking the specified unit
//
// unitRecno - unit_recno of the specified unit
//
void UnitArray::stop_attack_unit(short unitRecno)
{
if(nation_hand_over_flag)
return;
Unit *unitPtr;
for(int i=size(); i>0; --i)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
if(!unitPtr->is_visible())
continue;
if((unitPtr->action_para==unitRecno && unitPtr->action_mode==ACTION_ATTACK_UNIT) ||
(unitPtr->action_para2==unitRecno && unitPtr->action_mode2==ACTION_ATTACK_UNIT))
unitPtr->stop2(KEEP_DEFENSE_MODE);
}
}
//----------- End of function UnitArray::stop_attack_unit -----------//
//--------- Begin of function UnitArray::stop_attack_firm ---------//
// stop all units that is attacking the specified firm
//
// firmRecno - the firm_recno of the firm
//
void UnitArray::stop_attack_firm(short firmRecno)
{
if(nation_hand_over_flag)
return;
Unit *unitPtr;
for(int i=size(); i>0; --i)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
if(!unitPtr->is_visible())
continue;
if((unitPtr->action_para==firmRecno && unitPtr->action_mode==ACTION_ATTACK_FIRM) ||
(unitPtr->action_para2==firmRecno && unitPtr->action_mode2==ACTION_ATTACK_FIRM))
unitPtr->stop2(KEEP_DEFENSE_MODE);
}
}
//----------- End of function UnitArray::stop_attack_firm -----------//
//--------- Begin of function UnitArray::stop_attack_town ---------//
// stop all units that is attacking the specified town
//
// townRecno - the town_recno of the specified town
//
void UnitArray::stop_attack_town(short townRecno)
{
if(nation_hand_over_flag)
return;
Unit *unitPtr;
for(int i=size(); i>0; --i)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
if(!unitPtr->is_visible())
continue;
if((unitPtr->action_para==townRecno && unitPtr->action_mode==ACTION_ATTACK_TOWN) ||
(unitPtr->action_para2==townRecno && unitPtr->action_mode2==ACTION_ATTACK_TOWN))
unitPtr->stop2(KEEP_DEFENSE_MODE);
}
}
//----------- End of function UnitArray::stop_attack_town -----------//
//--------- Begin of function UnitArray::assign ---------//
// group assign to firm/town/unit
//
// destX - x location assigned to
// destY - y location assigned to
// divided - whether the array is divied by divide_array(...) (1 - divided, 0 not)
// remoteAction -
// [short*] selectedArray - unit_recno of the selected units (default: NULL)
// [int] selectedCount - number of selected units (default: 0)
//
void UnitArray::assign(int destX, int destY, int divided, char remoteAction, short* selectedArray, int selectedCount)
{
err_when(destX<0 || destY<0 || destX>MAX_WORLD_X_LOC-1 || destY>MAX_WORLD_Y_LOC-1);
//###### begin trevor 25/8 #######//
//--- set the destination to the top left position of the town/firm ---//
Location* locPtr = world.get_loc(destX, destY);
//---- if there is a firm on this location -----//
if( locPtr->is_firm() )
{
Firm* firmPtr = firm_array[locPtr->firm_recno()];
destX = firmPtr->loc_x1;
destY = firmPtr->loc_y1;
}
//---- if there is a town on this location -----//
else if( locPtr->is_town() )
{
Town* townPtr = town_array[locPtr->town_recno()];
destX = townPtr->loc_x1;
destY = townPtr->loc_y1;
}
//###### end trevor 25/8 #######//
//-------------------------------------------//
Unit* unitPtr;
int freeMemory = 0;
if( selectedArray == NULL)
{
selectedArray = (short*) mem_add(sizeof(short)*size());
selectedCount = 0;
freeMemory = 1;
// find myself
for(int i=size(); i>0; i--)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
//err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
if(!unitPtr->is_visible())
continue;
if( unitPtr->selected_flag && unitPtr->is_own() )
{
err_when(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE);
selectedArray[selectedCount++] = i;
}
}
}
if(!remoteAction && remote.is_enable())
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_ASSIGN,
sizeof(short) * (4+selectedCount));
shortPtr[0] = destX;
shortPtr[1] = destY;
shortPtr[2] = selectedCount;
shortPtr[3] = divided;
memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);
}
else
{
if(!divided)
{
for(int j=0; j< selectedCount; ++j)
{
int i = selectedArray[j];
if(is_deleted(i))
continue;
unitPtr = operator[](i); //unit_array[i];
//### begin trevor 7/7#######//
err_when(!unitPtr->is_visible() );
err_when( unitPtr->hit_points<=0 );
//### end trevor 7/7#######//
unitPtr->stop2();
}
//--------- divide the unit by their mobile_type ------------//
divide_array(destX, destY, selectedArray, selectedCount);
if(selected_land_unit_count)
assign(destX, destY, 1, remoteAction, selected_land_unit_array, selected_land_unit_count);
if(selected_sea_unit_count)
{
Location *locPtr = world.get_loc(destX, destY);
if(locPtr->is_firm())
{
err_when(firm_array.is_deleted(locPtr->firm_recno()));
Firm *firmPtr = firm_array[locPtr->firm_recno()];
if(firmPtr->firm_id==FIRM_HARBOR) // recursive call
assign(destX, destY, 1, remoteAction, selected_sea_unit_array, selected_sea_unit_count);
else
ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
}
//else if(locPtr->is_town())
else
{
err_when(town_array.is_deleted(locPtr->town_recno()));
ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
}
}
if(selected_air_unit_count) // no assign for air units
move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);
//------------ deinit static variables ------------//
selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
mem_del(selected_land_unit_array);
mem_del(selected_sea_unit_array);
mem_del(selected_air_unit_array);
}
else
{
//---------- set unit to assign -----------//
if(selectedCount<2)
{
unitPtr = (Unit*) get_ptr(selectedArray[0]);
err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
if(unitPtr->sprite_info->loc_width<=1)
{
unitPtr->unit_group_id = unit_array.cur_group_id++;
unitPtr->assign(destX, destY);
}
else // move to object surrounding
{
Location *locPtr = world.get_loc(destX, destY);
if(locPtr->is_firm())
unitPtr->move_to_firm_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height, locPtr->firm_recno());
else if(locPtr->is_town())
unitPtr->move_to_town_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height);
else if(locPtr->has_unit(UNIT_LAND))
unitPtr->move_to_unit_surround(destX, destY, unitPtr->sprite_info->loc_width, unitPtr->sprite_info->loc_height, locPtr->unit_recno(UNIT_LAND));
}
}
else // for more than one unit selecting, call group_assign() to take care of it
{
set_group_id(selectedArray, selectedCount);
group_assign(destX, destY, selectedArray, selectedCount);
}
}
}
if( freeMemory )
mem_del(selectedArray);
}
//----------- End of function UnitArray::assign -----------//
//--------- Begin of function UnitArray::group_assign ---------//
// destX - x location assigned to
// destY - y location assigned to
// selectedArray - unit recno of the selected units
// selectedCount - num of selected units
//
void UnitArray::group_assign(int destX, int destY, short* selectedArray, int selectedCount)
{
enum { ASSIGN_TYPE_UNIT = 1,
ASSIGN_TYPE_FIRM,
ASSIGN_TYPE_TOWN,
};
Location *locPtr = world.get_loc(destX, destY);
int assignType = 0; // 1 for unit, 2 for firm, 3 for town
int miscNo = 0; // usedd to store the recno of the object
if(locPtr->has_unit(UNIT_LAND))
{
assignType = ASSIGN_TYPE_UNIT;
miscNo = locPtr->unit_recno(UNIT_LAND);
}
else if(locPtr->is_firm())
{
assignType = ASSIGN_TYPE_FIRM;
miscNo = firm_array[locPtr->firm_recno()]->firm_id;
}
else if(locPtr->is_town())
{
assignType = ASSIGN_TYPE_TOWN;
miscNo = 0;
}
else
err_here();
Unit* unitPtr;
for(int i=0; iis_visible() || unitPtr->hit_points<=0);
if(unitPtr->sprite_info->loc_width<=1)
unitPtr->assign(destX, destY, i+1); // the thrid parameter is used to generate different result for the searching
else
{
//-----------------------------------------------------------------//
// for 2x2 unit, unable to assign, so move to the surrounding
//-----------------------------------------------------------------//
switch(assignType)
{
case ASSIGN_TYPE_UNIT:
unitPtr->move_to_unit_surround(destX, destY, unitPtr->sprite_info->loc_width,
unitPtr->sprite_info->loc_height, miscNo);
break; // is a unit
case ASSIGN_TYPE_FIRM:
unitPtr->move_to_firm_surround(destX, destY, unitPtr->sprite_info->loc_width,
unitPtr->sprite_info->loc_height, miscNo);
break; // is a firm
case ASSIGN_TYPE_TOWN:
unitPtr->move_to_town_surround(destX, destY, unitPtr->sprite_info->loc_width,
unitPtr->sprite_info->loc_height);
break; // is a town
default: err_here();
break;
}
}
}
}
//----------- End of function UnitArray::group_assign -----------//
//--------- Begin of function UnitArray::assign_to_camp ---------//
// destX - x location where the camp is
// destY - y location where the camp is
// remoteAction -
// [short*] selectedUnitArray - recno of the selected units (default: NULL)
// [int] selectedCount - number of selected units (default: 0)
//
void UnitArray::assign_to_camp(int destX, int destY, char remoteAction, short* selectedUnitArray, int selectedCount)
{
divide_array(destX, destY, selectedUnitArray, selectedCount);
if(selected_land_unit_count)
{
int assignCount=0, moveCount=0;
short *assignArray = (short*) mem_add(sizeof(short)*selected_land_unit_count);
short *moveArray = (short*) mem_add(sizeof(short)*selected_land_unit_count);
char unitClass;
Unit *unitPtr;
memset(assignArray, 0, sizeof(short)*selected_land_unit_count);
memset(moveArray, 0, sizeof(short)*selected_land_unit_count);
//----------------------------------------------------------------//
// Only human and weapon can be assigned to the camp. Others are
// ordered to move to camp as close as possible.
//----------------------------------------------------------------//
for(int i=0; iunit_id]->unit_class;
if(unitClass==UNIT_CLASS_HUMAN || unitClass==UNIT_CLASS_WEAPON)
assignArray[assignCount++] = selectedUnitArray[i];
else
moveArray[moveCount++] = selectedUnitArray[i];
}
if(assignCount)
assign(destX, destY, 1, remoteAction, assignArray, assignCount);
if(moveCount)
move_to(destX, destY, 1, moveArray, moveCount, remoteAction);
mem_del(assignArray);
mem_del(moveArray);
}
if(selected_sea_unit_count)
ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
if(selected_air_unit_count)
move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);
//---------------- deinit static parameters ---------------//
selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
mem_del(selected_land_unit_array);
mem_del(selected_sea_unit_array);
mem_del(selected_air_unit_array);
}
//----------- End of function UnitArray::assign_to_camp -----------//
//--------- Begin of function UnitArray::settle ---------//
// destX - x location settle to
// destY - y location settle to
// divided - whether the selected is divided into subgroup, (1 = divided, 0 = not)
// remoteAction -
// [short*] selectedArray - the recno of the selected units (default: NULL)
// [int] selectedCount - num of selected units (default: 0)
//
void UnitArray::settle(int destX, int destY, int divided, char remoteAction, short* selectedArray, int selectedCount)
{
Unit* unitPtr;
int freeMemory = 0;
if(selectedArray == NULL)
{
selectedArray = (short*) mem_add(sizeof(short)*size());
selectedCount = 0;
freeMemory = 1;
// find myself
for(int i=size(); i>0; i--)
{
if(is_deleted(i))
continue;
unitPtr = operator[](i);
//err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
if(!unitPtr->is_visible())
continue;
if( unitPtr->selected_flag && unitPtr->is_own() )
{
err_when(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode==ACTION_DIE);
selectedArray[selectedCount++] = i;
}
}
}
if(!remoteAction && remote.is_enable())
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_SETTLE, sizeof(short)*(4+selectedCount));
shortPtr[0] = destX;
shortPtr[1] = destY;
shortPtr[2] = selectedCount;
shortPtr[3] = divided;
memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);
}
else
{
if(!divided)
{
for(int j=0; j< selectedCount; ++j)
{
int i = selectedArray[j];
if(is_deleted(i))
continue;
unitPtr = operator[](i); //unit_array[i];
err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
unitPtr->stop2();
}
divide_array(destX, destY, selectedArray, selectedCount);
if(selected_land_unit_count)
settle(destX, destY, 1, remoteAction, selected_land_unit_array, selected_land_unit_count);
if(selected_sea_unit_count)
ship_to_beach(destX, destY, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
if(selected_air_unit_count)
move_to(destX, destY, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);
//-------------- deinit static parameters --------------//
selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
mem_del(selected_land_unit_array);
mem_del(selected_sea_unit_array);
mem_del(selected_air_unit_array);
}
else
{
//---------- set unit to settle -----------//
if(selectedCount<2)
{
unitPtr = (Unit*) get_ptr(selectedArray[0]);
err_when(!unitPtr->is_visible() || unitPtr->hit_points<=0);
unitPtr->unit_group_id = unit_array.cur_group_id++;
unitPtr->settle(destX, destY);
}
else
{
set_group_id(selectedArray, selectedCount);
group_settle(destX, destY, selectedArray, selectedCount);
}
}
}
if(freeMemory)
mem_del(selectedArray);
}
//----------- End of function UnitArray::settle -----------//
//--------- Begin of function UnitArray::group_settle ---------//
// destX - x location to settle to
// destY - y location to settle to
// selectedArray - recno. of selected units
// selectedCount - num. of selected units
//
void UnitArray::group_settle(int destX, int destY, short* selectedArray, int selectedCount)
{
#ifdef DEBUG
DWORD debugGroupId = (operator[](selectedArray[0]))->unit_group_id;
#endif
Unit* unitPtr;
for(int i=0; iis_visible() || unitPtr->hit_points<=0);
#ifdef DEBUG
err_when(unitPtr->unit_group_id!=debugGroupId);
#endif
unitPtr->settle(destX, destY, i+1);
}
}
//----------- End of function UnitArray::group_settle -----------//
//--------- Begin of function UnitArray::assign_to_ship ---------//
// shipXLoc - x location of the ship
// shipYLoc - y location of the ship
// divided - whether the selected groups is divided (1 - divided, 0 - not)
// selectedArray - recno of selected units
// selectedCount - num. of selected units
// remoteAction -
//
void UnitArray::assign_to_ship(int shipXLoc, int shipYLoc, int divided, short* selectedArray, int selectedCount, char remoteAction, int shipRecno)
{
err_when(terrain_res[world.get_loc(shipXLoc, shipYLoc)->terrain_id]->average_type!=TERRAIN_OCEAN);
err_when(!selectedCount || selectedCount>1000);
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_ASSIGN_TO_SHIP,
sizeof(short) * (5+selectedCount));
shortPtr[0] = shipXLoc;
shortPtr[1] = shipYLoc;
shortPtr[2] = shipRecno;
shortPtr[3] = selectedCount;
shortPtr[4] = divided;
memcpy(shortPtr+5, selectedArray, sizeof(short)*selectedCount);
return;
}
if(!divided)
{
divide_array(shipXLoc, shipYLoc, selectedArray, selectedCount);
if(selected_sea_unit_count) // Note: the order to call ship unit first
move_to(shipXLoc, shipYLoc, 1, selected_sea_unit_array, selected_sea_unit_count, remoteAction);
if(selected_land_unit_count)
assign_to_ship(shipXLoc, shipYLoc, 1, selected_land_unit_array, selected_land_unit_count, remoteAction, shipRecno);
if(selected_air_unit_count)
move_to(shipXLoc, shipYLoc, 1, selected_air_unit_array, selected_air_unit_count, remoteAction);
//---------------- deinit static parameters -----------------//
selected_land_unit_count = selected_sea_unit_count = selected_air_unit_count = 0;
mem_del(selected_land_unit_array);
mem_del(selected_sea_unit_array);
mem_del(selected_air_unit_array);
return;
}
else
{
// ###### begin Gilbert 5/8 ##########//
// ----- dont not use shipXLoc, shipYLoc passed, use shipRecno --------//
UnitMarine *shipPtr = (UnitMarine*) get_ptr(shipRecno);
if( shipPtr && shipPtr->is_visible() )
{
shipXLoc = shipPtr->next_x_loc();
shipYLoc = shipPtr->next_y_loc();
}
else
return;
// ##### patch end Gilbert 5/8 #######//
//------------------------------------------------------------------------------------//
// find the closest unit to the ship
//------------------------------------------------------------------------------------//
int minDist=0x7FFFFF, dist, distX, distY;
int closestUnitRecno = -1;
Unit *unitPtr;
int i;
for(i=0; inext_x_loc());
distY = abs(shipYLoc - unitPtr->next_y_loc());
dist = (distX>distY) ? distX : distY;
if(dist < minDist)
{
minDist = dist;
closestUnitRecno = i;
}
}
err_when(closestUnitRecno==-1);
//------------------------------------------------------------------------------------//
// If the seleceted units are distributed on different territories, select those unit
// on the same territory as the closet unit for processing, there will be no action for
// the rest units.
//------------------------------------------------------------------------------------//
DWORD curGroupId = unit_array.cur_group_id++;
Unit *closestUnit = (Unit*) get_ptr(selectedArray[closestUnitRecno]);
int closestUnitXLoc = closestUnit->next_x_loc();
int closestUnitYLoc = closestUnit->next_y_loc();
unsigned char defaultRegionId = world.get_loc(closestUnitXLoc, closestUnitYLoc)->region_id;
short *newSelectedArray;
int newSelectedCount = 0;
if(selectedCount>1)
{
newSelectedArray = (short*) mem_add(sizeof(short)*selectedCount);
memset(newSelectedArray, 0, sizeof(short)*selectedCount);
for(i=0; inext_x_loc(), unitPtr->next_y_loc())->region_id == defaultRegionId)
{
newSelectedArray[newSelectedCount++] = selectedArray[i]; // on the same territory
unitPtr->unit_group_id = curGroupId;
}
if(unitPtr->cur_action==SPRITE_IDLE)
unitPtr->set_ready();
}
err_when(newSelectedCount > selectedCount);
}
else
{
err_when(closestUnit->sprite_recno!=selectedArray[0]);
newSelectedArray = (short*) mem_add(sizeof(short)); // only one unit
newSelectedArray[0] = selectedArray[0];
newSelectedCount = 1;
closestUnit->unit_group_id = curGroupId;
}
//-------------- ordering the ship move near the coast ----------------//
int curXLoc = closestUnit->next_x_loc();
int curYLoc = closestUnit->next_y_loc();
// ##### patch begin Gilbert 5/8 #######//
// UnitMarine *shipPtr = (UnitMarine*) get_ptr(world.get_unit_recno(shipXLoc, shipYLoc, UNIT_SEA));
// ##### patch end Gilbert 5/8 #######//
int landX, landY;
shipPtr->unit_group_id = curGroupId;
shipPtr->ship_to_beach(curXLoc, curYLoc, landX, landY);
if(landX!=-1 && landY!=-1)
{
//-------------- ordering the units ---------------//
#define TRY_SIZE 5
int countLimit = TRY_SIZE*TRY_SIZE;
//### begin alex 30/10 ###//
int j, k, xShift, yShift, checkXLoc, checkYLoc;
UCHAR regionId = world.get_loc(landX, landY)->region_id;
Location *locPtr;
for(i=0, k=0; icountLimit)
k = 1;
m.cal_move_around_a_point(k, TRY_SIZE, TRY_SIZE, xShift, yShift);
checkXLoc = landX+xShift;
checkYLoc = landY+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->region_id!=regionId || !locPtr->can_move(UNIT_LAND))
continue;
unitPtr = (Unit*) get_ptr(newSelectedArray[i]);
unitPtr->assign_to_ship(landX, landY, shipPtr->sprite_recno, k);
break;
}
}
//#### end alex 30/10 ####//
}
mem_del(newSelectedArray);
}
}
//----------- End of function UnitArray::assign_to_ship -----------//
//--------- Begin of function UnitArray::ship_to_beach ---------//
// destX - x location the ship move to
// destY - y location the ship move to
// divided - whether the units are divided (1 - divided, 0 - not)
// selectedArray - the recno. of the selected units
// selectedCount - num. of selected units
// remoteAction -
//
void UnitArray::ship_to_beach(int destX, int destY, int divided, short* selectedArray, int selectedCount, char remoteAction)
{
Unit *unitPtr;
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNITS_SHIP_TO_BEACH,
sizeof(short) * (4+selectedCount));
shortPtr[0] = destX;
shortPtr[1] = destY;
shortPtr[2] = selectedCount;
shortPtr[3] = divided;
memcpy(shortPtr+4, selectedArray, sizeof(short)*selectedCount);
return;
}
set_group_id(selectedArray, selectedCount);
//--------------------------------------------------------------------//
//--------------------------------------------------------------------//
#define CHECK_SEA_DIMENSION 50
#define CHECK_SEA_SIZE CHECK_SEA_DIMENSION*CHECK_SEA_DIMENSION
Location *locPtr = world.get_loc(destX, destY);
UCHAR regionId = locPtr->region_id;
int xShift, yShift, checkXLoc, checkYLoc;
int landX, landY, seaX, seaY, tempX, tempY;
int j=1, k, found;
//--------------------------------------------------------------------//
// find a unit that can carrying units. Let it to do the first searching.
// Use the returned reference parameters (landX, landY) for the other
// ships to calculate their final location to move to
//--------------------------------------------------------------------//
int i;
for(i=0; iunit_id]->carry_unit_capacity>0)
{
unitPtr->ship_to_beach(destX, destY, landX, landY); // landX=landY=-1 if calling move_to() instead
i++;
break;
}
else
unitPtr->move_to(destX, destY, 1);
}
int totalCheck = 0;
for(; iunit_id]->carry_unit_capacity>0 && landX!=-1 && landY!=-1)
{
for(found=0; j<=CHECK_SEA_SIZE; j++, totalCheck++)
{
m.cal_move_around_a_point(j, CHECK_SEA_DIMENSION, CHECK_SEA_DIMENSION, xShift, yShift);
if(j>=CHECK_SEA_SIZE)
j = 1;
if(totalCheck == CHECK_SEA_SIZE)
{
//--------------------------------------------------------------------//
// can't handle this case
//--------------------------------------------------------------------//
unitPtr->ship_to_beach(landX, landY, tempX, tempY);
totalCheck = 0;
break;
}
seaX = landX+xShift;
seaY = landY+yShift;
if(seaX<0 || seaX>=MAX_WORLD_X_LOC || seaY<0 || seaY>=MAX_WORLD_Y_LOC)
continue;
locPtr = world.get_loc(seaX, seaY);
if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN)
continue;
//--------------------------------------------------------------------//
// if it is able to find a location around the surrounding location with
// same region id we prefer, order the unit to move there.
//--------------------------------------------------------------------//
for(k=2; k<=9; k++)
{
m.cal_move_around_a_point(k, 3, 3, xShift, yShift);
checkXLoc = seaX+xShift;
checkYLoc = seaY+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->region_id!=regionId)
continue;
unitPtr->ship_to_beach(checkXLoc, checkYLoc, tempX, tempY);
found++;
err_when(unitPtr->result_node_array && unitPtr->result_node_count==unitPtr->result_node_recno &&
(unitPtr->result_node_array[unitPtr->result_node_count-1].node_x!=unitPtr->go_x>>ZOOM_X_SHIFT_COUNT ||
unitPtr->result_node_array[unitPtr->result_node_count-1].node_y!=unitPtr->go_y>>ZOOM_Y_SHIFT_COUNT));
break;
}
if(found)
{
totalCheck = 0;
break;
}
}
}
else // cannot carry units
unitPtr->move_to(destX, destY, 1);
}
}
//----------- End of function UnitArray::ship_to_beach -----------//
//----------- Begin of function UnitArray::divide_attack_by_nation -----------//
//
// units which can be controlled by nationRecno to attack are moved
// to the front of the selectedArray, return is number of units passed
//
int UnitArray::divide_attack_by_nation(short nationRecno, short *selectedArray, int selectedCount)
{
// elements before i are pass, elements on or after passCount are not pass
int loopCount = selectedCount+2;
int passCount = selectedCount;
for( int i = 0; i < passCount; )
{
err_when(--loopCount == 0);
short unitRecno = selectedArray[i];
// a clocked spy cannot be commanded by original nation to attack
if( !is_deleted(unitRecno) && operator[](unitRecno)->nation_recno == nationRecno )
{
// pass
++i;
}
else
{
// fail, swap [i] with [passCount-1]
--passCount;
selectedArray[i] = selectedArray[passCount];
selectedArray[passCount] = unitRecno;
}
}
return passCount;
}
//----------- End of function UnitArray::divide_attack_by_nation -----------//
//----------- Begin of function UnitArray::add_way_point -----------//
// pointX - x location of the point to be added
// pointY - y location of the point to be added
// selectedArray - recno. of selected units
// selectedCount - num. of selected units
// remoteAction -
//
void UnitArray::add_way_point(int pointX, int pointY, short* selectedArray, int selectedCount, char remoteAction)
{
if(!remoteAction && remote.is_enable())
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_ADD_WAY_POINT,
sizeof(short) * (3+selectedCount));
shortPtr[0] = pointX;
shortPtr[1] = pointY;
shortPtr[2] = selectedCount;
memcpy(shortPtr+3, selectedArray, sizeof(short)*selectedCount);
}
else
{
DWORD groupId = unit_array.cur_group_id;
Unit *unitPtr;
int i;
for(i=0; iunit_group_id = groupId;
}
unit_array.cur_group_id++;
for(i=0; iadd_way_point(pointX, pointY);
}
}
}
//----------- End of function UnitArray::add_way_point -----------//