/*========================================================================= pmodes.cpp Author: PKG Created: Project: Spongebob Purpose: Copyright (c) 2001 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ #include "player\pmodes.h" #ifndef __PLAYER_PLAYER_H__ #include "player\player.h" #endif #ifndef __PLAYER_PSTATES_H__ #include "player\pstates.h" #endif #ifndef __LAYER_COLLISION_H__ #include "level\layercollision.h" #endif // States #ifndef __PLAYER__PSJUMP_H__ #include "player\psjump.h" #endif #ifndef __PLAYER__PSRUN_H__ #include "player\psrun.h" #endif #ifndef __PLAYER__PSFALL_H__ #include "player\psfall.h" #endif #ifndef __PLAYER__PSHITGND_H__ #include "player\pshitgnd.h" #endif #ifndef __PLAYER__PSIDLE_H__ #include "player\psidle.h" #endif #ifndef __PLAYER__PSBUTT_H__ #include "player\psbutt.h" #endif #ifndef __PLAYER__PSDUCK_H__ #include "player\psduck.h" #endif /* Std Lib ------- */ /* Data ---- */ #ifndef __ANIM_SPONGEBOB_HEADER__ #include #endif /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ /*---------------------------------------------------------------------- Structure defintions -------------------- */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ static CPlayerState *s_stateTable[]= { &s_stateUnarmedIdle, // STATE_IDLE &s_stateTeeterIdle, // STATE_IDLETEETER &s_stateJump, // STATE_JUMP &s_stateRun, // STATE_RUN &s_stateFall, // STATE_FALL &s_stateFallFar, // STATE_FALLFAR &s_stateHitGround, // STATE_HITGROUND &s_stateButtBounce, // STATE_BUTTBOUNCE &s_stateButtBounceFall, // STATE_BUTTFALL &s_stateButtBounceLand, // STATE_BUTTLAND &s_stateDuck, // STATE_DUCK &s_stateSoakUp, // STATE_SOAKUP &s_stateGetUp, // STATE_GETUP }; static PlayerMetrics s_playerMetrics= { { DEFAULT_PLAYER_JUMP_VELOCITY, // PM__JUMP_VELOCITY DEFAULT_PLAYER_MAX_JUMP_FRAMES, // PM__MAX_JUMP_FRAMES DEFAULT_PLAYER_MAX_SAFE_FALL_FRAMES, // PM__MAX_SAFE_FALL_FRAMES DEFAULT_PLAYER_MAX_RUN_VELOCITY, // PM__MAX_RUN_VELOCITY DEFAULT_PLAYER_RUN_SPEEDUP, // PM__RUN_SPEEDUP DEFAULT_PLAYER_RUN_REVERSESLOWDOWN, // PM__RUN_REVERSESLOWDOWN DEFAULT_PLAYER_RUN_SLOWDOWN, // PM__RUN_SLOWDOWN DEFAULT_PLAYER_PLAYER_GRAVITY, // PM__GRAVITY DEFAULT_PLAYER_TERMINAL_VELOCITY, // PM__TERMINAL_VELOCITY } }; /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerMode::getPadInputHeld() {return m_player->getPadInputHeld();} int CPlayerMode::getPadInputDown() {return m_player->getPadInputDown();} /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ DVECTOR CPlayerMode::getPlayerPos() {return m_player->getPlayerPos();} void CPlayerMode::setPlayerPos(DVECTOR *_pos) {m_player->setPlayerPos(_pos);} /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerMode::respawn() {m_player->respawn();} /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::enter() { m_fallFrames=0; setState(STATE_IDLE); m_moveVelocity.vx=m_moveVelocity.vy=0; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::think() { getStateTable()[m_currentState]->think(this); thinkVerticalMovement(); thinkHorizontalMovement(); // Teeter if on an edge if(canTeeter()&&isOnEdge()) { setState(STATE_IDLETEETER); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::render() { } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerModeBase::isInAttackState() { int ret=false; switch(getState()) { case STATE_BUTTFALL: case STATE_BUTTLAND: ret=true; break; case STATE_IDLE: case STATE_IDLETEETER: case STATE_JUMP: case STATE_RUN: case STATE_FALL: case STATE_FALLFAR: case STATE_BUTTBOUNCE: case STATE_DUCK: case STATE_SOAKUP: case STATE_GETUP: break; } return ret; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::thinkVerticalMovement() { CLayerCollision *collision; DVECTOR pos; int colHeight; collision=m_player->getLayerCollision(); pos=m_player->getPlayerPos(); colHeight=m_player->getHeightFromGround(pos.vx,pos.vy,1); if(colHeight>=0) { // Above or on the ground // Are we falling? if(m_moveVelocity.vy>0) { // Yes.. Check to see if we're about to hit/go through the ground colHeight=m_player->getHeightFromGround(pos.vx,pos.vy+(m_moveVelocity.vy>>VELOCITY_SHIFT),getPlayerMetrics()->m_metric[PM__TERMINAL_VELOCITY]+1); if(colHeight<=0) { // Just hit the ground // Stick at ground level pos.vy+=(m_moveVelocity.vy>>VELOCITY_SHIFT)+colHeight; playerHasHitGround(); } } else if(colHeight) { if(m_currentState!=STATE_FALL&&m_currentState!=STATE_FALLFAR&& m_currentState!=STATE_BUTTFALL&&m_currentState!=STATE_BUTTBOUNCE&& m_currentState!=STATE_JUMP) { // Was floating in the air.. fall! setState(STATE_FALL); } } } else { if((m_player->getLayerCollision()->getCollisionBlock(pos.vx,pos.vy+(m_moveVelocity.vy>>VELOCITY_SHIFT))&COLLISION_TYPE_MASK)==(6<isOnPlatform() && m_moveVelocity.vy >= 0 ) { pos.vy += colHeight; playerHasHitGround(); } } pos.vy+=m_moveVelocity.vy>>VELOCITY_SHIFT; m_player->setPlayerPos(&pos); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::thinkHorizontalMovement() { if(m_moveVelocity.vx) { CLayerCollision *collision; DVECTOR pos; int colHeight; collision=m_player->getLayerCollision(); pos=m_player->getPlayerPos(); colHeight=m_player->getHeightFromGround(pos.vx,pos.vy,5); if(colHeight==0) { // Ok.. we're on the ground. What happens if we move left/right colHeight=m_player->getHeightFromGround(pos.vx+(m_moveVelocity.vx>>VELOCITY_SHIFT),pos.vy); if(colHeight<-8) { // Big step up. Stop at the edge of the obstruction int dir,vx,cx,i; if(m_moveVelocity.vx<0) { dir=-1; vx=-m_moveVelocity.vx>>VELOCITY_SHIFT; } else { dir=+1; vx=m_moveVelocity.vx>>VELOCITY_SHIFT; } cx=pos.vx; for(i=0;igetHeightFromGround(cx,pos.vy)<-8) { break; } cx+=dir; } if(i) pos.vx=cx-dir; // If running then go to idle, otherwise leave in same state if(m_currentState==STATE_RUN) { setState(STATE_IDLE); } m_moveVelocity.vx=0; // Get the height at this new position and then try the step-up code below. // Without this, there are problems when you run up a slope and hit a wall at the same time colHeight=m_player->getHeightFromGround(pos.vx,pos.vy); } if(colHeight&&colHeight>=-8&&colHeight<=8) { // Small step up/down. Follow the contour of the level pos.vy+=colHeight; } } else { // In the air if((m_player->getLayerCollision()->getCollisionBlock(pos.vx+(m_moveVelocity.vx>>VELOCITY_SHIFT),pos.vy)&COLLISION_TYPE_MASK)==(6<0) { pos.vx+=15; } m_moveVelocity.vx=0; } else if(colHeight>=0) // Lets you jump through platforms from below { colHeight=m_player->getHeightFromGround(pos.vx+(m_moveVelocity.vx>>VELOCITY_SHIFT),pos.vy,5); if(colHeight<0) { // Stop at the edge of the obstruction int dir,vx,cx,i; if(m_moveVelocity.vx<0) { dir=-1; vx=m_moveVelocity.vx>>VELOCITY_SHIFT; } else { dir=+1; vx=m_moveVelocity.vx>>VELOCITY_SHIFT; } cx=pos.vx; for(i=0;igetHeightFromGround(cx,pos.vy)<0) { break; } cx+=dir; } if(i) pos.vx=cx-dir; m_moveVelocity.vx=0; } } } pos.vx+=m_moveVelocity.vx>>VELOCITY_SHIFT; m_player->setPlayerPos(&pos); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::playerHasHitGround() { // Grrr! m_moveVelocity.vy=0; m_fallFrames=0; if(m_currentState==STATE_BUTTFALL) { // Landed from a butt bounce setState(STATE_BUTTLAND); } else if(m_currentState==STATE_FALLFAR) { // Landed from a painfully long fall setState(STATE_HITGROUND); m_player->takeDamage(DAMAGE__FALL); m_moveVelocity.vx=0; CSoundMediator::playSfx(CSoundMediator::SFX_SPONGEBOB_LAND_AFTER_FALL); } else if(m_moveVelocity.vx) { // Landed from a jump with x movement setState(STATE_RUN); } else { // Landed from a jump with no x movement setState(STATE_IDLE); setAnimNo(ANIM_SPONGEBOB_JUMPEND); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ const struct PlayerMetrics *CPlayerModeBase::getPlayerMetrics() { return &s_playerMetrics; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerModeBase::setState(int _state) { CPlayerState *nextState; int ret=false; nextState=getStateTable()[_state]; if(nextState) { m_currentStateClass=nextState; m_currentStateClass->enter(this); m_currentState=(PLAYER_STATE)_state; ret=true; } return ret; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerModeBase::getFacing() {return m_player->getFacing();} void CPlayerModeBase::setFacing(int _facing) {m_player->setFacing(_facing);} int CPlayerModeBase::getAnimNo() {return m_player->getAnimNo();} void CPlayerModeBase::setAnimNo(int _animNo) {m_player->setAnimNo(_animNo);setAnimFrame(0);} int CPlayerModeBase::getAnimFrame() {return m_player->getAnimFrame();} int CPlayerModeBase::getAnimFrameCount() {return m_player->getAnimFrameCount();} void CPlayerModeBase::setAnimFrame(int _animFrame) {m_player->setAnimFrame(_animFrame);} /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerModeBase::advanceAnimFrameAndCheckForEndOfAnim() { int animFrame,frameCount; int looped; animFrame=getAnimFrame()+1; frameCount=getAnimFrameCount(); looped=false; if(animFrame>=frameCount) { looped=true; animFrame=0; } setAnimFrame(animFrame); return looped; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ DVECTOR CPlayerModeBase::getMoveVelocity() {return m_moveVelocity;} void CPlayerModeBase::zeroMoveVelocity() {m_moveVelocity.vx=m_moveVelocity.vy=0;} void CPlayerModeBase::setMoveVelocity(DVECTOR *_moveVel) {m_moveVelocity=*_moveVel;} /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: FACING_LEFT if left half of player is hanging, FACING_RIGHT if right half of player is hanging or 0 if no part of the player is hanging ---------------------------------------------------------------------- */ int csize=5; int cheight=15; int CPlayerModeBase::isOnEdge() { CLayerCollision *collision; DVECTOR pos; int ret; collision=m_player->getLayerCollision(); pos=m_player->getPlayerPos(); ret=0; if(m_player->getHeightFromGround(pos.vx-csize,pos.vy,cheight+1)>cheight) { ret=FACING_LEFT; } else if(m_player->getHeightFromGround(pos.vx+csize,pos.vy,cheight+1)>cheight) { ret=FACING_RIGHT; } return ret; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayerModeBase::canMoveLeft() { DVECTOR pos; pos=m_player->getPlayerPos(); return m_player->getHeightFromGround(pos.vx-1,pos.vy,16)>-8?true:false; } int CPlayerModeBase::canMoveRight() { DVECTOR pos; pos=m_player->getPlayerPos(); return m_player->getHeightFromGround(pos.vx+1,pos.vy,16)>-8?true:false; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayerModeBase::moveLeft() { const PlayerMetrics *metrics; metrics=getPlayerMetrics(); setFacing(FACING_LEFT); if(m_moveVelocity.vx<=0) { m_moveVelocity.vx-=metrics->m_metric[PM__RUN_SPEEDUP]; if(m_moveVelocity.vx<-metrics->m_metric[PM__MAX_RUN_VELOCITY]<m_metric[PM__MAX_RUN_VELOCITY]<m_metric[PM__RUN_REVERSESLOWDOWN]; } } void CPlayerModeBase::moveRight() { const PlayerMetrics *metrics; metrics=getPlayerMetrics(); setFacing(FACING_RIGHT); if(m_moveVelocity.vx>=0) { m_moveVelocity.vx+=metrics->m_metric[PM__RUN_SPEEDUP]; if(m_moveVelocity.vx>metrics->m_metric[PM__MAX_RUN_VELOCITY]<m_metric[PM__MAX_RUN_VELOCITY]<m_metric[PM__RUN_REVERSESLOWDOWN]; } } int CPlayerModeBase::slowdown() { const PlayerMetrics *metrics; int ret=false; metrics=getPlayerMetrics(); if(m_moveVelocity.vx<0) { m_moveVelocity.vx+=metrics->m_metric[PM__RUN_SLOWDOWN]; if(m_moveVelocity.vx>=0) { m_moveVelocity.vx=0; ret=true; } } else if(m_moveVelocity.vx>0) { m_moveVelocity.vx-=metrics->m_metric[PM__RUN_SLOWDOWN]; if(m_moveVelocity.vx<=0) { m_moveVelocity.vx=0; ret=true; } } else { // Hmm.. was already stopped(?) // This should probly be considered a bug.. (pkg) ret=true; } return ret; } void CPlayerModeBase::jump() { m_moveVelocity.vy=-getPlayerMetrics()->m_metric[PM__JUMP_VELOCITY]<m_metric[PM__GRAVITY]; if(m_moveVelocity.vy>=metrics->m_metric[PM__TERMINAL_VELOCITY]<m_metric[PM__TERMINAL_VELOCITY]<metrics->m_metric[PM__MAX_SAFE_FALL_FRAMES]) { setState(STATE_FALLFAR); } } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ CPlayerState **CPlayerModeBase::getStateTable() { return s_stateTable; } /*=========================================================================== end */