/*========================================================================= player.cpp Author: PKG Created: Project: Spongebob Purpose: Copyright (c) 2001 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ #include "player\player.h" #ifndef __PAD_PADS_H__ #include "pad\pads.h" #endif #ifndef __GAME_GAMESLOT_H__ #include "game\gameslot.h" #endif #ifndef __LAYER_COLLISION_H__ #include "level\layercollision.h" #endif #ifndef __PLAYER_PMODES_H__ #include "player\pmodes.h" #endif #ifndef __PLAYER_PMBLOON_H__ #include "player\pmbloon.h" #endif #ifndef __PLAYER_PMBUBBLE_H__ #include "player\pmbubble.h" #endif #ifndef __PLAYER_PMNET_H__ #include "player\pmnet.h" #endif #ifndef __PLAYER_PMCHOP_H__ #include "player\pmchop.h" #endif #ifndef __PLAYER_PMCORAL_H__ #include "player\pmcoral.h" #endif #ifndef __PLAYER_PMDEAD_H__ #include "player\pmdead.h" #endif #ifndef __PLAYER_PMFLY_H__ #include "player\pmfly.h" #endif #ifndef __PLAYER_PMJELLY_H__ #include "player\pmjelly.h" #endif #ifndef __GFX_FONT_H__ #include "gfx\font.h" #endif #ifndef __GFX_SPRBANK_H__ #include "gfx\sprbank.h" #endif #ifndef __PLATFORM_PLATFORM_H__ #include "platform\platform.h" #endif #ifndef __GAME_GAME_H__ #include "game\game.h" #endif /* Std Lib ------- */ /* Data ---- */ #ifndef __SPR_SPRITES_H__ #include #endif #ifndef __ANIM_SPONGEBOB_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_NET_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_CORALBLOWER_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_JELLYLAUNCHER_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_GLASSES_HEADER__ #include #endif //#ifndef __ANIM_SPONGEBOB_WAND_HEADER__ //#include //#endif #ifndef __ANIM_SPONGEBOB_JELLYFISH_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_GLOVE_HEADER__ #include #endif /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ //#define _RECORD_DEMO_MODE_ #define _STATE_DEBUG_ /*---------------------------------------------------------------------- Structure defintions -------------------- */ // Two dice. One says 'Re' on every face, the other says 'boot', // 'install', 'try', 'tire', 'sume' and 'number' /* WEAPON MODES unamred constant karate-chop constant balloon timed ( respawn ) bubble mixture (un)limited supply ( respawn ) helmet constant ( respawn ) coral blower constant ( respawn ) net constant jelly launcher limited supply ( respawn ) POWER-UPS glasses constant squeaky boots timed ( respawn ) mm & bb ring timed */ /*---------------------------------------------------------------------- Function Prototypes ------------------- */ /*---------------------------------------------------------------------- Vars ---- */ #ifdef _RECORD_DEMO_MODE_ #include "player\demoplay.h" #define MAX_DEMO_SIZE 512 // So max size of a demo is 1k #define MAX_DEMO_TIME_IN_FRAMES 30*60 // Recorded demo will last 30 seconds static CDemoPlayer::demoPlayerControl s_demoControls[MAX_DEMO_SIZE]={{PI_NONE,0}}; static int s_demoSize=0; static int s_demoFrameCount=0; static void writeDemoControls() { char filename[32]; int fh; int fc=MAX_DEMO_TIME_IN_FRAMES; sprintf(filename,"demo____.dmo"); fh=PCcreat((char *)filename,0); ASSERT(fh!=-1); PCwrite(fh,(char*)&fc,sizeof(fc)); // frame count PCwrite(fh,(char*)&s_demoSize,sizeof(s_demoSize)); // demo size for(int i=0;iinitialise(&standardFont); m_fontBank->setOt(5); m_spriteBank=new ("PlayerSprites") SpriteBank(); m_spriteBank->load(SPRITES_SPRITES_SPR); m_layerCollision=NULL; m_actorGfx=CActorPool::GetActor(ACTORS_SPONGEBOB_SBK); for(i=0;iinitialise(this); } m_animNo=0; m_animFrame=0; setFacing(FACING_RIGHT); m_currentPlayerModeClass=NULL; m_lastModeBeforeDeath=PLAYER_MODE_FULLUNARMED; // Player will then respawn into this mode m_lives++;respawn(); m_lives=CGameSlotManager::getSlotData()->m_lives; m_lastPadInput=m_padInput=PI_NONE; s_screenPos=128; resetPlayerCollisionSizeToBase(); m_divingHelmet=false; setIsInWater(true); // Always ( cept for one level ) need this registerAddon(PLAYER_ADDON_GLOVE); #ifdef __USER_paul__ registerAddon(PLAYER_ADDON_NET); registerAddon(PLAYER_ADDON_CORALBLOWER); registerAddon(PLAYER_ADDON_JELLYLAUNCHER); registerAddon(PLAYER_ADDON_GLASSES); registerAddon(PLAYER_ADDON_BUBBLEWAND); registerAddon(PLAYER_ADDON_JELLYFISHINNET); #endif } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::shutdown() { int i; for(i=0;ishutdown(); } for(i=0;idump(); delete m_spriteBank; m_fontBank->dump(); delete m_fontBank; CPlayerThing::shutdown(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static int oldmode=-1; int newmode=-1; int scmax=160; int scspeed=5; void CPlayer::think(int _frames) { int i; if(PadGetDown(0)&PAD_L1&&m_currentMode!=PLAYER_MODE_DEAD) { oldmode=m_currentMode; newmode=PLAYER_MODE_FLY; } else if(oldmode!=-1&&!(PadGetHeld(0)&PAD_L1)) { newmode=oldmode; oldmode=-1; } if(newmode!=-1) { setMode((PLAYER_MODE)newmode); newmode=-1; } CThing *platform; platform=isOnPlatform(); if(platform) { int platformOffset = ( ( CNpcPlatform* ) platform )->getHeightFromPlatformAtPosition( Pos.vx, Pos.vy ); Pos.vy += platformOffset; DVECTOR posDelta; posDelta=platform->getPosDelta(); posDelta.vy = 0; shove(posDelta); /*if(((CNpcPlatform*)platform)->getHeightFromPlatformAtPosition(Pos.vx+posDelta.vx,Pos.vy+posDelta.vy)==0) { shove(posDelta); }*/ } m_allowConversation=false; if(m_healthReactFrames) { m_healthReactFrames-=_frames; if(m_healthReactFrames<0) { m_healthReactFrames=0; } } m_tryingToPickupWeapon=false; for(i=0;i<_frames;i++) { // Think updatePadInput(); if(getPadInputDown()) { PAUL_DBGMSG("%02x",getPadInputDown()); } if(getPadInputDown()&PI_WEAPONCHANGE) { if(!m_tryingToPickupWeapon&& m_currentMode!=PLAYER_MODE_BASICUNARMED&& m_currentMode!=PLAYER_MODE_FULLUNARMED&& m_currentMode!=PLAYER_MODE_DEAD) { setMode(PLAYER_MODE_FULLUNARMED); } m_tryingToPickupWeapon=true; } // Trying to converate? if(m_allowConversation==false&& getPadInputDown()&PI_UP) { m_allowConversation=true; } m_currentPlayerModeClass->think(); // Powerups if(m_squeakyBootsTimer) { m_squeakyBootsTimer--; } if(m_invincibilityRingTimer) { m_invincibilityRingTimer--; } // Flashing.. if(m_invincibleFrameCount) { m_invincibleFrameCount--; } // Camera scroll.. if(m_cameraXScrollDir==-1) { if(m_cameraXScrollPos>-(CAMERA_SCROLLLIMIT*CAMERA_TILESIZE)<(CAMERA_SCROLLLIMIT*CAMERA_TILESIZE)<returnsafespace) { if(returntimeoutcount0) { m_cameraXScrollPos=0; } } else if(m_cameraXScrollPos>0) { m_cameraXScrollPos-=returnspeed; if(m_cameraXScrollPos<0) { m_cameraXScrollPos=0; } } } } } #endif // Stop the player vanishing off the edge of the telly.. if(!m_lockCamera) { if(Pos.vxm_playerPosLimitBox.x2) Pos.vx=m_playerPosLimitBox.x2; if(Pos.vym_playerPosLimitBox.y2) Pos.vy=m_playerPosLimitBox.y2; } // Look around int pad=getPadInputHeld(); if(pad&PI_UP&&canDoLookAround()) { if(m_padLookAroundTimer>0) { m_padLookAroundTimer=0; } else if(m_padLookAroundTimer>-looktimeout) { m_padLookAroundTimer--; } else if(m_cameraLookOffset>-lookmaxoffsetup) { m_cameraLookOffset-=lookspeed; if(m_cameraLookOffset<-lookmaxoffsetup) { m_cameraLookOffset=-lookmaxoffsetup; } } } else if(pad&PI_DOWN&&canDoLookAround()) { if(m_padLookAroundTimer<0) { m_padLookAroundTimer=0; } else if(m_padLookAroundTimerlookmaxoffsetdown) { m_cameraLookOffset=lookmaxoffsetdown; } } } else { m_padLookAroundTimer=0; } // Return to centre if(m_padLookAroundTimer==0&&m_cameraLookOffset<0) { m_cameraLookOffset+=lookreturnspeed; if(m_cameraLookOffset>0) { m_cameraLookOffset=0; } } if(m_padLookAroundTimer==0&&m_cameraLookOffset>0) { m_cameraLookOffset-=lookreturnspeed; if(m_cameraLookOffset<0) { m_cameraLookOffset=0; } } // Automatic anim sfx playAnimFrameSfx(m_animNo,m_animFrame); } // Out of water and wearing helmet..? ASSERT(!(getIsInWater()==false&&isWearingDivingHelmet()==false)); if(isWearingDivingHelmet()&&getIsInWater()==false&& m_currentMode!=PLAYER_MODE_DEAD&&m_currentMode!=PLAYER_MODE_FLY) { m_healthWaterLevel-=waterDrainSpeed*_frames; if(m_healthWaterLevel<=0) { dieYouPorousFreak(DEATHTYPE__DRYUP); } } // Ledge look-ahead stuff if(m_ledgeLookAhead&&m_ledgeLookAhead==m_lastLedgeLookAhead) { if(m_ledgeLookTimer0) { if(m_ledgeLookOffsetlimit) { m_ledgeLookOffset=limit; } } else if(m_ledgeLookOffset>limit) { // Look up m_ledgeLookOffset-=ledgeSpeedIn*_frames; if(m_ledgeLookOffset0) { // Relax from look down m_ledgeLookOffset-=ledgeSpeedOut*_frames; if(m_ledgeLookOffset<=0) { m_ledgeLookOffset=0; m_ledgeLookTimer=0; } } else if(m_ledgeLookOffset<0) { // Relax from look up m_ledgeLookOffset+=ledgeSpeedOut*_frames; if(m_ledgeLookOffset>=0) { m_ledgeLookOffset=0; m_ledgeLookTimer=0; } } } m_lastLedgeLookAhead=m_ledgeLookAhead; m_ledgeLookAhead=0; // Camera focus point stuff calcCameraFocusPointTarget(); for(i=0;i<_frames;i++) { m_currentCamFocusPoint.vx+=(m_currentCamFocusPointTarget.vx-m_currentCamFocusPoint.vx)>>cammove; m_currentCamFocusPoint.vy+=(m_currentCamFocusPointTarget.vy-m_currentCamFocusPoint.vy)>>cammove; } // Final camera position int yoff; yoff=m_cameraLookOffset+(m_ledgeLookOffset>>ledgeShift); if(yoff<-lookmaxoffsetup)yoff=-lookmaxoffsetup; else if(yoff>lookmaxoffsetdown)yoff=lookmaxoffsetdown; if(!m_lockCamera) { m_cameraPos.vx=m_currentCamFocusPoint.vx; m_cameraPos.vy=m_currentCamFocusPoint.vy+yoff; } // Limit camera scroll to the edges of the map if(m_cameraPos.vxm_cameraPosLimitBox.x2) m_cameraPos.vx=m_cameraPosLimitBox.x2; if(m_cameraPos.vym_cameraPosLimitBox.y2) m_cameraPos.vy=m_cameraPosLimitBox.y2; CPlayerThing::think(_frames); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int panim=-1; #include "gfx\prim.h" // (pkg) #ifdef _STATE_DEBUG_ int stateDebugX=280; int stateDebugY=60; #endif #ifdef __USER_paul__ #define NUM_LASTPOS 100 typedef struct { int vx,vy; int h; int onp; }POSMEM; static POSMEM lastpos[NUM_LASTPOS]; static int lastposnum=0; #endif #ifdef __USER_paul__ int mouth=-1,eyes=-1; #endif #include "gui\gui.h" void CPlayer::render() { CPlayerThing::render(); #ifdef _STATE_DEBUG_ char buf[100]; #ifdef __USER_paul__ sprintf(buf,"%04d (%02d) ,%04d (%02d)\ndfg:%+02d\nMode:%s",Pos.vx,Pos.vx&0x0f,Pos.vy,Pos.vy&0x0f,getHeightFromGround(Pos.vx,Pos.vy),s_modeText[m_currentMode]); #else sprintf(buf,"Pos: %04d,%04d",Pos.vx,Pos.vy); #endif m_fontBank->print(stateDebugX,stateDebugY,buf); #endif #ifdef __USER_paul__ if(PadGetDown(0)&PAD_R1) { POSMEM clear={0,0,0,false}; for(int i=0;ivx=Pos.vx; p->vy=Pos.vy; p->onp=isOnPlatform()!=NULL; if(p->onp) { p->h=getHeightFromPlatformNoGround(Pos.vx,Pos.vy,150); } else { p->h=getHeightFromGround(Pos.vx,Pos.vy,150); } } POSMEM *p=lastpos; for(int i=0;ivx-m_cameraPos.vx; y=p->vy-m_cameraPos.vy; DrawLine(x-4,y-4,x+4,y+4,0,0,255,0); DrawLine(x-4,y+4,x+4,y-4,0,0,255,0); y=y+p->h; if(p->onp) { DrawLine(x-6,y,x+6,y,255,0,255,0); } else { DrawLine(x-6,y,x+6,y,128,0,255,0); } p++; } #endif // Render DVECTOR sbPos= { Pos.vx-m_cameraPos.vx, Pos.vy-m_cameraPos.vy, }; renderSb(&sbPos,m_animNo,m_animFrame>>sbanimspeed); m_currentPlayerModeClass->render(&sbPos); // Health if(!isWearingDivingHelmet()) { // In water - Use normal SB face for health static int s_fullHealthFrames[]= { FRM__HEALTH_FULL_1, FRM__HEALTH_FULL_2, FRM__HEALTH_FULL_3, FRM__HEALTH_FULL_4, FRM__HEALTH_FULL_5, }; static int s_emptyHealthFrames[]= { FRM__HEALTH_EMPTY_1, FRM__HEALTH_EMPTY_2, FRM__HEALTH_EMPTY_3, FRM__HEALTH_EMPTY_4, FRM__HEALTH_EMPTY_5, }; int i,x,y; POLY_FT4 *ft4; int *frames; x=HEALTH_ICONX; y=HEALTH_ICONY; if(m_health==0||m_healthReactFrames) { frames=s_emptyHealthFrames; } else { frames=s_fullHealthFrames; } int ygap; ygap=m_spriteBank->getFrameHeader(*frames)->H; for(i=5;i>0;i--) { ft4=m_spriteBank->printFT4(*frames++,x,y,0,0,0); setSemiTrans(ft4,i>m_health); y+=ygap; } } else { // Out of water - Use bowl of water POLY_FT4 *ft4; sFrameHdr *fh; int V,W,H,partH; ft4=m_spriteBank->printFT4(FRM__WATERHILIGHT,HEALTH_ICONX,HEALTH_ICONY,0,0,0); setSemiTrans(ft4,true); fh=m_spriteBank->getFrameHeader(FRM__WATER); ft4=m_spriteBank->printFT4(fh,0,0,0,0,0); setSemiTrans(ft4,true); V=fh->V; W=fh->W; H=fh->H; partH=(H*(255-(m_healthWaterLevel>>WATERLEVELSHIFT)))>>8; if(partH>H)partH=H; setXYWH(ft4,HEALTH_ICONX,HEALTH_ICONY+(partH),W,H-partH); ft4->v0=V+(partH); ft4->v1=V+(partH); m_spriteBank->printFT4(FRM__WATERMETER,HEALTH_ICONX,HEALTH_ICONY,0,0,0); } // Mode specific ui int itemX=COLLECTEDITEM_BASEX; // Pickups m_currentPlayerModeClass->renderModeUi(); if(isWearingBoots()) { int x,y; sFrameHdr *fh=m_spriteBank->getFrameHeader(FRM__SHOE); x=itemX-(fh->W/2); y=COLLECTEDITEM_BASEY-(fh->H/2); m_spriteBank->printFT4(fh,x+2,y+2,0,0,0); m_spriteBank->printFT4(fh,x-2,y-2,0,0,0); itemX+=COLLECTEDITEM_GAP; } /* if(isWearingDivingHelmet()) { sFrameHdr *fh=m_spriteBank->getFrameHeader(FRM__HELMET); m_spriteBank->printFT4(fh,itemX-(fh->W/2),COLLECTEDITEM_BASEY-(fh->H/2),0,0,0); itemX+=COLLECTEDITEM_GAP; } */ } /*---------------------------------------------------------------------- Function: Purpose: Pre-calcs the visible edges of the map ( ie: the hard limits for the camera pos ) Params: camera box ( in tiles ) Returns: ---------------------------------------------------------------------- */ void CPlayer::setCameraBox(CameraBox _cameraBox) { m_cameraPosLimitBox.x1=_cameraBox.x1; m_cameraPosLimitBox.y1=_cameraBox.y1; m_cameraPosLimitBox.x2=_cameraBox.x2-(32*MAP2D_BLOCKSTEPSIZE); // Made up numbers! :) (pkg); m_cameraPosLimitBox.y2=_cameraBox.y2-(16*MAP2D_BLOCKSTEPSIZE); m_playerPosLimitBox.x1=_cameraBox.x1+64; m_playerPosLimitBox.y1=_cameraBox.y1+64; m_playerPosLimitBox.x2=_cameraBox.x2-64; m_playerPosLimitBox.y2=_cameraBox.y2-64; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getHeightFromGround(int _x,int _y,int _maxHeight) { int height; height=m_layerCollision->getHeightFromGround(_x,_y,_maxHeight); if(height>=_maxHeight) { CThing *platform; platform=isOnPlatform(); if(platform) { height=((CNpcPlatform*)platform)->getHeightFromPlatformAtPosition(_x,_y); if(height>_maxHeight)height=_maxHeight; else if(height<-_maxHeight)height=-_maxHeight; } } return height; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getHeightFromPlatformNoGround(int _x,int _y,int _maxHeight) { CThing *platform; int height; platform=isOnPlatform(); ASSERT(platform); height=((CNpcPlatform*)platform)->getHeightFromPlatformAtPosition(_x,_y); if(height>_maxHeight)height=_maxHeight; else if(height<-_maxHeight)height=-_maxHeight; return height; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getHeightFromGroundNoPlatform(int _x,int _y,int _maxHeight=32) { return( m_layerCollision->getHeightFromGround(_x,_y,_maxHeight) ); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::addHealth(int _health) { if(!isWearingDivingHelmet()) { m_health+=_health; if(m_health>MAX_HEALTH) { m_health=MAX_HEALTH; } } else { m_healthWaterLevel+=WATERHEALTHPART*_health; if(m_healthWaterLevel>WATERMAXHEALTH) { m_healthWaterLevel=WATERMAXHEALTH; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::addLife() { m_lives++; if(m_lives>MAX_LIVES) { m_lives=MAX_LIVES; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ ATTACK_STATE CPlayer::getAttackState() { return m_currentPlayerModeClass->getAttackState(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::registerAddon(PLAYER_ADDONS _addon) { if(!s_addonActorGfx[_addon]) { FileEquate sbk; sbk=s_addonActorPoolNames[_addon]; if(sbk!=-1) { s_addonActorGfx[_addon]=CActorPool::GetActor(sbk); } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::setMode(PLAYER_MODE _mode) { int state; if(_mode==PLAYER_MODE_DEAD) { ASSERT(m_currentMode!=PLAYER_MODE_DEAD); m_lastModeBeforeDeath=m_currentMode; } resetPlayerCollisionSizeToBase(); if(m_currentPlayerModeClass) { state=m_currentPlayerModeClass->getState(); } else { state=STATE_IDLE; } m_currentMode=_mode; m_currentPlayerModeClass=s_playerModes[_mode]; if(!m_currentPlayerModeClass->setState(state)) { m_currentPlayerModeClass->setState(STATE_IDLE); m_moveVelocity.vx=m_moveVelocity.vy=0; } m_currentPlayerModeClass->enter(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getFacing() { return m_facing; } void CPlayer::setFacing(int _facing) { m_facing=_facing; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getAnimFrame() { return m_animFrame; } void CPlayer::setAnimFrame(int _animFrame) { m_animFrame=_animFrame; } int CPlayer::getAnimFrameCount() { return m_actorGfx->getFrameCount(m_animNo)<springPlayerUp(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::teleportTo(int _x,int _y) { DVECTOR pos={_x,_y}; CameraBox releaseCamBox={0,0,29999,29999}; setCameraBox(releaseCamBox); setPos(pos); setRespawnPos(pos); calcCameraFocusPointTarget(); m_currentCamFocusPoint=m_currentCamFocusPointTarget; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::playAnimFrameSfx(int _animNo,int _animFrame) { static int lastAnimNo=-1; static const AnimSfx *sfx; if(_animNo!=lastAnimNo) { // Lookup the new anim number and cache it for next time :) int i; sfx=s_animSfx; for(i=0;im_animNumber==_animNo) { break; } sfx++; } if(i==s_numAnimSfx) { // No sfx for this anim sfx=NULL; } lastAnimNo=_animNo; } // Are there any sounds for this anim at this frame? if(sfx) { const AnimFrameSfx *frameSfx; int i; ASSERT(sfx->m_numAnimFrameSfx); frameSfx=sfx->m_animFrameSfx; for(i=0;im_numAnimFrameSfx;i++) { if(m_animFrame==frameSfx->m_frame) { CSoundMediator::SFXID sfxId=frameSfx->m_sfxId; if(m_squeakyBootsTimer) { // Ugh.. horrible way to change the sfx when wearing squeaky boots (pkg) if(sfxId==CSoundMediator::SFX_SPONGEBOB_WALK_1)sfxId=CSoundMediator::SFX_SPONGEBOB_SQUEAKY_SHOES_1; else if(sfxId==CSoundMediator::SFX_SPONGEBOB_WALK_2)sfxId=CSoundMediator::SFX_SPONGEBOB_SQUEAKY_SHOES_2; } CSoundMediator::playSfx(sfxId); break; } if(m_animFramem_frame) { break; } frameSfx++; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::calcCameraFocusPointTarget() { m_currentCamFocusPointTarget.vx=Pos.vx+MAP2D_CENTRE_X-(m_cameraXScrollPos>>CAMERA_ACCURACYSHIFT); m_currentCamFocusPointTarget.vy=Pos.vy+MAP2D_CENTRE_Y; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::respawn() { setMode(m_lastModeBeforeDeath); m_allowConversation=false; m_health=MAX_HEALTH; m_healthWaterLevel=WATERMAXHEALTH; m_healthReactFrames=0; m_invincibleFrameCount=INVINCIBLE_FRAMES__START; Pos=m_respawnPos; m_cameraLookOffset=0; m_lockCamera=false; m_cameraXScrollDir=0; m_cameraXScrollPos=0; calcCameraFocusPointTarget(); m_currentCamFocusPoint=m_currentCamFocusPointTarget; m_cameraPos.vx=m_currentCamFocusPoint.vx; m_cameraPos.vy=m_currentCamFocusPoint.vy; m_padLookAroundTimer=0; m_ledgeLookAhead=m_lastLedgeLookAhead=0; m_ledgeLookOffset=0; m_ledgeLookTimer=0; m_glassesFlag=0; m_squeakyBootsTimer=0; m_invincibilityRingTimer=0; m_bubbleAmmo=0; m_jellyAmmo=0; m_jellyfishAmmo=0; m_moveVelocity.vx=m_moveVelocity.vy=0; clearPlatform(); updateCollisionArea(); m_lives--; } /*---------------------------------------------------------------------- Function: Purpose: Yes - This function is fat! It can be tidied up when all of the anims are finalised. Etracting the repeated code to a function will probly not improve things cos of the amount of data that would need to be passed about. Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::renderSb(DVECTOR *_pos,int _animNo,int _animFrame) { int playerMode; int trans; int addon; POLY_FT4 *ft4; if(m_currentMode==PLAYER_MODE_DEAD) { playerMode=m_lastModeBeforeDeath; } else { playerMode=m_currentMode; } trans=m_invincibleFrameCount||m_invincibilityRingTimer; // Render an addon? addon=s_addonNumbers[playerMode]; if(addon!=NO_ADDON) { s8 addonAnimNo=s_animMapNet[addon][_animNo]; if(addonAnimNo!=-1) { CActorGfx *addonGfx=s_addonActorGfx[addon]; if(addonGfx) { if(_animFrame>=addonGfx->getFrameCount(addonAnimNo)) { PAUL_DBGMSG("FRAME OVERRUN ON SPONGEBOB ADDON! ( %d vs %d )",m_actorGfx->getFrameCount(_animNo),addonGfx->getFrameCount(addonAnimNo)); } else { ft4=addonGfx->Render(*_pos,addonAnimNo,_animFrame,m_facing==FACING_RIGHT?0:1); setSemiTrans(ft4,trans); } } } } // Render JFish in a net? if(playerMode==PLAYER_MODE_NET&&getJellyFishAmmo()) { s8 addonAnimNo=s_animMapNet[PLAYER_ADDON_JELLYFISHINNET][_animNo]; if(addonAnimNo!=-1) { CActorGfx *addonGfx=s_addonActorGfx[PLAYER_ADDON_JELLYFISHINNET]; if(addonGfx) { if(_animFrame>=addonGfx->getFrameCount(addonAnimNo)) { PAUL_DBGMSG("FRAME OVERRUN ON SPONGEBOB JELLYFISH ADDON! ( %d vs %d )",m_actorGfx->getFrameCount(_animNo),addonGfx->getFrameCount(addonAnimNo)); } else { ft4=addonGfx->Render(*_pos,addonAnimNo,_animFrame,m_facing==FACING_RIGHT?0:1); setRGB0(ft4,255,128,255); setSemiTrans(ft4,trans); } } } } // Render glasses addon? if(isWearingGlasses()) { s8 addonAnimNo=s_animMapNet[PLAYER_ADDON_GLASSES][_animNo]; if(addonAnimNo!=-1) { CActorGfx *addonGfx=s_addonActorGfx[PLAYER_ADDON_GLASSES]; if(addonGfx) { if(_animFrame>=addonGfx->getFrameCount(addonAnimNo)) { PAUL_DBGMSG("FRAME OVERRUN ON SPONGEBOB GLASSES ADDON! ( %d vs %d )",m_actorGfx->getFrameCount(_animNo),addonGfx->getFrameCount(addonAnimNo)); } else { ft4=addonGfx->Render(*_pos,addonAnimNo,_animFrame,m_facing==FACING_RIGHT?0:1); setSemiTrans(ft4,trans); } } } } // Render glove addon? if(m_currentMode==PLAYER_MODE_FULLUNARMED) { s8 addonAnimNo=s_animMapNet[PLAYER_ADDON_GLOVE][_animNo]; if(addonAnimNo!=-1) { CActorGfx *addonGfx=s_addonActorGfx[PLAYER_ADDON_GLOVE]; if(addonGfx) { if(_animFrame>=addonGfx->getFrameCount(addonAnimNo)) { PAUL_DBGMSG("FRAME OVERRUN ON SPONGEBOB GLOVE ADDON! ( %d vs %d )",m_actorGfx->getFrameCount(_animNo),addonGfx->getFrameCount(addonAnimNo)); } else { ft4=addonGfx->Render(*_pos,addonAnimNo,_animFrame,m_facing==FACING_RIGHT?0:1); setSemiTrans(ft4,trans); } } } } // Render SB ft4=m_actorGfx->Render(*_pos,_animNo,_animFrame,m_facing==FACING_RIGHT?0:1); setSemiTrans(ft4,trans); } /*---------------------------------------------------------------------- Function: Purpose: Says whether SB can do the look up/down thing Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::canDoLookAround() { return m_currentPlayerModeClass->canDoLookAround(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::inSoakUpState() { if(isWearingDivingHelmet()&& (m_layerCollision->getCollisionBlock(Pos.vx,Pos.vy)&COLLISION_TYPE_MASK)==COLLISION_TYPE_FLAG_WATER) { m_healthWaterLevel+=waterSoakUpSpeed; if(m_healthWaterLevel>WATERMAXHEALTH) { m_healthWaterLevel=WATERMAXHEALTH; } } } /*---------------------------------------------------------------------- Function: Purpose: Params: When _reactDirection is REACT__GET_DIRECTION_FROM_THING then _thing must point to the thing that caused the damage Returns: ---------------------------------------------------------------------- */ #if defined(__USER_daveo__) int invincibleSponge=true; // NB: This is for debugging purposes only so don't try and use it for a permenant cheat mode.. #else int invincibleSponge=false; // NB: This is for debugging purposes only so don't try and use it for a permenant cheat mode.. #endif void CPlayer::takeDamage(DAMAGE_TYPE _damage,REACT_DIRECTION _reactDirection,CThing *_thing) { if(m_invincibleFrameCount==0&& // Don't take damage if still recovering from the last hit m_invincibilityRingTimer==0&& // Or if we have the invincibility ring on m_currentPlayerModeClass->getState()!=STATE_SOAKUP&& // Or soaking up m_currentMode!=PLAYER_MODE_DEAD) // Or already dead! :) { int ouchThatHurt=true; int ouchThatHurtSoMuchThatImJustGoingToDieNow=false; // Check if we are currently immune to this damage type switch(_damage) { case DAMAGE__NONE: ouchThatHurt=false; break; case DAMAGE__ELECTROCUTION: case DAMAGE__SHOCK_ENEMY: if(m_squeakyBootsTimer) { ouchThatHurt=false; } break; case DAMAGE__FALL: case DAMAGE__LAVA: case DAMAGE__HIT_ENEMY: case DAMAGE__GAS_ENEMY: case DAMAGE__POISON_ENEMY: case DAMAGE__SWALLOW_ENEMY: case DAMAGE__PINCH_ENEMY: case DAMAGE__SQUASH_ENEMY: case DAMAGE__BURN_ENEMY: case DAMAGE__BITE_ENEMY: case DAMAGE__COLLISION_DAMAGE: break; case DAMAGE__KILL_OUTRIGHT: ouchThatHurt=ouchThatHurtSoMuchThatImJustGoingToDieNow=true; break; } if(ouchThatHurt) { int died=false; if(invincibleSponge) { m_invincibleFrameCount=INVINCIBLE_FRAMES__HIT; } else { if(!isWearingDivingHelmet()) { if(!ouchThatHurtSoMuchThatImJustGoingToDieNow) { m_health--; } else { m_health=-1; } if(m_health<0) { died=true; } } else { if(!ouchThatHurtSoMuchThatImJustGoingToDieNow) { m_healthWaterLevel-=WATERHEALTHPART; } else { m_health=-1; } if(m_healthWaterLevel<0) { died=true; } } } if(died) { DEATH_TYPE deathType; switch(_damage) { case DAMAGE__SQUASH_ENEMY: deathType=DEATHTYPE__SQUASH; break; default: deathType=DEATHTYPE__NORMAL; break; } dieYouPorousFreak(deathType); } else { if(_reactDirection!=REACT__NO_REACTION) { if(_reactDirection==REACT__GET_DIRECTION_FROM_THING) { ASSERT(_thing); if(Pos.vx<_thing->getPos().vx) { _reactDirection=REACT__LEFT; } else { _reactDirection=REACT__RIGHT; } } m_moveVelocity.vx=((int)_reactDirection); switch(_reactDirection) { case REACT__LEFT: setFacing(FACING_RIGHT); break; case REACT__RIGHT: setFacing(FACING_LEFT); break; case REACT__UP: case REACT__GET_DIRECTION_FROM_THING: case REACT__NO_REACTION: break; } m_currentPlayerModeClass->setState(STATE_JUMPBACK); } m_invincibleFrameCount=INVINCIBLE_FRAMES__HIT; m_healthReactFrames=25; } } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::dieYouPorousFreak(DEATH_TYPE _deathType) { ASSERT(m_currentMode!=PLAYER_MODE_DEAD); m_deathType=_deathType; CSoundMediator::playSfx(CSoundMediator::SFX_SPONGEBOB_DEFEATED_JINGLE); setMode(PLAYER_MODE_DEAD); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::updatePadInput() { m_lastPadInput=m_padInput; m_padInput=readPadInput(); m_padInputDown=(PLAYERINPUT)(m_padInput&(m_lastPadInput^-1)); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ PLAYERINPUT CPlayer::readPadInput() { PLAYERINPUT input; int pad; input=PI_NONE; pad=PadGetHeld(0); if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_UP)) { input=(PLAYERINPUT)(input|PI_UP); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_DOWN)) { input=(PLAYERINPUT)(input|PI_DOWN); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_LEFT)) { input=(PLAYERINPUT)(input|PI_LEFT); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_RIGHT)) { input=(PLAYERINPUT)(input|PI_RIGHT); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_JUMP)) { input=(PLAYERINPUT)(input|PI_JUMP); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_FIRE)) { input=(PLAYERINPUT)(input|PI_FIRE); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_CATCH)) { input=(PLAYERINPUT)(input|PI_CATCH); } if(pad&CPadConfig::getButton(CPadConfig::PAD_CFG_WEAPONCHANGE)) { input=(PLAYERINPUT)(input|PI_WEAPONCHANGE); } #ifdef _RECORD_DEMO_MODE_ CDemoPlayer::demoPlayerControl *crnt; PLAYERINPUT lastInput; crnt=&s_demoControls[s_demoSize]; if(s_demoFrameCount==0) { crnt->m_inputValue=input; } lastInput=(PLAYERINPUT)crnt->m_inputValue; if(crnt->m_length==255) { lastInput=(PLAYERINPUT)(input-1); } if(lastInput==input) { crnt->m_length++; } else { s_demoSize++; ASSERT(s_demoSizem_inputValue=input; crnt->m_length=1; } s_demoFrameCount++; if(s_demoFrameCount==MAX_DEMO_TIME_IN_FRAMES) { writeDemoControls(); ASSERT(!"DEMO ENDED"); } #endif return input; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::justButtBouncedABadGuy() { m_currentPlayerModeClass->setState(STATE_BUTTBOUNCEUP); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::shove( DVECTOR move ) { int colHeight; // X movement colHeight=m_layerCollision->getHeightFromGround(Pos.vx+move.vx,Pos.vy,5); if(colHeight<0) { // Stop at the edge of the obstruction int dir,vx,cx,i; if(move.vx<0) { dir=-1; vx=move.vx; } else { dir=+1; vx=move.vx; } cx=Pos.vx; for(i=0;igetHeightFromGround(cx,Pos.vy)<0) { break; } cx+=dir; } if(i) Pos.vx=cx-dir; } else { // No obstruction Pos.vx+=move.vx; } // Y movement colHeight=m_layerCollision->getHeightFromGround(Pos.vx,Pos.vy+move.vy,5); if(colHeight<0) { // Stop at the edge of the obstruction int dir,vy,cy,i; if(move.vy<0) { dir=-1; vy=move.vy; } else { dir=+1; vy=move.vy; } cy=Pos.vy; for(i=0;igetHeightFromGround(Pos.vx,cy)<0) { break; } cy+=dir; } if(i) Pos.vy=cy-dir; } else { // No obstruction Pos.vy+=move.vy; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::moveLeft() { if(m_moveVelocity.vx<-CAMERA_STARTMOVETHRESHOLD||m_cameraXScrollPos<-(CAMERA_SCROLLTHRESHOLD*CAMERA_TILESIZE)<-CAMERA_STOPMOVETHRESHOLD) { m_cameraXScrollDir=0; } } void CPlayer::moveRight() { if(m_moveVelocity.vx>CAMERA_STARTMOVETHRESHOLD||m_cameraXScrollPos>(CAMERA_SCROLLTHRESHOLD*CAMERA_TILESIZE)<0) { int colHeightBefore,colHeightAfter; // Yes.. Check to see if we're about to hit/go through the ground/platform colHeightBefore=getHeightFromGround(pos.vx,pos.vy,16); colHeightAfter=getHeightFromGround(pos.vx,pos.vy+_moveDistance,16); if(isOnPlatform()&& !(colHeightBefore>=0&&colHeightAfter<=0)) { colHeightBefore=getHeightFromPlatformNoGround(pos.vx,pos.vy,16); colHeightAfter=getHeightFromPlatformNoGround(pos.vx,pos.vy+_moveDistance,16); } if(colHeightBefore>=0&&colHeightAfter<=0) { // About to hit a 'fall to death' block? if((m_layerCollision->getCollisionBlock(pos.vx,pos.vy+_moveDistance)&COLLISION_TYPE_MASK)!=COLLISION_TYPE_FLAG_DEATH) { // No // Stick at ground level pos.vy+=colHeightAfter+_moveDistance; _moveDistance=0; hitGround=true; } else { // Yeah! if(m_currentMode!=PLAYER_MODE_DEAD) { // Lock the camera, kill the player and let him fall to his death.. setMode(PLAYER_MODE_DEAD); m_lockCamera=true; } } } } else if(_moveDistance<0) { // Must be below ground // Are we jumping into an impassable block? if((m_layerCollision->getCollisionBlock(pos.vx,pos.vy+_moveDistance)&COLLISION_TYPE_MASK)!=COLLISION_TYPE_FLAG_NORMAL&& getHeightFromGround(pos.vx,pos.vy+_moveDistance)<=0) { pos.vy=(pos.vy&0xfff0); _moveDistance=0; hitGround=true; } } else { // Stood on any important types of collision? switch(m_layerCollision->getCollisionBlock(pos.vx,pos.vy+_moveDistance)&COLLISION_TYPE_MASK) { case COLLISION_TYPE_FLAG_DAMAGE: takeDamage(DAMAGE__COLLISION_DAMAGE); break; default: break; } } pos.vy+=_moveDistance; setPlayerPos(&pos); return hitGround; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::moveHorizontal(int _moveDistance) { int hitWall; hitWall=false; if(_moveDistance) { CLayerCollision *collision; DVECTOR pos; int colHeight; collision=getLayerCollision(); pos=getPlayerPos(); colHeight=getHeightFromGround(pos.vx,pos.vy,5); if(colHeight==0) { // Ok.. we're on the ground. What happens if we move left/right colHeight=getHeightFromGround(pos.vx+_moveDistance,pos.vy); if(colHeight<-8) { // Big step up. Stop at the edge of the obstruction int dir,vx,cx,i; if(_moveDistance<0) { dir=-1; vx=-_moveDistance; } else { dir=+1; vx=_moveDistance; } cx=pos.vx; for(i=0;i=-8&&colHeight<=8) { // Small step up/down. Follow the contour of the level pos.vy+=colHeight; } } else if(colHeight>0) // Lets you jump through platforms from below { if((m_layerCollision->getCollisionBlock(pos.vx+_moveDistance,pos.vy)&COLLISION_TYPE_MASK)!=COLLISION_TYPE_FLAG_NORMAL&& getHeightFromGround(pos.vx+_moveDistance,pos.vy,5)<0) { // Stop at the edge of the obstruction int dir,vx,cx,i; if(_moveDistance<0) { dir=-1; vx=-_moveDistance; } else { dir=+1; vx=_moveDistance; } cx=pos.vx; for(i=0;i