/*
* 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 : OSITE.CPP
//Description : Object Site
#include
#include
#include
#include
#include
#include
#include
#include
#include
//-------------- Define constant -----------//
#define EXIST_RAW_RESERVE_QTY (MAX_RAW_RESERVE_QTY / 20) // only sites with reserve qty >= 5% of MAX_RAW_RESERVE_QTY are counted as raw sites
//--------- Begin of function SiteArray::SiteArray -------//
SiteArray::SiteArray() : DynArrayB(sizeof(Site), 50, DEFAULT_REUSE_INTERVAL_DAYS)
{
}
//----------- End of function SiteArray::SiteArray -------//
//--------- Begin of function SiteArray::~SiteArray -------//
SiteArray::~SiteArray()
{
deinit();
}
//----------- End of function SiteArray::~SiteArray -------//
//--------- Begin of function SiteArray::init -------//
void SiteArray::init()
{
untapped_raw_count = 0;
std_raw_site_count = 0;
}
//----------- End of function SiteArray::init -------//
//--------- Begin of function SiteArray::deinit -------//
void SiteArray::deinit()
{
if( size()==0 )
return;
zap(); // zap the DynArrayB
untapped_raw_count = 0;
}
//----------- End of function SiteArray::deinit -------//
//--------- Begin of function SiteArray::add_site ---------//
//
// Add a raw item to the site array
//
// Return : 1 - the raw is added
// 0 - duplicated, not added
//
int SiteArray::add_site(int xLoc, int yLoc, int siteType, int objectId, int reserveQty)
{
//----- linkin the raw and update raw attribute ----//
Site site;
linkin(&site);
Site* sitePtr = (Site*) get(recno());
sitePtr->init(recno(), siteType, xLoc, yLoc);
sitePtr->object_id = objectId;
sitePtr->reserve_qty = reserveQty;
switch( siteType )
{
case SITE_RAW:
untapped_raw_count++;
break;
case SITE_SCROLL:
scroll_count++;
break;
case SITE_GOLD_COIN:
gold_coin_count++;
break;
}
return 1;
}
//----------- End of function SiteArray::add_site ----------//
//--------- Begin of function SiteArray::del_site ----------//
//
// Delete a specified site.
//
// siteRecno = the record no. of the site to be deleted
//
void SiteArray::del_site(int siteRecno)
{
err_if( siteRecno == 0 )
err_now( "SiteArray::del_site" );
Site* sitePtr = site_array[siteRecno];
switch( sitePtr->site_type )
{
case SITE_RAW:
untapped_raw_count--;
break;
case SITE_SCROLL:
scroll_count--;
break;
case SITE_GOLD_COIN:
gold_coin_count--;
break;
}
//-------------------------------//
sitePtr->deinit();
linkout(siteRecno);
if( siteRecno == site_array.selected_recno )
site_array.selected_recno = 0;
}
//--------- End of function SiteArray::del_site ----------//
//--------- Begin of function SiteArray::generate_raw_site ----------//
//
// Generate raw sites. This function is both called at the beginning
// of a game and when existing raw sites are being used up.
//
// [int] rawGenCount - no. of raw sites to be generated.
// (if this is not given, it will use the existing std_raw_site_count)
//
void SiteArray::generate_raw_site(int rawGenCount)
{
if( rawGenCount )
std_raw_site_count = rawGenCount; // use this number for determing whether new sites should emerge in the future
#define MAX_RAW_REGION 3 // maximum no. of regions that has raw sites
#define SMALLEST_RAW_REGION 50 // only put raw on the region if its size is larger than this
#define REGION_SIZE_PER_RAW 100
//----- count the no. of existing raw sites -------//
Site* sitePtr;
int existRawSiteCount=0;
int i;
for( i=size() ; i>0 ; i-- )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( sitePtr->site_type == SITE_RAW &&
sitePtr->reserve_qty >= EXIST_RAW_RESERVE_QTY )
{
existRawSiteCount++;
}
}
if( existRawSiteCount >= std_raw_site_count )
return;
//----- check which regions are valid for raw sites -----//
int regionCount = min( MAX_RAW_REGION, region_array.region_info_count );
int validRegionCount, totalValidSize=0;
RegionInfo* regionInfo;
for( validRegionCount=0 ; validRegionCountregion_type != REGION_LAND )
continue;
if( regionInfo->region_size < SMALLEST_RAW_REGION )
break;
totalValidSize += regionInfo->region_size;
}
if( validRegionCount==0 ) // valid regions are those that are big enough to put raw sites
return;
//----- count the no. of existing raw sites in each ragion ------//
int regionId;
char regionRawCountArray[MAX_REGION];
memset( regionRawCountArray, 0, sizeof(regionRawCountArray) );
for( i=size() ; i>0 ; i-- )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( sitePtr->site_type == SITE_RAW &&
sitePtr->reserve_qty >= EXIST_RAW_RESERVE_QTY )
{
regionId = world.get_region_id(sitePtr->map_x_loc, sitePtr->map_y_loc);
regionRawCountArray[regionId-1]++;
}
}
//--------- generate raw sites now ----------//
int avgValidSize = min( 10000, totalValidSize / std_raw_site_count );
int j, createCount;
err_when( validRegionCount > region_array.region_info_count || validRegionCount > MAX_RAW_REGION );
for( int k=0 ; k<10 ; k++ ) // one loop may not be enough to generate all raw sites, have more loops to make sure all are generated
{
for( i=0 ; iregion_type != REGION_LAND )
continue;
if( regionInfo->region_size < SMALLEST_RAW_REGION )
break;
createCount = regionInfo->region_size / avgValidSize;
createCount = max(1, createCount);
//--------- create now --------//
for( j=regionRawCountArray[regionInfo->region_id-1] ; jregion_id) )
{
if( ++existRawSiteCount == std_raw_site_count )
return;
}
}
}
}
}
//--------- End of function SiteArray::generate_raw_site ----------//
//--------- Begin of function SiteArray::create_raw_site ----------//
//
// regionId - if this parameter is given, the raw site
// will be built on this region.
// [int] townRecno - if this parameter is given, the raw site
// will be built near this town.
//
int SiteArray::create_raw_site(int regionId, int townRecno)
{
//-------- count the no. of each raw material -------//
Site* sitePtr;
short rawCountArray[MAX_RAW];
memset( rawCountArray, 0, sizeof(rawCountArray) );
int i;
for( i=size(); i>0 ; i-- )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( sitePtr->site_type == SITE_RAW )
{
err_when( sitePtr->object_id < 1 || sitePtr->object_id > MAX_RAW );
rawCountArray[ sitePtr->object_id-1 ]++;
}
}
//---- find the minimum raw count ----//
int minCount=0xFFFF;
for( i=0 ; i MAX_RAW )
rawId = 1;
if( rawCountArray[rawId-1] == minCount ) // don't use this raw type unless it is one of the less available ones.
break;
}
//--------- create the raw site now ------//
int locX1, locY1, locX2, locY2;
int maxTries;
if( townRecno )
{
#define MAX_TOWN_SITE_DISTANCE 10
Town* townPtr = town_array[townRecno];
locX1 = townPtr->center_x - MAX_TOWN_SITE_DISTANCE;
locX2 = townPtr->center_x + MAX_TOWN_SITE_DISTANCE;
locY1 = townPtr->center_y - MAX_TOWN_SITE_DISTANCE;
locY2 = townPtr->center_y + MAX_TOWN_SITE_DISTANCE;
if(locX1<0)
locX1 = 0;
else if(locX2>=MAX_WORLD_X_LOC)
locX2 = MAX_WORLD_X_LOC-1;
if(locY1<0)
locY1 = 0;
else if(locY2>=MAX_WORLD_Y_LOC)
locY2 = MAX_WORLD_Y_LOC-1;
maxTries = (locX2-locX1+1)*(locY2-locY1+1);
regionId = townPtr->region_id;
}
else
{
locX1 = 0;
locY1 = 0;
locX2 = MAX_WORLD_X_LOC-1;
locY2 = MAX_WORLD_Y_LOC-1;
maxTries = 10000;
}
//----- randomly locate a space to add the site -----//
if( world.locate_space_random(locX1, locY1, locX2, locY2,
5, 5, maxTries, regionId, 1) ) // 5,5 are the size of the raw site, it must be large enough for a mine to build and 1 location for the edges. The last para 1 = site building mode
{
int reserveQty = MAX_RAW_RESERVE_QTY * (50 + m.random(50)) / 100;
add_site( locX1+2, locY1+2, SITE_RAW, rawId, reserveQty ); // xLoc+1 & yLoc+1 as the located size is 3x3, the raw site is at the center of it
return 1;
}
else
{
return 0;
}
}
//--------- End of function SiteArray::create_raw_site ----------//
//--------- Begin of function SiteArray::scan_site ----------//
//
// Scan for the a site that is closest the given location.
//
// xLoc, yLoc - the location given.
// [int] siteType - if given, only scan for this site (default: 0)
//
// return: nearestSiteRecno - the recno of the raw materials
// that is nearest to the given location.
//
int SiteArray::scan_site(int xLoc, int yLoc, int siteType)
{
Site* sitePtr;
int siteDis, minDis=0x7FFFFFFF, nearestSiteRecno=0;
for( int i=site_array.size() ; i>0 ; i-- )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( siteType==0 || sitePtr->site_type==siteType )
{
siteDis = m.points_distance( xLoc, yLoc, sitePtr->map_x_loc, sitePtr->map_y_loc );
if( siteDis < minDis )
{
minDis = siteDis;
nearestSiteRecno = i;
}
}
}
return nearestSiteRecno;
}
//---------- End of function SiteArray::scan_site -----------//
//--------- Begin of function SiteArray::next_day ----------//
//
void SiteArray::next_day()
{
if( info.game_date%30 == 0 )
{
generate_raw_site(); // check if we need to generate existing raw sites are being used up and if we need to generate new ones
}
//-- if there is any scroll or gold coins available, ask AI to get them --//
if(scroll_count || gold_coin_count)
{
int aiGetSiteObject = (info.game_date%5 == 0);
Site* sitePtr;
Location *locPtr;
for(int i=size(); i; i--)
{
if(is_deleted(i))
continue;
sitePtr = site_array[i];
switch(sitePtr->site_type)
{
case SITE_SCROLL:
case SITE_GOLD_COIN:
locPtr = world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc);
//---- if the unit is standing on a scroll site -----//
if(locPtr->has_unit(UNIT_LAND))
{
sitePtr->get_site_object( locPtr->unit_recno(UNIT_LAND) );
}
else if(aiGetSiteObject)
{
sitePtr->ai_get_site_object();
}
break;
}
}
}
//-------- debug testing --------//
#ifdef DEBUG
if( info.game_date%10 == 0 )
{
Site* sitePtr;
Location* locPtr;
for( int i=1 ; i<=size() ; i++ )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
locPtr = world.get_loc( sitePtr->map_x_loc, sitePtr->map_y_loc );
err_when( !locPtr->has_site() );
err_when( locPtr->site_recno() != i );
if( sitePtr->has_mine )
{
err_when( !locPtr->is_firm() );
err_when( firm_array[locPtr->firm_recno()]->firm_id != FIRM_MINE );
}
else
{
err_when( locPtr->is_firm() || locPtr->is_town() );
}
}
}
#endif
}
//--------- End of function SiteArray::next_day ----------//
//--------- Begin of function SiteArray::ai_get_site_object -------//
//
// Notify AI units to acquire scrolls or gold coins available on the
// map.
//
void SiteArray::ai_get_site_object()
{
Site* sitePtr;
for( int i=1 ; i<=size() ; i++ )
{
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( sitePtr->site_type == SITE_SCROLL ||
sitePtr->site_type == SITE_GOLD_COIN )
{
sitePtr->ai_get_site_object();
}
}
}
//----------- End of function SiteArray::ai_get_site_object -------//
//------- Begin of function Site::ai_get_site_object -------//
//
// Ask AI units around to get the object on this site.
//
int Site::ai_get_site_object()
{
#define NOTIFY_GET_RANGE 30 // only notify units within this range
#define MAX_UNIT_TO_ORDER 5
int xOffset, yOffset;
int xLoc, yLoc;
Location* locPtr;
Unit* unitPtr;
int unitOrderedCount=0;
int siteRaceId = 0;
if( site_type == SITE_SCROLL )
siteRaceId = god_res[object_id]->race_id;
for( int i=2 ; ihas_unit(UNIT_LAND) )
continue;
//------------------------------//
int unitRecno = locPtr->unit_recno(UNIT_LAND);
if( unit_array.is_deleted(unitRecno) )
continue;
unitPtr = unit_array[unitRecno];
if( !unitPtr->race_id || !unitPtr->ai_unit || unitPtr->ai_action_id )
continue;
if( siteRaceId && siteRaceId != unitPtr->race_id )
continue;
unitPtr->move_to(map_x_loc, map_y_loc);
//--- if the unit is just standing next to the site ---//
if( abs(map_x_loc-xLoc)<=1 && abs(map_y_loc-yLoc)<=1 )
{
return 1;
}
else // order more than one unit to get the site at the same time
{
if( ++unitOrderedCount >= MAX_UNIT_TO_ORDER )
return 1;
}
}
return 0;
}
//-------- End of function Site::ai_get_site_object -------//
//--------- Begin of function SiteArray::go_to_a_raw_site -------//
//
// Go to an untapped raw site.
//
void SiteArray::go_to_a_raw_site()
{
//----- try to locate an untapped raw site -----//
Site* sitePtr;
//### begin alex 22/10 ###//
int arraySize = size();
int i = selected_recno ? selected_recno : 0;
//#### end alex 22/10 ####//
//### begin alex 22/10 ###//
//for( int i=1 ; i<=size() ; i++ )
//{
int j;
for( j=1 ; j<=arraySize ; j++ )
{
if(++i > arraySize)
i = 1;
//#### end alex 22/10 ####//
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( !sitePtr->has_mine )
{
if( world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc)->explored() )
{
world.go_loc( sitePtr->map_x_loc, sitePtr->map_y_loc, 1 ); // 1-select the object on the location
return;
}
}
}
//---- if no untapped raw sites left, jump to built mines ----//
//### begin alex 22/10 ###//
i = 1;
if(firm_array.selected_recno)
{
//------- get the site_recno if a mine is selected ---------//
Firm *firmPtr = firm_array[firm_array.selected_recno];
if(firmPtr->firm_id==FIRM_MINE)
{
int x1 = firmPtr->loc_x1;
int y1 = firmPtr->loc_y1;
int x2 = firmPtr->loc_x2;
int y2 = firmPtr->loc_y2;
for(int count=1; count<=arraySize; ++count)
{
if(site_array.is_deleted(count))
continue;
sitePtr = site_array[count];
if(sitePtr->map_x_loc>=x1 && sitePtr->map_x_loc<=x2 && sitePtr->map_y_loc>=y1 && sitePtr->map_y_loc<=y2)
{
i = count;
break;
}
}
}
}
//#### end alex 22/10 ####//
//### begin alex 22/10 ###//
//for( i=1 ; i<=size() ; i++ )
//{
for( j=1 ; j<=arraySize ; j++ )
{
if(++i > arraySize)
i = 1;
//#### end alex 22/10 ####//
if( site_array.is_deleted(i) )
continue;
sitePtr = site_array[i];
if( world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc)->explored() )
{
world.go_loc( sitePtr->map_x_loc, sitePtr->map_y_loc, 1 ); // 1-select the object on the location
return;
}
}
}
//----------- End of function SiteArray::go_to_a_raw_site -------//
//--------- Begin of function Site::init ----------//
//
void Site::init(int siteRecno, int siteType, int xLoc, int yLoc)
{
site_recno = siteRecno;
site_type = siteType;
map_x_loc = xLoc;
map_y_loc = yLoc;
has_mine = 0;
//------- set world's location --------//
Location* locPtr = world.get_loc(xLoc, yLoc);
locPtr->set_site(siteRecno);
region_id = locPtr->region_id;
}
//---------- End of function Site::init -----------//
//--------- Begin of function Site::deinit ----------//
//
void Site::deinit()
{
//------ reset world's location ---------//
world.get_loc(map_x_loc, map_y_loc)->remove_site();
}
//---------- End of function Site::deinit -----------//
//--------- Begin of function Site::get_site_object ----------//
//
// An unit takes the object from the site
//
// unitRecno - recno of the unit that takes the object on the site.
//
int Site::get_site_object(int unitRecno)
{
Unit* unitPtr = unit_array[unitRecno];
int objectTaken=0;
if( !unitPtr->nation_recno )
return 0;
//----- if this is a scroll site ------//
if( site_type == SITE_SCROLL )
{
if( god_res[object_id]->race_id == unitPtr->race_id )
{
god_res[object_id]->enable_know(unitPtr->nation_recno);
objectTaken = 1;
news_array.scroll_acquired(unitPtr->nation_recno, god_res[object_id]->race_id );
}
}
//------ if there are gold coins on this site -----//
if( site_type == SITE_GOLD_COIN )
{
nation_array[unitPtr->nation_recno]->add_income(INCOME_TREASURE, object_id);
objectTaken = 1;
if( unitPtr->nation_recno == nation_array.player_recno )
news_array.monster_gold_acquired(object_id);
}
//---- if the object has been taken by the unit ----//
if( objectTaken )
{
site_array.del_site(site_recno);
return 1;
}
return 0;
}
//---------- End of function Site::get_site_object -----------//
//------- Begin of function SiteArray::is_deleted -----//
int SiteArray::is_deleted(int recNo)
{
Site* sitePtr = (Site*) get(recNo);
return !sitePtr || sitePtr->site_type==0;
}
//--------- End of function SiteArray::is_deleted ----//
#ifdef DEBUG
//------- Begin of function SiteArray::operator[] -----//
Site* SiteArray::operator[](int recNo)
{
Site* sitePtr = (Site*) get(recNo);
if( !sitePtr || sitePtr->site_type==0 )
err.run( "SiteArray[] is deleted" );
return sitePtr;
}
//--------- End of function SiteArray::operator[] ----//
//------- Begin of function SiteArray::operator() -----//
Site* SiteArray::operator()()
{
Site* sitePtr = (Site*) get();
if( !sitePtr || sitePtr->site_type==0 )
err.run( "SiteArray[recno()] is deleted" );
return sitePtr;
}
//--------- End of function SiteArray::operator() ----//
#endif