/*
* 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 : OWORLD.CPP
//Description : Object World
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//------------ Define static class variables ------------//
short World::view_top_x, World::view_top_y;
int World::max_x_loc=200, World::max_y_loc=200;
//----------- Begin of function World::World ----------//
World::World()
{
memset( this, 0, sizeof(World) );
//------- initialize matrix objects -------//
map_matrix = new MapMatrix;
zoom_matrix = new ZoomMatrix;
}
//------------- End of function World::World -----------//
//----------- Begin of function World::~World ----------//
World::~World()
{
if( map_matrix )
{
delete map_matrix;
map_matrix = NULL;
}
if( zoom_matrix )
{
delete zoom_matrix;
zoom_matrix = NULL;
}
deinit();
}
//------------- End of function World::~World -----------//
//----------- Begin of function World::init ----------//
void World::init()
{
//----------- initialize vars -------------//
scan_fire_x = 0;
scan_fire_y = 0;
lightning_signal = 0;
map_matrix->init_para();
zoom_matrix->init_para();
}
//------------- End of function World::init -----------//
//----------- Begin of function World::deinit ----------//
void World::deinit()
{
if( loc_matrix )
{
mem_del( loc_matrix );
loc_matrix = NULL;
}
}
//------------- End of function World::deinit -----------//
//--------- Begin of function World::assign_map ----------//
//
// After a map is loaded, assign_map() need to be called to
// initial map_matrix and zoom_matrix
//
void World::assign_map()
{
//------------- assign map -------------//
map_matrix-> assign_map(loc_matrix, max_x_loc, max_y_loc );
zoom_matrix->assign_map(loc_matrix, max_x_loc, max_y_loc );
//-------- set the zoom area box on map matrix ------//
map_matrix->cur_x_loc = 0;
map_matrix->cur_y_loc = 0;
map_matrix->cur_cargo_width = zoom_matrix->disp_x_loc;
map_matrix->cur_cargo_height = zoom_matrix->disp_y_loc;
}
//----------- End of function World::assign_map ----------//
//----------- Begin of function World::paint ------------//
//
// Paint world window and scroll bars
//
void World::paint()
{
map_matrix->paint();
zoom_matrix->paint();
}
//----------- End of function World::paint ------------//
//----------- Begin of function World::refresh ------------//
//
void World::refresh()
{
map_matrix->refresh();
zoom_matrix->refresh();
}
//----------- End of function World::refresh ------------//
//----------- Begin of function World::process ------------//
//
// Called every frame
//
void World::process()
{
//-------- process wall ----------//
form_world_wall();
//-------- process fire -----------//
// BUGHERE : set Location::flammability for every change in cargo
world.spread_fire(weather);
// ------- process visibility --------//
process_visibility();
//-------- process lightning ------//
// ###### begin Gilbert 11/8 ########//
if(lightning_signal== 0 && weather.is_lightning())
{
// ------- create new lightning ----------//
lightning_signal = 110;
}
if( lightning_signal == 106 && config.weather_effect)
{
lightning_strike(m.random(MAX_MAP_WIDTH), m.random(MAX_MAP_HEIGHT), 1);
}
if(lightning_signal == 100)
lightning_signal = 5 + m.random(10);
else if( lightning_signal)
lightning_signal--;
// ###### end Gilbert 11/8 ########//
//---------- process ambient sound ---------//
if( sys.frame_count%10 == 0 ) // process once per ten frames
process_ambient_sound();
// --------- update scan fire x y ----------//
if(++scan_fire_x >= SCAN_FIRE_DIST)
{
scan_fire_x = 0;
if( ++scan_fire_y >= SCAN_FIRE_DIST)
scan_fire_y =0;
}
}
//----------- End of function World::process ------------//
//----------- Begin of function World::next_day ------------//
//
// Called every frame
//
void World::next_day()
{
plant_ops();
weather = weather_forecast[0];
for(int foreDay=0; foreDay < MAX_WEATHER_FORECAST-1; ++foreDay)
{
weather_forecast[foreDay] = weather_forecast[foreDay+1];
}
weather_forecast[MAX_WEATHER_FORECAST-1].next_day();
// ####### begin Gilbert 11/7 #########//
magic_weather.next_day();
// ####### end Gilbert 11/7 #########//
if(weather.has_tornado() && config.weather_effect)
{
tornado_array.add_tornado(weather.tornado_x_loc(max_x_loc, max_y_loc),
weather.tornado_y_loc(max_x_loc, max_y_loc), 600);
}
// ######## begin Gilbert 31/7 #######//
if( weather.is_quake() && config.random_event_frequency)
// ######## end Gilbert 31/7 #######//
{
earth_quake();
}
//-------- Debug code: BUGHERE ----------//
#ifdef DEBUG
Location* locPtr = loc_matrix;
for( int y=0 ; yhas_unit(UNIT_LAND) )
{
err_when( unit_array.is_truly_deleted( locPtr->unit_recno(UNIT_LAND) ) );
}
locPtr++;
}
}
#endif
}
//----------- End of function World::next_day ------------//
//----------- Begin of function World::detect ------------//
//
// Detect mouse action from user
//
// Return : 1 - mouse pressed on World area
// 0 - mouse not pressed on World area
//
int World::detect()
{
if( map_matrix->detect() )
return 1;
if( zoom_matrix->detect() )
return 1;
if( detect_scroll() )
return 1;
// ##### begin Gilbert 16/9 #######//
// return detect_firm_town();
return 0;
// ##### end Gilbert 16/9 #######//
}
//----------- End of function World::detect ------------//
//--------- Begin of function World::detect_scroll ---------//
//
// Detect if the mouse cursor is pushed towards the border
// of the screen to scroll the zoom window.
//
int World::detect_scroll()
{
if( mouse_cursor.frame_flag ) // if it's now in frame selection mode
return 0;
if( next_scroll_time && m.get_time() < next_scroll_time ) // just scrolled not too long ago, wait for a little while before next scroll.
return 0;
int rc=0;
//----- scroll left -----//
if( mouse.cur_x == mouse.bound_x1 )
{
zoom_matrix->scroll(-1,0);
rc = 1;
}
//---- scroll right -----//
if( mouse.cur_x == mouse.bound_x2 )
{
zoom_matrix->scroll(1,0);
rc = 1;
}
//---- scroll top -------//
if( mouse.cur_y == mouse.bound_y1 )
{
zoom_matrix->scroll(0,-1);
rc = 1;
}
//---- scroll bottom ----//
if( mouse.cur_y == mouse.bound_y2 )
{
zoom_matrix->scroll(0,1);
rc = 1;
}
//----- set next scroll time based on scroll_speed -----//
//
// slowest scroll speed: 500/1 = 500 milliseconds or 1/2 second
// fastest scroll speed: 500/10 = 50 milliseconds or 1/20 second
//
//------------------------------------------------------//
if( rc )
{
sys.zoom_need_redraw = 1; // ask the zoom window to refresh next time
next_scroll_time = m.get_time() + 500/(config.scroll_speed+1);
}
return rc;
}
//----------- End of function World::detect_scroll -----------//
//--------- Begin of function World::go_loc --------//
//
// Go to a specified location.
//
// xLoc, yLoc - location to go to.
// [int] selectFlag - whether should the object on the location if
// there is one. (default: 0)
//
void World::go_loc(int xLoc, int yLoc, int selectFlag)
{
//------- set location ---------//
zoom_matrix->cur_x_loc = xLoc;
zoom_matrix->cur_y_loc = yLoc;
map_matrix->cur_x_loc = xLoc - zoom_matrix->disp_x_loc/2;
map_matrix->cur_y_loc = yLoc - zoom_matrix->disp_y_loc/2;
//--------- refresh ------------//
map_matrix->valid_cur_box();
zoom_matrix->top_x_loc = map_matrix->cur_x_loc;
zoom_matrix->top_y_loc = map_matrix->cur_y_loc;
sys.zoom_need_redraw = 1;
//---- if should select the object on the location ----//
if( selectFlag )
{
Location* locPtr = world.get_loc(xLoc, yLoc);
if( locPtr->has_any_unit() )
{
int mobileType;
int unitRecno = locPtr->get_any_unit( mobileType );
power.reset_selection();
unit_array[unitRecno]->selected_flag = 1;
unit_array.selected_recno = unitRecno;
unit_array.selected_count++;
}
else if( locPtr->is_firm() )
{
power.reset_selection();
firm_array.selected_recno = locPtr->firm_recno();
}
else if( locPtr->is_town() )
{
power.reset_selection();
town_array.selected_recno = locPtr->town_recno();
}
else if( locPtr->has_site() )
{
power.reset_selection();
site_array.selected_recno = locPtr->site_recno();
}
}
//------- refresh the display -------//
info.disp();
}
//----------- End of function World::go_loc --------//
//-------- Begin of function World::unveil ---------//
//
// Unveil all surrounding areas of the given object.
//
// xLoc1, yLoc1 = the position of the object.
// xLoc2, yLoc2 = the position of the object.
//
void World::unveil(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
{
if( config.explore_whole_map )
return;
xLoc1 = max( 0, xLoc1 - EXPLORE_RANGE);
yLoc1 = max( 0, yLoc1 - EXPLORE_RANGE);
xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EXPLORE_RANGE);
yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EXPLORE_RANGE);
explore( xLoc1, yLoc1, xLoc2, yLoc2 );
}
//--------- End of function World::unveil ---------//
//-------- Begin of function World::explore ---------//
//
// Explore a specific area. No further exploration around the area.
//
// xLoc1, yLoc1 = the position of the area.
// xLoc2, yLoc2 = the position of the area.
//
void World::explore(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
{
if( config.explore_whole_map )
return;
int xLoc, yLoc;
Location* locPtr;
char* imageBuf = map_matrix->save_image_buf + sizeof(short)*2;
char* nationColorArray = nation_array.nation_power_color_array;
char* writePtr;
int shadowMapDist = max_x_loc + 1;
int tileYOffset;
Location *northWestPtr;
char tilePixel;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
locPtr = get_loc(xLoc1, yLoc);
for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
{
if( !locPtr->explored() )
{
locPtr->explored_on();
//-------- draw pixel ----------//
writePtr = imageBuf+MAP_WIDTH*yLoc+xLoc;
switch( world.map_matrix->map_mode )
{
case MAP_MODE_TERRAIN:
if( locPtr->fire_str() > 0)
*writePtr = (char) FIRE_COLOR;
else if( locPtr->is_plant() )
*writePtr = plant_res.plant_map_color;
else
{
tileYOffset = (yLoc & TERRAIN_TILE_Y_MASK) * TERRAIN_TILE_WIDTH;
tilePixel = terrain_res.get_map_tile(locPtr->terrain_id)[tileYOffset + (xLoc & TERRAIN_TILE_X_MASK)];
if( xLoc == 0 || yLoc == 0)
{
*writePtr = tilePixel;
}
else
{
northWestPtr = locPtr - shadowMapDist;
if( (terrain_res[locPtr->terrain_id]->average_type >=
terrain_res[northWestPtr->terrain_id]->average_type) )
{
*writePtr = tilePixel;
}
else
{
*writePtr = (char) VGA_GRAY;
}
}
break;
}
break;
case MAP_MODE_SPOT:
if( locPtr->sailable() )
*writePtr = (char) 0x32;
else if( locPtr->has_hill() )
*writePtr = (char) V_BROWN;
else if( locPtr->is_plant() )
*writePtr = (char) V_DARK_GREEN;
else
*writePtr = (char) VGA_GRAY+10;
break;
case MAP_MODE_POWER:
if( locPtr->sailable() )
*writePtr = (char) 0x32;
else if( locPtr->has_hill() )
*writePtr = (char) V_BROWN;
else if( locPtr->is_plant() )
*writePtr = (char) V_DARK_GREEN;
else
*writePtr = nationColorArray[locPtr->power_nation_recno];
break;
}
//---- if the command base of the opponent revealed, establish contact ----//
if( locPtr->is_firm() )
{
Firm* firmPtr = firm_array[locPtr->firm_recno()];
if( firmPtr->nation_recno > 0 && nation_array.player_recno )
{
NationRelation *relation = (~nation_array)->get_relation(firmPtr->nation_recno);
if( !relation->has_contact )
{
if( !remote.is_enable() )
{
(~nation_array)->establish_contact(firmPtr->nation_recno);
}
else
{
if( !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] = firmPtr->nation_recno;
relation->contact_msg_flag = 1;
}
}
}
}
}
if( locPtr->is_town() )
{
Town* townPtr = town_array[locPtr->town_recno()];
if( townPtr->nation_recno > 0 && nation_array.player_recno )
{
NationRelation *relation = (~nation_array)->get_relation(townPtr->nation_recno);
if( !relation->has_contact )
{
if( !remote.is_enable() )
{
(~nation_array)->establish_contact(townPtr->nation_recno);
}
else
{
if( !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] = townPtr->nation_recno;
relation->contact_msg_flag = 1;
}
}
}
}
}
}
}
}
}
//--------- End of function World::explore ---------//
//-------- Begin of function World::is_explored ---------//
//
// Check if the whole area has been explored or not.
//
// xLoc1, yLoc1 = the coordination of the area to explore
// xLoc2, yLoc2 = the coordination of the area to explore
//
int World::is_explored(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
{
if( config.explore_whole_map )
return 1;
int xLoc, yLoc;
Location* locPtr;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
locPtr = get_loc(xLoc1, yLoc);
for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
{
if( !locPtr->explored() )
return 0;
}
}
return 1;
}
//--------- End of function World::is_explored ---------//
//----------- Begin of function World::load_map ------------//
//
// Load a custom map file.
//
void World::load_map(char* fileName)
{
generate_map();
return;
//---------- initialize the map matrix --------//
max_x_loc = 200;
max_y_loc = 200;
loc_matrix = (Location*) mem_resize( loc_matrix , max_x_loc * max_y_loc * sizeof(Location) );
memset( loc_matrix, 0, sizeof(Location) * max_x_loc * max_y_loc );
int baseType = TERRAIN_DARK_DIRT;
int terrainId = terrain_res.scan(baseType, MIDDLE_MASK, baseType, MIDDLE_MASK,
baseType, MIDDLE_MASK, baseType, MIDDLE_MASK, 1); // 1-get the first instance
for( int i=0 ; i xLoc1 = the upper left x
// yLoc1 = the upper left y
// xLoc2 = the lower right x
// yLoc2 = the lower right y
// [int] mobileType = mobile type (default: UNIT_LAND)
// [int] buildFlag = whether the located area is for building a firm/town
// if so, the location must no have any raw site.
// (default: 0)
//
// return 1 for true. 0 for false
//
inline int World::check_unit_space(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int mobileType, int buildFlag)
{
if(xLoc1<0 || xLoc1>=MAX_WORLD_X_LOC)
return 0;
if(yLoc1<0 || yLoc1>=MAX_WORLD_Y_LOC)
return 0;
if(xLoc2<0 || xLoc2>=MAX_WORLD_X_LOC)
return 0;
if(yLoc2<0 || yLoc2>=MAX_WORLD_Y_LOC)
return 0;
Location* locPtr = world.get_loc(xLoc1, yLoc1);
int x, y;
int canBuildFlag = 1;
for(y=yLoc1; y<=yLoc2; y++)
{
locPtr = world.get_loc(xLoc1, y);
for(x=xLoc1; x<=xLoc2; x++, locPtr++)
{
if( !locPtr->can_move(mobileType) ||
( buildFlag && (locPtr->is_power_off() || locPtr->has_site()) ) ) // if build a firm/town, there must not be any sites in the area
{
canBuildFlag=0;
break;
}
}
if(canBuildFlag==0)
break;
}
if( canBuildFlag )
return 1;
else
return 0;
}
//-------- End of function World::check_unit_space ------//
//-------- Begin of function World::locate_space ------//
//
// Locate an area in the world map around the firm to place
// the unit
//
// xLoc1 = the upper left x location of the building, also for returning the result location
// yLoc1 = the upper left y location of the building
// xLoc2 = the lower right x location of the building
// yLoc2 = the lower right y location of the building
// spaceLocWidth = the location width of the required space
// spaceLocHeight = the location height of the required space
// [int] mobileType = mobile type (default: UNIT_LAND)
// [int] regionId = specify the region no. of the location to locate
// (default: region no. of xLoc1, yLoc1)
// [int] buildFlag = whether the located area is for building a firm/town
// if so, the location must no have any raw site.
// (default: 0)
//
// return : 1 - free space found
// 0 - free space not found
//
int World::locate_space(int& xLoc1, int& yLoc1, int xLoc2, int yLoc2,
int spaceLocWidth, int spaceLocHeight, int mobileType, int regionId, int buildFlag)
{
if( !regionId )
regionId = get_loc(xLoc1, yLoc1)->region_id;
int isPlateau = get_loc(xLoc1, yLoc1)->is_plateau();
//-----------------------------------------------------------//
// xLoc, yLoc is the adjusted upper left corner location of
// the firm. with the adjustment, it is easier to do the following
// checking.
//-----------------------------------------------------------//
Location* locPtr;
int xLoc = xLoc1 - spaceLocWidth + 1;
int yLoc = yLoc1 - spaceLocHeight + 1;
if(xLoc < 0)
xLoc = 0;
if(yLoc < 0)
yLoc = 0;
int width = xLoc2 - xLoc + 1;
int height = yLoc2 - yLoc + 1;
int loopCount=0;
while(1)
{
err_when( ++loopCount > MAX_WORLD_X_LOC * MAX_WORLD_Y_LOC * 4 );
//-----------------------------------------------------------//
// step 1
//-----------------------------------------------------------//
int xOffset = width/2;
int yOffset = height;
int x, y;
x = xLoc + xOffset;
y = yLoc + yOffset;
if(x>=0 && y>=0 && x+spaceLocWidth-1region_id == regionId &&
locPtr->is_plateau() == isPlateau &&
check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
{
xLoc1 = x;
yLoc1 = y;
return 1;
}
}
}
int sign = -1;
int i, j, k, limit;
//-----------------------------------------------------------//
// step 2
//-----------------------------------------------------------//
//y = yLoc + yOffset;
limit = width + 2;
for(i=1; i=0 && y>=0 && x+spaceLocWidth-1region_id == regionId &&
locPtr->is_plateau() == isPlateau &&
check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
{
xLoc1 = x;
yLoc1 = y;
return 1;
}
}
}
sign *= -1;
}
//-----------------------------------------------------------//
// step 3
//-----------------------------------------------------------//
i = limit-1;
limit = (height+1)*2;
int r = sign*i;
int lastX = xOffset;
//int lastY = yOffset;
for(j=0; j=0 && y>=0 && x+spaceLocWidth-1region_id == regionId &&
locPtr->is_plateau() == isPlateau &&
check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
{
xLoc1 = x;
yLoc1 = y;
return 1;
}
}
}
}
else
{
xOffset = lastX + r;
yOffset--;
x = xLoc + xOffset;
y = yLoc + yOffset;
if(x>=0 && y>=0 && x+spaceLocWidth-1region_id == regionId &&
locPtr->is_plateau() == isPlateau &&
check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
{
xLoc1 = x;
yLoc1 = y;
return 1;
}
}
}
}
}
//-----------------------------------------------------------//
// step 4
//-----------------------------------------------------------//
y = yLoc + yOffset;
for(k=0; k<=width; k++)
{
sign *= -1;
i--;
r = sign*i;
xOffset -= r;
x = xLoc + xOffset;
if(x>=0 && y>=0 && x+spaceLocWidth-1region_id == regionId &&
locPtr->is_plateau() == isPlateau &&
check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
{
xLoc1 = x;
yLoc1 = y;
return 1;
}
}
}
}
//-----------------------------------------------------------//
// re-init the parameters
//-----------------------------------------------------------//
if(xLoc<=0 && yLoc<=0 && width>=MAX_WORLD_X_LOC && height>=MAX_WORLD_Y_LOC)
break; // the whole map has been checked
width += 2;
height += 2;
xLoc -= 1;
yLoc -= 1;
if(xLoc<0)
{
xLoc = 0;
width--;
}
if(yLoc<0)
{
yLoc=0;
height--;
}
if(xLoc+width>MAX_WORLD_X_LOC)
width--;
if(yLoc+height>MAX_WORLD_Y_LOC)
height--;
//if(width==xLoc2-xLoc1+spaceLocWidth && height==yLoc2-yLoc1+spaceLocHeight) // terminate the checking
// return 0;
}
return 0;
}
//-------- End of function World::locate_space ------//
//-------- Begin of function World::locate_space_random ------//
//
// Locate an area of space in the world map randomly. Pick any
// space available in that area without a specific scanning order.
//
// xLoc1 = the scaning range, also for returning the result location
// yLoc1 = the scaning range
// xLoc2 = the scaning range
// yLoc2 = the scaning range
// spaceLocWidth = the location width of the required space
// spaceLocHeight = the location height of the required space
// maxTries = maximum no. of tries
// [int] regionId = if this is specified, the result location will
// be in this region.
// [int] buildSite = whether locating space for building a site
// (default: 0)
// [char] teraMask = terrain mask (default: 1)
//
// return : 1 - free space found
// 0 - free space found
//
int World::locate_space_random(int& xLoc1, int& yLoc1, int xLoc2, int yLoc2,
int spaceLocWidth, int spaceLocHeight, int maxTries,
int regionId, int buildSite, char teraMask)
{
int i, x, y, xTemp, xLoc, yLoc, canBuildFlag;
int scanWidth = xLoc2-xLoc1-spaceLocWidth+2; //xLoc2-xLoc1+1-spaceLocWidth+1;
int scanHeight = yLoc2-yLoc1-spaceLocHeight+2; //yLoc2-yLoc1+1-spaceLocHeight+1;
Location* locPtr;
for( i=0 ; i=yLoc; y-- )
{
locPtr = world.get_loc(xTemp, y);
for(x=xTemp; x>=xLoc; x--, locPtr-- )
{
if( ( buildSite ? !locPtr->can_build_site(teraMask) : !locPtr->can_build_firm(teraMask) ) ||
locPtr->is_power_off() )
{
canBuildFlag=0;
break;
}
}
if(!canBuildFlag)
break;
}
if( !canBuildFlag )
continue;
//------ check region id. ------------//
locPtr = world.get_loc(xLoc, yLoc);
if( regionId && locPtr->region_id != regionId )
continue;
//------------------------------------//
xLoc1 = xLoc;
yLoc1 = yLoc;
err_when(buildSite && !locPtr->can_build_site(teraMask));//-*** hard codes for mine size 3x3
return 1;
}
return 0;
}
//-------- End of function World::locate_space_random ------//
//-------- Begin of function World::can_build_firm ---------//
//
// Check if it is free to construct a building on the specific area.
//
// xLoc1, yLoc1 = the coordination of the area to can_build
// firmId = id. of the firm
// [short] unitRecno = the unit recno of the unit to build the firm
// if the builder unit stands on the building area, still consider the area as buildable
// (default: -1, do not take the builder into account)
//
int World::can_build_firm(int xLoc1, int yLoc1, int firmId, short unitRecno)
{
if( xLoc1 < 0 || yLoc1 < 0 || xLoc1 > MAX_WORLD_X_LOC || yLoc1 > MAX_WORLD_Y_LOC )
return 0;
//------------------------------------------//
FirmInfo* firmInfo = firm_res[firmId];
int xLoc, yLoc;
int xLoc2 = xLoc1 + firmInfo->loc_width - 1;
int yLoc2 = yLoc1 + firmInfo->loc_height - 1;
if(xLoc2>=max_x_loc || yLoc2>max_y_loc)
return 0;
Location* locPtr;
char teraMask, pierFlag;
switch(firmInfo->tera_type)
{
case 1: // default : land firm
case 2: // sea firm
case 3: // land or sea firm
teraMask = firmInfo->tera_type;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
locPtr = get_loc(xLoc1, yLoc);
for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
{
// ##### patch begin Gilbert 14/3 ######//
if(!locPtr->can_build_firm(teraMask) &&
(!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno))
return 0;
// ##### patch end Gilbert 14/3 ######//
if( firmId != FIRM_MINE && locPtr->has_site() ) // don't allow building any buildings other than mines on a location with a site
return 0;
}
}
return 1;
case 4: // special firm, such as harbor
// must be 3x3,
// centre square of one side is land (teraMask=1),
// two squares on that side can be land or sea (teraMask=3)
// and other (6 squares) are sea (teraMask=2)
if( firmInfo->loc_width != 3 ||
firmInfo->loc_height != 3)
return 0;
pierFlag = 1|2|4|8; // bit0=north, bit1=south, bit2=west, bit3=east
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
locPtr = get_loc(xLoc1, yLoc);
for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
{
if( locPtr->has_site() ) // don't allow building any buildings other than mines on a location with a site
return 0;
static char northPierTera[3][3] = { {2,2,2},{2,2,2},{3,1,3} };
static char southPierTera[3][3] = { {3,1,3},{2,2,2},{2,2,2} };
static char westPierTera[3][3] = { {2,2,3},{2,2,1},{2,2,3} };
static char eastPierTera[3][3] = { {3,2,2},{1,2,2},{3,2,2} };
int x = xLoc - xLoc1;
int y = yLoc - yLoc1;
if(!locPtr->can_build_harbor(northPierTera[y][x]) )
pierFlag &= ~1;
if(!locPtr->can_build_harbor(southPierTera[y][x]) )
pierFlag &= ~2;
if(!locPtr->can_build_harbor(westPierTera[y][x]) )
pierFlag &= ~4;
if(!locPtr->can_build_harbor(eastPierTera[y][x]) )
pierFlag &= ~8;
}
}
err_when( pierFlag != 0 && pierFlag != 1 && pierFlag != 2 &&
pierFlag != 4 && pierFlag != 8 );
return pierFlag;
break;
// other tera_type here
default:
err_here();
return 0;
}
}
//--------- End of function World::can_build_firm ---------//
//-------- Begin of function World::can_build_town ---------//
//
// xLoc1, yLoc1 = the coordination of the area to can_build
// [short] unitRecno = the unit recno of the unit to build the town
// if the builder unit stands on the building area, still consider the area as buildable
// (default: -1, do not take the builder into account)
//
int World::can_build_town(int xLoc1, int yLoc1, short unitRecno)
{
int xLoc, yLoc;
int xLoc2 = xLoc1 + STD_TOWN_LOC_WIDTH - 1;
int yLoc2 = yLoc1 + STD_TOWN_LOC_HEIGHT - 1;
if(xLoc2>=max_x_loc || yLoc2>=max_y_loc)
return 0;
Location* locPtr;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
locPtr = get_loc(xLoc1, yLoc);
for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
{
// ##### patch begin Gilbert 14/3 ######//
// allow the building unit to stand in the area
if( !locPtr->can_build_town() &&
(!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno) )
return 0;
// ##### patch end Gilbert 14/3 ######//
}
}
return 1;
}
//--------- End of function World::can_build_town ---------//
//-------- Begin of function World::can_build_wall ---------//
//
// xLoc, yLoc = the coordination of the area to can_build
// nationRecno = recno of the builder nation.
//
int World::can_build_wall(int xLoc, int yLoc, short nationRecno)
{
Location* locPtr = get_loc(xLoc, yLoc);
return locPtr->can_build_wall() && locPtr->power_nation_recno == nationRecno;
}
//--------- End of function World::can_build_wall ---------//
//-------- Begin of function World::can_destruct_wall ---------//
//
// xLoc, yLoc = the coordination of the area to can_build
// nationRecno = recno of the builder nation.
//
int World::can_destruct_wall(int xLoc, int yLoc, short nationRecno)
{
Location* locPtr = get_loc(xLoc, yLoc);
return locPtr->is_wall() && locPtr->power_nation_recno == nationRecno;
}
//--------- End of function World::can_destruct_wall ---------//
//---------- Begin of function World::draw_link_line -----------//
//
// srcFirmId - id. of the source firm.
// 0 if the source is a town
// srcTownRecno - town recno of the source town
// 0 if the source is a firm
// srcXLoc1, srcYLoc1 - the location of the source area
// srcXLoc2, srcYLoc2
//
// [int] giveEffectiveDis - use this value as the effective distance if this is given
// (default: 0)
//
void World::draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1,
int srcYLoc1, int srcXLoc2, int srcYLoc2, int givenEffectiveDis)
{
if( srcFirmId == FIRM_INN ) // FirmInn's link is only for scan for neighbor inns quickly, the link line is not displayed
return;
//--------------------------------------//
int srcXLoc = (srcXLoc1 + srcXLoc2)/2;
int srcYLoc = (srcYLoc1 + srcYLoc2)/2;
int srcX = ( ZOOM_X1 + (srcXLoc1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
+ ZOOM_X1 + (srcXLoc2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
int srcY = ( ZOOM_Y1 + (srcYLoc1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
+ ZOOM_Y1 + (srcYLoc2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
//------- draw lines connected to town ---------//
int i, townX, townY, effectiveDis;
Town* townPtr;
if( givenEffectiveDis )
effectiveDis = givenEffectiveDis;
else
{
if( srcFirmId )
effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
else
effectiveDis = EFFECTIVE_TOWN_TOWN_DISTANCE;
}
if( !srcFirmId || firm_res[srcFirmId]->is_linkable_to_town ) // don't draw link line to town if it's an inn
{
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( srcTownRecno && townPtr->town_recno != srcTownRecno )
continue;
//-------- check the distance --------//
if( m.points_distance( townPtr->center_x, townPtr->center_y,
srcXLoc, srcYLoc ) > effectiveDis )
{
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(srcXLoc, srcYLoc)->is_plateau()==1) )
{
continue;
}
//---------- draw line now -----------//
townX = ( ZOOM_X1 + (townPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
+ ZOOM_X1 + (townPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
townY = ( ZOOM_Y1 + (townPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
+ ZOOM_Y1 + (townPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
anim_line.draw_line(&vga_back, srcX, srcY, townX, townY);
}
}
//------- draw lines connected to firms ---------//
if( givenEffectiveDis )
effectiveDis = givenEffectiveDis;
else
{
if( srcFirmId )
effectiveDis = EFFECTIVE_FIRM_FIRM_DISTANCE;
else
effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
}
int firmX, firmY, linkFlag;
Firm* firmPtr;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
//------ only link if the firms have relationship -----//
if( srcFirmId )
linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_firm(srcFirmId);
else
linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_town;
if( !linkFlag )
continue;
//-------- check the distance --------//
if( m.points_distance( firmPtr->center_x, firmPtr->center_y,
srcXLoc, srcYLoc ) > effectiveDis )
{
continue;
}
//------ check if both are on the same terrain type ------//
if( (world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()==1)
!= (world.get_loc(srcXLoc, srcYLoc)->is_plateau()==1) )
{
continue;
}
//---------- draw line now -----------//
firmX = ( ZOOM_X1 + (firmPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
+ ZOOM_X1 + (firmPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
firmY = ( ZOOM_Y1 + (firmPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
+ ZOOM_Y1 + (firmPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
anim_line.draw_line(&vga_back, srcX, srcY, firmX, firmY);
}
}
//----------- End of function World::draw_link_line ------------//
//-------- Begin of function World::set_surr_power_off ---------//
void World::set_surr_power_off(int xLoc, int yLoc)
{
if(xLoc>0) // west
get_loc(xLoc-1, yLoc)->set_power_off();
if(xLocset_power_off();
if(yLoc>0) // north
get_loc(xLoc, yLoc-1)->set_power_off();
if(yLocset_power_off();
}
//----------- End of function World::set_surr_power_off ------------//
//-------- Begin of function World::set_all_power ---------//
//
void World::set_all_power()
{
//--------- set town's influence -----------//
Town* townPtr;
int i;
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( !townPtr->nation_recno )
continue;
//------- set the influence range of this town -----//
set_power(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, (char)townPtr->nation_recno);
}
//--------- set firm's influence -----------//
Firm* firmPtr;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
if( !firmPtr->nation_recno )
continue;
if( !firmPtr->should_set_power )
continue;
//------- set the influence range of this firm -----//
set_power(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, (char)firmPtr->nation_recno);
}
}
//--------- End of function World::set_all_power ---------//
//-------- Begin of function World::set_power ---------//
//
// xLoc1, yLoc1, - area on the map which the power should be set
// xLoc2, yLoc2
//
// nationRcno - nation recno
//
void World::set_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int nationRecno)
{
//------- reset power_nation_recno first ------//
int plateauResult = (get_loc((xLoc1+xLoc2)/2, (yLoc1+yLoc2)/2)->is_plateau()==1);
int xLoc, yLoc, centerY, t;
Location* locPtr = loc_matrix;
xLoc1 = max( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
yLoc1 = max( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
centerY = (yLoc1+yLoc2) / 2;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
t=abs(yLoc-centerY)/2;
for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
{
locPtr = get_loc(xLoc, yLoc);
if(locPtr->sailable())//if(!locPtr->walkable())
continue;
if(locPtr->is_power_off())
continue;
if((locPtr->is_plateau()==1) != plateauResult)
continue;
if(locPtr->power_nation_recno==0)
{
locPtr->power_nation_recno = nationRecno;
sys.map_need_redraw = 1; // request redrawing the map next time
}
}
}
}
//--------- End of function World::set_power ---------//
//-------- Begin of function World::restore_power ---------//
//
// xLoc1, yLoc1, - area on the map which the power should be restored
// xLoc2, yLoc2
//
// townRecno, firmRecno - either one
//
void World::restore_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int townRecno, int firmRecno)
{
int nationRecno;
if( townRecno )
{
nationRecno = town_array[townRecno]->nation_recno;
town_array[townRecno]->nation_recno = 0;
}
if( firmRecno )
{
nationRecno = firm_array[firmRecno]->nation_recno;
firm_array[firmRecno]->nation_recno = 0;
}
//------- reset power_nation_recno first ------//
int xLoc, yLoc, centerY, t;
Location* locPtr = loc_matrix;
xLoc1 = max( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
yLoc1 = max( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
centerY = (yLoc1+yLoc2) / 2;
for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
{
t=abs(yLoc-centerY)/2;
for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
{
locPtr = get_loc(xLoc, yLoc);
if( locPtr->power_nation_recno==nationRecno )
{
locPtr->power_nation_recno = 0;
sys.map_need_redraw = 1; // request redrawing the map next time
}
}
}
//--- if some power areas are freed up, see if neighbor towns/firms should take up these power areas ----//
if( sys.map_need_redraw ) // when calls set_all_power(), the nation_recno of the calling firm must be reset
set_all_power();
//------- restore the nation recno of the calling town/firm -------//
if( townRecno )
town_array[townRecno]->nation_recno = nationRecno;
if( firmRecno )
firm_array[firmRecno]->nation_recno = nationRecno;
}
//--------- End of function World::restore_power ---------//
//-------- Begin of function World::detect_firm_town ---------//
//
int World::detect_firm_town()
{
// ##### begin Gilbert 19/9 ########//
// int rc = mouse.single_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2);
if( !mouse.any_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2) )
return 0;
// ##### end Gilbert 19/9 ########//
//------ detect pressing on link enable/disable sign -----//
Firm* firmPtr;
if( firm_array.selected_recno )
{
firmPtr = firm_array[firm_array.selected_recno];
if( firmPtr->should_show_info() && // only if should_show_info() is 1, we can detect links from this firm (it is not limited to player firms, as firms with player's workers should be allowed for resigning the player worker from the firm
firmPtr->draw_detect_link_line(1) ) // 1-detect action
{
return 1;
}
}
Town* townPtr;
if( town_array.selected_recno )
{
townPtr = town_array[town_array.selected_recno];
if( townPtr->nation_recno==nation_array.player_recno &&
townPtr->draw_detect_link_line(1) ) // 1-detect action
{
return 1;
}
}
// ####### begin Gilbert 12/9 #########// see Power::detect_select
/*
//--------------- detect firm ------------------//
if( rc==1 ) // left click
{
int mouseAbsX = mouse.cur_x - ZOOM_X1 + World::view_top_x;
int mouseAbsY = mouse.cur_y - ZOOM_Y1 + World::view_top_y;
int i;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) )
continue;
firmPtr = firm_array[i];
if( m.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
firmPtr->abs_x1, firmPtr->abs_y1, firmPtr->abs_x2, firmPtr->abs_y2 ) )
{
power.reset_selection();
firm_array.selected_recno = i;
info.disp();
// -------- sound effect -----------//
if( firmPtr->nation_recno == nation_array.player_recno && se_res.mark_select_object_time() )
{
se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
'F', firmPtr->firm_id, firmPtr->under_construction ? "SELU" : "SEL" );
}
return 1;
}
}
//----------- detect town section --------------//
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
townPtr = town_array[i];
if( m.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
townPtr->abs_x1, townPtr->abs_y1, townPtr->abs_x2, townPtr->abs_y2 ) )
{
power.reset_selection();
town_array.selected_recno = i;
info.disp();
// -------- sound effect -----------//
if( townPtr->nation_recno == nation_array.player_recno
&& se_res.mark_select_object_time() )
{
se_res.sound(townPtr->center_x, townPtr->center_y, 1,
'T', 0, "SEL" );
}
return 1;
}
}
}
*/
return 0;
}
//-------- End of function World::detect_firm_town ---------//
//-------- Begin of function World::earth_equake ------//
void World::earth_quake()
{
Location *locPtr;
int x,y;
for(y = 0; y < max_y_loc; ++y)
{
locPtr = get_loc(0,y);
for( x = 0; x < max_x_loc; ++x, ++locPtr)
{
if(locPtr->is_wall() )
{
locPtr->attack_wall( weather.quake_rate(x,y) /2 );
}
}
}
int firmDamage = 0;
int firmDie = 0;
int i;
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
continue;
Firm *firmPtr = firm_array[i];
x = firmPtr->center_x;
y = firmPtr->center_y;
firmPtr->hit_points -= weather.quake_rate(x,y);
if( firmPtr->own_firm() )
firmDamage++;
if( firmPtr->hit_points <= 0)
{
firmPtr->hit_points = (float) 0;
if( firmPtr->own_firm() )
firmDie++;
se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
'F', firmPtr->firm_id, "DIE" );
firm_array.del_firm(i);
}
}
int townDamage = 0;
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i) )
continue;
Town *townPtr = town_array[i];
int ownTown = townPtr->nation_recno == nation_array.player_recno;
short beforePopulation = townPtr->population;
short causalty = weather.quake_rate(townPtr->center_x, townPtr->center_y) / 10;
for( ; causalty > 0 && !town_array.is_deleted(i); --causalty )
{
townPtr->kill_town_people(0);
}
if( town_array.is_deleted(i) )
causalty = beforePopulation;
else
causalty = beforePopulation - townPtr->population;
if(ownTown)
townDamage += causalty;
}
int unitDamage = 0;
int unitDie = 0;
for( i=unit_array.size(); i > 0; i-- )
{
if( unit_array.is_deleted(i))
continue;
Unit *unitPtr = unit_array[i];
// ###### begin Gilbert 30/8 ######//
// no damage to air unit , sea unit or overseer
if( !unitPtr->is_visible() || unitPtr->mobile_type == UNIT_AIR
|| unitPtr->mobile_type == UNIT_SEA)
continue;
// ###### end Gilbert 30/8 ######//
float damage = (float) weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc() ) *
unitPtr->max_hit_points / 200;
if( damage >= unitPtr->hit_points)
damage = unitPtr->hit_points -1;
if( damage < (float) 5)
damage = (float) 5;
unitPtr->hit_points -= damage;
if( unitPtr->is_own() )
unitDamage++;
if( unitPtr->hit_points <= 0)
{
unitPtr->hit_points = (float) 0;
if( unitPtr->is_own() )
unitDie++;
}
else
{
if( unit_res[unitPtr->unit_id]->solider_id &&
weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc()) >= 60)
{
((UnitVehicle *)unitPtr)->dismount();
}
}
}
news_array.earthquake_damage(unitDamage-unitDie, unitDie, townDamage, firmDamage-firmDie, firmDie);
}
//-------- End of function World::earth_equake ------//
//-------- Begin of function World::lightning_strike ------//
void World::lightning_strike(short cx, short cy, short radius)
{
short x, y;
for( y = cy-radius; y <= cy+radius; ++y)
{
if( y < 0 || y >= max_y_loc)
continue;
for( x = cx-radius; x <= cx+radius; ++x)
{
if( x < 0 || x >= max_x_loc)
continue;
Location *locPtr = get_loc(x,y);
if( locPtr->is_plant() )
{
// ---- add a fire on it ------//
locPtr->set_fire_str(80);
// ##### begin Gilbert 11/8 #####//
if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
locPtr->set_fire_str(5);
// ##### end Gilbert 11/8 #####//
}
}
}
// ------ check hitting units -------//
int i;
for( i=unit_array.size(); i > 0; i-- )
{
if( unit_array.is_deleted(i))
continue;
Unit *unitPtr = unit_array[i];
// no damage to overseer
if( !unitPtr->is_visible())
continue;
if( unitPtr->cur_x_loc() <= cx+ radius &&
unitPtr->cur_x_loc() + unitPtr->sprite_info->loc_width > cx-radius &&
unitPtr->cur_y_loc() <= cy+radius &&
unitPtr->cur_y_loc() + unitPtr->sprite_info->loc_height > cy-radius )
{
unitPtr->hit_points -= (float) unitPtr->sprite_info->lightning_damage / ATTACK_SLOW_DOWN;
// ---- add news -------//
if( unitPtr->is_own() )
news_array.lightning_damage(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(),
NEWS_LOC_UNIT, i, unitPtr->hit_points <= (float) 0);
if( unitPtr->hit_points <= 0)
unitPtr->hit_points = (float) 0;
}
}
for( i=firm_array.size() ; i>0 ; i-- )
{
if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
continue;
Firm *firmPtr = firm_array[i];
if( firmPtr->loc_x1 <= cx+radius &&
firmPtr->loc_x2 >= cx-radius &&
firmPtr->loc_y1 <= cy+radius &&
firmPtr->loc_y2 >= cy-radius)
{
firmPtr->hit_points -= (float) 50 / ATTACK_SLOW_DOWN;
// ---- add news -------//
if( firmPtr->own_firm() )
news_array.lightning_damage(firmPtr->center_x, firmPtr->center_y,
NEWS_LOC_FIRM, i, firmPtr->hit_points <= (float) 0);
// ---- add a fire on it ------//
Location *locPtr = get_loc(firmPtr->center_x, firmPtr->center_y);
if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
locPtr->set_fire_str(5);
if( firmPtr->hit_points <= 0)
{
firmPtr->hit_points = (float) 0;
se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
'F', firmPtr->firm_id, "DIE" );
firm_array.del_firm(i);
}
}
}
for( i=town_array.size() ; i>0 ; i-- )
{
if( town_array.is_deleted(i))
continue;
Town *townPtr = town_array[i];
if( townPtr->loc_x1 <= cx+radius &&
townPtr->loc_x2 >= cx-radius &&
townPtr->loc_y1 <= cy+radius &&
townPtr->loc_y2 >= cy-radius)
{
// ---- add news -------//
if( townPtr->nation_recno == nation_array.player_recno )
news_array.lightning_damage(townPtr->center_x, townPtr->center_y,
NEWS_LOC_TOWN, i, 0);
// ---- add a fire on it ------//
// ####### begin Gilbert 11/8 #########//
Location *locPtr = get_loc(townPtr->center_x, townPtr->center_y);
if( locPtr->can_set_fire() && locPtr->fire_str() < 5)
locPtr->set_fire_str(5);
// ####### end Gilbert 11/8 #########//
townPtr->kill_town_people(0);
}
}
}
//-------- End of function World::lightning_strike -------//
// ------- Begin of function World::visit -----------//
// set the visit_level surrounding unit, town and firm
void World::visit(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int range, int extend)
{
if(config.fog_of_war)
{
int left = max( 0, xLoc1 - range);
int top = max( 0, yLoc1 - range);
int right = min( MAX_WORLD_X_LOC-1, xLoc2 + range);
int bottom = min( MAX_WORLD_Y_LOC-1, yLoc2 + range);
// ----- mark the visit_level of the square around the unit ------//
for( int yLoc=top ; yLoc<=bottom ; yLoc++ )
{
Location *locPtr = get_loc(left, yLoc);
for( int xLoc=left ; xLoc<=right ; xLoc++, locPtr++ )
{
locPtr->set_visited();
}
}
// ----- visit_level decreasing outside the visible range ------//
if( extend > 0)
{
int visitLevel = FULL_VISIBILITY;
int levelDrop = (FULL_VISIBILITY - EXPLORED_VISIBILITY) / (extend+1);
xLoc1 -= range;
xLoc2 += range;
yLoc1 -= range;
yLoc2 += range;
for( ++range; extend > 0; --extend, ++range)
{
xLoc1--;
xLoc2++;
yLoc1--;
yLoc2++;
visitLevel -= levelDrop;
visit_shell(xLoc1, yLoc1, xLoc2, yLoc2, visitLevel);
}
}
}
}
// ------- End of function World::visit -----------//
// ------- Begin of function World::visit_shell -----------//
// set specific visit_level on the surrounding unit, town and firm
void World::visit_shell(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int visitLevel)
{
int left = max( 0, xLoc1 );
int top = max( 0, yLoc1 );
int right = min( MAX_WORLD_X_LOC-1, xLoc2);
int bottom = min( MAX_WORLD_Y_LOC-1, yLoc2);
// ------- top side ---------//
if( yLoc1 >= 0)
{
Location *locPtr = get_loc( left, yLoc1);
for( int x = left; x <= right; ++x, ++locPtr)
locPtr->set_visited(visitLevel);
}
// ------- bottom side ---------//
if( yLoc2 < max_y_loc)
{
Location *locPtr = get_loc( left, yLoc2);
for( int x = left; x <= right; ++x, ++locPtr)
locPtr->set_visited(visitLevel);
}
// ------- left side -----------//
if( xLoc1 >= 0)
{
for( int y = top; y <= bottom; ++y)
{
get_loc(xLoc1,y)->set_visited(visitLevel);
}
}
// ------- right side -----------//
if( xLoc2 < max_x_loc)
{
for( int y = top; y <= bottom; ++y)
{
get_loc(xLoc2,y)->set_visited(visitLevel);
}
}
}
// ------- End of function World::visit_shell -----------//
//------- Begin of function World::process_visibility -----------//
void World::process_visibility()
{
if( config.fog_of_war )
{
// ###### begin Gilbert 13/10 ########//
//for( int y = 0; y < max_y_loc; ++y)
//{
// Location *locPtr = get_loc(0,y);
// for( int x = 0; x < max_x_loc; ++x, ++locPtr)
// {
// locPtr->dec_visibility();
// }
//}
int count = max_x_loc * max_y_loc;
const int sizeOfLoc = sizeof(Location);
unsigned char *locVisitLevel = &get_loc(0,0)->visit_level;
unsigned char decVisitLevel = EXPLORED_VISIBILITY*2+1;
/* Original Visual C++ assembly code for reference
_asm
{
mov ecx, count
mov ebx, locVisitLevel
mov edx, sizeOfLoc
mov ah, decVisitLevel
process_visit_level_1:
mov al,[ebx]
cmp al,ah // if(al > EXPLORED_VISIBILITY*2) al--;
cmc
sbb al,0
mov [ebx],al
add ebx, edx
loop process_visit_level_1
}
*/
__asm__ __volatile__ (
"movb %0, %%ah\n"
"process_visit_level_1:\n\t"
"movb (%%ebx), %%al\n\t"
"cmpb %%ah, %%al\n\t"
"cmc\n\t"
"sbbb $0, %%al\n\t"
"movb %%al, (%%ebx)\n\t"
"addl %%edx, %%ebx\n\t"
"loop process_visit_level_1\n\t"
:
: "m"(decVisitLevel), "b"(locVisitLevel), "c"(count), "d"(sizeOfLoc)
: "%eax"
);
// ###### end Gilbert 13/10 ########//
}
}
//------- End of function World::process_visibility -----------//
//--------- Begin of function World::disp_next --------//
//
// Display the next object of the same type.
//
// seekDir : -1 - display the previous one in the list.
// 1 - display the next one in the list.
//
// sameNation - whether display the next object of the same
// nation only or of any nation.
//
void World::disp_next(int seekDir, int sameNation)
{
//--- if the selected one is a unit ----//
if( unit_array.selected_recno )
{
int unitRecno = unit_array.selected_recno;
Unit* unitPtr = unit_array[unit_array.selected_recno];
int unitClass = unit_res[unitPtr->unit_id]->unit_class;
int nationRecno = unitPtr->nation_recno;
while(1)
{
if( seekDir < 0 )
{
unitRecno--;
if( unitRecno < 1 )
unitRecno = unit_array.size();
}
else
{
unitRecno++;
if( unitRecno > unit_array.size() )
unitRecno = 1;
}
if( unit_array.is_deleted(unitRecno) )
continue;
unitPtr = unit_array[unitRecno];
if( !unitPtr->is_visible() )
continue;
//--- check if the location of the unit has been explored ---//
if( !world.get_loc(unitPtr->next_x_loc(), unitPtr->next_y_loc())->explored() )
continue;
//-------- if are of the same nation --------//
if( sameNation && unitPtr->nation_recno != nationRecno )
continue;
//---------------------------------//
if( unit_res[unitPtr->unit_id]->unit_class == unitClass )
{
power.reset_selection();
unitPtr->selected_flag = 1;
unit_array.selected_recno = unitRecno;
unit_array.selected_count++;
world.go_loc( unitPtr->cur_x_loc(), unitPtr->cur_y_loc() );
return;
}
//--- if the recno loops back to the starting one ---//
if( unitRecno == unit_array.selected_recno )
break;
}
}
//--- if the selected one is a firm ----//
if( firm_array.selected_recno )
{
int firmRecno = firm_array.selected_recno;
Firm* firmPtr = firm_array[firm_array.selected_recno];
int firmId = firmPtr->firm_id;
int nationRecno = firmPtr->nation_recno;
while(1)
{
if( seekDir < 0 )
{
firmRecno--;
if( firmRecno < 1 )
firmRecno = firm_array.size();
}
else
{
firmRecno++;
if( firmRecno > firm_array.size() )
firmRecno = 1;
}
if( firm_array.is_deleted(firmRecno) )
continue;
firmPtr = firm_array[firmRecno];
//-------- if are of the same nation --------//
if( sameNation && firmPtr->nation_recno != nationRecno )
continue;
//--- check if the location of this firm has been explored ---//
if( !world.get_loc(firmPtr->center_x, firmPtr->center_y)->explored() )
continue;
//---------------------------------//
if( firmPtr->firm_id == firmId )
{
power.reset_selection();
firm_array.selected_recno = firmRecno;
world.go_loc( firmPtr->center_x, firmPtr->center_y );
return;
}
//--- if the recno loops back to the starting one ---//
if( firmRecno == firm_array.selected_recno )
break;
}
}
//--- if the selected one is a town ----//
if( town_array.selected_recno )
{
int townRecno = town_array.selected_recno;
int nationRecno = town_array[townRecno]->nation_recno;
Town* townPtr;
while(1)
{
if( seekDir < 0 )
{
townRecno--;
if( townRecno < 1 )
townRecno = town_array.size();
}
else
{
townRecno++;
if( townRecno > town_array.size() )
townRecno = 1;
}
if( town_array.is_deleted(townRecno) )
continue;
townPtr = town_array[townRecno];
//-------- if are of the same nation --------//
if( sameNation && townPtr->nation_recno != nationRecno )
continue;
//--- check if the location of this town has been explored ---//
if( !world.get_loc(townPtr->center_x, townPtr->center_y)->explored() )
continue;
//---------------------------------//
power.reset_selection();
town_array.selected_recno = townRecno;
world.go_loc( townPtr->center_x, townPtr->center_y );
return;
//--- if the recno loops back to the starting one ---//
if( townRecno == town_array.selected_recno )
break;
}
}
//--- if the selected one is a natural resource site ----//
if( site_array.selected_recno )
{
int siteRecno = site_array.selected_recno;
Site* sitePtr = site_array[site_array.selected_recno];
int siteType = sitePtr->site_type;
while(1)
{
if( seekDir < 0 )
{
siteRecno--;
if( siteRecno < 1 )
siteRecno = site_array.size();
}
else
{
siteRecno++;
if( siteRecno > site_array.size() )
siteRecno = 1;
}
if( site_array.is_deleted(siteRecno) )
continue;
sitePtr = site_array[siteRecno];
//--- check if the location of this site has been explored ---//
if( !world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc)->explored() )
continue;
//---------------------------------//
if( sitePtr->site_type == siteType )
{
power.reset_selection();
site_array.selected_recno = siteRecno;
world.go_loc( sitePtr->map_x_loc, sitePtr->map_y_loc );
return;
}
//--- if the recno loops back to the starting one ---//
if( siteRecno == site_array.selected_recno )
break;
}
}
}
//----------- End of function World::disp_next --------//
#ifdef DEBUG3
//--------- Begin of function World::get_loc --------//
//
Location* World::get_loc(int xLoc, int yLoc)
{
err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
return loc_matrix + MAX_WORLD_X_LOC * yLoc + xLoc;
}
//----------- End of function World::get_loc --------//
//--------- Begin of function World::get_region_id --------//
//
BYTE World::get_region_id(int xLoc, int yLoc)
{
err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
return loc_matrix[MAX_WORLD_X_LOC*yLoc+xLoc].region_id;
}
//----------- End of function World::get_region_id --------//
#endif
// ####### begin Gilbert 25/7 #########//
// return true if any location adjacent to (x,y) is on a particular region
int World::is_adjacent_region(int x, int y, int regionId)
{
if( y > 0 )
{
if( x > 0 )
{
if( get_region_id(x-1,y-1) == regionId )
return 1;
}
if( get_region_id(x,y-1) == regionId )
return 1;
if( x < max_x_loc-1 )
{
if( get_region_id(x+1,y-1) == regionId )
return 1;
}
}
if( x > 0 )
{
if( get_region_id(x-1,y) == regionId )
return 1;
}
if( x < max_x_loc-1 )
{
if( get_region_id(x+1,y) == regionId )
return 1;
}
if( y < max_y_loc-1)
{
if( x > 0 )
{
if( get_region_id(x-1,y+1) == regionId )
return 1;
}
if( get_region_id(x,y+1) == regionId )
return 1;
if( x < max_x_loc-1 )
{
if( get_region_id(x+1,y+1) == regionId )
return 1;
}
}
return 0;
}
// ####### end Gilbert 25/7 #########//