1 /******************************************************************************************
2 *
3 * HighNoon - Duell im All
4 * Copyright (c) 2005, 2006 Patrick Gerdsmeier <patrick@gerdsmeier.net>
5 *
6 * "shoot.cpp"
7 *
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 ******************************************************************************************/
25
26 #include <cmath>
27
28 #include "sound.hpp"
29 #include "shoot.hpp"
30
31 extern SDL_Surface* MYSDLSCREEN;
32 extern Soundset *sound;
33
34 #ifdef __DEBUG__
35 extern int __SHOOTS;
36 extern int __HITS;
37 #endif
38
39 /************************************************************************
40 * *
41 * Explosion *
42 * *
43 ************************************************************************/
Explosion(double x,double y)44 Explosion::Explosion( double x, double y )
45 :
46 Spaceobject( x, y ),
47 exploding(false)
48 {
49 verbose( "Initializing Explosion" );
50
51 explosion_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/explosionanim.gif", 6 );
52 explosion_sprite->setAlpha(230);
53 explosion_sprite->setRepeatmode(false);
54 explosion_sprite->setFramerate(1);
55 }
56
~Explosion()57 Explosion::~Explosion()
58 {
59 verbose( "Deleting Explosion" );
60
61 delete explosion_sprite;
62 }
63
is_active() const64 bool Explosion::is_active() const
65 {
66 return exploding;
67 }
68
activate(double x,double y)69 void Explosion::activate( double x, double y )
70 {
71 set_Pos( x, y );
72 explosion_sprite->setPos( (int)x, (int)y );
73 explosion_sprite->resetFrames();
74 exploding = true;
75
76 sound->play(SOUND_EXPLOSION);
77 }
78
check_collision(double x,double y,double width,bool spacing)79 bool Explosion::check_collision( double x, double y, double width, bool spacing )
80 {
81 return false;
82 }
83
draw()84 void Explosion::draw()
85 {
86 if ( is_active() ) {
87 explosion_sprite->draw();
88 exploding = !explosion_sprite->is_onLastFrame();
89 }
90 }
91
hit(Spaceobject * object)92 void Explosion::hit( Spaceobject *object ) {}
93
94 /************************************************************************
95 * *
96 * Shoot *
97 * *
98 ************************************************************************/
Shoot(double x,double y)99 Shoot::Shoot( double x, double y )
100 :
101 Spaceobject( x, y ),
102 is_exploding(false),
103 moving_time(0),
104 last_shootPos( Vector_2(0,0,K) ),
105 pre_calculated_Steps(0)
106 {
107 verbose( "Initializing Shoot" );
108
109 weight = 1;
110 explosion = new Explosion();
111 }
112
~Shoot()113 Shoot::~Shoot()
114 {
115 verbose( "Deleting Shoot" );
116
117 delete explosion;
118 }
119
is_active() const120 bool Shoot::is_active() const
121 {
122 return false;
123 }
124
will_be_a_Hit(int player_id,double factor,Vector_2 start,Vector_2 direction,Galaxy * galaxy)125 bool Shoot::will_be_a_Hit( int player_id, double factor, Vector_2 start, Vector_2 direction, Galaxy *galaxy )
126 {
127 calculate_ShootPath( start, direction, galaxy );
128
129 for ( int i=0; i < pre_calculated_Steps; i++ )
130 if ( galaxy->is_Ufo_In_Area( player_id, pre_calculated_Pos[i].x, pre_calculated_Pos[i].y, factor ) )
131 return true;
132
133 return false;
134 }
135
activate(Vector_2 start,Vector_2 vector)136 void Shoot::activate( Vector_2 start, Vector_2 vector )
137 {
138 set_Pos( start.getX(), start.getY() );
139 direction = vector.getAngle();
140 speed = vector.getLength();
141 last_shootPos = start;
142 is_exploding = false;
143 moving_time = MAXSHOOTRUN;
144
145 sound->play(SOUND_SHOOT);
146 }
147
reset()148 void Shoot::reset() {}
149
destroy()150 void Shoot::destroy() {}
151
move(Galaxy * galaxy)152 bool Shoot::move( Galaxy *galaxy ) { return false; }
153
has_Extra_collision(Extra * extra)154 bool Shoot::has_Extra_collision( Extra *extra )
155 {
156 return false;
157 }
158
check_collision(double x,double y,double width,bool spacing)159 bool Shoot::check_collision( double x, double y, double width, bool spacing )
160 {
161 return false;
162 }
163
draw()164 void Shoot::draw() {}
165
draw_hint(Vector_2 start,Vector_2 direction,Galaxy * galaxy)166 void Shoot::draw_hint( Vector_2 start, Vector_2 direction, Galaxy *galaxy )
167 {
168 static int colorpos = 50;
169
170 if ( (colorpos -= 20) < 50 ) colorpos = 255;
171
172 calculate_ShootPath( start, direction, galaxy );
173
174 int c = colorpos;
175
176 SDL_LockSurface( MYSDLSCREEN );
177
178 for (int i=0; i < pre_calculated_Steps; i++) {
179 Sprite::putpixel(
180 pre_calculated_Pos[i].x + Sprite::x_offset,
181 pre_calculated_Pos[i].y + Sprite::y_offset,
182 SDL_MapRGB( MYSDLSCREEN->format, c, c, c ) );
183
184 if ( (c += 30) > 255 ) c = 50;
185 }
186
187 SDL_UnlockSurface( MYSDLSCREEN );
188 }
189
hit(Spaceobject * object)190 void Shoot::hit( Spaceobject *object ) {}
191
calculate_ShootPath(Vector_2 start,Vector_2 direction,Galaxy * galaxy)192 void Shoot::calculate_ShootPath( Vector_2 start, Vector_2 direction, Galaxy *galaxy )
193 {
194 static Vector_2 last_angle=Vector_2( 0, 0, K );
195 static Vector_2 last_shoot=Vector_2( 0, 0, K );
196
197 if ( last_angle != direction || last_shoot != start ) {
198
199 pre_calculated_Steps = 0;
200 last_angle = direction;
201 last_shoot = start;
202
203 for ( int i=0; i < MAXPRECALC; i++ ) {
204 galaxy->calculate_nextPos( start, direction );
205 double x = start.getX();
206 double y = start.getY();
207
208 if ( !galaxy->check_collision( x, y, get_Width() ) ) {
209 pre_calculated_Pos[i].x = (int)x;
210 pre_calculated_Pos[i].y = (int)y;
211 pre_calculated_Steps++;
212 } else break;
213 }
214 }
215 }
216
217 /************************************************************************
218 * *
219 * Laser *
220 * *
221 ************************************************************************/
Laser(double x,double y)222 Laser::Laser( double x, double y )
223 :
224 Shoot( x, y )
225 {
226 verbose( "Initializing Laser" );
227
228 laser_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shoot.gif" );
229 laserback_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shootback.gif" );
230 laserbackk_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shootbackk.gif" );
231
232 width = laser_sprite->getWidth();
233 }
234
~Laser()235 Laser::~Laser()
236 {
237 verbose( "Deleting Laser" );
238
239 delete laser_sprite;
240 delete laserback_sprite;
241 delete laserbackk_sprite;
242 }
243
is_active() const244 bool Laser::is_active() const
245 {
246 return moving_time > 0;
247 }
248
destroy()249 void Laser::destroy()
250 {
251 if ( is_active() )
252 hit( this );
253 }
254
move(Galaxy * galaxy)255 bool Laser::move( Galaxy *galaxy )
256 {
257 if ( is_active() ) {
258 if ( --moving_time == 0 ) return true;
259
260 Vector_2 my_shootPos = Vector_2( get_X(), get_Y(), K );
261 Vector_2 my_shootVector = Vector_2( speed, direction, P );
262 last_shootPos = my_shootPos;
263
264 galaxy->calculate_nextPos( my_shootPos, my_shootVector );
265
266 x = my_shootPos.getX();
267 y = my_shootPos.getY();
268 speed = my_shootVector.getLength();
269 direction = my_shootVector.getAngle();
270
271 if ( galaxy->has_collision( this ) &&
272 !is_active() )
273
274 return true;
275 }
276
277 return false;
278 }
279
has_Extra_collision(Extra * extra)280 bool Laser::has_Extra_collision( Extra *extra )
281 {
282 if ( extra->has_collision( (Spaceobject *)this ) )
283 return true;
284
285 return false;
286 }
287
check_collision(double x,double y,double width,bool spacing)288 bool Laser::check_collision( double x, double y, double width, bool spacing )
289 {
290 return check_sphere_collision( x, y, width, spacing );
291 }
292
draw()293 void Laser::draw()
294 {
295 if ( is_active() ) {
296
297 if ( moving_time > 100 ||
298 (int)RANDOM(100, 0) < ( moving_time/2 )+25 ) {
299
300 double x_anim = RANDOM(2, -2);
301 double y_anim = RANDOM(2, -2);
302 int alpha_anim = (int)RANDOM(10, -10);
303
304 Vector_2 v = last_shootPos-Vector_2( get_X(), get_Y(), K );
305 Vector_2 v_1 = v*0.5;
306 Vector_2 v_2 = v*0.2;
307
308 laserbackk_sprite->setAlpha( 120+alpha_anim );
309 laserbackk_sprite->setPos(
310 (int)( get_X()+v_1.getX() ),
311 (int)( get_Y()+v_1.getY() ) );
312 laserbackk_sprite->draw();
313
314 laserback_sprite->setAlpha( 140+alpha_anim );
315 laserback_sprite->setPos(
316 (int)( get_X()+v_2.getX() + x_anim ),
317 (int)( get_Y()+v_2.getY() + y_anim ) );
318 laserback_sprite->draw();
319
320 laser_sprite->setAlpha( 200+alpha_anim );
321 laser_sprite->setPos( (int)get_X(), (int)get_Y() );
322 laser_sprite->draw();
323 }
324 }
325
326 if ( is_exploding ) {
327 explosion->draw();
328 is_exploding = explosion->is_active();
329 }
330 }
331
hit(Spaceobject * object)332 void Laser::hit( Spaceobject *object )
333 {
334 explosion->activate( x, y );
335 is_exploding = true;
336 moving_time = 0;
337 }
338
339 /************************************************************************
340 * *
341 * Heavy *
342 * *
343 ************************************************************************/
Heavy(double x,double y)344 Heavy::Heavy( double x, double y )
345 :
346 Shoot( x, y )
347 {
348 verbose( "Initializing Heavy" );
349
350 weight = 2;
351
352 heavy_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/heavy.gif" );
353 heavyback_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/heavyback.gif" );
354 heavybackk_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/heavybackk.gif" );
355
356 width = heavy_sprite->getWidth();
357 }
358
~Heavy()359 Heavy::~Heavy()
360 {
361 verbose( "Deleting Heavy" );
362
363 delete heavy_sprite;
364 delete heavyback_sprite;
365 delete heavybackk_sprite;
366 }
367
is_active() const368 bool Heavy::is_active() const
369 {
370 return moving_time > 0;
371 }
372
destroy()373 void Heavy::destroy()
374 {
375 if ( is_active() )
376 hit( this );
377 }
378
move(Galaxy * galaxy)379 bool Heavy::move( Galaxy *galaxy )
380 {
381 if ( is_active() ) {
382
383 if ( --moving_time == 0 ) return true;
384
385 Vector_2 my_shootPos = Vector_2( get_X(), get_Y(), K );
386 Vector_2 my_shootVector = Vector_2( speed, direction, P );
387 last_shootPos = my_shootPos;
388
389 galaxy->calculate_nextPos( my_shootPos, my_shootVector );
390
391 x = my_shootPos.getX();
392 y = my_shootPos.getY();
393 speed = my_shootVector.getLength();
394 direction = my_shootVector.getAngle();
395
396 if ( galaxy->has_collision( this ) &&
397 !is_active() )
398
399 return true;
400 }
401
402 return false;
403 }
404
has_Extra_collision(Extra * extra)405 bool Heavy::has_Extra_collision( Extra *extra )
406 {
407 if ( extra->has_collision( (Spaceobject *)this ) )
408 return true;
409
410 return false;
411 }
412
check_collision(double x,double y,double width,bool spacing)413 bool Heavy::check_collision( double x, double y, double width, bool spacing )
414 {
415 return check_sphere_collision( x, y, width, spacing );
416 }
417
draw()418 void Heavy::draw()
419 {
420 if ( is_active() ) {
421
422 if ( moving_time > 100 ||
423 (int)RANDOM(100, 0) < ( moving_time/2 )+25 ) {
424
425 double x_anim = RANDOM(2, -2);
426 double y_anim = RANDOM(2, -2);
427 int alpha_anim = (int)RANDOM(10, -10);
428
429 Vector_2 v = last_shootPos-Vector_2( get_X(), get_Y(), K );
430 Vector_2 v_1 = v * 0.5;
431 Vector_2 v_2 = v * 0.2;
432
433 heavy_sprite->setAlpha( 200 + alpha_anim );
434 heavy_sprite->setPos( (int)get_X(), (int)get_Y() );
435 heavy_sprite->draw();
436
437 heavybackk_sprite->setAlpha( 100 + alpha_anim );
438 heavybackk_sprite->setPos(
439 (int)( get_X() + v_1.getX() ),
440 (int)( get_Y() + v_1.getY() ) );
441 heavybackk_sprite->draw();
442
443 heavyback_sprite->setAlpha( 130 + alpha_anim );
444 heavyback_sprite->setPos(
445 (int)( get_X() + v_2.getX() + x_anim ),
446 (int)( get_Y() + v_2.getY() + y_anim ) );
447 heavyback_sprite->draw();
448 }
449 }
450
451 if ( is_exploding ) {
452 explosion->draw();
453 is_exploding = explosion->is_active();
454 }
455 }
456
hit(Spaceobject * object)457 void Heavy::hit( Spaceobject *object )
458 {
459 explosion->activate( x, y );
460 is_exploding = true;
461 moving_time = 0;
462 }
463
464 /************************************************************************
465 * *
466 * Cluster *
467 * *
468 ************************************************************************/
Cluster(double x,double y)469 Cluster::Cluster( double x, double y )
470 :
471 Shoot( x, y ),
472 lasers_active(false)
473 {
474 verbose( "Initializing Cluster" );
475
476 reset();
477
478 cluster_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shoot.gif" );
479 clusterback_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shootback.gif" );
480 clusterbackk_sprite = new Sprite( (char*)"/usr/local/share/highmoon/gfx/shootbackk.gif" );
481
482 width = cluster_sprite->getWidth();
483
484 lasers = new Laser[MAXCLUSTERLASER];
485 }
486
~Cluster()487 Cluster::~Cluster()
488 {
489 verbose( "Deleting Cluster" );
490
491 delete cluster_sprite;
492 delete clusterback_sprite;
493 delete clusterbackk_sprite;
494 delete[] lasers;
495 }
496
is_active() const497 bool Cluster::is_active() const
498 {
499 for ( int i=0; i < MAXCLUSTERLASER; i++ )
500 if ( lasers[i].is_active() )
501 return true;
502
503 return moving_time>0;
504 }
505
reset()506 void Cluster::reset()
507 {
508 destroyed = false;
509 laser_hits = 0;
510 moving_time = 0;
511 }
512
destroy()513 void Cluster::destroy()
514 {
515
516 for ( int i=0; i < MAXCLUSTERLASER; i++ )
517 if ( lasers[i].is_active() )
518 lasers[i].hit(this);
519
520 if ( is_active() ) {
521 destroyed = true;
522 hit( this );
523 }
524 }
525
move(Galaxy * galaxy)526 bool Cluster::move( Galaxy *galaxy )
527 {
528 if ( destroyed )
529 return true;
530
531 if ( moving_time > 0 ) {
532
533 if ( --moving_time == 0 )
534 return true;
535
536 else {
537 Vector_2 my_shootPos = Vector_2( get_X(), get_Y(), K );
538 Vector_2 my_shootVector = Vector_2( speed, direction, P );
539 last_shootPos = my_shootPos;
540
541 galaxy->calculate_nextPos( my_shootPos, my_shootVector );
542
543 x = my_shootPos.getX();
544 y = my_shootPos.getY();
545 speed = my_shootVector.getLength();
546 direction = my_shootVector.getAngle();
547
548 if ( galaxy->has_collision( this ) ) {
549 laser_hits++;
550 }
551 }
552 }
553
554 for ( int i=0; i < MAXCLUSTERLASER; i++ )
555 if ( lasers[i].is_active() && lasers[i].move( galaxy ) )
556 laser_hits++;
557
558 if ( laser_hits >= MAXCLUSTERLASER + 1 )
559 return true;
560
561 return false;
562 }
563
has_Extra_collision(Extra * extra)564 bool Cluster::has_Extra_collision( Extra *extra )
565 {
566 if ( is_active() && extra->has_collision( (Spaceobject *)this ) )
567 return true;
568
569 for ( int i=0; i < MAXCLUSTERLASER; i++ ) {
570 if ( lasers[i].is_active() && extra->has_collision( (Spaceobject *)&lasers[i] ) )
571 return true;
572 }
573
574 return false;
575 }
576
check_collision(double x,double y,double width,bool spacing)577 bool Cluster::check_collision( double x, double y, double width, bool spacing )
578 {
579 for ( int i=0; i < MAXCLUSTERLASER; i++ )
580 if ( lasers[i].check_collision( x, y, width, spacing ) )
581 return true;
582
583 return check_sphere_collision( x, y, width, spacing );
584 }
585
draw()586 void Cluster::draw()
587 {
588 if ( moving_time > 0 ) {
589
590 if ( moving_time > 100 ||
591 (int)RANDOM(100, 0) < ( moving_time/2 )+25 ) {
592
593 double x_anim = RANDOM(2, -2);
594 double y_anim = RANDOM(2, -2);
595 int alpha_anim = (int)RANDOM(10, -10);
596
597 Vector_2 v = last_shootPos-Vector_2( get_X(), get_Y(), K );
598 Vector_2 v_1 = v * 0.5;
599 Vector_2 v_2 = v * 0.2;
600
601 clusterbackk_sprite->setAlpha( 120 + alpha_anim );
602 clusterbackk_sprite->setPos(
603 (int)( get_X() + v_1.getX() ),
604 (int)( get_Y() + v_1.getY() ) );
605 clusterbackk_sprite->draw();
606
607 clusterback_sprite->setAlpha( 140 + alpha_anim );
608 clusterback_sprite->setPos(
609 (int)( get_X() + v_2.getX() + x_anim ),
610 (int)( get_Y() + v_2.getY() + y_anim ) );
611 clusterback_sprite->draw();
612
613 cluster_sprite->setAlpha( 200 + alpha_anim );
614 cluster_sprite->setPos( (int)get_X(), (int)get_Y() );
615 cluster_sprite->draw();
616 }
617 }
618
619 for (int i=0; i < MAXCLUSTERLASER; i++)
620 lasers[i].draw();
621
622 if ( is_exploding ) {
623 explosion->draw();
624 is_exploding = explosion->is_active();
625 }
626 }
627
hit(Spaceobject * object)628 void Cluster::hit( Spaceobject *object )
629 {
630 if ( moving_time > 0 ) {
631
632 explosion->activate( x, y );
633 is_exploding = true;
634 moving_time = 0;
635
636 if ( !destroyed ) {
637 Vector_2 v_hit_vector = Vector_2( get_X(), get_Y(), K )-Vector_2( object->get_X(), object->get_Y(), K );
638 Vector_2 v_hit_start = Vector_2( get_X(), get_Y(), K );
639 double dir = v_hit_vector.getAngle()-( CLUSTERLASERANGLE*MAXCLUSTERLASER/2 ) * PI / 180;
640
641 for ( int i=0; i < MAXCLUSTERLASER; i++ ) {
642 Vector_2 v_direction = Vector_2( get_Speed() / 5 * 3, dir, P );
643 Vector_2 v_start = v_hit_start + Vector_2( 10, dir, P );
644 lasers[i].activate( v_start, v_direction );
645 dir += CLUSTERLASERANGLE*PI/180;
646 }
647 }
648 }
649 }
650