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