Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | pmbaty | 1 | /* |
2 | * src/ents.c |
||
3 | * |
||
4 | * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved. |
||
5 | * |
||
6 | * The use and distribution terms for this software are contained in the file |
||
7 | * named README, which can be found in the root of this distribution. By |
||
8 | * using this software in any fashion, you are agreeing to be bound by the |
||
9 | * terms of this license. |
||
10 | * |
||
11 | * You must not remove this notice, or any other, from this software. |
||
12 | */ |
||
13 | |||
14 | #include <stdlib.h> |
||
15 | |||
16 | #include "system.h" |
||
17 | #include "game.h" |
||
18 | #include "ents.h" |
||
19 | |||
20 | #include "e_bullet.h" |
||
21 | #include "e_bomb.h" |
||
22 | #include "e_rick.h" |
||
23 | #include "e_them.h" |
||
24 | #include "e_bonus.h" |
||
25 | #include "e_box.h" |
||
26 | #include "e_sbonus.h" |
||
27 | #include "rects.h" |
||
28 | #include "maps.h" |
||
29 | #include "draw.h" |
||
30 | |||
31 | /* |
||
32 | * global vars |
||
33 | */ |
||
34 | ent_t ent_ents[ENT_ENTSNUM + 1]; |
||
35 | rect_t *ent_rects = NULL; |
||
36 | |||
37 | |||
38 | /* |
||
39 | * prototypes |
||
40 | */ |
||
41 | static void ent_addrect (S16, S16, U16, U16); |
||
42 | static U8 ent_creat1 (U8 *); |
||
43 | static U8 ent_creat2 (U8 *, U16); |
||
44 | |||
45 | |||
46 | /* |
||
47 | * Reset entities |
||
48 | * |
||
49 | * ASM 2520 |
||
50 | */ |
||
51 | void ent_reset (void) |
||
52 | { |
||
53 | U8 i; |
||
54 | |||
55 | E_RICK_STRST (E_RICK_STSTOP); |
||
56 | e_bomb_lethal = FALSE; |
||
57 | |||
58 | ent_ents[0].n = 0; |
||
59 | for (i = 2; ent_ents[i].n != 0xff; i++) |
||
60 | ent_ents[i].n = 0; |
||
61 | } |
||
62 | |||
63 | |||
64 | /* |
||
65 | * Create an entity on slots 4 to 8 by using the first slot available. |
||
66 | * Entities of type e_them on slots 4 to 8, when lethal, can kill |
||
67 | * other e_them (on slots 4 to C) as well as rick. |
||
68 | * |
||
69 | * ASM 209C |
||
70 | * |
||
71 | * e: anything, CHANGED to the allocated entity number. |
||
72 | * return: TRUE/OK FALSE/not |
||
73 | */ |
||
74 | static U8 ent_creat1 (U8 *e) |
||
75 | { |
||
76 | /* look for a slot */ |
||
77 | for (*e = 0x04; *e < 0x09; (*e)++) |
||
78 | if (ent_ents[*e].n == 0) |
||
79 | { |
||
80 | /* if slot available, use it */ |
||
81 | ent_ents[*e].c1 = 0; |
||
82 | return TRUE; |
||
83 | } |
||
84 | |||
85 | return FALSE; |
||
86 | } |
||
87 | |||
88 | |||
89 | /* |
||
90 | * Create an entity on slots 9 to C by using the first slot available. |
||
91 | * Entities of type e_them on slots 9 to C can kill rick when lethal, |
||
92 | * but they can never kill other e_them. |
||
93 | * |
||
94 | * ASM 20BC |
||
95 | * |
||
96 | * e: anything, CHANGED to the allocated entity number. |
||
97 | * m: number of the mark triggering the creation of the entity. |
||
98 | * ret: TRUE/OK FALSE/not |
||
99 | */ |
||
100 | static U8 ent_creat2 (U8 *e, U16 m) |
||
101 | { |
||
102 | /* make sure the entity created by this mark is not active already */ |
||
103 | for (*e = 0x09; *e < 0x0c; (*e)++) |
||
104 | if (ent_ents[*e].n != 0 && ent_ents[*e].mark == m) |
||
105 | return FALSE; |
||
106 | |||
107 | /* look for a slot */ |
||
108 | for (*e = 0x09; *e < 0x0c; (*e)++) |
||
109 | if (ent_ents[*e].n == 0) |
||
110 | { |
||
111 | /* if slot available, use it */ |
||
112 | ent_ents[*e].c1 = 2; |
||
113 | return TRUE; |
||
114 | } |
||
115 | |||
116 | return FALSE; |
||
117 | } |
||
118 | |||
119 | |||
120 | /* |
||
121 | * Process marks that are within the visible portion of the map, |
||
122 | * and create the corresponding entities. |
||
123 | * |
||
124 | * absolute map coordinate means that they are not relative to |
||
125 | * map_frow, as any other coordinates are. |
||
126 | * |
||
127 | * ASM 1F40 |
||
128 | * |
||
129 | * frow: first visible row of the map -- absolute map coordinate |
||
130 | * lrow: last visible row of the map -- absolute map coordinate |
||
131 | */ |
||
132 | void ent_actvis (U8 frow, U8 lrow) |
||
133 | { |
||
134 | U16 m; |
||
135 | U8 e; |
||
136 | S16 y; |
||
137 | |||
138 | /* |
||
139 | * go through the list and find the first mark that |
||
140 | * is visible, i.e. which has a row greater than the |
||
141 | * first row (marks being ordered by row number). |
||
142 | */ |
||
143 | for (m = map_submaps[game_submap].mark; map_marks[m].row != 0xff && map_marks[m].row < frow; m++) |
||
144 | ; |
||
145 | |||
146 | if (map_marks[m].row == 0xff) |
||
147 | return; // none found |
||
148 | |||
149 | /* |
||
150 | * go through the list and process all marks that are |
||
151 | * visible, i.e. which have a row lower than the last |
||
152 | * row (marks still being ordered by row number). |
||
153 | */ |
||
154 | for (; map_marks[m].row != 0xff && map_marks[m].row < lrow; m++) |
||
155 | { |
||
156 | if (map_marks[m].ent & MAP_MARK_NACT) |
||
157 | continue; // ignore marks that are not active |
||
158 | |||
159 | /* |
||
160 | * allocate a slot to the new entity |
||
161 | * |
||
162 | * slot type |
||
163 | * 0 available for e_them (lethal to other e_them, and stops entities |
||
164 | * i.e. entities can't move over them. E.g. moving blocks. But they |
||
165 | * can move over entities and kill them!). |
||
166 | * 1 rick |
||
167 | * 2 bullet |
||
168 | * 3 bomb |
||
169 | * 4-8 available for e_them, e_box, e_bonus or e_sbonus (lethal to |
||
170 | * other e_them, identified by their number being >= 0x10) |
||
171 | * 9-C available for e_them, e_box, e_bonus or e_sbonus (not lethal to |
||
172 | * other e_them, identified by their number being < 0x10) |
||
173 | * |
||
174 | * the type of an entity is determined by its .n as detailed below. |
||
175 | * |
||
176 | * 1 rick |
||
177 | * 2 bullet |
||
178 | * 3 bomb |
||
179 | * 4, 7, a, d e_them, type 1a |
||
180 | * 5, 8, b, e e_them, type 1b |
||
181 | * 6, 9, c, f e_them, type 2 |
||
182 | * 10, 11 box |
||
183 | * 12, 13, 14, 15 bonus |
||
184 | * 16, 17 speed bonus |
||
185 | * >17 e_them, type 3 |
||
186 | * 47 zombie |
||
187 | */ |
||
188 | |||
189 | if (!(map_marks[m].flags & ENT_FLG_STOPRICK)) |
||
190 | { |
||
191 | if (map_marks[m].ent >= 0x10) |
||
192 | { |
||
193 | /* boxes, bonuses and type 3 e_them go to slot 4-8 */ |
||
194 | /* (c1 set to 0 -> all type 3 e_them are sleeping) */ |
||
195 | if (!ent_creat1 (&e)) |
||
196 | continue; |
||
197 | } |
||
198 | else |
||
199 | { |
||
200 | /* type 1 and 2 e_them go to slot 9-c */ |
||
201 | /* (c1 set to 2) */ |
||
202 | if (!ent_creat2 (&e, m)) |
||
203 | continue; |
||
204 | } |
||
205 | } |
||
206 | else |
||
207 | { |
||
208 | /* entities stopping rick (e.g. blocks) go to slot 0 */ |
||
209 | if (ent_ents[0].n) |
||
210 | continue; |
||
211 | |||
212 | e = 0; |
||
213 | ent_ents[0].c1 = 0; |
||
214 | } |
||
215 | |||
216 | /* |
||
217 | * initialize the entity |
||
218 | */ |
||
219 | ent_ents[e].mark = m; |
||
220 | ent_ents[e].flags = map_marks[m].flags; |
||
221 | ent_ents[e].n = map_marks[m].ent; |
||
222 | |||
223 | /* |
||
224 | * if entity is to be already running (i.e. not asleep and waiting |
||
225 | * for some trigger to move), then use LETHALR i.e. restart flag, right |
||
226 | * from the beginning |
||
227 | */ |
||
228 | if (ent_ents[e].flags & ENT_FLG_LETHALR) |
||
229 | ent_ents[e].n |= ENT_LETHAL; |
||
230 | |||
231 | ent_ents[e].x = (S16) (map_marks[m].xy & 0xf8); |
||
232 | |||
233 | y = (S16) ((map_marks[m].xy & 0x07) + (map_marks[m].row & 0xf8) - map_frow); |
||
234 | y <<= 3; |
||
235 | |||
236 | if (!(ent_ents[e].flags & ENT_FLG_STOPRICK)) |
||
237 | y += 3; |
||
238 | ent_ents[e].y = y; |
||
239 | |||
240 | ent_ents[e].xsave = ent_ents[e].x; |
||
241 | ent_ents[e].ysave = ent_ents[e].y; |
||
242 | |||
243 | /*ent_ents[e].w0C = 0;*/ /* in ASM code but never used */ |
||
244 | |||
245 | ent_ents[e].w = ent_entdata[map_marks[m].ent].w; |
||
246 | ent_ents[e].h = ent_entdata[map_marks[m].ent].h; |
||
247 | ent_ents[e].sprbase = ent_entdata[map_marks[m].ent].spr; |
||
248 | ent_ents[e].sprite = (U8) ent_entdata[map_marks[m].ent].spr; |
||
249 | ent_ents[e].step_no_i = ent_entdata[map_marks[m].ent].sni; |
||
250 | ent_ents[e].trigsnd = (U8) ent_entdata[map_marks[m].ent].snd; |
||
251 | |||
252 | /* |
||
253 | * FIXME what is this? when all trigger flags are up, then |
||
254 | * use .sni for sprbase. Why? What is the point? (This is |
||
255 | * for type 1 and 2 e_them, ...) |
||
256 | * |
||
257 | * This also means that as long as sprite has not been |
||
258 | * recalculated, a wrong value is used. This is normal, see |
||
259 | * what happens to the falling guy on the right on submap 3: |
||
260 | * it changes when hitting the ground. |
||
261 | */ |
||
262 | #define ENT_FLG_TRIGGERS (ENT_FLG_TRIGBOMB|ENT_FLG_TRIGBULLET|ENT_FLG_TRIGSTOP|ENT_FLG_TRIGRICK) |
||
263 | if ((ent_ents[e].flags & ENT_FLG_TRIGGERS) == ENT_FLG_TRIGGERS && e >= 0x09) |
||
264 | ent_ents[e].sprbase = ent_entdata[map_marks[m].ent].sni & 0x00ff; |
||
265 | #undef ENT_FLG_TRIGGERS |
||
266 | |||
267 | ent_ents[e].trig_x = (S16) (map_marks[m].lt & 0xf8); |
||
268 | ent_ents[e].latency = (map_marks[m].lt & 0x07) << 5; /* <<5 eq *32 */ |
||
269 | |||
270 | ent_ents[e].trig_y = 3 + 8 * (S16) ((map_marks[m].row & 0xf8) - map_frow + (map_marks[m].lt & 0x07)); |
||
271 | |||
272 | ent_ents[e].c2 = 0; |
||
273 | ent_ents[e].offsy = 0; |
||
274 | ent_ents[e].ylow = 0; |
||
275 | |||
276 | ent_ents[e].front = FALSE; |
||
277 | } |
||
278 | } |
||
279 | |||
280 | |||
281 | /* |
||
282 | * Add a tile-aligned rectangle containing the given rectangle (indicated |
||
283 | * by its MAP coordinates) to the list of rectangles. Clip the rectangle |
||
284 | * so it fits into the display zone. |
||
285 | */ |
||
286 | static void ent_addrect (S16 x, S16 y, U16 width, U16 height) |
||
287 | { |
||
288 | S16 x0, y0; |
||
289 | U16 w0, h0; |
||
290 | |||
291 | /*sys_printf("rect %#04x,%#04x %#04x %#04x ", x, y, width, height);*/ |
||
292 | |||
293 | /* align to tiles */ |
||
294 | x0 = x & 0xfff8; |
||
295 | y0 = y & 0xfff8; |
||
296 | w0 = width; |
||
297 | h0 = height; |
||
298 | |||
299 | if (x - x0) |
||
300 | w0 = (w0 + (x - x0)) | 0x0007; |
||
301 | if (y - y0) |
||
302 | h0 = (h0 + (y - y0)) | 0x0007; |
||
303 | |||
304 | /* clip */ |
||
305 | if (draw_clipms(&x0, &y0, &w0, &h0)) |
||
306 | return; // do not add if fully clipped |
||
307 | |||
308 | /*sys_printf("-> %#04x,%#04x %#04x %#04x\n", x0, y0, w0, h0);*/ |
||
309 | |||
310 | /* get to screen */ |
||
311 | x0 -= DRAW_XYMAP_SCRLEFT; |
||
312 | y0 -= DRAW_XYMAP_SCRTOP; |
||
313 | |||
314 | /* add rectangle to the list */ |
||
315 | ent_rects = rects_new(x0, y0, w0, h0, ent_rects); |
||
316 | } |
||
317 | |||
318 | |||
319 | /* |
||
320 | * Draw all entities onto the frame buffer. |
||
321 | * |
||
322 | * ASM 07a4 |
||
323 | * |
||
324 | * NOTE This may need to be part of draw.c. Also needs better comments, |
||
325 | * NOTE and probably better rectangles management. |
||
326 | */ |
||
327 | void ent_draw (void) |
||
328 | { |
||
329 | U8 i; |
||
330 | S16 dx, dy; |
||
331 | |||
332 | draw_tilesBank = map_tilesBank; |
||
333 | |||
334 | /* reset rectangles list */ |
||
335 | rects_free (ent_rects); |
||
336 | ent_rects = NULL; |
||
337 | |||
338 | /*sys_printf("\n");*/ |
||
339 | |||
340 | /* |
||
341 | * background loop : erase all entities that were visible |
||
342 | */ |
||
343 | for (i = 0; ent_ents[i].n != 0xff; i++) |
||
344 | { |
||
345 | if (ent_ents[i].prev_n && ent_ents[i].prev_s) |
||
346 | /* if entity was active, then erase it (redraw the map) */ |
||
347 | draw_spriteBackground (ent_ents[i].prev_x, ent_ents[i].prev_y); |
||
348 | } |
||
349 | |||
350 | /* |
||
351 | * foreground loop : draw all entities that are visible |
||
352 | */ |
||
353 | for (i = 0; ent_ents[i].n != 0xff; i++) |
||
354 | { |
||
355 | /* |
||
356 | * If entity is active now, draw the sprite. If entity was |
||
357 | * not active before, add a rectangle for the sprite. |
||
358 | */ |
||
359 | if (ent_ents[i].n && ent_ents[i].sprite) |
||
360 | draw_sprite2 (ent_ents[i].sprite, ent_ents[i].x, ent_ents[i].y, ent_ents[i].front); |
||
361 | } |
||
362 | |||
363 | /* |
||
364 | * rectangles loop : figure out which parts of the screen have been |
||
365 | * impacted and need to be refreshed, then save state |
||
366 | */ |
||
367 | for (i = 0; ent_ents[i].n != 0xff; i++) |
||
368 | { |
||
369 | if (ent_ents[i].prev_n && ent_ents[i].prev_s) |
||
370 | { |
||
371 | /* (1) if entity was active and has been drawn ... */ |
||
372 | if (ent_ents[i].n && ent_ents[i].sprite) |
||
373 | { |
||
374 | /* (1.1) ... and is still active now and still needs to be drawn, */ |
||
375 | /* then check if rectangles intersect */ |
||
376 | dx = abs(ent_ents[i].x - ent_ents[i].prev_x); |
||
377 | dy = abs(ent_ents[i].y - ent_ents[i].prev_y); |
||
378 | if (dx < 0x20 && dy < 0x16) |
||
379 | { |
||
380 | /* (1.1.1) if they do, then create one rectangle */ |
||
381 | ent_addrect ((S16) ((ent_ents[i].prev_x < ent_ents[i].x) ? ent_ents[i].prev_x : ent_ents[i].x), |
||
382 | (S16) ((ent_ents[i].prev_y < ent_ents[i].y) ? ent_ents[i].prev_y : ent_ents[i].y), |
||
383 | (U16) (dx + 0x20), |
||
384 | (U16) (dy + 0x15)); |
||
385 | } |
||
386 | else |
||
387 | { |
||
388 | /* (1.1.2) else, create two rectangles */ |
||
389 | ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15); |
||
390 | ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15); |
||
391 | } |
||
392 | } |
||
393 | else |
||
394 | /* (1.2) ... and is not active anymore or does not need to be drawn */ |
||
395 | /* then create one single rectangle */ |
||
396 | ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15); |
||
397 | } |
||
398 | else if (ent_ents[i].n && ent_ents[i].sprite) |
||
399 | { |
||
400 | /* (2) if entity is active and needs to be drawn, */ |
||
401 | /* then create one rectangle */ |
||
402 | ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15); |
||
403 | } |
||
404 | |||
405 | /* save state */ |
||
406 | ent_ents[i].prev_x = ent_ents[i].x; |
||
407 | ent_ents[i].prev_y = ent_ents[i].y; |
||
408 | ent_ents[i].prev_n = ent_ents[i].n; |
||
409 | ent_ents[i].prev_s = ent_ents[i].sprite; |
||
410 | } |
||
411 | } |
||
412 | |||
413 | |||
414 | /* |
||
415 | * Clear entities previous state |
||
416 | * |
||
417 | */ |
||
418 | void ent_clprev (void) |
||
419 | { |
||
420 | U8 i; |
||
421 | |||
422 | for (i = 0; ent_ents[i].n != 0xff; i++) |
||
423 | ent_ents[i].prev_n = 0; |
||
424 | } |
||
425 | |||
426 | |||
427 | /* |
||
428 | * Table containing entity action function pointers. |
||
429 | */ |
||
430 | void (*ent_actf[]) (U8) = |
||
431 | { |
||
432 | NULL, /* 00 - zero means that the slot is free */ |
||
433 | e_rick_action, /* 01 - 12CA */ |
||
434 | e_bullet_action, /* 02 - 1883 */ |
||
435 | e_bomb_action, /* 03 - 18CA */ |
||
436 | e_them_t1a_action, /* 04 - 2452 */ |
||
437 | e_them_t1b_action, /* 05 - 21CA */ |
||
438 | e_them_t2_action, /* 06 - 2718 */ |
||
439 | e_them_t1a_action, /* 07 - 2452 */ |
||
440 | e_them_t1b_action, /* 08 - 21CA */ |
||
441 | e_them_t2_action, /* 09 - 2718 */ |
||
442 | e_them_t1a_action, /* 0A - 2452 */ |
||
443 | e_them_t1b_action, /* 0B - 21CA */ |
||
444 | e_them_t2_action, /* 0C - 2718 */ |
||
445 | e_them_t1a_action, /* 0D - 2452 */ |
||
446 | e_them_t1b_action, /* 0E - 21CA */ |
||
447 | e_them_t2_action, /* 0F - 2718 */ |
||
448 | e_box_action, /* 10 - 245A */ |
||
449 | e_box_action, /* 11 - 245A */ |
||
450 | e_bonus_action, /* 12 - 242C */ |
||
451 | e_bonus_action, /* 13 - 242C */ |
||
452 | e_bonus_action, /* 14 - 242C */ |
||
453 | e_bonus_action, /* 15 - 242C */ |
||
454 | e_sbonus_start, /* 16 - 2182 */ |
||
455 | e_sbonus_stop /* 17 - 2143 */ |
||
456 | }; |
||
457 | |||
458 | |||
459 | /* |
||
460 | * Run entities action function |
||
461 | * |
||
462 | */ |
||
463 | void ent_action (void) |
||
464 | { |
||
465 | U8 i, k; |
||
466 | |||
467 | for (i = 0; ent_ents[i].n != 0xff; i++) |
||
468 | { |
||
469 | if (ent_ents[i].n) |
||
470 | { |
||
471 | k = ent_ents[i].n & 0x7f; |
||
472 | if (k == 0x47) |
||
473 | e_them_z_action (i); |
||
474 | else if (k >= 0x18) |
||
475 | e_them_t3_action (i); |
||
476 | else |
||
477 | ent_actf[k] (i); |
||
478 | } |
||
479 | } |
||
480 | } |