1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
- //Filename : OF_MONS.CPP
- //Description : Firm Airport
- #include <OINFO.h>
- #include <OVGA.h>
- #include <ODATE.h>
- #include <OSTR.h>
- #include <OSYS.h>
- #include <OSITE.h>
- #include <OFONT.h>
- #include <OBUTTON.h>
- #include <OPOWER.h>
- #include <OTOWN.h>
- #include <OU_MONS.h>
- #include <OGAME.h>
- #include <ONATION.h>
- #include <OMONSRES.h>
- #include <OF_MONS.h>
- //----------- 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 ; i<monster_general_count ; i++ )
- {
- if( monster_general_array[i].hit_points < monster_general_array[i].max_hit_points )
- monster_general_array[i].hit_points++;
- }
- }
- //--------- End of function FirmMonster::recover_hit_points -------//
- //--------- Begin of function FirmMonster::assign_unit ---------//
- //
- // Mobilized defender units are assigned back to the firm.
- //
- void FirmMonster::assign_unit(int unitRecno)
- {
- Unit* unitPtr = unit_array[unitRecno];
- UnitInfo* unitInfo = unit_res[unitPtr->unit_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 ; i<waiting_soldier_count ; i++ )
- {
- //--- if this waiting soldier was led by this general ---//
- if( waiting_soldier_array[i] == generalUnitRecno )
- {
- monsterInFirm->soldier_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 ---------//
- //
- // <int> 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<monster_general_count ; i++ )
- {
- if( monster_general_array[i].mobile_unit_recno == generalUnitRecno )
- {
- if(monster_general_array[i].soldier_count>=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 ; i<monster_general_count ; i++, monsterInFirm++ )
- {
- if( monsterInFirm->soldier_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.
- //
- // <int> generalId - id. of the general.
- // [int] mobilizeSoldier - whether also mobilize soldiers this general
- // commands. (default: 1)
- //
- // Return: <int> 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 ; i<monsterInFirm->soldier_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 ---------//
- //
- // <int> monsterId = id. of the monster to be mobilized
- // <int> rankId = rank id. of the monster.
- // <int> 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: <int> 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()
- //
- // <int> 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.
- //
- // <int> 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 ; i<monster_general_count ; i++, monsterInFirm++ )
- {
- totalCombatLevel += monsterInFirm->hit_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 ; i<monster_general_count ; i++, monsterInFirm++ )
- {
- if( monsterInFirm->soldier_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_count<MIN_GENERAL_EXPAND_NUM)
- return 0;
- //--- count the number of generals commanding 8 soldiers ----//
- int generalCount=0;
- MonsterInFirm* monsterInFirm = monster_general_array;
- for( int i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
- {
- if( monsterInFirm->soldier_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 ; i<monster_general_count ; i++, monsterInFirm++ )
- {
- if( monsterInFirm->soldier_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 -------//
|