1 /***************************************************************************
2                           shots.c  -  description
3                              -------------------
4     begin                : Sat Sep 8 2001
5     copyright            : (C) 2001 by Michael Speck
6     email                : kulkanie@gmx.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "../client/lbreakout.h"
19 #include "mathfuncs.h"
20 #include "balls.h"
21 #include "bricks.h"
22 
23 int shot_w = 10;
24 int shot_h = 10;
25 float shot_v_y = 0.2;
26 extern Game *cur_game;
27 
28 int last_shot_fire_x = -1; /* HACK: used to play local sound */
29 
30 /*
31 ====================================================================
32 Locals
33 ====================================================================
34 */
35 
36 /*
37 ====================================================================
38 Compute target of shot.
39 ====================================================================
40 */
shot_get_target(Shot * shot)41 void shot_get_target( Shot *shot ) {
42     int mx = (int)(shot->x + 3) / BRICK_WIDTH;
43     int my = (int)(shot->y + 3 + ((shot->dir==1)?5:0) ) / BRICK_HEIGHT;
44     memset( &shot->target, 0, sizeof(Target) );
45     while ( cur_game->bricks[mx][my].id == -1 )
46         my += shot->dir;
47     shot->target.mx = mx; shot->target.my = my;
48     mx = (int)(shot->x + 6) / BRICK_WIDTH;
49     if (mx != shot->target.mx) {
50         my = (int)(shot->y + 3 + ((shot->dir==1)?5:0) ) / BRICK_HEIGHT;
51         while(cur_game->bricks[mx][my].id == -1)
52             my += shot->dir;
53         if (my == shot->target.my)
54             shot->next_too = 1;
55         else
56             if ( ( shot->dir == -1 && my > shot->target.my ) ||
57                  ( shot->dir ==  1 && my < shot->target.my ) ) {
58                 shot->target.mx = mx;
59                 shot->target.my = my;
60                 shot->next_too = 0;
61             }
62     }
63     shot->target.cur_tm = 0;
64     shot->target.time = abs(
65 		(int)((shot->y + 3 +
66 		((shot->dir==1)?5:0) -
67 		(shot->target.my * BRICK_HEIGHT + ((shot->dir==-1)?(BRICK_HEIGHT - 1):0) )) /
68 		fabs(shot_v_y)) );
69 }
70 
71 /*
72 ====================================================================
73 Publics
74 ====================================================================
75 */
76 
77 /*
78 ====================================================================
79 Create new shot at position (centered).
80 'signum' of direction determines into which direction the shot
81 vertically goes.
82 ====================================================================
83 */
shot_create(Paddle * paddle)84 void shot_create( Paddle *paddle )
85 {
86     Shot *shot = calloc( 1, sizeof( Shot ) );
87     shot->cur_fr = 0;
88     shot->paddle = paddle;
89     shot->dir = (paddle->type == PADDLE_TOP) ? 1 : -1;
90     shot->x = paddle->x + ( paddle->w >> 1 ) - (shot_w >> 1);
91     shot->y = paddle->y + ( paddle->h >> 1 ) - (shot_h >> 1);
92     shot->get_target = 1;
93     list_add( cur_game->shots, shot );
94 
95     cur_game->mod.fired_shot_count++;
96     last_shot_fire_x = shot->x; /* HACK: used to play local sound */
97 }
98 
99 /*
100 ====================================================================
101 Set 'get_target' flag so target is updated next time
102 'shots_update' is called. -1 means to update all shots.
103 ====================================================================
104 */
shots_check_targets(int mx,int my)105 void shots_check_targets( int mx, int my )
106 {
107     Shot        *shot;
108     list_reset( cur_game->shots );
109     while ( ( shot = list_next( cur_game->shots ) ) )
110         if ( mx == -1 || (shot->target.mx == mx && shot->target.my == my) )
111             shot->get_target = 1;
112 }
113 
114 /*
115 ====================================================================
116 Update position of shots and check if bricks get destroyed.
117 A list of all hit bricks is returned (at maximum
118 PADDLE_WEAPON_AMMO * 4)
119 ====================================================================
120 */
shots_update(int ms)121 void shots_update( int ms )
122 {
123 	int i;
124 	ListEntry  *entry = cur_game->shots->head->next;
125 	Shot        *shot;
126 
127 	while ( entry != cur_game->shots->tail ) {
128 		shot = entry->item;
129 		if ( shot->get_target ) { /* new target? */
130 			shot_get_target(shot);
131 			shot->get_target = 0;
132 		}
133 		shot->y += shot->dir * ms * shot_v_y;
134 		shot->target.cur_tm += ms;
135 		entry = entry->next;
136 		/* kill 'out of screen' shots */
137 		if ( shot->y + shot_h < 0 || shot->y > 480 ) {
138 			shot->paddle->weapon_ammo++; /* give back used shot */
139 			list_delete_entry( cur_game->shots, entry->prev );
140 			continue;
141 		}
142 		/* check hits */
143 		if (shot->target.cur_tm > shot->target.time) {
144 			if ( brick_hit( shot->target.mx, shot->target.my,
145 					0, SHR_BY_SHOT, vector_get( 0, shot->dir ),
146 					shot->paddle ) ) {
147 				shots_check_targets( shot->target.mx, shot->target.my );
148                 		balls_check_targets( shot->target.mx, shot->target.my );
149 			}
150 			if (shot->next_too)
151 			if ( brick_hit( shot->target.mx + 1, shot->target.my,
152 					0, SHR_BY_SHOT, vector_get( 0, shot->dir ),
153 					shot->paddle ) ) {
154 				shots_check_targets(shot->target.mx + 1, shot->target.my);
155                 		balls_check_targets( shot->target.mx, shot->target.my );
156 			}
157 			shot->paddle->weapon_ammo++; /* give back used shot */
158 			list_delete_entry( cur_game->shots, entry->prev );
159 			continue;
160 		}
161 		/* in multiplayer we check if we hit the opponent if so we steal
162 		   him a 1000 points */
163 		for ( i = 0; i < cur_game->paddle_count; i++ )
164 			if ( cur_game->paddles[i] != shot->paddle )
165 			if ( shot->x + shot_w > cur_game->paddles[i]->x )
166 			if ( shot->x < cur_game->paddles[i]->x + cur_game->paddles[i]->w )
167 			if ( shot->y + shot_h > cur_game->paddles[i]->y )
168 			if ( shot->y < cur_game->paddles[i]->y + cur_game->paddles[i]->h ) {
169 				if ( (cur_game->paddles[i]->score -= 1000) < 0 )
170 					cur_game->paddles[i]->score = 0;
171 				shot->paddle->score += 1000;
172 				shot->paddle->weapon_ammo++;
173 				list_delete_entry( cur_game->shots, entry->prev );
174 				break;
175 			}
176 	}
177 }
178 
179