1 /*
2 * Seven Kingdoms: Ancient Adversaries
3 *
4 * Copyright 1997,1998 Enlight Software Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 // Filename : OW_FIRE.CPP
22 // Description: World class function related to spreading of fire
23 // Ownership : Gilbert
24
25
26 #include <OWORLD.h>
27 #include <OMATRIX.h>
28 #include <OWEATHER.h>
29 #include <OWORLDMT.h>
30 #include <OTERRAIN.h>
31 #include <OUNIT.h>
32 #include <OFIRM.h>
33 #include <OFIRMA.h>
34 #include <OCONFIG.h>
35 // #### begin Gilbert 29/5 #######//
36 #include <OSERES.h>
37 // #### end Gilbert 29/5 #######//
38 #include <math.h>
39 //### begin alex 6/8 ###//
40 #ifdef DEBUG
41 #include <OSYS.h>
42 #endif
43 //#### end alex 6/8 ####//
44
45
46 //------------ define constant ------------
47 #define SPREAD_RATE (config.fire_spread_rate)
48 // #define CONSUMPTION_RATE 1.0
49 #define WIND_SPREADFIRE (config.wind_spread_fire_rate)
50 #define FIRE_FADE_RATE (config.fire_fade_rate)
51
52 // 0 - 100
53 #define RESTORE_RATE (config.fire_restore_prob)
54
55 // 0 - 20
56 #define RAIN_SNOW_REDUCTION (config.rain_reduce_fire_rate)
57
58
59 // ----------- Define static function ----------//
bound_zero(char n)60 static char bound_zero(char n)
61 {
62 if( n > 0)
63 return n;
64 return 0;
65 }
66
67 // ---------- Level of Location::fire_str() ---------//
68 // 51 to 100 Highly flammable, restorable
69 // 1 to 50 flammable, restorable
70 // -30 to 0 flammable but the fire cannot grow, or spreaded, restorable
71 // -50 to -31 flammable but the fire cannot grow, flammability unrestorable
72 // -100 to -51 absolutely non-inflammable
73
74 // ----------- begin of function World::init_fire ---------- //
init_fire()75 void World::init_fire()
76 {
77 Location *locPtr = get_loc(0,0);
78 for( int c = max_x_loc*max_y_loc; c >0; --c, ++locPtr)
79 {
80 if( locPtr->has_hill())
81 {
82 locPtr->set_fire_src(-100);
83 }
84 else if( locPtr->is_wall() )
85 {
86 locPtr->set_fire_src(-50);
87 }
88 else if( locPtr->is_firm() || locPtr->is_plant() || locPtr->is_town() )
89 {
90 locPtr->set_fire_src(100);
91 }
92 else
93 {
94 switch(terrain_res[locPtr->terrain_id]->average_type)
95 {
96 case TERRAIN_OCEAN:
97 locPtr->set_fire_src(-100);
98 break;
99 case TERRAIN_DARK_GRASS:
100 locPtr->set_fire_src(100);
101 break;
102 case TERRAIN_LIGHT_GRASS:
103 locPtr->set_fire_src(50);
104 break;
105 case TERRAIN_DARK_DIRT:
106 locPtr->set_fire_src(-50);
107 break;
108 default:
109 err_now("Undefined terrain type");
110 }
111 }
112 // --------- put off fire on the map ----------//
113 locPtr->set_fire_str(-100);
114 }
115 }
116 // ----------- end of function World::init_fire ---------- //
117
118
119 // ----------- begin of function World::spread_fire ---------- //
spread_fire(Weather & w)120 void World::spread_fire(Weather &w)
121 {
122
123 char fireValue;
124 int x,y;
125 Location *locPtr;
126
127 // -------- normalize wind_speed between -WIND_SPREADFIRE*SPREAD_RATE to +WIND_SPREADFIRE*SPREAD_RATE -------
128 int windCos = int(w.wind_speed() * cos(w.wind_direct_rad()) / 100.0 * SPREAD_RATE * WIND_SPREADFIRE);
129 int windSin = int(w.wind_speed() * sin(w.wind_direct_rad()) / 100.0 * SPREAD_RATE * WIND_SPREADFIRE);
130 char rainSnowReduction = 0;
131
132 rainSnowReduction = (w.rain_scale() > 0 || w.snow_scale() > 0) ?
133 RAIN_SNOW_REDUCTION + (w.rain_scale() + w.snow_scale()) / 4: 0;
134
135 float flameDamage = (float)config.fire_damage/ATTACK_SLOW_DOWN;
136
137 // -------------update fire_level-----------
138 for( y = scan_fire_y; y < max_y_loc; y += SCAN_FIRE_DIST)
139 {
140 locPtr = get_loc(scan_fire_x,y);
141 for( x = scan_fire_x; x < max_x_loc; x += SCAN_FIRE_DIST, locPtr+=SCAN_FIRE_DIST)
142 {
143 char oldFireValue = fireValue = locPtr->fire_str();
144 char flammability = locPtr->fire_src();
145
146
147 // ------- reduce fire_level on raining or snow
148 fireValue -= rainSnowReduction;
149 if(fireValue < -100)
150 fireValue = -100;
151
152 if( fireValue > 0)
153 {
154 Unit *targetUnit;
155
156 // ------- burn wall -------- //
157 if( locPtr->is_wall() )
158 {
159 if( !locPtr->attack_wall(int(4.0*flameDamage)))
160 correct_wall(x, y, 2);
161 }
162 // ------- burn units ---------//
163 else if( locPtr->has_unit(UNIT_LAND))
164 {
165 targetUnit = unit_array[locPtr->unit_recno(UNIT_LAND)];
166 targetUnit->hit_points -= (float)2.0*flameDamage;
167 if( targetUnit->hit_points <= 0 )
168 targetUnit->hit_points = (float) 0;
169 }
170 else if( locPtr->has_unit(UNIT_SEA))
171 {
172 targetUnit = unit_array[locPtr->unit_recno(UNIT_SEA)];
173 targetUnit->hit_points -= (float)2.0*flameDamage;
174 if( targetUnit->hit_points <= 0 )
175 targetUnit->hit_points = (float) 0;
176 }
177 else if( locPtr->is_firm() && firm_res[firm_array[locPtr->firm_recno()]->firm_id]->buildable)
178 {
179 Firm *targetFirm = firm_array[locPtr->firm_recno()];
180 //### begin alex 6/8 ###//
181 #ifdef DEBUG
182 if(debug_sim_game_type!=2)
183 #endif
184 //#### end alex 6/8 ####//
185 targetFirm->hit_points -= flameDamage;
186 if( targetFirm->hit_points <= 0)
187 {
188 targetFirm->hit_points = (float) 0;
189 // ###### begin Gilbert 29/5 ########//
190 se_res.sound(targetFirm->center_x, targetFirm->center_y, 1,
191 'F', targetFirm->firm_id, "DIE" );
192 // ###### end Gilbert 29/5 ########//
193 firm_array.del_firm(locPtr->firm_recno());
194 }
195 }
196
197 if(SPREAD_RATE > 0)
198 {
199
200 Location *sidePtr;
201 // spread of north square
202 if( y>0 && (sidePtr = get_loc(x,y-1))->fire_src() >0
203 && sidePtr->fire_str() <= 0)
204 {
205 sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE+windCos)));
206 }
207
208 // spread of south square
209 if( y<max_y_loc-1 && (sidePtr = get_loc(x,y+1))->fire_src() >0
210 && sidePtr->fire_str() <= 0)
211 {
212 sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE-windCos)));
213 }
214
215 // spread of east square
216 if( x<max_x_loc-1 && (sidePtr = get_loc(x+1,y))->fire_src() >0
217 && sidePtr->fire_str() <= 0)
218 {
219 sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE+windSin)));
220 }
221
222 // spread of west square
223 if( x>0 && (sidePtr = get_loc(x-1,y))->fire_src() >0
224 && sidePtr->fire_str() <= 0)
225 {
226 sidePtr->add_fire_str(bound_zero(char(SPREAD_RATE-windSin)));
227 }
228 }
229
230 if( flammability > 0)
231 {
232 // increase fire_level on its own
233 if(++fireValue > 100)
234 fireValue = 100;
235
236 flammability -= FIRE_FADE_RATE;
237 // if a plant on it then remove the plant, if flammability <= 0
238 if( locPtr->is_plant() && flammability <= 0)
239 {
240 locPtr->remove_plant();
241 plant_count--;
242 }
243
244 }
245 else
246 {
247 // fireValue > 0, flammability < 0
248 // putting of fire
249 if( flammability >= -30)
250 {
251 fireValue-=2;
252 flammability -= FIRE_FADE_RATE;
253 if( flammability < -30)
254 flammability = -30;
255 }
256 else if (flammability >= -50)
257 {
258 fireValue-=2;
259 flammability -= FIRE_FADE_RATE;
260 if( flammability < -50)
261 flammability = -50;
262 }
263 else
264 {
265 fireValue = -100;
266 flammability -= FIRE_FADE_RATE;
267 if( flammability < -100)
268 flammability = -100;
269 }
270
271 // if a plant on it then remove the plant, if flammability <= 0
272 if( locPtr->is_plant() && flammability <= 0)
273 {
274 locPtr->remove_plant();
275 plant_count--;
276 }
277 }
278 }
279 else
280 {
281 // fireValue < 0
282 // ---------- fire_level drop slightly ----------
283 if( fireValue > -100)
284 fireValue--;
285
286 // ---------- restore flammability ------------
287 if( flammability >= -30 && flammability < 50 &&
288 misc.random(100) < RESTORE_RATE)
289 flammability++;
290 }
291
292 // ---------- update new fire level -----------
293 //-------- when fire is put off
294 // so the fire will not light again very soon
295 if(fireValue <= 0 && oldFireValue > 0)
296 {
297 fireValue -= 50;
298 }
299
300 locPtr->set_fire_str(fireValue);
301 locPtr->set_fire_src(flammability);
302 }
303 }
304 }
305 //----------- end of function World::spread_fire ---------- //
306
307
308 //----------- begin of function World::setup_fire ---------- //
309 //
310 // set a fire at location x, y
311 // fireStrength is between 1 - 100, (default: 30)
312 //
setup_fire(short x,short y,char fireStrength)313 void World::setup_fire(short x, short y, char fireStrength)
314 {
315 err_when( x < 0 || y < 0 || x >= max_x_loc || y >= max_y_loc);
316 err_when(fireStrength < 0 || fireStrength > 100);
317
318 Location *locPtr = get_loc(x, y);
319 if( locPtr->fire_str() < fireStrength )
320 {
321 locPtr->set_fire_str(fireStrength);
322 }
323 }
324 // ----------- end of function World::setup_fire ---------- //
325
326