int Unit::think_normal_human_action() { if( home_camp_firm_recno ) return 0; //-- if we also don't have any existing camps in this region --// Nation* nationPtr = nation_array[nation_recno]; if( nationPtr->ai_camp_count==0 || nationPtr->total_camp_unit_space(0) <= nationPtr->total_unit_count ) // If there are more units than the existing forts can hold { if( ai_build_firm() ) return 1; } //--- the following are actions that are only performed if the unit is not led by a commander ---// if( leader_unit_recno && unit_array[leader_unit_recno]->is_visible() ) // if the unit is led by a commander, let the commander makes the decision. If the leader has been assigned to a firm, don't consider it as a leader anymore { return 0; } err_when( !race_id ); err_when( !nation_recno ); //--- if this is a military unit, think about assigning it to a camp or fort ---// if( !is_civilian() ) { if( think_assign_soldier_to_camp() ) return 1; } else { if( think_assign_human_to_town() ) return 1; } return 0; }
//--------- Begin of function Unit::can_succeed_king ---------// // int Unit::can_succeed_king() { if( !nation_recno || !race_id ) return 0; Nation* nationPtr = nation_array[nation_recno]; if( nationPtr->king_unit_recno ) // the king is still alive return 0; if( nationPtr->is_human() ) { //-- only the nation is a human nation, only human military unit can succeed the king --// return is_human() && !is_civilian(); } else { return monster_res[ nationPtr->monster_id() ]->unit_id == unit_id; } }
//--------- 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 ); if( rank_id == rankId ) return; err_when( unit_mode != UNIT_MODE_REBEL && rankId >= RANK_GENERAL && is_civilian() ); //------- 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 { err_when( !unit_array[leader_unit_recno]->team_info ); unit_array[leader_unit_recno]->team_info->del_member(sprite_recno); } leader_unit_recno = 0; } } // ###### patch begin Gilbert 27/9 #######// // ------- clear royal in campaign mode -----// if( rankId == RANK_KING ) { is_royal = 0; } // ###### patch end Gilbert 27/9 #######// //-------------- update AI info --------------// if( nation_recno ) { 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) ); memset( team_info, 0, sizeof(TeamInfo) ); } //--- set leadership if this unit does not have any now ----// if( skill_level() < 10 ) skill.set_skill_level( + m.random(40) ); } //------ refresh if the current unit is selected -----// if( unit_array.selected_recno == sprite_recno ) info.disp(); }
//--------- 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) { //----- if this is a spy, call spy_change_nation -----// if( spy_recno && spy_array[spy_recno]->cloaked_nation_recno != newNationRecno ) // cloaked_nation_recno == newNationRecno if betray() is called by spy_change_nation() already { spy_change_nation(newNationRecno, COMMAND_AUTO); return 1; } //-------------------------------// err_when( newNationRecno && nation_array[newNationRecno]->is_human() && // monsters in firms should not betray to humans is_monster() && unit_mode == UNIT_MODE_OVERSEE ); int unitRecno = sprite_recno; err_when( unit_array.is_truly_deleted(unitRecno) ); err_when( rank_id == RANK_KING ); if( nation_recno == newNationRecno ) return 0; if( unit_mode == UNIT_MODE_CONSTRUCT_FIRM || // don't change nation when the unit is constructing a firm unit_mode == UNIT_MODE_CONSTRUCT_TOWN || unit_mode == UNIT_MODE_ON_SHIP ) // don't change nation when the unit is constructing a firm { return 0; } //--- special case: units in Monster Fortress cannot change nation ---// if( unit_mode == UNIT_MODE_OVERSEE && firm_array[unit_mode_para]->firm_id == FIRM_FORTRESS ) { 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 ------// err_when( unit_array.is_truly_deleted(unitRecno) ); change_nation(newNationRecno); err_when( unit_array.is_truly_deleted(unitRecno) ); //-------- set the loyalty of the unit -------// if( nation_recno ) { Nation* nationPtr = nation_array[nation_recno]; loyalty = UNIT_BETRAY_LOYALTY + 10 + m.random(20); 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 ---// if( rank_id==RANK_GENERAL ) { err_when( !team_info ); for( int i=0 ; i<team_info->member_count ; i++ ) { int memberUnitRecno = team_info->member_unit_array[i]; if( memberUnitRecno == unitRecno ) // this is the unit itself continue; Unit* unitPtr = unit_array[memberUnitRecno]; if( !unitPtr->is_visible() ) continue; if( unitPtr->spy_recno ) // if the unit is a spy unitPtr->spy_change_nation(newNationRecno, COMMAND_AUTO); else unitPtr->change_nation(newNationRecno); } } err_when( unit_array.is_truly_deleted(unitRecno) ); //------ go to meet the new master -------// if( is_visible() && nation_recno ) { if( !spy_recno || spy_array[spy_recno]->notify_cloaked_nation_flag ) { if( is_civilian() ) ai_move_to_nearby_town(); else ai_move_to_nearby_firm(FIRM_CAMP, FIRM_FORT); } } err_when( unit_array.is_truly_deleted(unitRecno) ); return 1; }
//--------- 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 || !race_id ) return; if( unit_mode == UNIT_MODE_CONSTRUCT_FIRM || // constructor worker will not change their loyalty when they are in a building unit_mode == UNIT_MODE_CONSTRUCT_TOWN ) { return; } //--- the loyalty of civilians does not change when they are mobile ---// if( is_civilian() ) { 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_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 unit is a spy, set its fake loyalty ------// if( spy_recno ) // it should never go below the rebel level target_loyalty = max( 30+sprite_recno%10, target_loyalty ); } //-------- 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_level(); //---------------------------------------------------// // // Soldiers with higher combat and leadership skill // will get discontented if they are led by a general // with low leadership. // //---------------------------------------------------// targetLoyalty -= combat_level()/2; targetLoyalty -= 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 ); }
//--------- Begin of function Unit::disp_unit_profile ---------// // // <int> dispY1 - the top y coordination of the info area // <int> refreshFlag // void Unit::disp_unit_profile(int dispY1, int refreshFlag) { //--------- set help parameters --------// int x=INFO_X1+4; if( mouse.in_area(x, dispY1+3, x+UNIT_LARGE_ICON_WIDTH-1, dispY1+UNIT_LARGE_ICON_HEIGHT+2) ) help.set_unit_help( unit_id, rank_id, x, dispY1+3, x+UNIT_LARGE_ICON_WIDTH-1, dispY1+UNIT_LARGE_ICON_HEIGHT+2 ); //-----------------------------------------// if( refreshFlag != INFO_REPAINT ) // only display in repaint mode return; //-----------------------------------------// const char *str=NULL; if( race_id ) { if( rank_id == RANK_KING ) { str = _("King"); } else if( rank_id == RANK_GENERAL ) { // ##### patch begin Gilbert 17/2 #####// if( unit_mode == UNIT_MODE_REBEL ) str = _("Rebel Leader"); else str = _("General"); // ##### patch end Gilbert 17/2 #####// } else if( unit_mode == UNIT_MODE_DEFEND_TOWN ) { str = _("Defending Villager"); } else if( unit_mode == UNIT_MODE_REBEL ) { str = _("Rebel"); } else if( unit_res[unit_id]->unit_class == UNIT_CLASS_GOD ) { str = _("Greater Being"); } else { if( should_show_info() ) { switch( skill.skill_id ) { case SKILL_LEADING: str = _("Soldier"); break; case SKILL_CONSTRUCTION: str = _("Construction Worker"); break; case SKILL_MINING: str = _("Miner"); break; case SKILL_MFT: str = _("Worker"); break; case SKILL_RESEARCH: str = _("Scientist"); break; case SKILL_SPYING: str = _("Spy"); break; default: str = _("Peasant"); break; } } else //--- don't display too much info on enemy units ---// { if( skill.skill_id == SKILL_LEADING ) str = _("Soldier"); else if( is_civilian() ) str = _("Civilian"); } } } //---------------- paint the panel --------------// vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+44); vga_front.put_bitmap( x, dispY1+3, unit_res[unit_id]->get_large_icon_ptr(rank_id) ); //--------------------------------------// x += UNIT_LARGE_ICON_WIDTH; if( str ) { font_san.center_put( x, dispY1+4, INFO_X2-2, dispY1+21, str ); font_san.center_put( x, dispY1+22, INFO_X2-2, dispY1+40, unit_name(0) ); // 0-without title } else { font_san.center_put( x, dispY1, INFO_X2-2, dispY1+44, unit_name() ); // non-human units } }
//--------- Begin of function Unit::disp_unit_info ---------// // // Display the skill information of the people in the town. // // <int> dispY1 - the top y coordination of the info area // <int> refreshFlag - refresh flag // void Unit::disp_unit_info(int dispY1, int refreshFlag) { #ifdef DEBUG if(debug2_enable_flag) { if(unit_res[unit_id]->unit_class == UNIT_CLASS_MONSTER) { int x=INFO_X1+4, y=dispY1+20; y+=20; font_san.field( x, y, " " , x+2, sprite_recno, 1, INFO_X2-2, refreshFlag); font_san.field( x+20, y, " " , x+22, next_x_loc(), 1, INFO_X2-2, refreshFlag); font_san.field( x+50, y, " " , x+52, next_y_loc(), 1, INFO_X2-2, refreshFlag); font_san.field( x+70, y, " " , x+72, nation_recno, 1, INFO_X2-2, refreshFlag); font_san.field( x+100, y, " " , x+102, action_mode, 1, INFO_X2-2, refreshFlag); font_san.field( x+120, y, " " , x+122, action_para, 1, INFO_X2-2, refreshFlag); font_san.field( x+140, y, " " , x+142, action_x_loc, 1, INFO_X2-2, refreshFlag); font_san.field( x+160, y, " " , x+162, action_y_loc, 1, INFO_X2-2, refreshFlag); y-=20; font_san.field( x+100, y, " " , x+102, action_mode2, 1, INFO_X2-2, refreshFlag); font_san.field( x+120, y, " " , x+122, action_para2, 1, INFO_X2-2, refreshFlag); font_san.field( x+140, y, " " , x+142, action_x_loc2, 1, INFO_X2-2, refreshFlag); font_san.field( x+160, y, " " , x+162, action_y_loc2, 1, INFO_X2-2, refreshFlag); y-=20; font_san.field( x+160, y, " " , x+162, cur_action, 1, INFO_X2-2, refreshFlag); } } #endif //--------------------------------------------// if( !race_id ) // if it's not a human unit, don't display anything return; if( refreshFlag==INFO_REPAINT ) vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+87 ); int x=INFO_X1+4, y=dispY1+4; String str; //--------- display loyalty ---------// if( rank_id != RANK_KING && (nation_recno || spy_recno) ) { if( spy_recno && // only display spy loyalty instead of unit loyalty if this is a spy and this spy is ours true_nation_recno() == nation_array.player_recno ) { font_san.field( x, y, _("Loyalty"), x+92, spy_array[spy_recno]->spy_loyalty, 1, INFO_X2-2, refreshFlag); } else if( nation_recno ) { info.disp_loyalty( x, y, x+92, loyalty, target_loyalty, nation_recno, refreshFlag ); } y+=16; } //--------- display combat level ----------// font_san.field( x, y, _("Combat") , x+92, skill.combat_level, 1, INFO_X2-2, refreshFlag); y+=16; //-------- display skill level ---------// if( skill.skill_id ) { if( refreshFlag == INFO_REPAINT ) font_san.field( x, y, skill.skill_des(), x+92, skill.skill_level , 1, INFO_X2-2, refreshFlag); else font_san.field( x, y, skill.skill_des(), x+92, skill.skill_level , 1, INFO_X2-2, refreshFlag); y+=16; } //------- display spying skill if the unit is a spy -----// if( spy_recno && spy_array[spy_recno]->true_nation_recno == nation_array.player_recno ) // only spies of the player's nation can see the spy skill details { font_san.field( x, y, _("Spying"), x+92, spy_array[spy_recno]->spy_skill, 1, INFO_X2-2, refreshFlag); y+=16; } //--------- display debug info ---------// if( !is_civilian() && rank_id != RANK_KING ) font_san.field( x, y, _("Contribution"), x+92, nation_contribution, 1, INFO_X2-2, refreshFlag); }
int Unit::think_reward() { Nation* ownNation = nation_array[nation_recno]; //----------------------------------------------------------// // The need to secure high loyalty on this unit is based on: // -its skill // -its combat level // -soldiers commanded by this unit //----------------------------------------------------------// if( spy_recno && true_nation_recno() == nation_recno ) // if this is a spy of ours { return 0; // Spy::think_reward() will handle this. } int curLoyalty = loyalty; int neededLoyalty; //----- if this unit is on a mission ------/ if( cur_order.ai_action_id ) { neededLoyalty = UNIT_BETRAY_LOYALTY+10; } //----- otherwise only reward soldiers and generals ------// else if( !is_civilian() ) // it is a military unit { //----- calculate the needed loyalty --------// neededLoyalty = commanded_soldier_count()*5 + skill_level(); if( unit_mode == UNIT_MODE_OVERSEE ) // if this unit is an overseer { if( loyalty < UNIT_BETRAY_LOYALTY ) // if this unit's loyalty is < betrayel level, reward immediately { reward(nation_recno); // reward it immediatley if it's an overseer, don't check ai_should_spend() return 1; } neededLoyalty += 30; } neededLoyalty = MAX( UNIT_BETRAY_LOYALTY+10, neededLoyalty ); // 10 points above the betray loyalty level to prevent betrayal neededLoyalty = MIN( 100, neededLoyalty ); } else { return 0; } //------- if the loyalty is already high enough ------// if( curLoyalty >= neededLoyalty ) return 0; //---------- see how many cash & profit we have now ---------// int rewardNeedRating = neededLoyalty - curLoyalty; if( curLoyalty < UNIT_BETRAY_LOYALTY+5 ) rewardNeedRating += 50; if( ownNation->ai_should_spend(rewardNeedRating) ) { reward(nation_recno); return 1; } return 0; }