1384 lines
31 KiB
C++
1384 lines
31 KiB
C++
/*=========================================================================
|
|
|
|
thing.cpp
|
|
|
|
Author: PKG
|
|
Created:
|
|
Project: Spongebob
|
|
Purpose:
|
|
|
|
Copyright (c) 2001 Climax Development Ltd
|
|
|
|
===========================================================================*/
|
|
|
|
#define USE_FREE_LIST
|
|
/*----------------------------------------------------------------------
|
|
Includes
|
|
-------- */
|
|
|
|
#include "thing\thing.h"
|
|
|
|
#ifndef __PLAYER_PLAYER_H__
|
|
#include "player\player.h"
|
|
#endif
|
|
|
|
#ifndef __GAME_GAME_H__
|
|
#include "game\game.h"
|
|
#endif
|
|
|
|
#ifndef __UTILS_HEADER__
|
|
#include "utils\utils.h"
|
|
#endif
|
|
|
|
#include "level\level.h"
|
|
|
|
// Needed for freelist table :o(
|
|
#include "pickups\pickup.h"
|
|
#include "platform\platform.h"
|
|
#include "projectl\projectl.h"
|
|
#include "enemy\npc.h"
|
|
#include "friend\friend.h"
|
|
#include "triggers\trigger.h"
|
|
#include "fx\fx.h"
|
|
|
|
#ifndef __FRIEND_FRIEND_H__
|
|
#include "friend\friend.h"
|
|
#endif
|
|
|
|
#ifndef __FRIEND_FGARY_H__
|
|
#include "friend\fgary.h"
|
|
#endif
|
|
|
|
#ifndef __HAZARD_HRWEIGHT_H__
|
|
#include "hazard\hrweight.h"
|
|
#endif
|
|
|
|
#ifndef __HAZARD_HRWHEEL_H__
|
|
#include "hazard\hrwheel.h"
|
|
#endif
|
|
|
|
#ifndef __HAZARD_HPSWITCH_H__
|
|
#include "hazard\hpswitch.h"
|
|
#endif
|
|
|
|
#ifndef __TRIGGERS_TGARYGO_H__
|
|
#include "triggers\tgarygo.h"
|
|
#endif
|
|
|
|
/* Std Lib
|
|
------- */
|
|
|
|
/* Data
|
|
---- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Tyepdefs && Defines
|
|
------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Structure defintions
|
|
-------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function Prototypes
|
|
------------------- */
|
|
|
|
/*----------------------------------------------------------------------
|
|
Vars
|
|
---- */
|
|
|
|
static const int s_RenderBBoxX0=0;
|
|
static const int s_RenderBBoxX1=512;
|
|
static const int s_RenderBBoxY0=0;
|
|
static const int s_RenderBBoxY1=256;
|
|
static const int s_ThinkBBoxX0=0-256;
|
|
static const int s_ThinkBBoxX1=512+526;
|
|
static const int s_ThinkBBoxY0=0-128;
|
|
static const int s_ThinkBBoxY1=256+128;
|
|
|
|
CThing *CThingManager::s_thingLists[CThing::MAX_TYPE];
|
|
CThing *CThingManager::s_CollisionLists[CThing::MAX_TYPE];
|
|
int CThingManager::s_initialised=false;
|
|
sBBox CThingManager::m_RenderBBox;
|
|
sBBox CThingManager::m_ThinkBBox;
|
|
|
|
#ifdef USE_FREE_LIST
|
|
CThing **CThingManager::s_FreeList[CThing::MAX_TYPE];
|
|
CThing *DuffList;
|
|
int FreeListCount=0;
|
|
int DuffListCount=0;
|
|
|
|
|
|
struct sFreeListTable
|
|
{
|
|
u16 Type;
|
|
u16 Count;
|
|
};
|
|
|
|
static const sFreeListTable FreeListTable[]=
|
|
{
|
|
/* 0*/ {CThing::TYPE_PICKUP ,CBasePickup::MAX_SUBTYPE},
|
|
/* 1*/ {CThing::TYPE_PLATFORM ,CNpcPlatform::MAX_SUBTYPE},
|
|
/* 2*/ {CThing::TYPE_PLAYER ,CPlayerThing::MAX_SUBTYPE},
|
|
/* 3*/ {CThing::TYPE_PLAYERPROJECTILE ,CPlayerProjectile::MAX_SUBTYPE},
|
|
/* 4*/ {CThing::TYPE_NPC ,CNpcFriend::MAX_SUBTYPE},
|
|
/* 5*/ {CThing::TYPE_ENEMY ,CNpcEnemy::MAX_SUBTYPE},
|
|
/* 6*/ {CThing::TYPE_ENEMYPROJECTILE ,CProjectile::MAX_SUBTYPE},
|
|
/* 7*/ {CThing::TYPE_TRIGGER ,CTrigger::MAX_SUBTYPE},
|
|
/* 8*/ {CThing::TYPE_HAZARD ,CNpcHazard::MAX_SUBTYPE},
|
|
/* 9*/ {CThing::TYPE_FX ,CFX::MAX_SUBTYPE},
|
|
};
|
|
static const int FreeListTableSize=sizeof(FreeListTable)/sizeof(sFreeListTable);
|
|
#endif
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::init()
|
|
{
|
|
ASSERT(!s_initialised);
|
|
initList(s_thingLists);
|
|
initList(s_CollisionLists);
|
|
initFreeList();
|
|
s_initialised=true;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::shutdown()
|
|
{
|
|
int i;
|
|
CThing *thing;
|
|
|
|
ASSERT(s_initialised);
|
|
for(i=0;i<CThing::MAX_TYPE;i++)
|
|
{
|
|
while(s_thingLists[i])
|
|
{
|
|
thing=s_thingLists[i];
|
|
thing->shutdown();
|
|
DeleteThing(thing);
|
|
}
|
|
}
|
|
s_initialised=false;
|
|
shutdownFreeList();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::initList(CThing **List)
|
|
{
|
|
int i;
|
|
|
|
for(i=0 ;i<CThing::MAX_TYPE; i++)
|
|
{
|
|
List[i]=NULL;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::killAllThingsForRespawn()
|
|
{
|
|
int i;
|
|
|
|
ASSERT(s_initialised);
|
|
for(i=0;i<CThing::MAX_TYPE;i++)
|
|
{
|
|
// Hey - it's not optimal in speed, but it's vaguely funny :)
|
|
// ( and anyway.. it probly *is* optimal in size.. )
|
|
CThing *thing;
|
|
thing=s_thingLists[i];
|
|
while(thing)
|
|
{
|
|
if(thing->dontKillDuringLevelRespawn())
|
|
{
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
else
|
|
{
|
|
thing->shutdown();
|
|
DeleteThing(thing);
|
|
thing=s_thingLists[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::initAllThings()
|
|
{
|
|
for(int i=0; i<CThing::MAX_TYPE; i++)
|
|
{
|
|
CThing *thing=s_thingLists[i];
|
|
while(thing)
|
|
{
|
|
thing->updateCollisionArea();
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void CThingManager::matchPressureSwitches()
|
|
{
|
|
CNpcHazard *hazard;
|
|
|
|
hazard = (CNpcHazard *) s_thingLists[CThing::TYPE_HAZARD];
|
|
|
|
while( hazard )
|
|
{
|
|
if ( hazard->getThingSubType() == CNpcHazard::NPC_PRESSURE_SWITCH_HAZARD )
|
|
{
|
|
CNpcPressureSwitchHazard *switchHazard = (CNpcPressureSwitchHazard *) hazard;
|
|
|
|
DVECTOR triggerPos = switchHazard->getTriggerPos();
|
|
|
|
CNpcPlatform *platform;
|
|
|
|
platform = (CNpcPlatform *) s_thingLists[CThing::TYPE_PLATFORM];
|
|
|
|
while( platform )
|
|
{
|
|
if ( platform->getThingSubType() == CNpcPlatform::NPC_TRAPDOOR_PLATFORM )
|
|
{
|
|
CNpcTrapdoorPlatform *trapdoor = (CNpcTrapdoorPlatform *) platform;
|
|
|
|
DVECTOR testPos = trapdoor->getTriggerPos();
|
|
|
|
if ( testPos.vx == triggerPos.vx && testPos.vy == triggerPos.vy )
|
|
{
|
|
switchHazard->linkToPlatform( trapdoor );
|
|
}
|
|
}
|
|
|
|
platform = (CNpcPlatform *) platform->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
hazard = (CNpcHazard *) hazard->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void CThingManager::matchWheelsAndWeights()
|
|
{
|
|
CNpcHazard *hazard1;
|
|
CNpcHazard *hazard2;
|
|
|
|
hazard1 = (CNpcHazard *) s_thingLists[CThing::TYPE_HAZARD];
|
|
|
|
while( hazard1 )
|
|
{
|
|
if ( hazard1->getThingSubType() == CNpcHazard::NPC_RISING_WEIGHT_HAZARD )
|
|
{
|
|
CNpcRisingWeightHazard *weight = (CNpcRisingWeightHazard *) hazard1;
|
|
DVECTOR wheelPos = weight->getWheelPos();
|
|
|
|
hazard2 = (CNpcHazard *) s_thingLists[CThing::TYPE_HAZARD];
|
|
|
|
while( hazard2 )
|
|
{
|
|
if ( hazard2->getThingSubType() == CNpcHazard::NPC_RISING_WEIGHT_WHEEL_HAZARD )
|
|
{
|
|
CNpcRisingWeightWheelHazard *wheel = (CNpcRisingWeightWheelHazard *) hazard2;
|
|
|
|
DVECTOR testPos = wheel->getWheelPos();
|
|
|
|
if ( testPos.vx == wheelPos.vx && testPos.vy == wheelPos.vy )
|
|
{
|
|
wheel->linkToWeight( weight );
|
|
}
|
|
}
|
|
|
|
hazard2 = (CNpcHazard *) hazard2->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
hazard1 = (CNpcHazard *) hazard1->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void CThingManager::matchGaryTriggers()
|
|
{
|
|
CNpcFriend *friendNpc;
|
|
|
|
friendNpc = (CNpcFriend *) s_thingLists[CThing::TYPE_NPC];
|
|
|
|
while( friendNpc )
|
|
{
|
|
if ( friendNpc->getThingSubType() == CNpcFriend::NPC_FRIEND_GARY )
|
|
{
|
|
CNpcGaryFriend *gary = (CNpcGaryFriend *) friendNpc;
|
|
|
|
DVECTOR triggerPos = gary->getTriggerPos();
|
|
|
|
CTrigger *trigger;
|
|
|
|
trigger = (CTrigger *) s_thingLists[CThing::TYPE_TRIGGER];
|
|
|
|
while( trigger )
|
|
{
|
|
if ( trigger->getThingSubType() == CTrigger::TRIGGER_GARY_START )
|
|
{
|
|
CGaryStartTrigger *garyTrigger = (CGaryStartTrigger *) trigger;
|
|
|
|
DVECTOR testPos = garyTrigger->getPos();
|
|
testPos.vx >>= 4;
|
|
testPos.vy >>= 4;
|
|
|
|
if ( testPos.vx == triggerPos.vx && testPos.vy == triggerPos.vy )
|
|
{
|
|
garyTrigger->setGary( gary );
|
|
}
|
|
}
|
|
|
|
trigger = (CTrigger *) trigger->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
friendNpc = (CNpcFriend *) friendNpc->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
void CThingManager::thinkAllThings(int _frames)
|
|
{
|
|
// Setup Screen BBox's
|
|
DVECTOR const &CamPos=CLevel::getCameraPos();
|
|
|
|
m_ThinkBBox.XMin=s_ThinkBBoxX0+CamPos.vx;
|
|
m_ThinkBBox.XMax=s_ThinkBBoxX1+CamPos.vx;
|
|
m_ThinkBBox.YMin=s_ThinkBBoxY0+CamPos.vy;
|
|
m_ThinkBBox.YMax=s_ThinkBBoxY1+CamPos.vy;
|
|
|
|
int i;
|
|
CThing *thing;
|
|
CThing *thing1,*thing2,*playerThing;
|
|
|
|
initList(s_CollisionLists);
|
|
|
|
for(i=0; i<CThing::MAX_TYPE; i++)
|
|
{
|
|
thing=s_thingLists[i];
|
|
while(thing)
|
|
{
|
|
// Check If in Thinkable range
|
|
CRECT const *ThingRect= thing->getThinkBBox();
|
|
int lastFlag=thing->getThinkFlag()<<1;
|
|
int Flag=1;
|
|
// Will speed this up
|
|
if (!thing->alwaysThink())
|
|
{
|
|
if (ThingRect->x2<m_ThinkBBox.XMin || ThingRect->x1>m_ThinkBBox.XMax) Flag=0;
|
|
if (ThingRect->y2<m_ThinkBBox.YMin || ThingRect->y1>m_ThinkBBox.YMax) Flag=0;
|
|
}
|
|
thing->setThinkFlag(Flag);
|
|
if (Flag)
|
|
{
|
|
thing->think(_frames);
|
|
// thing->updateCollisionArea();
|
|
if (thing->canCollide())
|
|
{
|
|
CThingManager::addToCollisionList(thing);
|
|
}
|
|
}
|
|
Flag|=lastFlag;
|
|
switch (Flag)
|
|
{ // Last This
|
|
case 0: // 0 0
|
|
break;
|
|
case 1: // 0 1
|
|
thing->enterThingZone(_frames);
|
|
break;
|
|
case 2: // 1 0
|
|
thing->leftThingZone(_frames);
|
|
break;
|
|
case 3: // 1 1
|
|
break;
|
|
default:
|
|
ASSERT("Invalid Think State");
|
|
}
|
|
|
|
|
|
|
|
/* THIS WILL NOT STAY HERE, THINGS MUST BE INITIALISED CORRECTLY */
|
|
thing->updateCollisionArea();
|
|
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
CPlayer *player = GameScene.getPlayer();
|
|
|
|
if ( player )
|
|
{
|
|
player->clearPlatform();
|
|
}
|
|
|
|
playerThing=s_CollisionLists[CThing::TYPE_PLAYER];
|
|
|
|
if (player && playerThing)
|
|
{
|
|
playerThing->setHasPlatformCollided( false );
|
|
|
|
// Player -> Platform collision
|
|
thing1=s_CollisionLists[CThing::TYPE_PLATFORM];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Pickup collision
|
|
thing1=s_CollisionLists[CThing::TYPE_PICKUP];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Enemy collision
|
|
thing1=s_CollisionLists[CThing::TYPE_ENEMY];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Friend collision
|
|
thing1=s_CollisionLists[CThing::TYPE_NPC];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Hazard collision
|
|
thing1=s_CollisionLists[CThing::TYPE_HAZARD];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Enemy projectile collision
|
|
thing1=s_CollisionLists[CThing::TYPE_ENEMYPROJECTILE];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Player -> Trigger collision
|
|
thing1=s_CollisionLists[CThing::TYPE_TRIGGER];
|
|
while(thing1)
|
|
{
|
|
if(thing1->checkCollisionAgainst(playerThing, _frames))
|
|
{
|
|
thing1->collidedWith(playerThing);
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Friend -> Trigger collision
|
|
thing1=s_CollisionLists[CThing::TYPE_TRIGGER];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_NPC];
|
|
while(thing2)
|
|
{
|
|
if(thing1->checkCollisionAgainst(thing2, _frames))
|
|
{
|
|
thing1->collidedWith(thing2);
|
|
}
|
|
thing2=thing2->m_nextCollisionThing;
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Enemy -> Trigger collision
|
|
thing1=s_CollisionLists[CThing::TYPE_TRIGGER];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_ENEMY];
|
|
while(thing2)
|
|
{
|
|
if(thing1->checkCollisionAgainst(thing2, _frames))
|
|
{
|
|
thing1->collidedWith(thing2);
|
|
}
|
|
thing2=thing2->m_nextCollisionThing;
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Enemy -> Player projectile collision
|
|
thing1=s_CollisionLists[CThing::TYPE_PLAYERPROJECTILE];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_ENEMY];
|
|
while(thing2)
|
|
{
|
|
if(thing1->checkCollisionAgainst(thing2, _frames))
|
|
{
|
|
thing1->collidedWith(thing2);
|
|
}
|
|
thing2=thing2->m_nextCollisionThing;
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Enemy -> Enemy collision
|
|
thing1=s_CollisionLists[CThing::TYPE_ENEMY];
|
|
while(thing1)
|
|
{
|
|
thing2=thing1->m_nextCollisionThing;//s_CollisionLists[CThing::TYPE_ENEMY];
|
|
|
|
while(thing2)
|
|
{
|
|
ASSERT(thing1 != thing2 );
|
|
// if ( thing1 != thing2 )
|
|
{
|
|
if (thing1->checkCollisionAgainst( thing2, _frames ) )
|
|
{
|
|
thing1->collidedWith( thing2 );
|
|
//thing2->collidedWith( thing1 );
|
|
}
|
|
}
|
|
thing2 = thing2->m_nextCollisionThing;
|
|
}
|
|
thing1 = thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Hazard -> Platform collision
|
|
thing1=s_CollisionLists[CThing::TYPE_PLATFORM];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_HAZARD];
|
|
|
|
while(thing2)
|
|
{
|
|
if ( thing1 != thing2 )
|
|
{
|
|
if (thing1->checkCollisionAgainst( thing2, _frames ) )
|
|
{
|
|
thing1->collidedWith( thing2 );
|
|
//thing2->collidedWith( thing1 );
|
|
}
|
|
}
|
|
|
|
thing2 = thing2->m_nextCollisionThing;
|
|
}
|
|
|
|
thing1 = thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Platform -> Player projectile collision
|
|
thing1=s_CollisionLists[CThing::TYPE_PLATFORM];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_PLAYERPROJECTILE];
|
|
while(thing2)
|
|
{
|
|
if(thing1->checkCollisionAgainst(thing2, _frames))
|
|
{
|
|
thing1->collidedWith(thing2);
|
|
}
|
|
thing2=thing2->m_nextCollisionThing;
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
|
|
// Friendly npc -> Platform projectile collision - first clear platforms
|
|
|
|
CNpcFriend *friendNpc = (CNpcFriend *) s_CollisionLists[CThing::TYPE_NPC];
|
|
while( friendNpc )
|
|
{
|
|
friendNpc->clearPlatform();
|
|
friendNpc = (CNpcFriend *) friendNpc->m_nextCollisionThing;
|
|
}
|
|
|
|
// now detect new platform
|
|
|
|
thing1=s_CollisionLists[CThing::TYPE_PLATFORM];
|
|
while(thing1)
|
|
{
|
|
thing2=s_CollisionLists[CThing::TYPE_NPC];
|
|
while(thing2)
|
|
{
|
|
if(thing1->checkCollisionAgainst(thing2, _frames))
|
|
{
|
|
thing1->collidedWith(thing2);
|
|
}
|
|
thing2=thing2->m_nextCollisionThing;
|
|
}
|
|
thing1=thing1->m_nextCollisionThing;
|
|
}
|
|
}
|
|
// Shut emm down, sh sh shut em down, we shutem down
|
|
for(i=0;i<CThing::MAX_TYPE;i++)
|
|
{
|
|
thing=s_thingLists[i];
|
|
CThing *nextThing = thing;
|
|
while(thing)
|
|
{
|
|
nextThing=thing->m_nextListThing;
|
|
|
|
if ( thing->isSetToShutdown() )
|
|
{
|
|
thing->shutdown();
|
|
DeleteThing(thing);
|
|
}
|
|
|
|
thing = nextThing;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::renderAllThings()
|
|
{
|
|
// Setup Screen BBox's
|
|
DVECTOR const &CamPos=CLevel::getCameraPos();
|
|
|
|
m_RenderBBox.XMin=s_RenderBBoxX0+CamPos.vx;
|
|
m_RenderBBox.XMax=s_RenderBBoxX1+CamPos.vx;
|
|
m_RenderBBox.YMin=s_RenderBBoxY0+CamPos.vy;
|
|
m_RenderBBox.YMax=s_RenderBBoxY1+CamPos.vy;
|
|
|
|
|
|
for(int i=0;i<CThing::MAX_TYPE;i++)
|
|
{
|
|
CThing *thing=s_thingLists[i];
|
|
while(thing)
|
|
{
|
|
thing->render();
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::processEventAllThings(GAME_EVENT _event,CThing *_sourceThing)
|
|
{
|
|
int i;
|
|
CThing *thing;
|
|
|
|
for(i=0;i<CThing::MAX_TYPE;i++)
|
|
{
|
|
thing=s_thingLists[i];
|
|
while(thing)
|
|
{
|
|
thing->processEvent(_event,_sourceThing);
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose: Searches through a list of things to check for collision against an area.
|
|
The first time this is called, _continue should be false. If no colliding things are found then
|
|
NULL will be returned. If a colliding thing is found then it's address gets returned. To continue
|
|
searching through the list for the next colliding thing, call the function again with _continue set
|
|
to true.
|
|
NB: This function could probly cause weird bugs if not used properly! BE AWARE!
|
|
Params: *_area Area to check against
|
|
_type Type of thing to search for
|
|
_continue If false then the list is searched from the start, if true then the search continues
|
|
from the last thing that was found ( um.. see above )
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
CThing *CThingManager::checkCollisionAreaAgainstThings(CRECT *_area,int _type,int _continue)
|
|
{
|
|
static CThing *thing=NULL;
|
|
|
|
ASSERT(_type<CThing::MAX_TYPE);
|
|
|
|
if(_continue)
|
|
{
|
|
ASSERT(thing);
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
else
|
|
{
|
|
thing=s_thingLists[_type];
|
|
}
|
|
while(thing)
|
|
{
|
|
if(thing->canCollide() && thing->checkCollisionAgainstArea(_area))
|
|
{
|
|
return thing;
|
|
}
|
|
thing=thing->m_nextListThing;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::addToThingList(CThing *_this)
|
|
{
|
|
int Type=_this->getThingType();
|
|
|
|
_this->m_nextListThing=s_thingLists[Type];
|
|
s_thingLists[Type]=_this;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::removeFromThingList(CThing *_this)
|
|
{
|
|
CThing *prevThing,*thing;
|
|
|
|
prevThing=NULL;
|
|
thing=s_thingLists[_this->getThingType()];
|
|
while(thing!=_this)
|
|
{
|
|
prevThing=thing;
|
|
thing=thing->m_nextListThing;
|
|
ASSERT(thing); // Not in the list!?!?
|
|
}
|
|
if(prevThing)
|
|
{
|
|
prevThing->m_nextListThing=_this->m_nextListThing;
|
|
}
|
|
else
|
|
{
|
|
s_thingLists[_this->getThingType()]=_this->m_nextListThing;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThingManager::addToCollisionList(CThing *thing)
|
|
{
|
|
int Type=thing->getThingType();
|
|
|
|
thing->m_nextCollisionThing=s_CollisionLists[Type];
|
|
s_CollisionLists[Type]=thing;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
/*** Free List Stuff ************************************************/
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
void CThingManager::initFreeList()
|
|
{
|
|
#ifdef USE_FREE_LIST
|
|
// Make sure no-one is being naughty
|
|
ASSERT(FreeListTableSize==CThing::MAX_TYPE)
|
|
|
|
for (int i=0; i<FreeListTableSize; i++)
|
|
{
|
|
sFreeListTable const &ThisType=FreeListTable[i];
|
|
int Count=ThisType.Count;
|
|
CThing **List=(CThing**)MemAlloc(Count*sizeof(CThing**),"ThingCache");
|
|
for (int t=0; t<Count; t++)
|
|
{
|
|
List[t]=0;
|
|
|
|
}
|
|
s_FreeList[ThisType.Type]=List;
|
|
|
|
}
|
|
DuffList=0;
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
void CThingManager::resetFreeList()
|
|
{
|
|
#ifdef USE_FREE_LIST
|
|
for (int i=0; i<FreeListTableSize; i++)
|
|
{
|
|
sFreeListTable const &ThisType=FreeListTable[i];
|
|
int Count=ThisType.Count;
|
|
|
|
CThing **List=s_FreeList[i];
|
|
for (int t=0; t<Count; t++)
|
|
{
|
|
CThing *ThisThing=List[t];
|
|
while (ThisThing)
|
|
{
|
|
CThing *Next=ThisThing->NextFreeThing;
|
|
delete ThisThing;
|
|
FreeListCount--;
|
|
ThisThing=Next;
|
|
}
|
|
List[t]=0;
|
|
}
|
|
}
|
|
CThing *Duff=DuffList;
|
|
while (Duff)
|
|
{
|
|
CThing *next=Duff->NextFreeThing;
|
|
delete Duff;
|
|
DuffListCount--;
|
|
Duff=next;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
void CThingManager::shutdownFreeList()
|
|
{
|
|
#ifdef USE_FREE_LIST
|
|
resetFreeList();
|
|
for (int i=0; i<FreeListTableSize; i++)
|
|
{
|
|
sFreeListTable const &ThisType=FreeListTable[i];
|
|
MemFree(s_FreeList[ThisType.Type]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
CThing *CThingManager::GetThing(int Type,int SubType)
|
|
{
|
|
#ifdef USE_FREE_LIST
|
|
CThing **List=s_FreeList[Type];
|
|
CThing *Thing=List[SubType];
|
|
|
|
ASSERT(Type<CThing::MAX_TYPE);
|
|
ASSERT(SubType<FreeListTable[Type].Count);
|
|
if (Thing)
|
|
{
|
|
List[SubType]=Thing->NextFreeThing;
|
|
Thing->initDef();
|
|
Thing->NextFreeThing=0;
|
|
FreeListCount--;
|
|
}
|
|
|
|
return(Thing);
|
|
#else
|
|
return(0);
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
void CThingManager::DeleteThing(CThing *Thing)
|
|
{
|
|
#ifdef USE_FREE_LIST
|
|
int Type=Thing->getThingType();
|
|
int SubType=Thing->getThingSubType();
|
|
CThing **List=s_FreeList[Type];
|
|
|
|
// Check its been aquired/set correctly
|
|
// ASSERT(SubType!=1234);
|
|
if (SubType!=1234)
|
|
{
|
|
Thing->NextFreeThing=List[SubType];
|
|
List[SubType]=Thing;
|
|
FreeListCount++;
|
|
}
|
|
else
|
|
{
|
|
printf("%i %i\n",Type,SubType);
|
|
ASSERT(!"Thing not Setup Correctly");
|
|
Thing->NextFreeThing=DuffList;
|
|
DuffList=Thing;
|
|
DuffListCount++;
|
|
}
|
|
|
|
#else
|
|
delete Thing;
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
/********************************************************************/
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::init()
|
|
{
|
|
ParentThing=NULL;
|
|
NextThing=NULL;
|
|
NextFreeThing=0;
|
|
m_numChildren = 0;
|
|
|
|
Pos.vx=Pos.vy=10;
|
|
// These need to stay for init
|
|
setCollisionSize(20,20); // Some temporary defaults.. (pkg)
|
|
setCollisionCentreOffset(0,0);
|
|
|
|
// Add to thing list
|
|
CThingManager::addToThingList(this);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::shutdown()
|
|
{
|
|
|
|
if (ParentThing)
|
|
{ // Is child
|
|
ParentThing->removeChild(this);
|
|
}
|
|
else
|
|
{ // Is Parent
|
|
removeAllChild();
|
|
}
|
|
|
|
// Remove from thing list
|
|
CThingManager::removeFromThingList(this);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::think(int _frames)
|
|
{
|
|
PosDelta.vx=Pos.vx-PosLast.vx;
|
|
PosDelta.vy=Pos.vy-PosLast.vy;
|
|
PosLast=Pos;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
#if defined (__USER_paul__) || defined (__USER_charles__)
|
|
#define SHOW_BBOX 1
|
|
int showthings=true;
|
|
#endif
|
|
|
|
#if defined (__USER_daveo__)
|
|
#define SHOW_BBOX 1
|
|
int showthings=false;
|
|
#endif
|
|
|
|
void CThing::render()
|
|
{
|
|
// Check Is Onscreen
|
|
CRECT const *ThingRect= getRenderBBox();
|
|
sBBox &ScrBBox=CThingManager::getRenderBBox();
|
|
DVECTOR const &CamPos=CLevel::getCameraPos();
|
|
|
|
m_RenderPos.vx = Pos.vx - CamPos.vx;
|
|
m_RenderPos.vy = Pos.vy - CamPos.vy;
|
|
|
|
// Will speed this up
|
|
m_renderFlag=true;
|
|
if (ThingRect->x2<ScrBBox.XMin || ThingRect->x1>ScrBBox.XMax) m_renderFlag=false;
|
|
if (ThingRect->y2<ScrBBox.YMin || ThingRect->y1>ScrBBox.YMax) m_renderFlag=false;
|
|
|
|
/***/
|
|
#ifdef SHOW_BBOX
|
|
if(showthings) ShowBBox();
|
|
#endif
|
|
|
|
}
|
|
/****************************************************************************************/
|
|
#ifdef SHOW_BBOX
|
|
#include "gfx\prim.h"
|
|
|
|
void CThing::ShowBBox()
|
|
{
|
|
if(showthings)
|
|
{
|
|
DVECTOR const &ofs=CLevel::getCameraPos();
|
|
CRECT area;
|
|
|
|
area=getCollisionArea();
|
|
area.x1-=ofs.vx;
|
|
area.y1-=ofs.vy;
|
|
area.x2-=ofs.vx;
|
|
area.y2-=ofs.vy;
|
|
|
|
if(area.x1<=511&&area.x2>=0 && area.y1<=255&&area.y2>=0)
|
|
{
|
|
DrawLine(area.x1,area.y1,area.x2,area.y1,255,255,255,0);
|
|
DrawLine(area.x2,area.y1,area.x2,area.y2,255,255,255,0);
|
|
DrawLine(area.x2,area.y2,area.x1,area.y2,255,255,255,0);
|
|
DrawLine(area.x1,area.y2,area.x1,area.y1,255,255,255,0);
|
|
|
|
area.x1=Pos.vx-10-ofs.vx;
|
|
area.y1=Pos.vy-10-ofs.vy;
|
|
area.x2=Pos.vx+10-ofs.vx;
|
|
area.y2=Pos.vy+10-ofs.vy;
|
|
DrawLine(area.x1,area.y1,area.x2,area.y2,255,0,0,0);
|
|
DrawLine(area.x2,area.y1,area.x1,area.y2,255,0,0,0);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::addChild(CThing *Child)
|
|
{
|
|
CThing *List=NextThing;
|
|
|
|
if ( List )
|
|
{
|
|
// Find end of list
|
|
while (List->NextThing)
|
|
{
|
|
List=List->NextThing;
|
|
}
|
|
List->NextThing=Child;
|
|
Child->ParentThing=this;
|
|
m_numChildren++;
|
|
}
|
|
else
|
|
{
|
|
// List does not exist, create
|
|
NextThing = Child;
|
|
Child->ParentThing=this;
|
|
m_numChildren++;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::removeChild(CThing *Child)
|
|
{
|
|
CThing *List=NextThing;
|
|
CThing *Last=NULL;
|
|
|
|
// Find Child
|
|
while ( List != Child && List->NextThing )
|
|
{
|
|
Last = List;
|
|
List = List->NextThing;
|
|
}
|
|
|
|
// if there are no more links to continue down, the current 'List' must either be the correct item, or the item does not
|
|
// exist in the list at all
|
|
|
|
ASSERT( List == Child );
|
|
|
|
if ( Last )
|
|
{
|
|
Last->NextThing = List->NextThing;
|
|
}
|
|
else
|
|
{
|
|
this->NextThing = List->NextThing;
|
|
}
|
|
|
|
m_numChildren--;
|
|
|
|
Child->ParentThing=NULL;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::removeAllChild()
|
|
{
|
|
CThing *List=NextThing;
|
|
|
|
while (List)
|
|
{
|
|
CThing *NextThing=List->NextThing;
|
|
List->ParentThing=NULL;
|
|
List->NextThing=NULL;
|
|
List=NextThing;
|
|
}
|
|
NextThing=NULL;
|
|
|
|
m_numChildren = 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::deleteAllChild()
|
|
{
|
|
CThing *List=NextThing;
|
|
|
|
while (List)
|
|
{
|
|
CThing *NextThing=List->NextThing;
|
|
List->ParentThing=NULL;
|
|
List->NextThing=NULL;
|
|
List->shutdown();
|
|
CThingManager::DeleteThing(List);
|
|
List=NextThing;
|
|
}
|
|
NextThing=NULL;
|
|
|
|
m_numChildren = 0;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
/*
|
|
bool CThing::hasChild(CThing *Child)
|
|
{
|
|
CThing *nextChild = NextThing;
|
|
|
|
while( nextChild )
|
|
{
|
|
if ( nextChild == Child )
|
|
{
|
|
return( true );
|
|
}
|
|
|
|
nextChild = nextChild->NextThing;
|
|
}
|
|
|
|
return( false );
|
|
}
|
|
*/
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::setCollisionSize(int _w,int _h)
|
|
{
|
|
m_collisionSize.vx=_w;
|
|
m_collisionSize.vy=_h;
|
|
if(m_collisionSize.vx>m_collisionSize.vy)
|
|
{
|
|
m_collisionRadius=m_collisionSize.vx;
|
|
}
|
|
else
|
|
{
|
|
m_collisionRadius=m_collisionSize.vy;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::updateCollisionArea()
|
|
{
|
|
m_collisionCentre.vx=Pos.vx+m_collisionCentreOffset.vx;
|
|
m_collisionCentre.vy=Pos.vy+m_collisionCentreOffset.vy;
|
|
m_collisionArea.x1=m_collisionCentre.vx-(m_collisionSize.vx/2);
|
|
m_collisionArea.x2=m_collisionArea.x1+m_collisionSize.vx;
|
|
m_collisionArea.y1=m_collisionCentre.vy-(m_collisionSize.vy/2);
|
|
m_collisionArea.y2=m_collisionArea.y1+m_collisionSize.vy;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
|
|
s32 CThing::getNewYPos(CThing *_thisThing)
|
|
{
|
|
CRECT thisRect;
|
|
thisRect = getCollisionArea();
|
|
|
|
if ( thisRect.y1 < thisRect.y2 )
|
|
{
|
|
return( thisRect.y1 );
|
|
}
|
|
else
|
|
{
|
|
return( thisRect.y2 );
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
int CThing::checkCollisionAgainst(CThing *_thisThing, int _frames)
|
|
{
|
|
DVECTOR pos,thisThingPos;
|
|
int radius;
|
|
int collided;
|
|
|
|
pos=getCollisionCentre();
|
|
thisThingPos=_thisThing->getCollisionCentre();
|
|
|
|
radius=getCollisionRadius()+_thisThing->getCollisionRadius();
|
|
collided=false;
|
|
if(abs(pos.vx-thisThingPos.vx)<radius&&
|
|
abs(pos.vy-thisThingPos.vy)<radius)
|
|
{
|
|
CRECT thisRect,thatRect;
|
|
|
|
thisRect=getCollisionArea();
|
|
|
|
thatRect=_thisThing->getCollisionArea();
|
|
|
|
if(((thisRect.x1>=thatRect.x1&&thisRect.x1<=thatRect.x2)||(thisRect.x2>=thatRect.x1&&thisRect.x2<=thatRect.x2)||(thisRect.x1<=thatRect.x1&&thisRect.x2>=thatRect.x2))&&
|
|
((thisRect.y1>=thatRect.y1&&thisRect.y1<=thatRect.y2)||(thisRect.y2>=thatRect.y1&&thisRect.y2<=thatRect.y2)||(thisRect.y1<=thatRect.y1&&thisRect.y2>=thatRect.y2)))
|
|
{
|
|
collided=true;
|
|
}
|
|
}
|
|
|
|
return collided;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
int CThing::checkCollisionAgainstArea(CRECT *_rect)
|
|
{
|
|
CRECT thisRect;
|
|
int ret;
|
|
|
|
thisRect=getCollisionArea();
|
|
ret=false;
|
|
|
|
if(((thisRect.x1>=_rect->x1&&thisRect.x1<=_rect->x2)||(thisRect.x2>=_rect->x1&&thisRect.x2<=_rect->x2)||(thisRect.x1<=_rect->x1&&thisRect.x2>=_rect->x2))&&
|
|
((thisRect.y1>=_rect->y1&&thisRect.y1<=_rect->y2)||(thisRect.y2>=_rect->y1&&thisRect.y2<=_rect->y2)||(thisRect.y1<=_rect->y1&&thisRect.y2>=_rect->y2)))
|
|
{
|
|
ret=true;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|
|
void CThing::processEvent(GAME_EVENT _event,CThing *_sourceThing)
|
|
{
|
|
// do nothing by default - ignore event
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------------------
|
|
Function:
|
|
Purpose:
|
|
Params:
|
|
Returns:
|
|
---------------------------------------------------------------------- */
|