- /* 
-  * src/e_rick.c 
-  * 
-  * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net). All rights reserved. 
-  * 
-  * The use and distribution terms for this software are contained in the file 
-  * named README, which can be found in the root of this distribution. By 
-  * using this software in any fashion, you are agreeing to be bound by the 
-  * terms of this license. 
-  * 
-  * You must not remove this notice, or any other, from this software. 
-  */ 
-   
- #include "system.h" 
- #include "game.h" 
- #include "ents.h" 
- #include "e_rick.h" 
-   
- #include "e_bullet.h" 
- #include "e_bomb.h" 
- #include "control.h" 
- #include "maps.h" 
- #include "util.h" 
-   
- /* 
-  * public vars 
-  */ 
- S16 e_rick_stop_x = 0; 
- S16 e_rick_stop_y = 0; 
- U8 e_rick_state = 0; 
-   
- /* 
-  * local vars 
-  */ 
- static U8 scrawl; 
-   
- static U8 trigger = FALSE; 
-   
- static S8 offsx; 
- static U8 ylow; 
- static S16 offsy; 
-   
- static U8 seq; 
-   
- static U8 save_crawl; 
- static U16 save_x, save_y; 
-   
-   
- /* 
-  * Box test 
-  * 
-  * ASM 113E (based on) 
-  * 
-  * e: entity to test against (corresponds to SI in asm code -- here DI 
-  *      is assumed to point to rick). 
-  * ret: TRUE/intersect, FALSE/not. 
-  */ 
- U8 e_rick_boxtest (U8 e) 
- { 
-    /* 
-     * rick: x+0x05 to x+0x11, y+[0x08 if rick's crawling] to y+0x14 
-     * entity: x to x+w, y to y+h 
-     */ 
-   
-    if (E_RICK_ENT.x + 0x11 < ent_ents[e].x 
-        || E_RICK_ENT.x + 0x05 > ent_ents[e].x + ent_ents[e].w 
-        || E_RICK_ENT.y + 0x14 < ent_ents[e].y 
-        || E_RICK_ENT.y + (E_RICK_STTST (E_RICK_STCRAWL) ? 0x08 : 0x00) > ent_ents[e].y + ent_ents[e].h - 1) 
-       return FALSE; 
-    else 
-       return TRUE; 
- } 
-   
-   
- /* 
-  * Go zombie 
-  * 
-  * ASM 1851 
-  */ 
- void e_rick_gozombie (void) 
- { 
-    //return; // cheat 
-   
-    /* already zombie? */ 
-    if (E_RICK_STTST (E_RICK_STZOMBIE)) 
-       return; 
-   
-    syssnd_play (WAV_DIE, 1); 
-   
-    E_RICK_STSET (E_RICK_STZOMBIE); 
-    offsy = -0x0400; 
-    offsx = (E_RICK_ENT.x > 0x80 ? -3 : +3); 
-    ylow = 0; 
-    E_RICK_ENT.front = TRUE; 
- } 
-   
-   
- /* 
-  * Action sub-function for e_rick when zombie 
-  * 
-  * ASM 17DC 
-  */ 
- static void e_rick_z_action (void) 
- { 
-    U32 i; 
-   
-    /* sprite */ 
-    E_RICK_ENT.sprite = (E_RICK_ENT.x & 0x04) ? 0x1A : 0x19; 
-   
-    /* x */ 
-    E_RICK_ENT.x += offsx; 
-   
-    /* y */ 
-    i = (E_RICK_ENT.y << 8) + offsy + ylow; 
-    E_RICK_ENT.y = (S16) (i >> 8); 
-    offsy += 0x80; 
-    ylow = (U8) i; 
-   
-    /* dead when out of screen */ 
-    if (E_RICK_ENT.y < 0 || E_RICK_ENT.y > 0x0140) 
-       E_RICK_STSET (E_RICK_STDEAD); 
- } 
-   
-   
- /* 
-  * Action sub-function for e_rick. 
-  * 
-  * ASM 13BE 
-  */ 
- void e_rick_action2 (void) 
- { 
-    U8 env0, env1; 
-    S16 x, y; 
-    U32 i; 
-   
-    E_RICK_STRST (E_RICK_STSTOP | E_RICK_STSHOOT); 
-   
-    /* if zombie, run dedicated function and return */ 
-    if E_RICK_STTST(E_RICK_STZOMBIE) 
-    { 
-       e_rick_z_action (); 
-       return; 
-    } 
-   
-    /* climbing? */ 
-    if (E_RICK_STTST (E_RICK_STCLIMB)) 
-       goto climbing; 
-   
-    /* 
-     * NOT CLIMBING 
-     */ 
-    E_RICK_STRST (E_RICK_STJUMP); 
-   
-    /* calc y */ 
-    i = (E_RICK_ENT.y << 8) + offsy + ylow; 
-    y = (S16) (i >> 8); 
-   
-    /* test environment */ 
-    u_envtest (E_RICK_ENT.x, y, (U8) E_RICK_STTST (E_RICK_STCRAWL), &env0, &env1); 
-   
-    /* stand up, if possible */ 
-    if (E_RICK_STTST (E_RICK_STCRAWL) && !env0) 
-       E_RICK_STRST (E_RICK_STCRAWL); 
-   
-    /* can move vertically? */ 
-    if (env1 & (offsy < 0 ? 
-                MAP_EFLG_VERT | MAP_EFLG_SOLID | MAP_EFLG_SPAD 
-                : MAP_EFLG_VERT | MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP)) 
-       goto vert_not; 
-   
-    /* 
-     * VERTICAL MOVE 
-     */ 
-    E_RICK_STSET (E_RICK_STJUMP); 
-   
-    /* killed? */ 
-    if (env1 & MAP_EFLG_LETHAL) 
-    { 
-       e_rick_gozombie (); 
-       return; 
-    } 
-   
-    /* save */ 
-    E_RICK_ENT.y = y; 
-    ylow = (U8) i; 
-   
-    /* climb? */ 
-    if ((env1 & MAP_EFLG_CLIMB) && (control_status & (CONTROL_UP | CONTROL_DOWN))) 
-    { 
-       offsy = 0x0100; 
-       E_RICK_STSET (E_RICK_STCLIMB); 
-       return; 
-    } 
-   
-    /* fall */ 
-    offsy += 0x0080; 
-   
-    if (offsy > 0x0800) 
-    { 
-       offsy = 0x0800; 
-       ylow = 0; 
-    } 
-   
-    /* 
-     * HORIZONTAL MOVE 
-     */ 
-    horiz: 
-   
-    /* should move? */ 
-    if (!(control_status & (CONTROL_LEFT|CONTROL_RIGHT))) 
-    { 
-       seq = 2; /* no: reset seq and return */ 
-       return; 
-    } 
-   
-    if (control_status & CONTROL_LEFT) 
-    { 
-       /* move left */ 
-       x = E_RICK_ENT.x - 2; 
-       game_dir = LEFT; 
-   
-       if (x < 0) 
-       { 
-          /* prev submap */ 
-          game_chsm = TRUE; 
-          E_RICK_ENT.x = 0xe2; 
-          return; 
-       } 
-    } 
-    else 
-    { 
-       /* move right */ 
-       x = E_RICK_ENT.x + 2; 
-       game_dir = RIGHT; 
-   
-       if (x >= 0xe8) 
-       { 
-          /* next submap */ 
-          game_chsm = TRUE; 
-          E_RICK_ENT.x = 0x04; 
-          return; 
-       } 
-    } 
-   
-    /* still within this map: test environment */ 
-    u_envtest (x, E_RICK_ENT.y, (U8) E_RICK_STTST (E_RICK_STCRAWL), &env0, &env1); 
-   
-    /* save x-position if it is possible to move */ 
-    if (!(env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP))) 
-    { 
-       E_RICK_ENT.x = x; 
-   
-       if (env1 & MAP_EFLG_LETHAL) 
-          e_rick_gozombie (); 
-    } 
-   
-    /* end */ 
-    return; 
-   
-    /* 
-     * NO VERTICAL MOVE 
-     */ 
- vert_not: 
-    if (offsy < 0) 
-    { 
-       /* not climbing + trying to go _up_ not possible -> hit the roof */ 
-       E_RICK_STSET (E_RICK_STJUMP);   /* fall back to the ground */ 
-       E_RICK_ENT.y &= 0xF8; 
-       offsy = 0; 
-       ylow = 0; 
-       goto horiz; 
-    } 
-   
-    /* else: not climbing + trying to go _down_ not possible -> standing */ 
-    /* align to ground */ 
-    E_RICK_ENT.y &= 0xF8; 
-    E_RICK_ENT.y |= 0x03; 
-    ylow = 0; 
-   
-    /* standing on a super pad? */ 
-    if ((env1 & MAP_EFLG_SPAD) && offsy >= 0X0200) 
-    { 
-       offsy = (control_status & CONTROL_UP) ? 0xf800 : 0x00fe - offsy; 
-       syssnd_play (WAV_PAD, 1); 
-       goto horiz; 
-    } 
-   
-    offsy = 0x0100;   /* reset*/ 
-   
-    /* standing. firing ? */ 
-    if (scrawl || !(control_status & CONTROL_FIRE)) 
-       goto firing_not; 
-   
-    /* 
-     * FIRING 
-     */ 
-    if (control_status & (CONTROL_LEFT | CONTROL_RIGHT)) 
-    { 
-       /* stop */ 
-       if (control_status & CONTROL_RIGHT) 
-       { 
-          game_dir = RIGHT; 
-          e_rick_stop_x = E_RICK_ENT.x + 0x17; 
-       } 
-       else 
-       { 
-          game_dir = LEFT; 
-          e_rick_stop_x = E_RICK_ENT.x; 
-       } 
-   
-       e_rick_stop_y = E_RICK_ENT.y + 0x000E; 
-       E_RICK_STSET (E_RICK_STSTOP); 
-       return; 
-    } 
-   
-    if (control_status == (CONTROL_FIRE | CONTROL_UP)) 
-    { 
-       /* bullet */ 
-       E_RICK_STSET (E_RICK_STSHOOT); 
-   
-       /* not an automatic gun: shoot once only */ 
-       if (trigger) 
-          return; 
-       else 
-          trigger = TRUE; 
-   
-       /* already a bullet in the air ... that's enough */ 
-       if (E_BULLET_ENT.n) 
-          return; 
-   
-       /* else use a bullet, if any available */ 
-       if (!game_bullets) 
-          return; 
-   
-       /* initialize bullet */ 
-       e_bullet_init (E_RICK_ENT.x, E_RICK_ENT.y); 
-       game_bullets--; 
-       return; 
-    } 
-   
-    trigger = FALSE; /* not shooting means trigger is released */ 
-    seq = 0; /* reset */ 
-   
-    if (control_status == (CONTROL_FIRE | CONTROL_DOWN)) 
-    { 
-       /* bomb */ 
-       /* already a bomb ticking ... that's enough */ 
-       if (E_BOMB_ENT.n) 
-          return; 
-   
-       /* else use a bomb, if any available */ 
-       if (!game_bombs) 
-          return; 
-   
-       /* initialize bomb */ 
-       e_bomb_init (E_RICK_ENT.x, E_RICK_ENT.y); 
-       game_bombs--; 
-       return; 
-    } 
-   
-    return; 
-   
-    /* 
-     * NOT FIRING 
-     */ 
- firing_not: 
-    if (control_status & CONTROL_UP) 
-    { 
-       /* jump or climb */ 
-       if (env1 & MAP_EFLG_CLIMB) 
-       { 
-          /* climb */ 
-          E_RICK_STSET (E_RICK_STCLIMB); 
-          return; 
-       } 
-   
-       offsy = -0x0580;   /* jump */ 
-       ylow = 0; 
-       syssnd_play (WAV_JUMP, 1); 
-       goto horiz; 
-    } 
-   
-    if (control_status & CONTROL_DOWN) 
-    { 
-       /* crawl or climb */ 
-       if ((env1 & MAP_EFLG_VERT)   /* can go down */ 
-           && !(control_status & (CONTROL_LEFT | CONTROL_RIGHT))   /* + not moving horizontaly */ 
-           && (E_RICK_ENT.x & 0x1f) < 0x0a) 
-       { 
-          /* + aligned -> climb */ 
-          E_RICK_ENT.x &= 0xf0; 
-          E_RICK_ENT.x |= 0x04; 
-          E_RICK_STSET (E_RICK_STCLIMB); 
-       } 
-       else 
-       { 
-          /* crawl */ 
-          E_RICK_STSET (E_RICK_STCRAWL); 
-          goto horiz; 
-       } 
-   
-    } 
-    goto horiz; 
-   
-    /* 
-     * CLIMBING 
-     */ 
- climbing: 
-    /* should move? */ 
-    if (!(control_status & (CONTROL_UP | CONTROL_DOWN | CONTROL_LEFT | CONTROL_RIGHT))) 
-    { 
-       seq = 0; /* no: reset seq and return */ 
-       return; 
-    } 
-   
-    if (control_status & (CONTROL_UP | CONTROL_DOWN)) 
-    { 
-       /* up-down: calc new y and test environment */ 
-       y = E_RICK_ENT.y + ((control_status & CONTROL_UP) ? -0x02 : 0x02); 
-       u_envtest (E_RICK_ENT.x, y, (U8) E_RICK_STTST (E_RICK_STCRAWL), &env0, &env1); 
-   
-       if (env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP) 
-           && !(control_status & CONTROL_UP)) 
-       { 
-          /* FIXME what? */ 
-          E_RICK_STRST (E_RICK_STCLIMB); 
-          return; 
-       } 
-   
-       if (!(env1 & (MAP_EFLG_SOLID | MAP_EFLG_SPAD | MAP_EFLG_WAYUP)) 
-           || (env1 & MAP_EFLG_WAYUP)) 
-       { 
-          /* ok to move, save */ 
-          E_RICK_ENT.y = y; 
-   
-          if (env1 & MAP_EFLG_LETHAL) 
-          { 
-             e_rick_gozombie (); 
-             return; 
-          } 
-   
-          if (!(env1 & (MAP_EFLG_VERT | MAP_EFLG_CLIMB))) 
-          { 
-             /* reached end of climb zone */ 
-             offsy = (control_status & CONTROL_UP) ? -0x0300 : 0x0100; 
-   
-             if (control_status & CONTROL_UP) 
-                syssnd_play (WAV_JUMP, 1); 
-   
-             E_RICK_STRST (E_RICK_STCLIMB); 
-             return; 
-          } 
-       } 
-    } 
-   
-    if (control_status & (CONTROL_LEFT | CONTROL_RIGHT)) 
-    { 
-       /* left-right: calc new x and test environment */ 
-       if (control_status & CONTROL_LEFT) 
-       { 
-          x = E_RICK_ENT.x - 0x02; 
-   
-          if (x < 0) 
-          { 
-             /* (i.e. negative) prev submap */ 
-             game_chsm = TRUE; 
-   
-             /*6dbd = 0x00;*/ 
-             E_RICK_ENT.x = 0xe2; 
-             return; 
-          } 
-       } 
-       else 
-       { 
-          x = E_RICK_ENT.x + 0x02; 
-   
-          if (x >= 0xe8) 
-          { 
-             /* next submap */ 
-             game_chsm = TRUE; 
-   
-             /*6dbd = 0x01;*/ 
-             E_RICK_ENT.x = 0x04; 
-             return; 
-          } 
-       } 
-   
-       u_envtest (x, E_RICK_ENT.y, (U8) E_RICK_STTST (E_RICK_STCRAWL), &env0, &env1); 
-   
-       if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD)) 
-          return; 
-   
-       E_RICK_ENT.x = x; 
-   
-       if (env1 & MAP_EFLG_LETHAL) 
-       { 
-          e_rick_gozombie (); 
-          return; 
-       } 
-   
-       if (env1 & (MAP_EFLG_VERT | MAP_EFLG_CLIMB)) 
-          return; 
-   
-       E_RICK_STRST (E_RICK_STCLIMB); 
-   
-       if (control_status & CONTROL_UP) 
-          offsy = -0x0300; 
-    } 
- } 
-   
-   
- /* 
-  * Action function for e_rick 
-  * 
-  * ASM 12CA 
-  */ 
- void e_rick_action (U8 e) 
- { 
-    static U8 stopped = FALSE; /* is this the most elegant way? */ 
-   
-    e_rick_action2 (); 
-   
-    scrawl = E_RICK_STTST (E_RICK_STCRAWL); 
-   
-    if E_RICK_STTST (E_RICK_STZOMBIE) 
-       return; 
-   
-    /* 
-     * set sprite 
-     */ 
-    if (E_RICK_STTST (E_RICK_STSTOP)) 
-    { 
-       E_RICK_ENT.sprite = (game_dir ? 0x17 : 0x0B); 
-   
-       if (!stopped) 
-       { 
-          syssnd_play (WAV_STICK, 1); 
-          stopped = TRUE; 
-       } 
-       return; 
-    } 
-   
-    stopped = FALSE; 
-   
-    if (E_RICK_STTST (E_RICK_STSHOOT)) 
-    { 
-       E_RICK_ENT.sprite = (game_dir ? 0x16 : 0x0A); 
-       return; 
-    } 
-   
-    if (E_RICK_STTST (E_RICK_STCLIMB)) 
-    { 
-       E_RICK_ENT.sprite = (((E_RICK_ENT.x ^ E_RICK_ENT.y) & 0x04) ? 0x18 : 0x0c); 
-       seq = (seq + 1) & 0x03; 
-   
-       if (seq == 0) 
-          syssnd_play (WAV_WALK, 1); 
-   
-       return; 
-    } 
-   
-    if (E_RICK_STTST(E_RICK_STCRAWL)) 
-    { 
-       E_RICK_ENT.sprite = (game_dir ? 0x13 : 0x07); 
-   
-       if (E_RICK_ENT.x & 0x04) 
-          E_RICK_ENT.sprite++; 
-   
-       seq = (seq + 1) & 0x03; 
-   
-       if (seq == 0) 
-          syssnd_play (WAV_CRAWL, 1); 
-   
-       return; 
-    } 
-   
-    if (E_RICK_STTST (E_RICK_STJUMP)) 
-    { 
-       E_RICK_ENT.sprite = (game_dir ? 0x15 : 0x06); 
-       return; 
-    } 
-   
-    seq++; 
-   
-    if (seq >= 0x14) 
-    { 
-       syssnd_play (WAV_WALK, 1); 
-       seq = 0x04; 
-    } 
-    else if (seq == 0x0C) 
-       syssnd_play (WAV_WALK, 1); 
-   
-    E_RICK_ENT.sprite = (seq >> 2) + 1 + (game_dir ? 0x0c : 0x00); 
- } 
-   
-   
- /* 
-  * Save status 
-  * 
-  * ASM part of 0x0BBB 
-  */ 
- void e_rick_save (void) 
- { 
-    save_x = E_RICK_ENT.x; 
-    save_y = E_RICK_ENT.y; 
-    save_crawl = E_RICK_STTST (E_RICK_STCRAWL); 
-   
-    /* FIXME 
-     * save_C0 = E_RICK_ENT.b0C; 
-     * plus some 6DBC stuff? 
-     */ 
- } 
-   
-   
- /* 
-  * Restore status 
-  * 
-  * ASM part of 0x0BDC 
-  */ 
- void e_rick_restore (void) 
- { 
-    E_RICK_ENT.x = save_x; 
-    E_RICK_ENT.y = save_y; 
-    E_RICK_ENT.front = FALSE; 
-   
-    if (save_crawl) 
-       E_RICK_STSET (E_RICK_STCRAWL); 
-    else 
-       E_RICK_STRST (E_RICK_STCRAWL); 
-   
-    /* FIXME 
-     * E_RICK_ENT.b0C = save_C0; 
-     * plus some 6DBC stuff? 
-     */ 
- } 
-