/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OFIRM.CPP
//Description : Object Firm
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// ###### begin Gilbert 2/10 ######//
#include
// ###### end Gilbert 2/10 ######//
#include
//---------- define static member vars -------------//
char Firm::firm_menu_mode=FIRM_MENU_MAIN; // whether the firm is in spy menu mode
short Firm::action_spy_recno;
char Firm::bribe_result=BRIBE_NONE;
char Firm::assassinate_result=0;
//----------- define static parameters -------------//
static int remove_firm = 0; // true only when the firm is to be removed from the firm_array
//--------- Begin of function Firm::Firm --------//
//
// After created a Firm, you must either call Firm::set_world_matrix()
// to set the record no. of the firm in the matrix or set it yourself
//
// NOTE : this function will be called by firm_array.read_file()
// it CANNOT change any settings in nation_array
//
Firm::Firm()
{
//####### patch begin Gilbert 21/1 #######//
// memset( (char *)this, 0, sizeof(Firm) );
memset( (char *)this + sizeof(void *), 0, sizeof(Firm) - sizeof(void *) );
//####### patch end Gilbert 21/1 #######//
}
//----------- End of function Firm::Firm ---------//
//--------- Begin of function Firm::~Firm --------//
//
// Two ways to terminate a Firm :
//
// 1.call Firm::deinit() first and then delete the firm
// 2.delete the firm directly
//
Firm::~Firm()
{
deinit();
}
//----------- End of function Firm::~Firm --------//
//--------- Begin of function Firm::init --------//
//
// It will initialize vars, and set the world matrix.
// Before calling init(), firm_recno should be set
//
// Note : it will set world matrix regardless the existing location content,
// so you must ensure that the location is clean by calling
// world.zoom_matrix->add_firm_test()
//
// xLoc, yLoc = the location of firm in the world map
// nationRecno = the recno of nation which build this firm
// firmId = id(type) of the firm
// [char*] buildCode = the build code of the firm, no need to give if the firm just have one build type
// [short] builderRecno = recno of the builder unit
//
void Firm::init(int xLoc, int yLoc, int nationRecno, int firmId, char* buildCode, short builderRecno)
{
FirmInfo* firmInfo = firm_res[firmId];
firm_id = firmId;
if( buildCode )
firm_build_id = firmInfo->get_build_id(buildCode);
else
firm_build_id = firmInfo->first_build_id;
//----------- set vars -------------//
nation_recno = nationRecno;
setup_date = info.game_date;
overseer_recno = 0;
if( firmInfo->need_worker )
worker_array = (Worker*) mem_add( MAX_WORKER * sizeof(Worker) );
else
worker_array = NULL;
//----- set the firm's absolute positions on the map -----//
FirmBuild* firmBuild = firm_res.get_build(firm_build_id);
race_id = firmBuild->race_id;
loc_x1 = xLoc;
loc_y1 = yLoc;
loc_x2 = loc_x1 + firmBuild->loc_width - 1;
loc_y2 = loc_y1 + firmBuild->loc_height - 1;
center_x = (loc_x1 + loc_x2) / 2;
center_y = (loc_y1 + loc_y2) / 2;
region_id = world.get_region_id( center_x, center_y );
abs_x1 = xLoc * ZOOM_LOC_WIDTH + firmBuild->min_offset_x;
abs_y1 = yLoc * ZOOM_LOC_HEIGHT + firmBuild->min_offset_y;
abs_x2 = abs_x1 + firmBuild->max_bitmap_width - 1;
abs_y2 = abs_y1 + firmBuild->max_bitmap_height - 1;
//--------- set animation frame vars ---------//
if( firmBuild->animate_full_size )
cur_frame = 1;
else
{
cur_frame = 2; // start with the 2nd frame as the 1st frame is the common frame
err_when( firmBuild->frame_count <=2 ); // for segmented animation, the minimum no. of frames must be 3, as the first one is the common frame
}
remain_frame_delay = (char) firmBuild->frame_delay(cur_frame);
//--------- initialize gaming vars ----------//
hit_points = (float) 0;
max_hit_points = firmInfo->max_hit_points;
//------ set construction and builder -------//
under_construction = firmInfo->buildable; // whether the firm is under construction, if the firm is not buildable it is completed in the first place
if( !under_construction ) // if this firm doesn't been to be constructed, set its hit points to the maximum
hit_points = max_hit_points;
if( builderRecno )
set_builder(builderRecno);
else
builder_recno = 0;
//------ update firm counter -------//
firmInfo->total_firm_count++;
if( nation_recno )
firmInfo->inc_nation_firm_count(nation_recno);
//-------------------------------------------//
if( nation_recno > 0 )
{
Nation* nationPtr = nation_array[nation_recno];
firm_ai = nationPtr->is_ai();
ai_processed = 1;
//--------- increase firm counter -----------//
nationPtr->nation_firm_count++;
//-------- update last build date ------------//
nationPtr->last_build_firm_date = info.game_date;
}
else
{
firm_ai = 0;
ai_processed = 0;
}
ai_status = FIRM_WITHOUT_ACTION;
ai_link_checked = 1; // check the connected firms if ai_link_checked = 0;
//--------------------------------------------//
setup_link();
set_world_matrix();
init_name();
//----------- init AI -----------//
if( firm_ai )
nation_array[nation_recno]->add_firm_info(firm_id, firm_recno);
//-------- init derived ---------//
init_derived(); // init_derived() before set_world_matrix() so that init_derived has access to the original land info.
}
//----------- End of function Firm::init ---------//
//--------- Begin of function Firm::deinit --------//
//
void Firm::deinit()
{
if( !firm_recno ) // already deleted
return;
deinit_derived();
remove_firm = 1; // set static parameter
//------- delete AI info ----------//
if(firm_ai)
{
Nation* nationPtr = nation_array[nation_recno];
if( should_close_flag )
nationPtr->firm_should_close_array[firm_id-1]--;
err_when( nationPtr->firm_should_close_array[firm_id-1] < 0 );
nationPtr->del_firm_info(firm_id, firm_recno);
}
//--------- clean up related stuff -----------//
restore_world_matrix();
release_link();
//------ all workers and the overseer resign ------//
if( !sys.signal_exit_flag )
{
// ##### begin Gilbert 28/10 ########//
if( !under_construction )
{
// -------- create a firm die record ------//
// can be called as soon as restore_world_matrix
FirmDie firmDie;
firmDie.init(this);
firm_die_array.add(&firmDie);
}
// ##### end Gilbert 28/10 ########//
assign_overseer(0); // this function must be called before restore_world_matrix(), otherwise the power area can't be completely reset
if( worker_array )
{
resign_all_worker(); // the workers in the firm will be killed if there is no space for creating the workers
mem_del( worker_array );
worker_array = NULL;
}
if(builder_recno)
mobilize_builder(builder_recno);
}
else
{
if(builder_recno)
kill_builder(builder_recno);
kill_overseer();
if(worker_array)
{
kill_all_worker();
mem_del(worker_array);
worker_array = NULL;
}
}
//--------- decrease firm counter -----------//
if( nation_recno )
nation_array[nation_recno]->nation_firm_count--;
//------ update firm counter -------//
FirmInfo* firmInfo = firm_res[firm_id];
firmInfo->total_firm_count--;
if( nation_recno )
firmInfo->dec_nation_firm_count(nation_recno);
//------- update town border ---------//
loc_x1 = -1; // mark deleted
//------- if the current firm is the selected -----//
if( firm_array.selected_recno == firm_recno )
{
firm_array.selected_recno = 0;
info.disp();
}
//-------------------------------------------------//
firm_recno = 0;
remove_firm = 0; // reset static parameter
}
//----------- End of function Firm::deinit ---------//
//--------- Begin of function Firm::init_name --------//
//
// Set the name of this firm. Name related vars are set.
//
void Firm::init_name()
{
char t=firm_res[firm_id]->short_name[0];
if( t==' ' || !t ) // if this firm does not have any short name, display the full name without displaying the town name together
return;
//---- find the closest town and set closest_town_name_id -----//
closest_town_name_id = get_closest_town_name_id();
//--------- set firm_name_instance_id -----------//
char usedInstanceArray[256];
Firm* firmPtr;
memset( usedInstanceArray, 0, sizeof(usedInstanceArray) );
int i;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
if( firmPtr->firm_id == firm_id &&
firmPtr->closest_town_name_id == closest_town_name_id &&
firmPtr->firm_name_instance_id )
{
usedInstanceArray[firmPtr->firm_name_instance_id-1] = 1;
}
}
for( i=0 ; i<256 ; i++ ) // get the smallest id. which are not used by existing firms
{
if( !usedInstanceArray[i] )
{
firm_name_instance_id = i+1;
break;
}
}
}
//--------- End of function Firm::init_name --------//
//------- Begin of function Firm::get_closest_town_name_id -----------//
//
// return the name id. of the closest town.
//
int Firm::get_closest_town_name_id()
{
//---- find the closest town and set closest_town_name_id -----//
int townDistance, minTownDistance=0x7FFF;
int closestTownNameId=0;
Town* townPtr;
for( int i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
townDistance = m.points_distance( townPtr->center_x, townPtr->center_y,
center_x, center_y );
if( townDistance < minTownDistance )
{
minTownDistance = townDistance;
closestTownNameId = townPtr->town_name_id;
}
}
return closestTownNameId;
}
//--------- End of function Firm::get_closest_town_name_id -----------//
//------- Begin of function Firm::firm_name -----------//
//
char* Firm::firm_name()
{
static String str;
if( !closest_town_name_id )
{
str = firm_res[firm_id]->name;
}
else
{
#if(defined(SPANISH))
str = firm_res[firm_id]->short_name;
str += " de ";
str += town_res.get_name(closest_town_name_id);
#else
// FRENCH, GERMAN and US
str = town_res.get_name(closest_town_name_id);
str += " ";
str += firm_res[firm_id]->short_name;
#endif
if( firm_name_instance_id > 1 ) // don't display number for the first firm
{
str += " ";
str += firm_name_instance_id;
}
}
return str;
}
//--------- End of function Firm::firm_name -----------//
//------- Begin of function Firm::complete_construction -----------//
//
// Complete construction instantly.
//
void Firm::complete_construction()
{
if( under_construction )
{
hit_points = max_hit_points;
under_construction = 0;
}
}
//--------- End of function Firm::complete_construction -----------//
//------- Begin of function Firm::assign_unit -----------//
//
void Firm::assign_unit(int unitRecno)
{
err_when( !unitRecno );
Unit* unitPtr = unit_array[unitRecno];
//------- if this is a construction worker -------//
if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION )
{
set_builder(unitRecno);
return;
}
//---- if the unit does not belong to the firm's nation ----//
if( unitPtr->nation_recno != nation_recno )
{
// can no longer capture a firm with a normal unit - must use spy
//----- capture this firm if there is nobody here -----//
/*
if( worker_array && worker_count==0 && overseer_recno==0 && // if the firm is empty, assign to take over the firm
unitPtr->skill.skill_id == firm_skill_id ) // the takeover unit must have the skill of this firm
{
change_nation(unitPtr->nation_recno);
}
else
*/ return; // if cannot capture, the nations are not the same, return now. This will happen if the unit's nation was changed during his moving to the firm.
}
//-- if there isn't any overseer in this firm or this unit's skill is higher than the current overseer's skill --//
//### begin alex 18/10 ###//
unitPtr->group_select_id = 0; // clear group select id
//#### end alex 18/10 ####//
FirmInfo* firmInfo = firm_res[firm_id];
if( firmInfo->need_overseer &&
( !overseer_recno ||
( unitPtr->skill.skill_id == firm_skill_id &&
unit_array[overseer_recno]->skill.skill_id != firm_skill_id ) || // the current overseer does not have the required skill
( unitPtr->skill.skill_id == firm_skill_id &&
unitPtr->skill.skill_level > unit_array[overseer_recno]->skill.skill_level )
) )
{
assign_overseer(unitRecno);
}
else if( firmInfo->need_worker )
{
assign_worker(unitRecno);
}
}
//--------- End of function Firm::assign_unit -----------//
//--------- Begin of function Firm::assign_overseer --------//
//
// Assign an unit as the overseer of this firm
//
// newOverseerRecno - recno of the new overseer unit.
// 0 means resign the current overseer
//
// Note: If a new overseer is assigned to the firm, there should be
// space for the old overseer to initialize and appear in the
// map (the space the new overseer occupied).
//
// ** If the newOverseerRecno==0, there may be no space for
// creating the old overseer. Then, the old overseer will be
// deleted. **
// ** else there must be space for creating the old overseer,
// at least the space occupied by the new overseer **
//
void Firm::assign_overseer(int newOverseerRecno)
{
if( !firm_res[firm_id]->need_overseer )
return;
if( !newOverseerRecno && !overseer_recno )
return;
//--- if the new overseer's nation is not the same as the firm's nation, don't assign ---//
if( newOverseerRecno && unit_array[newOverseerRecno]->nation_recno != nation_recno )
return;
//------------------------------------------//
int oldOverseerRecno = overseer_recno;
if(!newOverseerRecno)
{
//------------------------------------------------------------------------------------------------//
// the old overseer may be kept in firm or killed if remove_firm is true
//------------------------------------------------------------------------------------------------//
err_when(!overseer_recno);
Unit *oldUnitPtr = unit_array[overseer_recno];
SpriteInfo *spriteInfo = sprite_res[unit_res[oldUnitPtr->unit_id]->sprite_id];
int xLoc = loc_x1;
int yLoc = loc_y1;
if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
{
if(remove_firm)
kill_overseer();
}
else
{
//------ there should be space for creating the overseer -----//
mobilize_overseer();
/*
//-- if the overseer is resigned without successor, mobilize a worker as overseer --//
if(!newOverseerRecno && worker_array)
{
int bestWorkerId = best_worker_id(); // find the most skilled worker
if( bestWorkerId )
newOverseerRecno = mobilize_worker(bestWorkerId,1);
}
*/
}
}
else
{
//----------- there should be space for creating the overseer ---------//
err_when(!newOverseerRecno);
Unit *unitPtr = unit_array[newOverseerRecno];
int originalXLoc = unitPtr->next_x_loc();
int originalYLoc = unitPtr->next_y_loc();
err_when( unitPtr->hit_points <= 0 );
unitPtr->deinit_sprite();
//----------------------------------------------------------------------------------------//
// There should be at least one location (occupied by the new overseer) for creating the old
// overseer.
//
// 1) If a town is already created, the new overseer settle down there, free its space for
// creating the new overseer.
// 2) If the overseer and the workers live in the firm, no town will be created. Thus, the
// space occupied by the old overseer is free for creating the new overseer.
// 3) If the overseer and the workers need live in town, and a town is created. i.e. there
// is no overseer or worker in the firm, so just assign the new overseer in the firm
//----------------------------------------------------------------------------------------//
if(!overseer_recno && !worker_count)
{
//------------------------------------------------------------------------------------------------//
// the firm is empty
//------------------------------------------------------------------------------------------------//
if(firm_res[firm_id]->live_in_town)
{
overseer_town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 1); // the overseer settles down
if(!overseer_town_recno)
return; // no space for creating the town, just return without assigning
}
//------- set the unit to overseer mode and deinit the sprite ------//
overseer_recno = newOverseerRecno;
Unit *unitPtr = unit_array[overseer_recno];
unitPtr->set_mode(UNIT_MODE_OVERSEE, firm_recno);
unitPtr->deinit_sprite(); // hide the unit from the world map
//--------- if the unit is a spy -----------//
if( unitPtr->spy_recno )
spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
/*
//------ capture the firm if the overseer is from another nation ---//
if(unit_array[overseer_recno]->nation_recno != nation_recno)
change_nation(unit_array[overseer_recno]->nation_recno);
*/
}
else
{
//------------------------------------------------------------------------------------------------//
// a town should exist if the overseer need live in town
//------------------------------------------------------------------------------------------------//
if(firm_res[firm_id]->live_in_town)
{
overseer_town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 1); // the overseer settles down
if(!overseer_town_recno)
return; // reach max population and no space to create town, return without assigning
}
Unit *unitPtr = unit_array[newOverseerRecno];
unitPtr->deinit_sprite();
if(overseer_recno)
mobilize_overseer();
overseer_recno = newOverseerRecno;
unitPtr->set_mode(UNIT_MODE_OVERSEE, firm_recno);
//--------- if the unit is a spy -----------//
if( unitPtr->spy_recno )
spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
/*
//------ capture the firm if the overseer is from another nation ---//
if(unit_array[overseer_recno]->nation_recno != nation_recno)
change_nation(unit_array[overseer_recno]->nation_recno);
*/
}
}
//------- update loyalty -------//
if( newOverseerRecno && !unit_array.is_deleted(newOverseerRecno) )
unit_array[newOverseerRecno]->update_loyalty();
//----------- refresh display if this firm is selected ----------//
if(firm_array.selected_recno == firm_recno)
info.disp();
}
//----------- End of function Firm::assign_overseer --------//
//--------- Begin of function Firm::mobilize_overseer --------//
//
int Firm::mobilize_overseer()
{
if( !overseer_recno )
return 0;
//--------- restore overseer's harmony ---------//
int overseerRecno = overseer_recno;
Unit* unitPtr = unit_array[overseer_recno];
//-------- if the overseer is a spy -------//
if( unitPtr->spy_recno )
spy_array[unitPtr->spy_recno]->set_place(SPY_MOBILE, unitPtr->sprite_recno);
//---- cancel the overseer's presence in the town -----//
if( firm_res[firm_id]->live_in_town )
town_array[overseer_town_recno]->dec_pop(unitPtr->race_id, 1);
//----- get this overseer out of the firm -----//
SpriteInfo* spriteInfo = sprite_res[unit_res[unitPtr->unit_id]->sprite_id];
int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
int spaceFound = locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height);
if(spaceFound)
{
unitPtr->init_sprite(xLoc, yLoc);
unitPtr->set_mode(0); // reset overseen firm recno
}
else
{
unit_array.del(overseer_recno); // delete it when there is no space for the unit
return 0;
}
//--------- reset overseer_recno -------------//
overseer_recno = 0;
overseer_town_recno = 0;
//------- update loyalty -------//
if( overseerRecno && !unit_array.is_deleted(overseerRecno) )
unit_array[overseerRecno]->update_loyalty();
return overseerRecno;
}
//----------- End of function Firm::mobilize_overseer --------//
//--------- Begin of function Firm::mobilize_builder --------//
int Firm::mobilize_builder(short recno)
{
//----------- mobilize the builder -------------//
Unit* unitPtr = unit_array[recno];
SpriteInfo *spriteInfo = unitPtr->sprite_info;
int xLoc=loc_x1, yLoc=loc_y1;
if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height, UNIT_LAND, builder_region_id) &&
!world.locate_space(xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height, UNIT_LAND, builder_region_id))
{
kill_builder(recno);
return 0;
}
unitPtr->init_sprite(xLoc, yLoc);
unitPtr->stop2(); // clear all previously defined action
err_when(unitPtr->unit_mode != UNIT_MODE_CONSTRUCT);
unitPtr->set_mode(0);
return 1;
}
//----------- End of function Firm::mobilize_builder --------//
//--------- Begin of function Firm::best_worker_id --------//
//
int Firm::best_worker_id()
{
int bestWorkerId=0, maxWorkerSkill=0;
char rankId;
int liveInTown = firm_res[firm_id]->live_in_town;
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
for( int i=0 ; ination_recno == nation_recno )
{
if(firm_id==FIRM_CAMP)
{
rankId = worker_array[i].rank_id;
if(rankId!=RANK_GENERAL && rankId!=RANK_KING)
continue;
}
if( worker_array[i].skill_level > maxWorkerSkill )
{
maxWorkerSkill = worker_array[i].skill_level;
bestWorkerId = i+1;
}
}
}
return bestWorkerId;
}
//----------- End of function Firm::best_worker_id --------//
//--------- Begin of function Firm::free_worker_room --------//
//
// Resign the worst worker from the firm to free up a room for
// a new worker.
//
void Firm::free_worker_room()
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
//---- if there is space for one more worker, demote the overseer to worker ----//
if( worker_count < MAX_WORKER || worker_count==0 )
return;
//---- if all worker space are full, resign the worst worker to release one worker space for the overseer ----//
int worestWorkerId=0, minWorkerSkill=0x7FFF;
for( int i=0 ; itrue_nation_recno() != nation_recno &&
worker_count == MAX_WORKER )
{
return;
}
//---- if all worker space are full, resign the worst worker to release one worker space for the overseer ----//
err_when( unitPtr->rank_id == RANK_KING );
err_when( unitPtr->hit_points <= 0 );
int unitXLoc= -1, unitYLoc;
if( worker_count == MAX_WORKER )
{
int worstWorkerId=0, minWorkerSkill=0x7FFF, workerSkill;
for(int i=0; iMAX_WORKER);
unitXLoc = unitPtr->next_x_loc(); // save the location for later init_sprite() if the assign settle action failed
unitYLoc = unitPtr->next_y_loc();
unitPtr->deinit_sprite(); // free the location for creating the worst unit
#ifdef DEBUG
int oldWorkerCount = worker_count;
int resignResult = resign_worker(worstWorkerId);
err_when(!resignResult && oldWorkerCount==worker_count);
#else
resign_worker(worstWorkerId);
#endif
}
// err_when( worker_count >= MAX_WORKER );
//---------- there is room for the new worker ------------//
Worker* workerPtr = worker_array + worker_count;
memset( workerPtr, 0, sizeof(Worker) );
if( firm_res[firm_id]->live_in_town )
{
workerPtr->town_recno = assign_settle(unitPtr->race_id, unitPtr->loyalty, 0); // the worker settles down
if( !workerPtr->town_recno )
{
//--- the unit was deinit_sprite(), and now the assign settle action failed, we need to init_sprite() to restore it ---//
if( unitXLoc>=0 && !unitPtr->is_visible() )
unitPtr->init_sprite(unitXLoc, unitYLoc);
return;
}
}
else
{
workerPtr->town_recno = 0;
workerPtr->worker_loyalty = unitPtr->loyalty;
}
//------- add the worker to the firm -------//
worker_count++;
err_when( worker_count > MAX_WORKER );
workerPtr->name_id = unitPtr->name_id;
workerPtr->race_id = unitPtr->race_id;
workerPtr->unit_id = unitPtr->unit_id;
workerPtr->rank_id = unitPtr->rank_id;
workerPtr->skill_id = firm_skill_id;
workerPtr->skill_level = unitPtr->skill.get_skill(firm_skill_id);
if( workerPtr->skill_level == 0 )
workerPtr->skill_level = CITIZEN_SKILL_LEVEL;
err_when( workerPtr->skill_level<0 );
err_when( workerPtr->skill_level>100 );
/*#ifdef DEBUG2
if(unit_res[unitPtr->unit_id]->unit_class==UNIT_CLASS_HUMAN)
{
unitPtr->skill.combat_level = 60;
unitPtr->hit_points = unitPtr->skill.combat_level*2;
unitPtr->max_hit_points = unitPtr->hit_points;
}
#endif*/
workerPtr->combat_level = unitPtr->skill.combat_level;
workerPtr->hit_points = (int) unitPtr->hit_points;
err_when( workerPtr->combat_level <= 0 || workerPtr->combat_level > 100 );
err_when( workerPtr->hit_points < 0 );
if( workerPtr->hit_points == 0 ) // 0.? will become 0 in (float) to (int) conversion
workerPtr->hit_points = 1;
if( unit_res[unitPtr->unit_id]->unit_class == UNIT_CLASS_WEAPON )
{
workerPtr->extra_para = unitPtr->get_weapon_version();
}
else if( unitPtr->race_id )
{
workerPtr->extra_para = unitPtr->cur_power;
}
else
{
workerPtr->extra_para = 0;
}
workerPtr->init_potential();
//------ if the recruited worker is a spy -----//
if( unitPtr->spy_recno )
{
spy_array[unitPtr->spy_recno]->set_place( SPY_FIRM, firm_recno );
workerPtr->spy_recno = unitPtr->spy_recno;
unitPtr->spy_recno = 0; // reset it now so Unit::deinit() won't delete the Spy in spy_array
}
//--------- the unit disappear in firm -----//
if( !firm_res[firm_id]->live_in_town ) // if the unit does not live in town, increase the unit count now
unit_res[unitPtr->unit_id]->inc_nation_unit_count(nation_recno);
unit_array.disappear_in_firm(workerUnitRecno);
}
//----------- End of function Firm::assign_worker --------//
//--------- Begin of function Firm::assign_settle --------//
//
// The newly assigned overseer / worker settles down.
//
// raceId - race id. of the unit
// unitLoyalty - loyalty of the unit
// isOverseer - whether the unit is an overseer, if not,
// it is then a worker.
//
// return: townRecno - the home town of the overseer/worker
// 0 - no space to settle.
//
int Firm::assign_settle(int raceId, int unitLoyalty, int isOverseer)
{
err_when( !firm_res[firm_id]->live_in_town );
err_when( unitLoyalty < 0 || unitLoyalty > 100 );
//--- if there is a town of our nation within the effective distance ---//
int townRecno = find_settle_town();
if( townRecno )
{
town_array[townRecno]->inc_pop(raceId, 1, unitLoyalty);
return townRecno;
}
//--- should create a town near the this firm, if there is no other town in the map ---//
int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
if( world.locate_space( xLoc, yLoc, loc_x2, loc_y2, STD_TOWN_LOC_WIDTH,
STD_TOWN_LOC_HEIGHT, UNIT_LAND, region_id, 1 ) ) // the town must be in the same region as this firm.
{
if( m.points_distance( center_x, center_y, xLoc+(STD_TOWN_LOC_WIDTH-1)/2,
yLoc+(STD_TOWN_LOC_HEIGHT-1)/2 ) <= EFFECTIVE_FIRM_TOWN_DISTANCE )
{
int townRecno = town_array.add_town( nation_recno, raceId, xLoc, yLoc );
Town* townPtr = town_array[townRecno];
townPtr->init_pop( raceId, 1, unitLoyalty, 1 ); // 1st 1 - population, 2nd 1 - the unit has a job already
townPtr->auto_set_layout();
return townRecno;
}
}
//---- not able to find a space for a new town within the effective distance ----//
return 0;
}
//----------- End of function Firm::assign_settle --------//
//--------- Begin of function Firm::find_settle_town --------//
//
// Find a suitable town for the unit to settle.
//
int Firm::find_settle_town()
{
int townDistance, minDistance=0x7FFF, nearestTownRecno=0;
Town* townPtr;
Nation* nationPtr = nation_array[nation_recno];
//-------- scan for our own town first -----------//
for( int i=0 ; ipopulation>=MAX_TOWN_POPULATION )
continue;
if( townPtr->nation_recno != nation_recno )
continue;
townDistance = m.points_distance( townPtr->center_x, townPtr->center_y, center_x, center_y );
if( townDistance < minDistance )
{
minDistance = townDistance;
nearestTownRecno = townPtr->town_recno;
}
}
if( nearestTownRecno )
return nearestTownRecno;
else
return 0;
}
//----------- End of function Firm::find_settle_town --------//
//--------- Begin of function Firm::set_world_matrix --------//
//
// Set the cargo id of current firm int he world matrix
//
void Firm::set_world_matrix()
{
//--- if a nation set up a firm in a location that the player has explored, contact between the nation and the player is established ---//
int xLoc, yLoc;
for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
{
for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
{
world.get_loc(xLoc, yLoc)->set_firm(firm_recno);
}
}
//--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---//
establish_contact_with_player();
//------------ reveal new land ----------//
if( nation_recno == nation_array.player_recno ||
(nation_recno && nation_array[nation_recno]->is_allied_with_player) )
{
world.unveil( loc_x1, loc_y1, loc_x2, loc_y2 );
world.visit( loc_x1, loc_y1, loc_x2, loc_y2, EXPLORE_RANGE-1 );
}
//-------- set should_set_power --------//
should_set_power = get_should_set_power();
//---- set this town's influence on the map ----//
if( should_set_power )
world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, nation_recno);
//---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----//
if( is_in_zoom_win() )
sys.zoom_need_redraw = 1; // set the flag on so it will be redrawn in the next frame
}
//----------- End of function Firm::set_world_matrix --------//
//--------- Begin of function Firm::get_should_set_power --------//
//
int Firm::get_should_set_power()
{
int shouldSetPower = 1;
if( firm_id == FIRM_HARBOR ) // don't set power for harbors
{
shouldSetPower = 0;
}
else if( firm_id == FIRM_MARKET )
{
//--- don't set power for a market if it's linked to another nation's town ---//
Town *townPtr;
shouldSetPower = 0;
//--- only set the shouldSetPower to 1 if the market is linked to a firm of ours ---//
for( int i=0 ; ination_recno == nation_recno )
{
shouldSetPower = 1;
break;
}
}
}
return shouldSetPower;
}
//----------- End of function Firm::get_should_set_power --------//
//------- Begin of function Firm::establish_contact_with_player --------//
//
// See if the town's location is an explored area, establish contact
// with the player.
//
void Firm::establish_contact_with_player()
{
if( !nation_recno )
return;
int xLoc, yLoc;
Location* locPtr;
for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
{
for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
{
locPtr = world.get_loc(xLoc, yLoc);
locPtr->set_firm(firm_recno);
if( locPtr->explored() && nation_array.player_recno )
{
NationRelation *relation = (~nation_array)->get_relation(nation_recno);
if( !remote.is_enable() )
{
relation->has_contact = 1;
}
else
{
if( !relation->has_contact && !relation->contact_msg_flag )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
*shortPtr = nation_array.player_recno;
shortPtr[1] = nation_recno;
relation->contact_msg_flag = 1;
}
}
}
}
}
}
//-------- End of function Firm::establish_contact_with_player --------//
//--------- Begin of function Firm::restore_world_matrix --------//
//
// When the firm is destroyed, restore the original land id
//
void Firm::restore_world_matrix()
{
int xLoc, yLoc;
for( yLoc=loc_y1 ; yLoc<=loc_y2 ; yLoc++ )
{
for( xLoc=loc_x1 ; xLoc<=loc_x2 ; xLoc++ )
{
err_when( world.get_loc(xLoc,yLoc)->firm_recno() != firm_recno );
world.get_loc(xLoc,yLoc)->remove_firm();
}
}
//---- restore this town's influence on the map ----//
if( should_set_power ) // no power region for harbor as it build on coast which cannot be set with power region
world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
//---- if the newly built firm is visual in the zoom window, redraw the zoom buffer ----//
if( is_in_zoom_win() )
sys.zoom_need_redraw = 1;
}
//----------- End of function Firm::restore_world_matrix --------//
//---------- Begin of function Firm::own_firm --------//
//
int Firm::own_firm()
{
return nation_recno == nation_array.player_recno;
}
//----------- End of function Firm::own_firm ---------//
//---------- Begin of function Firm::process_animation --------//
//
void Firm::process_animation()
{
//-------- process animation ----------//
FirmBuild* firmBuild = firm_res.get_build(firm_build_id);
int frameCount = firmBuild->frame_count;
if( frameCount==1 ) // no animation for this firm
return;
//---------- next frame -----------//
if( --remain_frame_delay==0 ) // if it is in the delay between frames
{
remain_frame_delay = (char) firmBuild->frame_delay(cur_frame);
if( ++cur_frame > frameCount )
{
if( firmBuild->animate_full_size )
cur_frame = 1;
else
{
cur_frame = 2; // start with the 2nd frame as the 1st frame is the common frame
err_when( frameCount <=2 ); // for segmented animation, the minimum no. of frames must be 3, as the first one is the common frame
}
}
}
}
//---------- End of function Firm::process_animation --------//
//---------- Begin of function Firm::process_construction --------//
//
void Firm::process_construction()
{
err_when(firm_id!=FIRM_MONSTER && builder_recno<=0);
if(firm_id==FIRM_MONSTER)
{
//--------- process construction for monster firm ----------//
hit_points++;
#ifdef DEBUG
if( config.fast_build && nation_recno==nation_array.player_recno )
hit_points += 10;
#endif;
if(hit_points>=max_hit_points)
{
hit_points = max_hit_points;
under_construction = 0;
}
return;
}
err_when(firm_id==FIRM_MONSTER);
if( !under_construction )
return;
//--- can only do construction when the firm is not under attack ---//
if( info.game_date <= last_attacked_date+1 )
return;
if( sys.frame_count%2!=0 ) // one build every 2 frames
return;
//------ increase the construction progress ------//
Unit *unitPtr = unit_array[builder_recno];
if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION ) // if builder unit has construction skill
hit_points += 1+unitPtr->skill.skill_level/30;
else
hit_points++;
if( config.fast_build && nation_recno==nation_array.player_recno )
hit_points += 10;
//----- increase skill level of the builder unit -----//
if( unitPtr->skill.skill_id == SKILL_CONSTRUCTION ) // if builder unit has construction skill
{
if( ++unitPtr->skill.skill_level_minor > 100 )
{
unitPtr->skill.skill_level_minor = 0;
if( unitPtr->skill.skill_level < 100 )
unitPtr->skill.skill_level++;
}
}
//------- when the construction is complete ----------//
if( hit_points >= max_hit_points ) // finished construction
{
hit_points = max_hit_points;
int needAssignUnit=0;
under_construction = 0;
// ##### begin Gilbert 10/10 #######//
if( nation_recno == nation_array.player_recno )
se_res.far_sound(center_x, center_y, 1, 'S', unitPtr->sprite_id,
"FINS", 'F', firm_id);
// ##### end Gilbert 10/10 #######//
err_when(builder_recno<=0 || unit_array.is_deleted(builder_recno));
err_when(unitPtr->nation_recno!=nation_recno);
FirmInfo* firmInfo=firm_res[firm_id];
if( (firmInfo->need_overseer || firmInfo->need_worker) &&
(firmInfo->firm_skill_id==0 || firmInfo->firm_skill_id == (unitPtr->skill).skill_id) ) // the builder with the skill required
{
unitPtr->set_mode(0); // reset it from UNIT_MODE_CONSTRUCT
needAssignUnit=1;
}
else
{
set_builder(0);
}
//---------------------------------------------------------------------------------------//
// should call assign_unit() first before calling action_finished(...UNDER_CONSTRUCTION)
//---------------------------------------------------------------------------------------//
if( needAssignUnit )
{
assign_unit(builder_recno);
//------------------------------------------------------------------------------//
// Note: there may be chance the unit cannot be assigned into the firm
//------------------------------------------------------------------------------//
if(!worker_count && !overseer_recno) // no assignment, can't assign
{
//------- init_sprite or delete the builder ---------//
int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
SpriteInfo *spriteInfo = unitPtr->sprite_info;
if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
unit_array.disappear_in_firm(builder_recno); // kill the unit
else
unitPtr->init_sprite(xLoc, yLoc); // restore the unit
}
}
// ##### begin Gilbert 10/10 #######//
//if( nation_recno == nation_array.player_recno )
// se_res.far_sound(center_x, center_y, 1, 'S', unitPtr->sprite_id,
// "FINS", 'F', firm_id);
// ##### end Gilbert 10/10 #######//
builder_recno = 0;
}
err_when (hit_points < 0 || hit_points > max_hit_points );
}
//---------- End of function Firm::process_construction --------//
//---------- Begin of function Firm::set_builder --------//
//
// newBuilderRecno - >0 the recno of the new builder unit.
// 0 just remove the existing builder, do not assign new one.
//
// return: 0-the old builder is killed
// 1-the builder is changed successfully.
//
int Firm::set_builder(short newBuilderRecno)
{
err_when( under_construction && newBuilderRecno==0 ); // can't remove the construction worker when the firm is under construction
//------------------------------------//
short oldBuilderRecno = builder_recno; // store the old builder recno
builder_recno = newBuilderRecno;
//-------- assign the new builder ---------//
if(builder_recno)
{
Unit* unitPtr = unit_array[builder_recno];
//### begin alex 18/10 ###//
unitPtr->group_select_id = 0; // clear group select id
//#### end alex 18/10 ####//
if(unitPtr->is_visible()) // is visible if the unit is not inside the firm location
{
builder_region_id = world.get_region_id( unitPtr->cur_x_loc(), unitPtr->cur_y_loc() );
unitPtr->deinit_sprite();
if( unitPtr->selected_flag )
{
unitPtr->selected_flag = 0;
unit_array.selected_count--;
}
}
err_when( unitPtr->unit_mode != 0 );
unitPtr->set_mode( UNIT_MODE_CONSTRUCT, firm_recno );
}
if(oldBuilderRecno)
mobilize_builder(oldBuilderRecno);
return 1;
}
//---------- End of function Firm::set_builder --------//
//---------- Begin of function Firm::next_day --------//
//
void Firm::next_day()
{
if( !nation_recno )
return;
//------ think about updating link status -------//
//
// This part must be done here instead of in
// process_ai() because it will be too late to do
// it in process_ai() as the next_day() will call
// first and some wrong goods may be input to markets.
//
//-----------------------------------------------//
if( firm_ai )
{
if( info.game_date%30==firm_recno%30 || !ai_link_checked ) // once 30 days or when the link has been changed.
{
ai_update_link_status();
ai_link_checked = 1;
}
}
//-------- pay expenses ----------//
pay_expense();
//------- update loyalty --------//
if( info.game_date%30 == firm_recno%30 )
update_loyalty();
//-------- consume food --------//
if( !firm_res[firm_id]->live_in_town && worker_count>0 )
consume_food();
//------ think worker migration -------//
if( worker_array && info.game_date%30 == firm_recno%30 )
think_worker_migrate();
//--------- repairing ----------//
process_repair();
//------ catching spies -------//
if( info.game_date%30 == firm_recno%30 )
spy_array.catch_spy(SPY_FIRM, firm_recno);
//----- process workers from other town -----//
if( firm_res[firm_id]->live_in_town )
{
process_independent_town_worker();
}
//--- recheck no_neighbor_space after a period, there may be new space available now ---//
if( no_neighbor_space && info.game_date%180 == firm_recno%180 )
{
short buildXLoc, buildYLoc;
if( nation_array[nation_recno]->find_best_firm_loc(FIRM_INN, loc_x1, loc_y1, buildXLoc, buildYLoc) ) // whether it's FIRM_INN or not really doesn't matter, just any firm type will do
no_neighbor_space = 0;
}
//-------- debug code ---------//
#ifdef DEBUG
err_when( builder_recno && unit_array.is_deleted(builder_recno) );
if( worker_array )
{
for( int i=0 ; irank_id == RANK_SOLDIER );
}
#endif
}
//----------- End of function Firm::next_day ---------//
//---------- Begin of function Firm::next_month --------//
//
void Firm::next_month()
{
//------ update nation power recno ------//
int newShouldSetPower = get_should_set_power();
if( newShouldSetPower == should_set_power )
return;
if( should_set_power )
world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
should_set_power = newShouldSetPower;
if( should_set_power )
world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, nation_recno);
}
//----------- End of function Firm::next_month ---------//
//---------- Begin of function Firm::next_year --------//
//
void Firm::next_year()
{
//------- post income data --------//
last_year_income = cur_year_income;
cur_year_income = (float) 0;
}
//----------- End of function Firm::next_year ---------//
//---------- Begin of function Firm::update_loyalty --------//
//
void Firm::update_loyalty()
{
if( firm_res[firm_id]->live_in_town ) // only for those who do not live in town
return;
//----- update loyalty of the soldiers -----//
Worker* workerPtr = worker_array;
for( int i=0 ; itarget_loyalty(firm_recno);
if( targetLoyalty > workerPtr->worker_loyalty )
{
int incValue = (targetLoyalty - workerPtr->worker_loyalty)/10;
int newLoyalty = (int) workerPtr->worker_loyalty + max(1, incValue);
if( newLoyalty > targetLoyalty )
newLoyalty = targetLoyalty;
workerPtr->worker_loyalty = newLoyalty;
}
else if( targetLoyalty < workerPtr->worker_loyalty )
{
workerPtr->worker_loyalty--;
}
}
}
//----------- End of function Firm::update_loyalty ---------//
//---------- Begin of function Firm::process_repair --------//
//
void Firm::process_repair()
{
if( nation_array[nation_recno]->cash < 0 ) // if you don't have cash, the repair workers will not work
return;
if( !builder_recno )
return;
Unit *unitPtr = unit_array[builder_recno];
//--- can only do construction when the firm is not under attack ---//
if( info.game_date <= last_attacked_date+1 )
{
//---- if the construction worker is a spy, it will damage the building when the building is under attack ----//
if( unitPtr->spy_recno &&
unitPtr->true_nation_recno() != nation_recno )
{
hit_points -= (float) spy_array[unitPtr->spy_recno]->spy_skill / 30;
if( hit_points < 0 )
hit_points = (float) 0;
}
return;
}
//------- repair now - only process once every 3 days -----//
if( hit_points >= max_hit_points )
return;
err_when( unitPtr->skill.skill_id != SKILL_CONSTRUCTION );
int dayInterval = (100-unitPtr->skill.skill_level)/20+1; // repair once every 1 to 6 days, depending on the skill level of the construction worker
if( firm_recno % dayInterval == info.game_date % dayInterval )
{
hit_points++;
if( hit_points > max_hit_points )
hit_points = max_hit_points;
}
}
//----------- End of function Firm::process_repair ---------//
//---------- Begin of function Firm::pay_expense --------//
//
void Firm::pay_expense()
{
if( !nation_recno )
return;
Nation* nationPtr = nation_array[nation_recno];
//-------- fixed expenses ---------//
float dayExpense = (float) firm_res[firm_id]->year_cost / 365;
if( nationPtr->cash >= dayExpense )
{
nationPtr->add_expense( EXPENSE_FIRM, dayExpense, 1 );
}
else
{
if( hit_points > 0 )
hit_points--;
if( hit_points < 0 )
hit_points = (float) 0;
//--- when the hit points drop to zero and the firm is destroyed ---//
if( hit_points==0 && nation_recno == nation_array.player_recno )
news_array.firm_worn_out(firm_recno);
}
//----- paying salary to workers from other nations -----//
if( worker_array && firm_res[firm_id]->live_in_town )
{
int townNationRecno, payWorkerCount=0;
Worker* workerPtr;
for( int i=worker_count-1 ; i>=0 ; i-- )
{
workerPtr = worker_array+i;
townNationRecno = town_array[workerPtr->town_recno]->nation_recno;
if( townNationRecno != nation_recno )
{
//--- if we don't have cash to pay the foreign workers, resign them ---//
if( nationPtr->cash < 0 )
{
resign_worker(i+1);
}
else //----- pay salaries to the foreign workers now -----//
{
payWorkerCount++;
if( townNationRecno ) // the nation of the worker will get income
nation_array[townNationRecno]->add_income( INCOME_FOREIGN_WORKER, (float) WORKER_YEAR_SALARY / 365, 1 );
}
}
}
nationPtr->add_expense( EXPENSE_FOREIGN_WORKER, (float) WORKER_YEAR_SALARY * payWorkerCount / 365, 1 );
}
}
//----------- End of function Firm::pay_expense ---------//
//--------- Begin of function Firm::consume_food ---------//
//
void Firm::consume_food()
{
if( nation_array[nation_recno]->food > 0 )
{
int humanUnitCount=0;
for( int i=0 ; iconsume_food((float) humanUnitCount * PERSON_FOOD_YEAR_CONSUMPTION / 365);
}
else //--- decrease loyalty if the food has been run out ---//
{
if( info.game_date%NO_FOOD_LOYALTY_DECREASE_INTERVAL == 0 ) // decrease 1 loyalty point every 2 days
{
for( int i=0 ; iadd_income(incomeType, incomeAmt, 1);
}
//----------- End of function Firm::add_income ---------//
//--------- Begin of function Firm::year_expense ---------//
//
// Return the yearly expense for this firm.
//
int Firm::year_expense()
{
int totalExpense = firm_res[firm_id]->year_cost;
//---- pay salary to workers from foreign towns ----//
int payWorkerCount=0;
if( worker_array && firm_res[firm_id]->live_in_town )
{
int payWorkerCount=0;
Worker* workerPtr = worker_array;
for( int i=0 ; itown_recno]->nation_recno != nation_recno )
payWorkerCount++;
}
totalExpense += WORKER_YEAR_SALARY * payWorkerCount;
}
return totalExpense;
}
//----------- End of function Firm::year_expense -----------//
//--------- Begin of function Firm::sell_firm ---------//
void Firm::sell_firm(char remoteAction)
{
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_SELL, sizeof(short));
*shortPtr = firm_recno;
return;
}
//------- sell at 50% of the original cost -------//
Nation* nationPtr = nation_array[nation_recno];
int sellIncome = firm_res[firm_id]->setup_cost / 2 * (int) hit_points / (int) max_hit_points;
nationPtr->add_income(INCOME_SELL_FIRM, (float)sellIncome);
se_res.sound(center_x, center_y, 1, 'F', firm_id, "SELL" );
firm_array.del_firm(firm_recno);
}
//----------- End of function Firm::sell_firm -----------//
//--------- Begin of function Firm::destruct_firm ---------//
void Firm::destruct_firm(char remoteAction)
{
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_DESTRUCT, sizeof(short));
*shortPtr = firm_recno;
return;
}
se_res.sound(center_x, center_y, 1, 'F', firm_id, "DEST" );
firm_array.del_firm(firm_recno);
}
//----------- End of function Firm::destruct_firm -----------//
//--------- Begin of function Firm::cancel_construction ---------//
//
// Cancel construction
//
void Firm::cancel_construction(char remoteAction)
{
if( !remoteAction && remote.is_enable())
{
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_CANCEL, sizeof(short));
shortPtr[0] = firm_recno;
return;
}
//------ get half of the construction cost back -------//
Nation* nationPtr = nation_array[nation_recno];
nationPtr->add_expense( EXPENSE_FIRM, (float) -firm_res[firm_id]->setup_cost/2 );
firm_array.del_firm(firm_recno);
}
//----------- End of function Firm::cancel_construction -----------//
//---------- Begin of function Firm::recruit_worker --------//
//
void Firm::recruit_worker()
{
if( MAX_WORKER==worker_count )
return;
if( info.game_date%5 != firm_recno%5 ) // update population once 10 days
return;
err_when( worker_count > MAX_WORKER );
//-------- pull from neighbor towns --------//
int i;
Town* townPtr;
Nation* nationPtr = nation_array[nation_recno];
for( i=0 ; icash < 0 && nation_recno != townPtr->nation_recno )
continue;
//-------- if the town has any unit ready for jobs -------//
if( townPtr->jobless_population == 0 )
continue;
//---- if nation of the town is not hositle to this firm's nation ---//
if( pull_town_people(townPtr->town_recno, COMMAND_AUTO) )
return;
}
}
//----------- End of function Firm::recruit_worker ---------//
//---------- Begin of function Firm::pull_town_people --------//
//
// Pull people from the town. Also called by Town::draw_detect_link_line()
//
// townRecno - the town recno which the people are pulled from.
// [int] raceId - the race of the people to be pulled.
// if not given, pick one randomly.
// [int] forcePull - force pull people to to the firm.
// (default: 0)
//
int Firm::pull_town_people(int townRecno, char remoteAction, int raceId, int forcePull)
{
if( worker_count == MAX_WORKER ) // this can happen in a multiplayer game as Town::draw_detect_link_line() still have the old worker_count and thus allow this function being called.
return 0;
err_when( worker_count > MAX_WORKER );
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
if(!remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_PULL_TOWN_PEOPLE, 4*sizeof(short));
shortPtr[0] = firm_recno;
shortPtr[1] = townRecno;
shortPtr[2] = raceId;
// if raceId == 0, let each player choose the race by random number,
// to sychronize the random number
shortPtr[3] = forcePull;
return 0;
}
//---- people in the town go to work for the firm ---//
Town* townPtr = town_array[townRecno];
int i, popAdded=0;
//---- if doesn't specific a race, randomly pick one ----//
if( !raceId )
raceId = m.random(MAX_RACE)+1;
//----------- scan the races -----------//
for( i=0 ; irecruitable_race_pop(raceId,1); // 1-allow recruiting spies
if( recruitableCount > 0 )
{
//----- if the unit is forced to move to the firm ---//
if( forcePull ) // right-click to force pulling a worker from the village
{
if( townPtr->race_loyalty_array[raceId-1] < MIN_RECRUIT_LOYALTY )
return 0;
townPtr->recruit_dec_loyalty(raceId);
}
else //--- see if the unit will voluntarily move to the firm ---//
{
//--- the higher the loyalty is, the higher the chance of working for the firm ---//
if( townPtr->nation_recno )
{
if( m.random( (100-(int)townPtr->race_loyalty_array[raceId-1])/10 ) > 0 )
return 0;
}
else
{
if( m.random( (100-(int)townPtr->race_resistance_array[raceId-1][nation_recno-1])/10 ) > 0 )
return 0;
}
}
//----- get the chance of getting people to your command base is higher when the loyalty is higher ----//
if( firm_res[firm_id]->live_in_town )
{
townPtr->jobless_race_pop_array[raceId-1]--; // decrease the town's population
townPtr->jobless_population--;
err_when( townPtr->recruitable_race_pop(raceId,1) < 0 );
err_when( townPtr->jobless_population < 0 );
}
else
{
townPtr->dec_pop(raceId, 0);
}
//------- add the worker to the firm -----//
worker_count++;
err_when( worker_count > MAX_WORKER );
Worker* workerPtr = worker_array + worker_count - 1;
memset( workerPtr, 0, sizeof(Worker) );
workerPtr->race_id = raceId;
workerPtr->rank_id = RANK_SOLDIER;
workerPtr->unit_id = (char) race_res[raceId]->basic_unit_id;
workerPtr->worker_loyalty = (char) townPtr->race_loyalty_array[raceId-1];
if( firm_res[firm_id]->live_in_town )
workerPtr->town_recno = townRecno;
workerPtr->combat_level = CITIZEN_COMBAT_LEVEL;
workerPtr->hit_points = CITIZEN_HIT_POINTS;
workerPtr->skill_id = firm_skill_id;
workerPtr->skill_level = CITIZEN_SKILL_LEVEL;
workerPtr->init_potential();
//--------- if this is a military camp ---------//
//
// Increase armed unit count of the race of the worker assigned,
// as when a unit is assigned to a camp, Unit::deinit() will decrease
// the counter, so we need to increase it back here.
//
//---------------------------------------------------//
if( !firm_res[firm_id]->live_in_town )
unit_res[workerPtr->unit_id]->inc_nation_unit_count(nation_recno);
//------ if the recruited worker is a spy -----//
int spyCount = townPtr->race_spy_count_array[raceId-1];
if( spyCount >= m.random(recruitableCount)+1 )
{
int spyRecno = spy_array.find_town_spy(townRecno, raceId, m.random(spyCount)+1 ); // the 3rd parameter is which spy to recruit
err_when( !spyRecno );
workerPtr->spy_recno = spyRecno;
spy_array[spyRecno]->set_place(SPY_FIRM, firm_recno);
}
return 1;
}
if( ++raceId > MAX_RACE )
raceId = 1;
}
return 0;
}
//----------- End of function Firm::pull_town_people ---------//
//------ Begin of function Firm::process_independent_town_worker -----//
//
// Process workers from independent towns.
//
// When workers work for a foreign firm, the overall resistance of
// the worker's town towards that nation decreases.
//
void Firm::process_independent_town_worker()
{
if( firm_recno%15 != info.game_date%15 )
return;
#define RESISTANCE_DECREASE_PER_WORKER float(0.2) // resistance decrease per month every 15 days
Town* townPtr;
for( int i=0 ; ination_recno==0 ) // if it's an independent town
{
townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] -= RESISTANCE_DECREASE_PER_WORKER;
if( townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] < 0 )
townPtr->race_resistance_array[worker_array[i].race_id-1][nation_recno-1] = (float) 0;
}
}
}
//------- End of function Firm::process_independent_town_worker ------//
//---------- Begin of function Worker::init_potential --------//
//
void Worker::init_potential()
{
if( m.random(10)==0 ) // 1 out of 10 has a higher than normal potential in this skill
{
skill_potential = 50+m.random(51); // 50 to 100 potential
}
}
//----------- End of function Worker::init_potential ---------//
//---------- Begin of function Firm::calc_productivity --------//
//
// Calculate the productivity of the firm.
//
void Firm::calc_productivity()
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
#define RACE_SKILL_MULTIPLE (float)2.0
productivity = (float) 0;
//------- calculate the productivity of the workers -----------//
int i;
float totalSkill=(float)0;
Worker* workerPtr = worker_array;
for( i=0 ; iskill_level
* workerPtr->hit_points / workerPtr->max_hit_points();
}
//----- include skill in the calculation ------//
productivity = totalSkill / MAX_WORKER - sabotage_level;
if( productivity < 0 )
productivity = (float) 0;
}
//----------- End of function Firm::calc_productivity ---------//
//---------- Begin of function Firm::average_worker_skill --------//
//
// Return the average skill level of the workers in this firm.
//
int Firm::average_worker_skill()
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
if( worker_count==0 )
return 0;
//------- calculate the productivity of the workers -----------//
int i;
int totalSkill = 0;
Worker* workerPtr = worker_array;
for( i=0 ; iskill_level;
//----- include skill in the calculation ------//
return totalSkill / worker_count;
}
//----------- End of function Firm::average_worker_skill ---------//
//---------- Begin of function Firm::update_worker --------//
//
void Firm::update_worker()
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
if( info.game_date%15 != firm_recno%15 )
return;
if( worker_count==0 )
return;
//------- update the worker's para ---------//
int incValue, levelMinor;
Worker* workerPtr = worker_array;
for( int i=0 ; iskill_level < 100 ) // only train when the workers are working
{
err_when(workerPtr->skill_level<0 || workerPtr->skill_level>100);
incValue = max(10, 100-workerPtr->skill_level)
* workerPtr->hit_points / workerPtr->max_hit_points()
* (100+workerPtr->skill_potential) / 100 / 2;
//-------- increase level minor now --------//
levelMinor = workerPtr->skill_level_minor + incValue * (75+m.random(50)) / 100; // with random factors, resulting in 75% to 125% of the original
int loopCount=0;
while( levelMinor >= 100 )
{
levelMinor -= 100;
workerPtr->skill_level++;
err_when( loopCount++ > 1000 );
}
workerPtr->skill_level_minor = levelMinor;
}
//------- increase worker hit points --------//
int maxHitPoints = workerPtr->max_hit_points();
err_when( maxHitPoints <= 0 );
if( workerPtr->hit_points < maxHitPoints )
{
workerPtr->hit_points += 2; // units in firms recover twice as fast as they are mobile
if( workerPtr->hit_points > maxHitPoints )
workerPtr->hit_points = maxHitPoints;
}
}
}
//----------- End of function Firm::update_worker ---------//
//---------- Begin of function Firm::create_unit --------//
//
// Create an unit and place it below the firm.
//
// unitId - id. of the unit
// [int] townRecno - recno of the town from which the unit comes from
// if given, it means the unit comes from the town and
// should decrease the town population.
// (default: 0)
// [int] unitHasJob - whether the unit current has a job or not
// (default: 0)
//
// return : unitRecno - the recno of the unit created
//
int Firm::create_unit(int unitId, int townRecno, int unitHasJob)
{
//----look for an empty locatino for the unit to stand ----//
//--- scan for the 5 rows right below the building ---//
SpriteInfo* spriteInfo = sprite_res[unit_res[unitId]->sprite_id];
int xLoc=loc_x1, yLoc=loc_y1; // xLoc & yLoc are used for returning results
if(!locate_space(remove_firm, xLoc, yLoc, loc_x2, loc_y2, spriteInfo->loc_width, spriteInfo->loc_height))
return 0;
//------------ add the unit now ----------------//
int unitNationRecno;
if( townRecno )
unitNationRecno = town_array[townRecno]->nation_recno;
else
unitNationRecno = nation_recno;
int unitRecno = unit_array.add_unit( unitId, unitNationRecno, RANK_SOLDIER, 0, xLoc, yLoc );
//----- update the population of the town ------//
if( townRecno )
town_array[townRecno]->dec_pop(unit_array[unitRecno]->race_id, unitHasJob);
return unitRecno;
}
//----------- End of function Firm::create_unit ---------//
//--------- Begin of function Firm::mobilize_worker ---------//
//
// Promote a firm worker as a unit.
//
// return: the recno of the unit created.
//
int Firm::mobilize_worker(int workerId, char remoteAction)
{
if(!remoteAction && remote.is_enable() )
{
// packet strcture :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_MOBL_WORKER, 2*sizeof(short) );
shortPtr[0] = firm_recno;
shortPtr[1] = workerId;
return 0;
}
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
err_when( workerId<1 || workerId>worker_count );
//------------- resign worker --------------//
Worker thisWorker = worker_array[workerId-1];
int oldWorkerCount = worker_count;
int unitRecno2 = resign_worker(workerId);
if(!unitRecno2 && worker_count==oldWorkerCount)
return 0;
//------ create a mobile unit -------//
int unitRecno=0;
if( firm_res[firm_id]->live_in_town ) // if does not live_in_town, resign_worker() create the unit already, so don't create it again here.
{
unitRecno = create_worker_unit(thisWorker);
if( !unitRecno ) // no space for creating units
return 0;
}
//------------------------------------//
err_when( unitRecno2 && unitRecno ); // only one of them should have value
err_when( !unitRecno2 && !unitRecno ); // one of them must have a value
if( unitRecno )
return unitRecno;
else
return unitRecno2;
}
//----------- End of function Firm::mobilize_worker -----------//
//--------- Begin of function Firm::create_worker_unit ---------//
//
int Firm::create_worker_unit(Worker& thisWorker)
{
//--------- copy the worker's info --------//
int unitLoyalty = thisWorker.loyalty();
//------------ create an unit --------------//
int unitId = thisWorker.unit_id;
int unitRecno = create_unit( unitId, thisWorker.town_recno, 0 ); // this worker no longer has a job as it has been resigned
if( !unitRecno )
return 0;
Unit* unitPtr = unit_array[unitRecno];
UnitInfo *unitInfo = unit_res[unitId];
//------- set the unit's parameters --------//
unitPtr->skill.skill_id = thisWorker.skill_id;
unitPtr->skill.skill_level = thisWorker.skill_level;
unitPtr->skill.skill_level_minor = thisWorker.skill_level_minor;
err_when( unitPtr->skill.skill_level<0 || unitPtr->skill.skill_level>100 );
unitPtr->set_combat_level(thisWorker.combat_level);
unitPtr->skill.combat_level_minor = thisWorker.combat_level_minor;
err_when( unitPtr->skill.combat_level<=0 || unitPtr->skill.combat_level>100 );
unitPtr->loyalty = unitLoyalty;
unitPtr->hit_points = thisWorker.hit_points;
unitPtr->rank_id = thisWorker.rank_id;
if( unit_res[unitPtr->unit_id]->unit_class == UNIT_CLASS_WEAPON )
{
unitPtr->set_weapon_version( thisWorker.extra_para ); // restore nation contribution
}
else if( unitPtr->race_id )
{
unitPtr->cur_power = thisWorker.extra_para;
if( unitPtr->cur_power < 0 )
unitPtr->cur_power = 0;
if( unitPtr->cur_power > 150 )
unitPtr->cur_power = 150;
}
err_when( unitPtr->hit_points <= 0 );
unitPtr->fix_attack_info();
//if( unitInfo->unit_class == UNIT_CLASS_WEAPON )
//{
// switch( unitId )
// {
// case UNIT_BALLISTA:
// unitPtr->attack_count = 2;
// break;
// case UNIT_EXPLOSIVE_CART:
// unitPtr->attack_count = 0;
// break;
// default:
// unitPtr->attack_count = 1;
//}
// if( unitPtr->attack_count > 0)
// {
// unitPtr->attack_info_array = unit_res.attack_info_array
// + unitInfo->first_attack-1
// + (thisWorker.extra_para -1) * unitPtr->attack_count; // extra para keeps the weapon version
// }
// else
// {
// // no attack like explosive cart
// unitPtr->attack_info_array = NULL;
// }
// }
if( thisWorker.name_id && thisWorker.race_id ) // if this worker is formerly an unit who has a name
unitPtr->set_name(thisWorker.name_id);
err_when( !unitPtr->is_visible() );
//------ if the unit is a spy -------//
if( thisWorker.spy_recno )
{
Spy* spyPtr = spy_array[thisWorker.spy_recno];
unitPtr->spy_recno = thisWorker.spy_recno;
unitPtr->ai_unit = spyPtr->cloaked_nation_recno &&
nation_array[spyPtr->cloaked_nation_recno]->is_ai();
unitPtr->set_name(spyPtr->name_id); // set the name id. of this unit
spyPtr->set_place(SPY_MOBILE, unitRecno);
}
//--- decrease the nation unit count as the Unit has already increased it ----//
if( !firm_res[firm_id]->live_in_town ) // if the unit does not live in town, increase the unit count now
unit_res[unitPtr->unit_id]->dec_nation_unit_count(nation_recno);
return unitRecno;
}
//----------- End of function Firm::create_worker_unit -----------//
//--------- Begin of function Firm::mobilize_all_worker ---------//
//
// mobilize as many as workers if there is space for creating the
// workers
//
// [int] leaderUnitRecno - if given, the workers are assigned as
// a team and their leader_unit_recno are set.
// (default: 0)
//
void Firm::mobilize_all_worker(int leaderUnitRecno)
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
//------- detect buttons on hiring firm workers -------//
int loopCount = 0;
short unitRecno;
err_when( worker_count > MAX_WORKER );
while( worker_count > 0 )
{
err_when(++loopCount > 100);
unitRecno = mobilize_worker(1, COMMAND_AUTO); // always record 1 as the workers info are moved forward from the back to the front
if(!unitRecno)
break; // keep the rest workers as there is no space for creating the unit
if( leaderUnitRecno )
{
Unit* unitPtr = unit_array[unitRecno];
unitPtr->team_id = unit_array.cur_team_id; // define it as a team
unitPtr->leader_unit_recno = leaderUnitRecno;
unitPtr->update_loyalty(); // the unit is just assigned to a new leader, set its target loyalty
err_when( unitPtr->rank_id != RANK_KING && unitPtr->rank_id != RANK_GENERAL );
if( nation_recno == nation_array.player_recno )
unitPtr->selected_flag = 1;
}
}
unit_array.cur_team_id++;
}
//----------- End of function Firm::mobilize_all_worker -----------//
//--------- Begin of function Firm::resign_all_worker ---------//
//
// Resign all workers in the firm.
//
// [int] disappearFlag - whether the worker should disappear after
// resigning, and does not go back to the town.
//
void Firm::resign_all_worker(int disappearFlag)
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
//------- detect buttons on hiring firm workers -------//
int loopCount=0, townRecno, raceId;
int oldWorkerCount;
while( worker_count > 0 )
{
err_when(++loopCount > 100);
townRecno = worker_array[0].town_recno;
raceId = worker_array[0].race_id;
oldWorkerCount = worker_count;
if(!resign_worker(1))
{
if(oldWorkerCount==worker_count)
break; // no space to resign the worker, keep them in firm
}
if( disappearFlag && townRecno )
town_array[townRecno]->dec_pop(raceId, 0);
}
}
//----------- End of function Firm::resign_all_worker -----------//
//--------- Begin of function Firm::resign_worker ---------//
//
// Resign the worker from the firm.
//
// return: recno of the mobile unit created if there is one created.
//
int Firm::resign_worker(int workerId)
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
err_when( workerId<1 || workerId>worker_count );
//------- decrease worker no. and create an unit -----//
Worker* workerPtr = worker_array+workerId-1;
int unitRecno = 0;
if( workerPtr->race_id && workerPtr->name_id )
race_res[workerPtr->race_id]->free_name_id(workerPtr->name_id);
if( workerPtr->town_recno ) // town_recno is 0 if the workers in the firm do not live in towns
{
Town* townPtr = town_array[workerPtr->town_recno];
townPtr->jobless_race_pop_array[workerPtr->race_id-1]++; // decrease the town's population
townPtr->jobless_population++;
//------ put the spy in the town -------//
if( workerPtr->spy_recno )
spy_array[workerPtr->spy_recno]->set_place(SPY_TOWN, workerPtr->town_recno);
}
else
{
Worker thisWorker = worker_array[workerId-1];
unitRecno = create_worker_unit(thisWorker); // if he is a spy, create_worker_unit wil call set_place(SPY_MOBILE)
if(!unitRecno)
return 0; // return 0 eg there is no space to create the unit
}
//------- delete the record from the worker_array ------//
err_when( worker_count > MAX_WORKER );
err_when( selected_worker_id > worker_count );
m.del_array_rec(worker_array, worker_count, sizeof(Worker), workerId);
if( selected_worker_id > workerId || selected_worker_id == worker_count )
selected_worker_id--;
worker_count--;
err_when( worker_count < 0 );
err_when( selected_worker_id > worker_count );
return unitRecno;
}
//----------- End of function Firm::resign_worker -----------//
//------- Begin of function Firm::think_worker_migrate ---------//
//
// Let the workers think if they want to worker_migrate or not.
//
void Firm::think_worker_migrate()
{
#define MIN_MIGRATE_ATTRACT_LEVEL 30
if( worker_count==0 || !firm_res[firm_id]->live_in_town )
return;
int townPtrCount = town_array.size();
int townRecno = m.random(townPtrCount)+1;
int firmXLoc = center_x, firmYLoc = center_y;
int i, j, raceId, workerId;
Town *townPtr, *workerTownPtr;
Worker *workerPtr;
int curBaseAttractLevel, targetBaseAttractLevel, curAttractLevel, targetAttractLevel;
for( i=townPtrCount ; i>0 ; i-- )
{
if( ++townRecno > townPtrCount )
townRecno=1;
if( town_array.is_deleted(townRecno) )
continue;
townPtr = town_array[townRecno];
if(townPtr->population>=MAX_TOWN_POPULATION)
continue;
//------ check if this town is linked to the current firm -----//
for( j=townPtr->linked_firm_count-1 ; j>=0 ; j-- )
{
if( townPtr->linked_firm_array[j] == firm_recno &&
townPtr->linked_firm_enable_array[j] )
{
break;
}
}
if( j<0 )
continue;
//------------------------------------------------//
//
// Calculate the attractive factor, it is based on:
//
// - the reputation of the target nation (+0 to 100)
// - the racial harmony of the race in the target town (+0 to 100)
// - the no. of people of the race in the target town
// - distance between the current town and the target town (-0 to 100)
//
// Attractiveness level range: 0 to 200
//
//------------------------------------------------//
targetBaseAttractLevel = 0;
if( townPtr->nation_recno )
targetBaseAttractLevel += (int) nation_array[townPtr->nation_recno]->reputation;
//---- scan all workers, see if any of them want to worker_migrate ----//
workerId=m.random(worker_count)+1;
for(j=0 ; j worker_count )
workerId = 1;
workerPtr = worker_array+workerId-1;
if( workerPtr->town_recno == townRecno )
continue;
//-- do not migrate if the target town's population of that race is less than half of the population of the current town --//
raceId = workerPtr->race_id;
workerTownPtr = town_array[workerPtr->town_recno];
if( townPtr->race_pop_array[raceId-1] < workerTownPtr->race_pop_array[raceId-1]/2 )
continue;
//------ calc the current and target attractiveness level ------//
workerTownPtr = town_array[workerPtr->town_recno];
if( workerTownPtr->nation_recno )
curBaseAttractLevel = (int) nation_array[workerTownPtr->nation_recno]->reputation;
else
curBaseAttractLevel = 0;
targetAttractLevel = targetBaseAttractLevel +
townPtr->race_harmony(raceId);
if( targetAttractLevel < MIN_MIGRATE_ATTRACT_LEVEL )
continue;
curAttractLevel = curBaseAttractLevel +
workerTownPtr->race_harmony(raceId) +
((int)workerPtr->loyalty() - 40); // loyalty > 40 is considered as positive force, < 40 is considered as negative force
if( targetAttractLevel > curAttractLevel )
{
int newLoyalty = max( REBEL_LOYALTY+1, targetAttractLevel/2 );
worker_migrate(workerId, townRecno, newLoyalty);
return;
}
}
}
}
//-------- End of function Firm::think_worker_migrate -----------//
//------- Begin of function Firm::worker_migrate ---------//
//
// Worker worker_migrate from one town to another.
//
// workerId - id. of the worker
// destTownRecno - recno of the destination town.
// newLoyalty - loyalty of the unit in the target town.
//
void Firm::worker_migrate(int workerId, int destTownRecno, int newLoyalty)
{
err_when( !worker_array ); // this function shouldn't be called if this firm does not need worker
err_when( !firm_res[firm_id]->live_in_town );
Worker* workerPtr = worker_array+workerId-1;
int raceId = workerPtr->race_id;
Town* srcTown = town_array[workerPtr->town_recno];
Town* destTown = town_array[destTownRecno];
err_when( !raceId );
err_when( m.points_distance( center_x, center_y, destTown->center_x,
destTown->center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE );
//------------- add news --------------//
if( srcTown->nation_recno==nation_array.player_recno ||
destTown->nation_recno==nation_array.player_recno )
{
if( srcTown->nation_recno != destTown->nation_recno ) // don't add news for migrating between own towns
news_array.migrate(srcTown->town_recno, destTownRecno, raceId, 1, firm_recno);
}
//--------- migrate now ----------//
int keepJob = 1;
workerPtr->town_recno = destTownRecno;
//--------- decrease the population of the home town ------//
srcTown->dec_pop(raceId, keepJob);
//--------- increase the population of the target town ------//
destTown->inc_pop(raceId, keepJob, newLoyalty);
}
//-------- End of function Firm::worker_migrate -----------//
//-------- Begin of function Firm::set_worker_home_town --------//
//
// This function has two purposes.
//
// If the worker's home town is already the given one,
// then resign the worker.
//
// Otherwise, set the worker's home town to the new onel.
//
// townRecno - the new home town recno
// [int] workerId - the id. of the worker to be set to a new home town
// (default: the currently selected worker, selected_worker_id)
//
void Firm::set_worker_home_town(int townRecno, char remoteAction, int workerId)
{
if( !workerId )
workerId = selected_worker_id;
if( !workerId || workerId > worker_count )
return;
if(!remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_SET_WORKER_HOME, 3*sizeof(short));
shortPtr[0] = firm_recno;
shortPtr[1] = townRecno;
shortPtr[2] = workerId;
return;
}
err_when( workerId<1 || workerId>worker_count );
//-------------------------------------------------//
Worker* workerPtr = worker_array+workerId-1;
err_when( !workerPtr->race_id );
if( workerPtr->town_recno == townRecno )
{
resign_worker(workerId);
}
//--- otherwise, set the worker's home town to the new one ---//
else if( workerPtr->is_nation(firm_recno, nation_recno) ) // only allow when the worker lives in a town belonging to the same nation
{
int workerLoyalty = workerPtr->loyalty();
town_array[workerPtr->town_recno]->dec_pop(workerPtr->race_id, 1);
town_array[townRecno]->inc_pop(workerPtr->race_id, 1, workerLoyalty);
workerPtr->town_recno = townRecno;
}
}
//-------- End of function Firm::set_worker_home_town --------//
//------- Begin of function Worker::loyalty ---------//
//
int Worker::loyalty()
{
if( town_recno ) // if the worker lives in a town
return (int) town_array[town_recno]->race_loyalty_array[race_id-1];
else
return (int) worker_loyalty;
}
//-------- End of function Worker::loyalty -----------//
//------- Begin of function Worker::target_loyalty ---------//
//
int Worker::target_loyalty(int firmRecno)
{
if( town_recno ) // if the worker lives in a town
{
return (int) town_array[town_recno]->race_loyalty_array[race_id-1];
}
else
{
Firm* firmPtr = firm_array[firmRecno];
if( firmPtr->overseer_recno )
{
Unit* overseerUnit = unit_array[firmPtr->overseer_recno];
int overseerSkill = overseerUnit->skill.get_skill(SKILL_LEADING);
int targetLoyalty = 30 + overseerSkill/2;
//---------------------------------------------------//
//
// Soldiers with higher combat and leadership skill
// will get discontented if they are led by a general
// with low leadership.
//
//---------------------------------------------------//
targetLoyalty -= combat_level/2;
if( skill_level > overseerSkill )
targetLoyalty -= skill_level - overseerSkill;
if( overseerUnit->rank_id == RANK_KING )
targetLoyalty += 20;
if( race_res.is_same_race(race_id, overseerUnit->race_id) )
targetLoyalty += 20;
if( targetLoyalty < 0 )
targetLoyalty = 0;
if( targetLoyalty > 100 )
targetLoyalty = 100;
return targetLoyalty;
}
else //-- if there is no overseer, just return the current loyalty --//
{
return worker_loyalty;
}
}
}
//-------- End of function Worker::target_loyalty -----------//
//------- Begin of function Firm::setup_link ---------//
//
void Firm::setup_link()
{
//-----------------------------------------------------------------------------//
// check the connected firms location and structure if ai_link_checked is true
//-----------------------------------------------------------------------------//
if(firm_ai)
ai_link_checked = 0;
//----- build firm-to-firm link relationship -------//
int firmRecno, defaultLinkStatus;
Firm* firmPtr;
FirmInfo* firmInfo = firm_res[firm_id];
linked_firm_count = 0;
for( firmRecno=firm_array.size() ; firmRecno>0 ; firmRecno-- )
{
if( firm_array.is_deleted(firmRecno) || firmRecno==firm_recno )
continue;
firmPtr = firm_array[firmRecno];
//---- do not allow links between firms of different nation ----//
if( firmPtr->nation_recno != nation_recno )
continue;
//---------- check if the firm is close enough to this firm -------//
if( m.points_distance( firmPtr->center_x, firmPtr->center_y,
center_x, center_y ) > EFFECTIVE_FIRM_FIRM_DISTANCE )
{
continue;
}
//------ check if both are on the same terrain type ------//
if( world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()
!= world.get_loc(center_x, center_y)->is_plateau() )
{
continue;
}
//----- if the firms are linkable to each other -----//
if( !firmInfo->is_linkable_to_firm(firmPtr->firm_id) )
continue;
//------- determine the default link status ------//
if( firmPtr->nation_recno == nation_recno ) // if the two firms are of the same nation, get the default link status which is based on the types of the firms
defaultLinkStatus = firmInfo->default_link_status(firmPtr->firm_id);
else
defaultLinkStatus = LINK_DD; // if the two firms are of different nations, default link status is both side disabled
//-------- add the link now -------//
if( linked_firm_count < MAX_LINKED_FIRM_FIRM )
{
linked_firm_array[linked_firm_count] = firmRecno;
linked_firm_enable_array[linked_firm_count] = defaultLinkStatus;
linked_firm_count++;
}
else // we must link it as it is linked both sides, if one side is linked and the other is not, that will cause a bug
{
err_here();
}
if( firmPtr->linked_firm_count < MAX_LINKED_FIRM_FIRM )
{
if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker
defaultLinkStatus=LINK_DE;
else if( defaultLinkStatus==LINK_DE )
defaultLinkStatus=LINK_ED;
firmPtr->linked_firm_array[firmPtr->linked_firm_count] = firm_recno;
firmPtr->linked_firm_enable_array[firmPtr->linked_firm_count] = defaultLinkStatus;
firmPtr->linked_firm_count++;
if(firmPtr->firm_ai)
firmPtr->ai_link_checked = 0;
if(firmPtr->firm_id==FIRM_HARBOR)
{
FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
harborPtr->link_checked = 0;
}
}
else
{
err_here();
}
}
//----- build firm-to-town link relationship -------//
linked_town_count = 0;
if( !firmInfo->is_linkable_to_town )
return;
int townRecno;
Town* townPtr;
for( townRecno=town_array.size() ; townRecno>0 ; townRecno-- )
{
if( town_array.is_deleted(townRecno) )
continue;
townPtr = town_array[townRecno];
//------ check if the town is close enough to this firm -------//
if( m.points_distance( townPtr->center_x, townPtr->center_y,
center_x, center_y ) > EFFECTIVE_FIRM_TOWN_DISTANCE )
{
continue;
}
//------ check if both are on the same terrain type ------//
if( (world.get_loc(townPtr->center_x, townPtr->center_y)->is_plateau()==1)
!= (world.get_loc(center_x, center_y)->is_plateau()==1) )
{
continue;
}
//------- determine the default link status ------//
if( townPtr->nation_recno == nation_recno ) // if the two firms are of the same nation, get the default link status which is based on the types of the firms
defaultLinkStatus = LINK_EE;
else
defaultLinkStatus = LINK_DD; // if the two firms are of different nations, default link status is both side disabled
//---------------------------------------------------//
//
// If this is a camp, it can be linked to the town when
// either the town is an independent one or the town
// is not linked to any camps of its own.
//
//---------------------------------------------------//
if( firm_id==FIRM_CAMP )
{
if( townPtr->nation_recno==0 || !townPtr->has_linked_own_camp )
defaultLinkStatus = LINK_EE;
}
//-------- add the link now -------//
if( linked_town_count < MAX_LINKED_FIRM_TOWN )
{
linked_town_array[linked_town_count] = townRecno;
linked_town_enable_array[linked_town_count] = defaultLinkStatus;
linked_town_count++;
}
else
{
err_here();
}
if( townPtr->linked_firm_count < MAX_LINKED_FIRM_TOWN )
{
if( defaultLinkStatus==LINK_ED ) // Reverse the link status for the opposite linker
defaultLinkStatus=LINK_DE;
else if( defaultLinkStatus==LINK_DE )
defaultLinkStatus=LINK_ED;
townPtr->linked_firm_array[townPtr->linked_firm_count] = firm_recno;
townPtr->linked_firm_enable_array[townPtr->linked_firm_count] = defaultLinkStatus;
townPtr->linked_firm_count++;
if(townPtr->ai_town)
townPtr->ai_link_checked = 0;
}
else
{
err_here();
}
}
}
//-------- End of function Firm::setup_link -----------//
//------- Begin of function Firm::release_link ---------//
//
void Firm::release_link()
{
int i;
Firm *firmPtr;
Town *townPtr;
//------ release linked firms ------//
for( i=0 ; irelease_firm_link(firm_recno);
if(firmPtr->firm_ai)
firmPtr->ai_link_checked = 0;
}
//------ release linked towns ------//
for( i=0 ; irelease_firm_link(firm_recno);
if(townPtr->ai_town)
townPtr->ai_link_checked = 0;
}
}
//-------- End of function Firm::release_link -----------//
//------- Begin of function Firm::release_firm_link ---------//
//
void Firm::release_firm_link(int releaseFirmRecno)
{
//-----------------------------------------------------------------------------//
// check the connected firms location and structure if ai_link_checked is true
//-----------------------------------------------------------------------------//
if(firm_ai)
ai_link_checked = 0;
for( int i=0 ; i MAX_LINKED_FIRM_FIRM );
m.del_array_rec( linked_firm_array, linked_firm_count, sizeof(linked_firm_array[0]), i+1 );
m.del_array_rec( linked_firm_enable_array, linked_firm_count, sizeof(linked_firm_enable_array[0]), i+1 );
linked_firm_count--;
return;
}
}
err_here();
}
//------- End of function Firm::release_firm_link ---------//
//------- Begin of function Firm::release_town_link ---------//
//
void Firm::release_town_link(int releaseTownRecno)
{
//-----------------------------------------------------------------------------//
// check the connected firms location and structure if ai_link_checked is true
//-----------------------------------------------------------------------------//
if(firm_ai)
ai_link_checked = 0;
for( int i=0 ; i MAX_LINKED_FIRM_TOWN );
m.del_array_rec( linked_town_array, linked_town_count, sizeof(linked_town_array[0]), i+1 );
m.del_array_rec( linked_town_enable_array, linked_town_count, sizeof(linked_town_enable_array[0]), i+1 );
linked_town_count--;
return;
}
}
err_here();
}
//------- End of function Firm::release_town_link ---------//
//--------- Begin of function Firm::capture_firm --------//
//
// The firm is being captured by another nation.
//
void Firm::capture_firm(int newNationRecno)
{
if( nation_recno == nation_array.player_recno )
news_array.firm_captured(firm_recno, newNationRecno, 0); // 0 - the capturer is not a spy
//-------- if this is an AI firm --------//
if( firm_ai )
ai_firm_captured(newNationRecno);
//------------------------------------------//
//
// If there is an overseer in this firm, then the only
// unit who can capture this firm will be the overseer only,
// so calling its betray() function will capture the whole
// firm already.
//
//------------------------------------------//
if( overseer_recno && unit_array[overseer_recno]->spy_recno )
unit_array[overseer_recno]->spy_change_nation(newNationRecno, COMMAND_AUTO);
else
change_nation(newNationRecno);
}
//--------- End of function Firm::capture_firm --------//
//------- Begin of function Firm::change_nation ---------//
//
void Firm::change_nation(int newNationRecno)
{
if( nation_recno == newNationRecno )
return;
//---------- stop all attack actions to this firm ----------//
unit_array.stop_attack_firm(firm_recno);
rebel_array.stop_attack_firm(firm_recno);
Nation *oldNationPtr = nation_array[nation_recno];
Nation *newNationPtr = nation_array[newNationRecno];
//------ if there is a builder in this firm, change its nation also ----//
if( builder_recno )
{
Unit* unitPtr = unit_array[builder_recno];
unitPtr->change_nation(newNationRecno);
//--- if this is a spy, chance its cloak ----//
if( unitPtr->spy_recno )
spy_array[unitPtr->spy_recno]->cloaked_nation_recno = newNationRecno;
}
//---------- stop all actions attacking this firm --------//
unit_array.stop_attack_firm(firm_recno);
//------ clear defense mode for military camp -----//
if(firm_id==FIRM_CAMP)
((FirmCamp*)this)->clear_defense_mode();
//---- update nation_unit_count_array[] ----//
FirmInfo* firmInfo = firm_res[firm_id];
if( nation_recno )
firmInfo->dec_nation_firm_count(nation_recno);
if( newNationRecno )
firmInfo->inc_nation_firm_count(newNationRecno);
//---- reset should_close_flag -----//
if( firm_ai )
{
if( should_close_flag )
{
oldNationPtr->firm_should_close_array[firm_id-1]--;
should_close_flag = 0;
err_when( oldNationPtr->firm_should_close_array[firm_id-1] < 0 );
}
}
//------- update player_spy_count -------//
spy_array.update_firm_spy_count(firm_recno);
//--- update the cloaked_nation_recno of all spies in the firm ---//
spy_array.change_cloaked_nation(SPY_FIRM, firm_recno, nation_recno, newNationRecno); // check the cloaked nation recno of all spies in the firm
//-----------------------------------------//
if(firm_ai)
oldNationPtr->del_firm_info(firm_id, firm_recno);
//------ update power nation recno ----------//
if( should_set_power )
world.restore_power(loc_x1, loc_y1, loc_x2, loc_y2, 0, firm_recno);
should_set_power = get_should_set_power();
if( should_set_power )
world.set_power(loc_x1, loc_y1, loc_x2, loc_y2, newNationRecno); // set power of the new nation
//------------ update link --------------//
release_link(); // need to update link because firms are only linked to firms of the same nation
nation_recno = newNationRecno;
setup_link();
//---------------------------------------//
firm_ai = nation_array[nation_recno]->is_ai();
if(firm_ai)
newNationPtr->add_firm_info(firm_id, firm_recno);
//--- if a nation set up a town in a location that the player has explored, contact between the nation and the player is established ---//
establish_contact_with_player();
//---- reset the action mode of all spies in this town ----//
spy_array.set_action_mode( SPY_FIRM, firm_recno, SPY_IDLE ); // we need to reset it. e.g. when we have captured an enemy town, SPY_SOW_DISSENT action must be reset to SPY_IDLE
//-- refresh display if this firm is currently selected --//
if( firm_array.selected_recno == firm_recno )
info.disp();
}
//-------- End of function Firm::change_nation ---------//
//------- Begin of function Firm::toggle_firm_link ---------//
//
// Toggle the firm link of the current firm.
//
// linkId - id. of the link
// toggleFlag - 1-enable, 0-disable
// [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD)
// if this is -1, the only one side will be set even though the nation recno of the firm and town are the same
// (default: 0)
//
void Firm::toggle_firm_link(int linkId, int toggleFlag, char remoteAction, int setBoth)
{
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_TOGGLE_LINK_FIRM, 3*sizeof(short));
shortPtr[0] = firm_recno;
shortPtr[1] = linkId;
shortPtr[2] = toggleFlag;
return;
}
int linkedNationRecno = firm_array[linked_firm_array[linkId-1]]->nation_recno;
int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link
linkedNationRecno == 0 ||
nation_recno == 0;
if( toggleFlag )
{
if( (sameNation && setBoth==0) || setBoth==1 )
linked_firm_enable_array[linkId-1] = LINK_EE;
else
linked_firm_enable_array[linkId-1] |= LINK_ED;
}
else
{
if( (sameNation && setBoth==0) || setBoth==1 )
linked_firm_enable_array[linkId-1] = LINK_DD;
else
linked_firm_enable_array[linkId-1] &= ~LINK_ED;
}
//---------- if this firm is harbor, set FirmHarbor's parameter link_checked to 0
if(firm_id == FIRM_HARBOR)
{
FirmHarbor *harborPtr = (FirmHarbor*) this;
harborPtr->link_checked = 0;
}
//------ set the linked flag of the opposite firm -----//
Firm* firmPtr = firm_array[ linked_firm_array[linkId-1] ];
//---------- if firm is harbor, set FirmHarbor's parameter link_checked to 0
if(firmPtr->firm_id==FIRM_HARBOR)
{
FirmHarbor *harborPtr = (FirmHarbor*) firmPtr;
harborPtr->link_checked = 0;
}
int i;
for( i=0 ; ilinked_firm_count ; i++ )
{
if( firmPtr->linked_firm_array[i] == firm_recno )
{
if( toggleFlag )
{
if( (sameNation && setBoth==0) || setBoth==1 )
firmPtr->linked_firm_enable_array[i] = LINK_EE;
else
firmPtr->linked_firm_enable_array[i] |= LINK_DE;
}
else
{
if( (sameNation && setBoth==0) || setBoth==1 )
firmPtr->linked_firm_enable_array[i] = LINK_DD;
else
firmPtr->linked_firm_enable_array[i] &= ~LINK_DE;
}
break;
}
}
}
//-------- End of function Firm::toggle_firm_link ---------//
//------- Begin of function Firm::toggle_town_link ---------//
//
// Toggle the town link of the current firm.
//
// linkId - id. of the link
// toggleFlag - 1-enable, 0-disable
// [int] setBoth - if this is 1, it will set the link to either LINK_EE or LINK_DD (and no LINK_ED or LINK_DD)
// if this is -1, the only one side will be set even though the nation recno of the firm and town are the same
// (default: 0)
//
void Firm::toggle_town_link(int linkId, int toggleFlag, char remoteAction, int setBoth)
{
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_TOGGLE_LINK_TOWN, 3*sizeof(short));
shortPtr[0] = firm_recno;
shortPtr[1] = linkId;
shortPtr[2] = toggleFlag;
return;
}
int linkedNationRecno = town_array[linked_town_array[linkId-1]]->nation_recno;
int sameNation = linkedNationRecno == nation_recno || // if one of the linked end is an indepdendent firm/nation, consider this link as a single nation link
firm_id==FIRM_BASE; // town cannot decide whether it wants to link to Command Base or not, it is the Command Base which influences the town.
if( toggleFlag )
{
if( (sameNation && setBoth==0) || setBoth==1 )
linked_town_enable_array[linkId-1] = LINK_EE;
else
linked_town_enable_array[linkId-1] |= LINK_ED;
}
else
{
if( (sameNation && setBoth==0) || setBoth==1 )
linked_town_enable_array[linkId-1] = LINK_DD;
else
linked_town_enable_array[linkId-1] &= ~LINK_ED;
}
//------ set the linked flag of the opposite town -----//
Town* townPtr = town_array[ linked_town_array[linkId-1] ];
int i;
for( i=0 ; ilinked_firm_count ; i++ )
{
if( townPtr->linked_firm_array[i] == firm_recno )
{
if( toggleFlag )
{
if( (sameNation && setBoth==0) || setBoth==1 )
townPtr->linked_firm_enable_array[i] = LINK_EE;
else
townPtr->linked_firm_enable_array[i] |= LINK_DE;
}
else
{
if( (sameNation && setBoth==0) || setBoth==1 )
townPtr->linked_firm_enable_array[i] = LINK_DD;
else
townPtr->linked_firm_enable_array[i] &= ~LINK_DE;
}
break;
}
}
//-------- update the town's influence --------//
if( townPtr->nation_recno==0 )
townPtr->update_target_resistance();
//--- redistribute demand if a link to market place has been toggled ---//
if( firm_id == FIRM_MARKET )
town_array.distribute_demand();
}
//-------- End of function Firm::toggle_town_link ---------//
//------- Begin of function Firm::auto_defense -----------//
void Firm::auto_defense(short targetRecno)
{
//--------------------------------------------------------//
// if the firm_id is FIRM_CAMP, send the units to defense
// the firm
//--------------------------------------------------------//
if(firm_id == FIRM_CAMP)
{
FirmCamp *campPtr = cast_to_FirmCamp();
campPtr->defend_target_recno = targetRecno;
campPtr->defense(targetRecno);
}
Town *townPtr;
for(int i=linked_town_count-1; i>=0; i--)
{
if(!linked_town_array[i] || town_array.is_deleted(linked_town_array[i]))
continue;
townPtr = town_array[linked_town_array[i]];
//-------------------------------------------------------//
// find whether military camp is linked to this town. If
// so, defense for this firm
//-------------------------------------------------------//
if(townPtr->nation_recno == nation_recno)
townPtr->auto_defense(targetRecno);
//-------------------------------------------------------//
// some linked town may be deleted after calling auto_defense().
// Also, the data in the linked_town_array may also be changed.
//-------------------------------------------------------//
if(i>linked_town_count)
i = linked_town_count;
}
}
//--------- End of function Firm::auto_defense -----------//
//------- Begin of function Worker::Worker -----------//
//
Worker::Worker()
{
memset( this, 0, sizeof(Worker) );
}
//--------- End of function Worker::Worker -----------//
//------- Begin of function Worker::max_hit_points -----------//
//
short Worker::max_hit_points()
{
err_when( combat_level <= 0 );
err_when( combat_level > 100 );
return (int) unit_res[unit_id]->hit_points * combat_level / 100;
}
//--------- End of function Worker::max_hit_points -----------//
//--------- Begin of function Worker::max_attack_range ---------//
int Worker::max_attack_range()
{
int maxRange=0;
AttackInfo *attackInfo = unit_res.get_attack_info(unit_res[unit_id]->first_attack);
int attackCount = unit_res[unit_id]->attack_count;
for(int i=0; i= attackInfo->combat_level &&
attackInfo->attack_range>maxRange)
maxRange = attackInfo->attack_range;
}
return maxRange;
}
//--------- End of function Worker::max_attack_range -----------//
//--------- Begin of function Worker::is_nation ---------//
//
// Whether this worker belongs to the specific nation.
//
// firmRecno - the recno of the firm the worker works in
// nationRecno - the recno of th nation to check against.
//
int Worker::is_nation(int firmRecno, int nationRecno)
{
if( spy_recno && spy_array[spy_recno]->true_nation_recno == nationRecno )
return 1;
if( town_recno )
return town_array[town_recno]->nation_recno == nationRecno;
else
return firm_array[firmRecno]->nation_recno == nationRecno;
}
//----------- End of function Worker::is_nation ---------//
//-------- Begin of function Firm::can_assign_capture ------//
//
// Return whether new units assigned to this firm can capture
// this firm.
//
int Firm::can_assign_capture()
{
return (overseer_recno==0 && worker_count==0);
}
//----------- End of function Worker::can_assign_capture ---------//
//-------- Begin of function Firm::should_show_info ------//
//
// Whether information of this firm should be shown.
//
int Firm::should_show_info()
{
if( config.show_ai_info || nation_recno==nation_array.player_recno ||
player_spy_count > 0 )
{
return 1;
}
//------ if the builder is a spy of the player ------//
if( builder_recno )
{
if( unit_array[builder_recno]->true_nation_recno() == nation_array.player_recno )
return 1;
}
//----- if any of the workers belong to the player, show the info of this firm -----//
Worker* workerPtr = worker_array;
for( int i=0 ; iis_nation(firm_recno, nation_array.player_recno) )
return 1;
}
//---- if there is a phoenix of the player over this firm ----//
if( nation_array.player_recno && (~nation_array)->revealed_by_phoenix(loc_x1, loc_y1) )
return 1;
return 0;
}
//---------- End of function Firm::should_show_info --------//
//-------- Begin of function Firm::majority_race ------//
//
char Firm::majority_race()
{
//--- if there is a overseer, return the overseer's race ---//
if( overseer_recno )
return unit_array[overseer_recno]->race_id;
if( worker_count==0 )
return 0;
//----- count the no. people in each race ------//
char raceCountArray[MAX_RACE];
memset( raceCountArray, 0, sizeof(raceCountArray) );
int i;
for( i=0 ; i mostRaceCount )
{
mostRaceCount = raceCountArray[i];
mostRaceId = i+1;
}
}
return mostRaceId;
}
//---------- End of function Firm::majority_race --------//
//---------- Begin of function Worker::small_icon_ptr --------//
char* Worker::small_icon_ptr()
{
// ###### begin Gilbert 17/10 ########//
return unit_res[unit_id]->get_small_icon_ptr(rank_id);
// ###### end Gilbert 17/10 ########//
}
//---------- End of function Worker::small_icon_ptr --------//
//---------- Begin of function Worker::change_loyalty --------//
void Worker::change_loyalty(int loyaltyChange)
{
if( town_recno ) // for those live in town, their loyalty are based on town people loyalty.
return;
int newLoyalty = worker_loyalty + loyaltyChange;
newLoyalty = min( 100, newLoyalty );
worker_loyalty = max( 0, newLoyalty );
}
//---------- End of function Worker::change_loyalty --------//
//---------- Begin of function Worker::change_hit_points --------//
void Worker::change_hit_points(int changePoints)
{
err_when( town_recno ); // for those live in town, their loyalty are based on town people loyalty.
int newHitPoints = hit_points + changePoints;
int maxHitPoints = max_hit_points();
newHitPoints = min( maxHitPoints, newHitPoints );
hit_points = max( 0, newHitPoints );
}
//---------- End of function Worker::change_hit_points --------//
//-------- Begin of function Firm::is_worker_full ------//
//
int Firm::is_worker_full()
{
return worker_count == MAX_WORKER;
}
//----------- End of function Firm::is_worker_full ---------//
//--------- Begin of function Firm::reward ---------//
//
// Only military camp has the "reward" option and not the other firms also
// because workers in other firms live in the towns and their loyalty
// are based on the town they live. Military camp is not linked to a town.
//
// workerId - 0 - commander, >0 - id. of the soldier
// remoteAction - either COMMAND_PLAYER or COMMAND_REMOTE
//
void Firm::reward(int workerId, int remoteAction)
{
if( remoteAction==COMMAND_PLAYER && remote.is_enable() )
{
if( !remoteAction && remote.is_enable() )
{
// packet structure :
short *shortPtr = (short *)remote.new_send_queue_msg(MSG_FIRM_REWARD, 2*sizeof(short) );
*shortPtr = firm_recno;
shortPtr[1] = workerId;
}
}
else
{
if( workerId == 0 )
{
if( overseer_recno )
unit_array[overseer_recno]->reward(nation_recno);
}
else
{
err_when( workerId < 1 || workerId > worker_count );
worker_array[workerId-1].change_loyalty( REWARD_LOYALTY_INCREASE );
nation_array[nation_recno]->add_expense( EXPENSE_REWARD_UNIT, (float)REWARD_COST);
}
}
}
//----------- End of function Firm::reward -----------//