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