/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight Software Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//Filename : OF_INN.CPP
//Description : Firm Military Inn
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//------------- Define coordinations -----------//
enum { HIRE_BROWSE_X1 = INFO_X1,
HIRE_BROWSE_Y1 = INFO_Y1+52,
HIRE_BROWSE_X2 = INFO_X2,
HIRE_BROWSE_Y2 = HIRE_BROWSE_Y1+144
};
enum { HIRE_DET_X1 = INFO_X1,
HIRE_DET_Y1 = HIRE_BROWSE_Y2+5,
HIRE_DET_X2 = INFO_X2,
HIRE_DET_Y2 = HIRE_DET_Y1+54
};
//----------- Define static variables ----------//
static VBrowseIF browse_hire;
static Button3D button_hire;
static int last_hire_count;
static FirmInn* firm_inn_ptr;
//----------- Define static functions ----------//
static void put_hire_rec(int recNo, int x, int y, int refreshFlag);
//--------- Begin of function FirmInn::FirmInn ---------//
//
FirmInn::FirmInn()
{
}
//----------- End of function FirmInn::FirmInn -----------//
//--------- Begin of function FirmInn::~FirmInn ---------//
//
FirmInn::~FirmInn()
{
}
//----------- End of function FirmInn::~FirmInn -----------//
//--------- Begin of function FirmInn::init_derived ---------//
//
void FirmInn::init_derived()
{
inn_unit_count = 0;
next_skill_id = m.random(MAX_TRAINABLE_SKILL)+1;
}
//----------- End of function FirmInn::init_derived -----------//
//--------- Begin of function FirmInn::assign_unit ---------//
//
void FirmInn::assign_unit(int unitRecno)
{
//------- if this is a construction worker -------//
if( unit_array[unitRecno]->skill.skill_id == SKILL_CONSTRUCTION )
{
set_builder(unitRecno);
return;
}
/*
//--- can only assign if the unit is a spy cloaked into this firm's nation color ---//
if( !unitPtr->spy_recno || unitPtr->nation_recno != nation_recno )
return;
//---------------------------------------------//
if( inn_unit_count == MAX_INN_UNIT )
return;
err_when( inn_unit_count > MAX_INN_UNIT );
err_when( !unitRecno );
Unit* unitPtr = unit_array[unitRecno];
//--------- add the InnUnit --------//
InnUnit *innUnit = inn_unit_array+inn_unit_count;
inn_unit_count++;
//--------- set InnUnit vars -----------------//
innUnit->unit_id = unitPtr->unit_id;
innUnit->skill = unitPtr->skill;
innUnit->spy_recno = unitPtr->spy_recno;
innUnit->set_hire_cost();
unitPtr->deinit_sprite();
*/
}
//----------- End of function FirmInn::assign_unit -----------//
//--------- Begin of function FirmInn::put_info ---------//
//
void FirmInn::put_info(int refreshFlag)
{
firm_inn_ptr = this;
disp_basic_info(INFO_Y1, refreshFlag);
if( !should_show_info() )
return;
//----------- display browser -----------//
if( refreshFlag == INFO_REPAINT )
{
browse_hire.init( HIRE_BROWSE_X1, HIRE_BROWSE_Y1, HIRE_BROWSE_X2, HIRE_BROWSE_Y2,
0, 25, inn_unit_count, put_hire_rec );
browse_hire.open(1);
}
else
{
if( last_hire_count != inn_unit_count )
{
if( last_hire_count==0 || inn_unit_count==0 ) // repaint the whole area as the detail area needs to disappear
{
last_hire_count = inn_unit_count;
info.disp();
return;
}
last_hire_count = inn_unit_count;
browse_hire.refresh(-1, inn_unit_count);
if( last_hire_count==0 || inn_unit_count==0 )
refreshFlag = INFO_REPAINT;
}
else
browse_hire.update(); // update only
}
last_hire_count = inn_unit_count;
put_det(refreshFlag);
//---------- display spy button ----------//
disp_spy_button(INFO_X1+BUTTON_ACTION_WIDTH, HIRE_DET_Y2+4, refreshFlag);
}
//----------- End of function FirmInn::put_info -----------//
//--------- Begin of function FirmInn::detect_info ---------//
//
void FirmInn::detect_info()
{
firm_inn_ptr = this;
if( detect_basic_info() )
return;
//-------- detect spy button ----------//
if( !own_firm() )
{
detect_spy_button();
return;
}
//-------------------------------------//
if( browse_hire.detect() )
{
put_det(INFO_UPDATE);
}
if( button_hire.detect() && inn_unit_count > 0 )
{
// ###### begin Gilbert 31/7 #######//
se_res.far_sound(center_x, center_y, 1, 'S',
unit_res[inn_unit_array[browse_hire.recno()-1].unit_id]->sprite_id,
"RDY" );
// ###### end Gilbert 31/7 #######//
if(remote.is_enable())
{
// packet structure : ,
short *shortPtr=(short *)remote.new_send_queue_msg(MSG_F_INN_HIRE, 3*sizeof(short));
shortPtr[0] = firm_recno;
shortPtr[1] = browse_hire.recno();
shortPtr[2] = nation_recno;
}
else
{
hire(browse_hire.recno());
}
}
}
//----------- End of function FirmInn::detect_info -----------//
//--------- Begin of function FirmInn::hire ---------//
//
int FirmInn::hire(short recNo)
{
err_when( recNo < 1 );
if( recNo > inn_unit_count ) // this may happen in a multiplayer game
return 0;
//--------- first check if you have enough money to hire ------//
InnUnit* innUnit;
Nation* nationPtr = nation_array[nation_recno];
innUnit = inn_unit_array+recNo-1;
if( nationPtr->cash < innUnit->hire_cost )
return 0;
//---------- add the unit now -----------//
int unitRecno = create_unit( innUnit->unit_id );
if(!unitRecno)
return 0; // no space for creating the unit
nationPtr->add_expense(EXPENSE_HIRE_UNIT, innUnit->hire_cost);
//-------- set skills of the unit --------//
Unit* unitPtr = unit_array[unitRecno];
memcpy( &(unitPtr->skill), &(innUnit->skill), sizeof(Skill) );
err_when( innUnit->skill.combat_level<=0 || innUnit->skill.combat_level>100 );
unitPtr->set_combat_level( innUnit->skill.combat_level );
//-------- if the unit's skill is spying -----//
if( unitPtr->skill.skill_id == SKILL_SPYING )
{
unitPtr->spy_recno = spy_array.add_spy(unitRecno, unitPtr->skill.skill_level);
unitPtr->skill.skill_id = 0; // reset its primary skill, its spying skill has been recorded in spy_array
}
//----------------------------------------//
//
// Loyalty of the hired unit
//
// = 30 + the nation's reputation / 2 + 30 if racially homogenous
//
//----------------------------------------//
int unitLoyalty = 30 + (int)nationPtr->reputation/2;
if( race_res.is_same_race(unitPtr->race_id, nationPtr->race_id) )
unitLoyalty += 20;
unitLoyalty = max( 40, unitLoyalty );
unitLoyalty = min( 100, unitLoyalty );
if( unitPtr->spy_recno )
spy_array[unitPtr->spy_recno]->spy_loyalty = unitLoyalty;
else
unitPtr->loyalty = unitLoyalty;
//---- remove the record from the hire list ----//
del_inn_unit(recNo);
if( firm_recno == firm_array.selected_recno &&
nation_recno == nation_array.player_recno )
{
put_info(INFO_UPDATE);
}
return unitRecno;
}
//----------- End of function FirmInn::hire -----------//
//--------- Begin of function FirmInn::put_det ---------//
//
void FirmInn::put_det(int refreshFlag)
{
if( browse_hire.none_record )
{
button_hire.reset();
return;
}
//--------- display details ----------//
InnUnit* innUnit = inn_unit_array+browse_hire.recno()-1;
disp_unit_info(HIRE_DET_Y1, innUnit, refreshFlag );
//------- paint buttons --------//
if( own_firm() )
{
if( refreshFlag == INFO_REPAINT )
{
button_hire.paint( HIRE_DET_X1, HIRE_DET_Y2+4, 'A', "HIREUNIT" );
}
else
{
if( inn_unit_count > 0 &&
(~nation_array)->cash >= inn_unit_array[browse_hire.recno()-1].hire_cost )
{
button_hire.enable();
}
else
{
button_hire.disable();
}
}
}
}
//----------- End of function FirmInn::put_det -----------//
//--------- Begin of function FirmInn::disp_unit_info ---------//
//
// Display the skill information of the people in the town.
//
// dispY1 - the top y coordination of the info area
// hireInfoPtr - pointer to a HireInfo structure
// refreshFlag - refresh flag
//
void FirmInn::disp_unit_info(int dispY1, InnUnit* hireInfoPtr, int refreshFlag)
{
Skill* skillPtr = &(hireInfoPtr->skill);
//---------------- paint the panel --------------//
if( refreshFlag == INFO_REPAINT )
{
vga.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+54 );
}
//------ display population composition of this resident town -----//
int x=INFO_X1+4, y=dispY1+4, x1=x+100;
String str;
font_san.field( x, y, "Combat", x1, skillPtr->combat_level, 1, INFO_X2-10, refreshFlag );
if( refreshFlag == INFO_REPAINT )
{
font_san.field( x, y+16, skillPtr->skill_des(), x1, skillPtr->skill_level , 1, INFO_X2-10, refreshFlag );
}
else
{
font_san.use_max_height();
font_san.put( x+2, y+18, skillPtr->skill_des(), 1, x1-2 );
font_san.use_std_height();
font_san.update_field( x1, y+16, skillPtr->skill_level, 1, INFO_X2-10);
}
font_san.field( x, y+32, "Hiring Cost", x1, hireInfoPtr->hire_cost, 2, INFO_X2-10, refreshFlag);
}
//----------- End of function FirmInn::disp_unit_info -----------//
//-------- Begin of static function put_hire_rec --------//
//
static void put_hire_rec(int recNo, int x, int y, int refreshFlag)
{
InnUnit* innUnit = firm_inn_ptr->inn_unit_array+recNo-1;
//-------- display unit icon -------//
vga_front.d3_panel_down(x+1, y+1, x+UNIT_SMALL_ICON_WIDTH+4, y+UNIT_SMALL_ICON_HEIGHT+4, 2, 0 );
// ##### begin Gilbert 17/10 #######//
vga_front.put_bitmap(x+3, y+3, unit_res[innUnit->unit_id]->get_small_icon_ptr(RANK_SOLDIER) );
// ##### end Gilbert 17/10 #######//
//--------- set help parameters --------//
if( mouse.in_area(x+1, y+1, x+UNIT_SMALL_ICON_WIDTH+4, y+UNIT_SMALL_ICON_HEIGHT+4) )
help.set_unit_help( innUnit->unit_id, 0, x+1, y+1, x+UNIT_SMALL_ICON_WIDTH+4, y+UNIT_SMALL_ICON_HEIGHT+4 );
//---------- display info ----------//
y+=6;
font_san.use_max_height();
if( innUnit->skill.skill_level > 0 )
{
font_san.put( x+32 , y, innUnit->skill.skill_des(1), 1, x+122 ); // 1-use short words
font_san.put( x+116, y, innUnit->skill.skill_level, 1, x+146 );
}
else
{
font_san.put( x+32 , y, "Combat", 1, x+122 ); // 1-use short words
font_san.put( x+116, y, innUnit->skill.combat_level, 1, x+146 );
}
font_san.use_std_height();
font_san.put( x+140, y, m.format(innUnit->hire_cost,2), 1, x+browse_hire.rec_width-3 );
}
//----------- End of static function put_hire_rec -----------//
//--------- Begin of function FirmInn::next_day ---------//
//
void FirmInn::next_day()
{
//----------- run next_day() of the base class -------------//
Firm::next_day();
//------------ update the hire list ------------//
int updateInterveal = 10 + info.year_passed*2; // there will be less and less units to hire as the game passes
if( info.game_date % updateInterveal == firm_recno % updateInterveal )
update_add_hire_list();
if( info.game_date % 10 == firm_recno % 10 )
update_del_hire_list();
}
//----------- End of function FirmInn::next_day -----------//
//---------- Begin of function FirmInn::update_add_hire_list --------//
//
void FirmInn::update_add_hire_list()
{
//-------- new units come by --------//
if( inn_unit_count < MAX_INN_UNIT )
{
if( should_add_inn_unit() )
{
int unitId = race_res[m.random(MAX_RACE)+1]->basic_unit_id;
if( unitId )
add_inn_unit(unitId);
}
}
}
//----------- End of function FirmInn::update_add_hire_list ---------//
//--------- Begin of function FirmInn::update_del_hire_list --------//
//
void FirmInn::update_del_hire_list()
{
//------- existing units leave -------//
for( int i=inn_unit_count ; i>0 && inn_unit_count>0 ; i-- )
{
if( !inn_unit_array[i-1].spy_recno && --inn_unit_array[i-1].stay_count==0 )
{
del_inn_unit(i);
if( firm_recno == firm_array.selected_recno )
{
if( browse_hire.recno() > i && browse_hire.recno() > 1 )
browse_hire.refresh( browse_hire.recno()-1, inn_unit_count );
}
}
}
}
//--------- End of function FirmInn::update_del_hire_list ---------//
//-------- Begin of function FirmInn::should_add_inn_unit --------//
//
int FirmInn::should_add_inn_unit()
{
#define MAX_INN_UNIT_PER_REGION 10 // maximum no. of inn units in any single region
FirmInn* firmInn;
int totalInnUnit = inn_unit_count;
for(int i=0; ifirm_id != FIRM_INN );
totalInnUnit += firmInn->inn_unit_count;
}
return totalInnUnit < MAX_INN_UNIT_PER_REGION;
}
//--------- End of function FirmInn::should_add_inn_unit ---------//
//--------- Begin of function FirmInn::add_inn_unit ---------//
void FirmInn::add_inn_unit(int unitId)
{
err_when( inn_unit_count >= MAX_INN_UNIT );
InnUnit *innUnit = inn_unit_array+inn_unit_count;
inn_unit_count++;
innUnit->unit_id = unitId;
//--------- set the skill now -----------------//
char skillId = (char) next_skill_id;
if( ++next_skill_id > MAX_TRAINABLE_SKILL )
next_skill_id = 1;
innUnit->skill.skill_id = skillId;
if( skillId > 0 )
innUnit->skill.skill_level = 30+m.random(70);
else
innUnit->skill.skill_level = 0;
if( skillId==0 || skillId==SKILL_LEADING )
innUnit->skill.combat_level = 30+m.random(70);
else
innUnit->skill.combat_level = 10;
innUnit->set_hire_cost();
innUnit->stay_count = 5 + m.random(5);
innUnit->spy_recno = 0;
}
//----------- End of function FirmInn::add_inn_unit -----------//
//--------- Begin of function InnUnit::set_hire_cost ---------//
//
void InnUnit::set_hire_cost()
{
hire_cost = skill.combat_level + (int)skill.skill_level*2;
if( skill.skill_id==SKILL_LEADING ) // the cost of a leader unit is higher
{
hire_cost += skill.skill_level*2;
for( int i=10 ; i<=100 ; i+=20 ) // increase the hiring cost with bigger steps when the skill level gets higher
{
if( i > skill.skill_level )
hire_cost += i/5;
}
}
else if( skill.skill_id==SKILL_SPYING ) // the cost of a leader unit is higher
{
hire_cost += skill.skill_level;
}
hire_cost *= 2;
}
//----------- End of function InnUnit::set_hire_cost -----------//
//--------- Begin of function FirmInn::del_inn_unit ---------//
void FirmInn::del_inn_unit(int recNo)
{
err_when( recNo<1 || recNo>MAX_INN_UNIT );
err_when( inn_unit_count < 1 );
err_when( inn_unit_count > MAX_INN_UNIT );
m.del_array_rec(inn_unit_array, inn_unit_count, sizeof(InnUnit), recNo);
inn_unit_count--;
}
//----------- End of function FirmInn::del_inn_unit -----------//
//--------- Begin of function FirmInn::auto_defense ---------//
void FirmInn::auto_defense(short targetRecno)
{
//---------- the area to check -----------//
int xLoc1 = center_x - EFFECTIVE_FIRM_TOWN_DISTANCE;
int yLoc1 = center_y - EFFECTIVE_FIRM_TOWN_DISTANCE;
int xLoc2 = center_x + EFFECTIVE_FIRM_TOWN_DISTANCE;
int yLoc2 = center_y + EFFECTIVE_FIRM_TOWN_DISTANCE;
//----------- boundary checking ----------//
if(xLoc1<0) xLoc1 = 0;
if(yLoc1<0) yLoc1 = 0;
if(xLoc2>=MAX_WORLD_X_LOC) xLoc2 = MAX_WORLD_X_LOC-1;
if(yLoc2>=MAX_WORLD_Y_LOC) yLoc2 = MAX_WORLD_Y_LOC-1;
int skipWidthDist = STD_TOWN_LOC_WIDTH;
int skipHeightDist = STD_TOWN_LOC_HEIGHT;
int xEnd, yEnd, xLimit, yLimit;
int i, j, dist;
Location *locPtr;
Town *townPtr;
//--------------------------------------------------//
// check for our town in the effective area
//--------------------------------------------------//
xLimit = xLoc2+skipWidthDist-1;
yLimit = yLoc2+skipHeightDist-1;
for(xEnd=0, i=xLoc1; i<=xLimit && !xEnd; i+=skipWidthDist)
{
if(i>=xLoc2)
{
xEnd++; // final
i = xLoc2;
}
for(yEnd=0, j=yLoc1; j<=yLimit && !yEnd; j+=skipHeightDist)
{
if(j>=yLoc2)
{
yEnd++; // final
j = yLoc2;
}
err_when(ixLoc2 || jyLoc2);
locPtr = world.get_loc(i, j);
if(!locPtr->is_town())
continue;
err_when(!locPtr->town_recno() || town_array.is_deleted(locPtr->town_recno()));
townPtr = town_array[locPtr->town_recno()];
if(townPtr->nation_recno!=nation_recno)
continue;
dist = m.points_distance(center_x, center_y, townPtr->center_x, townPtr->center_y);
if(dist <= EFFECTIVE_FIRM_TOWN_DISTANCE)
townPtr->auto_defense(targetRecno);
}
}
}
//----------- End of function FirmInn::auto_defense -----------//