/*
* 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: OUNIT2.CPP
//Description: Unit functions
#include
#include
#include
#include
#include
//------- Begin of function Unit::think_aggressive_action --------//
//
// This function is called when the unit is in aggressive mode.
//
int Unit::think_aggressive_action()
{
//------ think about resuming the original action -----//
if( original_action_mode && cur_action!=SPRITE_ATTACK ) // if it is currently attacking somebody, don't think about resuming the original action
{
return think_resume_original_action();
}
//---- think about attacking nearby units if this unit is attacking a town or a firm ---//
if( aggressive_mode && unit_mode==0 && cur_action==SPRITE_ATTACK ) // only in attack mode, as if the unit is still moving the target may be far away from the current position
{
//--- only when the unit is currently attacking a firm or a town ---//
if( action_mode2 == ACTION_ATTACK_FIRM ||
action_mode2 == ACTION_ATTACK_TOWN )
{
if( info.game_date%5==0 ) // check once every 5 days
return think_change_attack_target();
}
}
return 0;
}
//-------- End of function Unit::think_aggressive_action --------//
//--------- Begin of function Unit::think_resume_original_action --------//
//
// If this unit is chasing a target to attack. Stop the chase
// if the target is being far away from its original location.
//
int Unit::think_resume_original_action()
{
if( !is_visible() ) // if the unit is no longer visible, cancel the saved orignal action
{
original_action_mode = 0;
return 0;
}
//---- if the unit is in defense mode now, don't do anything ----//
if( in_any_defense_mode() )
return 0;
//----------------------------------------------------//
//
// If the action has been changed or the target unit has been deleted,
// stop the chase right and move back to the original position
// before the auto guard attack.
//
//----------------------------------------------------//
if(action_mode2!=ACTION_ATTACK_UNIT || unit_array.is_deleted(action_para2))
{
resume_original_action();
return 1;
}
//-----------------------------------------------------//
//
// Stop the chase if the target is being far away from
// its original location and move back to its original
// position before the auto guard attack.
//
//-----------------------------------------------------//
#define AUTO_GUARD_CHASE_ATTACK_DISTANCE 5
Unit* targetUnit = unit_array[action_para2];
int curDistance = m.points_distance( targetUnit->next_x_loc(), targetUnit->next_y_loc(),
original_target_x_loc, original_target_y_loc );
if( curDistance > AUTO_GUARD_CHASE_ATTACK_DISTANCE )
{
resume_original_action();
return 1;
}
return 0;
}
//---------- End of function Unit::think_resume_original_action --------//
//------- Begin of function Unit::think_change_attack_target -------//
//
// When the unit is attacking a firm or town, look out for enemy units
// to attack. Enemy units should be attacked first.
//
int Unit::think_change_attack_target()
{
err_when( !nation_recno ); // only for nation units
//----------------------------------------------//
int attackRange = max(attack_range, 8);
int attackScanRange = attackRange*2+1;
int xOffset, yOffset;
int xLoc, yLoc;
Location* locPtr;
int curXLoc = next_x_loc(), curYLoc = next_y_loc();
BYTE regionId = world.get_region_id(curXLoc, curYLoc);
for( int i=2 ; iregion_id != regionId )
continue;
//----- if there is a unit on the location ------//
if( locPtr->has_unit(UNIT_LAND) )
{
int unitRecno = locPtr->unit_recno(UNIT_LAND);
if( unit_array.is_deleted(unitRecno) )
continue;
if( unit_array[unitRecno]->nation_recno != nation_recno &&
idle_detect_unit_checking(unitRecno) )
{
save_original_action();
original_target_x_loc = xLoc;
original_target_y_loc = yLoc;
attack_unit(xLoc, yLoc);
return 1;
}
}
}
return 0;
}
//---------- End of function Unit::think_change_attack_target ------//
//----------- Begin of function Unit::save_original_action -------//
void Unit::save_original_action()
{
if( original_action_mode==0 )
{
original_action_mode = action_mode2;
original_action_para = action_para2;
original_action_x_loc = action_x_loc2;
original_action_y_loc = action_y_loc2;
}
}
//----------- End of function Unit::save_original_action -------//
//----------- Begin of function Unit::resume_original_action -------//
void Unit::resume_original_action()
{
if( !original_action_mode )
return;
//--------- If it is an attack action ---------//
if( original_action_mode == ACTION_ATTACK_UNIT ||
original_action_mode == ACTION_ATTACK_FIRM ||
original_action_mode == ACTION_ATTACK_TOWN )
{
resume_original_attack_action();
return;
}
//--------------------------------------------//
if( original_action_x_loc<0 || original_action_x_loc>=MAX_WORLD_X_LOC ||
original_action_y_loc<0 || original_action_y_loc>=MAX_WORLD_Y_LOC )
{
original_action_mode = 0;
return;
}
short selectedArray[1];
selectedArray[0] = sprite_recno; // use unit_array.attack() instead of unit.attack_???() as we are unsure about what type of object the target is.
Location* locPtr = world.get_loc(original_action_x_loc, original_action_y_loc);
//--------- resume assign to town -----------//
if( original_action_mode == ACTION_ASSIGN_TO_TOWN && locPtr->is_town() )
{
if( locPtr->town_recno() == original_action_para &&
town_array[original_action_para]->nation_recno == nation_recno )
{
unit_array.assign( original_action_x_loc, original_action_y_loc, 0,
COMMAND_AUTO, selectedArray, 1 );
}
}
//--------- resume assign to firm ----------//
else if( original_action_mode == ACTION_ASSIGN_TO_FIRM && locPtr->is_firm() )
{
if( locPtr->firm_recno() == original_action_para &&
firm_array[original_action_para]->nation_recno == nation_recno )
{
unit_array.assign( original_action_x_loc, original_action_y_loc, 0,
COMMAND_AUTO, selectedArray, 1 );
}
}
//--------- resume build firm ---------//
else if( original_action_mode == ACTION_BUILD_FIRM )
{
if( world.can_build_firm( original_action_x_loc, original_action_y_loc,
original_action_para, sprite_recno ) )
{
build_firm( original_action_x_loc, original_action_y_loc,
original_action_para, COMMAND_AUTO );
}
}
//--------- resume settle ---------//
else if( original_action_mode == ACTION_SETTLE )
{
if( world.can_build_town( original_action_x_loc, original_action_y_loc, sprite_recno ) )
{
unit_array.settle( original_action_x_loc, original_action_y_loc,
0, COMMAND_AUTO, selectedArray, 1 );
}
}
//--------- resume move ----------//
else if( original_action_mode == ACTION_MOVE )
{
unit_array.move_to( original_action_x_loc, original_action_y_loc, 0,
selectedArray, 1, COMMAND_AUTO );
}
original_action_mode = 0;
}
//----------- End of function Unit::resume_original_action -------//
//----------- Begin of function Unit::resume_original_attack_action -------//
//
void Unit::resume_original_attack_action()
{
if( !original_action_mode )
return;
if( original_action_mode != ACTION_ATTACK_UNIT &&
original_action_mode != ACTION_ATTACK_FIRM &&
original_action_mode != ACTION_ATTACK_TOWN )
{
original_action_mode = 0;
return;
}
//--------------------------------------------//
err_when( original_action_x_loc<0 || original_action_x_loc>=MAX_WORLD_X_LOC );
err_when( original_action_y_loc<0 || original_action_y_loc>=MAX_WORLD_Y_LOC );
Location* locPtr = world.get_loc(original_action_x_loc, original_action_y_loc);
int targetNationRecno = -1;
if( original_action_mode == ACTION_ATTACK_UNIT && locPtr->has_unit(UNIT_LAND) )
{
int unitRecno = locPtr->unit_recno(UNIT_LAND);
if( unitRecno == original_action_para )
targetNationRecno = unit_array[unitRecno]->nation_recno;
}
else if( original_action_mode == ACTION_ATTACK_FIRM && locPtr->is_firm() )
{
int firmRecno = locPtr->firm_recno();
if( firmRecno == original_action_para )
targetNationRecno = firm_array[firmRecno]->nation_recno;
}
else if( original_action_mode == ACTION_ATTACK_TOWN && locPtr->is_town() )
{
int townRecno = locPtr->town_recno();
if( townRecno == original_action_para )
targetNationRecno = town_array[townRecno]->nation_recno;
}
//----- the original target is no longer valid ----//
if( targetNationRecno == -1 )
{
original_action_mode = 0;
return;
}
//---- only resume attacking the target if the target nation is at war with us currently ---//
if( !targetNationRecno || (targetNationRecno &&
targetNationRecno != nation_recno &&
nation_array[nation_recno]->get_relation_status(targetNationRecno) == NATION_HOSTILE ))
{
short selectedArray[1];
selectedArray[0] = sprite_recno; // use unit_array.attack() instead of unit.attack_???() as we are unsure about what type of object the target is.
// #### begin Gilbert 5/8 ########//
unit_array.attack(original_action_x_loc, original_action_y_loc, 0, selectedArray, 1, COMMAND_AI, 0 );
// #### end Gilbert 5/8 ########//
}
original_action_mode = 0;
}
//----------- End of function Unit::resume_original_attack_action -------//
//------- Begin of function Unit::ask_team_help_attack --------//
//
// It returns whether any of the co-member of this unit in a troop
// is under attack.
//
// attackerUnit - the unit pointer of the attacker
//
void Unit::ask_team_help_attack(Unit* attackerUnit)
{
//--- if the attacking unit is our unit (this can happen if the unit is porcupine) ---//
if( attackerUnit->nation_recno == nation_recno )
return;
//-----------------------------------------//
int leaderUnitRecno=0;
if( leader_unit_recno ) // if the current unit is a soldier, get its leader's recno
leaderUnitRecno = leader_unit_recno;
else if( team_info ) // this unit is the commander
leaderUnitRecno = sprite_recno;
if( leaderUnitRecno )
{
TeamInfo* teamInfo = unit_array[leaderUnitRecno]->team_info;
err_when( !teamInfo );
for( int i=teamInfo->member_count-1 ; i>=0 ; i-- )
{
int unitRecno = teamInfo->member_unit_array[i];
if( unit_array.is_deleted(unitRecno) )
continue;
Unit* unitPtr = unit_array[ unitRecno ];
if( unitPtr->cur_action==SPRITE_IDLE && unitPtr->is_visible() )
{
unitPtr->attack_unit(attackerUnit->sprite_recno);
return;
}
}
}
}
//-------- End of function Unit::ask_team_help_attack --------//