/*
* 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 : OMATRIX.CPP
//Description : Object road direction turn, derived by World, Chain class
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// --------- define constant ----------//
#define DEFAULT_WALL_TIMEOUT 10
#define WALL_DEFENCE 5
#define MIN_WALL_DAMAGE 3
//----------- Begin of function Matrix::init ----------//
//
// winX1,winY1 = the coordination of the win,
// winX2,winY2 including the scroll bar and up,down panel
//
// areaWidth = width and height of the bitmap area
// areaHeight
//
// locWidth = width and height of each location
// locHeight
//
// maxCargoWidth = max. widht of height of cargo
// maxCargoHeight (unit is Loc, not pixel
//
// saveAreaToBuf = whether save the area to a buffer,
// set it true - when the area will be ruined by
// animation
//
void Matrix::init(int winX1, int winY1, int winX2, int winY2, int areaWidth,
int areaHeight, int locWidth, int locHeight, int saveAreaToBuf )
{
err_when(FULL_VISIBILITY != MAX_BRIGHTNESS_ADJUST_DEGREE * 8 + 7);
win_x1 = winX1; // window area,
win_y1 = winY1; // including scroll bar
win_x2 = winX2;
win_y2 = winY2;
image_width = areaWidth;
image_height = areaHeight;
image_x1 = win_x1; // bitmap area only
image_y1 = win_y1;
image_x2 = image_x1+image_width-1;
image_y2 = image_y1+image_height-1;
loc_width = locWidth;
loc_height = locHeight;
//----------------------------------------------//
if( saveAreaToBuf )
save_image_buf = mem_add( sizeof(short)*2 + image_width * image_height ); // 2 for width & height info
else
save_image_buf = NULL;
just_drawn_flag = 0;
//---------------------------------------------//
loc_matrix = NULL;
top_x_loc = 0;
top_y_loc = 0;
cur_x_loc = -1;
cur_y_loc = -1;
}
//------------- End of function Matrix::init -----------//
//----------- Begin of function Matrix::~Matrix ----------//
Matrix::~Matrix()
{
if( save_image_buf )
mem_del( save_image_buf );
if( own_matrix && loc_matrix ) // the matrix is allocated by us
mem_del( loc_matrix );
}
//------------- End of function Matrix::~Matrix -----------//
//----------- Begin of function Matrix::assign_map -----------//
//
// Instead of loading the map file, we can assign a pre-loaded
// map to it.
//
void Matrix::assign_map(Matrix* matrixPtr)
{
own_matrix = 0;
loc_matrix = matrixPtr->loc_matrix;
max_x_loc = matrixPtr->max_x_loc;
max_y_loc = matrixPtr->max_y_loc;
init_var();
top_x_loc = 0;
top_y_loc = 0;
cur_x_loc = 0;
cur_y_loc = 0;
}
//------------- End of function Matrix::assign_map -----------//
//----------- Begin of function Matrix::assign_map -----------//
//
// Instead of loading the map file, we can assign a pre-loaded
// map to it.
//
void Matrix::assign_map(Location* locMatrix, int maxXLoc, int maxYLoc )
{
own_matrix = 0;
loc_matrix = locMatrix;
max_x_loc = maxXLoc;
max_y_loc = maxYLoc;
init_var();
cur_x_loc = 0;
cur_y_loc = 0;
}
//------------- End of function Matrix::assign_map -----------//
//-------- Begin of function Matrix::init_var ---------//
//
// Called by assign_map() & MatrixMap::set_view_map()
//
void Matrix::init_var()
{
disp_x_loc = image_width/loc_width;
if( disp_x_loc > max_x_loc )
disp_x_loc = max_x_loc;
disp_y_loc = image_height/loc_height;
if( disp_y_loc > max_y_loc )
disp_y_loc = max_y_loc;
}
//------------ End of function Matrix::init_var -----------//
//----------- Begin of function Matrix::paint ------------//
//
// Paint world window and scroll bars
//
void Matrix::paint()
{
}
//----------- End of function Matrix::paint ------------//
//---------- Begin of function Matrix::draw ------------//
//
// Draw world zoom
//
void Matrix::draw()
{
int i=0, x, y, xLoc, yLoc;
Location* locPtr;
int maxXLoc = top_x_loc + disp_x_loc; // divide by 2 for world_info
int maxYLoc = top_y_loc + disp_y_loc;
//----------------------------------------------------//
for( y=image_y1,yLoc=top_y_loc ; yLoc whether the window is scrolled
//
int Matrix::valid_cur_box(int callRefresh)
{
int scrolledFlag=0;
//------- valid current highlight box first --------//
if( cur_x_loc < 0 )
cur_x_loc = 0;
if( cur_y_loc < 0 )
cur_y_loc = 0;
if( cur_x_loc+cur_cargo_width > max_x_loc )
cur_x_loc = max_x_loc-cur_cargo_width;
if( cur_y_loc+cur_cargo_height > max_y_loc )
cur_y_loc = max_y_loc-cur_cargo_height;
//--- scroll the display area to fit the current highlight ---//
if( cur_x_loc < top_x_loc ||
cur_x_loc >= top_x_loc + disp_x_loc )
{
top_x_loc = cur_x_loc - disp_x_loc/2;
if( top_x_loc < 0 )
top_x_loc = 0;
if( top_x_loc + disp_x_loc > max_x_loc )
top_x_loc = max_x_loc - disp_x_loc;
scrolledFlag=1;
}
if( cur_y_loc < top_y_loc ||
cur_y_loc >= top_y_loc + disp_y_loc )
{
top_y_loc = cur_y_loc - disp_y_loc/2;
if( top_y_loc < 0 )
top_y_loc = 0;
if( top_y_loc + disp_y_loc > max_y_loc )
top_y_loc = max_y_loc - disp_y_loc;
scrolledFlag=1;
}
return scrolledFlag;
}
//----------- End of function Matrix::valid_cur_box ------------//
//--------- Begin of function Matrix::valid_disp_area ------//
//
// Validate the current location, adjust it if it is out of border
//
// Call valid_cur_box() if current highlight box is specified,
// adjust window area to fit it
//
// Call valid_disp_area() if window display area is specified,
// adjust highlight box to fit it
//
// [int] fitInBox = whether must fit in current box into the
// display area (default : 0)
//
void Matrix::valid_disp_area(int fitInBox)
{
//------- valid display area first ---------//
if( top_x_loc < 0 )
top_x_loc = 0;
if( top_y_loc < 0 )
top_y_loc = 0;
if( top_x_loc + disp_x_loc > max_x_loc )
top_x_loc = max_x_loc - disp_x_loc;
if( top_y_loc + disp_y_loc > max_y_loc )
top_y_loc = max_y_loc - disp_y_loc;
//--- if the current highlighted location is outside the display area, then reposition it ----//
if( fitInBox )
{
if( cur_x_loc < top_x_loc )
cur_x_loc = top_x_loc;
if( cur_x_loc >= top_x_loc + disp_x_loc )
cur_x_loc = top_x_loc + disp_x_loc - 1;
if( cur_y_loc < top_y_loc )
cur_y_loc = top_y_loc;
if( cur_y_loc >= top_y_loc + disp_y_loc )
cur_y_loc = top_y_loc + disp_y_loc - 1;
}
}
//--------- End of function Matrix::valid_disp_area ------//
//---------- Begin of function Matrix::scroll -----------//
//
// xScroll - horizontal scroll step (negative:left, positive:right)
// yScroll - vertical scroll step (negative:left, positive:right)
//
void Matrix::scroll(int xScroll, int yScroll)
{
top_x_loc += xScroll;
top_y_loc += yScroll;
valid_disp_area();
}
//----------- End of function Matrix::scroll ------------//
// ------- Begin of function Location::walkable_reset -----/
void Location::walkable_reset()
{
if( loc_flag & LOCATE_BLOCK_MASK )
{
walkable_off();
}
else
{
if( terrain_res[terrain_id]->average_type == TERRAIN_OCEAN)
{
loc_flag |= LOCATE_WALK_SEA;
}
else
{
loc_flag |= LOCATE_WALK_LAND;
}
}
}
// ----------- End of function Location::walkable_reset -------//
// ----------- Begin of function Location::is_plateau ---------//
int Location::is_plateau()
{
return terrain_res[terrain_id]->average_type == TERRAIN_DARK_DIRT; //**BUGHERE, to be changed to TERRAIN_HILL when the no. of terrain type has been reduced to 4 from 7
}
// ----------- End of function Location::is_plateau ---------//
//---------- Begin of function Location::set_site ------------//
//
void Location::set_site(int siteRecno)
{
err_when( !can_build_site() );
loc_flag = loc_flag & ~LOCATE_SITE_MASK | LOCATE_HAS_SITE;
// loc_flag |= LOCATION_HAS_SITE;
extra_para = siteRecno;
}
//------------ End of function Location::set_site ------------//
//---------- Begin of function Location::remove_site ------------//
//
void Location::remove_site()
{
err_when( !has_site() );
loc_flag &= ~LOCATE_SITE_MASK;
extra_para = 0;
}
//------------ End of function Location::remove_site ------------//
//------------ Begin of function Location::set_wall_timeout ------------//
void Location::set_wall_timeout(int initTimeout)
{
err_when((!can_build_site() && !had_wall()) || initTimeout <= 0);
loc_flag = (loc_flag & ~LOCATE_SITE_MASK) | LOCATE_HAD_WALL;
extra_para = (unsigned char) initTimeout;
}
//------------ End of function Location::set_wall_timeout ------------//
//------------ Begin of function Location::dec_wall_timeout ------------//
// return : true if the timeout drop to zero, and is removed
int Location::dec_wall_timeout(int t)
{
err_when( !had_wall() );
if( (extra_para -= t) <= 0)
{
remove_wall_timeout();
return 1;
}
return 0;
}
//------------ End of function Location::dec_wall_timeout ------------//
//------------ Begin of function Location::remove_wall_timeout ------------//
void Location::remove_wall_timeout()
{
err_when( !had_wall() );
loc_flag &= ~LOCATE_SITE_MASK;
extra_para = 0;
}
//------------ End of function Location::remove_wall_timeout ------------//
//---------- Begin of function Location::set_dirt ------------//
//
void Location::set_dirt(int dirtRecno)
{
err_when( !can_add_dirt() );
loc_flag = loc_flag & ~LOCATE_SITE_MASK | LOCATE_HAS_DIRT;
extra_para = dirtRecno;
}
//------------ End of function Location::set_dirt ------------//
//---------- Begin of function Location::remove_dirt ------------//
//
void Location::remove_dirt()
{
err_when( !has_dirt() );
loc_flag &= ~LOCATE_SITE_MASK;
extra_para = 0;
}
//------------ End of function Location::remove_dirt ------------//
//---------- Begin of function Location::set_firm ------------//
//
void Location::set_firm(int firmRecno)
{
// can't check the terrain type here
err_when( !can_build_firm() && !firmRecno );
walkable_off();
loc_flag = (loc_flag & ~LOCATE_BLOCK_MASK) | LOCATE_IS_FIRM;
cargo_recno = firmRecno;
}
//------------ End of function Location::set_firm ------------//
//---------- Begin of function Location::remove_firm ------------//
//
void Location::remove_firm()
{
err_when( !is_firm() );
loc_flag &= ~LOCATE_BLOCK_MASK;
cargo_recno = 0;
walkable_reset();
err_when(is_firm());
}
//------------ End of function Location::remove_firm ------------//
//---------- Begin of function Location::set_town ------------//
//
void Location::set_town(int townRecno)
{
err_when( !can_build_town() || !townRecno );
walkable_off();
loc_flag = loc_flag & ~LOCATE_BLOCK_MASK | LOCATE_IS_TOWN;
cargo_recno = townRecno;
}
//------------ End of function Location::set_town ------------//
//---------- Begin of function Location::remove_town ------------//
//
void Location::remove_town()
{
err_when( !is_town() );
loc_flag &= ~LOCATE_BLOCK_MASK;
cargo_recno = 0;
walkable_reset();
err_when(is_firm());
}
//------------ End of function Location::remove_town ------------//
//---------- Begin of function Location::set_hill ------------//
// set hillId to hill_id1 (cargo_recno) or hill_id2 (extra_para)
// depend on the priority of the hill block
void Location::set_hill(int hillId)
{
err_when( !can_add_hill() || !hillId );
err_when( !hill_res[hillId] );
// clear LOCATE_WALK_LAND and LOCATE_WALK_SEA bits
walkable_off();
if( has_hill() )
{
// already has a hill block
// compare which is on the top, swap if necessary
if(hill_res[cargo_recno]->priority <= hill_res[hillId]->priority)
{
err_when(cargo_recno >= 256);
extra_para = (unsigned char) cargo_recno;
cargo_recno = hillId;
}
else
{
// if two hill blocks there, the lower one get replaced
err_when( hillId >= 256);
extra_para = (unsigned char) hillId;
}
}
else
{
// no existing hill block
loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
| (LOCATE_IS_HILL | LOCATE_SITE_RESERVED);
cargo_recno = hillId;
extra_para = 0;
}
}
//------------ End of function Location::set_hill ------------//
//---------- Begin of function Location::remove_hill ------------//
void Location::remove_hill()
{
err_when( !has_hill() );
loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
extra_para = 0;
cargo_recno = 0;
// err_when(is_firm());
// BUGHERE : need to call walkable_reset();
}
//------------ End of function Location::remove_hill ------------//
//---------- Begin of function Location::set_wall ------------//
//
// wallId = the id. of the wall
// townRecno = recno of the town which the wall belongs to
// hitPoints = hit points remained for the wall
//
void Location::set_wall(int wallId, int townRecno, int hitPoints)
{
err_when( !can_build_wall() || !wallId );
walkable_off();
loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
| (LOCATE_IS_WALL | LOCATE_SITE_RESERVED);
extra_para = wallId;
cargo_recno = (hitPoints<<8) + townRecno;
}
//------------ End of function Location::set_wall ------------//
//------------ Begin of function Location::set_wall_creating ------------//
void Location::set_wall_creating()
{
err_when( !is_wall() );
int hp = wall_hit_point();
if( hp < 0)
hp = -hp;
cargo_recno = (hp << 8) | wall_town_recno();
}
//------------ End of function Location::set_wall_creating ------------//
//------------ Begin of function Location::set_wall_destructing------------//
void Location::set_wall_destructing()
{
err_when( !is_wall() );
int hp = wall_hit_point();
if( hp > 0)
hp = -hp;
cargo_recno = (hp << 8) | wall_town_recno();
}
//------------ End of function Location::set_wall_desctructing ------------//
//------------ Begin of function Location::inc_wall_hit_point ------------//
int Location::inc_wall_hit_point(int grow)
{
err_when( !is_wall() );
int hp = wall_hit_point();
if( hp < 0 && hp > -grow)
{
hp = 0;
}
else if( hp > 100-grow)
{
hp = 100;
}
else
hp += grow;
cargo_recno = (hp << 8) | wall_town_recno();
return hp;
}
//------------ End of function Location::inc_wall_hit_point ------------//
//------------ Begin of function Location::attack_wall ------------//
//
// attack wall
// int damage damage to a wall
// note : if the return value is 0, call world.correct_wall to
// correct the shape of the adjacent squares
//
int Location::attack_wall(int damage)
{
err_when( !is_wall() );
if(damage >= WALL_DEFENCE + MIN_WALL_DAMAGE) // damage >= 8, damage -= 5
damage -= WALL_DEFENCE;
else if( damage >= MIN_WALL_DAMAGE ) // 3 <= damage < 8, damage = 3
damage = MIN_WALL_DAMAGE;
else if( damage <= 0) // 0 < damage < 3, no change to
return wall_hit_point(); // no change to hit point to damage
int hp = wall_hit_point();
if( hp > 0)
{
hp-= damage;
if( hp <= 0)
{
hp = 0;
remove_wall();
return 0;
}
}
else if( hp < 0)
{
hp+= damage;
if( hp >= 0)
{
hp = 0;
remove_wall();
return 0;
}
}
cargo_recno = (hp << 8) | wall_town_recno();
return hp;
}
//------------ End of function Location::attack_wall ------------//
//---------- Begin of function Location::remove_wall ------------//
//
// setTimeOut call set_wall_timeout to refuse building wall at the same place
// 0 to disable timeout, -1 to take default: 10
//
void Location::remove_wall(int setTimeOut)
{
err_when( !is_wall() );
loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
extra_para = 0;
cargo_recno = 0;
walkable_reset();
if( setTimeOut < 0)
set_wall_timeout( DEFAULT_WALL_TIMEOUT );
else if( setTimeOut > 0)
{
err_when( setTimeOut > 255 );
set_wall_timeout( setTimeOut );
}
err_when(is_firm());
}
//------------ End of function Location::remove_wall ------------//
//---------- Begin of function Location::set_plant ------------//
//
void Location::set_plant(int plantId, int offsetX, int offsetY)
{
err_when( !can_add_plant() || !plantId );
walkable_off();
loc_flag = loc_flag & ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK )
| (LOCATE_IS_PLANT | LOCATE_SITE_RESERVED);
extra_para = plantId;
cargo_recno = (offsetY<<8) + offsetX;
err_when(cargo_recno==0 || is_firm());
}
//------------ End of function Location::set_plant ------------//
//---------- Begin of function Location::remove_plant ------------//
//
void Location::remove_plant()
{
err_when( !is_plant() );
loc_flag &= ~(LOCATE_BLOCK_MASK | LOCATE_SITE_MASK);
extra_para = 0;
cargo_recno = 0;
walkable_reset();
err_when(is_firm());
}
//------------ End of function Location::remove_plant ------------//
//---------- Begin of function Location::set_rock ------------//
//
void Location::set_rock(short rockArrayRecno)
{
err_when( !can_add_rock(3) || !rockArrayRecno );
walkable_off();
loc_flag = loc_flag & ~LOCATE_BLOCK_MASK | LOCATE_IS_ROCK;
cargo_recno = rockArrayRecno;
}
//------------ End of function Location::set_rock ------------//
//---------- Begin of function Location::remove_rock ------------//
//
void Location::remove_rock()
{
err_when( !is_rock() );
loc_flag &= ~LOCATE_BLOCK_MASK;
cargo_recno = 0;
walkable_reset();
}
//------------ End of function Location::remove_rock ------------//
//-------- Begin of function Location::has_unit --------//
// return 0 or unit recno
int Location::has_unit(int mobileType)
{
switch(mobileType)
{
// #### patch begin Gilbert 5/8 #######//
case UNIT_LAND:
if( walkable() )
return cargo_recno;
break;
case UNIT_SEA:
if( sailable() )
return cargo_recno;
break;
case UNIT_AIR:
return air_cargo_recno;
break;
// #### patch end Gilbert 5/8 #######//
}
return 0;
}
//-------- End of function Location::has_unit --------//
//-------- Begin of function Location::has_any_unit --------//
// mobileType - (default: UNIT_LAND)
//
// return the mobile_type if there is any unit here
// return 0 otherwise
//
int Location::has_any_unit(int mobileType)
{
if(mobileType==UNIT_LAND)
{
if(air_cargo_recno)
return UNIT_AIR;
else if(walkable() && cargo_recno)
return UNIT_LAND;
else if(sailable() && cargo_recno)
return UNIT_SEA;
}
else
{
if(walkable() && cargo_recno)
return UNIT_LAND;
else if(sailable() && cargo_recno)
return UNIT_SEA;
else if(air_cargo_recno)
return UNIT_AIR;
}
return 0;
}
//-------- End of function Location::has_any_unit --------//
//-------- Begin of function Location::get_any_unit --------//
//
// mobileType - var for returning the mobile type of
// unit in the location.
//
// return: unit recno of the unit.
//
int Location::get_any_unit(int& mobileType)
{
if(air_cargo_recno)
{
mobileType = UNIT_AIR;
return air_cargo_recno;
}
else if(walkable() && cargo_recno)
{
mobileType = UNIT_LAND;
return cargo_recno;
}
else if(sailable() && cargo_recno)
{
mobileType = UNIT_SEA;
return cargo_recno;
}
return 0;
}
//-------- End of function Location::get_any_unit --------//
//-------- Begin of function Location::is_unit_group_accessible --------//
//
// Return whether the location can be accessed by the unit of the specific
// unit group id.
//
// return : whether the location can be accessed by the unit of
// the specific unit group id.
//
int Location::is_unit_group_accessible(int mobileType, DWORD curGroupId)
{
if(is_accessible(mobileType))
{
int unitRecno = unit_recno(mobileType);
return unitRecno==0 || unit_array[unitRecno]->unit_group_id == curGroupId;
}
return 0;
}
//-------- End of function Location::is_unit_group_accessible --------//
//### begin alex 24/6 ###//
//-------- Begin of function Location::set_power_on --------//
void Location::set_power_on()
{
loc_flag &= ~LOCATE_POWER_OFF;
}
//-------- End of function Location::set_power_on --------//
//-------- Begin of function Location::set_power_off --------//
void Location::set_power_off()
{
loc_flag |= LOCATE_POWER_OFF;
}
//-------- End of function Location::set_power_off --------//
//-------- Begin of function Location::is_power_off --------//
int Location::is_power_off()
{
return (loc_flag & LOCATE_POWER_OFF);
}
//-------- End of function Location::is_power_off --------//
//#### end alex 24/6 ####//