A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 540 lines 14 kB view raw
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 */