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 : OTORNADO.CPP
22 //Description : Object Tornado
23 //Ownership : Gilbert
24
25 #include <OSYS.h>
26 #include <OVGA.h>
27 #include <OUNIT.h>
28 #include <OTORNADO.h>
29 #include <OWORLD.h>
30 #include <OWEATHER.h>
31 #include <math.h>
32 #include <OFIRM.h>
33 #include <OFIRMA.h>
34 #include <OSERES.h>
35 #include <OTOWN.h>
36
37
38 #define PI 3.141592654
39 #define DAMAGE_POINT_RADIUS 32
40
41 #define TORNADO_SPRITE_ID 12 // Tornado sprite in SPRITE.DBF
42
43
44 //--------- Begin of function Tornado::init ---------//
45 //
46 // <short> startX, startY starting location of the tornado
47 // <short> lifeTime time (no. of frames) the tornado survive
48 //
init(short startX,short startY,short lifeTime)49 void Tornado::init(short startX, short startY, short lifeTime)
50 {
51 Sprite::init(TORNADO_SPRITE_ID, startX, startY);
52 err_when( strcmp("TORNADO", sprite_info->sprite_code ) );
53
54 attack_damage = (float) 2.0 / ATTACK_SLOW_DOWN;
55 life_time = lifeTime;
56
57 set_dir(DIR_N);
58 cur_action = SPRITE_MOVE; // always moving
59 dmg_offset_x = 0;
60 dmg_offset_y = 0;
61 }
62 //----------- End of function Tornado::init -----------//
63
64 //----------- Begin of function Tornado::pre_process ----------//
pre_process()65 void Tornado::pre_process()
66 {
67 double angle = misc.random(32) / 16.0 * PI;
68 dmg_offset_x = short(DAMAGE_POINT_RADIUS * sin(angle));
69 dmg_offset_y = short(DAMAGE_POINT_RADIUS * cos(angle));
70 if( --life_time <= 0)
71 cur_action = SPRITE_DIE;
72 }
73 //----------- End of function Tornado::pre_process ----------//
74
75 //--------- Begin of function Tornado::process_move --------//
76
process_move()77 void Tornado::process_move()
78 {
79 int speed = weather.wind_speed() / 6;
80 int minSpeed = magic_weather.wind_day > 0 ? 1 : 5;
81 if( speed < minSpeed)
82 speed = minSpeed;
83 if( speed > 10)
84 speed = 10;
85
86 double windDir = weather.wind_direct_rad() + (misc.random(31)-15)*PI/180.0;
87 cur_x += short(speed * sin(windDir));
88 cur_y -= short(speed * cos(windDir));
89 if( ++cur_frame > cur_sprite_move()->frame_count )
90 cur_frame = 1;
91 // static UCHAR nextFrame[] = { 1,6,1,1,1,1,4 }; // 1->6->4->1 ...
92 // cur_frame = nextFrame[cur_frame];
93
94 hit_target();
95 }
96 //---------- End of function Tornado::process_move ----------//
97
98
99 //--------- Begin of function Tornado::hit_target --------//
100
hit_target()101 void Tornado::hit_target()
102 {
103 //---- check if there is any unit in the target location ----//
104
105 short damageXLoc = damage_x_loc();
106 short damageYLoc = damage_y_loc();
107 if( damageXLoc < 0 || damageXLoc >= world.max_x_loc ||
108 damageYLoc < 0 || damageYLoc >= world.max_y_loc)
109 return;
110
111 Location *locPtr = world.get_loc(damageXLoc, damageYLoc);
112
113 Unit *targetUnit;
114 if( locPtr->has_unit(UNIT_AIR))
115 {
116 targetUnit = unit_array[locPtr->unit_recno(UNIT_AIR)];
117 targetUnit->hit_points -= 2*attack_damage;
118 if( targetUnit->hit_points <= 0)
119 targetUnit->hit_points = (float) 0;
120 }
121
122 if( locPtr->has_unit(UNIT_LAND))
123 {
124 targetUnit = unit_array[locPtr->unit_recno(UNIT_LAND)];
125 targetUnit->hit_points -= attack_damage;
126 if( targetUnit->hit_points <= 0)
127 targetUnit->hit_points = (float) 0;
128 }
129 else if( locPtr->has_unit(UNIT_SEA))
130 {
131 targetUnit = unit_array[locPtr->unit_recno(UNIT_SEA)];
132 targetUnit->hit_points -= attack_damage;
133 if( targetUnit->hit_points <= 0)
134 targetUnit->hit_points = (float) 0;
135 }
136 else
137 {
138 hit_building(); // pass to hit_building to check whether a building is in the location
139 }
140
141 hit_plant();
142 hit_fire();
143 }
144 //---------- End of function Tornado::hit_target ----------//
145
146
147 //------- Begin of function Tornado::hit_building -----//
148 // building means firm or town
149 //
hit_building()150 void Tornado::hit_building()
151 {
152 short damageXLoc = damage_x_loc();
153 short damageYLoc = damage_y_loc();
154 if( damageXLoc < 0 || damageXLoc >= world.max_x_loc ||
155 damageYLoc < 0 || damageYLoc >= world.max_y_loc)
156 return;
157
158 Location* locPtr = world.get_loc(damageXLoc, damageYLoc);
159
160 // ##### begin Gilbert 30/10 #####//
161 if(locPtr->is_firm() )
162 // && firm_res[(firmPtr=firm_array[locPtr->firm_recno()])->firm_id]->buildable )
163 {
164 Firm *firmPtr = firm_array[locPtr->firm_recno()];
165 firmPtr->hit_points -= attack_damage*2;
166 if( firmPtr->hit_points <= 0)
167 {
168 firmPtr->hit_points = (float) 0;
169
170 se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
171 'F', firmPtr->firm_id, "DIE" );
172
173 firm_array.del_firm(locPtr->firm_recno());
174 }
175 }
176
177 if( locPtr->is_town() )
178 {
179 Town *townPtr = town_array[locPtr->town_recno()];
180 if( (life_time % 30) == 0 )
181 townPtr->kill_town_people(0);
182 }
183 // ##### end Gilbert 30/10 #####//
184 }
185 //---------- End of function Tornado::hit_building ----------//
186
187
188 //---------- Begin of function Tornado::hit_plant --------//
hit_plant()189 void Tornado::hit_plant()
190 {
191 short damageXLoc = damage_x_loc();
192 short damageYLoc = damage_y_loc();
193 if( damageXLoc < 0 || damageXLoc >= world.max_x_loc ||
194 damageYLoc < 0 || damageYLoc >= world.max_y_loc)
195 return;
196
197 Location *locPtr = world.get_loc(damageXLoc, damageYLoc);
198 if(locPtr->is_plant())
199 {
200 locPtr->remove_plant();
201 // ###### begin Gilbert 24/6 ########//
202 world.plant_count--;
203 // ###### end Gilbert 24/6 ########//
204 }
205 }
206 //---------- End of function Tornado::hit_plant --------//
207
208
209 //---------- Begin of function Tornado::hit_fire --------//
hit_fire()210 void Tornado::hit_fire()
211 {
212 short damageXLoc = damage_x_loc();
213 short damageYLoc = damage_y_loc();
214 if( damageXLoc < 0 || damageXLoc >= world.max_x_loc ||
215 damageYLoc < 0 || damageYLoc >= world.max_y_loc)
216 return;
217
218 Location *locPtr = world.get_loc(damageXLoc, damageYLoc);
219 if(locPtr->fire_str() > 0)
220 {
221 locPtr->set_fire_str(1);
222 }
223 }
224 //---------- End of function Tornado::hit_plant --------//
225
226
227
228 #ifdef DYNARRAY_DEBUG_ELEMENT_ACCESS
229
230 //------- Begin of function TornadoArray::operator[] -----//
231
operator [](int recNo)232 Tornado* TornadoArray::operator[](int recNo)
233 {
234 Tornado* tornadoPtr = (Tornado*) get_ptr(recNo);
235
236 if( !tornadoPtr )
237 err.run( "TornadoArray[] is deleted" );
238
239 return tornadoPtr;
240 }
241
242 //--------- End of function TornadoArray::operator[] ----//
243
244 #endif
245
246 //--------- Begin of function TornadoArray::TornadoArray ------//
TornadoArray(int initArraySize)247 TornadoArray::TornadoArray(int initArraySize): SpriteArray(initArraySize)
248 {
249 }
250 //--------- End of function TornadoArray::TornadoArray ------//
251
252
253 //--------- Begin of function TornadoArray::add_tornado ------//
254 //
255 // <short> startX, startY starting location of the tornado
256 // <short> lifeTime time (no. of frames) the tornado survive
257 //
add_tornado(int xLoc,int yLoc,short lifeTime)258 short TornadoArray::add_tornado(int xLoc, int yLoc, short lifeTime)
259 {
260 Tornado *tornadoPtr = new Tornado;
261 tornadoPtr->init(xLoc, yLoc, lifeTime);
262 add(tornadoPtr);
263 return 1;
264 }
265 //--------- End of function TornadoArray::add_tornado ------//
266
267
268 //--------- Begin of function TornadoArray::create_tornado ------//
269 //
270 // return: <int> recno of the tornado created.
271 //
create_tornado()272 short TornadoArray::create_tornado()
273 {
274 Tornado *tornadoPtr = new Tornado;
275 add(tornadoPtr);
276
277 return recno();
278 }
279 //--------- End of function TornadoArray::create_tornado ------//
280
281
282 //--------- Begin of function TornadoArray::process ---------//
283
process()284 void TornadoArray::process()
285 {
286 int i;
287 Tornado* tornadoPtr;
288
289 for (i=1; i <=size() ; i++)
290 {
291 tornadoPtr = (Tornado*)get_ptr(i);
292
293 if( !tornadoPtr)
294 continue;
295
296 //-------- system yield ---------//
297
298 if( i%20==1 )
299 sys.yield();
300
301 //------- process tornado --------//
302
303 tornadoPtr->pre_process();
304
305 switch(tornadoPtr->cur_action)
306 {
307 case SPRITE_IDLE:
308 case SPRITE_READY_TO_MOVE:
309 tornadoPtr->process_idle();
310 break;
311
312 case SPRITE_MOVE:
313 tornadoPtr->process_move();
314 break;
315
316 //### begin alex 7/3 ###//
317 case SPRITE_TURN:
318 err_here();
319 break;
320 //#### end alex 7/3 ####//
321
322 case SPRITE_WAIT:
323 tornadoPtr->process_wait();
324 break;
325
326 case SPRITE_ATTACK:
327 tornadoPtr->process_attack();
328 break;
329
330 case SPRITE_DIE:
331 if( tornadoPtr->process_die() )
332 del(i);
333 break;
334 }
335 }
336 }
337 //----------- End of function TornadoArray::process -----------//
338
339
340 //--------- Begin of function TornadoArray::draw_dot ---------//
341 //
342 // Draw 2x2 tiny squares on map window representing the location of the unit ---//
343 //
draw_dot()344 void TornadoArray::draw_dot()
345 {
346 char* vgaBufPtr = vga_back.buf_ptr();
347 char* writePtr;
348 Tornado* tornadoPtr;
349 int i, mapX, mapY;
350 int vgaBufPitch = vga_back.buf_pitch();
351
352 for(i=1; i <=size() ; i++)
353 {
354 tornadoPtr = (Tornado*)get_ptr(i);
355
356 if( !tornadoPtr )
357 continue;
358
359 mapX = MAP_X1 + tornadoPtr->cur_x_loc();
360 mapY = MAP_Y1 + tornadoPtr->cur_y_loc();
361
362 // ####### begin Gilbert 13/11 #########//
363 if( mapX < MAP_X1 || mapX > MAP_X2 || mapY < MAP_Y1 || mapY > MAP_Y2 )
364 return;
365 // ####### end Gilbert 13/11 #########//
366
367 writePtr = vgaBufPtr + mapY*vgaBufPitch + mapX;
368
369 if( mapY > MAP_Y1)
370 {
371 if( mapX > MAP_X1 && writePtr[-vgaBufPitch-1] != UNEXPLORED_COLOR)
372 writePtr[-vgaBufPitch-1] = (char)TORNADO_COLOR2;
373 if( writePtr[-vgaBufPitch] != UNEXPLORED_COLOR)
374 writePtr[-vgaBufPitch] = (char)TORNADO_COLOR1;
375 if( mapX < MAP_X2 && writePtr[-vgaBufPitch+1] != UNEXPLORED_COLOR)
376 writePtr[-vgaBufPitch+1] = (char)TORNADO_COLOR2;
377 }
378
379 if( mapX > MAP_X1 && writePtr[-1] != UNEXPLORED_COLOR)
380 writePtr[-1] = (char)TORNADO_COLOR1;
381 if( mapX < MAP_X2 && writePtr[1] != UNEXPLORED_COLOR)
382 writePtr[1] = (char)TORNADO_COLOR1;
383
384 if( mapY < MAP_Y2)
385 {
386 if( mapX > MAP_X1 && writePtr[vgaBufPitch-1] != UNEXPLORED_COLOR)
387 writePtr[vgaBufPitch-1] = (char)TORNADO_COLOR2;
388 if( writePtr[vgaBufPitch] != UNEXPLORED_COLOR)
389 writePtr[vgaBufPitch] = (char)TORNADO_COLOR1;
390 if( mapX < MAP_X2 && writePtr[vgaBufPitch+1] != UNEXPLORED_COLOR)
391 writePtr[vgaBufPitch+1] = (char)TORNADO_COLOR2;
392 }
393
394 }
395 }
396 //----------- End of function UnitArray::draw_dot -----------//
397
398