diff --git a/makefile.gaz b/makefile.gaz index 54793ca68..7edf0aace 100644 --- a/makefile.gaz +++ b/makefile.gaz @@ -61,6 +61,7 @@ enemy_src := 2denemy \ nshrkman \ ngeneric \ nanemone \ + neyeball \ enemy projectl_src := projectl diff --git a/source/enemy/neyeball.cpp b/source/enemy/neyeball.cpp new file mode 100644 index 000000000..f7ec4fe87 --- /dev/null +++ b/source/enemy/neyeball.cpp @@ -0,0 +1,47 @@ +/*========================================================================= + + neyeball.cpp + + Author: CRB + Created: + Project: Spongebob + Purpose: + + Copyright (c) 2000 Climax Development Ltd + +===========================================================================*/ + +#ifndef __ENEMY_NPC_H__ +#include "enemy\npc.h" +#endif + +#ifndef __GAME_GAME_H__ +#include "game\game.h" +#endif + +#ifndef __PLAYER_PLAYER_H__ +#include "player\player.h" +#endif + +#ifndef __PROJECTL_PROJECTL_H__ +#include "projectl\projectl.h" +#endif + + +void CNpc::processCloseEyeballAttack( int _frames ) +{ + if ( Next ) + { + // already have child, ignore + } + else + { + // create child projectile which will be deleted when the projectile has returned + + CProjectile *projectile; + projectile = new ( "test projectile" ) CProjectile; + projectile->init( Pos, m_fireHeading, CProjectile::PROJECTILE_USER_SEEK, CProjectile::PROJECTILE_INFINITE_LIFE ); + + addChild( projectile ); + } +} \ No newline at end of file diff --git a/source/enemy/npc.cpp b/source/enemy/npc.cpp index 7f932589f..3828efa16 100644 --- a/source/enemy/npc.cpp +++ b/source/enemy/npc.cpp @@ -3,9 +3,9 @@ npc.cpp Author: CRB - Created: + Created: Project: Spongebob - Purpose: + Purpose: Copyright (c) 2000 Climax Development Ltd @@ -277,10 +277,10 @@ CNpc::NPC_DATA CNpc::m_data[NPC_UNIT_TYPE_MAX] = { // NPC_EYEBALL NPC_INIT_DEFAULT, - NPC_SENSOR_NONE, + NPC_SENSOR_EYEBALL_USER_CLOSE, NPC_MOVEMENT_STATIC, NPC_MOVEMENT_MODIFIER_NONE, - NPC_CLOSE_NONE, + NPC_CLOSE_EYEBALL_ATTACK, NPC_TIMER_NONE, false, 0, @@ -387,7 +387,7 @@ CNpc::NPC_DATA CNpc::m_data[NPC_UNIT_TYPE_MAX] = void CNpc::init() { - m_type = NPC_GHOST_PIRATE; + m_type = NPC_EYEBALL; m_heading = m_fireHeading = 0; m_movementTimer = 0; @@ -718,6 +718,20 @@ bool CNpc::processSensor() } } + case NPC_SENSOR_EYEBALL_USER_CLOSE: + { + if ( xDistSqr + yDistSqr < 40000 ) + { + m_controlFunc = NPC_CONTROL_CLOSE; + + return( true ); + } + else + { + return( false ); + } + } + default: return( false ); } @@ -793,7 +807,7 @@ void CNpc::processMovement(int _frames) m_heading += moveDist; m_heading = m_heading % ONE; - + s32 preShiftX = _frames * m_data[m_type].speed * rcos( m_heading ); s32 preShiftY = _frames * m_data[m_type].speed * rsin( m_heading ); @@ -818,7 +832,7 @@ void CNpc::processMovement(int _frames) case NPC_MOVEMENT_USER_SEEK: { CPlayer *player; - + player = GameScene.getPlayer(); break; @@ -913,6 +927,11 @@ void CNpc::processClose(int _frames) break; + case NPC_CLOSE_EYEBALL_ATTACK: + processCloseEyeballAttack( _frames ); + + break; + default: break; } @@ -959,27 +978,48 @@ void CNpc::render() void CNpc::processEvent( GAME_EVENT evt, CThing *sourceThing ) { - if ( m_data[this->m_type].canTalk ) + switch( evt ) { - DVECTOR sourcePos; - s32 xDiffSqr, yDiffSqr; - - // check talk distance - - sourcePos = sourceThing->getPos(); - - xDiffSqr = this->Pos.vx - sourcePos.vx; - xDiffSqr *= xDiffSqr; - - yDiffSqr = this->Pos.vy - sourcePos.vy; - yDiffSqr *= yDiffSqr; - - if ( xDiffSqr + yDiffSqr < 250 ) + case USER_REQUEST_TALK_EVENT: { - if( !CConversation::isActive() ) + if ( m_data[this->m_type].canTalk ) { - CConversation::trigger( SCRIPTS_SPEECHTEST_DAT ); + DVECTOR sourcePos; + s32 xDiffSqr, yDiffSqr; + + // check talk distance + + sourcePos = sourceThing->getPos(); + + xDiffSqr = this->Pos.vx - sourcePos.vx; + xDiffSqr *= xDiffSqr; + + yDiffSqr = this->Pos.vy - sourcePos.vy; + yDiffSqr *= yDiffSqr; + + if ( xDiffSqr + yDiffSqr < 250 ) + { + if( !CConversation::isActive() ) + { + CConversation::trigger( SCRIPTS_SPEECHTEST_DAT ); + } + } } + + break; + } + + case PROJECTILE_RETURNED_TO_SOURCE_EVENT: + { + m_controlFunc = NPC_CONTROL_MOVEMENT; + m_timerFunc = NPC_TIMER_ATTACK_DONE; + m_timerTimer = GameState::getOneSecondInFrames(); + m_sensorFunc = NPC_SENSOR_NONE; + + removeChild( sourceThing ); + delete sourceThing; + + break; } } -} +} \ No newline at end of file diff --git a/source/enemy/npc.h b/source/enemy/npc.h index cb488e27f..d69017de6 100644 --- a/source/enemy/npc.h +++ b/source/enemy/npc.h @@ -27,16 +27,6 @@ class CNpc : public CThing { public: - void init(); - void shutdown(); - void think(int _frames); - virtual void render(); - void processEvent( GAME_EVENT evt, CThing *sourceThing ); - - -protected: - // NPC data structure definitions // - enum NPC_UNIT_TYPE { NPC_TEST_TYPE = 0, @@ -70,6 +60,16 @@ protected: NPC_UNIT_TYPE_MAX, }; + void init(); + void shutdown(); + void think(int _frames); + virtual void render(); + void processEvent( GAME_EVENT evt, CThing *sourceThing ); + + +protected: + // NPC data structure definitions // + enum NPC_INIT_FUNC { NPC_INIT_DEFAULT = 0, @@ -97,6 +97,7 @@ protected: NPC_SENSOR_SHARK_MAN_USER_VISIBLE, NPC_SENSOR_OIL_BLOB_USER_CLOSE, NPC_SENSOR_ANEMONE_USER_CLOSE, + NPC_SENSOR_EYEBALL_USER_CLOSE, }; enum NPC_CLOSE_FUNC @@ -110,6 +111,7 @@ protected: NPC_CLOSE_GENERIC_USER_SEEK, NPC_CLOSE_ANEMONE_1_ATTACK, NPC_CLOSE_ANEMONE_2_ATTACK, + NPC_CLOSE_EYEBALL_ATTACK, }; enum NPC_MOVEMENT_FUNC @@ -197,6 +199,10 @@ protected: void processCloseAnemone1Attack( int _frames ); void processCloseAnemone2Attack( int _frames ); + // eyeball functions + + void processCloseEyeballAttack( int _frames ); + // data static NPC_DATA m_data[NPC_UNIT_TYPE_MAX]; @@ -210,9 +216,9 @@ protected: CNpcPath m_npcPath; s32 m_heading; s32 m_fireHeading; - s32 m_movementTimer; s32 m_velocity; bool m_evadeClockwise; + s32 m_movementTimer; s32 m_timerTimer; s32 m_extension; bool m_extendDir; diff --git a/source/game/event.h b/source/game/event.h index c2aee3a47..94f4740eb 100644 --- a/source/game/event.h +++ b/source/game/event.h @@ -8,6 +8,7 @@ enum GAME_EVENT { USER_REQUEST_TALK_EVENT, + PROJECTILE_RETURNED_TO_SOURCE_EVENT, }; #endif \ No newline at end of file diff --git a/source/game/game.cpp b/source/game/game.cpp index c0ebae000..3c5892f7d 100644 --- a/source/game/game.cpp +++ b/source/game/game.cpp @@ -75,10 +75,6 @@ void CGameScene::init() enemy=new ("test enemy") C2dEnemy; enemy->init(); - CProjectile *testProjectile; - testProjectile = new( "test projectile" ) CProjectile; - testProjectile->init(); - m_player=new ("player") CPlayer(); m_player->init(); diff --git a/source/projectl/projectl.cpp b/source/projectl/projectl.cpp index e742686c4..a518507a4 100644 --- a/source/projectl/projectl.cpp +++ b/source/projectl/projectl.cpp @@ -39,6 +39,10 @@ #include "game\game.h" #endif +#ifndef __PLAYER_PLAYER_H__ +#include "player\player.h" +#endif + /*****************************************************************************/ @@ -49,6 +53,10 @@ void CProjectile::init() m_heading = 0; m_lifetime = GameState::getOneSecondInFrames() * 2; + m_movementType = PROJECTILE_DUMBFIRE; + m_lifetimeType = PROJECTILE_FINITE_LIFE; + m_state = PROJECTILE_ATTACK; + m_turnSpeed = 256; } void CProjectile::init( DVECTOR initPos, s16 initHeading ) @@ -59,22 +67,172 @@ void CProjectile::init( DVECTOR initPos, s16 initHeading ) Pos = initPos; } +void CProjectile::init( DVECTOR initPos, s16 initHeading, PROJECTILE_MOVEMENT_TYPE initMoveType, PROJECTILE_LIFETIME_TYPE initLifeType ) +{ + init( initPos, initHeading ); + + m_movementType = initMoveType; + m_lifetimeType = initLifeType; +} + void CProjectile::shutdown() { m_spriteBank->dump(); delete m_spriteBank; } +bool CProjectile::processTargetSeek( int _frames, DVECTOR targetPos ) +{ + s32 moveX = 0, moveY = 0; + + s16 moveDist = 0; + + s32 moveVel = 0; + + s32 xDist, yDist; + s32 xDistSqr, yDistSqr; + + xDist = targetPos.vx - this->Pos.vx; + xDistSqr = xDist * xDist; + + yDist = targetPos.vy - this->Pos.vy; + yDistSqr = yDist * yDist; + + //if ( xDistSqr + yDistSqr > 22500 ) + //{ + //this->m_controlFunc = NPC_CONTROL_MOVEMENT; + //} + //else + { + s16 headingToTarget = ratan2( yDist, xDist ); + s16 maxTurnRate = m_turnSpeed; + s16 decDir, incDir; + + decDir = m_heading - headingToTarget; + + if ( decDir < 0 ) + { + decDir += ONE; + } + + incDir = headingToTarget - m_heading; + + if ( incDir < 0 ) + { + incDir += ONE; + } + + if ( decDir < incDir ) + { + moveDist = -decDir; + } + else + { + moveDist = incDir; + } + + if ( moveDist < -maxTurnRate ) + { + moveDist = -maxTurnRate; + } + else if ( moveDist > maxTurnRate ) + { + moveDist = maxTurnRate; + } + + m_heading += moveDist; + + m_heading = m_heading % ONE; + + s32 preShiftX = _frames * 3 * rcos( m_heading ); + s32 preShiftY = _frames * 3 * rsin( m_heading ); + + moveX = preShiftX >> 12; + if ( !moveX && preShiftX ) + { + moveX = preShiftX / abs( preShiftX ); + } + + moveY = preShiftY >> 12; + if ( !moveY && preShiftY ) + { + moveY = preShiftY / abs( preShiftY ); + } + + Pos.vx += moveX; + Pos.vy += moveY; + } + + xDist = targetPos.vx - this->Pos.vx; + xDistSqr = xDist * xDist; + + yDist = targetPos.vy - this->Pos.vy; + yDistSqr = yDist * yDist; + + if ( xDistSqr + yDistSqr < 100 ) + { + return( true ); + } + else + { + return( false ); + } +} + void CProjectile::think(int _frames) { - Pos.vx += ( _frames * 3 * rcos( m_heading ) ) >> 12; - Pos.vy += ( _frames * 3 * rsin( m_heading ) ) >> 12; - - m_lifetime -= _frames; - - if ( m_lifetime <= 0 ) + switch( m_movementType ) { - shutdown(); - delete this; + case PROJECTILE_USER_SEEK: + { + switch( m_state ) + { + case PROJECTILE_RETURN: + { + if ( processTargetSeek( _frames, Parent->getPos() ) ) + { + Parent->processEvent( PROJECTILE_RETURNED_TO_SOURCE_EVENT, this ); + } + + break; + } + + case PROJECTILE_ATTACK: + default: + { + CPlayer *player = GameScene.getPlayer(); + DVECTOR playerPos = player->getPos(); + + if ( processTargetSeek( _frames, playerPos ) ) + { + m_state = PROJECTILE_RETURN; + } + + break; + } + } + + break; + } + + case PROJECTILE_DUMBFIRE: + default: + { + Pos.vx += ( _frames * 3 * rcos( m_heading ) ) >> 12; + Pos.vy += ( _frames * 3 * rsin( m_heading ) ) >> 12; + + break; + } + } + + if ( m_lifetimeType == PROJECTILE_FINITE_LIFE ) + { + m_lifetime -= _frames; + + if ( m_lifetime <= 0 ) + { + shutdown(); + delete this; + } } } diff --git a/source/projectl/projectl.h b/source/projectl/projectl.h index 35b80e5de..a6a64477e 100644 --- a/source/projectl/projectl.h +++ b/source/projectl/projectl.h @@ -22,8 +22,27 @@ class CProjectile : public CThing { public: + enum PROJECTILE_MOVEMENT_TYPE + { + PROJECTILE_DUMBFIRE = 0, + PROJECTILE_USER_SEEK = 1, + }; + + enum PROJECTILE_LIFETIME_TYPE + { + PROJECTILE_FINITE_LIFE = 0, + PROJECTILE_INFINITE_LIFE = 1, + }; + + enum PROJECTILE_STATE + { + PROJECTILE_ATTACK = 0, + PROJECTILE_RETURN = 1, + }; + void init(); void init( DVECTOR initPos, s16 initHeading ); + void init( DVECTOR initPos, s16 initHeading, PROJECTILE_MOVEMENT_TYPE initMoveType, PROJECTILE_LIFETIME_TYPE initLifeType ); void shutdown(); void think(int _frames); virtual void render(); @@ -31,10 +50,15 @@ public: protected: DVECTOR getScreenOffset(); + bool processTargetSeek( int _frames, DVECTOR targetPos ); - class SpriteBank *m_spriteBank; - s16 m_heading; - s32 m_lifetime; + class SpriteBank *m_spriteBank; + s16 m_heading; + s32 m_lifetime; + PROJECTILE_MOVEMENT_TYPE m_movementType; + PROJECTILE_LIFETIME_TYPE m_lifetimeType; + PROJECTILE_STATE m_state; + u16 m_turnSpeed; }; diff --git a/users/paul/spongebob project/spongebob project.dsp b/users/paul/spongebob project/spongebob project.dsp index 84e3b67f1..7e4c339b2 100644 --- a/users/paul/spongebob project/spongebob project.dsp +++ b/users/paul/spongebob project/spongebob project.dsp @@ -133,6 +133,10 @@ SOURCE=..\..\..\source\enemy\nclam.cpp # End Source File # Begin Source File +SOURCE=..\..\..\source\enemy\neyeball.cpp +# End Source File +# Begin Source File + SOURCE=..\..\..\source\enemy\ngeneric.cpp # End Source File # Begin Source File