/*
* 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 : OW_FIRE.CPP
// Description: World class function related to spreading of fire
// Ownership : Gilbert
#include
#include
#include
#include
#include
#include
#include
#include
#include
// #### begin Gilbert 29/5 #######//
#include
// #### end Gilbert 29/5 #######//
#include
//### begin alex 6/8 ###//
#ifdef DEBUG
#include
#endif
//#### end alex 6/8 ####//
//------------ define constant ------------
#define SPREAD_RATE (config.fire_spread_rate)
// #define CONSUMPTION_RATE 1.0
#define WIND_SPREADFIRE (config.wind_spread_fire_rate)
#define FIRE_FADE_RATE (config.fire_fade_rate)
// 0 - 100
#define RESTORE_RATE (config.fire_restore_prob)
// 0 - 20
#define RAIN_SNOW_REDUCTION (config.rain_reduce_fire_rate)
// ----------- Define static function ----------//
static char bound_zero(char n)
{
if( n > 0)
return n;
return 0;
}
// ---------- Level of Location::fire_str() ---------//
// 51 to 100 Highly flammable, restorable
// 1 to 50 flammable, restorable
// -30 to 0 flammable but the fire cannot grow, or spreaded, restorable
// -50 to -31 flammable but the fire cannot grow, flammability unrestorable
// -100 to -51 absolutely non-inflammable
// ----------- begin of function World::init_fire ---------- //
void World::init_fire()
{
Location *locPtr = get_loc(0,0);
for( int c = max_x_loc*max_y_loc; c >0; --c, ++locPtr)
{
if( locPtr->has_hill())
{
locPtr->set_fire_src(-100);
}
else if( locPtr->is_wall() )
{
locPtr->set_fire_src(-50);
}
else if( locPtr->is_firm() || locPtr->is_plant() || locPtr->is_town() )
{
locPtr->set_fire_src(100);
}
else
{
switch(terrain_res[locPtr->terrain_id]->average_type)
{
case TERRAIN_OCEAN:
locPtr->set_fire_src(-100);
break;
case TERRAIN_DARK_GRASS:
locPtr->set_fire_src(100);
break;
case TERRAIN_LIGHT_GRASS:
locPtr->set_fire_src(50);
break;
case TERRAIN_DARK_DIRT:
locPtr->set_fire_src(-50);
break;
default:
err_now("Undefined terrain type");
}
}
// --------- put off fire on the map ----------//
locPtr->set_fire_str(-100);
}
}
// ----------- end of function World::init_fire ---------- //
// ----------- begin of function World::spread_fire ---------- //
void World::spread_fire(Weather &w)
{
char fireValue;
int x,y;
Location *locPtr;
// -------- normalize wind_speed between -WIND_SPREADFIRE*SPREAD_RATE to +WIND_SPREADFIRE*SPREAD_RATE -------
int windCos = int(w.wind_speed() * cos(w.wind_direct_rad()) / 100.0 * SPREAD_RATE * WIND_SPREADFIRE);
int windSin = int(w.wind_speed() * sin(w.wind_direct_rad()) / 100.0 * SPREAD_RATE * WIND_SPREADFIRE);
char rainSnowReduction = 0;
rainSnowReduction = (w.rain_scale() > 0 || w.snow_scale() > 0) ?
RAIN_SNOW_REDUCTION + (w.rain_scale() + w.snow_scale()) / 4: 0;
float flameDamage = (float)config.fire_damage/ATTACK_SLOW_DOWN;
// -------------update fire_level-----------
for( y = scan_fire_y; y < max_y_loc; y += SCAN_FIRE_DIST)
{
locPtr = get_loc(scan_fire_x,y);
for( x = scan_fire_x; x < max_x_loc; x += SCAN_FIRE_DIST, locPtr+=SCAN_FIRE_DIST)
{
char oldFireValue = fireValue = locPtr->fire_str();
char flammability = locPtr->fire_src();
// ------- reduce fire_level on raining or snow
fireValue -= rainSnowReduction;
if(fireValue < -100)
fireValue = -100;
if( fireValue > 0)
{
Unit *targetUnit;
// ------- burn wall -------- //
if( locPtr->is_wall() )
{
if( !locPtr->attack_wall(int(4.0*flameDamage)))
correct_wall(x, y, 2);
}
// ------- burn units ---------//
else if( locPtr->has_unit(UNIT_LAND))
{
targetUnit = unit_array[locPtr->unit_recno(UNIT_LAND)];
targetUnit->hit_points -= (float)2.0*flameDamage;
if( targetUnit->hit_points <= 0 )
targetUnit->hit_points = (float) 0;
}
else if( locPtr->has_unit(UNIT_SEA))
{
targetUnit = unit_array[locPtr->unit_recno(UNIT_SEA)];
targetUnit->hit_points -= (float)2.0*flameDamage;
if( targetUnit->hit_points <= 0 )
targetUnit->hit_points = (float) 0;
}
else if( locPtr->is_firm() && firm_res[firm_array[locPtr->firm_recno()]->firm_id]->buildable)
{
Firm *targetFirm = firm_array[locPtr->firm_recno()];
//### begin alex 6/8 ###//
#ifdef DEBUG
if(debug_sim_game_type!=2)
#endif
//#### end alex 6/8 ####//
targetFirm->hit_points -= flameDamage;
if( targetFirm->hit_points <= 0)
{
targetFirm->hit_points = (float) 0;
// ###### begin Gilbert 29/5 ########//
se_res.sound(targetFirm->center_x, targetFirm->center_y, 1,
'F', targetFirm->firm_id, "DIE" );
// ###### end Gilbert 29/5 ########//
firm_array.del_firm(locPtr->firm_recno());
}
}
if(SPREAD_RATE > 0)
{
Location *sidePtr;
// spread of north square
if( y>0 && (sidePtr = get_loc(x,y-1))->fire_src() >0
&& sidePtr->fire_str() <= 0)
{
sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE+windCos)));
}
// spread of south square
if( yfire_src() >0
&& sidePtr->fire_str() <= 0)
{
sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE-windCos)));
}
// spread of east square
if( xfire_src() >0
&& sidePtr->fire_str() <= 0)
{
sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE+windSin)));
}
// spread of west square
if( x>0 && (sidePtr = get_loc(x-1,y))->fire_src() >0
&& sidePtr->fire_str() <= 0)
{
sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE-windSin)));
}
}
if( flammability > 0)
{
// increase fire_level on its own
if(++fireValue > 100)
fireValue = 100;
flammability -= FIRE_FADE_RATE;
// if a plant on it then remove the plant, if flammability <= 0
if( locPtr->is_plant() && flammability <= 0)
{
locPtr->remove_plant();
plant_count--;
}
}
else
{
// fireValue > 0, flammability < 0
// putting of fire
if( flammability >= -30)
{
fireValue-=2;
flammability -= FIRE_FADE_RATE;
if( flammability < -30)
flammability = -30;
}
else if (flammability >= -50)
{
fireValue-=2;
flammability -= FIRE_FADE_RATE;
if( flammability < -50)
flammability = -50;
}
else
{
fireValue = -100;
flammability -= FIRE_FADE_RATE;
if( flammability < -100)
flammability = -100;
}
// if a plant on it then remove the plant, if flammability <= 0
if( locPtr->is_plant() && flammability <= 0)
{
locPtr->remove_plant();
plant_count--;
}
}
}
else
{
// fireValue < 0
// ---------- fire_level drop slightly ----------
if( fireValue > -100)
fireValue--;
// ---------- restore flammability ------------
if( flammability >= -30 && flammability < 50 &&
m.random(100) < RESTORE_RATE)
flammability++;
}
// ---------- update new fire level -----------
//-------- when fire is put off
// so the fire will not light again very soon
if(fireValue <= 0 && oldFireValue > 0)
{
fireValue -= 50;
}
locPtr->set_fire_str(fireValue);
locPtr->set_fire_src(flammability);
}
}
}
//----------- end of function World::spread_fire ---------- //
//----------- begin of function World::setup_fire ---------- //
//
// set a fire at location x, y
// fireStrength is between 1 - 100, (default: 30)
//
void World::setup_fire(short x, short y, char fireStrength)
{
err_when( x < 0 || y < 0 || x >= max_x_loc || y >= max_y_loc);
err_when(fireStrength < 0 || fireStrength > 100);
Location *locPtr = get_loc(x, y);
if( locPtr->fire_str() < fireStrength )
{
locPtr->set_fire_str(fireStrength);
}
}
// ----------- end of function World::setup_fire ---------- //