mirror of
https://github.com/dwsJason/xrick2gs.git
synced 2024-09-12 06:55:40 +00:00
567 lines
11 KiB
C
567 lines
11 KiB
C
/*
|
|
* xrick/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 "config.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)
|
|
{
|
|
#ifdef ENABLE_CHEATS
|
|
if (game_cheat2) return;
|
|
#endif
|
|
|
|
/* already zombie? */
|
|
if E_RICK_STTST(E_RICK_STZOMBIE) return;
|
|
|
|
#ifdef ENABLE_SOUND
|
|
syssnd_play(WAV_DIE, 1);
|
|
#endif
|
|
|
|
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 = i >> 8;
|
|
offsy += 0x80;
|
|
ylow = 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 = i >> 8;
|
|
/* test environment */
|
|
u_envtest(E_RICK_ENT.x, y, 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 = 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, 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;
|
|
#ifdef ENABLE_SOUND
|
|
syssnd_play(WAV_PAD, 1);
|
|
#endif
|
|
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;
|
|
#ifdef ENABLE_CHEATS
|
|
if (!game_cheat1)
|
|
game_bullets--;
|
|
#endif
|
|
/* initialize bullet */
|
|
e_bullet_init(E_RICK_ENT.x, E_RICK_ENT.y);
|
|
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;
|
|
#ifdef ENABLE_CHEATS
|
|
if (!game_cheat1)
|
|
game_bombs--;
|
|
#endif
|
|
/* initialize bomb */
|
|
e_bomb_init(E_RICK_ENT.x, E_RICK_ENT.y);
|
|
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;
|
|
#ifdef ENABLE_SOUND
|
|
syssnd_play(WAV_JUMP, 1);
|
|
#endif
|
|
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, 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;
|
|
#ifdef ENABLE_SOUND
|
|
if (control_status & CONTROL_UP)
|
|
syssnd_play(WAV_JUMP, 1);
|
|
#endif
|
|
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, 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(UNUSED(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);
|
|
#ifdef ENABLE_SOUND
|
|
if (!stopped)
|
|
{
|
|
syssnd_play(WAV_STICK, 1);
|
|
stopped = TRUE;
|
|
}
|
|
#endif
|
|
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);
|
|
#ifdef ENABLE_SOUND
|
|
seq = (seq + 1) & 0x03;
|
|
if (seq == 0) syssnd_play(WAV_WALK, 1);
|
|
#endif
|
|
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++;
|
|
#ifdef ENABLE_SOUND
|
|
seq = (seq + 1) & 0x03;
|
|
if (seq == 0) syssnd_play(WAV_CRAWL, 1);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if E_RICK_STTST(E_RICK_STJUMP)
|
|
{
|
|
E_RICK_ENT.sprite = (game_dir ? 0x15 : 0x06);
|
|
return;
|
|
}
|
|
|
|
seq++;
|
|
|
|
if (seq >= 0x14)
|
|
{
|
|
#ifdef ENABLE_SOUND
|
|
syssnd_play(WAV_WALK, 1);
|
|
#endif
|
|
seq = 0x04;
|
|
}
|
|
#ifdef ENABLE_SOUND
|
|
else
|
|
if (seq == 0x0C)
|
|
syssnd_play(WAV_WALK, 1);
|
|
#endif
|
|
|
|
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?
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
|
|
/* eof */
|