/*
* 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 : OF_MONS.CPP
//Description : Firm Airport
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//----------- Define constant ------------//
#define MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER 2
static char current_monster_action_mode;
//--------- Begin of function FirmMonster::init_derived ---------//
//
void FirmMonster::init_derived()
{
monster_general_count = 0;
// ##### patch begin Gilbert 21/1 #######//
// monster_king.monster_id = 0;
memset( &monster_king, 0, sizeof(monster_king) );
// ##### patch end Gilbert 21/1 #######//
memset( monster_general_array, 0, sizeof(monster_general_array) );
waiting_soldier_count = 0;
defending_king_count = 0;
defending_general_count = 0;
defending_soldier_count = 0;
monster_nation_relation = 0;
//----------------------------------------//
// Set monster agressiveness. It affects:
//
// -the number of defenders will be called out at one time.
//----------------------------------------//
defend_target_recno = 0;
patrol_unit_count = 0;
//-- these vars must be initialized here instead of in FirmMonster::FirmMonster() for random seed sync during load game --//
monster_aggressiveness = 20 + m.random(50); // 20 to 70
}
//----------- End of function FirmMonster::init_derived -----------//
//--------- Begin of function FirmMonster::~FirmMonster ---------//
//
FirmMonster::~FirmMonster()
{
if( sys.signal_exit_flag )
return;
int goldAmount = 800 * (monster_res[monster_id]->level*30 + m.random(50)) / 100;
site_array.add_site( center_x, center_y, SITE_GOLD_COIN, goldAmount );
site_array.ai_get_site_object(); // ask AI units to get the gold coins
}
//----------- End of function FirmMonster::~FirmMonster -----------//
//--------- Begin of function FirmMonster::deinit_derived ---------//
//
void FirmMonster::deinit_derived()
{
if( sys.signal_exit_flag )
return;
//-------- mobilize all monsters in the firm --------//
int loopCount=0;
if( monster_king.monster_id )
mobilize_king();
while( monster_general_count > 0 )
{
if(!mobilize_general(1))
break;
err_when( loopCount++ > 100 );
}
clear_defense_mode();
}
//----------- End of function FirmMonster::deinit_derived -----------//
//------- Begin of function FirmMonster::firm_name -----------//
//
char* FirmMonster::firm_name()
{
static String str;
#if(defined(SPANISH))
str = "Guarida ";
str += monster_res[monster_id]->name;
#elif(defined(FRENCH))
str = "Antre des ";
str += monster_res[monster_id]->name;
#else
// GERMAN, US
str = monster_res[monster_id]->name;
str += translate.process(" Lair");
#endif
return str;
}
//--------- End of function FirmMonster::firm_name -----------//
//--------- Begin of function FirmMonster::put_info ---------//
//
void FirmMonster::put_info(int refreshFlag)
{
disp_basic_info(INFO_Y1, refreshFlag);
if( !config.show_ai_info && nation_recno!=nation_array.player_recno )
return;
disp_monster_info(INFO_Y1+54, refreshFlag);
}
//----------- End of function FirmMonster::put_info -----------//
//--------- Begin of function FirmMonster::detect_info ---------//
//
void FirmMonster::detect_info()
{
if( detect_basic_info() )
return;
if( !config.show_ai_info && nation_recno!=nation_array.player_recno )
return;
}
//----------- End of function FirmMonster::detect_info -----------//
//--------- Begin of function FirmMonster::disp_monster_info ---------//
//
void FirmMonster::disp_monster_info(int dispY1, int refreshFlag)
{
return;
//---------------- paint the panel --------------//
if( refreshFlag == INFO_REPAINT )
vga.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+22 );
int x=INFO_X1+4, y=dispY1+3;
}
//----------- End of function FirmMonster::disp_monster_info -----------//
//--------- Begin of function FirmMonster::next_day ---------//
//
void FirmMonster::next_day()
{
//-------- validate patrol unit --------//
validate_patrol_unit();
//---- the monster boss recruit new monsters ----//
if( info.game_date%10 == firm_recno%10 )
recruit_soldier();
//----- monsters recover hit points -------//
if( info.game_date%15 == firm_recno%15 ) // once a week
recover_hit_points();
//------ monster thinks about expansion -------//
if( config.monster_type == OPTION_MONSTER_OFFENSIVE )
{
if( info.game_date%30 == firm_recno%30 && m.random(3)==0 )
recruit_general();
/*
if( info.game_date%90 == firm_recno%90 )
think_attack_neighbor();
*/
//------ attack human towns and firms randomly -----//
if( info.game_date > info.game_start_date + 1000 && // only start attacking 3 years after the game starts so the human can build up things
info.game_date%30 == firm_recno%30 &&
m.random( firm_res[FIRM_MONSTER]->total_firm_count*6 )==0 ) // it will expand slower when there are already a lot of the monster structures on the map
{
think_attack_human();
}
//--------- think expansion ---------//
if( info.game_date%180 == firm_recno%180 &&
m.random( firm_res[FIRM_MONSTER]->total_firm_count*10 )==0 ) // it will expand slower when there are already a lot of the monster structures on the map
{
think_expansion();
}
}
}
//----------- End of function FirmMonster::next_day -----------//
//------- Begin of function FirmMonster::recover_hit_points -------//
//
void FirmMonster::recover_hit_points()
{
//------ recover the king's hit points -------//
if( monster_king.hit_points < monster_king.max_hit_points )
monster_king.hit_points++;
//------ recover the generals' hit points -------//
for( int i=0 ; iunit_id];
err_when( !unitInfo->is_monster );
switch( unitPtr->rank_id )
{
case RANK_KING:
set_king(unitPtr->get_monster_id(), unitPtr->skill.combat_level);
break;
case RANK_GENERAL:
add_general(unitRecno);
break;
case RANK_SOLDIER:
add_soldier(unitPtr->leader_unit_recno);
break;
}
//--------- the unit disappear in firm -----//
unit_array.disappear_in_firm(unitRecno);
}
//----------- End of function FirmMonster::assign_unit -----------//
//--------- Begin of function FirmMonster::set_king ---------//
//
// Set the monster king of this firm.
//
void FirmMonster::set_king(int monsterId, int combatLevel)
{
monster_king.monster_id = monsterId;
monster_king.set_combat_level(combatLevel);
monster_king.hit_points = monster_king.max_hit_points;
}
//----------- End of function FirmMonster::set_king -----------//
//--------- Begin of function FirmMonster::add_general ---------//
//
// Add a general to the firm, this function is called when a
// mobilized monster general is assigned back to the firm.
//
void FirmMonster::add_general(int generalUnitRecno)
{
if(monster_general_count>=MAX_MONSTER_GENERAL_IN_FIRM)
return;
Unit* unitPtr = unit_array[generalUnitRecno];
UnitInfo* unitInfo = unit_res[unitPtr->unit_id];
MonsterInFirm* monsterInFirm = monster_general_array+monster_general_count;
monsterInFirm->monster_id = unitPtr->get_monster_id(); // contribution is used for storing the monster id. temporary
monsterInFirm->set_combat_level(unitPtr->skill.combat_level);
monsterInFirm->hit_points = (int) unitPtr->hit_points;
if( monsterInFirm->hit_points == 0 ) // 0.? will become 0 in (float) to (int) conversion
monsterInFirm->hit_points = 1;
monsterInFirm->soldier_monster_id = unitPtr->get_monster_soldier_id(); // skill id is used for storing the soldier monster id temporarily
monsterInFirm->soldier_count = 0;
monsterInFirm->mobile_unit_recno = generalUnitRecno; // unit recno of this monster when it is a mobile unit
// this is only used as a reference for soldiers to find their leaders
monster_general_count++;
//----- check if there are any soldiers waiting for this general ----//
//
// These are soldiers who follow the general to go out to defend
// against the attack but then went back to the firm sooner
// than the general does.
//
//-------------------------------------------------------------------//
for( int i=0 ; isoldier_count++;
err_when( waiting_soldier_count > MAX_WAITING_SOLDIER );
m.del_array_rec(waiting_soldier_array, waiting_soldier_count, sizeof(waiting_soldier_array[0]), i+1);
waiting_soldier_count--;
}
}
}
//----------- End of function FirmMonster::add_general -----------//
//--------- Begin of function FirmMonster::add_soldier ---------//
//
// generalUnitRecno - the unit recno of the general leading
// this soldier.
//
void FirmMonster::add_soldier(int generalUnitRecno)
{
//----- check if the soldier's leading general is here ----//
for( int i=0 ; i=MAX_SOLDIER_PER_GENERAL)
return;
monster_general_array[i].soldier_count++;
return;
}
}
//---- if not, put the soldier into the waiting list ----//
if( waiting_soldier_count < MAX_WAITING_SOLDIER ) // if the list is full, the unit disappear in air
{
waiting_soldier_array[waiting_soldier_count++] = generalUnitRecno; // the soldier is waiting for this general.
}
}
//----------- End of function FirmMonster::add_soldier -----------//
//--------- Begin of function FirmMonster::recruit_general ---------//
//
// Recruit general monsters.
//
// [int] soldierCount - the no. of soldiers to be created with this general.
// (default: randomly from 1 to MAX_MONSTER_PER_GENERAL)
//
int FirmMonster::recruit_general(int soldierCount)
{
err_when( monster_general_count < 0 || monster_general_count > MAX_MONSTER_GENERAL_IN_FIRM );
if( monster_general_count >= MAX_MONSTER_GENERAL_IN_FIRM * monster_aggressiveness / 100 )
return 0;
if( !monster_king.monster_id )
return 0;
//---------- recruit the general now ----------//
MonsterInFirm* monsterInFirm = monster_general_array+monster_general_count;
int combatLevel = 40 + m.random(30); // 40 to 70
monsterInFirm->monster_id = monster_king.monster_id;
monsterInFirm->set_combat_level(combatLevel);
monsterInFirm->hit_points = monsterInFirm->max_hit_points;
monsterInFirm->soldier_monster_id = monster_king.monster_id;
if( soldierCount >= 0 )
monsterInFirm->soldier_count = soldierCount;
else
monsterInFirm->soldier_count = m.random(MAX_SOLDIER_PER_GENERAL/2)+1;
monster_general_count++;
return 1;
}
//----------- End of function FirmMonster::recruit_general -----------//
//--------- Begin of function FirmMonster::recruit_soldier ---------//
//
// Recruit soldier monsters.
//
void FirmMonster::recruit_soldier()
{
MonsterInFirm* monsterInFirm = monster_general_array;
for( int i=0 ; isoldier_count < MAX_SOLDIER_PER_GENERAL &&
m.random(3) > 0 ) // 2/3 chance of recruiting a soldier
{
monsterInFirm->soldier_count++;
}
}
}
//----------- End of function FirmMonster::recruit_soldier -----------//
//--------- Begin of function FirmMonster::mobilize_king ---------//
//
// The king himself does not lead any soldiers.
//
int FirmMonster::mobilize_king()
{
if( !mobilize_monster( monster_king.monster_id, RANK_KING, monster_king.combat_level, monster_king.hit_points ) )
return 0;
monster_king.monster_id = 0;
return 1;
}
//----------- End of function FirmMonster::mobilize_king ---------//
//--------- Begin of function FirmMonster::mobilize_general ---------//
//
// Mobilize monster generals. Soldiers need by the general is also mobilized.
//
// generalId - id. of the general.
// [int] mobilizeSoldier - whether also mobilize soldiers this general
// commands. (default: 1)
//
// Return: the no. of monsters have been mobilized.
//
int FirmMonster::mobilize_general(int generalId, int mobilizeSoldier)
{
err_when( generalId < 1 || generalId > monster_general_count );
MonsterInFirm* monsterInFirm = monster_general_array + generalId - 1;
//------ mobilize the monster general ------//
int generalUnitRecno = mobilize_monster( monsterInFirm->monster_id, RANK_GENERAL, monsterInFirm->combat_level, monsterInFirm->hit_points );
if( !generalUnitRecno )
return 0;
unit_array[generalUnitRecno]->set_monster_soldier_id(monsterInFirm->soldier_monster_id);
int mobilizedCount = 1;
patrol_unit_array[0] = generalUnitRecno;
patrol_unit_count = 1;
//------ mobilize soldiers commanded by the monster general ------//
if( mobilizeSoldier )
{
for( int i=0 ; isoldier_count ; i++ )
{
//--- the combat level of its soldiers ranges from 25% to 50% of the combat level of the general ---//
int soldierCombatLevel = monsterInFirm->combat_level/MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER + m.random(monsterInFirm->combat_level/MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER);
int unitRecno = mobilize_monster( monsterInFirm->soldier_monster_id, RANK_SOLDIER, soldierCombatLevel );
if( unitRecno )
{
unit_array[unitRecno]->leader_unit_recno = generalUnitRecno;
mobilizedCount++;
patrol_unit_array[patrol_unit_count++] = unitRecno;
if(patrol_unit_count==MAX_SOLDIER_PER_GENERAL+1)
break;
}
else
break; // no space for init_sprite
}
}
//---- delete the monster general record from the array ----//
err_when( monster_general_count > MAX_MONSTER_GENERAL_IN_FIRM );
m.del_array_rec(monster_general_array, monster_general_count, sizeof(MonsterInFirm), generalId);
monster_general_count--;
return mobilizedCount;
}
//----------- End of function FirmMonster::mobilize_general ---------//
//--------- Begin of function FirmMonster::mobilize_monster ---------//
//
// monsterId = id. of the monster to be mobilized
// rankId = rank id. of the monster.
// combatLevel = the combat level of the monster
// [int] hitPoints = set the hit points of the monster to this
// (default: hit points of the monster is set to the max hit points when it is first created.)
//
// return: the unit recno of the mobile unit created.
//
int FirmMonster::mobilize_monster(int monsterId, int rankId, int combatLevel, int hitPoints)
{
MonsterInfo* monsterInfo = monster_res[monsterId];
UnitInfo* unitInfo = unit_res[monsterInfo->unit_id];
//------- locate a space first --------//
int xLoc=center_x, yLoc=center_y;
SpriteInfo* spriteInfo = sprite_res[unitInfo->sprite_id];
if( !world.locate_space( xLoc, yLoc, xLoc, yLoc, spriteInfo->loc_width, spriteInfo->loc_height, unitInfo->mobile_type ) )
return 0;
//---------- add the unit now -----------//
int unitRecno = unit_array.add_unit( unitInfo->unit_id, 0,
rankId, 0, xLoc, yLoc );
UnitMonster* monsterPtr = (UnitMonster*) unit_array[unitRecno];
monsterPtr->set_mode(UNIT_MODE_MONSTER, firm_recno);
monsterPtr->set_combat_level(combatLevel);
monsterPtr->set_monster_id(monsterId);
monsterPtr->set_monster_action_mode(current_monster_action_mode);
if( hitPoints )
{
monsterPtr->hit_points = (float) hitPoints;
err_when( hitPoints > monsterPtr->max_hit_points );
}
else
monsterPtr->hit_points = monsterPtr->max_hit_points;
//-----------------------------------------------------//
// enable unit defend mode
//-----------------------------------------------------//
if(firm_recno) // 0 when firm is ready to be deleted
{
monsterPtr->stop2();
monsterPtr->action_mode2 = ACTION_MONSTER_DEFEND_DETECT_TARGET;
monsterPtr->action_para2 = MONSTER_DEFEND_DETECT_COUNT;
monsterPtr->action_misc = ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO;
monsterPtr->action_misc_para = firm_recno;
}
return unitRecno;
}
//----------- End of function FirmMonster::mobilize_monster -----------//
//--------- Begin of function FirmMonster::being_attacked ---------//
//
// This function is called by Unit::hit_firm()
//
// attackerUnitRecno - recno of the unit attacking this firm.
//
void FirmMonster::being_attacked(int attackerUnitRecno)
{
int attackerNationRecno = unit_array[attackerUnitRecno]->nation_recno;
//--- increase reputation of the nation that attacks monsters ---//
if( attackerNationRecno )
{
nation_array[attackerNationRecno]->change_reputation(REPUTATION_INCREASE_PER_ATTACK_MONSTER);
set_hostile_nation(attackerNationRecno); // also set hostile with the nation
}
//------ max no. of defender it should call out -----//
int maxDefender = MAX_MONSTER_IN_FIRM * monster_aggressiveness / 200;
if( total_defender() >= maxDefender ) // only mobilize new ones when the max defender no. has been reached yet
return;
current_monster_action_mode = MONSTER_ACTION_DEFENSE;
//---- mobilize monster general to defend against the attack ----//
if( monster_general_count > 0 )
{
int mobilizedCount = mobilize_general( m.random(monster_general_count)+1 );
if(mobilizedCount)
{
defending_general_count++;
defending_soldier_count += mobilizedCount-1;
}
}
else if( monster_king.monster_id )
{
if( mobilize_king() )
defending_king_count++;
}
defend_target_recno = attackerUnitRecno;
}
//----------- End of function FirmMonster::being_attacked -----------//
//-------- Begin of function FirmMonster::clear_defense_mode -------//
//
// This function is called when the firm monster is destroyed.
//
void FirmMonster::clear_defense_mode()
{
//------------------------------------------------------------------//
// change defense unit's to non-defense mode
//------------------------------------------------------------------//
Unit *unitPtr;
for(int i=unit_array.size(); i>=1; --i)
{
if(unit_array.is_deleted(i))
continue;
unitPtr = unit_array[i];
//------ reset the monster's defense mode -----//
if(unitPtr->in_monster_defend_mode() && unitPtr->action_misc==ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO &&
unitPtr->action_misc_para==firm_recno)
{
unitPtr->clear_monster_defend_mode();
((UnitMonster*)unitPtr)->set_monster_action_mode(MONSTER_ACTION_STOP);
}
//--- if this unit belongs to this firm, reset its association with this firm ---//
if( unitPtr->unit_mode == UNIT_MODE_MONSTER &&
unitPtr->unit_mode_para == firm_recno )
{
unitPtr->unit_mode_para = 0;
}
}
}
//----------- End of function FirmMonster::clear_defense_mode -----------//
//-------- Begin of function FirmMonster::reduce_defender_count -------//
//
// A defender unit moves back into the firm, reducing the defender count.
//
// rankId - rank id. of the defender unit
//
void FirmMonster::reduce_defender_count(int rankId)
{
switch(rankId)
{
case RANK_KING:
defending_king_count--;
if( defending_king_count < 0 ) //**BUGHERE
defending_king_count = 0;
err_when( defending_king_count < 0 );
break;
case RANK_GENERAL:
defending_general_count--;
if( defending_general_count < 0 ) //**BUGHERE
defending_general_count = 0;
err_when( defending_general_count < 0 );
break;
case RANK_SOLDIER:
defending_soldier_count--;
if( defending_soldier_count < 0 ) //**BUGHERE
defending_soldier_count = 0;
err_when( defending_soldier_count < 0 );
break;
}
if( total_defender()==0 )
monster_nation_relation = 0;
}
//------ End of function FirmMonster::reduce_defender_count ---------//
//-------- Begin of function MonsterInFirm::set_combat_level -------//
void MonsterInFirm::set_combat_level(int combatLevel)
{
UnitInfo* unitInfo = unit_res[monster_res[monster_id]->unit_id];
combat_level = combatLevel;
max_hit_points = (int) unitInfo->hit_points * combatLevel / 100;
}
//--------- End of function MonsterInFirm::set_combat_level --------//
//-------- Begin of function FirmMonster::total_combat_level -------//
//
int FirmMonster::total_combat_level()
{
MonsterInFirm* monsterInFirm = monster_general_array;
int totalCombatLevel=50; // for the structure
for( int i=0 ; ihit_points +
(monsterInFirm->combat_level * 2 / MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER) // *2 because total_combat_level() actually takes hit_points instead of combat_level
* 3 / 2 * monsterInFirm->soldier_count; // *3/2 because the function use 100% + random(100%) for the combat level, so we take 150% as the average
}
return totalCombatLevel;
}
//------ End of function FirmMonster::total_combat_level ---------//
//-------- Begin of function FirmMonster::can_assign_monster -------//
//
// Return whether the given monster can be assigned to this firm.
//
// It checks if the type of the monster and the type of the monster
// structure are compatible.
//
int FirmMonster::can_assign_monster(int unitRecno)
{
Unit* unitPtr = unit_array[unitRecno];
int monsterId = unitPtr->get_monster_id();
return strcmp( firm_res.get_build(firm_build_id)->build_code, // can assign if the build code are the same
monster_res[monsterId]->firm_build_code ) == 0;
}
//------ End of function FirmMonster::can_assign_monster ---------//
//-------- Begin of function FirmMonster::set_hostile_nation -------//
void FirmMonster::set_hostile_nation(int nationRecno)
{
if(nationRecno==0)
return;
err_when(nationRecno>7); // only 8 bits
monster_nation_relation |= (0x1 << nationRecno);
}
//------ End of function FirmMonster::set_hostile_nation ---------//
//-------- Begin of function FirmMonster::reset_hostile_nation -------//
void FirmMonster::reset_hostile_nation(int nationRecno)
{
if(nationRecno==0)
return;
err_when(nationRecno>7); // only 8 bits
monster_nation_relation &= ~(0x1 << nationRecno);
}
//------ End of function FirmMonster::reset_hostile_nation ---------//
//-------- Begin of function FirmMonster::is_hostile_nation -------//
// return 1 for hostile nation
// return 0 otherwise
//
int FirmMonster::is_hostile_nation(int nationRecno)
{
if(nationRecno==0)
return 0;
err_when(nationRecno>7); // only 8 bits
return (monster_nation_relation & (0x1 << nationRecno));
}
//------ End of function FirmMonster::is_hostile_nation ---------//
//------- Begin of function FirmMonster::validate_patrol_unit ---------//
//
void FirmMonster::validate_patrol_unit()
{
if(patrol_unit_count<=0)
return;
int unitRecno;
Unit* unitPtr;
for( int i=patrol_unit_count ; i>0 ; i-- )
{
unitRecno = patrol_unit_array[i-1];
if( unit_array.is_deleted(unitRecno) ||
(unitPtr=unit_array[unitRecno])->is_visible()==0 )
{
err_when( patrol_unit_count > MAX_SOLDIER_PER_GENERAL+1 );
m.del_array_rec( patrol_unit_array, patrol_unit_count, sizeof(patrol_unit_array[0]), i );
err_when( patrol_unit_count==0 ); // it's already 0
patrol_unit_count--;
}
}
err_when(patrol_unit_count<0);
if(patrol_unit_count==0 && total_defender()==0)
monster_nation_relation = 0;
else if(patrol_unit_count<0)
patrol_unit_count = 0;
}
//-------- End of function FirmMonster::validate_patrol_unit ---------//
//------- Begin of function FirmMonster::think_attack_neighbor -------//
//
int FirmMonster::think_attack_neighbor()
{
//-- don't attack new target if some mobile monsters are already attacking somebody --//
if( patrol_unit_count > 0 )
return 0;
//-------- only attack if we have enough generals ---------//
int generalCount=0;
MonsterInFirm* monsterInFirm = monster_general_array;
int totalCombatLevel=0;
//--- count the number of generals commanding at least 5 soldiers ---//
int i;
for( i=0 ; isoldier_count >= 5 )
generalCount++;
}
if( generalCount<=1 ) // don't attack if there is only one general in the firm
return 0;
//------ look for neighbors to attack ------//
int xOffset, yOffset;
int xLoc, yLoc;
int attackFlag=0;
FirmInfo* firmInfo = firm_res[firm_id];
Location* locPtr;
int scanLocWidth = MONSTER_ATTACK_NEIGHBOR_RANGE*2;
int scanLocHeight = MONSTER_ATTACK_NEIGHBOR_RANGE*2;
int scanLimit = scanLocWidth * scanLocHeight;
short targetNation;
for(i=firmInfo->loc_width*firmInfo->loc_height+1; i<=scanLimit; i++)
{
m.cal_move_around_a_point(i, scanLocWidth, scanLocHeight, xOffset, yOffset);
xLoc = center_x + xOffset;
yLoc = center_y + yOffset;
xLoc = max(0, xLoc);
xLoc = min(MAX_WORLD_X_LOC-1, xLoc);
yLoc = max(0, yLoc);
yLoc = min(MAX_WORLD_Y_LOC-1, yLoc);
locPtr = world.get_loc(xLoc, yLoc);
if(locPtr->is_firm())
{
Firm *firmPtr = firm_array[locPtr->firm_recno()];
if(firmPtr->nation_recno)
{
targetNation = firmPtr->nation_recno;
attackFlag = 1;
xLoc = firmPtr->loc_x1;
yLoc = firmPtr->loc_y1;
break;
}
}
else if(locPtr->is_town())
{
Town *townPtr = town_array[locPtr->town_recno()];
if(townPtr->nation_recno)
{
targetNation = townPtr->nation_recno;
attackFlag = 1;
xLoc = townPtr->loc_x1;
yLoc = townPtr->loc_y1;
break;
}
}
}
if( !attackFlag )
return 0;
//------- attack the civilian now --------//
current_monster_action_mode = MONSTER_ACTION_ATTACK;
mobilize_general( m.random(monster_general_count)+1 );
if( patrol_unit_count > 0 )
{
//### begin alex 16/9 ###//
set_hostile_nation(targetNation);
//#### end alex 16/9 ####//
// ##### patch begin Gilbert 5/8 #######//
unit_array.attack(xLoc, yLoc, 0, patrol_unit_array, patrol_unit_count, COMMAND_AI, 0);
// ##### patch end Gilbert 5/8 #######//
return 1;
}
else
return 0;
}
//-------- End of function FirmMonster::think_attack_neighbor -------//
//-------- Begin of function FirmMonster::think_expansion -------//
//
int FirmMonster::think_expansion()
{
#define MIN_GENERAL_EXPAND_NUM 3
if(patrol_unit_count>0)
return 0;
if(!monster_king.monster_id || monster_general_countsoldier_count == MAX_SOLDIER_PER_GENERAL )
generalCount++;
}
if( generalCount < MIN_GENERAL_EXPAND_NUM ) // don't expand if the no. of generals is less than 3
return 0;
//------------- locate space to build monster firm randomly -------------//
#define EXPAND_FIRM_DISTANCE 30
#define FREE_SPACE_DISTANCE 3
MonsterInfo* monsterInfo = monster_res[monster_king.monster_id];
FirmInfo* firmInfo = firm_res[FIRM_MONSTER];
char teraMask = UnitRes::mobile_type_to_mask(UNIT_LAND);
int xLoc1 = max(0, loc_x1-EXPAND_FIRM_DISTANCE);
int yLoc1 = max(0, loc_y1-EXPAND_FIRM_DISTANCE);
int xLoc2 = min(MAX_WORLD_X_LOC-1, loc_x2+EXPAND_FIRM_DISTANCE);
int yLoc2 = min(MAX_WORLD_Y_LOC-1, loc_y2+EXPAND_FIRM_DISTANCE);
if( !world.locate_space_random(xLoc1, yLoc1, xLoc2, yLoc2,
firmInfo->loc_width+FREE_SPACE_DISTANCE*2,
firmInfo->loc_height+FREE_SPACE_DISTANCE*2, // leave at least 3 location space around the building
(xLoc2-xLoc1+1)*(yLoc2-yLoc1+1), 0, 1, teraMask) )
{
return 0;
}
monster_general_count--;
//monsterInFirm = monster_general_array + monster_general_count;
//unit_array.disappear_in_firm(monsterInFirm->mobile_unit_recno);
return monsterInfo->build_firm_monster(xLoc1+FREE_SPACE_DISTANCE, yLoc1+FREE_SPACE_DISTANCE, 1); //1-full hit points
}
//------ End of function FirmMonster::think_expansion ---------//
//------- Begin of function FirmMonster::think_attack_human -------//
//
int FirmMonster::think_attack_human()
{
//-- don't attack new target if some mobile monsters are already attacking somebody --//
if( patrol_unit_count > 0 )
return 0;
//-------- only attack if we have enough generals ---------//
int generalCount=0;
MonsterInFirm* monsterInFirm = monster_general_array;
int totalCombatLevel=0;
//--- count the number of generals commanding at least 5 soldiers ---//
int i;
for( i=0 ; isoldier_count >= 5 )
generalCount++;
}
if( generalCount<=1 ) // don't attack if there is only one general in the firm
return 0;
//------ look for neighbors to attack ------//
int firmRecno, townRecno;
int targetXLoc= -1, targetYLoc, targetNationRecno=0;
Firm* firmPtr;
Town* townPtr;
for(i=1 ; i<100 ; i++ )
{
//----- randomly pick a firm ------//
firmRecno = m.random(firm_array.size()) + 1;
if( firm_array.is_deleted(firmRecno) )
continue;
firmPtr = firm_array[firmRecno];
if( firmPtr->region_id == region_id )
{
targetXLoc = firmPtr->loc_x1;
targetYLoc = firmPtr->loc_y1;
targetNationRecno = firmPtr->nation_recno;
break;
}
//----- randomly pick a town ------//
townRecno = m.random(town_array.size()) + 1;
if( town_array.is_deleted(townRecno) )
continue;
townPtr = town_array[townRecno];
if( townPtr->nation_recno && townPtr->region_id == region_id )
{
targetXLoc = townPtr->loc_x1;
targetYLoc = townPtr->loc_y1;
targetNationRecno = townPtr->nation_recno;
break;
}
}
if( targetXLoc == -1 ) // no target selected
return 0;
//------- attack the civilian now --------//
current_monster_action_mode = MONSTER_ACTION_ATTACK;
mobilize_general( m.random(monster_general_count)+1 );
if( patrol_unit_count > 0 )
{
set_hostile_nation(targetNationRecno);
// ##### patch begin Gilbert 5/8 #######//
unit_array.attack(targetXLoc, targetYLoc, 0, patrol_unit_array, patrol_unit_count, COMMAND_AI, 0);
// ##### patch end Gilbert 5/8 #######//
return 1;
}
else
return 0;
}
//-------- End of function FirmMonster::think_attack_human -------//