123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757 |
- /*
- * 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 : OUNIT.CPP
- //Description : Object Unit
- #include <ALL.h>
- #include <ODATE.h>
- #include <OWORLD.h>
- #include <OVGA.h>
- #include <OSTR.h>
- #include <ONEWS.h>
- #include <OREBEL.h>
- #include <OSPY.h>
- #include <ONATION.h>
- #include <OFONT.h>
- #include <OBULLET.h>
- #include <OGAME.h>
- #include <OTOWN.h>
- #include <ORACERES.h>
- #include <ORAWRES.h>
- #include <OPOWER.h>
- #include <OU_VEHI.h>
- #include <OU_MARI.h>
- #include <OU_MONS.h>
- #include <OF_CAMP.h>
- #include <OF_MONS.h>
- #include <OF_HARB.h>
- #include <OMONSRES.h>
- #include <OREMOTE.h>
- #include <OSYS.h>
- #if(GAME_FRAMES_PER_DAY!=FRAMES_PER_DAY)
- #error
- #endif
- #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 Unit::Unit ---------//
- //
- Unit::Unit()
- {
- // ##### patch begin Gilbert 21/1 ######//
- // unit_id = 0;
- memset( sizeof(Sprite) + (char *)this, 0, sizeof(Unit) - sizeof(Sprite));
- // ##### patch end Gilbert 21/1 ######//
- }
- //----------- End of function Unit::Unit -----------//
- //--------- Begin of function Unit::~Unit ---------//
- //
- Unit::~Unit()
- {
- deinit();
- }
- //----------- End of function Unit::~Unit -----------//
- //--------- Begin of function Unit::init ---------//
- //
- // <int> unitId - the id. of the unit
- // <int> nationRecno - the recno of nation
- // [int] rankId - rank id. of the unit (none for non-human unit)
- // [int] unitLoyalty - loyalty of the unit (none for non-human unit)
- // [int] startXLoc, startYLoc - the starting location of the unit
- // (if startXLoc < 0, this is a unit for hire, and is not a unit of the game yet. init_sprite() won't be called for this unit)
- // (default: -1, -1)
- //
- // Note: sprite_recno must be initialized first before calling Unit::init()
- //
- void Unit::init(int unitId, int nationRecno, int rankId, int unitLoyalty, int startXLoc, int startYLoc)
- {
- //------------ set basic vars -------------//
- nation_recno = (char) nationRecno;
- rank_id = rankId; // rank_id must be initialized before init_unit_id() as init_unit_id() may overwrite it
- nation_contribution = 0; // nation_contribution must be initialized before init_unit_id() as init_unit_id() may overwrite it
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- {
- team_info = (TeamInfo*) mem_add( sizeof(TeamInfo) );
- team_info->member_count = 0;
- }
- else
- team_info = NULL;
- init_unit_id(unitId);
- group_select_id = 0;
- unit_group_id = unit_array.cur_group_id++;
- race_id = (char) unit_res[unit_id]->race_id;
- //------- init unit name ---------//
- if( race_id )
- {
- name_id = race_res[race_id]->get_new_name_id();
- }
- else //---- init non-human unit series no. ----//
- {
- if( nation_recno )
- name_id = ++nation_array[nation_recno]->last_unit_name_id_array[unit_id-1];
- else
- name_id = 0;
- }
- //------- init ai_unit ----------//
- if( nation_recno )
- ai_unit = nation_array[nation_recno]->nation_type == NATION_AI;
- else
- ai_unit = 0;
- err_when( unitLoyalty < 0 || unitLoyalty > 100 );
- //----------------------------------------------//
- ai_action_id = 0;
- action_misc = ACTION_MISC_STOP;
- action_misc_para = 0;
- action_mode2 = action_mode = ACTION_STOP;
- action_para2 = action_para = 0;
- action_x_loc2 = action_y_loc2 = action_x_loc = action_y_loc = -1;
- memset(blocked_edge, 0, sizeof(char)*4);
- attack_range = 0; //store the attack range of the current attack mode if the unit is ordered to attack
- leader_unit_recno= 0;
- team_id = 0;
- selected_flag = 0;
- waiting_term = 0;
- swapping = 0; // indicate whether swapping is processed.
- spy_recno = 0;
- range_attack_x_loc = -1;
- range_attack_y_loc = -1;
- //------- initialize path seek vars -------//
- result_node_array = NULL;
- result_node_count = result_node_recno = result_path_dist = 0;
- //------- initialize way point vars -------//
- way_point_array = NULL;
- way_point_array_size = 0;
- way_point_count = 0;
- //---------- initialize game vars ----------//
- unit_mode = 0;
- unit_mode_para = 0;
- max_hit_points = unit_res[unit_id]->hit_points;
- hit_points = max_hit_points;
- loyalty = unitLoyalty;
- can_guard_flag = 0;
- can_attack_flag = 1;
- force_move_flag = 0;
- ai_no_suitable_action = 0;
- cur_power = 0;
- max_power = 0;
- total_reward = 0;
- home_camp_firm_recno = 0;
- seek_path_fail_count = 0;
- ignore_power_nation = 0;
- aggressive_mode = 1; // the default mode is 1
- err_when( loyalty<0 || loyalty>100 );
- //--------- init skill potential ---------//
- if( m.random(10)==0 ) // 1 out of 10 has a higher than normal potential in this skill
- {
- skill.skill_potential = 50+m.random(51); // 50 to 100 potential
- }
- //------ initialize the base Sprite class -------//
- if( startXLoc >= 0 )
- init_sprite( startXLoc, startYLoc );
- else
- {
- cur_x = -1;
- }
- //------------- set attack_dir ------------//
- attack_dir = final_dir;
- //-------------- update loyalty -------------//
- update_loyalty();
- //--------------- init AI info -------------//
- if( ai_unit )
- {
- Nation* nationPtr = nation_array[nation_recno];
- if( rank_id==RANK_GENERAL || rank_id==RANK_KING )
- nationPtr->add_general_info(sprite_recno);
- switch( unit_res[unit_id]->unit_class )
- {
- case UNIT_CLASS_CARAVAN:
- nationPtr->add_caravan_info(sprite_recno);
- break;
- case UNIT_CLASS_SHIP:
- nationPtr->add_ship_info(sprite_recno);
- break;
- }
- }
- //----------- init derived class ----------//
- init_derived();
- }
- //----------- End of function Unit::init -----------//
- //--------- Begin of function Unit::init_unit_id ---------//
- void Unit::init_unit_id(int unitId)
- {
- unit_id = unitId;
- UnitInfo* unitInfo = unit_res[unit_id];
- sprite_id = unitInfo->sprite_id;
- sprite_info = sprite_res[sprite_id];
- mobile_type = unitInfo->mobile_type;
- //--- if this unit is a weapon unit with multiple versions ---//
- set_combat_level(100); // set combat level default to 100, for human units, it will be adjusted later by individual functions
- int techLevel;
- if( nation_recno &&
- unitInfo->unit_class == UNIT_CLASS_WEAPON &&
- (techLevel=unitInfo->nation_tech_level_array[nation_recno-1]) > 0 )
- {
- set_weapon_version(techLevel);
- }
- fix_attack_info();
- //-------- set unit count ----------//
- if( nation_recno )
- {
- if( rank_id != RANK_KING )
- unitInfo->inc_nation_unit_count(nation_recno);
- if( rank_id == RANK_GENERAL )
- unitInfo->inc_nation_general_count(nation_recno);
- }
- //--------- increase monster count ----------//
- if( unit_res[unit_id]->unit_class == UNIT_CLASS_MONSTER )
- unit_res.mobile_monster_count++;
- }
- //----------- End of function Unit::init_unit_id -----------//
- //--------- Begin of function Unit::deinit_unit_id ---------//
- void Unit::deinit_unit_id()
- {
- if( sys.signal_exit_flag )
- return;
- //-----------------------------------------//
- UnitInfo *unitInfo = unit_res[unit_id];
- if( nation_recno )
- {
- if( rank_id != RANK_KING )
- unitInfo->dec_nation_unit_count(nation_recno);
- if( rank_id == RANK_GENERAL )
- unitInfo->dec_nation_general_count(nation_recno);
- }
- //--------- if the unit is a spy ----------//
- //
- // A spy has double identity and is counted
- // by both the true controlling nation and
- // the deceiving nation.
- //
- //-----------------------------------------//
- if( spy_recno && true_nation_recno() != nation_recno )
- {
- err_when( !race_id );
- int trueNationRecno = true_nation_recno();
- if( rank_id != RANK_KING )
- unitInfo->dec_nation_unit_count(trueNationRecno);
- if( rank_id == RANK_GENERAL )
- unitInfo->dec_nation_general_count(trueNationRecno);
- }
- //--------- decrease monster count ----------//
- if( unit_res[unit_id]->unit_class == UNIT_CLASS_MONSTER )
- {
- unit_res.mobile_monster_count--;
- err_when( unit_res.mobile_monster_count < 0 );
- }
- }
- //----------- End of function Unit::deinit_unit_id -----------//
- //--------- Begin of function Unit::set_spy ---------//
- void Unit::set_spy(int spyRecno)
- {
- spy_recno = spyRecno;
- }
- //---------- End of function Unit::set_spy ---------//
- //--------- Begin of function Unit::init_sprite ---------//
- //
- // <int> startXLoc, startYLoc - the starting location of the unit
- //
- void Unit::init_sprite(int startXLoc, int startYLoc)
- {
- err_when( !world.get_loc(startXLoc, startYLoc)->can_move(unit_res[unit_id]->mobile_type) );
- err_when(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP && (startXLoc%2 || startYLoc%2));
- Sprite::init(unit_res[unit_id]->sprite_id, startXLoc, startYLoc);
- //--------------------------------------------------------------------//
- // move_to_?_loc is always the current location of the unit as
- // cur_action == SPRITE_IDLE
- //--------------------------------------------------------------------//
- original_action_mode = 0;
- ai_original_target_x_loc = -1;
- attack_range = 0;
- move_to_x_loc = next_x_loc();
- move_to_y_loc = next_y_loc();
- go_x = next_x;
- go_y = next_y;
- //-------- set the cargo_recno -------------//
- char w, h;
- short x, y;
- err_if(!sprite_recno) // sprite_recno must be initialized first before calling Unit::init()
- err_here();
- for(h=0, y=startYLoc; h<sprite_info->loc_height; h++, y++)
- {
- for(w=0, x=startXLoc; w<sprite_info->loc_width; w++, x++)
- {
- err_if( world.get_unit_recno(x, y, mobile_type) ) // it must be 0 to put the sprite in this location
- err_here();
- world.set_unit_recno(x, y, mobile_type, sprite_recno);
- }
- }
- if( is_own() ||
- (nation_recno && nation_array[nation_recno]->is_allied_with_player) )
- {
- world.unveil(startXLoc, startYLoc, startXLoc+sprite_info->loc_width-1,
- startYLoc+sprite_info->loc_height-1 );
- world.visit(startXLoc, startYLoc, startXLoc+sprite_info->loc_width-1,
- startYLoc+sprite_info->loc_height-1, unit_res[unit_id]->visual_range,
- unit_res[unit_id]->visual_extend);
- }
- err_when(result_node_array || result_path_dist);
- }
- //----------- End of function Unit::init_sprite -----------//
- //--------- Begin of function Unit::deinit ---------//
- void Unit::deinit()
- {
- err_when( unit_array.is_truly_deleted(sprite_recno) );
- if( !unit_id )
- return;
- //-------- if this is a king --------//
- if( !sys.signal_exit_flag && nation_recno )
- {
- if( rank_id == RANK_KING ) // check nation_recno because monster kings will die also.
- {
- king_die();
- err_when( unit_array.is_truly_deleted(sprite_recno) );
- }
- else if( rank_id == RANK_GENERAL )
- {
- general_die();
- err_when( unit_array.is_truly_deleted(sprite_recno) );
- }
- }
- //------------ free up team_info -----------//
- if( team_info )
- {
- mem_del(team_info);
- team_info = NULL;
- }
- //---- if this is a general, deinit its link with its soldiers ----//
- //
- // We do not use team_info because monsters and rebels also use
- // leader_unit_recno and they do not use keep the member info
- // in team_info.
- //
- //-----------------------------------------------------------------//
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- {
- for( int i=unit_array.size() ; i>0 ; i-- )
- {
- if( unit_array.is_deleted(i) )
- continue;
- if( unit_array[i]->leader_unit_recno == sprite_recno )
- unit_array[i]->leader_unit_recno = 0;
- }
- }
- //----- if this is a unit on a ship ------//
- if( unit_mode == UNIT_MODE_ON_SHIP )
- {
- if( !unit_array.is_deleted(unit_mode_para) ) // the ship may have been destroyed at the same time. Actually when the ship is destroyed, all units onboard are killed and this function is called.
- {
- Unit* unitPtr = unit_array[unit_mode_para];
- err_when( unit_res[unitPtr->unit_id]->unit_class != UNIT_CLASS_SHIP );
- ((UnitMarine*)unitPtr)->del_unit(sprite_recno);
- }
- }
- //----- if this is a ship in the harbor -----//
- else if( unit_mode == UNIT_MODE_IN_HARBOR )
- {
- if( !firm_array.is_deleted(unit_mode_para) ) // the ship may have been destroyed at the same time. Actually when the ship is destroyed, all firms onboard are killed and this function is called.
- {
- Firm* firmPtr = firm_array[unit_mode_para];
- err_when( firmPtr->firm_id != FIRM_HARBOR );
- ((FirmHarbor*)firmPtr)->del_hosted_ship(sprite_recno);
- }
- }
- //----- if this unit is a constructor in a firm -------//
- else if( unit_mode == UNIT_MODE_CONSTRUCT )
- {
- err_when( firm_array[unit_mode_para]->builder_recno != sprite_recno );
- firm_array[unit_mode_para]->builder_recno = 0;
- }
- //-------- if this is a spy ---------//
- if( spy_recno )
- {
- spy_array.del_spy( spy_recno );
- spy_recno = 0;
- }
- //---------- reset command ----------//
- if( power.command_unit_recno == sprite_recno )
- power.reset_command();
- //-----------------------------------//
- deinit_unit_id();
- //-------- reset seek path ----------//
- reset_path();
- //----- if cur_x == -1, the unit has not yet been hired -----//
- if( cur_x >= 0 )
- deinit_sprite();
- //------------------------------------------------//
- //
- // Prime rule:
- //
- // world.get_loc(next_x_loc() and next_y_loc())->cargo_recno
- // is always = sprite_recno
- //
- // no matter what cur_action is.
- //
- //------------------------------------------------//
- //
- // Relationship between (next_x, next_y) and (cur_x, cur_y)
- //
- // when SPRITE_WAIT, SPRITE_IDLE, SPRITE_READY_TO_MOVE,
- // SPRITE_ATTACK, SPRITE_DIE:
- //
- // (next_x, next_y) == (cur_x, cur_y), it's the location of the sprite.
- //
- // when SPRITE_MOVE:
- //
- // (next_x, next_y) != (cur_x, cur_y)
- // (next_x, next_y) is where the sprite is moving towards.
- // (cur_x , cur_y ) is the location of the sprite.
- //
- //------------------------------------------------//
- //--------------- deinit AI info -------------//
- if( ai_unit )
- {
- if( !nation_array.is_deleted(nation_recno) )
- {
- Nation* nationPtr = nation_array[nation_recno];
- if( rank_id==RANK_GENERAL || rank_id==RANK_KING )
- nationPtr->del_general_info(sprite_recno);
- switch( unit_res[unit_id]->unit_class )
- {
- case UNIT_CLASS_CARAVAN:
- nationPtr->del_caravan_info(sprite_recno);
- break;
- case UNIT_CLASS_SHIP:
- nationPtr->del_ship_info(sprite_recno);
- break;
- }
- }
- }
- //-------------- reset unit_id ---------------//
- unit_id = 0;
- }
- //----------- End of function Unit::deinit -----------//
- //--------- Begin of function Unit::deinit_sprite ---------//
- //
- // [int] keepSelected - keep it selected if it is current selected.
- // (default: 0)
- //
- void Unit::deinit_sprite(int keepSelected)
- {
- err_when(result_node_array!=NULL);
- if( cur_x == -1 )
- return;
- //---- if this unit is led by a leader, only mobile units has leader_unit_recno assigned to a leader -----//
- if( leader_unit_recno )
- {
- if( !unit_array.is_deleted(leader_unit_recno) ) // the leader unit may have been killed at the same time
- unit_array[leader_unit_recno]->del_team_member(sprite_recno);
- leader_unit_recno = 0;
- }
- //-------- clear the cargo_recno ----------//
- short w, h;
- short x, y;
- for(h=0, y=next_y_loc(); h<sprite_info->loc_height; h++, y++)
- {
- for(w=0, x=next_x_loc(); w<sprite_info->loc_width; w++, x++)
- {
- err_if( world.get_unit_recno(x, y, mobile_type) != sprite_recno ) // it must be 0 to put the sprite in this location
- err_here();
- world.set_unit_recno(x, y, mobile_type, 0);
- }
- }
- cur_x = -1;
- //---- reset other parameters related to this unit ----//
- if( !keepSelected )
- {
- if( unit_array.selected_recno == sprite_recno )
- {
- unit_array.selected_recno = 0;
- info.disp();
- }
- if( power.command_unit_recno == sprite_recno )
- power.command_id = 0;
- }
- //------- deinit unit mode -------//
- deinit_unit_mode();
- }
- //----------- End of function Unit::deinit_sprite -----------//
- //--------- Begin of function Unit::deinit_unit_mode ---------//
- //
- void Unit::deinit_unit_mode()
- {
- if( sys.signal_exit_flag )
- return;
- //----- this unit was defending the town before it gets killed ----//
- if(unit_mode==UNIT_MODE_DEFEND_TOWN)
- {
- if(!town_array.is_deleted(unit_mode_para))
- {
- Town *townPtr = town_array[unit_mode_para];
- if(nation_recno == townPtr->nation_recno)
- townPtr->reduce_defender_count();
- }
- set_mode(0); // reset mode
- }
- //----- this is a monster unit defending its town ------//
- else if( unit_mode==UNIT_MODE_MONSTER && unit_mode_para )
- {
- if(((UnitMonster*)this)->monster_action_mode!=MONSTER_ACTION_DEFENSE)
- return;
- FirmMonster* firmMonster = (FirmMonster*) firm_array[unit_mode_para];
- err_when( firmMonster->firm_id != FIRM_MONSTER );
- firmMonster->reduce_defender_count(rank_id);
- }
- }
- //----------- End of function Unit::deinit_unit_mode -----------//
- //--------- Begin of function Unit::king_die ---------//
- //
- void Unit::king_die()
- {
- //--------- add news ---------//
- news_array.king_die(nation_recno);
- //--- see if the units, firms and towns of the nation are all destroyed ---//
- Nation* nationPtr = nation_array[nation_recno];
- nationPtr->king_unit_recno = 0;
- }
- //----------- End of function Unit::king_die -----------//
- //--------- Begin of function Unit::general_die ---------//
- //
- void Unit::general_die()
- {
- //--------- add news ---------//
- if( nation_recno == nation_array.player_recno )
- news_array.general_die(sprite_recno);
- }
- //----------- End of function Unit::general_die -----------//
- //--------- Begin of function Unit::unit_name ---------//
- //
- // [int] withTitle - whether return a string with the title of the unit
- // or not. (default: 1)
- //
- char* Unit::unit_name(int withTitle)
- {
- static String str;
- UnitInfo* unitInfo = unit_res[unit_id];
- //------------------------------------//
- if( race_id )
- {
- str = "";
- if( withTitle )
- {
- if( unit_mode == UNIT_MODE_REBEL )
- {
- if( rank_id == RANK_GENERAL )
- str = "Rebel Leader ";
- }
- else
- {
- if( rank_id == RANK_KING )
- str = "King ";
- else if( rank_id == RANK_GENERAL )
- str = "General ";
- }
- }
- str = translate.process(str);
- if( rank_id == RANK_KING ) // use the player name
- str += nation_array[nation_recno]->king_name();
- else
- str += race_res[race_id]->get_name(name_id);
- }
- else
- {
- str = unitInfo->name;
- //--- for weapons, the rank_id is used to store the version of the weapon ---//
- if( unitInfo->unit_class == UNIT_CLASS_WEAPON && get_weapon_version() > 1 )
- {
- str += " ";
- str += m.roman_number(get_weapon_version());
- }
- if( unitInfo->unit_class != UNIT_CLASS_GOD ) // God doesn't have any series no.
- {
- str += " ";
- str += name_id; // name id is the series no. of the unit
- }
- }
- return str;
- }
- //----------- End of function Unit::unit_name ---------//
- //--------- Begin of function Unit::set_name ---------//
- //
- // Set the name id. of this unit.
- //
- void Unit::set_name(WORD newNameId)
- {
- //------- free up the existing name id. ------//
- race_res[race_id]->free_name_id(name_id);
- //------- set the new name id. ---------//
- name_id = newNameId;
- //-------- register usage of the new name id. ------//
- race_res[race_id]->use_name_id(name_id);
- }
- //----------- End of function Unit::set_name ---------//
- //--------- Begin of function Unit::is_own ---------//
- //
- int Unit::is_own()
- {
- return is_nation(nation_array.player_recno);
- }
- //----------- End of function Unit::is_own ---------//
- //--------- Begin of function Unit::is_own_spy ---------//
- //
- int Unit::is_own_spy()
- {
- return spy_recno && spy_array[spy_recno]->true_nation_recno == nation_array.player_recno;
- }
- //----------- End of function Unit::is_own_spy ---------//
- //--------- Begin of function Unit::is_nation ---------//
- //
- // Whether the unit belongs to the specific nation.
- //
- int Unit::is_nation(int nationRecno)
- {
- if( nation_recno == nationRecno )
- return 1;
- if( spy_recno && spy_array[spy_recno]->true_nation_recno == nationRecno )
- return 1;
- return 0;
- }
- //----------- End of function Unit::is_nation ---------//
- //--------- Begin of function Unit::is_civilian ---------//
- //
- int Unit::is_civilian()
- {
- return race_id>0 && skill.combat_level<20 &&
- skill.skill_id != SKILL_LEADING &&
- unit_mode != UNIT_MODE_DEFEND_TOWN &&
- unit_mode != UNIT_MODE_REBEL;
- }
- //----------- End of function Unit::is_civilian ---------//
- //--------- Begin of function Unit::true_nation_recno ---------//
- //
- // The true nation recno of the unit, taking care of the
- // situation where the unit is a spy.
- //
- int Unit::true_nation_recno()
- {
- if( spy_recno )
- return spy_array[spy_recno]->true_nation_recno;
- else
- return nation_recno;
- }
- //----------- End of function Unit::true_nation_recno ---------//
- //--------- Begin of function Unit::next_day ---------//
- //
- void Unit::next_day()
- {
- int unitRecno = sprite_recno;
- err_when( unit_array.is_deleted(unitRecno) );
- err_when( race_id && !is_visible() && unit_mode==0 );
- #ifdef DEBUG
- if( unit_mode == UNIT_MODE_UNDER_TRAINING )
- {
- Town* townPtr =town_array[unit_mode_para];
- err_when( townPtr->train_unit_recno != sprite_recno );
- err_when( townPtr->nation_recno != nation_recno );
- }
- #endif
- //------- functions for non-independent nations only ------//
- if( nation_recno )
- {
- pay_expense();
- if( unit_array.is_deleted(unitRecno) ) // if its hit points go down to 0, is_deleted() will return 1.
- return;
- //------- update loyalty -------------//
- if( info.game_date%30 == sprite_recno%30 )
- {
- update_loyalty();
- err_when( unit_array.is_deleted(unitRecno) );
- }
- //------- think about rebeling -------------//
- if( info.game_date%15 == sprite_recno%15 )
- {
- if( think_betray() )
- return;
- }
- }
- //------- recover from damage -------//
- if( info.game_date%15 == sprite_recno%15 ) // recover one point per two weeks
- {
- process_recover();
- err_when( unit_array.is_deleted(unitRecno) );
- }
- //------- restore cur_power --------//
- cur_power += 5;
- if( cur_power > max_power)
- cur_power = max_power;
- //------- king undie flag (for testing games only) --------//
- if( config.king_undie_flag && rank_id == RANK_KING &&
- nation_recno && !nation_array[nation_recno]->is_ai() )
- {
- hit_points = max_hit_points;
- }
- //-------- if aggresive_mode is 1 --------//
- if( nation_recno && is_visible() )
- think_aggressive_action();
- //---------- debug ------------//
- #ifdef DEBUG
- err_when( unit_res[unit_id]->unit_class != UNIT_CLASS_HUMAN && race_id );
- if( spy_recno )
- {
- err_when( spy_array.is_deleted(spy_recno) );
- Spy* spyPtr = spy_array[spy_recno];
- err_when( nation_recno != spyPtr->cloaked_nation_recno );
- if( unit_mode == UNIT_MODE_OVERSEE )
- {
- err_when( spyPtr->spy_place != SPY_FIRM );
- err_when( spyPtr->spy_place_para != unit_mode_para );
- }
- else
- {
- err_when( spyPtr->spy_place != SPY_MOBILE );
- err_when( spyPtr->spy_place_para != sprite_recno );
- }
- }
- if( leader_unit_recno )
- {
- Unit* unitPtr = unit_array[leader_unit_recno];
- err_when( unitPtr->rank_id != RANK_GENERAL && unitPtr->rank_id != RANK_KING );
- }
- err_when( (rank_id == RANK_GENERAL || rank_id == RANK_KING) &&
- !team_info );
- if( leader_unit_recno )
- {
- err_when( unit_array.is_truly_deleted(leader_unit_recno) );
- err_when( unit_array[leader_unit_recno]->nation_recno != nation_recno );
- // err_when( unit_array[leader_unit_recno]->team_id != team_id );
- }
- err_when( hit_points > max_hit_points );
- err_when( max_hit_points == 0 );
- err_when( skill.combat_level<=0 );
- err_when( skill.combat_level>100 );
- err_when( unit_mode==UNIT_MODE_REBEL && spy_recno ); // no rebel spies
- err_when( unit_mode==UNIT_MODE_REBEL && nation_recno ); // all rebels must be independent units
- err_when( unit_mode==UNIT_MODE_DEFEND_TOWN && spy_recno ); // no rebel spies
- err_when( loyalty < 0 || loyalty > 100 );
- err_when( skill.skill_id == SKILL_SPYING ); // skill.skill_id should never be SKILL_SPYING, it will be shown in spy_recno if it's a spy
- err_when( nation_contribution < 0 );
- err_when( nation_contribution > MAX_NATION_CONTRIBUTION );
- err_when( ai_unit && ( !nation_recno || !nation_array[nation_recno]->is_ai() ) );
- #else // fix bug on fly in the release version
- if( skill.combat_level > 100 )
- skill.combat_level = 100;
- #endif
- }
- //----------- End of function Unit::next_day -----------//
- //--------- Begin of function Unit::process_recover ---------//
- //
- void Unit::process_recover()
- {
- if( hit_points==0 || hit_points == max_hit_points ) // this unit is dead already
- return;
- err_when( hit_points > max_hit_points );
- //---- overseers in firms and ships in harbors recover faster ----//
- int hitPointsInc;
- if( unit_mode == UNIT_MODE_OVERSEE ||
- unit_mode == UNIT_MODE_IN_HARBOR )
- {
- hitPointsInc = 2;
- }
- //------ for units on ships --------//
- else if( unit_mode == UNIT_MODE_ON_SHIP )
- {
- //--- if the ship where the unit is on is in the harbor, the unit recovers faster ---//
- if( unit_array[unit_mode_para]->unit_mode == UNIT_MODE_IN_HARBOR )
- hitPointsInc = 2;
- else
- hitPointsInc = 1;
- }
- //----- only recover when the unit is not moving -----//
- else if( cur_action == SPRITE_IDLE )
- {
- hitPointsInc = 1;
- }
- else
- return;
- //---------- recover now -----------//
- hit_points += hitPointsInc;
- if( hit_points > max_hit_points )
- hit_points = max_hit_points;
- }
- //----------- End of function Unit::process_recover -----------//
- //--------- Begin of function Unit::update_loyalty ---------//
- //
- // How loyalty of units are updated:
- //
- // General: in a military camp - updated in FirmCamp::update_loyalty()
- // mobile - no update
- //
- // Soldiers led by a general: in a military camp - updated in FirmCamp::update_loyalty()
- // mobile - updated here
- //
- // Other units: no update.
- //
- void Unit::update_loyalty()
- {
- if( !nation_recno || rank_id==RANK_KING || !unit_res[unit_id]->race_id )
- return;
- if( unit_mode == UNIT_MODE_CONSTRUCT ) // constructor worker will not change their loyalty when they are in a building
- return;
- //----- if this unit is a spy, set its fake loyalty ------//
- if( spy_recno ) // a spy's loyalty is always >= 70
- {
- if( loyalty < 70 )
- loyalty = 70+m.random(20); // initialize it to be a number between 70 and 90
- target_loyalty = loyalty;
- return;
- }
- //-------- if this is a general ---------//
- Nation* ownNation = nation_array[nation_recno];
- int rc=0;
- if( rank_id==RANK_GENERAL )
- {
- //----- the general's power affect his loyalty ----//
- int targetLoyalty = commander_power();
- //----- the king's race affects the general's loyalty ----//
- if( ownNation->race_id == race_id )
- targetLoyalty += 20;
- //----- the kingdom's reputation affects the general's loyalty ----//
- targetLoyalty += (int)ownNation->reputation/4;
- //--- the king's leadership also affect the general's loyalty -----//
- if( ownNation->king_unit_recno )
- targetLoyalty += unit_array[ownNation->king_unit_recno]->skill.skill_level / 4;
- //-- if the unit is rewarded less than the amount of contribution he made, he will become unhappy --//
- if( nation_contribution > total_reward*2 )
- {
- int decLoyalty = (nation_contribution - total_reward*2)/2;
- targetLoyalty -= min(50, decLoyalty); // this affect 50 points at maximum
- }
- targetLoyalty = min( targetLoyalty, 100 );
- target_loyalty = max( targetLoyalty, 0 );
- }
- //-------- if this is a soldier ---------//
- else if( rank_id==RANK_SOLDIER )
- {
- if( leader_unit_recno )
- {
- //----------------------------------------//
- //
- // If this soldier is led by a general,
- // the targeted loyalty
- //
- // = race friendliness between the unit and the general / 2
- // + the leader unit's leadership / 2
- //
- //----------------------------------------//
- if( unit_array.is_deleted(leader_unit_recno) )
- {
- leader_unit_recno = 0;
- return;
- }
- Unit* leaderUnit = unit_array[leader_unit_recno];
- int targetLoyalty = 30 + leaderUnit->skill.get_skill(SKILL_LEADING);
- //---------------------------------------------------//
- //
- // Soldiers with higher combat and leadership skill
- // will get discontented if they are led by a general
- // with low leadership.
- //
- //---------------------------------------------------//
- targetLoyalty -= skill.combat_level/2;
- targetLoyalty -= skill.skill_level;
- if( leaderUnit->rank_id == RANK_KING )
- targetLoyalty += 20;
- if( race_res.is_same_race(race_id, leaderUnit->race_id) )
- targetLoyalty += 20;
- if( targetLoyalty < 0 )
- targetLoyalty = 0;
- targetLoyalty = min( targetLoyalty, 100 );
- target_loyalty = max( targetLoyalty, 0 );
- }
- else
- {
- target_loyalty = 0;
- }
- }
- //--------- update loyalty ---------//
- err_when( target_loyalty < 0 || target_loyalty > 100 );
- if( target_loyalty > loyalty ) // only increase, no decrease. Decrease are caused by events. Increases are made gradually
- {
- int incValue = (target_loyalty - loyalty)/10;
- int newLoyalty = (int) loyalty + max(1, incValue);
- if( newLoyalty > target_loyalty )
- newLoyalty = target_loyalty;
- loyalty = newLoyalty;
- }
- else if( target_loyalty < loyalty ) // only increase, no decrease. Decrease are caused by events. Increases are made gradually
- {
- loyalty--;
- }
- err_when( loyalty < 0 || loyalty > 100 );
- }
- //-------- End of function Unit::update_loyalty -----------//
- //--------- Begin of function Unit::commander_power ---------//
- //
- // A commander's power is determined:
- //
- // -Population of the towns he controls
- // -The employment rate of the towns he controls, the higher the
- // employment rate, the higher his power is
- // -If there are any other commanders controls the towns at the same time.
- // -the no. of soldiers led by the commander and their combat levels.
- //
- int Unit::commander_power()
- {
- //---- if the commander is in a military camp -----//
- int commanderPower=0;
- if( unit_mode == UNIT_MODE_OVERSEE )
- {
- Firm* firmPtr = firm_array[unit_mode_para];
- if( firmPtr->firm_id == FIRM_CAMP )
- {
- Town* townPtr;
- for( int i=firmPtr->linked_town_count-1 ; i>=0 ; i-- )
- {
- if( firmPtr->linked_town_enable_array[i] == LINK_EE )
- {
- townPtr = town_array[firmPtr->linked_town_array[i]];
- commanderPower += townPtr->population / townPtr->linked_active_camp_count();
- }
- }
- commanderPower += firmPtr->worker_count*3; // 0 to 24
- }
- else if( firmPtr->firm_id == FIRM_BASE )
- {
- commanderPower = 60;
- }
- }
- else
- {
- commanderPower = team_info->member_count*3; // 0 to 24
- }
- return commanderPower;
- }
- //----------- End of function Unit::commander_power -----------//
- //--------- Begin of function Unit::think_betray ---------//
- //
- int Unit::think_betray()
- {
- int unitRecno = sprite_recno;
- err_when( unit_array.is_deleted(unitRecno) );
- if( spy_recno ) // spies do not betray here, spy has its own functions for betrayal
- return 0;
- //----- if the unit is in training or is constructing a building, do not rebel -------//
- if( !is_visible() && unit_mode != UNIT_MODE_OVERSEE )
- return 0;
- if( loyalty >= UNIT_BETRAY_LOYALTY ) // you when unit is
- return 0;
- if( !unit_res[unit_id]->race_id || !nation_recno ||
- rank_id==RANK_KING || spy_recno )
- {
- return 0;
- }
- err_when(unit_res[unit_id]->unit_class == UNIT_CLASS_GOD);
- err_when(unit_id==UNIT_CARAVAN);
- //------ turn towards other nation --------//
- int i, bestNationRecno=0, nationScore, bestScore=loyalty; // the score must be larger than the current loyalty
- Nation *curNation, *nationPtr;
- int unitRegionId = region_id();
- if( loyalty==0 ) // if the loyalty is 0, it will definitely betray
- bestScore = -100;
- curNation = nation_array[nation_recno];
- for( i=nation_array.size() ; i>0 ; i-- )
- {
- if( nation_array.is_deleted(i) )
- continue;
- if( !curNation->get_relation(i)->has_contact || i==nation_recno )
- continue;
- nationPtr = nation_array[i];
- //--- only if the nation has a base town in the region where the unit stands ---//
- if( !region_array.nation_has_base_town(unitRegionId, i) )
- continue;
- //------------------------------------------------//
- nationScore = (int) nationPtr->reputation
- + (nationPtr->overall_rating - curNation->overall_rating);
- if( race_res.is_same_race(nationPtr->race_id, race_id) )
- nationScore += 30;
- if( nationScore > bestScore )
- {
- bestScore = nationScore;
- bestNationRecno = i;
- }
- }
- err_when( unit_array.is_deleted(unitRecno) );
- if( bestNationRecno )
- {
- return betray(bestNationRecno);
- }
- else if( loyalty==0 )
- {
- //----------------------------------------------//
- // If there is no good nation to turn towards to and
- // the loyalty has dropped to 0, resign itself and
- // leave the nation.
- //
- // However, if the unit is spy, it will stay with the
- // nation as it has never been really loyal to the nation.
- //---------------------------------------------//
- if( rank_id != RANK_KING && is_visible() &&
- !spy_recno )
- {
- resign(COMMAND_AUTO);
- return 1;
- }
- }
- return 0;
- }
- //-------- End of function Unit::think_betray -----------//
- //--------- Begin of function Unit::betray ---------//
- //
- // If this unit is a spy, this function betray() will be
- // called by Unit::spy_change_nation() or Firm::capture_firm().
- //
- // If this is not a spy, this function will only be called
- // by think_betray() and other nation deinit functions.
- //
- int Unit::betray(int newNationRecno)
- {
- int unitRecno = sprite_recno;
- //### begin alex 18/3 ###//
- //err_when( unit_array.is_deleted(unitRecno) );
- err_when( unit_array.is_truly_deleted(unitRecno) );
- //#### end alex 18/3 ####//
- err_when( rank_id == RANK_KING );
- if( nation_recno == newNationRecno )
- return 0;
- if( unit_mode == UNIT_MODE_CONSTRUCT || // don't change nation when the unit is constructing a firm
- unit_mode == UNIT_MODE_ON_SHIP ) // don't change nation when the unit is constructing a firm
- {
- return 0;
- }
- //---------- add news -----------//
- if( nation_recno == nation_array.player_recno ||
- newNationRecno == nation_array.player_recno )
- {
- //--- if this is a spy, don't display news message for betrayal as it is already displayed in Unit::spy_change_nation() ---//
- if( !spy_recno )
- news_array.unit_betray(sprite_recno, newNationRecno);
- }
- //------ change nation now ------//
- //### begin alex 18/3 ###//
- //err_when( unit_array.is_deleted(unitRecno) );
- err_when( unit_array.is_truly_deleted(unitRecno) );
- //#### end alex 18/3 ####//
- change_nation(newNationRecno);
- //### begin alex 18/3 ###//
- //err_when( unit_array.is_deleted(unitRecno) );
- err_when( unit_array.is_truly_deleted(unitRecno) );
- //#### end alex 18/3 ####//
- //-------- set the loyalty of the unit -------//
- if( nation_recno )
- {
- Nation* nationPtr = nation_array[nation_recno];
- loyalty = UNIT_BETRAY_LOYALTY + m.random(5);
- if( nationPtr->reputation > 0 )
- change_loyalty( (int) nationPtr->reputation );
- if( race_res.is_same_race( nationPtr->race_id, race_id ) )
- change_loyalty( 30 );
- err_when( loyalty < 0 || loyalty > 100 );
- update_loyalty(); // update target loyalty
- }
- else //------ if change to independent rebel -------//
- {
- loyalty = 0; // no loyalty needed
- }
- //--- if this unit is a general, change nation for the units he commands ---//
- DWORD newTeamId = unit_array.cur_team_id++;
- if( rank_id==RANK_GENERAL )
- {
- Unit* unitPtr;
- int i, nationReputation = (int) nation_array[nation_recno]->reputation;
- for( i=unit_array.size() ; i>0 ; i-- )
- {
- if( unit_array.is_deleted(i) )
- continue;
- unitPtr = unit_array[i];
- //---- capture the troop this general commands -----//
- if( unitPtr->leader_unit_recno == sprite_recno &&
- unitPtr->rank_id == RANK_SOLDIER && unitPtr->is_visible() )
- {
- if( unitPtr->spy_recno ) // if the unit is a spy
- unitPtr->spy_change_nation(newNationRecno, COMMAND_AUTO);
- else
- unitPtr->change_nation(newNationRecno);
- unitPtr->team_id = newTeamId; // assign new team_id or checking for nation_recno
- }
- }
- }
- team_id = newTeamId;
- //### begin alex 18/3 ###//
- //err_when( unit_array.is_deleted(unitRecno) );
- err_when( unit_array.is_truly_deleted(unitRecno) );
- //#### end alex 18/3 ####//
- //------ go to meet the new master -------//
- if( is_visible() && nation_recno )
- {
- if( !spy_recno || spy_array[spy_recno]->notify_cloaked_nation_flag )
- {
- if( rank_id == RANK_GENERAL ) // generals shouldn't automatically be assigned to camps, they should just move near your villages
- ai_move_to_nearby_town();
- else
- think_normal_human_action(); // this is an AI function in OUNITAI.CPP
- }
- }
- //### begin alex 18/3 ###//
- //err_when( unit_array.is_deleted(unitRecno) );
- err_when( unit_array.is_truly_deleted(unitRecno) );
- //#### end alex 18/3 ####//
- return 1;
- }
- //-------- End of function Unit::betray -----------//
- //--------- Begin of function Unit::change_nation ---------//
- //
- // This function is called when a unit change nation.
- // It is not necessarily a result of betray, when a spy
- // hands over his new nation to his parent nation, this
- // function will also be called.
- //
- // <int> newNationRecno - change the nation of the unit.
- //
- void Unit::change_nation(int newNationRecno)
- {
- err_when( newNationRecno && nation_array.is_deleted(newNationRecno) );
- err_when( unit_mode == UNIT_MODE_REBEL ); // rebels do not change nation
- //---------------------------------//
- int oldAiUnit = ai_unit;
- int oldNationRecno = nation_recno;
- group_select_id = 0; // clear group select id
- if(way_point_count)
- reset_way_point_array();
- //-- if the player is giving a command to this unit, cancel the command --//
- if( nation_recno == nation_array.player_recno &&
- sprite_recno == unit_array.selected_recno &&
- power.command_id )
- {
- power.command_id = 0;
- }
- //---------- stop all action to attack this unit ------------//
- unit_array.stop_attack_unit(sprite_recno);
- //---- update nation_unit_count_array[] ----//
- unit_res[unit_id]->unit_change_nation(newNationRecno, nation_recno, rank_id);
- //------- if the nation has an AI action -------//
- stop2(); // clear the existing order
- //---------------- update vars ----------------//
- unit_group_id = unit_array.cur_group_id++; // separate from the current group
- nation_recno = newNationRecno;
- home_camp_firm_recno = 0; // reset it
- original_action_mode = 0;
- if( race_id )
- {
- nation_contribution = 0; // contribution to the nation
- total_reward = 0;
- }
- //-------- if change to one of the existing nations ------//
- ai_unit = nation_recno && nation_array[nation_recno]->is_ai();
- //------------ update AI info --------------//
- if( oldAiUnit )
- {
- Nation* nationPtr = nation_array[oldNationRecno];
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- nationPtr->del_general_info(sprite_recno);
- else if( unit_res[unit_id]->unit_class == UNIT_CLASS_CARAVAN )
- nationPtr->del_caravan_info(sprite_recno);
- else if( unit_res[unit_id]->unit_class == UNIT_CLASS_SHIP )
- nationPtr->del_ship_info(sprite_recno);
- }
- if( ai_unit && nation_recno != 0 )
- {
- Nation* nationPtr = nation_array[nation_recno];
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- nationPtr->add_general_info(sprite_recno);
- else if( unit_res[unit_id]->unit_class == UNIT_CLASS_CARAVAN )
- nationPtr->add_caravan_info(sprite_recno);
- else if( unit_res[unit_id]->unit_class == UNIT_CLASS_SHIP )
- nationPtr->add_ship_info(sprite_recno);
- }
- //------ if this unit oversees a firm -----//
- if( unit_mode==UNIT_MODE_OVERSEE )
- firm_array[unit_mode_para]->change_nation(newNationRecno);
- //----- this unit was defending the town before it gets killed ----//
- else if( unit_mode==UNIT_MODE_DEFEND_TOWN )
- {
- if( !town_array.is_deleted(unit_mode_para) )
- town_array[unit_mode_para]->reduce_defender_count();
- set_mode(0); // reset unit mode
- }
- //---- if the unit is no longer the same nation as the leader ----//
- if( leader_unit_recno )
- {
- Unit* leaderUnit = unit_array[leader_unit_recno];
- if( leaderUnit->nation_recno != nation_recno )
- {
- leaderUnit->del_team_member(sprite_recno);
- leader_unit_recno = 0;
- team_id = 0;
- }
- }
- //------ if it is currently selected -------//
- if( selected_flag )
- info.disp();
- }
- //----------- End of function Unit::change_nation -----------//
- //--------- Begin of function Unit::pay_expense ---------//
- //
- void Unit::pay_expense()
- {
- if( game.game_mode == GAME_TEST ) // no deduction in testing game
- return;
- if( !nation_recno )
- return;
- //--- if it's a mobile spy or the spy is in its own firm, no need to pay salary here as Spy::pay_expense() will do that ---//
- //
- // -If your spies are mobile:
- // >your nation pays them 1 food and $5 dollars per month
- //
- // -If your spies are in an enemy's town or firm:
- // >the enemy pays them 1 food and the normal salary of their jobs.
- //
- // >your nation pays them $5 dollars per month. (your nation pays them no food)
- //
- // -If your spies are in your own town or firm:
- // >your nation pays them 1 food and $5 dollars per month
- //
- //------------------------------------------------------//
- if( spy_recno )
- {
- if( is_visible() ) // the cost will be deducted in spy_array
- return;
- if( unit_mode == UNIT_MODE_OVERSEE &&
- firm_array[unit_mode_para]->nation_recno == true_nation_recno() )
- {
- return;
- }
- }
- //---------- if it's a human unit -----------//
- //
- // The unit is paid even during its training period in a town
- //
- //-------------------------------------------//
- Nation* nationPtr = nation_array[nation_recno];
- if( unit_res[unit_id]->race_id )
- {
- //---------- reduce cash -----------//
- if( nationPtr->cash > 0 )
- {
- if( rank_id == RANK_SOLDIER )
- nationPtr->add_expense( EXPENSE_MOBILE_UNIT, (float) SOLDIER_YEAR_SALARY / 365, 1 );
- if( rank_id == RANK_GENERAL )
- nationPtr->add_expense( EXPENSE_GENERAL, (float) GENERAL_YEAR_SALARY / 365, 1 );
- }
- else // decrease loyalty if the nation cannot pay the unit
- {
- change_loyalty(-1);
- }
- //---------- reduce food -----------//
- if( unit_res[unit_id]->race_id ) // if it's a human unit
- {
- if( nationPtr->food > 0 )
- nationPtr->consume_food((float) PERSON_FOOD_YEAR_CONSUMPTION / 365);
- else
- {
- if( info.game_date%NO_FOOD_LOYALTY_DECREASE_INTERVAL == 0 ) // decrease 1 loyalty point every 2 days
- change_loyalty(-1);
- }
- }
- }
- else //----- it's a non-human unit ------//
- {
- if( nationPtr->cash > 0 )
- {
- int expenseType;
- switch(unit_res[unit_id]->unit_class)
- {
- case UNIT_CLASS_WEAPON:
- expenseType = EXPENSE_WEAPON;
- break;
- case UNIT_CLASS_SHIP:
- expenseType = EXPENSE_SHIP;
- break;
- case UNIT_CLASS_CARAVAN:
- expenseType = EXPENSE_CARAVAN;
- break;
- default:
- expenseType = EXPENSE_MOBILE_UNIT;
- }
- nationPtr->add_expense( expenseType, (float) unit_res[unit_id]->year_cost / 365, 1 );
- }
- else // decrease hit points if the nation cannot pay the unit
- {
- if( unit_res[unit_id]->unit_class != UNIT_CLASS_CARAVAN ) // Even when caravans are not paid, they still stay in your service.
- {
- if( hit_points > 0 )
- {
- hit_points--;
- if( hit_points < 0 )
- hit_points = (float) 0;
- //--- when the hit points drop to zero and the unit is destroyed ---//
- if( hit_points==0 )
- {
- if( nation_recno == nation_array.player_recno )
- {
- int unitClass = unit_res[unit_id]->unit_class;
- if( unitClass==UNIT_CLASS_WEAPON )
- news_array.weapon_ship_worn_out(unit_id, get_weapon_version());
- else if( unitClass==UNIT_CLASS_SHIP )
- news_array.weapon_ship_worn_out(unit_id, 0);
- }
- }
- }
- }
- }
- }
- }
- //----------- End of function Unit::pay_expense -----------//
- //--------- Begin of function Unit::change_hit_points ---------//
- //
- void Unit::change_hit_points(float changePoints)
- {
- hit_points += changePoints;
- if( hit_points < 0 )
- hit_points = (float) 0;
- if( hit_points > max_hit_points )
- hit_points = max_hit_points;
- }
- //-------- End of function Unit::change_hit_points -----------//
- //--------- Begin of function Unit::change_loyalty ---------//
- //
- // <int> changeAmt - amount of loyalty to be changed.
- //
- void Unit::change_loyalty(int changeAmt)
- {
- int newLoyalty = loyalty + changeAmt;
- newLoyalty = max(0, newLoyalty);
- loyalty = min(100, newLoyalty);
- }
- //----------- End of function Unit::change_loyalty -----------//
- //------- Begin of function Unit::inc_minor_combat_level --------//
- //
- void Unit::inc_minor_combat_level(int incLevel)
- {
- err_when( incLevel<0 || incLevel>100 ); // it cannot be larger than 100, because the current code can't handle it
- skill.combat_level_minor += incLevel;
- if( skill.combat_level_minor > 100 )
- {
- if( skill.combat_level < 100 )
- set_combat_level(skill.combat_level+1);
- skill.combat_level_minor -= 100;
- }
- }
- //-------- End of function Unit::inc_minor_combat_level ---------//
- //------- Begin of function Unit::inc_minor_skill_level --------//
- //
- void Unit::inc_minor_skill_level(int incLevel)
- {
- err_when( incLevel<0 || incLevel>100 );
- skill.skill_level_minor += incLevel;
- if( skill.skill_level_minor > 100 )
- {
- if( skill.skill_level < 100 )
- skill.skill_level++;
- skill.skill_level_minor -= 100;
- }
- }
- //-------- End of function Unit::inc_minor_skill_level ---------//
- //--------- Begin of function Unit::set_combat_level ---------//
- //
- void Unit::set_combat_level(int combatLevel)
- {
- err_when( combatLevel<=0 || combatLevel>100 );
- skill.combat_level = combatLevel;
- UnitInfo* unitInfo = unit_res[unit_id];
- int oldMaxHitPoints = max_hit_points;
- max_hit_points = unitInfo->hit_points * combatLevel / 100;
- hit_points = hit_points * max_hit_points / oldMaxHitPoints;
- hit_points = min(hit_points, max_hit_points);
- // --------- update can_guard_flag -------//
- if( combatLevel >= unitInfo->guard_combat_level)
- {
- can_guard_flag = sprite_info->can_guard_flag;
- #ifdef AMPLUS
- if( unit_id == UNIT_ZULU )
- can_guard_flag |= 4; // shield during attack delay
- #endif
- }
- else
- {
- can_guard_flag = 0;
- }
- max_power = skill.combat_level + 50;
- cur_power = min(cur_power, max_power);
- }
- //-------- End of function Unit::set_combat_level -----------//
- //--------- Begin of function Unit::set_rank ---------//
- //
- // Only if the unit has leadership skill, it can be a general or king.
- //
- void Unit::set_rank(int rankId)
- {
- err_when( !race_id );
- #ifdef DEBUG
- if( !is_visible() )
- {
- err_when( rank_id==RANK_GENERAL && rankId==RANK_SOLDIER );
- err_when( rank_id==RANK_SOLDIER && rankId==RANK_GENERAL );
- }
- #endif
- if( rank_id == rankId )
- return;
- //------- promote --------//
- if( rankId > rank_id )
- change_loyalty(PROMOTE_LOYALTY_INCREASE);
- //------- demote -----------//
- else if( rankId < rank_id && rank_id != RANK_KING ) // no decrease in loyalty if a spy king hands his nation to his parent nation and become a general again
- change_loyalty(-DEMOTE_LOYALTY_DECREASE);
- //---- update nation_general_count_array[] ----//
- if( nation_recno )
- {
- UnitInfo* unitInfo = unit_res[unit_id];
- if( rank_id == RANK_GENERAL ) // if it was a general originally
- unitInfo->dec_nation_general_count(nation_recno);
- if( rankId == RANK_GENERAL ) // if the new rank is general
- unitInfo->inc_nation_general_count(nation_recno);
- //------ if demote a king to a unit ------//
- if( rank_id == RANK_KING && rankId != RANK_KING )
- unitInfo->inc_nation_unit_count(nation_recno); // since kings are not included in nation_unit_count, when it is no longer a king, we need to re-increase it.
- //------ if promote a unit to a king ------//
- if( rank_id != RANK_KING && rankId == RANK_KING )
- unitInfo->dec_nation_unit_count(nation_recno); // since kings are not included in nation_unit_count, we need to decrease it
- }
- //----- reset leader_unit_recno if demote a general to soldier ----//
- if( rank_id == RANK_GENERAL && rankId == RANK_SOLDIER )
- {
- //----- reset leader_unit_recno of the units he commands ----//
- for( int i=unit_array.size() ; i>0 ; i-- )
- {
- Unit* unitPtr = (Unit*) unit_array.get_ptr(i); // don't use is_deleted() as it filters out units that are currently dying
- if( unitPtr && unitPtr->leader_unit_recno == sprite_recno )
- {
- unitPtr->leader_unit_recno = 0;
- unitPtr->team_id = 0;
- }
- }
- //--------- deinit team_info ---------//
- err_when( !team_info );
- mem_del(team_info);
- team_info = NULL;
- team_id = 0;
- }
- //----- if this is a soldier being promoted to a general -----//
- else if( rank_id == RANK_SOLDIER && rankId == RANK_GENERAL )
- {
- //-- if this soldier is formerly commanded by a general, detech it ---//
- if( leader_unit_recno )
- {
- if( !unit_array.is_deleted(leader_unit_recno) ) // the leader unit may have been killed at the same time
- unit_array[leader_unit_recno]->del_team_member(sprite_recno);
- leader_unit_recno = 0;
- }
- }
- //-------------- update AI info --------------//
- if( ai_unit )
- {
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- nation_array[nation_recno]->del_general_info(sprite_recno);
- rank_id = rankId;
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- nation_array[nation_recno]->add_general_info(sprite_recno);
- }
- else
- {
- rank_id = rankId;
- }
- //----- if this is a general/king ------//
- if( rank_id == RANK_GENERAL || rank_id == RANK_KING )
- {
- //--------- init team_info -------//
- if( !team_info )
- {
- team_info = (TeamInfo*) mem_add( sizeof(TeamInfo) );
- team_info->member_count = 0;
- }
- //--- set leadership if this unit does not have any now ----//
- if( skill.skill_id != SKILL_LEADING )
- {
- skill.skill_id = SKILL_LEADING;
- skill.skill_level = 10 + m.random(40);
- }
- }
- //------ refresh if the current unit is selected -----//
- if( unit_array.selected_recno == sprite_recno )
- info.disp();
- }
- //-------- End of function Unit::set_rank -----------//
- //--------- Begin of function Unit::embark ---------//
- //
- // Order this unit to embark an vehicle
- //
- // <int> vehicleRecno - recno of the vehicle.
- //
- void Unit::embark(int vehicleRecno)
- {
- err_here(); // this function is no longer functional
- Unit* vehiclePtr = unit_array[vehicleRecno];
- if( unit_res[unit_id]->vehicle_id == vehiclePtr->unit_id ) // not the right vehicle
- return;
- int vehicleUnitId = unit_res[unit_id]->vehicle_unit_id;
- float vehicleHitPoints = vehiclePtr->hit_points;
- int xLoc = vehiclePtr->cur_x_loc();
- int yLoc = vehiclePtr->cur_y_loc();
- //------- delete the vehicle unit --------//
- unit_array.del(vehicleRecno); // delete the vehicle (e.g. horse)
- //--------- add the combined unit -------//
- int newUnitRecno = unit_array.add_unit(vehicleUnitId, nation_recno, rank_id, loyalty, xLoc, yLoc); // add the combined unit (e.g. cavalry)
- UnitVehicle* unitVehicle = (UnitVehicle*) unit_array[newUnitRecno];
- unitVehicle->skill = skill;
- unitVehicle->set_combat_level(skill.combat_level);
- unitVehicle->solider_hit_points = (int) hit_points;
- unitVehicle->vehicle_hit_points = (int) vehicleHitPoints;
- unitVehicle->hit_points = (float) unitVehicle->solider_hit_points +
- unitVehicle->vehicle_hit_points;
- //-------- delete the solider unit ---------//
- unit_array.del(sprite_recno); // delete the embarker (e.g. knight)
- }
- //-------- End of function Unit::embark -----------//
- //--------- Begin of function Unit::reward ---------//
- //
- // <int> rewardNationRecno - the nation which does this reward.
- //
- void Unit::reward(int rewardNationRecno)
- {
- // ###### patch begin Gilbert 24/9 ########//
- if( nation_array[rewardNationRecno]->cash < REWARD_COST )
- return;
- // ###### patch end Gilbert 24/9 ########//
- //--------- if this is a spy ---------//
- if( spy_recno && true_nation_recno() == rewardNationRecno ) // if the spy's owning nation rewards the spy
- {
- spy_array[spy_recno]->change_loyalty(REWARD_LOYALTY_INCREASE);
- }
- //--- if this spy's nation_recno & true_nation_recno() are both == rewardNationRecno, it's true loyalty and cloaked loyalty will both be increased ---//
- if( nation_recno == rewardNationRecno )
- {
- total_reward += REWARD_COST;
- change_loyalty(REWARD_LOYALTY_INCREASE);
- }
- nation_array[rewardNationRecno]->add_expense(EXPENSE_REWARD_UNIT, (float)REWARD_COST);
- }
- //----------- End of function Unit::reward -----------//
- //------- Begin of function Unit::overseer_migrate ---------//
- //
- // Order the overseer migrate to a new town but still keeps
- // working for the same firm.
- //
- // <int> destTownRecno - the recno of the town the worker should
- // migrate to.
- //
- void Unit::overseer_migrate(int destTownRecno)
- {
- err_when( unit_mode!=UNIT_MODE_OVERSEE );
- int curTownRecno = firm_array[unit_mode_para]->overseer_town_recno;
- //------- decrease the population of the unit's home town ------//
- town_array[curTownRecno]->dec_pop(race_id, 1);
- //--------- increase the population of the target town ------//
- town_array[destTownRecno]->inc_pop(race_id, 1, loyalty );
- }
- //-------- End of function Unit::overseer_migrate ---------//
- //--------- Begin of function Unit::group_transform ---------//
- void Unit::group_transform(char remoteAction, short *selectedArray, short selectedCount)
- {
- }
- //----------- End of function Unit::group_transform -----------//
- //--------- Begin of function Unit::transform ---------//
- //
- // Transform the unit into another unit type.
- //
- void Unit::transform()
- {
- /*
- UnitInfo* unitInfo = unit_res[unit_id];
- if( unitInfo->transform_unit_id==0 )
- return;
- UnitInfo* newUnitInfo = unit_res[unitInfo->transform_unit_id];
- //--- check if the unit has the required combat level ---//
- if( skill.combat_level < unitInfo->transform_combat_level )
- return;
- //------ free up space on the map for the new unit -----//
- int xLoc=next_x_loc(), yLoc=next_y_loc();
- stop();
- deinit_sprite(1); // 1-keep the unit selected if it is currently selected
- //---- locate the space for the new unit as their size, mobile type may be different ----//
- SpriteInfo* spriteInfo = sprite_res[newUnitInfo->sprite_id];
- int xLoc2 = xLoc + spriteInfo->loc_width-1;
- int yLoc2 = yLoc + spriteInfo->loc_height-1;
- if( !world.check_unit_space(xLoc, yLoc, xLoc2, yLoc2, newUnitInfo->mobile_type) ) // first check if if is free to create unit on the same location
- {
- if( !world.locate_space( xLoc, yLoc, xLoc+spriteInfo->loc_width-1,
- yLoc+spriteInfo->loc_height-1, spriteInfo->loc_width,
- spriteInfo->loc_height, newUnitInfo->mobile_type) )
- {
- init_sprite( xLoc, yLoc ); // not able to find space for the new unit, transformation cancelled.
- return;
- }
- }
- //--------- transform now ------------//
- deinit_unit_id();
- init_unit_id(unitInfo->transform_unit_id);
- init_sprite( xLoc, yLoc );
- */
- }
- //----------- End of function Unit::transform -----------//
- //--------- Begin of function Unit::spy_change_nation ---------//
- //
- // Change the deceiving nation recno of a spy unit which you control.
- //
- // <int> newNationRecno - the new nation the spy changes its cloack to
- // <char> remoteAction - remote action type
- //
- void Unit::spy_change_nation(int newNationRecno, char remoteAction)
- {
- if( newNationRecno == nation_recno )
- return;
- if( newNationRecno && nation_array.is_deleted(newNationRecno) ) // this can happen in a multiplayer message
- return;
- //------- if this is a remote action -------//
- if( !remoteAction && remote.is_enable() )
- {
- // packet structure <unit recno> <new nation Recno>
- short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_SPY_NATION, 2*sizeof(short) );
- *shortPtr = sprite_recno;
- shortPtr[1] = newNationRecno;
- return;
- }
- //----- update the var in Spy ------//
- Spy* spyPtr = spy_array[spy_recno];
- //--- when a spy change cloak to another nation, he can't cloak as a general, he must become a soldier first ---//
- if( is_visible() && // if the spy is a commander in a camp, don't set its rank to soldier
- rank_id == RANK_GENERAL &&
- newNationRecno != spyPtr->true_nation_recno )
- {
- set_rank(RANK_SOLDIER);
- }
- //---------------------------------------------------//
- //
- // If this spy unit is a general or an overseer of the
- // cloaked nation, when he changes nation, that will
- // inevitably be noticed by the cloaked nation.
- //
- //---------------------------------------------------//
- if( spyPtr->true_nation_recno != nation_array.player_recno ) // only send news message if he is not the player's own spy
- {
- if( rank_id == RANK_GENERAL || unit_mode == UNIT_MODE_OVERSEE ||
- spyPtr->notify_cloaked_nation_flag )
- {
- //-- if this spy's cloaked nation is the player's nation, the player will be notified --//
- if( nation_recno == nation_array.player_recno )
- news_array.unit_betray(sprite_recno, newNationRecno);
- }
- //---- send news to the cloaked nation if notify flag is on ---//
- if( spyPtr->notify_cloaked_nation_flag )
- {
- if( newNationRecno == nation_array.player_recno ) // cloaked as the player's nation
- news_array.unit_betray(sprite_recno, newNationRecno);
- }
- }
- //--------- change nation recno now --------//
- spyPtr->cloaked_nation_recno = newNationRecno;
- betray(newNationRecno); // call the betray function to change natino. There is no difference between a spy changing nation and a unit truly betrays
- }
- //----------- End of function Unit::spy_change_nation -----------//
- //--------- Begin of function Unit::can_spy_change_nation ---------//
- //
- // Whether the spy unit can change its spy cloak now or not.
- //
- // If there are enemy nearby, the unit cannot change its cloak.
- //
- int Unit::can_spy_change_nation()
- {
- if( !spy_recno )
- return 0;
- //--------------------------------------------//
- int xLoc1=cur_x_loc()-SPY_ENEMY_RANGE, yLoc1=cur_y_loc()-SPY_ENEMY_RANGE;
- int xLoc2=cur_x_loc()+SPY_ENEMY_RANGE, yLoc2=cur_y_loc()+SPY_ENEMY_RANGE;
- xLoc1 = max(0, xLoc1);
- yLoc1 = max(0, yLoc1);
- xLoc2 = min(MAX_WORLD_X_LOC-1, xLoc2);
- yLoc2 = min(MAX_WORLD_Y_LOC-1, yLoc2);
- int xLoc, yLoc;
- int unitRecno, trueNationRecno = true_nation_recno();
- Location* locPtr;
- for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
- {
- locPtr = world.get_loc(xLoc1, yLoc);
- for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
- {
- if( locPtr->has_unit(UNIT_LAND) )
- unitRecno = locPtr->unit_recno(UNIT_LAND);
- else if( locPtr->has_unit(UNIT_SEA) )
- unitRecno = locPtr->unit_recno(UNIT_SEA);
- else if( locPtr->has_unit(UNIT_AIR) )
- unitRecno = locPtr->unit_recno(UNIT_AIR);
- else
- continue;
- if( unit_array.is_deleted(unitRecno) ) // the unit is dying, its recno is still in the location
- continue;
- if( unit_array[unitRecno]->true_nation_recno() != trueNationRecno )
- return 0;
- }
- }
- return 1;
- }
- //----------- End of function Unit::can_spy_change_nation -----------//
- //--------- Begin of function Unit::resign ---------//
- //
- // Resign the unit.
- //
- void Unit::resign(int remoteAction)
- {
- if( !remoteAction && remote.is_enable() )
- {
- // packet structure : <unit recno> <nation recno>
- short *shortPtr = (short *)remote.new_send_queue_msg(MSG_UNIT_RESIGN, 2*sizeof(short));
- *shortPtr = sprite_recno;
- shortPtr[1] = nation_array.player_recno;
- return;
- }
- //---- increase the wandering count when a unit is disbanded ----//
- if( race_id )
- town_array.race_wander_pop_array[race_id-1] += 2; // disbanding one resulted in two wandering units to make the effect more significant
- //--- if the unit is visible, call stop2() so if it has an AI action queue, that will be reset ---//
- if( is_visible() )
- stop2();
- //--- if the spy is resigned by an enemy, display a message ---//
- if( spy_recno && true_nation_recno() != nation_recno ) // the spy is cloaked in an enemy nation when it is resigned
- {
- //------ decrease reputation ------//
- nation_array[true_nation_recno()]->change_reputation((float)-SPY_KILLED_REPUTATION_DECREASE);
- //------- add news message -------//
- if( true_nation_recno() == nation_array.player_recno || // display when the player's spy is revealed or the player has revealed an enemy spy
- nation_recno == nation_array.player_recno )
- {
- //--- If a spy is caught, the spy's nation's reputation wil decrease ---//
- news_array.spy_killed(spy_recno);
- }
- }
- //----------------------------------------------//
- if( rank_id == RANK_GENERAL ) // if this is a general, news_array.general_die() will be called, set news_add_flag to 0 to suppress the display of thew news
- news_array.news_add_flag=0;
- unit_array.del( sprite_recno );
- news_array.news_add_flag=1;
- }
- //----------- End of function Unit::resign -----------//
- //--------- Begin of function Unit::region_id ---------//
- //
- // Return the region id. of this unit.
- //
- BYTE Unit::region_id()
- {
- if( is_visible() )
- {
- return world.get_region_id( next_x_loc(), next_y_loc() );
- }
- else
- {
- if( unit_mode == UNIT_MODE_OVERSEE )
- return firm_array[unit_mode_para]->region_id;
- }
- return 0;
- }
- //----------- End of function Unit::region_id -----------//
- //--------- Begin of function Unit::del_team_member ---------//
- //
- // Delete a specific member of the team led by this leader.
- //
- void Unit::del_team_member(int unitRecno)
- {
- err_when( !team_info );
- for( int i=0 ; i<team_info->member_count ; i++ )
- {
- if( team_info->member_unit_array[i] == unitRecno )
- {
- err_when( team_info->member_count > MAX_TEAM_MEMBER );
- m.del_array_rec( team_info->member_unit_array, team_info->member_count,
- sizeof( team_info->member_unit_array[0] ), i+1 );
- team_info->member_count--;
- return;
- }
- }
- //-------------------------------------------------------//
- //
- // Note: for rebels and monsters, although they have
- // leader_unit_recno, their team_info is not used.
- // So del_team_member() won't be able to match the
- // unit in its member_unit_array[].
- //
- //-------------------------------------------------------//
- }
- //----------- End of function Unit::del_team_member -----------//
- //--------- Begin of function Unit::validate_team ---------//
- //
- // Validate the member in this commander's team. If there
- // are any units with hit_points <= 0, delete them.
- //
- // Those unit may just be killed, so soon that the Unit's set_die()
- // function hsa been called yet. validate_team() function must
- // be called before all issunig any new team actions.
- //
- void Unit::validate_team()
- {
- err_when( !team_info );
- int unitRecno;
- for( int i=team_info->member_count-1 ; i>=0 ; i-- )
- {
- unitRecno = team_info->member_unit_array[i];
- if( unit_array.is_deleted(unitRecno) )
- {
- err_when( team_info->member_count > MAX_TEAM_MEMBER );
- m.del_array_rec( team_info->member_unit_array, team_info->member_count,
- sizeof( team_info->member_unit_array[0] ), i+1 );
- team_info->member_count--;
- }
- }
- }
- //----------- End of function Unit::validate_team -----------//
- //--------- Begin of function Unit::commanded_soldier_count ---------//
- //
- // Return the no. of soldiers commanded by this unit.
- //
- int Unit::commanded_soldier_count()
- {
- if( rank_id != RANK_GENERAL && rank_id != RANK_KING )
- return 0;
- //--------------------------------------//
- err_when( !team_info );
- int soldierCount=0;
- if( is_visible() )
- {
- soldierCount = team_info->member_count-1;
- if( soldierCount < 0 ) // member_count can be 0
- soldierCount = 0;
- }
- else
- {
- if( unit_mode == UNIT_MODE_OVERSEE )
- {
- Firm* firmPtr = firm_array[unit_mode_para];
- if( firmPtr->firm_id == FIRM_CAMP ) // it can be an overseer of a seat of powre
- soldierCount = firmPtr->worker_count;
- }
- }
- return soldierCount;
- }
- //----------- End of function Unit::commanded_soldier_count -----------//
- //----------- Begin of function Unit::fix_attack_info -----------//
- void Unit::fix_attack_info()
- {
- int techLevel;
- UnitInfo *unitInfo = unit_res[unit_id];
- attack_count = unitInfo->attack_count;
- if( attack_count > 0 && unitInfo->first_attack > 0)
- attack_info_array = unit_res.attack_info_array+unitInfo->first_attack-1;
- else
- attack_info_array = NULL;
- if( unitInfo->unit_class == UNIT_CLASS_WEAPON &&
- (techLevel=get_weapon_version()) > 0 )
- {
- switch( unit_id )
- {
- case UNIT_BALLISTA:
- #ifdef AMPLUS
- case UNIT_F_BALLISTA:
- #endif
- attack_count = 2;
- break;
- case UNIT_EXPLOSIVE_CART:
- attack_count = 0;
- break;
- default:
- attack_count = 1;
- }
- if( attack_count > 0)
- {
- attack_info_array += (techLevel-1) * attack_count;
- }
- else
- {
- // no attack like explosive cart
- attack_info_array = NULL;
- }
- }
- }
- //----------- End of function Unit::fix_attack_info -----------//
- //----------- Begin of function Unit::return_camp -----------//
- //
- // Order this unit to return to the camp. For ordering many
- // units to return to a camp, UnitArray::return_camp() should
- // be called instead.
- //
- int Unit::return_camp()
- {
- if( !home_camp_firm_recno )
- return 0;
- err_when( firm_array.is_deleted(home_camp_firm_recno) );
- Firm* firmPtr = firm_array[home_camp_firm_recno];
- if( firmPtr->region_id != region_id() )
- return 0;
- err_when( firmPtr->firm_id != FIRM_CAMP );
- err_when( firmPtr->nation_recno != nation_recno );
- //--------- assign now ---------//
- assign(firmPtr->loc_x1, firmPtr->loc_y1);
- force_move_flag = 1;
- return cur_action != SPRITE_IDLE;
- }
- //----------- End of function Unit::return_camp -----------//
- //----------- Begin of function Unit::unit_power -----------//
- //
- // Return a power index of the weapon, this is for calculating
- // the total combat level of a target.
- //
- int Unit::unit_power()
- {
- UnitInfo* unitInfo = unit_res[unit_id];
- if( unitInfo->unit_class == UNIT_CLASS_WEAPON )
- {
- return (int) hit_points + (unitInfo->weapon_power + get_weapon_version() - 1) * 15;
- }
- else
- {
- return (int) hit_points;
- }
- }
- //----------- End of function Unit::unit_power -----------//
- //----------- Begin of function Unit::get_cur_loc -----------//
- //
- // <short&> xLoc, yLoc - reference vars for returning the
- // location of this unit
- //
- // return : 0 - if this unit is invisible
- // 1 - if a location has been returned.
- //
- int Unit::get_cur_loc(short& xLoc, short& yLoc)
- {
- if( is_visible() )
- {
- xLoc = next_x_loc(); // update location
- yLoc = next_y_loc();
- }
- else if( unit_mode == UNIT_MODE_OVERSEE ||
- unit_mode==UNIT_MODE_CONSTRUCT ||
- unit_mode == UNIT_MODE_IN_HARBOR )
- {
- Firm* firmPtr = firm_array[unit_mode_para];
- xLoc = firmPtr->center_x;
- yLoc = firmPtr->center_y;
- }
- else if( unit_mode == UNIT_MODE_ON_SHIP )
- {
- Unit* unitPtr = unit_array[unit_mode_para];
- //### begin alex 22/10 ###//
- //xLoc = unitPtr->next_x_loc();
- //yLoc = unitPtr->next_y_loc();
- if(unitPtr->is_visible())
- {
- xLoc = unitPtr->next_x_loc();
- yLoc = unitPtr->next_y_loc();
- }
- else
- {
- err_when(unitPtr->unit_mode!=UNIT_MODE_IN_HARBOR);
- Firm *firmPtr = firm_array[unitPtr->unit_mode_para];
- xLoc = firmPtr->center_x;
- yLoc = firmPtr->center_y;
- }
- //#### end alex 22/10 ####//
- }
- else
- return 0;
- return 1;
- }
- //----------- End of function Unit::get_cur_loc -----------//
- //----------- Begin of function Unit::add_way_point -----------//
- // Add the point to the way_point_array if it is not in the array.
- // Otherwise, remove the point from the way_point_array.
- //
- // <short> x - x coordinate of the point
- // <short> y - y coordinate of the point
- //
- void Unit::add_way_point(short x, short y)
- {
- if(way_point_count>=100)
- return; // too many way point
- if(way_point_count>1) // don't allow to remove the 1st node, since the unit is moving there
- {
- ResultNode *nodePtr = way_point_array + 1;
- for(int i=1; i<way_point_count; ++i, nodePtr++)
- {
- if(nodePtr->node_x == x && nodePtr->node_y == y) // remove this node
- {
- m.del_array_rec(way_point_array, way_point_count, sizeof(ResultNode), i+1); // remove 1st node
- way_point_count--;
- return; // there should be one and only one node with the same value
- }
- }
- }
- //-------------- add new node -----------------//
- if(way_point_count>=way_point_array_size) // buffer full
- {
- way_point_array_size += WAY_POINT_ADJUST_SIZE;
-
- if(way_point_count)
- way_point_array = (ResultNode*) mem_resize(way_point_array, way_point_array_size*sizeof(ResultNode));
- else
- way_point_array = (ResultNode*) mem_add(sizeof(ResultNode)*WAY_POINT_ADJUST_SIZE);
- }
- ResultNode *nodePtr = way_point_array + way_point_count;
- nodePtr->node_x = x;
- nodePtr->node_y = y;
- way_point_count++;
-
- if(way_point_count==1)
- move_to(x, y);
- }
- //----------- End of function Unit::add_way_point -----------//
- //----------- Begin of function Unit::reset_way_point_array -----------//
- void Unit::reset_way_point_array()
- {
- //------------------------------------------------------------------------------------//
- // There are nly two conditions to reset the way_point_array
- // 1) action_mode2!=ACTION_MOVE in Unit::stop()
- // 2) dest? != node_? in the first node of way_point_array in calling Unit::move_to()
- //------------------------------------------------------------------------------------//
- if(way_point_array_size)
- {
- mem_del(way_point_array);
- way_point_array = NULL;
- way_point_array_size = 0;
- way_point_count = 0;
- }
- }
- //----------- End of function Unit::reset_way_point_array -----------//
- //----------- Begin of function Unit::process_way_point -----------//
- // move to the next way point and remove this point from the
- // way_point_array
- //
- void Unit::process_way_point()
- {
- err_when(action_mode!=ACTION_STOP || action_mode2!=ACTION_STOP || cur_action!=SPRITE_IDLE);
- int destX, destY;
- if(way_point_count>1)
- {
- ResultNode *nodePtr = way_point_array+1;
- destX = nodePtr->node_x;
- destY = nodePtr->node_y;
- m.del_array_rec(way_point_array, way_point_count, sizeof(ResultNode), 1); // remove 1st node
- way_point_count--;
- }
- else // only one unprocessed node
- {
- ResultNode *nodePtr = way_point_array;
- destX = nodePtr->node_x;
- destY = nodePtr->node_y;
- //m.del_array_rec(way_point_array, way_point_count, sizeof(ResultNode), 1); // remove 1st node
- //way_point_count--;
- }
- move_to(destX, destY);
- }
- //----------- End of function Unit::process_way_point -----------//
- //----------- Begin of function TeamInfo::TeamInfo ---------//
- TeamInfo::TeamInfo()
- {
- memset( this, 0, sizeof(TeamInfo) );
- }
- //----------- End of function TeamInfo::TeamInfo ---------//
|