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 | } |