1 /*  projectile.c */
2 
3 /*  Copyright Hugh Robinson 2006-2008.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17 
18 #include <math.h>
19 #include "asylum.h"
20 
21 #define _projno 32
22 #define _projlim 0x1000
23 
24 #define _projsmallno 54
25 #define _rocketspriteno 32
26 #define _rocketspritelim 41
27 
28 #define bulletloss (2<<8)
29 
30 const char _spcrumblelowlim = 140, _spcrumblehighlim = 143;
31 extern const char _translowlim, _transhighlim;
32 
33 extern int xposmax, yposmax;
34 extern fastspr_sprite blokeadr[];
35 extern char masterplotal;
36 
37 projent projofs[_projlim];
38 
39 projent* projadr;
40 int projctr;
41 
causeexplo(projent * r11)42 void causeexplo(projent* r11)
43 {
44     explogomaybe(r11->x-r11->dx, r11->y-r11->dy-(8<<8), 0, 0, 1, -1, 0);
45 }
causeexplonopyro(projent * r11)46 void causeexplonopyro(projent* r11)
47 {
48     explogonopyro(r11->x-r11->dx, r11->y-r11->dy-(8<<8), 0, 0, 1, -1, 0);
49 }
50 
project()51 void project()       // the projectile handler
52 {
53     int i = _projno; // get table length
54     projent* r11 = projadr;
55 
56     for (; i > 0; i--, r11++)
57     {
58        loop41:
59         if (r11->type == 0) continue;
60        foundproj:
61         r11->x += r11->dx; r11->y += r11->dy;
62         if ((r11->x <= xlowlim) || (xposmax <= r11->x) || (r11->y <= ylowlim) || (yposmax <= r11->y))
63         {
64             // goto projoffscr
65             r11->type = 0;
66             continue;
67         }
68         if (r11->flags&PROJ_ROCKET)
69         {
70             r11->dx += r11->dx>>4;  r11->dy += r11->dy>>4;
71         }
72 
73        projnoacc:
74         if (r11->dx > _speedlim) r11->dx = _speedlim;
75         if (r11->dx < -_speedlim) r11->dx = -_speedlim;
76         if (r11->dy > _speedlim) r11->dy = _speedlim;
77         if (r11->dy < -_speedlim) r11->dy = -_speedlim;
78 
79         r11->flags -= PROJ_TTL; // decrement the life counter
80         if (r11->flags < 0)     // out of time
81         {
82            projdestroy:
83             if (r11->flags&PROJ_SPLIT)
84             {
85                 projsplit(r11); continue;
86             }
87            projoffscr:
88             r11->type = 0;
89             continue;
90         }
91         alent* rs = bulcolcheck(r11->x, r11->y);
92         if (rs != NULL)
93         {
94             int r6;
95             if (r11->flags&PROJ_ROCKET)
96 	        r6 = projhital(rs,bulletloss<<2);
97             else r6 = projhital(rs, bulletloss);
98             r11->type = 0;
99             if (r6 == 0) continue;
100             makeobj(_Flyingbonus, r11->x, r11->y, r11->dx>>2, -(1<<10), (0x200<<16), r6);
101             if (r11->flags&PROJ_ROCKET) causeexplo(r11);
102             else causeexplonopyro(r11);
103             continue;
104         }
105 
106         char* r0 = fntranslate(r11->x, r11->y);
107         char r1 = *r0;
108         if ((r1 < 16) ||
109             //    projhit:  // hit a block
110             ((r1 >= _translowlim) && (r1 <= _transhighlim) && !(r11->flags&PROJ_ATOM)))
111         {
112            projhitins:
113             if (masterplotal == 0) continue;
114             relplot(blokeadr, r11->type, r11->x, r11->y);
115             continue;
116         }
117        projhitcont:
118         if ((r1 >= _spcrumblelowlim) && (r1 <= _spcrumblehighlim)
119             && ((r11->type == _projsmallno+2) || (r11->flags&PROJ_WEIRDSPLIT)))
120           // hack, better than original && (plweapontype == 5)
121         {
122             *r0 = 0;
123             explogo(r11->x, r11->y, 0, 0, 0, 0, 0);
124         }
125        nospcrumble:
126         r11->type = 0;
127         destroy(r0);
128         if (r11->flags&PROJ_ATOM)
129         {
130             atomrocket(r11, r0); continue;
131         }
132         if (r11->flags&PROJ_EXPLO)
133         {
134             causeexplonopyro(r11); continue;
135         }
136         if (r11->flags&PROJ_ROCKET)
137         {
138             causeexplo(r11); continue;
139         }
140     }
141 }
142 
143 int projsplittab[10];
144 
init_projsplittab()145 void init_projsplittab()
146 {
147     for (int i = 0; i < 5; i++)
148     {
149         projsplittab[i*2] = (int)(0x40*(0.5-sin(i/4.0*M_PI)));
150         projsplittab[i*2+1] = 0x100*(i-2);
151     }
152 }
153 
projsplit(projent * r11)154 void projsplit(projent* r11)
155 {
156     int x = r11->x, y = r11->y, dx = (r11->dx)>>1, dy = (r11->dy)>>1;
157     int flags = r11->flags;
158     int* r10;
159     int r9;
160 
161     if (flags&PROJ_ROCKET)
162     {
163         rocketsplit(r11); return;
164     }
165 
166     int r7 = r11->type, r4, r6;
167 
168     if (flags&PROJ_FIVEWAY)
169     {
170         r10 = projsplittab; r9 = 5; r4 = _projsmallno+1;
171     }
172     else
173     {
174         r10 = projsplittab+2; r9 = 3; r4 = _projsmallno;
175     }
176     if ((flags&PROJ_SLOWSPLIT) == 0) dx >>= 1;
177     if (flags&PROJ_WEIRDSPLIT)
178     {
179         r4 = _projsmallno+2; dx <<= 2;
180     }
181     if (flags&PROJ_EXPLO)
182     {
183         r4 = _projsmallno+3; r6 = PROJ_ROCKET;
184     }
185     else r6 = 64*PROJ_TTL;
186 
187     for (; r9 > 0; r9--)
188     {
189        loop76:
190         makeproj(x, y, dx+r10[0], dy+r10[1], r4, r6);
191         r10 += 2;
192     }
193     r11->type = 0;
194 }
195 
196 int rocketbursttab[10];
197 
init_rocketbursttab()198 void init_rocketbursttab()
199 {
200     for (int i = 0; i < 5; i++)
201     {
202         rocketbursttab[i*2] = (int)(0x200*sin((0.5+i)/2.5*M_PI));
203         rocketbursttab[i*2+1] = (int)(0x200*cos((0.5+i)/2.5*M_PI));
204     }
205 }
206 
rocketsplit(projent * r11)207 void rocketsplit(projent* r11)
208 {
209     int x = r11->x, y = r11->y, dx = (r11->dx)>>3, dy = (r11->dy)>>3;
210     int flags = r11->flags;
211 
212     if (flags&ROCK_DIVIDE)
213     {
214         rocketpair(r11); return;
215     }
216    rocketburst:;
217 
218     int r5 = (64*PROJ_TTL)|PROJ_ROCKET|PROJ_EXPLO;
219     int* r10 = rocketbursttab;
220     for (int r9 = 5; r9 > 0; r9--)
221     {
222        loop77:
223         makeproj(x, y, dx+r10[0], dy+r10[1], _projsmallno+3, r5);
224         r10 += 2;
225     }
226     r11->type = 0;
227     causeexplonopyro(r11);
228 }
229 
rocketpair(projent * r11)230 void rocketpair(projent* r11)
231 {
232     int x = r11->x, y = r11->y, dx = r11->dx, dy = r11->dy;
233     int flags = r11->flags;
234     int type = r11->type;
235     int newflags = 64*PROJ_TTL;
236 
237     if (flags&ROCK_BURST) newflags = (16*PROJ_TTL)|ROCK_BURST|PROJ_SPLIT;
238     if (flags&ROCK_REDIVIDE) // continue splitting
239     {
240         newflags &= ~(64*PROJ_TTL); newflags |= (16*PROJ_TTL)|ROCK_DIVIDE|PROJ_SPLIT;
241     }
242     newflags |= PROJ_ROCKET;
243 
244     int newtype = type-2;
245     if (newtype < _rocketspriteno) newtype += 2;
246 
247     if (type&1) makeproj(x, y, dx-(dy>>2), dy+(dx>>2)-(dy>>4), newtype, newflags);
248     else makeproj(x, y, dx+(dy>>2), dy-(dx>>2)+(dy>>4), newtype, newflags);
249 
250     newtype = type+2;
251     if (newtype > _rocketspritelim) newtype -= 2;
252 
253     if (type&1) makeproj(x, y, dx+(dy>>2), dy-(dx>>2)+(dy>>4), newtype, newflags);
254     else makeproj(x, y, dx-(dy>>2), dy+(dx>>2)-(dy>>4), newtype, newflags);
255 
256     r11->type = 0;
257 }
258 
makeproj(int x,int y,int dx,int dy,int type,int flags)259 int makeproj(int x, int y, int dx, int dy, int type, int flags)
260 {
261     projent* r10 = projadr+projctr;
262     int r9 = _projno-projctr;
263     int r8 = projctr;
264 
265     for (; r9 > 0; r9--)
266     {
267        loop42:
268         if (r10->type == 0) return foundmakeproj(r10, r8, x, y, dx, dy, type, flags);
269         r10++;
270         r8++;
271     }
272     r10 = projadr;
273     for (r9 = projctr; r9 > 0; r9--)
274     {
275        loop43:
276         if (r10->type == 0) return foundmakeproj(r10, r8, x, y, dx, dy, type, flags);
277         r10++;
278         r8++;
279     }
280     return 1;
281 }
282 
foundmakeproj(projent * r10,int r8,int x,int y,int dx,int dy,int type,int flags)283 int foundmakeproj(projent* r10, int r8, int x, int y, int dx, int dy, int type, int flags)
284 {
285     if (flags < (1*PROJ_TTL)) flags |= (64*PROJ_TTL);
286     r10->type = type; r10->x = x; r10->y = y;
287     r10->dx = dx; r10->dy = dy; r10->flags = flags;
288 
289     for (r8++; r8 >= _projno; r8 -= _projno)
290        loop45:;
291     projctr = r8;
292     return 0;
293 }
294 
initprojtab()295 void initprojtab()
296 {
297     projadr = projofs;
298     projent* r10 = projadr;
299     projctr = 0;
300     for (int r9 = _projno; r9 > 0; r9--)
301     {
302        loop44:
303         *(int*)r10 = 0;
304         r10++;
305     }
306 }
307