Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 1 | pmbaty | 1 | /* | 
| 2 |  * src/e_them.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 "system.h" | ||
| 15 | #include "game.h" | ||
| 16 | #include "ents.h" | ||
| 17 | #include "e_them.h" | ||
| 18 | |||
| 19 | #include "e_rick.h" | ||
| 20 | #include "e_bomb.h" | ||
| 21 | #include "e_bullet.h" | ||
| 22 | #include "maps.h" | ||
| 23 | #include "util.h" | ||
| 24 | |||
| 25 | #define TYPE_1A (0x00) | ||
| 26 | #define TYPE_1B (0xff) | ||
| 27 | |||
| 28 | |||
| 29 | /* | ||
| 30 |  * public vars | ||
| 31 |  */ | ||
| 32 | U32 e_them_rndseed = 0; | ||
| 33 | |||
| 34 | |||
| 35 | /* | ||
| 36 |  * local vars | ||
| 37 |  */ | ||
| 38 | static U16 e_them_rndnbr = 0; | ||
| 39 | |||
| 40 | |||
| 41 | /* | ||
| 42 |  * Check if entity boxtests with a lethal e_them i.e. something lethal | ||
| 43 |  * in slot 0 and 4 to 8. | ||
| 44 |  * | ||
| 45 |  * ASM 122E | ||
| 46 |  * | ||
| 47 |  * e: entity slot number. | ||
| 48 |  * ret: TRUE/boxtests, FALSE/not | ||
| 49 |  */ | ||
| 50 | U8 u_themtest (U8 e) | ||
| 51 | { | ||
| 52 |    U8 i; | ||
| 53 | |||
| 54 | if ((ent_ents[0].n & ENT_LETHAL) && u_boxtest (e, 0)) | ||
| 55 | return TRUE; | ||
| 56 | |||
| 57 | for (i = 4; i < 9; i++) | ||
| 58 | if ((ent_ents[i].n & ENT_LETHAL) && u_boxtest (e, i)) | ||
| 59 | return TRUE; | ||
| 60 | |||
| 61 | return FALSE; | ||
| 62 | } | ||
| 63 | |||
| 64 | |||
| 65 | /* | ||
| 66 |  * Go zombie | ||
| 67 |  * | ||
| 68 |  * ASM 237B | ||
| 69 |  */ | ||
| 70 | void e_them_gozombie (U8 e) | ||
| 71 | { | ||
| 72 | #define offsx c1 | ||
| 73 | ent_ents[e].n = 0x47; /* zombie entity */ | ||
| 74 | ent_ents[e].front = TRUE; | ||
| 75 | ent_ents[e].offsy = -0x0400; | ||
| 76 | syssnd_play(WAV_DIE, 1); | ||
| 77 | game_score += 50; | ||
| 78 | if (ent_ents[e].flags & ENT_FLG_ONCE) | ||
| 79 |    { | ||
| 80 |       /* make sure entity won't be activated again */ | ||
| 81 | map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT; | ||
| 82 |    } | ||
| 83 | ent_ents[e].offsx = (ent_ents[e].x >= 0x80 ? -0x02 : 0x02); | ||
| 84 | #undef offsx | ||
| 85 | } | ||
| 86 | |||
| 87 | |||
| 88 | /* | ||
| 89 |  * Action sub-function for e_them _t1a and _t1b | ||
| 90 |  * | ||
| 91 |  * Those two types move horizontally, and fall if they have to. | ||
| 92 |  * Type 1a moves horizontally over a given distance and then | ||
| 93 |  * u-turns and repeats; type 1b is more subtle as it does u-turns | ||
| 94 |  * in order to move horizontally towards rick. | ||
| 95 |  * | ||
| 96 |  * ASM 2242 | ||
| 97 |  */ | ||
| 98 | void e_them_t1_action2 (U8 e, U8 type) | ||
| 99 | { | ||
| 100 | #define offsx c1 | ||
| 101 | #define step_count c2 | ||
| 102 |    U32 i; | ||
| 103 | S16 x, y; | ||
| 104 | U8 env0, env1; | ||
| 105 | |||
| 106 |    /* by default, try vertical move. calculate new y */ | ||
| 107 | i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow; | ||
| 108 | y = (S16) (i >> 8); | ||
| 109 | |||
| 110 |    /* deactivate if outside vertical boundaries */ | ||
| 111 |    /* no need to test zero since e_them _t1a/b don't go up */ | ||
| 112 |    /* FIXME what if they got scrolled out ? */ | ||
| 113 | if (y > 0x140) | ||
| 114 |    { | ||
| 115 | ent_ents[e].n = 0; | ||
| 116 | return; | ||
| 117 |    } | ||
| 118 | |||
| 119 |    /* test environment */ | ||
| 120 | u_envtest (ent_ents[e].x, y, FALSE, &env0, &env1); | ||
| 121 | |||
| 122 | if (!(env1 & (MAP_EFLG_VERT | MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP))) | ||
| 123 |    { | ||
| 124 |       /* vertical move possible: falling */ | ||
| 125 | if (env1 & MAP_EFLG_LETHAL) | ||
| 126 |       { | ||
| 127 |          /* lethal entities kill e_them */ | ||
| 128 | e_them_gozombie (e); | ||
| 129 | return; | ||
| 130 |       } | ||
| 131 | |||
| 132 |       /* save, cleanup and return */ | ||
| 133 | ent_ents[e].y = y; | ||
| 134 | ent_ents[e].ylow = (U8) i; | ||
| 135 | ent_ents[e].offsy += 0x0080; | ||
| 136 | |||
| 137 | if (ent_ents[e].offsy > 0x0800) | ||
| 138 | ent_ents[e].offsy = 0x0800; | ||
| 139 | |||
| 140 | return; | ||
| 141 |    } | ||
| 142 | |||
| 143 |    /* vertical move not possible. calculate new sprite */ | ||
| 144 | ent_ents[e].sprite = ent_ents[e].sprbase + ent_sprseq[(ent_ents[e].x & 0x1c) >> 3] + (ent_ents[e].offsx < 0 ? 0x03 : 0x00); | ||
| 145 | |||
| 146 |    /* reset offsy */ | ||
| 147 | ent_ents[e].offsy = 0x0080; | ||
| 148 | |||
| 149 |    /* align to ground */ | ||
| 150 | ent_ents[e].y &= 0xfff8; | ||
| 151 | ent_ents[e].y |= 0x0003; | ||
| 152 | |||
| 153 |    /* latency: if not zero then decrease and return */ | ||
| 154 | if (ent_ents[e].latency > 0) | ||
| 155 |    { | ||
| 156 | ent_ents[e].latency--; | ||
| 157 | return; | ||
| 158 |    } | ||
| 159 | |||
| 160 |    /* horizontal move. calculate new x */ | ||
| 161 | if (ent_ents[e].offsx == 0) /* not supposed to move -> don't */ | ||
| 162 | return; | ||
| 163 | |||
| 164 | x = ent_ents[e].x + ent_ents[e].offsx; | ||
| 165 | if (ent_ents[e].x < 0x01 || ent_ents[e].x > 0xe8) | ||
| 166 |    { | ||
| 167 |       /* deactivate if reaching horizontal boundaries */ | ||
| 168 | ent_ents[e].n = 0; | ||
| 169 | return; | ||
| 170 |    } | ||
| 171 | |||
| 172 |    /* test environment */ | ||
| 173 | u_envtest (x, ent_ents[e].y, FALSE, &env0, &env1); | ||
| 174 | |||
| 175 | if (env1 & (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP)) | ||
| 176 |    { | ||
| 177 |       /* horizontal move not possible: u-turn and return */ | ||
| 178 | ent_ents[e].step_count = 0; | ||
| 179 | ent_ents[e].offsx = -ent_ents[e].offsx; | ||
| 180 | return; | ||
| 181 |    } | ||
| 182 | |||
| 183 |    /* horizontal move possible */ | ||
| 184 | if (env1 & MAP_EFLG_LETHAL) | ||
| 185 |    { | ||
| 186 |       /* lethal entities kill e_them */ | ||
| 187 | e_them_gozombie (e); | ||
| 188 | return; | ||
| 189 |    } | ||
| 190 | |||
| 191 |    /* save */ | ||
| 192 | ent_ents[e].x = x; | ||
| 193 | |||
| 194 |    /* depending on type, */ | ||
| 195 | if (type == TYPE_1B) | ||
| 196 |    { | ||
| 197 |       /* set direction to move horizontally towards rick */ | ||
| 198 | if ((ent_ents[e].x & 0x1e) != 0x10) /* prevents too frequent u-turns */ | ||
| 199 | return; | ||
| 200 | ent_ents[e].offsx = (ent_ents[e].x < E_RICK_ENT.x) ? 0x02 : -0x02; | ||
| 201 | return; | ||
| 202 |    } | ||
| 203 |    else | ||
| 204 |    { | ||
| 205 |       /* set direction according to step counter */ | ||
| 206 | ent_ents[e].step_count++; | ||
| 207 | |||
| 208 |       /* FIXME why trig_x (b16) ?? */ | ||
| 209 | if ((ent_ents[e].trig_x >> 1) > ent_ents[e].step_count) | ||
| 210 | return; | ||
| 9 | pmbaty | 211 | |
| 212 |       /* type is 1A and step counter reached its limit: u-turn */ | ||
| 213 | ent_ents[e].step_count = 0; | ||
| 214 | ent_ents[e].offsx = -ent_ents[e].offsx; | ||
| 1 | pmbaty | 215 |    } | 
| 216 | #undef offsx | ||
| 217 | #undef step_count | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | /* | ||
| 222 |  * ASM 21CF | ||
| 223 |  */ | ||
| 224 | void e_them_t1_action (U8 e, U8 type) | ||
| 225 | { | ||
| 226 | e_them_t1_action2 (e, type); | ||
| 227 | |||
| 228 |    /* lethal entities kill them */ | ||
| 229 | if (u_themtest (e)) | ||
| 230 |    { | ||
| 231 | e_them_gozombie (e); | ||
| 232 | return; | ||
| 233 |    } | ||
| 234 | |||
| 235 |    /* bullet kills them */ | ||
| 236 | if (E_BULLET_ENT.n && u_fboxtest (e, (S16) (E_BULLET_ENT.x + (e_bullet_offsx < 0 ? 0 : 0x18)), E_BULLET_ENT.y)) | ||
| 237 |    { | ||
| 238 | E_BULLET_ENT.n = 0; | ||
| 239 | e_them_gozombie (e); | ||
| 240 | return; | ||
| 241 |    } | ||
| 242 | |||
| 243 |    /* bomb kills them */ | ||
| 244 | if (e_bomb_lethal && e_bomb_hit (e)) | ||
| 245 |    { | ||
| 246 | e_them_gozombie (e); | ||
| 247 | return; | ||
| 248 |    } | ||
| 249 | |||
| 250 | if (E_RICK_STTST (E_RICK_STZOMBIE)) | ||
| 251 | return; | ||
| 252 | |||
| 253 |    /* rick stops them */ | ||
| 254 | if (E_RICK_STTST (E_RICK_STSTOP) && u_fboxtest (e, e_rick_stop_x, e_rick_stop_y)) | ||
| 255 | ent_ents[e].latency = 0x14; | ||
| 256 | |||
| 257 |    /* they kill rick */ | ||
| 258 | if (e_rick_boxtest (e)) | ||
| 259 | e_rick_gozombie (); | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | /* | ||
| 264 |  * Action function for e_them _t1a type (stays within boundaries) | ||
| 265 |  * | ||
| 266 |  * ASM 2452 | ||
| 267 |  */ | ||
| 268 | void e_them_t1a_action (U8 e) | ||
| 269 | { | ||
| 270 | e_them_t1_action (e, TYPE_1A); | ||
| 271 | } | ||
| 272 | |||
| 273 | |||
| 274 | /* | ||
| 275 |  * Action function for e_them _t1b type (runs for rick) | ||
| 276 |  * | ||
| 277 |  * ASM 21CA | ||
| 278 |  */ | ||
| 279 | void e_them_t1b_action (U8 e) | ||
| 280 | { | ||
| 281 | e_them_t1_action (e, TYPE_1B); | ||
| 282 | } | ||
| 283 | |||
| 284 | |||
| 285 | /* | ||
| 286 |  * Action function for e_them _z (zombie) type | ||
| 287 |  * | ||
| 288 |  * ASM 23B8 | ||
| 289 |  */ | ||
| 290 | void e_them_z_action (U8 e) | ||
| 291 | { | ||
| 292 | #define offsx c1 | ||
| 293 |    U32 i; | ||
| 294 | |||
| 295 |    /* calc new sprite */ | ||
| 296 | ent_ents[e].sprite = ent_ents[e].sprbase + ((ent_ents[e].x & 0x04) ? 0x07 : 0x06); | ||
| 297 | |||
| 298 |    /* calc new y */ | ||
| 299 | i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow; | ||
| 300 | |||
| 301 |    /* deactivate if out of vertical boundaries */ | ||
| 302 | if (ent_ents[e].y < 0 || ent_ents[e].y > 0x0140) | ||
| 303 |    { | ||
| 304 | ent_ents[e].n = 0; | ||
| 305 | return; | ||
| 306 |    } | ||
| 307 | |||
| 308 |    /* save */ | ||
| 309 | ent_ents[e].offsy += 0x0080; | ||
| 310 | ent_ents[e].ylow = (U8) i; | ||
| 311 | ent_ents[e].y = (S16) (i >> 8); | ||
| 312 | |||
| 313 |    /* calc new x */ | ||
| 314 | ent_ents[e].x += ent_ents[e].offsx; | ||
| 315 | |||
| 316 |    /* must stay within horizontal boundaries */ | ||
| 317 | if (ent_ents[e].x < 0) | ||
| 318 | ent_ents[e].x = 0; | ||
| 319 | if (ent_ents[e].x > 0xe8) | ||
| 320 | ent_ents[e].x = 0xe8; | ||
| 321 | #undef offsx | ||
| 322 | } | ||
| 323 | |||
| 324 | |||
| 325 | /* | ||
| 326 |  * Action sub-function for e_them _t2. | ||
| 327 |  * | ||
| 328 |  * Must document what it does. | ||
| 329 |  * | ||
| 330 |  * ASM 2792 | ||
| 331 |  */ | ||
| 332 | void e_them_t2_action2 (U8 e) | ||
| 333 | { | ||
| 334 | #define flgclmb c1 | ||
| 335 | #define offsx c2 | ||
| 336 |    U32 i; | ||
| 337 | S16 x, y, yd; | ||
| 338 | U8 env0, env1; | ||
| 339 | |||
| 340 |    /* | ||
| 341 |     * vars required by the Black Magic (tm) performance at the | ||
| 342 |     * end of this function. | ||
| 343 |     */ | ||
| 344 | static U16 bx; | ||
| 345 | static U8 *bl = (U8 *)&bx; | ||
| 346 | static U8 *bh = (U8 *)&bx + 1; | ||
| 347 | static U16 cx; | ||
| 348 | static U8 *cl = (U8 *)&cx; | ||
| 349 | static U8 *ch = (U8 *)&cx + 1; | ||
| 350 | static U16 *sl = (U16 *)&e_them_rndseed; | ||
| 351 | static U16 *sh = (U16 *)&e_them_rndseed + 2; | ||
| 352 | |||
| 353 |    /*sys_printf("e_them_t2 ------------------------------\n");*/ | ||
| 354 | |||
| 355 |    /* latency: if not zero then decrease */ | ||
| 356 | if (ent_ents[e].latency > 0) | ||
| 357 | ent_ents[e].latency--; | ||
| 358 | |||
| 359 |    /* climbing? */ | ||
| 360 | if (ent_ents[e].flgclmb != TRUE) | ||
| 361 | goto climbing_not; | ||
| 362 | |||
| 363 |    /* CLIMBING */ | ||
| 364 | |||
| 365 |    /*sys_printf("e_them_t2 climbing\n");*/ | ||
| 366 | |||
| 367 |    /* latency: if not zero then return */ | ||
| 368 | if (ent_ents[e].latency > 0) | ||
| 369 | return; | ||
| 370 | |||
| 371 |    /* calc new sprite */ | ||
| 372 | ent_ents[e].sprite = ent_ents[e].sprbase + 0x08 + (((ent_ents[e].x ^ ent_ents[e].y) & 0x04) ? 1 : 0); | ||
| 373 | |||
| 374 |    /* reached rick's level? */ | ||
| 375 | if ((ent_ents[e].y & 0xfe) != (E_RICK_ENT.y & 0xfe)) | ||
| 376 | goto ymove; | ||
| 377 | |||
| 378 | xmove: | ||
| 379 |       /* calc new x and test environment */ | ||
| 380 | ent_ents[e].offsx = (ent_ents[e].x < E_RICK_ENT.x) ? 0x02 : -0x02; | ||
| 381 | x = ent_ents[e].x + ent_ents[e].offsx; | ||
| 382 | u_envtest (x, ent_ents[e].y, FALSE, &env0, &env1); | ||
| 383 | |||
| 384 | if (env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP)) | ||
| 385 | return; | ||
| 386 | |||
| 387 | if (env1 & MAP_EFLG_LETHAL) | ||
| 388 |       { | ||
| 389 | e_them_gozombie(e); | ||
| 390 | return; | ||
| 391 |       } | ||
| 392 | |||
| 393 | ent_ents[e].x = x; | ||
| 394 | |||
| 395 | if (env1 & (MAP_EFLG_VERT | MAP_EFLG_CLIMB)) /* still climbing */ | ||
| 396 | return; | ||
| 397 | |||
| 398 | goto climbing_not; /* not climbing anymore */ | ||
| 399 | |||
| 400 | ymove: | ||
| 401 |       /* calc new y and test environment */ | ||
| 402 | yd = ent_ents[e].y < E_RICK_ENT.y ? 0x02 : -0x02; | ||
| 403 | y = ent_ents[e].y + yd; | ||
| 404 | |||
| 405 | if (y < 0 || y > 0x0140) | ||
| 406 |       { | ||
| 407 | ent_ents[e].n = 0; | ||
| 408 | return; | ||
| 409 |       } | ||
| 410 | |||
| 411 | u_envtest (ent_ents[e].x, y, FALSE, &env0, &env1); | ||
| 412 | |||
| 413 | if (env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP)) | ||
| 414 |       { | ||
| 415 | if (yd < 0) | ||
| 416 | goto xmove; /* can't go up */ | ||
| 417 |          else | ||
| 418 | goto climbing_not; /* can't go down */ | ||
| 419 |       } | ||
| 420 | |||
| 421 |       /* can move */ | ||
| 422 | ent_ents[e].y = y; | ||
| 423 | |||
| 424 | if (env1 & (MAP_EFLG_VERT | MAP_EFLG_CLIMB)) /* still climbing */ | ||
| 425 | return; | ||
| 426 | |||
| 427 |       /* NOT CLIMBING */ | ||
| 428 | |||
| 429 | climbing_not: | ||
| 430 |       /*sys_printf ("e_them_t2 climbing NOT\n");*/ | ||
| 431 | |||
| 432 | ent_ents[e].flgclmb = FALSE; /* not climbing */ | ||
| 433 | |||
| 434 |       /* calc new y (falling) and test environment */ | ||
| 435 | i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow; | ||
| 436 | y = (S16) (i >> 8); | ||
| 437 | |||
| 438 | u_envtest (ent_ents[e].x, y, FALSE, &env0, &env1); | ||
| 439 | |||
| 440 | if (!(env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP))) | ||
| 441 |       { | ||
| 442 |          /*sys_printf ("e_them_t2 y move OK\n");*/ | ||
| 443 |          /* can go there */ | ||
| 444 | if (env1 & MAP_EFLG_LETHAL) | ||
| 445 |          { | ||
| 446 | e_them_gozombie (e); | ||
| 447 | return; | ||
| 448 |          } | ||
| 449 | |||
| 450 | if (y > 0x0140) | ||
| 451 |          { | ||
| 452 |             /* deactivate if outside */ | ||
| 453 | ent_ents[e].n = 0; | ||
| 454 | return; | ||
| 455 |          } | ||
| 456 | |||
| 457 | if (!(env1 & MAP_EFLG_VERT)) | ||
| 458 |          { | ||
| 459 |             /* save */ | ||
| 460 | ent_ents[e].y = y; | ||
| 461 | ent_ents[e].ylow = (U8) i; | ||
| 462 | ent_ents[e].offsy += 0x0080; | ||
| 463 | |||
| 464 | if (ent_ents[e].offsy > 0x0800) | ||
| 465 | ent_ents[e].offsy = 0x0800; | ||
| 466 | |||
| 467 | return; | ||
| 468 |          } | ||
| 469 | |||
| 470 | if (((ent_ents[e].x & 0x07) == 0x04) && (y < E_RICK_ENT.y)) | ||
| 471 |          { | ||
| 472 |             /*sys_printf ("e_them_t2 climbing00\n");*/ | ||
| 473 | ent_ents[e].flgclmb = TRUE; /* climbing */ | ||
| 474 | return; | ||
| 475 |          } | ||
| 476 |       } | ||
| 477 | |||
| 478 |       /*sys_printf("e_them_t2 ymove nok or ...\n");*/ | ||
| 479 |       /* can't go there, or ... */ | ||
| 480 | ent_ents[e].y = (ent_ents[e].y & 0xf8) | 0x03; /* align to ground */ | ||
| 481 | ent_ents[e].offsy = 0x0100; | ||
| 482 | if (ent_ents[e].latency != 00) | ||
| 483 | return; | ||
| 484 | |||
| 485 | if ((env1 & MAP_EFLG_CLIMB) && ((ent_ents[e].x & 0x0e) == 0x04) && (ent_ents[e].y > E_RICK_ENT.y)) | ||
| 486 |       { | ||
| 487 |          /*sys_printf ("e_them_t2 climbing01\n");*/ | ||
| 488 | ent_ents[e].flgclmb = TRUE; /* climbing */ | ||
| 489 | return; | ||
| 490 |       } | ||
| 491 | |||
| 492 |       /* calc new sprite */ | ||
| 493 | ent_ents[e].sprite = ent_ents[e].sprbase + ent_sprseq[(ent_ents[e].offsx < 0 ? 4 : 0) + ((ent_ents[e].x & 0x0e) >> 3)]; | ||
| 494 |       /*sys_printf ("e_them_t2 sprite %02x\n", ent_ents[e].sprite);*/ | ||
| 495 | |||
| 496 | |||
| 497 |       /* */ | ||
| 498 | if (ent_ents[e].offsx == 0) | ||
| 499 | ent_ents[e].offsx = 2; | ||
| 500 | |||
| 501 | x = ent_ents[e].x + ent_ents[e].offsx; | ||
| 502 | |||
| 503 |       /*sys_printf ("e_them_t2 xmove x=%02x\n", x);*/ | ||
| 504 | |||
| 505 | if (x < 0xe8) | ||
| 506 |       { | ||
| 507 | u_envtest (x, ent_ents[e].y, FALSE, &env0, &env1); | ||
| 508 | if (!(env1 & (MAP_EFLG_VERT | MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP))) | ||
| 509 |          { | ||
| 510 | ent_ents[e].x = x; | ||
| 511 | |||
| 512 | if ((x & 0x1e) != 0x08) | ||
| 513 | return; | ||
| 514 | |||
| 515 |             /* | ||
| 516 |              * Black Magic (tm) | ||
| 517 |              * | ||
| 518 |              * this is obviously some sort of randomizer to define a direction | ||
| 519 |              * for the entity. it is an exact copy of what the assembler code | ||
| 520 |              * does but I can't explain. | ||
| 521 |              */ | ||
| 522 | bx = e_them_rndnbr + *sh + *sl + 0x0d; | ||
| 523 | cx = *sh; | ||
| 524 | *bl ^= *ch; | ||
| 525 | *bl ^= *cl; | ||
| 526 | *bl ^= *bh; | ||
| 527 | e_them_rndnbr = bx; | ||
| 528 | |||
| 529 | ent_ents[e].offsx = (*bl & 0x01) ? -0x02 : 0x02; | ||
| 530 | |||
| 531 |             /* back to normal */ | ||
| 532 | |||
| 533 | return; | ||
| 534 |          } | ||
| 535 |       } | ||
| 536 | |||
| 537 |       /* U-turn */ | ||
| 538 |       /*sys_printf ("e_them_t2 u-turn\n");*/ | ||
| 539 | if (ent_ents[e].offsx == 0) | ||
| 540 | ent_ents[e].offsx = 2; | ||
| 541 |       else | ||
| 542 | ent_ents[e].offsx = -ent_ents[e].offsx; | ||
| 543 | #undef offsx | ||
| 544 | } | ||
| 545 | |||
| 546 | |||
| 547 | /* | ||
| 548 |  * Action function for e_them _t2 type | ||
| 549 |  * | ||
| 550 |  * ASM 2718 | ||
| 551 |  */ | ||
| 552 | void e_them_t2_action (U8 e) | ||
| 553 | { | ||
| 554 | e_them_t2_action2 (e); | ||
| 555 | |||
| 556 |    /* they kill rick */ | ||
| 557 | if (e_rick_boxtest (e)) | ||
| 558 | e_rick_gozombie (); | ||
| 559 | |||
| 560 |    /* lethal entities kill them */ | ||
| 561 | if (u_themtest (e)) | ||
| 562 |    { | ||
| 563 | e_them_gozombie (e); | ||
| 564 | return; | ||
| 565 |    } | ||
| 566 | |||
| 567 |    /* bullet kills them */ | ||
| 568 | if (E_BULLET_ENT.n && u_fboxtest (e, (S16) (E_BULLET_ENT.x + (e_bullet_offsx < 0 ? 00 : 0x18)), E_BULLET_ENT.y)) | ||
| 569 |    { | ||
| 570 | E_BULLET_ENT.n = 0; | ||
| 571 | e_them_gozombie (e); | ||
| 572 | return; | ||
| 573 |    } | ||
| 574 | |||
| 575 |    /* bomb kills them */ | ||
| 576 | if (e_bomb_lethal && e_bomb_hit (e)) | ||
| 577 |    { | ||
| 578 | e_them_gozombie (e); | ||
| 579 | return; | ||
| 580 |    } | ||
| 581 | |||
| 582 |    /* rick stops them */ | ||
| 583 | if (E_RICK_STTST (E_RICK_STSTOP) && u_fboxtest (e, e_rick_stop_x, e_rick_stop_y)) | ||
| 584 | ent_ents[e].latency = 0x14; | ||
| 585 | } | ||
| 586 | |||
| 587 | |||
| 588 | /* | ||
| 589 |  * Action sub-function for e_them _t3 | ||
| 590 |  * | ||
| 591 |  * FIXME always starts asleep?? | ||
| 592 |  * | ||
| 593 |  * Waits until triggered by something, then execute move steps from | ||
| 594 |  * ent_mvstep with sprite from ent_sprseq. When done, either restart | ||
| 595 |  * or disappear. | ||
| 596 |  * | ||
| 597 |  * Not always lethal ... but if lethal, kills rick. | ||
| 598 |  * | ||
| 599 |  * ASM: 255A | ||
| 600 |  */ | ||
| 601 | void e_them_t3_action2 (U8 e) | ||
| 602 | { | ||
| 603 | #define sproffs c1 | ||
| 604 | #define step_count c2 | ||
| 605 |    U8 i; | ||
| 606 | S16 x, y; | ||
| 607 | |||
| 608 | while (1) | ||
| 609 |    { | ||
| 610 |       /* calc new sprite */ | ||
| 611 | i = ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs]; | ||
| 612 | if (i == 0xff) | ||
| 613 | i = ent_sprseq[ent_ents[e].sprbase]; | ||
| 614 | ent_ents[e].sprite = i; | ||
| 615 | |||
| 616 | if (ent_ents[e].sproffs != 0) | ||
| 617 |       { | ||
| 618 |          /* awake */ | ||
| 619 | |||
| 620 |          /* rotate sprseq */ | ||
| 621 | if (ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs] != 0xff) | ||
| 622 | ent_ents[e].sproffs++; | ||
| 623 | if (ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs] == 0xff) | ||
| 624 | ent_ents[e].sproffs = 1; | ||
| 625 | |||
| 626 | if (ent_ents[e].step_count < ent_mvstep[ent_ents[e].step_no].count) | ||
| 627 |          { | ||
| 628 |             /* | ||
| 629 |              * still running this step: try to increment x and y while | ||
| 630 |              * checking that they remain within boudaries. if so, return. | ||
| 631 |              * else switch to next step. | ||
| 632 |              */ | ||
| 633 | ent_ents[e].step_count++; | ||
| 634 | x = ent_ents[e].x + ent_mvstep[ent_ents[e].step_no].dx; | ||
| 635 | |||
| 636 |             /* check'n save */ | ||
| 637 | if (x > 0 && x < 0xe8) | ||
| 638 |             { | ||
| 639 | ent_ents[e].x = x; | ||
| 640 |                /*FIXME*/ | ||
| 641 |                /* | ||
| 642 |                y = ent_mvstep[ent_ents[e].step_no].dy; | ||
| 643 |                if (y < 0) | ||
| 644 |                y += 0xff00; | ||
| 645 |                y += ent_ents[e].y; | ||
| 646 |                */ | ||
| 647 | y = ent_ents[e].y + ent_mvstep[ent_ents[e].step_no].dy; | ||
| 648 | if (y > 0 && y < 0x0140) | ||
| 649 |                { | ||
| 650 | ent_ents[e].y = y; | ||
| 651 | return; | ||
| 652 |                } | ||
| 653 |             } | ||
| 654 |          } | ||
| 655 | |||
| 656 |          /* | ||
| 657 |           * step is done, or x or y is outside boundaries. try to | ||
| 658 |           * switch to next step | ||
| 659 |           */ | ||
| 660 | ent_ents[e].step_no++; | ||
| 661 | if (ent_mvstep[ent_ents[e].step_no].count != 0xff) | ||
| 662 | ent_ents[e].step_count = 0; // there is a next step: init and loop | ||
| 663 |          else | ||
| 664 |          { | ||
| 665 |             /* there is no next step: restart or deactivate */ | ||
| 666 | if (!E_RICK_STTST (E_RICK_STZOMBIE) && !(ent_ents[e].flags & ENT_FLG_ONCE)) | ||
| 667 |             { | ||
| 668 |                /* loop this entity */ | ||
| 669 | ent_ents[e].sproffs = 0; | ||
| 670 | ent_ents[e].n &= ~ENT_LETHAL; | ||
| 671 | |||
| 672 | if (ent_ents[e].flags & ENT_FLG_LETHALR) | ||
| 673 | ent_ents[e].n |= ENT_LETHAL; | ||
| 674 | |||
| 675 | ent_ents[e].x = ent_ents[e].xsave; | ||
| 676 | ent_ents[e].y = ent_ents[e].ysave; | ||
| 677 | |||
| 678 | if (ent_ents[e].y < 0 || ent_ents[e].y > 0x140) | ||
| 679 |                { | ||
| 680 | ent_ents[e].n = 0; | ||
| 681 | return; | ||
| 682 |                } | ||
| 683 |             } | ||
| 684 |             else | ||
| 685 |             { | ||
| 686 |                /* deactivate this entity */ | ||
| 687 | ent_ents[e].n = 0; | ||
| 688 | return; | ||
| 689 |             } | ||
| 690 |          } | ||
| 691 |       } | ||
| 692 |       else | ||
| 693 |       { | ||
| 694 |          /* ent_ents[e].sprseq1 == 0 -- waiting */ | ||
| 695 | |||
| 696 |          /* ugly GOTOs */ | ||
| 697 | |||
| 698 |          /* reacts to rick */ | ||
| 699 | if (ent_ents[e].flags & ENT_FLG_TRIGRICK) | ||
| 700 |          { | ||
| 701 |             /* wake up if triggered by rick */ | ||
| 702 | if (u_trigbox (e, (S16) (E_RICK_ENT.x + 0x0C), (S16) (E_RICK_ENT.y + 0x0A))) | ||
| 703 | goto wakeup; | ||
| 704 |          } | ||
| 705 | |||
| 706 |          /* reacts to rick "stop" */ | ||
| 707 | if (ent_ents[e].flags & ENT_FLG_TRIGSTOP) | ||
| 708 |          { | ||
| 709 |             /* wake up if triggered by rick "stop" */ | ||
| 710 | if (E_RICK_STTST(E_RICK_STSTOP) && u_trigbox (e, e_rick_stop_x, e_rick_stop_y)) | ||
| 711 | goto wakeup; | ||
| 712 |          } | ||
| 713 | |||
| 714 |          /* reacts to bullets */ | ||
| 715 | if (ent_ents[e].flags & ENT_FLG_TRIGBULLET) | ||
| 716 |          { | ||
| 717 |             /* wake up if triggered by bullet */ | ||
| 718 | if (E_BULLET_ENT.n && u_trigbox(e, e_bullet_xc, e_bullet_yc)) | ||
| 719 |             { | ||
| 720 | E_BULLET_ENT.n = 0; | ||
| 721 | goto wakeup; | ||
| 722 |             } | ||
| 723 |          } | ||
| 724 | |||
| 725 |          /* reacts to bombs */ | ||
| 726 | if (ent_ents[e].flags & ENT_FLG_TRIGBOMB) | ||
| 727 |          { | ||
| 728 |             /* wake up if triggered by bomb */ | ||
| 729 | if (e_bomb_lethal && u_trigbox(e, e_bomb_xc, e_bomb_yc)) | ||
| 730 | goto wakeup; | ||
| 731 |          } | ||
| 732 | |||
| 733 |          /* not triggered: keep waiting */ | ||
| 734 | return; | ||
| 735 | |||
| 736 |          /* something triggered the entity: wake up */ | ||
| 737 |          /* initialize step counter */ | ||
| 738 | wakeup: | ||
| 739 | if (E_RICK_STTST (E_RICK_STZOMBIE)) | ||
| 740 | return; | ||
| 741 | |||
| 742 |          /* | ||
| 743 |           * FIXME the sound should come from a table, there are 10 of them | ||
| 744 |           * but I dont have the table yet. must rip the data off the game... | ||
| 745 |           * FIXME is it 8 of them, not 10? | ||
| 746 |           * FIXME testing below... | ||
| 747 |           */ | ||
| 748 | if ((ent_ents[e].trigsnd & 0x1F) != 0) | ||
| 749 | syssnd_play(WAV_ENTITY[(ent_ents[e].trigsnd & 0x1F) - 0x14], 1); | ||
| 750 | |||
| 751 | ent_ents[e].n &= ~ENT_LETHAL; | ||
| 752 | |||
| 753 | if (ent_ents[e].flags & ENT_FLG_LETHALI) | ||
| 754 | ent_ents[e].n |= ENT_LETHAL; | ||
| 755 | |||
| 756 | ent_ents[e].sproffs = 1; | ||
| 757 | ent_ents[e].step_count = 0; | ||
| 758 | ent_ents[e].step_no = ent_ents[e].step_no_i; | ||
| 759 | return; | ||
| 760 |       } | ||
| 761 |    } | ||
| 762 | #undef step_count | ||
| 763 | } | ||
| 764 | |||
| 765 | |||
| 766 | /* | ||
| 767 |  * Action function for e_them _t3 type | ||
| 768 |  * | ||
| 769 |  * ASM 2546 | ||
| 770 |  */ | ||
| 771 | void e_them_t3_action (U8 e) | ||
| 772 | { | ||
| 773 | e_them_t3_action2 (e); | ||
| 774 | |||
| 775 |    /* if lethal, can kill rick */ | ||
| 776 | if ((ent_ents[e].n & ENT_LETHAL) && !E_RICK_STTST (E_RICK_STZOMBIE) && e_rick_boxtest (e)) | ||
| 777 | e_rick_gozombie (); // CALL 1130 | ||
| 778 | } |