/*========================================================================= player.cpp Author: PKG Created: Project: Spongebob Purpose: Copyright (c) 2001 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ #include "system\vid.h" #include "player\player.h" #ifndef __PAD_PADS_H__ #include "pad\pads.h" #endif #ifndef __PAD_VIBE_H__ #include "pad\vibe.h" #endif #ifndef __GAME_GAME_H__ #include "game\game.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 __PLAYER_PMCART_H__ #include "player\pmcart.h" #endif #ifndef __PLAYER_PMSWAL_H__ #include "player\pmswal.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 __PICKUPS_PICKUP_H__ #include "pickups\pickup.h" #endif #ifndef __MATHTABLE_HEADER__ #include "utils\mathtab.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_WAND_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_JELLYFISH_HEADER__ #include #endif #ifndef __ANIM_SPONGEBOB_GLOVE_HEADER__ #include #endif #include "fx\fx.h" /*---------------------------------------------------------------------- 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' /*---------------------------------------------------------------------- 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(POWERUPUI_OT); m_scalableFontBank=new ("PlayerFont") ScalableFontBank(); m_scalableFontBank->initialise(&standardFont); m_scalableFontBank->setOt(POWERUPUI_OT); 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_BASICUNARMED; // Player will then respawn into this mode respawn(); m_canExitLevel=false; m_lastPadInput=m_padInput=PI_NONE; s_screenPos=128; resetPlayerCollisionSizeToBase(); m_divingHelmet=false; setIsInWater(true); #ifdef __USER_paul__ registerAddon(PLAYER_ADDON_GLOVE); registerAddon(PLAYER_ADDON_NET); registerAddon(PLAYER_ADDON_CORALBLOWER); registerAddon(PLAYER_ADDON_JELLYLAUNCHER); 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_scalableFontBank; m_fontBank->dump(); delete m_fontBank; CPlayerThing::shutdown(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static int oldmode=-1; int newmode=-1; void CPlayer::think(int _frames) { int i; #ifdef __USER_daveo__ if(PadGetDown(0)&PAD_R1) { TestFX(getPos(),this); } #endif 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) { if ( ( (CNpcPlatform *) platform )->isCart() ) { if ( m_currentMode != PLAYER_MODE_CART && m_currentMode != PLAYER_MODE_DEAD ) { setMode( PLAYER_MODE_CART ); } } else { DVECTOR posDelta; posDelta=platform->getPosDelta(); posDelta.vy = 0; shove(posDelta); int platformOffset = ( ( CNpcPlatform* ) platform )->getHeightFromPlatformAtPosition( Pos.vx, Pos.vy ); int height=CGameScene::getCollision()->getHeightFromGround(Pos.vx,Pos.vy,16); if ( platformOffset < height ) { Pos.vy += platformOffset; } } } m_allowConversation=false; m_tryingToManuallyPickupWeapon=false; m_tryingToAutomaticallyPickupWeapon=false; m_xMove = Pos.vx; /// #ifdef __USER_paul__ if(PadGetDown(0)&PAD_TRIANGLE) { // CSoundMediator::setVolume(CSoundMediator::VOL_SONG,0); // m_currentPlayerModeClass->setState(STATE_CELEBRATE); } #endif /// for(i=0;i<_frames;i++) { updatePadInput(); // Weapon collect/drop/swap stuff.. if(m_currentMode==PLAYER_MODE_BASICUNARMED) { // Always trying to pickup weapon if unarmed... means that when SB walks // over an item whilst unarmed, he automatically picks it up m_tryingToAutomaticallyPickupWeapon=true; } if(getPadInputDown()&PI_WEAPONCHANGE) { // Trying to pick up a weapon m_tryingToManuallyPickupWeapon=true; // If already armed then drop current weapon if(m_currentMode!=PLAYER_MODE_BASICUNARMED&& m_currentMode!=PLAYER_MODE_DEAD) { static const int s_pickupsToDrop[NUM_PLAYERMODES]= { -1, // PLAYER_MODE_BASICUNARMED, -1, // PLAYER_MODE_FULLUNARMED, -1, // PLAYER_MODE_BALLOON, PICKUP__BUBBLE_WAND, // PLAYER_MODE_BUBBLE_MIXTURE, PICKUP__NET, // PLAYER_MODE_NET, PICKUP__CORAL_BLOWER, // PLAYER_MODE_CORALBLOWER, PICKUP__JELLY_LAUNCHER, // PLAYER_MODE_JELLY_LAUNCHER, -1, // PLAYER_MODE_DEAD, -1, // PLAYER_MODE_FLY, -1, // PLAYER_MODE_CART, }; int pickupToDrop; pickupToDrop=s_pickupsToDrop[m_currentMode]; if(pickupToDrop!=-1) { DVECTOR pickupPos; CBasePickup *pickup; pickupPos.vx=Pos.vx; pickupPos.vy=Pos.vy-30; pickup=createPickup((PICKUP_TYPE)pickupToDrop,&pickupPos); pickup->setPos(&pickupPos); } setMode(PLAYER_MODE_BASICUNARMED); } } // Trying to converate? if(m_allowConversation==false&& m_currentPlayerModeClass->canConverse()&& getPadInputDown()&PI_UP) { m_allowConversation=true; } // Think for the current player mode int oldBlock; DVECTOR oldPos; oldBlock=CGameScene::getCollision()->getCollisionBlock(Pos.vx,Pos.vy)&COLLISION_TYPE_MASK; oldPos=Pos; m_currentPlayerModeClass->think(); if(oldBlock==COLLISION_TYPE_FLAG_DESTRUCTABLE_FLOOR&& (Pos.vx>>4!=oldPos.vx>>4||Pos.vy>>4!=oldPos.vy>>4)) { GameScene.GetLevel().destroyMapTile(oldPos); } // Is player stood on any special collision? if(getHeightFromGroundNoPlatform(Pos.vx,Pos.vy,5)==0) { int block; block=CGameScene::getCollision()->getCollisionBlock(Pos.vx,Pos.vy)&COLLISION_TYPE_MASK; // Conveyor belt movement if(block==COLLISION_TYPE_FLAG_MOVE_LEFT) { moveHorizontal(-1); } else if(block==COLLISION_TYPE_FLAG_MOVE_RIGHT) { moveHorizontal(+1); } // Death? /*else if(m_currentMode!=PLAYER_MODE_DEAD&& block==COLLISION_TYPE_FLAG_DEATH_LIQUID) { dieYouPorousFreak(DEATHTYPE__LIQUID); } else if(m_currentMode!=PLAYER_MODE_DEAD&& block==COLLISION_TYPE_FLAG_DEATH_INSTANT) { dieYouPorousFreak(DEATHTYPE__NORMAL); }*/ } // 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; } // Falling camera lag if(m_isFalling) { if(m_fallFrames>CAMERA_FALL_FRAME_THRESHOLD) { if(m_cameraFallYScrollSpeed0) { m_cameraFallYScrollPos=0; } } m_fallFrames=0; m_cameraFallYScrollSpeed=0; } // 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); } m_xMove = Pos.vx - m_xMove; // 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) { // Drain water/health m_healthWaterLevel-=waterDrainSpeed*_frames; if(m_healthWaterLevel<=0) { dieYouPorousFreak(DEATHTYPE__DRYUP); } // Breath sound m_helmetSoundTimer+=_frames; if(m_helmetSoundTimer>150+(m_healthWaterLevel>>WATERLEVELSHIFT)) { CSoundMediator::playSfx(CSoundMediator::SFX_SPONGEBOB_DIVING_HELMET); m_helmetSoundTimer=0; } } // 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; CGameScene::shakeCamera(m_cameraPos); } // 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; m_ignoreNewlyPressedButtonsOnPadThisThink=false; CPlayerThing::think(_frames); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::detectHazardousSurface() { int height; height=CGameScene::getCollision()->getHeightFromGround( Pos.vx, Pos.vy ); if ( height <= 0 ) { CThing *platform; platform=isOnPlatform(); if(platform) { int platformHeight=((CNpcPlatform*)platform)->getHeightFromPlatformAtPosition( Pos.vx, Pos.vy ); if ( platformHeight < height ) { // on platform, which is higher than ground return; } } int block; block=CGameScene::getCollision()->getCollisionBlock(Pos.vx,Pos.vy)&COLLISION_TYPE_MASK; // Death? if(m_currentMode!=PLAYER_MODE_DEAD&& block==COLLISION_TYPE_FLAG_DEATH_LIQUID) { dieYouPorousFreak(DEATHTYPE__LIQUID); } else if(m_currentMode!=PLAYER_MODE_DEAD&& block==COLLISION_TYPE_FLAG_DEATH_INSTANT) { dieYouPorousFreak(DEATHTYPE__NORMAL); } } } /*---------------------------------------------------------------------- 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; int drawlastpos=false; #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); } } if(drawlastpos) { 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 SpriteBank *sb=CGameScene::getSpriteBank(); // Render player if(m_animNo!=ANIM_SPONGEBOB_DONOTDRAW) { DVECTOR sbPos= { Pos.vx-m_cameraPos.vx, Pos.vy-m_cameraPos.vy, }; renderSb(&sbPos,m_animNo,m_animFrame>>sbanimspeed); m_currentPlayerModeClass->render(&sbPos); } // UI int count; sFrameHdr *fh; char countBuf[5]; int x,y; // Spat/token count if(GameScene.getLevelNumber()!=5) { // Spat count count=m_numSpatulasHeld; fh=sb->getFrameHeader(FRM__SPATULA); } else { // Token count count=CGameSlotManager::getSlotData()->getKelpTokenCollectedCount(GameScene.getChapterNumber()-1,GameScene.getLevelNumber()-1); fh=sb->getFrameHeader(FRM__TOKEN); } sprintf(countBuf,"x%d",count); x=SB_UI_XBASE; y=SB_UI_YBASE; sb->printFT4(fh,x,y,0,0,POWERUPUI_OT); x+=fh->W; m_fontBank->print(x,y,countBuf); x+=SB_UI_GAP_FROM_SPAT_COUNT_TO_PICKUPS; if(isWearingDivingHelmet()) { // Helmet POLY_FT4 *ft4; int V,W,H,partH; ft4=sb->printFT4(FRM__WATERHILIGHT,x,y,0,0,POWERUPUI_OT); setSemiTrans(ft4,true); fh=sb->getFrameHeader(FRM__WATER); ft4=sb->printFT4(fh,0,0,0,0,POWERUPUI_OT); 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,x,y+(partH),W,H-partH); ft4->v0=V+(partH); ft4->v1=V+(partH); sb->printFT4(FRM__WATERMETER,x,y,0,0,POWERUPUI_OT); if(m_healthWaterLevel<(WATER_COUNTER_SECONDTIME*6)&&m_currentPlayerModeClass->getState()!=STATE_SOAKUP) { int digit; DVECTOR src={x+(W/2),y+(H/2)}; DVECTOR dst={INGAME_SCREENW/2,(INGAME_SCREENH/3)*1}; int frame; int digitX,digitY,scale; char buf[4]; int r,g,b; digit=m_healthWaterLevel/WATER_COUNTER_SECONDTIME; if(digit<0)digit=0; frame=WATER_COUNTER_SECONDTIME-(m_healthWaterLevel%WATER_COUNTER_SECONDTIME); if(frame>WATER_COUNTER_MOVINGTIME)frame=WATER_COUNTER_MOVINGTIME; digitX=src.vx+(((dst.vx-src.vx)*frame)/WATER_COUNTER_MOVINGTIME); digitY=src.vy+(((dst.vy-src.vy)*frame)/WATER_COUNTER_MOVINGTIME); scale=WATER_COUNTER_STARTSCALE+(((WATER_COUNTER_ENDSCALE-WATER_COUNTER_STARTSCALE)*frame)/WATER_COUNTER_MOVINGTIME); sprintf(buf,"%d",digit); m_scalableFontBank->setJustification(FontBank::JUST_CENTRE); m_scalableFontBank->setScale(scale); r=WATER_COUNTER_R2-(((WATER_COUNTER_R2-WATER_COUNTER_R1)*(m_healthWaterLevel))/(WATER_COUNTER_SECONDTIME*6)); g=WATER_COUNTER_G2-(((WATER_COUNTER_G2-WATER_COUNTER_G1)*(m_healthWaterLevel))/(WATER_COUNTER_SECONDTIME*6)); b=WATER_COUNTER_B2-(((WATER_COUNTER_B2-WATER_COUNTER_B1)*(m_healthWaterLevel))/(WATER_COUNTER_SECONDTIME*6)); m_scalableFontBank->setColour(r,g,b); m_scalableFontBank->print(digitX,digitY,buf); } x+=fh->W+SB_UI_GAP_BETWEEN_ITEMS; } if(isWearingBoots()) { // Boots int pickupX,pickupY; sFrameHdr *fh=sb->getFrameHeader(FRM__SHOE); if(m_squeakyBootsTimer>SQUEAKY_BOOTS_FLASH_TIME||m_squeakyBootsTimer&2) { sb->printFT4(fh,x,y,0,0,POWERUPUI_OT); sb->printFT4(fh,x+4,y+4,0,0,POWERUPUI_OT); } x+=fh->W+SB_UI_GAP_BETWEEN_ITEMS+4; } // Mode specific ui m_currentPlayerModeClass->renderModeUi(); } /*---------------------------------------------------------------------- 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: Like the normal setRespawnPos() but plays the telephone ring sound if this is not the current respawn point. To be used from the respawn triggers so that they make the ring sound Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::setRespawnPosAndRingTelephone(DVECTOR _respawn) { if(m_respawnPos.vx!=_respawn.vx|| m_respawnPos.vy!=_respawn.vy) { CSoundMediator::playSfx(CSoundMediator::SFX_TELEPHONE_BOX); setRespawnPos(_respawn); } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getHeightFromGround(int _x,int _y,int _maxHeight) { int height; height=CGameScene::getCollision()->getHeightFromGround(_x,_y,_maxHeight); if(height>=_maxHeight) { CThing *platform; platform=isOnPlatform(); if(platform) { int platformHeight=((CNpcPlatform*)platform)->getHeightFromPlatformAtPosition(_x,_y); if ( platformHeight < height ) { height = platformHeight; 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( CGameScene::getCollision()->getHeightFromGround(_x,_y,_maxHeight) ); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::addLife() { CGameSlotManager::GameSlot *gameSlot; gameSlot=CGameSlotManager::getSlotData(); if(gameSlot->m_livesm_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]; 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(_springHeight); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::setFloating() { m_currentPlayerModeClass->setFloating(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int haha=25; void CPlayer::floatPlayerUp() { m_moveVelocity.vy-=haha; } /*---------------------------------------------------------------------- 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(isWearingBoots()) { // 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-m_cameraFallYScrollPos; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::respawn() { setMode(m_lastModeBeforeDeath); m_allowConversation=false; m_numSpatulasHeld=0; m_healthWaterLevel=WATERMAXHEALTH; m_invincibleFrameCount=INVINCIBLE_FRAMES__START; m_helmetSoundTimer=0; Pos=m_respawnPos; m_cameraLookOffset=0; m_lockCamera=false; m_cameraXScrollDir=0; m_cameraXScrollPos=0; m_cameraFallYScrollPos=0; m_isFalling=false; m_fallFrames=false; m_cameraFallYScrollSpeed=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_tryingToManuallyPickupWeapon=false; m_tryingToAutomaticallyPickupWeapon=false; m_squeakyBootsTimer=0; m_invincibilityRingTimer=0; m_bubbleAmmo=0; m_jellyAmmo=0; m_jellyfishAmmoCount=0; m_moveVelocity.vx=m_moveVelocity.vy=0; clearPlatform(); updateCollisionArea(); m_ignoreNewlyPressedButtonsOnPadThisThink=true; } /*---------------------------------------------------------------------- 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 { u32 colour; colour=getColourOfNextJellyfishAmmo(); ft4=addonGfx->Render(*_pos,addonAnimNo,_animFrame,m_facing==FACING_RIGHT?0:1); setRGB0(ft4,(colour)&0xff,(colour>>8)&0x0ff,(colour>>16)&0xff); 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); CThing *platform; platform=isOnPlatform(); if(platform) { if ( ( (CNpcPlatform *) platform )->isCart() ) { m_actorGfx->RotateScale( ft4, *_pos, ( (CNpcPlatform *) platform )->getCollisionAngle(), ONE, ONE ); } } 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::ignoreNewlyPressedButtonsOnPadThisThink() { m_ignoreNewlyPressedButtonsOnPadThisThink=true; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::inSoakUpState() { if(isWearingDivingHelmet()&& (CGameScene::getCollision()->getCollisionBlock(Pos.vx,Pos.vy)&COLLISION_TYPE_MASK)==COLLISION_TYPE_FLAG_SOAKUP) { 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__) || defined(__USER_paul__) 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 && m_currentMode!=PLAYER_MODE_SWALLOW) // 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(isWearingBoots()) { 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(ouchThatHurtSoMuchThatImJustGoingToDieNow||getSpatulasHeld()==0/*&&m_currentMode!=PLAYER_MODE_NET)*/) { died=true; } else { // NET REMOVED FROM HIT SYSTEM (PKG) /* if(m_currentMode==PLAYER_MODE_NET) { // Launch net pickup setMode(PLAYER_MODE_BASICUNARMED); DVECTOR pickupPos; CBasePickup *pickup; pickupPos.vx=Pos.vx; pickupPos.vy=Pos.vy-30; pickup=createPickup(PICKUP__NET,&pickupPos); pickup->setPos(&pickupPos); } else */ { // Launch all spatulas! GameScene.dropHealth(Pos,m_numSpatulasHeld,1); m_numSpatulasHeld=0; } } } if(died) { DEATH_TYPE deathType; switch(_damage) { case DAMAGE__SQUASH_ENEMY: deathType=DEATHTYPE__SQUASH; break; default: deathType=DEATHTYPE__NORMAL; break; } dieYouPorousFreak(deathType); CPadVibrationManager::setVibration(0,CPadVibrationManager::VIBE_LONG_STROBEY); } else { CThing *platform; platform=isOnPlatform(); if(platform) { if ( ( (CNpcPlatform *) platform )->isCart() ) { m_invincibleFrameCount=INVINCIBLE_FRAMES__HIT; return; } } 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; CPadVibrationManager::setVibration(0,CPadVibrationManager::VIBE_SHORT); } } } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::collectedQuestItem() { m_currentPlayerModeClass->setState(STATE_CELEBRATE); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int CPlayer::getLivesLeft() { return CGameSlotManager::getSlotData()->m_lives; } /*---------------------------------------------------------------------- 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); // Take a life off.. CGameSlotManager::getSlotData()->m_lives--; PAUL_DBGMSG("lives now %d",CGameSlotManager::getSlotData()->m_lives); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::updatePadInput() { m_lastPadInput=m_padInput; m_padInput=readPadInput(); if(!m_ignoreNewlyPressedButtonsOnPadThisThink) { m_padInputDown=(PLAYERINPUT)(m_padInput&(m_lastPadInput^-1)); } else { m_padInputDown=PI_NONE; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ typedef struct { CPadConfig::PAD_CFG m_input; PLAYERINPUT m_output; } PAD_CONVERSION; static const PAD_CONVERSION s_padConversionTable[]= { { CPadConfig::PAD_CFG_UP, PI_UP }, { CPadConfig::PAD_CFG_DOWN, PI_DOWN }, { CPadConfig::PAD_CFG_LEFT, PI_LEFT }, { CPadConfig::PAD_CFG_RIGHT, PI_RIGHT }, { CPadConfig::PAD_CFG_JUMP, PI_JUMP }, { CPadConfig::PAD_CFG_FIRE, PI_FIRE }, { CPadConfig::PAD_CFG_CATCH, PI_CATCH }, { CPadConfig::PAD_CFG_WEAPONCHANGE, PI_WEAPONCHANGE }, }; static const int s_padConversionTableSize=sizeof(s_padConversionTable)/sizeof(PAD_CONVERSION); PLAYERINPUT CPlayer::readPadInput() { PLAYERINPUT input; int pad; const PAD_CONVERSION *table; int i; input=PI_NONE; pad=PadGetHeld(0); table=s_padConversionTable; for(i=0;im_input)) { input=(PLAYERINPUT)(input|table->m_output); } table++; } #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::giveJellyFishAmmo(u32 _colour) { ASSERT(!isJellyFishAmmoFull()); m_jellyfishAmmoColours[m_jellyfishAmmoCount]=_colour; m_jellyfishAmmoCount++; } void CPlayer::useOneJellyFishAmmo() { ASSERT(m_jellyfishAmmoCount!=0); int i; m_jellyfishAmmoCount--; for(i=0;isetState(STATE_BUTTBOUNCEUP); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void CPlayer::shove( DVECTOR move ) { int colHeight; // X movement colHeight=CGameScene::getCollision()->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=CGameScene::getCollision()->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((CGameScene::getCollision()->getCollisionBlock(pos.vx,pos.vy+_moveDistance)&COLLISION_TYPE_MASK)!=COLLISION_TYPE_FLAG_DEATH_FALL) { // 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) { // Are we jumping into an impassable block? if((CGameScene::getCollision()->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 if((CGameScene::getCollision()->getCollisionBlock(pos.vx,pos.vy+_moveDistance-HEIGHT_FOR_HEAD_COLLISION)&COLLISION_TYPE_MASK)!=COLLISION_TYPE_FLAG_NORMAL&& getHeightFromGround(pos.vx,pos.vy+_moveDistance-HEIGHT_FOR_HEAD_COLLISION)<=0) { switch(CGameScene::getCollision()->getCollisionBlock(pos.vx,pos.vy+_moveDistance-HEIGHT_FOR_HEAD_COLLISION)&COLLISION_TYPE_MASK) { case COLLISION_TYPE_FLAG_DAMAGE: takeDamage(DAMAGE__COLLISION_DAMAGE); break; case COLLISION_TYPE_FLAG_ELECTRIC: if(!isWearingBoots()) { takeDamage(DAMAGE__COLLISION_DAMAGE); } break; default: break; } pos.vy=((pos.vy+_moveDistance)&0xfff0); _moveDistance=0; hitGround=true; } } else { // Stood on any important types of collision? switch(CGameScene::getCollision()->getCollisionBlock(pos.vx,pos.vy+_moveDistance)&COLLISION_TYPE_MASK) { case COLLISION_TYPE_FLAG_DAMAGE: takeDamage(DAMAGE__COLLISION_DAMAGE); break; case COLLISION_TYPE_FLAG_ELECTRIC: if(!isWearingBoots()) { 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=CGameScene::getCollision(); DVECTOR pos; int colHeight; 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((CGameScene::getCollision()->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