Subversion Repositories Games.Rick Dangerous

Rev

Blame | Last modification | View Log | Download | RSS feed

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