mirror of
https://github.com/tribes2/engine.git
synced 2026-01-20 19:54:46 +00:00
2878 lines
95 KiB
C++
2878 lines
95 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "game/targetManager.h"
|
|
#include "sim/netConnection.h"
|
|
#include "core/bitStream.h"
|
|
#include "game/gameConnection.h"
|
|
#include "game/sensor.h"
|
|
#include "game/shapeBase.h"
|
|
#include "console/consoleTypes.h"
|
|
#include "game/player.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
TargetManager * gTargetManager = NULL;
|
|
HUDTargetList * gTargetList = NULL;
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Client target notification system:
|
|
//------------------------------------------------------------------------------
|
|
TargetManagerNotify::TargetManagerNotify()
|
|
{
|
|
AssertISV(gTargetManager, "TargetManagerNotify:: no target manager present!");
|
|
gTargetManager->addNotify(this);
|
|
}
|
|
|
|
TargetManagerNotify::~TargetManagerNotify()
|
|
{
|
|
if(gTargetManager)
|
|
gTargetManager->removeNotify(this);
|
|
}
|
|
|
|
void TargetManager::addNotify(TargetManagerNotify * notify)
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
if(notifyList[i] == notify)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::addNotify: object already being notified!");
|
|
return;
|
|
}
|
|
notifyList.push_back(notify);
|
|
}
|
|
|
|
void TargetManager::removeNotify(TargetManagerNotify * notify)
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
if(notifyList[i] == notify)
|
|
{
|
|
notifyList.erase(i);
|
|
return;
|
|
}
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::removeNotify: object not found in notify list!");
|
|
}
|
|
|
|
void TargetManager::notifyTargetAdded(U32 target)
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
notifyList[i]->targetAdded(target);
|
|
}
|
|
|
|
void TargetManager::notifyTargetRemoved(U32 target)
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
notifyList[i]->targetRemoved(target);
|
|
}
|
|
|
|
void TargetManager::notifyTargetChanged(U32 target)
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
notifyList[i]->targetChanged(target);
|
|
}
|
|
|
|
void TargetManager::notifyTargetsCleared()
|
|
{
|
|
for(S32 i = notifyList.size() - 1; i >= 0; i--)
|
|
notifyList[i]->targetsCleared();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Client target free notification:
|
|
//------------------------------------------------------------------------------
|
|
class TargetFreeEvent : public NetEvent
|
|
{
|
|
public:
|
|
S32 mTarget;
|
|
TargetFreeEvent(S32 target = 0)
|
|
{
|
|
mTarget = target;
|
|
}
|
|
void pack(NetConnection *, BitStream *bstream)
|
|
{
|
|
bstream->writeInt(mTarget, TargetManager::TargetIdBitSize);
|
|
}
|
|
void write(NetConnection *conn, BitStream *bstream)
|
|
{
|
|
pack(conn, bstream);
|
|
}
|
|
void unpack(NetConnection *, BitStream *bstream)
|
|
{
|
|
mTarget = bstream->readInt(TargetManager::TargetIdBitSize);
|
|
}
|
|
void process(NetConnection *conn)
|
|
{
|
|
GameConnection *gc = (GameConnection *) conn;
|
|
TargetInfo *targ = gTargetManager->getClientTarget(mTarget);
|
|
|
|
if(gTargetManager->mClientAudioHandles[mTarget] != NULL_AUDIOHANDLE)
|
|
{
|
|
alxStop(gTargetManager->mClientAudioHandles[mTarget]);
|
|
gTargetManager->mClientAudioHandles[mTarget] = 0;
|
|
}
|
|
|
|
if(targ->allocated)
|
|
gTargetManager->notifyTargetRemoved(mTarget);
|
|
|
|
if(bool(targ->targetObject))
|
|
targ->targetObject->targetInfoChanged(0);
|
|
|
|
targ->clear(false);
|
|
}
|
|
DECLARE_CONOBJECT(TargetFreeEvent);
|
|
};
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(TargetFreeEvent);
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Client new/changed target info event:
|
|
//------------------------------------------------------------------------------
|
|
class TargetInfoEvent : public NetEvent
|
|
{
|
|
public:
|
|
S32 mTarget;
|
|
S32 mNameTag;
|
|
S32 mSkinTag;
|
|
S32 mVoiceTag;
|
|
S32 mTypeTag;
|
|
S32 mSkinPrefTag;
|
|
S32 mSensorGroup;
|
|
S32 mDataBlockId;
|
|
S32 mRenderFlags;
|
|
F32 mVoicePitch;
|
|
|
|
TargetInfoEvent(S32 target = 0, S32 nameTag = 0, S32 skinTag = 0, S32 voiceTag = 0,
|
|
S32 typeTag = 0, S32 sensorGroup = 0, S32 dataBlockId = 0, S32 renderFlags = 0, F32 voicePitch = -1.0f, S32 prefSkin = -1)
|
|
{
|
|
mTarget = target;
|
|
mNameTag = nameTag;
|
|
mSkinTag = skinTag;
|
|
mVoiceTag = voiceTag;
|
|
mTypeTag = typeTag;
|
|
mSensorGroup = sensorGroup;
|
|
mDataBlockId = dataBlockId;
|
|
mSkinPrefTag = prefSkin;
|
|
mRenderFlags = renderFlags;
|
|
mVoicePitch = voicePitch;
|
|
}
|
|
|
|
void pack(NetConnection *, BitStream *bstream)
|
|
{
|
|
bstream->writeInt(mTarget, TargetManager::TargetIdBitSize);
|
|
if(bstream->writeFlag(mNameTag != -1))
|
|
if(bstream->writeFlag(mNameTag))
|
|
bstream->writeInt(mNameTag, NetStringTable::StringIdBitSize);
|
|
if(bstream->writeFlag(mSkinTag != -1))
|
|
if(bstream->writeFlag(mSkinTag))
|
|
bstream->writeInt(mSkinTag, NetStringTable::StringIdBitSize);
|
|
if(bstream->writeFlag(mSkinPrefTag != -1))
|
|
if(bstream->writeFlag(mSkinPrefTag))
|
|
bstream->writeInt(mSkinPrefTag, NetStringTable::StringIdBitSize);
|
|
if(bstream->writeFlag(mVoiceTag != -1))
|
|
if(bstream->writeFlag(mVoiceTag))
|
|
bstream->writeInt(mVoiceTag, NetStringTable::StringIdBitSize);
|
|
if(bstream->writeFlag(mTypeTag != -1))
|
|
if(bstream->writeFlag(mTypeTag))
|
|
bstream->writeInt(mTypeTag, NetStringTable::StringIdBitSize);
|
|
if(bstream->writeFlag(mSensorGroup != -1))
|
|
bstream->writeInt(mSensorGroup, 5);
|
|
if(bstream->writeFlag(mDataBlockId != -1))
|
|
if(bstream->writeFlag(mDataBlockId))
|
|
bstream->writeRangedU32(mDataBlockId, DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
if(bstream->writeFlag(mRenderFlags != -1))
|
|
bstream->writeInt(mRenderFlags, TargetInfo::NumRenderBits);
|
|
if(bstream->writeFlag(mVoicePitch != -1))
|
|
{
|
|
//convert the voice pitch from range [0.5, 2.0] to [0.0, 1.0]
|
|
if (mVoicePitch < 0.5f || mVoicePitch > 2.0f)
|
|
mVoicePitch = 1.0f;
|
|
F32 packFloat = (mVoicePitch - 0.5f) / 1.5f;
|
|
bstream->writeFloat(packFloat, 7);
|
|
}
|
|
}
|
|
|
|
void write(NetConnection *conn, BitStream *bstream)
|
|
{
|
|
pack(conn, bstream);
|
|
}
|
|
|
|
void unpack(NetConnection *, BitStream *bstream)
|
|
{
|
|
mTarget = bstream->readInt(TargetManager::TargetIdBitSize);
|
|
mNameTag = mSkinTag = mVoiceTag = mTypeTag = mSensorGroup = mDataBlockId = mRenderFlags = -1;
|
|
mSkinPrefTag = -1;
|
|
mVoicePitch = -1.0f;
|
|
if(bstream->readFlag())
|
|
{
|
|
if(bstream->readFlag())
|
|
mNameTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
else
|
|
mNameTag = 0;
|
|
}
|
|
if(bstream->readFlag())
|
|
{
|
|
if(bstream->readFlag())
|
|
mSkinTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
else
|
|
mSkinTag = 0;
|
|
}
|
|
if(bstream->readFlag())
|
|
{
|
|
if(bstream->readFlag())
|
|
mSkinPrefTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
else
|
|
mSkinPrefTag = 0;
|
|
}
|
|
if(bstream->readFlag())
|
|
{
|
|
if(bstream->readFlag())
|
|
mVoiceTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
else
|
|
mVoiceTag = 0;
|
|
}
|
|
if(bstream->readFlag())
|
|
{
|
|
if(bstream->readFlag())
|
|
mTypeTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
else
|
|
mTypeTag = 0;
|
|
}
|
|
if(bstream->readFlag())
|
|
mSensorGroup = bstream->readInt(5);
|
|
|
|
if(bstream->readFlag())
|
|
if(bstream->readFlag())
|
|
mDataBlockId = bstream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
|
|
if(bstream->readFlag())
|
|
mRenderFlags = bstream->readInt(TargetInfo::NumRenderBits);
|
|
|
|
if(bstream->readFlag())
|
|
{
|
|
//convert the voice pitch from range [0.0, 1.0] back to [0.5, 2.0]
|
|
F32 unpackFloat = bstream->readFloat(7);
|
|
mVoicePitch = (unpackFloat * 1.5f) + 0.5f;
|
|
}
|
|
}
|
|
|
|
void process(NetConnection *conn)
|
|
{
|
|
GameConnection *gc = (GameConnection *) conn;
|
|
|
|
// translate all the strings
|
|
TargetInfo *targ = gTargetManager->getClientTarget(mTarget);
|
|
if(mNameTag != -1)
|
|
{
|
|
targ->sNameTag = mNameTag;
|
|
targ->nameTag = conn->translateRemoteStringId(mNameTag);
|
|
}
|
|
if(mSkinTag != -1)
|
|
{
|
|
targ->sSkinTag = mSkinTag;
|
|
targ->skinTag = conn->translateRemoteStringId(mSkinTag);
|
|
}
|
|
if(mSkinPrefTag != -1)
|
|
{
|
|
targ->sSkinPrefTag = mSkinPrefTag;
|
|
targ->skinPrefTag = conn->translateRemoteStringId(mSkinPrefTag);
|
|
}
|
|
if(mVoiceTag != -1)
|
|
{
|
|
targ->sVoiceTag = mVoiceTag;
|
|
targ->voiceTag = conn->translateRemoteStringId(mVoiceTag);
|
|
}
|
|
if(mTypeTag != -1)
|
|
{
|
|
targ->sTypeTag = mTypeTag;
|
|
targ->typeTag = conn->translateRemoteStringId(mTypeTag);
|
|
}
|
|
|
|
U32 oldGroup = targ->sensorGroup;
|
|
if(mSensorGroup != -1)
|
|
targ->sensorGroup = mSensorGroup;
|
|
|
|
if(mRenderFlags != -1)
|
|
targ->renderFlags = mRenderFlags;
|
|
|
|
// team targets do not get notifications or objects
|
|
if(mTarget >= 32)
|
|
{
|
|
if(mDataBlockId >= 0)
|
|
targ->shapeBaseData = mDataBlockId ? dynamic_cast<ShapeBaseData*>(Sim::findObject(mDataBlockId)) : 0;
|
|
|
|
if(targ->allocated)
|
|
{
|
|
gTargetManager->notifyTargetChanged(mTarget);
|
|
}
|
|
else
|
|
{
|
|
// created a new client target
|
|
targ->allocated = true;
|
|
gTargetManager->notifyTargetAdded(mTarget);
|
|
}
|
|
|
|
if(bool(targ->targetObject))
|
|
targ->targetObject->targetInfoChanged(targ);
|
|
}
|
|
|
|
if(mVoicePitch != -1.0f)
|
|
targ->voicePitch = mVoicePitch;
|
|
}
|
|
DECLARE_CONOBJECT(TargetInfoEvent);
|
|
};
|
|
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(TargetInfoEvent);
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Targets get one audio handle associated with them
|
|
//------------------------------------------------------------------------------
|
|
static F32 SoundPosAccuracy = 0.5;
|
|
|
|
class SimTargetAudioEvent : public NetEvent
|
|
{
|
|
private:
|
|
S32 mTargetId;
|
|
S32 mFileTag;
|
|
S32 mDescriptionId;
|
|
|
|
bool mHasPosition;
|
|
Point3F mPosition;
|
|
|
|
bool mUpdateSound;
|
|
|
|
public:
|
|
SimTargetAudioEvent(S32 targetId = -1, S32 fileTag = 0, S32 descId = 0, Point3F * pos = 0, bool update = false);
|
|
void pack(NetConnection * con, BitStream * bstream);
|
|
void write(NetConnection * con, BitStream * bstream);
|
|
void unpack(NetConnection * con, BitStream * bstream);
|
|
void process(NetConnection *);
|
|
DECLARE_CONOBJECT(SimTargetAudioEvent);
|
|
};
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(SimTargetAudioEvent);
|
|
|
|
SimTargetAudioEvent::SimTargetAudioEvent(S32 targetId, S32 fileTag, S32 descId, Point3F * pos, bool update)
|
|
{
|
|
mTargetId = targetId;
|
|
mFileTag = fileTag;
|
|
mDescriptionId = descId;
|
|
mUpdateSound = update;
|
|
|
|
if(pos)
|
|
{
|
|
mHasPosition = true;
|
|
mPosition = *pos;
|
|
}
|
|
else
|
|
mHasPosition = false;
|
|
}
|
|
|
|
void SimTargetAudioEvent::pack(NetConnection * con, BitStream * bstream)
|
|
{
|
|
bstream->writeInt(mTargetId, TargetManager::TargetIdBitSize);
|
|
bstream->writeInt(mFileTag, NetStringTable::StringIdBitSize);
|
|
bstream->writeRangedU32(mDescriptionId, DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
if(bstream->writeFlag(mHasPosition))
|
|
con->writeCompressed(bstream, mPosition, SoundPosAccuracy);
|
|
|
|
bstream->writeFlag(mUpdateSound);
|
|
}
|
|
|
|
void SimTargetAudioEvent::write(NetConnection * con, BitStream * bstream)
|
|
{
|
|
pack(con, bstream);
|
|
}
|
|
|
|
void SimTargetAudioEvent::unpack(NetConnection * con, BitStream * bstream)
|
|
{
|
|
mTargetId = bstream->readInt(TargetManager::TargetIdBitSize);
|
|
mFileTag = bstream->readInt(NetStringTable::StringIdBitSize);
|
|
mDescriptionId = bstream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
|
|
mHasPosition = bstream->readFlag();
|
|
if(mHasPosition)
|
|
con->readCompressed(bstream, &mPosition, SoundPosAccuracy);
|
|
|
|
mUpdateSound = bstream->readFlag();
|
|
}
|
|
|
|
void SimTargetAudioEvent::process(NetConnection * con)
|
|
{
|
|
TargetInfo * targInfo = gTargetManager->getClientTarget(mTargetId);
|
|
if(!targInfo)
|
|
return;
|
|
|
|
AudioDescription * description = dynamic_cast<AudioDescription*>(Sim::findObject(mDescriptionId));
|
|
if(!description)
|
|
return;
|
|
|
|
if(!mHasPosition)
|
|
{
|
|
if(!bool(targInfo->targetObject))
|
|
return;
|
|
targInfo->targetObject->getTransform().getColumn(3, &mPosition);
|
|
}
|
|
|
|
mFileTag = con->translateRemoteStringId(mFileTag);
|
|
|
|
if(!mFileTag || !targInfo->voiceTag)
|
|
return;
|
|
|
|
const char * name = gNetStringTable->lookupString(mFileTag);
|
|
const char * voice = gNetStringTable->lookupString(targInfo->voiceTag);
|
|
|
|
if(!name || !voice || !name[0] || !voice[0])
|
|
return;
|
|
|
|
char buf[256];
|
|
dSprintf(buf, sizeof(buf), "voice/%s/%s.wav", voice, name);
|
|
|
|
MatrixF mat(true);
|
|
mat.setColumn(3, mPosition);
|
|
|
|
if( mUpdateSound )
|
|
{
|
|
AUDIOHANDLE & handle = gTargetManager->mClientAudioHandles[mTargetId];
|
|
if(handle != NULL_AUDIOHANDLE)
|
|
alxStop(handle);
|
|
handle = alxCreateSource(description, buf, &mat);
|
|
|
|
if (targInfo->voicePitch != 1.0f)
|
|
alxSourcef(handle, AL_PITCH, targInfo->voicePitch);
|
|
alxPlay(handle);
|
|
}
|
|
else
|
|
{
|
|
AUDIOHANDLE handle = alxCreateSource(description, buf, &mat);
|
|
if (targInfo->voicePitch != 1.0)
|
|
alxSourcef(handle, AL_PITCH, targInfo->voicePitch);
|
|
alxPlay(handle);
|
|
}
|
|
}
|
|
|
|
bool TargetManager::playTargetAudio(S32 targetId, S32 fileTag, AudioDescription * description, bool update)
|
|
{
|
|
// check args: must have target, file, description
|
|
if((targetId < 0) || (targetId >= MaxTargets))
|
|
return(false);
|
|
|
|
if(fileTag <= 0)
|
|
return(false);
|
|
|
|
if(!description)
|
|
return(false);
|
|
|
|
// get position of target
|
|
TargetInfo * targInfo = getServerTarget(targetId);
|
|
if(!targInfo)
|
|
return(false);
|
|
|
|
if(!bool(targInfo->targetObject))
|
|
return(false);
|
|
|
|
Point3F pos;
|
|
targInfo->targetObject->getTransform().getColumn(3, &pos);
|
|
|
|
// send to whomever can hear...
|
|
for(NetConnection * con = NetConnection::getConnectionList(); con; con = con->getNext())
|
|
{
|
|
if(con->isServerConnection())
|
|
continue;
|
|
|
|
if (dynamic_cast<GameConnection*>(con) && static_cast<GameConnection*>(con)->isAIControlled())
|
|
continue;
|
|
|
|
ShapeBase * controlObj = static_cast<GameConnection*>(con)->getControlObject();
|
|
if(!controlObj)
|
|
continue;
|
|
|
|
Point3F ear;
|
|
controlObj->getTransform().getColumn(3, &ear);
|
|
if((ear - pos).magnitudeSafe() >= description->mDescription.mMaxDistance)
|
|
continue;
|
|
|
|
// send position if not scoped on client
|
|
bool sendPos = con->getGhostIndex(targInfo->targetObject) == -1;
|
|
|
|
// send it
|
|
con->checkString(fileTag);
|
|
con->postNetEvent(new SimTargetAudioEvent(targetId, fileTag, description->getId(), sendPos ? &pos : 0, update));
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
TargetManager::TargetManager()
|
|
{
|
|
VECTOR_SET_ASSOCIATION(notifyList);
|
|
clear();
|
|
}
|
|
|
|
void TargetManager::clear()
|
|
{
|
|
mFreeCount = MaxTargets;
|
|
mLastSensedObject = 0;
|
|
mSensorGroupCount = 0;
|
|
U32 i;
|
|
for(i = 0; i < TargetFreeMaskSize; i++)
|
|
mFreeMask[i] = 0;
|
|
for(i = 0; i < MaxTargets; i++)
|
|
{
|
|
mTargets[i].clear();
|
|
mClientTargets[i].clear();
|
|
mClientAudioHandles[i] = NULL_AUDIOHANDLE;
|
|
}
|
|
|
|
// reserve team targets
|
|
mFreeCount -= 32;
|
|
mFreeMask[0] = 0xffffffff;
|
|
|
|
// setup the sensorgroups and sensorgroup masks
|
|
for(i = 0; i < 32; i++)
|
|
{
|
|
mSensorInfoArray[i].clear();
|
|
|
|
// team targets
|
|
mTargets[i].sensorGroup = mClientTargets[i].sensorGroup = i;
|
|
|
|
// default teams to be friendly, visible, and can listen to themselves
|
|
mSensorGroupListenMask[i] = mSensorGroupAlwaysVisMask[i] = mSensorGroupFriendlyMask[i] = (1 << i);
|
|
mSensorGroupNeverVisMask[i] = 0;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
class SensorGroupColorEvent : public NetEvent
|
|
{
|
|
public:
|
|
|
|
U32 mUpdateMask;
|
|
U32 mSensorGroup;
|
|
ColorI mColors[32];
|
|
|
|
SensorGroupColorEvent(U32 sensorGroup = 0, U32 updateMask = 0)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "SensorGroupColorEvent:: invalid sensor group");
|
|
|
|
mSensorGroup = sensorGroup;
|
|
mUpdateMask = updateMask;
|
|
dMemcpy(&mColors, &gTargetManager->mSensorInfoArray[mSensorGroup].groupColor, 32 * sizeof(ColorI));
|
|
}
|
|
|
|
void pack(NetConnection *, BitStream *bstream)
|
|
{
|
|
bstream->writeInt(mSensorGroup, 5);
|
|
bstream->write(mUpdateMask);
|
|
|
|
for(U32 i = 0; i < 32; i++)
|
|
if((1<<i) & mUpdateMask)
|
|
if(bstream->writeFlag(mColors[i] != TargetManager::SensorInfo::smDefaultColor))
|
|
{
|
|
bstream->write(mColors[i].red);
|
|
bstream->write(mColors[i].green);
|
|
bstream->write(mColors[i].blue);
|
|
bstream->write(mColors[i].alpha);
|
|
}
|
|
}
|
|
|
|
void write(NetConnection *conn, BitStream *bstream)
|
|
{
|
|
pack(conn, bstream);
|
|
}
|
|
|
|
void unpack(NetConnection *, BitStream *bstream)
|
|
{
|
|
mSensorGroup = bstream->readInt(5);
|
|
bstream->read(&mUpdateMask);
|
|
|
|
for(U32 i = 0; i < 32; i++)
|
|
if((1<<i) & mUpdateMask)
|
|
{
|
|
if(bstream->readFlag())
|
|
{
|
|
bstream->read(&mColors[i].red);
|
|
bstream->read(&mColors[i].green);
|
|
bstream->read(&mColors[i].blue);
|
|
bstream->read(&mColors[i].alpha);
|
|
}
|
|
else
|
|
mColors[i] = TargetManager::SensorInfo::smDefaultColor;
|
|
}
|
|
}
|
|
|
|
void process(NetConnection *)
|
|
{
|
|
TargetManager::SensorInfo * sensorInfo = &gTargetManager->mSensorInfoArray[mSensorGroup];
|
|
for(U32 i = 0; i < 32; i++)
|
|
if((1<<i) & mUpdateMask)
|
|
sensorInfo->groupColor[i] = mColors[i];
|
|
}
|
|
|
|
DECLARE_CONOBJECT(SensorGroupColorEvent);
|
|
};
|
|
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(SensorGroupColorEvent);
|
|
|
|
void TargetManager::clientSensorGroupChanged(NetConnection * client, U32 newGroup)
|
|
{
|
|
if(dynamic_cast<GameConnection*>(client) && static_cast<GameConnection*>(client)->isAIControlled())
|
|
return;
|
|
client->postNetEvent(new SensorGroupColorEvent(newGroup, 0xffffffff));
|
|
}
|
|
|
|
ColorI TargetManager::getSensorGroupColor(U32 sensorGroup, U32 colorGroup)
|
|
{
|
|
AssertFatal((sensorGroup < 32) && (colorGroup < 32), "TagetManager:: invalidSensorGroup");
|
|
return(mSensorInfoArray[sensorGroup].groupColor[colorGroup]);
|
|
}
|
|
|
|
void TargetManager::setSensorGroupColor(U32 sensorGroup, U32 updateMask, ColorI & color)
|
|
{
|
|
AssertFatal((sensorGroup >= 0) && (sensorGroup < 32), "TargetManager:: invalid sensor group");
|
|
SensorInfo * sensorInfo = &mSensorInfoArray[sensorGroup];
|
|
|
|
for(U32 i = 0; i < 32; i++)
|
|
if((1 << i) & updateMask)
|
|
sensorInfo->groupColor[i] = color;
|
|
|
|
for(NetConnection * con = NetConnection::getConnectionList(); con; con = con->getNext())
|
|
{
|
|
if(con->isServerConnection())
|
|
continue;
|
|
|
|
GameConnection * gc = dynamic_cast<GameConnection*>(con);
|
|
if(!gc)
|
|
continue;
|
|
|
|
if(gc->isAIControlled() || (gc->getSensorGroup() != sensorGroup))
|
|
continue;
|
|
|
|
gc->postNetEvent(new SensorGroupColorEvent(sensorGroup, updateMask));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// an '_' as the first char for the string excludes it
|
|
bool TargetManager::getGameName(S32 target, char * buf, S32 bufSize, bool server)
|
|
{
|
|
if(target < 0 || target >= MaxTargets)
|
|
return(false);
|
|
|
|
TargetInfo * targInfo = server ? gTargetManager->getServerTarget(target) :
|
|
gTargetManager->getClientTarget(target);
|
|
|
|
if(!targInfo->allocated)
|
|
return(false);
|
|
|
|
const char * name = gNetStringTable->lookupString(targInfo->nameTag);
|
|
const char * type = gNetStringTable->lookupString(targInfo->typeTag);
|
|
|
|
// game name = 'name type'
|
|
if(name && name[0] && (name[0] != '_'))
|
|
{
|
|
if(type && type[0] && (type[0] != '_'))
|
|
dSprintf(buf, bufSize, "%s %s", name, type);
|
|
else
|
|
dSprintf(buf, bufSize, "%s", name);
|
|
}
|
|
else if(type && type[0] && (type[0] != '_'))
|
|
dSprintf(buf, bufSize, "%s", type);
|
|
|
|
return(true);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void TargetManager::newClient(NetConnection *client)
|
|
{
|
|
if(dynamic_cast<GameConnection*>(client) && static_cast<GameConnection*>(client)->isAIControlled())
|
|
return;
|
|
|
|
for(U32 i = 0; i < TargetFreeMaskSize; i++)
|
|
{
|
|
if(mFreeMask[i] == 0)
|
|
continue;
|
|
|
|
for(U32 j = 0; j < 32; j++)
|
|
{
|
|
if(mFreeMask[i] & (1 << j))
|
|
{
|
|
TargetInfo &targ = mTargets[(i << 5) + j];
|
|
client->checkString(targ.nameTag);
|
|
client->checkString(targ.skinTag);
|
|
client->checkString(targ.voiceTag);
|
|
client->checkString(targ.typeTag);
|
|
|
|
client->postNetEvent(new TargetInfoEvent( (i << 5) + j, targ.nameTag,
|
|
targ.skinTag, targ.voiceTag, targ.typeTag, targ.sensorGroup,
|
|
bool(targ.shapeBaseData) ? targ.shapeBaseData->getId() : 0, targ.renderFlags, targ.voicePitch));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
S32 TargetManager::allocTarget(U32 nameTag, U32 skinTag, U32 voiceTag, U32 typeTag, U32 sensorGroup, U32 dataBlockId, F32 voicePitch, U32 prefSkin)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::allocTarget: invalid sensorGroup");
|
|
|
|
// find a free mask
|
|
if(mFreeCount == 0)
|
|
return -1;
|
|
S32 targ = -1;
|
|
for(U32 i = 0; i < TargetFreeMaskSize; i++)
|
|
{
|
|
if(mFreeMask[i] == 0xFFFFFFFF)
|
|
continue;
|
|
for(U32 j = 0; j < 32; j++)
|
|
{
|
|
if(!( mFreeMask[i] & (1 << j) ))
|
|
{
|
|
targ = (i << 5) + j;
|
|
mFreeMask[i] |= (1 << j);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
AssertFatal(targ != -1, "Invalid target index.");
|
|
mFreeCount--;
|
|
|
|
mTargets[targ].allocated = true;
|
|
mTargets[targ].nameTag = nameTag;
|
|
mTargets[targ].skinTag = skinTag;
|
|
mTargets[targ].voiceTag = voiceTag;
|
|
mTargets[targ].typeTag = typeTag;
|
|
mTargets[targ].skinPrefTag = prefSkin;
|
|
mTargets[targ].sensorGroup = sensorGroup;
|
|
mTargets[targ].renderFlags = 0;
|
|
mTargets[targ].voicePitch = voicePitch;
|
|
|
|
// vis/friend masks default to team values
|
|
mTargets[targ].sensorAlwaysVisMask = mSensorGroupAlwaysVisMask[sensorGroup];
|
|
mTargets[targ].sensorNeverVisMask = mSensorGroupNeverVisMask[sensorGroup];
|
|
mTargets[targ].sensorFriendlyMask = mSensorGroupFriendlyMask[sensorGroup];
|
|
|
|
mTargets[targ].sensorFlags = 0;
|
|
mTargets[targ].sensorVisMask = 0;
|
|
|
|
mTargets[targ].shapeBaseData = dataBlockId ? dynamic_cast<ShapeBaseData*>(Sim::findObject(dataBlockId)) : 0;
|
|
|
|
updateTarget(targ, nameTag, skinTag, voiceTag, typeTag, sensorGroup, dataBlockId, 0, voicePitch, prefSkin);
|
|
return targ;
|
|
}
|
|
|
|
void TargetManager::updateTarget(S32 targ, S32 nameTag, S32 skinTag, S32 voiceTag, S32 typeTag, S32 sensorGroup, S32 dataBlockId, S32 renderFlags, F32 voicePitch, U32 prefSkin)
|
|
{
|
|
for(NetConnection *conn = NetConnection::getConnectionList(); conn; conn = conn->getNext())
|
|
{
|
|
if(conn->isServerConnection())
|
|
continue;
|
|
|
|
if (dynamic_cast<GameConnection*>(conn) && static_cast<GameConnection*>(conn)->isAIControlled())
|
|
continue;
|
|
|
|
if(nameTag != -1)
|
|
conn->checkString(nameTag);
|
|
if(skinTag != -1)
|
|
conn->checkString(skinTag);
|
|
if(voiceTag != -1)
|
|
conn->checkString(voiceTag);
|
|
if(typeTag != -1)
|
|
conn->checkString(typeTag);
|
|
if(prefSkin != -1)
|
|
conn->checkString(prefSkin);
|
|
conn->postNetEvent(new TargetInfoEvent(targ, nameTag, skinTag, voiceTag, typeTag, sensorGroup, dataBlockId, renderFlags, voicePitch, prefSkin));
|
|
}
|
|
}
|
|
|
|
void TargetManager::freeTarget(S32 target)
|
|
{
|
|
AssertFatal(target >= 32 && target < MaxTargets, "Invalid target id.");
|
|
|
|
for(NetConnection *conn = NetConnection::getConnectionList(); conn; conn = conn->getNext())
|
|
{
|
|
if(conn->isServerConnection())
|
|
continue;
|
|
if (dynamic_cast<GameConnection*>(conn) && static_cast<GameConnection*>(conn)->isAIControlled())
|
|
continue;
|
|
conn->postNetEvent(new TargetFreeEvent(target));
|
|
}
|
|
|
|
for(U32 i = 0; i < 32; i++)
|
|
mSensorInfoArray[i].setSensorVisible(target, false);
|
|
|
|
// notify the target object
|
|
if(bool(mTargets[target].targetObject))
|
|
mTargets[target].targetObject->targetInfoChanged(0);
|
|
|
|
mTargets[target].clear(false);
|
|
|
|
// update the free mask/count
|
|
U32 index = target >> 5;
|
|
U32 bit = target & 0x1F;
|
|
if(!(mFreeMask[index] & (1 << bit)))
|
|
return;
|
|
mFreeMask[index] &= ~(1 << bit);
|
|
mFreeCount++;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Class ResetClientTargetsEvent: HUDTargetList will be notified of clear
|
|
// - overloaded for HUDTargetList use as well
|
|
// - needs to reset the connections visible target list on pack because
|
|
// the connection gets packed (and can change the visibility of items) before
|
|
// the event goes through
|
|
//--------------------------------------------------------------------------
|
|
class ResetClientTargetsEvent : public NetEvent
|
|
{
|
|
private:
|
|
bool mClientTargetsOnly;
|
|
|
|
public:
|
|
ResetClientTargetsEvent(bool clientTargetsOnly = false) { mClientTargetsOnly = clientTargetsOnly; }
|
|
void pack(NetConnection *con , BitStream * bstream)
|
|
{
|
|
bstream->writeFlag(mClientTargetsOnly);
|
|
if(!mClientTargetsOnly && dynamic_cast<GameConnection*>(con))
|
|
static_cast<GameConnection*>(con)->resetVisibleMasks();
|
|
}
|
|
void write(NetConnection * con, BitStream * bstream) { pack(con, bstream); }
|
|
void unpack(NetConnection *, BitStream * bstream) { mClientTargetsOnly = bstream->readFlag(); }
|
|
void process(NetConnection * con) { mClientTargetsOnly ? gTargetList->targetsCleared() : gTargetManager->resetClient(con); }
|
|
|
|
DECLARE_CONOBJECT(ResetClientTargetsEvent);
|
|
};
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(ResetClientTargetsEvent);
|
|
|
|
void TargetManager::resetClient(NetConnection * con)
|
|
{
|
|
// client?
|
|
if(con->isServerConnection())
|
|
{
|
|
// clear all the target infos
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
{
|
|
// clear objects
|
|
if(bool(mClientTargets[i].targetObject))
|
|
mClientTargets[i].targetObject->targetInfoChanged(0);
|
|
|
|
// clear audio
|
|
if(mClientAudioHandles[i] != NULL_AUDIOHANDLE)
|
|
alxStop(mClientAudioHandles[i]);
|
|
mClientAudioHandles[i] = NULL_AUDIOHANDLE;
|
|
|
|
mClientTargets[i].clear();
|
|
}
|
|
|
|
// notify objects that targets have been cleared
|
|
notifyTargetsCleared();
|
|
}
|
|
else
|
|
con->postNetEvent( new ResetClientTargetsEvent(false) );
|
|
}
|
|
|
|
void TargetManager::reset()
|
|
{
|
|
// notify the clients to clear their targets
|
|
for(NetConnection * con = NetConnection::getConnectionList(); con; con = con->getNext())
|
|
{
|
|
if(con->isServerConnection())
|
|
continue;
|
|
|
|
if (dynamic_cast<GameConnection*>(con) && static_cast<GameConnection*>(con)->isAIControlled())
|
|
continue;
|
|
|
|
resetClient(con);
|
|
}
|
|
// clear objects
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
if(bool(mTargets[i].targetObject))
|
|
mTargets[i].targetObject->targetInfoChanged(0);
|
|
|
|
// reset all the targetmanager info
|
|
clear();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
TargetInfo *TargetManager::getClientTarget(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return mClientTargets + target;
|
|
}
|
|
|
|
TargetInfo *TargetManager::getServerTarget(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return mTargets + target;
|
|
}
|
|
|
|
// TargetObject: ------------------------------------------------------------
|
|
// team targets can have multiple objects associtated with them (though, they
|
|
// will never have the target->obj set)
|
|
void TargetManager::setTargetObject(TargetInfo * target, GameBase *object)
|
|
{
|
|
AssertFatal(target, "TargetManager::setTargetObject: invalid target object");
|
|
|
|
// don't notify current object that it's target has gone bye-bye
|
|
target->targetObject = object;
|
|
}
|
|
|
|
// Name: --------------------------------------------------------------------
|
|
S32 TargetManager::getTargetName(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].nameTag);
|
|
}
|
|
|
|
void TargetManager::setTargetName(S32 target, U32 nameTag)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
if(mTargets[target].nameTag == nameTag)
|
|
return;
|
|
mTargets[target].nameTag = nameTag;
|
|
updateTarget(target, nameTag, -1, -1, -1, -1, -1, -1, -1, -1);
|
|
}
|
|
|
|
// Skin: --------------------------------------------------------------------
|
|
S32 TargetManager::getTargetSkin(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].skinTag);
|
|
}
|
|
|
|
void TargetManager::setTargetSkin(S32 target, U32 skinTag)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
if(mTargets[target].skinTag == skinTag)
|
|
return;
|
|
mTargets[target].skinTag = skinTag;
|
|
updateTarget(target, -1, skinTag, -1, -1, -1, -1, -1, -1, -1);
|
|
}
|
|
|
|
// Voice: --------------------------------------------------------------------
|
|
S32 TargetManager::getTargetVoice(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].voiceTag);
|
|
}
|
|
|
|
void TargetManager::setTargetVoice(S32 target, U32 voiceTag)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
if(mTargets[target].voiceTag == voiceTag)
|
|
return;
|
|
mTargets[target].voiceTag = voiceTag;
|
|
updateTarget(target, -1, -1, voiceTag, -1, -1, -1, -1, -1, -1);
|
|
}
|
|
|
|
// Type: --------------------------------------------------------------------
|
|
S32 TargetManager::getTargetType(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].typeTag);
|
|
}
|
|
|
|
void TargetManager::setTargetType(S32 target, U32 typeTag)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
if(mTargets[target].typeTag == typeTag)
|
|
return;
|
|
mTargets[target].typeTag = typeTag;
|
|
updateTarget(target, -1, -1, -1, typeTag, -1, -1, -1, -1, -1);
|
|
}
|
|
|
|
// SensorGroup: -------------------------------------------------------------
|
|
S32 TargetManager::getTargetSensorGroup(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].sensorGroup);
|
|
}
|
|
|
|
void TargetManager::setTargetSensorGroup(S32 target, U32 sensorGroup)
|
|
{
|
|
AssertFatal(target >= 32 && target < MaxTargets, "Invalid target id.");
|
|
AssertFatal(sensorGroup < 32, "Invalid sensor group.");
|
|
if(mTargets[target].sensorGroup == sensorGroup)
|
|
return;
|
|
mTargets[target].sensorGroup = sensorGroup;
|
|
|
|
mTargets[target].sensorAlwaysVisMask = mSensorGroupAlwaysVisMask[sensorGroup];
|
|
mTargets[target].sensorNeverVisMask = mSensorGroupNeverVisMask[sensorGroup];
|
|
mTargets[target].sensorFriendlyMask = mSensorGroupFriendlyMask[sensorGroup];
|
|
updateTarget(target, -1, -1, -1, -1, sensorGroup, -1, -1, -1, -1);
|
|
}
|
|
|
|
// voicePitch: --------------------------------------------------------------
|
|
F32 TargetManager::getTargetVoicePitch(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].voicePitch);
|
|
}
|
|
|
|
void TargetManager::setTargetVoicePitch(S32 target, F32 voicePitch)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
if(mTargets[target].voicePitch == voicePitch)
|
|
return;
|
|
if (voicePitch < 0.5f || voicePitch > 2.0f)
|
|
mTargets[target].voicePitch = 1.0f;
|
|
else
|
|
mTargets[target].voicePitch = voicePitch;
|
|
updateTarget(target, -1, -1, -1, -1, -1, -1, -1, voicePitch, -1);
|
|
}
|
|
|
|
// Misc: --------------------------------------------------------------------
|
|
void TargetManager::setTargetRenderMask(S32 target, U32 mask)
|
|
{
|
|
AssertFatal(target >= 32 && target < MaxTargets, "Invalid target id.");
|
|
mTargets[target].renderFlags = mask & ((1 << TargetInfo::NumRenderBits) - 1);
|
|
updateTarget(target, -1, -1, -1, -1, -1, -1, mTargets[target].renderFlags, -1, -1);
|
|
}
|
|
|
|
void TargetManager::setTargetShapeBaseData(S32 target, ShapeBaseData * data)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
mTargets[target].shapeBaseData = data;
|
|
updateTarget(target, -1, -1, -1, -1, -1, data ? data->getId() : 0, -1, -1, -1);
|
|
}
|
|
|
|
// TargetAlwaysVisMask: -----------------------------------------------------
|
|
U32 TargetManager::getTargetAlwaysVisMask(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].sensorAlwaysVisMask);
|
|
}
|
|
|
|
void TargetManager::setTargetAlwaysVisMask(S32 target, U32 mask)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
mTargets[target].sensorAlwaysVisMask = mask;
|
|
}
|
|
|
|
// TargetNeverVisMask: ------------------------------------------------------
|
|
U32 TargetManager::getTargetNeverVisMask(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].sensorNeverVisMask);
|
|
}
|
|
|
|
void TargetManager::setTargetNeverVisMask(S32 target, U32 mask)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
mTargets[target].sensorNeverVisMask = mask;
|
|
}
|
|
|
|
// TargetFriendlyMask: ------------------------------------------------------
|
|
U32 TargetManager::getTargetFriendlyMask(S32 target)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
return(mTargets[target].sensorFriendlyMask);
|
|
}
|
|
|
|
void TargetManager::setTargetFriendlyMask(S32 target, U32 mask)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
mTargets[target].sensorFriendlyMask = mask;
|
|
}
|
|
|
|
// all targets inherit group mask changes
|
|
void TargetManager::updateSensorGroupMask(U32 sensorGroup, U32 mask, U32 maskType)
|
|
{
|
|
for(U32 i = 0; i < TargetFreeMaskSize; i++)
|
|
{
|
|
if(mFreeMask[i] == 0)
|
|
continue;
|
|
|
|
for(U32 j = 0; j < 32; j++)
|
|
{
|
|
if(mFreeMask[i] & (1 << j))
|
|
{
|
|
TargetInfo &targ = mTargets[(i << 5) + j];
|
|
if(targ.sensorGroup == sensorGroup)
|
|
{
|
|
U32 * targMask = &targ.sensorAlwaysVisMask;
|
|
if(maskType == NeverVisMask)
|
|
targMask = &targ.sensorNeverVisMask;
|
|
else if(maskType == FriendlyMask)
|
|
targMask = &targ.sensorFriendlyMask;
|
|
*targMask = mask;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// SensorGroupAlwaysVisMask: ------------------------------------------------
|
|
U32 TargetManager::getSensorGroupAlwaysVisMask(U32 sensorGroup)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::getSensorGroupAlwaysVisMask: invalid sensor group");
|
|
return(mSensorGroupAlwaysVisMask[sensorGroup]);
|
|
}
|
|
|
|
void TargetManager::setSensorGroupAlwaysVisMask(U32 sensorGroup, U32 mask)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::setSensorGroupAlwaysVisMask: invalid sensor group");
|
|
updateSensorGroupMask(sensorGroup, mask, AlwaysVisMask);
|
|
mSensorGroupAlwaysVisMask[sensorGroup] = mask;
|
|
}
|
|
|
|
// SensorGroupNeverVisMask: -------------------------------------------------
|
|
U32 TargetManager::getSensorGroupNeverVisMask(U32 sensorGroup)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::getSensorGroupNeverVisMask: invalid sensor group");
|
|
return(mSensorGroupNeverVisMask[sensorGroup]);
|
|
}
|
|
|
|
void TargetManager::setSensorGroupNeverVisMask(U32 sensorGroup, U32 mask)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::setSensorGroupNeverVisMask: invalid sensor group");
|
|
updateSensorGroupMask(sensorGroup, mask, NeverVisMask);
|
|
mSensorGroupNeverVisMask[sensorGroup] = mask;
|
|
}
|
|
|
|
// SensorGroupFriendlyMask: -------------------------------------------------
|
|
U32 TargetManager::getSensorGroupFriendlyMask(U32 sensorGroup)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::getSensorGroupFriendlyMask: invalid sensor group");
|
|
return(mSensorGroupFriendlyMask[sensorGroup]);
|
|
}
|
|
|
|
void TargetManager::setSensorGroupFriendlyMask(U32 sensorGroup, U32 mask)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::setSensorGroupFriendlyMask: invalid sensor group");
|
|
updateSensorGroupMask(sensorGroup, mask, FriendlyMask);
|
|
mSensorGroupFriendlyMask[sensorGroup] = mask;
|
|
}
|
|
|
|
// Listen state: ------------------------------------------------------------
|
|
U32 TargetManager::getSensorGroupListenMask(U32 sensorGroup)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::getSensorGroupListenMask: invalid sensor group");
|
|
return(mSensorGroupListenMask[sensorGroup]);
|
|
}
|
|
|
|
void TargetManager::setSensorGroupListenMask(U32 sensorGroup, U32 mask)
|
|
{
|
|
AssertFatal(sensorGroup < 32, "TargetManager::setSensorGroupListenMask: invalid sensor group");
|
|
mSensorGroupListenMask[sensorGroup] = mask;
|
|
}
|
|
|
|
// IsTarget(...): -----------------------------------------------------------
|
|
bool TargetManager::isTargetFriendly(S32 target, U32 sensorGroup)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
AssertFatal(sensorGroup < 32, "Invalid sensor group");
|
|
return((mTargets[target].sensorFriendlyMask & (1 << sensorGroup)) != 0);
|
|
}
|
|
|
|
bool TargetManager::isTargetVisible(S32 target, U32 sensorGroup)
|
|
{
|
|
AssertFatal(target >= 0 && target < MaxTargets, "Invalid target id.");
|
|
AssertFatal(sensorGroup < 32, "Invalid sensor group");
|
|
|
|
U32 groupMask = (1 << sensorGroup);
|
|
|
|
if(mTargets[target].sensorNeverVisMask & groupMask)
|
|
return(false);
|
|
|
|
if(mTargets[target].sensorAlwaysVisMask & groupMask)
|
|
return(true);
|
|
|
|
return((mTargets[target].sensorVisMask & groupMask) != 0);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TargetManager console access:
|
|
//---------------------------------------------------------------------------
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Helpers...
|
|
static S32 getValidTarget(S32 target, const char * funcStr, bool excludeTeam)
|
|
{
|
|
if((target < 0) || (target >= TargetManager::MaxTargets))
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::%s: invalid target index [%d]", funcStr, target);
|
|
return(-1);
|
|
}
|
|
|
|
if(excludeTeam && target < 32)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::%s: cannot change attribute on team target [%d]", funcStr, target);
|
|
return(-1);
|
|
}
|
|
|
|
TargetInfo * targ = gTargetManager->getServerTarget(target);
|
|
if(!targ->allocated && (target >= 32))
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::%s: cannot change attribute on unallocated target [%d]", funcStr, target);
|
|
return(-1);
|
|
}
|
|
|
|
return(target);
|
|
}
|
|
|
|
static S32 getValidSensorGroup(S32 group, const char * funcStr)
|
|
{
|
|
if(group < 0 || group >= 32)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::%s: invalid sensor group [%d]", funcStr, group);
|
|
return(-1);
|
|
}
|
|
return(group);
|
|
}
|
|
|
|
static F32 getValidVoicePitch(F32 pitch, const char * funcStr)
|
|
{
|
|
if(pitch < 0.5f || pitch > 2.0f)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::%s: Invalid pitch [%d]", funcStr, pitch);
|
|
return (1.0f);
|
|
}
|
|
else
|
|
return(pitch);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
static void cReset(SimObject *, S32, const char **)
|
|
{
|
|
gTargetManager->reset();
|
|
}
|
|
|
|
static void cResetClientTargets(SimObject *, S32, const char ** argv)
|
|
{
|
|
NetConnection * client = dynamic_cast<NetConnection*>(Sim::findObject(dAtoi(argv[1])));
|
|
if(client)
|
|
{
|
|
if(dynamic_cast<GameConnection*>(client) && static_cast<GameConnection*>(client)->isAIControlled())
|
|
return;
|
|
|
|
client->postNetEvent( new ResetClientTargetsEvent(dAtob(argv[2])) );
|
|
}
|
|
}
|
|
|
|
static void cSendTargetsToClient(SimObject *, S32, const char ** argv)
|
|
{
|
|
NetConnection * client = dynamic_cast<NetConnection*>(Sim::findObject(dAtoi(argv[1])));
|
|
if(client)
|
|
gTargetManager->newClient(client);
|
|
}
|
|
|
|
static S32 cAllocTarget(SimObject *, S32 argc, const char **argv)
|
|
{
|
|
U32 nameTag = 0;
|
|
U32 skinTag = 0;
|
|
U32 voiceTag = 0;
|
|
U32 typeTag = 0;
|
|
U32 prefSkinTag = 0;
|
|
|
|
// check if tagprefix has already been removed
|
|
if(argv[1][0] == StringTagPrefixByte)
|
|
nameTag = dAtoi(argv[1] + 1);
|
|
else if(argv[1][0])
|
|
nameTag = dAtoi(argv[1]);
|
|
if(argv[2][0] == StringTagPrefixByte)
|
|
skinTag = dAtoi(argv[2] + 1);
|
|
else if(argv[2][0])
|
|
skinTag = dAtoi(argv[2]);
|
|
if(argv[3][0] == StringTagPrefixByte)
|
|
voiceTag = dAtoi(argv[3] + 1);
|
|
else if(argv[3][0])
|
|
voiceTag = dAtoi(argv[3]);
|
|
if(argv[4][0] == StringTagPrefixByte)
|
|
typeTag = dAtoi(argv[4] + 1);
|
|
else if(argv[4][0])
|
|
typeTag = dAtoi(argv[4]);
|
|
U32 sensorGroup = dAtoi(argv[5]);
|
|
U32 dataBlockId = dAtoi(argv[6]);
|
|
F32 voicePitch = dAtof(argv[7]);
|
|
if (voicePitch < 0.5 || voicePitch > 2.0)
|
|
voicePitch = 1.0;
|
|
if(argc == 9)
|
|
{
|
|
if(argv[8][0] == StringTagPrefixByte)
|
|
prefSkinTag = dAtoi(argv[8] + 1);
|
|
else if(argv[8][0])
|
|
prefSkinTag = dAtoi(argv[8]);
|
|
}
|
|
return gTargetManager->allocTarget(nameTag, skinTag, voiceTag, typeTag, sensorGroup, dataBlockId, voicePitch, prefSkinTag);
|
|
}
|
|
|
|
static void cFreeTarget(SimObject *, S32, const char **argv)
|
|
{
|
|
if(!gTargetManager)
|
|
return;
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cFreeTarget", true);
|
|
if(target == -1)
|
|
return;
|
|
gTargetManager->freeTarget(target);
|
|
}
|
|
|
|
// Name: --------------------------------------------------------------------
|
|
// - queries the server's game name for this target
|
|
static const char * cGetTargetGameName(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetGameName", false);
|
|
if(target == -1)
|
|
return("");
|
|
|
|
char * ret = Con::getReturnBuffer(128);
|
|
if(!gTargetManager->getGameName(target, ret, 128, true))
|
|
return("");
|
|
|
|
return(ret);
|
|
}
|
|
|
|
static S32 cGetTargetName(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetName", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetName(target));
|
|
}
|
|
|
|
static void cSetTargetName(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetName", false);
|
|
if(target == -1)
|
|
return;
|
|
if ( argv[2][0] == StringTagPrefixByte )
|
|
gTargetManager->setTargetName(target, dAtoi(argv[2] + 1));
|
|
else
|
|
gTargetManager->setTargetName(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// Skin: --------------------------------------------------------------------
|
|
static S32 cGetTargetSkin(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetSkin", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetSkin(target));
|
|
}
|
|
|
|
static void cSetTargetSkin(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetSkin", false);
|
|
if(target == -1)
|
|
return;
|
|
if ( argv[2][0] == StringTagPrefixByte )
|
|
gTargetManager->setTargetSkin(target, dAtoi(argv[2] + 1));
|
|
else
|
|
gTargetManager->setTargetSkin(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// Voice: -------------------------------------------------------------------
|
|
static S32 cGetTargetVoice(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetVoice", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetVoice(target));
|
|
}
|
|
|
|
static void cSetTargetVoice(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetVoice", false);
|
|
if(target == -1)
|
|
return;
|
|
if ( argv[2][0] == StringTagPrefixByte )
|
|
gTargetManager->setTargetVoice(target, dAtoi(argv[2] + 1));
|
|
else
|
|
gTargetManager->setTargetVoice(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// Type: --------------------------------------------------------------------
|
|
static S32 cGetTargetType(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetType", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetType(target));
|
|
}
|
|
|
|
static void cSetTargetType(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetType", false);
|
|
if(target == -1)
|
|
return;
|
|
if ( argv[2][0] == StringTagPrefixByte )
|
|
gTargetManager->setTargetType(target, dAtoi(argv[2] + 1));
|
|
else
|
|
gTargetManager->setTargetType(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// SensorGroup: -------------------------------------------------------------
|
|
static S32 cGetTargetSensorGroup(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetSensorGroup", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetSensorGroup(target));
|
|
}
|
|
|
|
static void cSetTargetSensorGroup(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetSensorGroup", true);
|
|
if(target == -1)
|
|
return;
|
|
S32 group = getValidSensorGroup(dAtoi(argv[2]), "cSetTargetSensorGroup");
|
|
if(group == -1)
|
|
return;
|
|
gTargetManager->setTargetSensorGroup(target, group);
|
|
}
|
|
|
|
// VoicePitch: -------------------------------------------------------------
|
|
static F32 cGetTargetVoicePitch(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetVoicePitch", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
return(gTargetManager->getTargetVoicePitch(target));
|
|
}
|
|
|
|
static void cSetTargetVoicePitch(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetVoicePitch", true);
|
|
if(target == -1)
|
|
return;
|
|
F32 pitch = getValidVoicePitch(dAtof(argv[2]), "cSetTargetVoicePitch");
|
|
gTargetManager->setTargetVoicePitch(target, pitch);
|
|
}
|
|
|
|
// SensorGroupCount: --------------------------------------------------------
|
|
static S32 cGetSensorGroupCount(SimObject *, S32, const char **)
|
|
{
|
|
return(gTargetManager->getSensorGroupCount());
|
|
}
|
|
|
|
static void cSetSensorGroupCount(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 groupCount = dAtoi(argv[1]);
|
|
if(groupCount < 0 || groupCount > 32)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "TargetManager::cSetSensorGroupCount: invalid group count [%d]", groupCount);
|
|
return;
|
|
}
|
|
gTargetManager->setSensorGroupCount(groupCount);
|
|
}
|
|
|
|
// TargetAlwaysVisMask: -----------------------------------------------------
|
|
static S32 cGetTargetAlwaysVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetAlwaysVisMask", false);
|
|
if(target == -1)
|
|
return(0);
|
|
return(gTargetManager->getTargetAlwaysVisMask(target));
|
|
}
|
|
|
|
static void cSetTargetAlwaysVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetAlwaysVisMask", false);
|
|
if(target == -1)
|
|
return;
|
|
gTargetManager->setTargetAlwaysVisMask(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
|
|
// TargetNeverVisMask: ------------------------------------------------------
|
|
static S32 cGetTargetNeverVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetNeverVisMask", false);
|
|
if(target == -1)
|
|
return(0);
|
|
return(gTargetManager->getTargetNeverVisMask(target));
|
|
}
|
|
|
|
static void cSetTargetNeverVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetNeverVisMask", false);
|
|
if(target == -1)
|
|
return;
|
|
gTargetManager->setTargetNeverVisMask(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// TargetFriendlyMask: ------------------------------------------------------
|
|
static S32 cGetTargetFriendlyMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetFriendlyMask", false);
|
|
if(target == -1)
|
|
return(0);
|
|
return(gTargetManager->getTargetFriendlyMask(target));
|
|
}
|
|
|
|
static void cSetTargetFriendlyMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetFriendlyMask", false);
|
|
if(target == -1)
|
|
return;
|
|
gTargetManager->setTargetFriendlyMask(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// SensorGroupAlwaysVisMask: ------------------------------------------------
|
|
static S32 cGetSensorGroupAlwaysVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cGetSensorGroupAlwaysVisMask");
|
|
if(group == -1)
|
|
return(0);
|
|
return(gTargetManager->getSensorGroupAlwaysVisMask(group));
|
|
}
|
|
|
|
static void cSetSensorGroupAlwaysVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cSetSensorGroupAlwaysVisMask");
|
|
if(group == -1)
|
|
return;
|
|
gTargetManager->setSensorGroupAlwaysVisMask(group, dAtoi(argv[2]));
|
|
}
|
|
|
|
// SensorGroupNeverVisMask: -------------------------------------------------
|
|
static S32 cGetSensorGroupNeverVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cGetSensorGroupNeverVisMask");
|
|
if(group == -1)
|
|
return(0);
|
|
return(gTargetManager->getSensorGroupNeverVisMask(group));
|
|
}
|
|
|
|
static void cSetSensorGroupNeverVisMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cSetSensorGroupNeverVisMask");
|
|
if(group == -1)
|
|
return;
|
|
gTargetManager->setSensorGroupNeverVisMask(group, dAtoi(argv[2]));
|
|
}
|
|
|
|
// SensorGroupFriendlyMask: -------------------------------------------------
|
|
static S32 cGetSensorGroupFriendlyMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cGetSensorGroupFriendlyMask");
|
|
if(group == -1)
|
|
return(0);
|
|
return(gTargetManager->getSensorGroupFriendlyMask(group));
|
|
}
|
|
|
|
static void cSetSensorGroupFriendlyMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cSetSensorGroupFriendlyMask");
|
|
if(group == -1)
|
|
return;
|
|
gTargetManager->setSensorGroupFriendlyMask(group, dAtoi(argv[2]));
|
|
}
|
|
|
|
// SensorGroupListenMask: ---------------------------------------------------
|
|
static S32 cGetSensorGroupListenMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cGetSensorGroupListenMask");
|
|
if(group == -1)
|
|
return(0);
|
|
return(gTargetManager->getSensorGroupListenMask(group));
|
|
}
|
|
|
|
static void cSetSensorGroupListenMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 group = getValidSensorGroup(dAtoi(argv[1]), "cSetSensorGroupListenMask");
|
|
if(group == -1)
|
|
return;
|
|
gTargetManager->setSensorGroupListenMask(group, dAtoi(argv[2]));
|
|
}
|
|
|
|
// IsTarget(...): -----------------------------------------------------------
|
|
static bool cIsTargetFriendly(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cIsTargetFriendly", false);
|
|
if(target == -1)
|
|
return(false);
|
|
S32 group = getValidSensorGroup(dAtoi(argv[2]), "cIsTargetFriendly");
|
|
if(group == -1)
|
|
return(false);
|
|
return(gTargetManager->isTargetFriendly(target, group));
|
|
}
|
|
|
|
static bool cIsTargetVisible(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cIsTargetVisible", false);
|
|
if(target == -1)
|
|
return(false);
|
|
S32 group = getValidSensorGroup(dAtoi(argv[2]), "cIsTargetVisible");
|
|
if(group == -1)
|
|
return(false);
|
|
return(gTargetManager->isTargetVisible(target, group));
|
|
}
|
|
|
|
// Others: ------------------------------------------------------------------
|
|
static void cSetTargetSensorData(SimObject *, S32, const char **argv)
|
|
{
|
|
S32 target = dAtoi(argv[1]);
|
|
if(target < 0 || target >= TargetManager::MaxTargets)
|
|
return;
|
|
|
|
SensorData * data = dynamic_cast<SensorData*>(Sim::findObject(argv[2]));
|
|
TargetInfo *targ = gTargetManager->getServerTarget(target);
|
|
targ->sensorData = data;
|
|
}
|
|
|
|
static S32 cGetTargetSensorData(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = dAtoi(argv[1]);
|
|
if(target < 0 || target >= TargetManager::MaxTargets)
|
|
return(-1);
|
|
|
|
TargetInfo * targ = gTargetManager->getServerTarget(target);
|
|
if(bool(targ->sensorData))
|
|
return(targ->sensorData->getId());
|
|
return(-1);
|
|
}
|
|
|
|
static const char * cGetTargetObject(SimObject *, S32, const char **argv)
|
|
{
|
|
char * buf = Con::getReturnBuffer(12);
|
|
S32 target = dAtoi(argv[1]);
|
|
if(target < 0 || target >= TargetManager::MaxTargets || !bool(gTargetManager->mTargets[target].targetObject))
|
|
dStrcpy(buf, "-1");
|
|
else
|
|
dSprintf(buf, 12, "%d", gTargetManager->mTargets[target].targetObject->getId());
|
|
return(buf);
|
|
}
|
|
|
|
// Color info: ------------------------------------------------------------
|
|
static const char * cGetSensorGroupColor(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 sensorGroup = getValidSensorGroup(dAtoi(argv[1]), "cGetSensorGroupColor");
|
|
if(sensorGroup == -1)
|
|
return("");
|
|
|
|
S32 colorGroup = getValidSensorGroup(dAtoi(argv[2]), "cGetSensorGroupColor");
|
|
if(colorGroup == -1)
|
|
return("");
|
|
|
|
char * buf = Con::getReturnBuffer(100);
|
|
|
|
ColorI col = gTargetManager->getSensorGroupColor(sensorGroup, colorGroup);
|
|
dSprintf(buf, 100, "%d %d %d %d", col.red, col.green, col.blue, col.alpha);
|
|
return(buf);
|
|
}
|
|
|
|
static void cSetSensorGroupColor(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 sensorGroup = getValidSensorGroup(dAtoi(argv[1]), "cSetSensorGroupColor");
|
|
if(sensorGroup == -1)
|
|
return;
|
|
|
|
U32 r,g,b,a;
|
|
dSscanf(argv[3], "%d %d %d %d", &r, &g, &b, &a);
|
|
|
|
ColorI col(r,g,b,a);
|
|
gTargetManager->setSensorGroupColor(sensorGroup, dAtoi(argv[2]), col);
|
|
}
|
|
|
|
// DataBlock info: ----------------------------------------------------------
|
|
static S32 cGetTargetDataBlock(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetDataBlock", true);
|
|
if(target == -1)
|
|
return(-1);
|
|
|
|
TargetInfo * targ = gTargetManager->getServerTarget(target);
|
|
if(!bool(targ->shapeBaseData))
|
|
return(0);
|
|
|
|
return(targ->shapeBaseData->getId());
|
|
}
|
|
|
|
static void cSetTargetDataBlock(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetDataBlock", true);
|
|
if(target == -1)
|
|
return;
|
|
|
|
ShapeBaseData * data = dynamic_cast<ShapeBaseData*>(Sim::findObject(dAtoi(argv[2])));
|
|
gTargetManager->setTargetShapeBaseData(target, data);
|
|
}
|
|
|
|
// TargetRender: ------------------------------------------------------------
|
|
static S32 cGetTargetRenderMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cGetTargetRender", false);
|
|
if(target == -1)
|
|
return(-1);
|
|
|
|
return(gTargetManager->getServerTarget(target)->renderFlags);
|
|
}
|
|
|
|
static void cSetTargetRenderMask(SimObject *, S32, const char ** argv)
|
|
{
|
|
S32 target = getValidTarget(dAtoi(argv[1]), "cSetTargetRender", false);
|
|
if(target == -1)
|
|
return;
|
|
|
|
gTargetManager->setTargetRenderMask(target, dAtoi(argv[2]));
|
|
}
|
|
|
|
// Audio: -------------------------------------------------------------------
|
|
static void cPlayTargetAudio(SimObject *, S32 argc, const char ** argv)
|
|
{
|
|
AudioDescription * desc = dynamic_cast<AudioDescription*>(Sim::findObject(argv[3]));
|
|
if(!desc || (desc->getId() < DataBlockObjectIdFirst) || (desc->getId() > DataBlockObjectIdLast))
|
|
{
|
|
Con::warnf("Invalid audio description '%s'.", argv[5]);
|
|
return;
|
|
}
|
|
|
|
bool update;
|
|
if(argc < 5)
|
|
update = false;
|
|
else
|
|
update = dAtob(argv[4]);
|
|
|
|
S32 fileTag = (argv[2][0] == StringTagPrefixByte) ? dAtoi(argv[2] + 1) : dAtoi(argv[2]);
|
|
if(!gTargetManager->playTargetAudio(dAtoi(argv[1]), fileTag, desc, update))
|
|
Con::warnf("Failed to send target audio event to clients");
|
|
}
|
|
|
|
void TargetManager::create()
|
|
{
|
|
gTargetManager = new TargetManager;
|
|
gTargetList = new HUDTargetList;
|
|
|
|
Con::addCommand("resetTargets", cReset, "resetTargets()", 1, 1);
|
|
Con::addCommand("resetClientTargets", cResetClientTargets, "resetClientTargets(connection, tasksOnly)", 3, 3);
|
|
|
|
Con::addCommand("sendTargetsToClient", cSendTargetsToClient, "sendTargetsToClient(connection)", 2, 2);
|
|
Con::addCommand("allocTarget", cAllocTarget, "allocTarget(nameTag, skinTag, voiceTag, typeTag, sensorGroup, dataBlockId, voicePitch, [prefskin])", 8, 9);
|
|
Con::addCommand("freeTarget", cFreeTarget, "freeTarget(targetId)", 2, 2);
|
|
|
|
Con::addCommand("getTargetGameName", cGetTargetGameName, "getTargetGameName(targetId)", 2, 2);
|
|
Con::addCommand("getTargetName", cGetTargetName, "getTargetName(targetId)", 2, 2);
|
|
Con::addCommand("setTargetName", cSetTargetName, "setTargetName(targetId, nameTag)", 3, 3);
|
|
Con::addCommand("getTargetSkin", cGetTargetSkin, "getTargetSkin(targetId)", 2, 2);
|
|
Con::addCommand("setTargetSkin", cSetTargetSkin, "setTargetSkin(targetId, skinTag)", 3, 3);
|
|
Con::addCommand("getTargetVoice", cGetTargetVoice, "getTargetVoice(targetId)", 2, 2);
|
|
Con::addCommand("setTargetVoice", cSetTargetVoice, "setTargetVoice(targetId, voiceTag)", 3, 3);
|
|
Con::addCommand("getTargetVoicePitch", cGetTargetVoicePitch, "getTargetVoicePitch(targetId)", 2, 2);
|
|
Con::addCommand("setTargetVoicePitch", cSetTargetVoicePitch, "setTargetVoice(targetId, voicePitch)", 3, 3);
|
|
Con::addCommand("getTargetType", cGetTargetType, "getTargetType(targetId)", 2, 2);
|
|
Con::addCommand("setTargetType", cSetTargetType, "setTargetType(targetId, typeTag)", 3, 3);
|
|
Con::addCommand("getTargetSensorGroup", cGetTargetSensorGroup, "getTargetSensorGroup(targetId)", 2, 2);
|
|
Con::addCommand("setTargetSensorGroup", cSetTargetSensorGroup, "setTargetSensorGroup(targetId, sensorGroup)", 3, 3);
|
|
|
|
Con::addCommand("getTargetAlwaysVisMask", cGetTargetAlwaysVisMask, "getTargetAlwaysVisMask(target)", 2, 2);
|
|
Con::addCommand("setTargetAlwaysVisMask", cSetTargetAlwaysVisMask, "setTargetAlwaysVisMask(target, mask)", 3, 3);
|
|
Con::addCommand("getTargetNeverVisMask", cGetTargetNeverVisMask, "getTargetNeverVisMask(target)", 2, 2);
|
|
Con::addCommand("setTargetNeverVisMask", cSetTargetNeverVisMask, "setTargetNeverVisMask(target, mask)", 3, 3);
|
|
Con::addCommand("getTargetFriendlyMask", cGetTargetFriendlyMask, "getTargetFriendlyMask(target)", 2, 2);
|
|
Con::addCommand("setTargetFriendlyMask", cSetTargetFriendlyMask, "setTargetFriendlyMask(target, mask)", 3, 3);
|
|
|
|
Con::addCommand("getSensorGroupAlwaysVisMask", cGetSensorGroupAlwaysVisMask, "getSensorGroupAlwaysVisMask(sensorGroup)", 2, 2);
|
|
Con::addCommand("setSensorGroupAlwaysVisMask", cSetSensorGroupAlwaysVisMask, "setSensorGroupAlwaysVisMask(sensorGroup, mask)", 3, 3);
|
|
Con::addCommand("getSensorGroupNeverVisMask", cGetSensorGroupNeverVisMask, "getSensorGroupNeverVisMask(sensorGroup)", 2, 2);
|
|
Con::addCommand("setSensorGroupNeverVisMask", cSetSensorGroupNeverVisMask, "setSensorGroupNeverVisMask(sensorGroup, mask)", 3, 3);
|
|
Con::addCommand("getSensorGroupFriendlyMask", cGetSensorGroupFriendlyMask, "getSensorGroupFriendlyMask(sensorGroup)", 2, 2);
|
|
Con::addCommand("setSensorGroupFriendlyMask", cSetSensorGroupFriendlyMask, "setSensorGroupFriendlyMask(sensorGroup, mask)", 3, 3);
|
|
|
|
Con::addCommand("getSensorGroupListenMask", cGetSensorGroupListenMask, "getSensorGroupListenMask(sensorGroup)", 2, 2);
|
|
Con::addCommand("setSensorGroupListenMask", cSetSensorGroupListenMask, "setSensorGroupListenMask(sensorGroup, mask)", 3, 3);
|
|
|
|
Con::addCommand("isTargetFriendly", cIsTargetFriendly, "isTargetFriendly(target, sensorGroup)", 3, 3);
|
|
Con::addCommand("isTargetVisible", cIsTargetVisible, "isTargetVisible(target, sensorGroup)", 3, 3);
|
|
|
|
Con::addCommand("getSensorGroupCount", cGetSensorGroupCount, "getSensorGroupCount()", 1, 1);
|
|
Con::addCommand("setSensorGroupCount", cSetSensorGroupCount, "setSensorGroupCount(count)", 2, 2);
|
|
|
|
Con::addCommand("setTargetSensorData", cSetTargetSensorData, "setTargetSensorData(targetId, sensorData)", 3, 3);
|
|
Con::addCommand("getTargetSensorData", cGetTargetSensorData, "getTargetSensorData(targetId)", 2, 2);
|
|
Con::addCommand("getTargetObject", cGetTargetObject, "getTargetObject(targetId)", 2, 2);
|
|
|
|
Con::addCommand("getSensorGroupColor", cGetSensorGroupColor, "getSensorGroupColor(sensorGroup, colorGroup)", 3, 3);
|
|
Con::addCommand("setSensorGroupColor", cSetSensorGroupColor, "setSensorGroupColor(sensorGroup, groupMask, color)", 4, 4);
|
|
|
|
Con::addCommand("setTargetDataBlock", cSetTargetDataBlock, "setTargetDataBlock(targetId, dataBlockId)", 3, 3);
|
|
Con::addCommand("getTargetDataBlock", cGetTargetDataBlock, "getTargetDataBlock(targetId)", 2, 2);
|
|
|
|
Con::addCommand("getTargetRenderMask", cGetTargetRenderMask, "getTargetRender(targetId)", 2, 2);
|
|
Con::addCommand("setTargetRenderMask", cSetTargetRenderMask, "setTargetRender(targetId, mask)", 3, 3);
|
|
|
|
Con::setIntVariable("$TargetInfo::HudRenderStart", TargetInfo::HudRenderStart);
|
|
Con::setIntVariable("$TargetInfo::NumHudRenderImages", TargetInfo::NumHudRenderImages);
|
|
Con::setIntVariable("$TargetInfo::CommanderListRender", TargetInfo::CommanderListRender);
|
|
|
|
Con::addCommand("playTargetAudio", cPlayTargetAudio, "playTargetAudio(target, fileTag, desc, update)", 5, 5);
|
|
}
|
|
|
|
void TargetManager::destroy()
|
|
{
|
|
delete gTargetList;
|
|
gTargetList = 0;
|
|
|
|
delete gTargetManager;
|
|
gTargetManager = 0;
|
|
}
|
|
|
|
void TargetManager::writeDemoStartBlock(ResizeBitStream *stream, GameConnection *)
|
|
{
|
|
TargetInfo *targ = mClientTargets;
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
{
|
|
if(stream->writeFlag(targ->allocated))
|
|
{
|
|
if(stream->writeFlag(targ->sNameTag))
|
|
stream->write(targ->sNameTag);
|
|
if(stream->writeFlag(targ->sSkinTag))
|
|
stream->write(targ->sSkinTag);
|
|
if(stream->writeFlag(targ->sSkinPrefTag))
|
|
stream->write(targ->sSkinPrefTag);
|
|
if(stream->writeFlag(targ->sVoiceTag))
|
|
stream->write(targ->sVoiceTag);
|
|
if(stream->writeFlag(targ->sTypeTag))
|
|
stream->write(targ->sTypeTag);
|
|
stream->writeInt(targ->sensorGroup, 5);
|
|
stream->writeInt(targ->renderFlags, TargetInfo::NumRenderBits);
|
|
if(i >= 32)
|
|
{
|
|
if(stream->writeFlag(targ->shapeBaseData))
|
|
stream->writeRangedU32(targ->shapeBaseData->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
}
|
|
//convert the voice pitch from range [0.5, 2.0] to [0.0, 1.0]
|
|
F32 packFloat;
|
|
if (targ->voicePitch < 0.5f || targ->voicePitch > 2.0f)
|
|
packFloat = (1.0f - 0.5f) / 1.5f;
|
|
else
|
|
packFloat = (targ->voicePitch - 0.5f) / 1.5f;
|
|
stream->writeFloat(packFloat, 7);
|
|
stream->validate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void TargetManager::readDemoStartBlock(BitStream *stream, GameConnection *conn)
|
|
{
|
|
TargetInfo *targ = mClientTargets;
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
{
|
|
if(stream->readFlag())
|
|
{
|
|
if(stream->readFlag())
|
|
{
|
|
stream->read(&targ->sNameTag);
|
|
targ->nameTag = conn->translateRemoteStringId(targ->sNameTag);
|
|
}
|
|
if(stream->readFlag())
|
|
{
|
|
stream->read(&targ->sSkinTag);
|
|
targ->skinTag = conn->translateRemoteStringId(targ->sSkinTag);
|
|
}
|
|
if(stream->readFlag())
|
|
{
|
|
stream->read(&targ->sVoiceTag);
|
|
targ->voiceTag = conn->translateRemoteStringId(targ->sVoiceTag);
|
|
}
|
|
if(stream->readFlag())
|
|
{
|
|
stream->read(&targ->sTypeTag);
|
|
targ->typeTag = conn->translateRemoteStringId(targ->sTypeTag);
|
|
}
|
|
targ->sensorGroup = stream->readInt(5);
|
|
|
|
targ->renderFlags = stream->readInt(TargetInfo::NumRenderBits);
|
|
targ->allocated = true;
|
|
if(i >= 32)
|
|
{
|
|
if(stream->readFlag())
|
|
{
|
|
U32 id;
|
|
id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
|
|
targ->shapeBaseData = dynamic_cast<ShapeBaseData*>(Sim::findObject(id));
|
|
}
|
|
gTargetManager->notifyTargetAdded(i);
|
|
if(bool(targ->targetObject))
|
|
targ->targetObject->targetInfoChanged(targ);
|
|
}
|
|
|
|
//convert the voice pitch from range [0.0, 1.0] back to [0.5, 2.0]
|
|
F32 unpackFloat = stream->readFloat(7);
|
|
targ->voicePitch = (unpackFloat * 1.5) + 0.5f;
|
|
if (targ->voicePitch < 0.5f)
|
|
targ->voicePitch = 0.5f;
|
|
else if (targ->voicePitch > 2.0f)
|
|
targ->voicePitch = 2.0f;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// HUDTargetListNotify: client target notification system, passes handles
|
|
// to the actual entries
|
|
//----------------------------------------------------------------------------
|
|
HUDTargetListNotify::HUDTargetListNotify()
|
|
{
|
|
AssertFatal(gTargetList, "HUDTargetListNotify:: No target list present");
|
|
gTargetList->addNotify(this);
|
|
}
|
|
|
|
HUDTargetListNotify::~HUDTargetListNotify()
|
|
{
|
|
if(gTargetList)
|
|
gTargetList->removeNotify(this);
|
|
}
|
|
|
|
void HUDTargetList::addNotify(HUDTargetListNotify * notify)
|
|
{
|
|
for(S32 i = hudNotifyList.size() - 1; i >= 0; i--)
|
|
if(hudNotifyList[i] == notify)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "HUDTargetList::addNotify: object already being notified!");
|
|
return;
|
|
}
|
|
hudNotifyList.push_back(notify);
|
|
}
|
|
|
|
void HUDTargetList::removeNotify(HUDTargetListNotify * notify)
|
|
{
|
|
for(S32 i = hudNotifyList.size() - 1; i >= 0; i--)
|
|
if(hudNotifyList[i] == notify)
|
|
{
|
|
hudNotifyList.erase(i);
|
|
return;
|
|
}
|
|
Con::errorf(ConsoleLogEntry::General, "HUDTargetList::removeNotify: object not found in notify list!");
|
|
}
|
|
|
|
void HUDTargetList::notifyTargetAdded(U32 target)
|
|
{
|
|
for(S32 i = hudNotifyList.size() - 1; i >= 0; i--)
|
|
hudNotifyList[i]->hudTargetAdded(target);
|
|
}
|
|
|
|
void HUDTargetList::notifyTargetRemoved(U32 target)
|
|
{
|
|
for(S32 i = hudNotifyList.size() - 1; i >= 0; i--)
|
|
hudNotifyList[i]->hudTargetRemoved(target);
|
|
}
|
|
|
|
void HUDTargetList::notifyTargetsCleared()
|
|
{
|
|
for(S32 i = hudNotifyList.size() - 1; i >= 0; i--)
|
|
hudNotifyList[i]->hudTargetsCleared();
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// HUDTargetList:
|
|
//----------------------------------------------------------------------------
|
|
U32 HUDTargetList::smTargetTimeout = HUDTargetList::DefaultTimeout;
|
|
|
|
//----------------------------------------------------------------------------
|
|
HUDTargetList::HUDTargetList()
|
|
{
|
|
VECTOR_SET_ASSOCIATION(hudNotifyList);
|
|
|
|
mCount = 0;
|
|
|
|
mNumAssignedTasks = 0;
|
|
mNumPotentialTasks = 0;
|
|
mNumWaypoints = 0;
|
|
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
mHandle[i] = FREE_HANDLE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
S32 HUDTargetList::findOldestEntry(S32 type)
|
|
{
|
|
AssertFatal(mCount, "HUDTargetList::findOldestEntry: should not have 0 count");
|
|
|
|
U32 oldTime = 0xffffffff;
|
|
S32 oldest = -1;
|
|
for(U32 i = 0; i < mCount; i++)
|
|
{
|
|
AssertFatal(bool(mList[i].target), "HUDTargetList::findOldestEntry: invalid target");
|
|
if((mList[i].target->mType == type) && (mList[i].doneTime < oldTime))
|
|
{
|
|
oldest = i;
|
|
oldTime = mList[i].doneTime;
|
|
}
|
|
}
|
|
return(oldest);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
S32 HUDTargetList::getAddSlot(ClientTarget * target)
|
|
{
|
|
S32 slot = mCount;
|
|
switch(target->mType)
|
|
{
|
|
case ClientTarget::AssignedTask:
|
|
if(mNumAssignedTasks == MaxAssignedTasks)
|
|
slot = findOldestEntry(ClientTarget::AssignedTask);
|
|
break;
|
|
|
|
case ClientTarget::PotentialTask:
|
|
if(mNumPotentialTasks == MaxPotentialTasks)
|
|
slot = findOldestEntry(ClientTarget::PotentialTask);
|
|
break;
|
|
|
|
case ClientTarget::Waypoint:
|
|
if(mNumWaypoints == MaxWaypoints)
|
|
slot = findOldestEntry(ClientTarget::Waypoint);
|
|
break;
|
|
|
|
default:
|
|
slot = -1;
|
|
break;
|
|
}
|
|
return(slot);
|
|
}
|
|
|
|
S32 HUDTargetList::getFreeHandle()
|
|
{
|
|
for(U32 i = 0; i < MaxTargets; i++)
|
|
if(mHandle[i] == FREE_HANDLE)
|
|
return(i);
|
|
return(MaxTargets);
|
|
}
|
|
|
|
// Hudtarget ids are actually handles which are mapped above TargetManager::MaxTarget so
|
|
// that any target type still has a unique target id
|
|
S32 HUDTargetList::getHandleIndex(S32 handle)
|
|
{
|
|
AssertFatal(handle >= TargetManager::MaxTargets && handle < TargetManager::MaxTargets + MaxTargets, "HUDTargetList::getNotifyEntry: invalid handle");
|
|
return(mHandle[handle - TargetManager::MaxTargets]);
|
|
}
|
|
|
|
bool HUDTargetList::addTarget(ClientTarget * target, bool canTimeout, U32 doneTime)
|
|
{
|
|
S32 slot = getAddSlot(target);
|
|
if(slot == -1)
|
|
return(false);
|
|
|
|
// something there?
|
|
if(slot != mCount)
|
|
{
|
|
AssertFatal(bool(mList[slot].target), "HUDTargetList::addTarget: invalid target in list");
|
|
mList[slot].target->onDie();
|
|
}
|
|
|
|
// notify class' get a handle to this entry
|
|
S32 handle = getFreeHandle();
|
|
AssertFatal(handle != MaxTargets, "HudTargetList::addTarget: failed to get free handle");
|
|
mHandle[handle] = mCount;
|
|
|
|
// always add at end
|
|
mList[mCount].target = target;
|
|
mList[mCount].canTimeout = canTimeout;
|
|
mList[mCount].doneTime = doneTime;
|
|
mList[mCount].handle = handle;
|
|
mCount++;
|
|
|
|
// increment the type count
|
|
if(target->mType == ClientTarget::AssignedTask)
|
|
mNumAssignedTasks++;
|
|
else if(target->mType == ClientTarget::PotentialTask)
|
|
mNumPotentialTasks++;
|
|
else if(target->mType == ClientTarget::Waypoint)
|
|
mNumWaypoints++;
|
|
|
|
// notify using unique target id's
|
|
notifyTargetAdded(handle + TargetManager::MaxTargets);
|
|
return(true);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Sent to remove a specific target type from the target list
|
|
//--------------------------------------------------------------------------
|
|
class RemoveClientTargetTypeEvent : public NetEvent
|
|
{
|
|
private:
|
|
U32 mTargetType;
|
|
|
|
public:
|
|
RemoveClientTargetTypeEvent(U32 type = 0) { mTargetType = type; }
|
|
void pack(NetConnection *, BitStream * bstream) { bstream->writeRangedU32(mTargetType, 0, ClientTarget::NumTypes); }
|
|
void write(NetConnection *, BitStream * bstream) { bstream->writeRangedU32(mTargetType, 0, ClientTarget::NumTypes); }
|
|
void unpack(NetConnection *, BitStream * bstream) { mTargetType = bstream->readRangedU32(0, ClientTarget::NumTypes); }
|
|
void process(NetConnection *) { gTargetList->removeTargetsOfType(mTargetType); }
|
|
|
|
DECLARE_CONOBJECT(RemoveClientTargetTypeEvent);
|
|
};
|
|
IMPLEMENT_CO_CLIENTEVENT_V1(RemoveClientTargetTypeEvent);
|
|
|
|
// remove any target with this type
|
|
void HUDTargetList::removeTargetsOfType(U32 type)
|
|
{
|
|
AssertFatal(type < ClientTarget::NumTypes, "HudTargetList::removeTargetsOfType: invalid type id");
|
|
|
|
// mCount gets updated on removing of an entry
|
|
for(U32 i = 0; i < mCount; i++)
|
|
{
|
|
AssertFatal(bool(mList[i].target), "HUDTargetList::removeTargetsOfType: invalid target");
|
|
if(mList[i].target->mType == type)
|
|
removeEntry(i);
|
|
}
|
|
}
|
|
|
|
void HUDTargetList::removeEntry(S32 entry)
|
|
{
|
|
AssertFatal(entry < mCount, "HUDTargetList::removeEntry: invalid entry");
|
|
notifyTargetRemoved(mList[entry].handle + TargetManager::MaxTargets);
|
|
|
|
// dec the type count
|
|
AssertFatal(bool(mList[entry].target), "HUDTargetList::removeEntry:: invalid target");
|
|
ClientTarget * target = static_cast<ClientTarget*>(mList[entry].target);
|
|
|
|
if(target->mType == ClientTarget::AssignedTask)
|
|
mNumAssignedTasks--;
|
|
else if(target->mType == ClientTarget::PotentialTask)
|
|
mNumPotentialTasks--;
|
|
else if(target->mType == ClientTarget::Waypoint)
|
|
mNumWaypoints--;
|
|
|
|
// update the notification handles as well
|
|
mCount--;
|
|
if(entry != mCount)
|
|
{
|
|
mHandle[mList[mCount].handle] = entry;
|
|
mHandle[mList[entry].handle] = FREE_HANDLE;
|
|
mList[entry] = mList[mCount];
|
|
}
|
|
else
|
|
mHandle[mList[entry].handle] = FREE_HANDLE;
|
|
|
|
mList[mCount].target = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TargetManager notification:
|
|
//---------------------------------------------------------------------------
|
|
void HUDTargetList::targetRemoved(U32 target)
|
|
{
|
|
// multiple hudtargets could be mapped to this target...
|
|
for(S32 i = mCount - 1; i >= 0; i--)
|
|
{
|
|
AssertFatal(bool(mList[i].target), "HUDTargetList::targetRemoved: invalid target in list!");
|
|
if(target == mList[i].target->mTargetId)
|
|
(static_cast<ClientTarget*>(mList[i].target))->deleteObject();
|
|
}
|
|
}
|
|
|
|
void HUDTargetList::targetsCleared()
|
|
{
|
|
for(S32 i = mCount - 1; i >= 0; i--)
|
|
{
|
|
AssertFatal(bool(mList[i].target), "HUDTargetList::targetRemoved: invalid target in list!");
|
|
(static_cast<ClientTarget*>(mList[i].target))->deleteObject();
|
|
}
|
|
notifyTargetsCleared();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void HUDTargetList::update(U32 newTime)
|
|
{
|
|
for(S32 i = mCount - 1; i >= 0; i--)
|
|
{
|
|
AssertFatal(bool(mList[i].target), "HUDTargetList::updateTime: invalid target");
|
|
|
|
// timeout
|
|
if(mList[i].canTimeout && (mList[i].doneTime < newTime))
|
|
{
|
|
mList[i].target->onDie();
|
|
continue;
|
|
}
|
|
|
|
// skip location targets (their position is already known)
|
|
if(mList[i].target->mTargetId == -1)
|
|
continue;
|
|
|
|
// update position
|
|
TargetInfo * targ = gTargetManager->getClientTarget(mList[i].target->mTargetId);
|
|
if(targ->sensorFlags & TargetInfo::VisibleToSensor)
|
|
if(bool(targ->targetObject))
|
|
targ->targetObject->getRenderWorldBox().getCenter(&mList[i].target->mLastTargetPos);
|
|
}
|
|
}
|
|
|
|
S32 HUDTargetList::getEntryByTarget(ClientTarget * target)
|
|
{
|
|
if(!target)
|
|
return(-1);
|
|
|
|
for(U32 i = 0; i < mCount; i++)
|
|
if(static_cast<ClientTarget*>(mList[i].target) == target)
|
|
return(i);
|
|
|
|
return(-1);
|
|
}
|
|
|
|
void HUDTargetList::removeEntryByTarget(ClientTarget * target)
|
|
{
|
|
S32 entry = getEntryByTarget(target);
|
|
if(entry == -1)
|
|
return;
|
|
|
|
removeEntry(entry);
|
|
}
|
|
|
|
HUDTargetList::Entry *HUDTargetList::getEntry(U32 index)
|
|
{
|
|
if(index >= mCount)
|
|
return(0);
|
|
return(mList + index);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
ClientTarget::ClientTarget(S32 type, S32 targetId, Point3F targetPos)
|
|
{
|
|
mType = type;
|
|
mTargetId = targetId;
|
|
mLastTargetPos = targetPos;
|
|
mText = 0;
|
|
}
|
|
|
|
void ClientTarget::onRemove()
|
|
{
|
|
if(gTargetList)
|
|
{
|
|
if(mType == Waypoint)
|
|
Con::executef(this, 1, "waypointRemoved");
|
|
gTargetList->removeEntryByTarget(this);
|
|
}
|
|
Parent::onRemove();
|
|
}
|
|
|
|
// being removed by the target list
|
|
void ClientTarget::onDie()
|
|
{
|
|
const char * typeStr = 0;
|
|
switch(mType)
|
|
{
|
|
case AssignedTask:
|
|
typeStr = "AssignedTask";
|
|
break;
|
|
case PotentialTask:
|
|
typeStr = "PotentialTask";
|
|
break;
|
|
|
|
default:
|
|
deleteObject();
|
|
return;
|
|
}
|
|
|
|
SimObjectPtr<ClientTarget> safeThis = this;
|
|
|
|
// give the console a chance to take possesion of this target
|
|
Con::executef(this, 2, "onDie", typeStr);
|
|
|
|
if(!bool(safeThis))
|
|
return;
|
|
|
|
// removed now?
|
|
gTargetList->removeEntryByTarget(this);
|
|
if(!getGroup() || (getGroup() == NetConnection::getServerConnection()))
|
|
deleteObject();
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// only ClientTarget created through event get processed (Tasks)
|
|
bool ClientTarget::process()
|
|
{
|
|
S32 time = Sim::getCurrentTime() + (mType == PotentialTask ? HUDTargetList::smTargetTimeout : 0);
|
|
if(gTargetList->addTarget(this, mType == PotentialTask, time))
|
|
{
|
|
Con::executef(this, 2, "onAdd", mType == AssignedTask ? "AssignedTask" : "PotentialTask");
|
|
return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
static void cTargetSendToServer(SimObject *target, S32, const char **)
|
|
{
|
|
ClientTarget *targ = static_cast<ClientTarget *>(target);
|
|
GameConnection *gc = GameConnection::getServerConnection();
|
|
if(gc)
|
|
gc->sendTargetToServer(targ->mTargetId, targ->mLastTargetPos);
|
|
}
|
|
|
|
// waypoints are created by the client
|
|
static void cCreateWaypoint(SimObject * obj, S32, const char ** argv)
|
|
{
|
|
ClientTarget * target = static_cast<ClientTarget*>(obj);
|
|
|
|
// can only create waypoints from untyped targets
|
|
if(target->mType != -1)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "ClientTarget::cCreateWaypoint: target already typed");
|
|
return;
|
|
}
|
|
|
|
target->mText = StringTable->insert(argv[2]);
|
|
target->mType = ClientTarget::Waypoint;
|
|
if(!gTargetList->addTarget(target, false, Sim::getCurrentTime()))
|
|
Con::errorf(ConsoleLogEntry::General, "ClientTarget::cCreateWaypoint: unable to create waypoint");
|
|
}
|
|
|
|
static void cAddPotentialTask(SimObject * obj, S32, const char **)
|
|
{
|
|
ClientTarget * target = static_cast<ClientTarget*>(obj);
|
|
if(target->mType != ClientTarget::PotentialTask)
|
|
return;
|
|
|
|
// may already be in the list
|
|
S32 entry = gTargetList->getEntryByTarget(target);
|
|
if(entry != -1)
|
|
return;
|
|
|
|
// add to the target-list
|
|
if(!gTargetList->addTarget(target, true, Sim::getCurrentTime() + HUDTargetList::smTargetTimeout))
|
|
Con::errorf(ConsoleLogEntry::General, "ClientTarget::cAddPotentialTask: unable to add task");
|
|
}
|
|
|
|
static void cSetText(SimObject * obj, S32, const char ** argv)
|
|
{
|
|
ClientTarget * target = static_cast<ClientTarget*>(obj);
|
|
target->mText = StringTable->insert(argv[2]);
|
|
}
|
|
|
|
static S32 cGetTargetId(SimObject * obj, S32, const char **)
|
|
{
|
|
ClientTarget * target = static_cast<ClientTarget*>(obj);
|
|
if(!gTargetList)
|
|
return(-1);
|
|
S32 entry = gTargetList->getEntryByTarget(target);
|
|
if(entry == -1)
|
|
return(-1);
|
|
return(TargetManager::MaxTargets + gTargetList->mList[entry].handle);
|
|
}
|
|
|
|
static S32 cCreateClientTarget(SimObject *, S32 argc, const char ** argv)
|
|
{
|
|
GameConnection * con = GameConnection::getServerConnection();
|
|
if(!con)
|
|
return(-1);
|
|
|
|
Point3F pos(0,0,0);
|
|
if(argc == 3)
|
|
dSscanf(argv[2],"%f %f %f", &pos.x, &pos.y, &pos.z);
|
|
|
|
ClientTarget * target = new ClientTarget(-1, dAtoi(argv[1]), pos);
|
|
target->registerObject();
|
|
con->addObject(target);
|
|
return(target->getId());
|
|
}
|
|
|
|
static U32 getTypeFromString(const char * str)
|
|
{
|
|
if(!str)
|
|
return(ClientTarget::NumTypes);
|
|
|
|
if(!dStricmp(str, "AssignedTask"))
|
|
return(ClientTarget::AssignedTask);
|
|
else if(!dStricmp(str, "PotentialTask"))
|
|
return(ClientTarget::PotentialTask);
|
|
else if(!dStricmp(str, "Waypoint"))
|
|
return(ClientTarget::Waypoint);
|
|
|
|
return(ClientTarget::NumTypes);
|
|
}
|
|
|
|
static void cRemoveClientTargetType(SimObject *, S32, const char ** argv)
|
|
{
|
|
U32 type = getTypeFromString(argv[2]);
|
|
|
|
// make sure type in range
|
|
if(type >= ClientTarget::NumTypes)
|
|
{
|
|
Con::errorf(ConsoleLogEntry::General, "HUDTargetList::removeClientTargetType: invalid type [%s]", argv[1]);
|
|
return;
|
|
}
|
|
|
|
// only send to a non-ai connection
|
|
NetConnection * client = dynamic_cast<NetConnection*>(Sim::findObject(dAtoi(argv[1])));
|
|
if(client && !client->isServerConnection())
|
|
{
|
|
if(dynamic_cast<GameConnection*>(client) && static_cast<GameConnection*>(client)->isAIControlled())
|
|
return;
|
|
client->postNetEvent( new RemoveClientTargetTypeEvent(type) );
|
|
}
|
|
else
|
|
Con::errorf(ConsoleLogEntry::General, "HUDTargetList::removeClientTargetType: invalid connection [%s]", argv[1]);
|
|
}
|
|
|
|
void ClientTarget::consoleInit()
|
|
{
|
|
Con::addCommand("ClientTarget", "sendToServer", cTargetSendToServer, "target.sendToServer()", 2, 2);
|
|
Con::addCommand("ClientTarget", "createWaypoint", cCreateWaypoint, "target.createWaypoint(text)", 3, 3);
|
|
Con::addCommand("ClientTarget", "addPotentialTask", cAddPotentialTask, "target.addPotentialTask()", 2, 2);
|
|
Con::addCommand("ClientTarget", "setText", cSetText, "target.setText(text)", 3, 3);
|
|
Con::addCommand("ClientTarget", "getTargetId", cGetTargetId, "target.getTargetId()", 2, 2);
|
|
|
|
Con::addCommand("createClientTarget", cCreateClientTarget, "createClientTarget(targetId, <x y z>)", 2, 3);
|
|
Con::addCommand("removeClientTargetType", cRemoveClientTargetType, "removeClientTargetType(client, type)", 3, 3);
|
|
|
|
Con::addVariable("clientTargetTimeout", TypeS32, &HUDTargetList::smTargetTimeout);
|
|
}
|
|
|
|
IMPLEMENT_CONOBJECT(ClientTarget);
|
|
|
|
//---------------------------------------------------------------------------
|
|
// TargetManager::SensorInfo:
|
|
//---------------------------------------------------------------------------
|
|
ColorI TargetManager::SensorInfo::smDefaultColor(255, 0, 0, 255);
|
|
|
|
void TargetManager::SensorInfo::clear()
|
|
{
|
|
U32 i;
|
|
for(i = 0; i < TargetManager::TargetFreeMaskSize; i++)
|
|
targetPingMask[i] = 0;
|
|
for(i = 0; i < 32; i++)
|
|
groupColor[i] = smDefaultColor;
|
|
}
|
|
|
|
void TargetManager::SensorInfo::setSensorVisible(S32 targetId, bool vis)
|
|
{
|
|
if(targetId < 0 || targetId >= TargetManager::MaxTargets)
|
|
return;
|
|
if(vis)
|
|
targetPingMask[targetId >> 5] |= (1 << (targetId & 0x1F));
|
|
else
|
|
targetPingMask[targetId >> 5] &= ~(1 << (targetId & 0x1F));
|
|
}
|
|
|
|
bool TargetManager::SensorInfo::getSensorVisible(S32 targetId)
|
|
{
|
|
if(targetId < 0 || targetId >= TargetManager::MaxTargets)
|
|
return false;
|
|
return targetPingMask[targetId >> 5] & (1 << (targetId & 0x1F));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
static inline bool testLOS(GameBase * sensor, const Point3F & sensorPos,
|
|
GameBase * target, const Point3F & targetPos)
|
|
{
|
|
static U32 losMask = TerrainObjectType | InteriorObjectType | ShapeBaseObjectType;
|
|
|
|
RayInfo info;
|
|
|
|
// disable collision for the target/sensor and possible mount
|
|
target->disableCollision();
|
|
sensor->disableCollision();
|
|
|
|
ShapeBase * mount = 0;
|
|
if(target->getType() & ShapeBaseObjectType)
|
|
{
|
|
mount = static_cast<ShapeBase*>(target)->getObjectMount();
|
|
if(mount)
|
|
mount->disableCollision();
|
|
}
|
|
|
|
bool hasLOS = !gServerContainer.castRay(sensorPos, targetPos, losMask, &info);
|
|
|
|
// enable the collisions for the objects..
|
|
target->enableCollision();
|
|
sensor->enableCollision();
|
|
if(mount)
|
|
mount->enableCollision();
|
|
|
|
return(hasLOS);
|
|
}
|
|
|
|
void TargetManager::tickSensorState()
|
|
{
|
|
U32 objectCount = 0;
|
|
U32 totalCount = MaxTargets - mFreeCount;
|
|
U32 pingCount = (totalCount >> 5) + 1; // ping everything once a second
|
|
U32 lastSensed = mLastSensedObject;
|
|
|
|
for(U32 i = mLastSensedObject + 1; i - mLastSensedObject < MaxTargets; i++)
|
|
{
|
|
U32 index = i & (MaxTargets - 1);
|
|
U32 maskPos = index >> 5;
|
|
U32 maskShift = index & 0x1F;
|
|
if((maskShift == 0) && mFreeMask[maskPos] == 0)
|
|
{
|
|
i += 31;
|
|
continue;
|
|
}
|
|
if(!(mFreeMask[maskPos] & (1 << maskShift)))
|
|
continue;
|
|
TargetInfo *targetInfo = mTargets + index;
|
|
|
|
if(!bool(targetInfo->targetObject))
|
|
continue;
|
|
|
|
GameBase * target = targetInfo->targetObject;
|
|
|
|
// ok, we have an object
|
|
// now loop through all the sensable objects
|
|
U32 baseVisMask = 0;
|
|
U32 activeJamVisMask = 0;
|
|
U32 passiveJamVisMask = 0;
|
|
U32 cloakVisMask = 0;
|
|
bool pinged = false;
|
|
bool jammed = false;
|
|
bool enemyJammed = false;
|
|
|
|
Point3F targetPos;
|
|
|
|
// grab eye point if player...
|
|
if(target->getType() & PlayerObjectType)
|
|
{
|
|
AssertFatal(dynamic_cast<Player*>(target), "Invalid player object.");
|
|
Player * player = static_cast<Player*>(target);
|
|
|
|
MatrixF eye;
|
|
player->getEyeTransform(&eye);
|
|
eye.getColumn(3, &targetPos);
|
|
}
|
|
else
|
|
targetPos = target->getBoxCenter();
|
|
|
|
Point3F targetVec;
|
|
|
|
for(U32 sens = 0; sens < MaxTargets; sens++)
|
|
{
|
|
bool testedLOS = false;
|
|
bool hasLOS = false;
|
|
U32 smaskPos = sens >> 5;
|
|
U32 smaskShift = sens & 0x1F;
|
|
if((smaskShift == 0) && mFreeMask[smaskPos] == 0)
|
|
{
|
|
sens += 31;
|
|
continue;
|
|
}
|
|
if(!(mFreeMask[smaskPos] & (1 << smaskShift)))
|
|
continue;
|
|
TargetInfo *sensorInfo = mTargets + sens;
|
|
if(!bool(sensorInfo->targetObject))
|
|
continue;
|
|
GameBase *sensor = sensorInfo->targetObject;
|
|
SensorData *sensorData = sensorInfo->sensorData;
|
|
|
|
if(!sensor || !sensorData)
|
|
continue;
|
|
|
|
// can't detect its own bad self, but can jam...
|
|
if(sens == index)
|
|
{
|
|
if(sensorData->jams)
|
|
jammed = true;
|
|
continue;
|
|
}
|
|
// sensors must be shapebase items (need damage state)
|
|
if(!dynamic_cast<ShapeBase*>(sensor))
|
|
continue;
|
|
|
|
ShapeBase * sensorShape = static_cast<ShapeBase*>(sensor);
|
|
if(sensorShape->getDamageState() != ShapeBase::Enabled)
|
|
continue;
|
|
|
|
Point3F sensorPos;
|
|
|
|
bool jumpNoDetect = false;
|
|
|
|
// jams? and is/not always visible?
|
|
U32 sensorMask = 1 << sensorInfo->sensorGroup;
|
|
if((targetInfo->sensorAlwaysVisMask | targetInfo->sensorNeverVisMask) & sensorMask)
|
|
{
|
|
if(sensorData->jams)
|
|
jumpNoDetect = true;
|
|
else
|
|
continue;
|
|
}
|
|
|
|
// grab the sensor position (grab eye of players)
|
|
// if this is a player then grab its eye...
|
|
if(sensor->getType() & PlayerObjectType)
|
|
{
|
|
AssertFatal(dynamic_cast<Player*>(sensor), "Invalid player object.");
|
|
|
|
MatrixF eye;
|
|
sensorShape->getEyeTransform(&eye);
|
|
eye.getColumn(3, &sensorPos);
|
|
}
|
|
else
|
|
sensorPos = sensor->getBoxCenter();
|
|
|
|
// jams but is visible?
|
|
if(jumpNoDetect)
|
|
goto nodetect;
|
|
|
|
// see if the sensor detects stuff:
|
|
if(!sensorData->detects)
|
|
goto nodetect;
|
|
|
|
U32 *mask;
|
|
if(sensorData->detectsActiveJammed) // everything
|
|
mask = &activeJamVisMask;
|
|
else if(sensorData->detectsCloaked) // all but motion
|
|
mask = &cloakVisMask;
|
|
else if(sensorData->detectsPassiveJammed) // all but motion and los
|
|
mask = &passiveJamVisMask;
|
|
else
|
|
mask = &baseVisMask;
|
|
|
|
// see if we can skip this one:
|
|
if((*mask & sensorMask) && (pinged == sensorData->detectionPings))
|
|
goto nodetect;
|
|
|
|
targetVec = targetPos - sensorPos;
|
|
|
|
// check distance:
|
|
if(targetVec.isZero())
|
|
continue;
|
|
|
|
// uncapped cylinder
|
|
if(Point2F(targetVec.x, targetVec.y).lenSquared() > sensorData->detectRSquared)
|
|
goto nodetect;
|
|
|
|
// normal sphere
|
|
// if(targetVec.lenSquared() > sensorData->detectRSquared)
|
|
// goto nodetect;
|
|
|
|
// minvel:
|
|
if(sensorData->detectMinVelocity != 0.f)
|
|
if(target->getVelocity().lenSquared() < sensorData->detectMinVSquared)
|
|
goto nodetect;
|
|
|
|
// fov:
|
|
if(sensorData->detectsFOVOnly)
|
|
{
|
|
MatrixF camMat;
|
|
sensorShape->getEyeTransform(&camMat);
|
|
|
|
VectorF camDir;
|
|
camMat.mulV(VectorF(0,1,0), &camDir);
|
|
targetVec.normalize();
|
|
|
|
F32 dot = mClampF(mDot(targetVec, camDir), -1.f, 1.f);
|
|
|
|
// check if interested in projected fov through this object
|
|
if(sensorData->useObjectFOV)
|
|
{
|
|
F32 objectFov = mDegToRad(sensorShape->getCameraFov());
|
|
F32 halfFovCos = mCos(objectFov / 2.f);
|
|
if(dot < halfFovCos)
|
|
goto nodetect;
|
|
|
|
if(sensorData->detectFOVPercent != 0.f)
|
|
{
|
|
F32 objRadius = target->getWorldSphere().radius;
|
|
F32 distance = Point3F(targetPos - sensorPos).len();
|
|
|
|
F32 projRadius = distance * mTan(objectFov / 2.f);
|
|
|
|
if(((objRadius / projRadius) * 100.f) < sensorData->detectFOVPercent)
|
|
goto nodetect;
|
|
}
|
|
}
|
|
else
|
|
if(dot < sensorData->halfFovCos)
|
|
goto nodetect;
|
|
}
|
|
|
|
// los:
|
|
if(sensorData->detectsUsingLOS)
|
|
{
|
|
testedLOS = true;
|
|
hasLOS = testLOS(sensor, sensorPos, target, targetPos);
|
|
if(!hasLOS)
|
|
goto nodetect;
|
|
}
|
|
|
|
// it's detected
|
|
*mask |= sensorMask;
|
|
|
|
// friendly do not ping
|
|
if(sensorData->detectionPings && !(sensorInfo->sensorFriendlyMask & (1 << targetInfo->sensorGroup)))
|
|
pinged = true;
|
|
|
|
nodetect:
|
|
|
|
// early out?
|
|
if(!sensorData->jams || (jammed && enemyJammed))
|
|
continue;
|
|
|
|
if(sensorInfo->sensorGroup == targetInfo->sensorGroup)
|
|
{
|
|
if(jammed)
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if(enemyJammed && sensorData->jamsOnlyGroup)
|
|
continue;
|
|
}
|
|
|
|
// normal sphere
|
|
if((targetPos - sensorPos).lenSquared() > sensorData->jamRSquared)
|
|
continue;
|
|
|
|
// check los
|
|
if(sensorData->jamsUsingLOS)
|
|
{
|
|
if(!testedLOS)
|
|
hasLOS = testLOS(sensor, sensorPos, target, targetPos);
|
|
|
|
if(!hasLOS)
|
|
continue;
|
|
}
|
|
|
|
// set the jammed state
|
|
if(sensorInfo->sensorGroup == targetInfo->sensorGroup)
|
|
jammed = true;
|
|
else
|
|
{
|
|
jammed = !sensorData->jamsOnlyGroup;
|
|
enemyJammed = true;
|
|
}
|
|
}
|
|
|
|
// check cloaked/passiveJammed: only ShapeBase objects
|
|
bool cloaked = false;
|
|
bool passiveJammed = false;
|
|
if(dynamic_cast<ShapeBase*>(target))
|
|
{
|
|
cloaked = (static_cast<ShapeBase*>(target))->getCloakedState();
|
|
passiveJammed = (static_cast<ShapeBase*>(target))->getPassiveJamState();
|
|
}
|
|
|
|
// check what could detect it: active->cloaked->passive->base
|
|
U32 visMask;
|
|
if(jammed)
|
|
visMask = activeJamVisMask;
|
|
else if(cloaked)
|
|
visMask = activeJamVisMask | cloakVisMask;
|
|
else if(passiveJammed)
|
|
visMask = activeJamVisMask | cloakVisMask | passiveJamVisMask;
|
|
else
|
|
visMask = activeJamVisMask | cloakVisMask | passiveJamVisMask | baseVisMask;
|
|
|
|
visMask |= targetInfo->sensorAlwaysVisMask;
|
|
visMask &= ~targetInfo->sensorNeverVisMask;
|
|
|
|
targetInfo->sensorVisMask = visMask;
|
|
targetInfo->sensorFlags = 0;
|
|
if(pinged)
|
|
targetInfo->sensorFlags |= TargetInfo::SensorPinged;
|
|
|
|
// if jammed, then notify the shapebase object
|
|
if(jammed || enemyJammed)
|
|
{
|
|
if(jammed)
|
|
targetInfo->sensorFlags |= TargetInfo::SensorJammed;
|
|
|
|
if(enemyJammed)
|
|
{
|
|
targetInfo->sensorFlags |= TargetInfo::EnemySensorJammed;
|
|
|
|
if(dynamic_cast<ShapeBase*>(static_cast<SimObject*>(targetInfo->targetObject)))
|
|
{
|
|
ShapeBase * shape = static_cast<ShapeBase*>(static_cast<SimObject*>(targetInfo->targetObject));
|
|
|
|
// reason gets passed down into script.. (shapebase actually doesnt do anything)
|
|
shape->forceUncloak("jammed");
|
|
}
|
|
}
|
|
}
|
|
|
|
for(U32 j = 0; j < mSensorGroupCount; j++, visMask >>= 1)
|
|
mSensorInfoArray[j].setSensorVisible(index, (visMask & 1));
|
|
|
|
objectCount++;
|
|
lastSensed = i;
|
|
if(objectCount >= pingCount)
|
|
break;
|
|
}
|
|
mLastSensedObject = lastSensed;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// debug list control: fills with target info
|
|
//------------------------------------------------------------------------------
|
|
#ifdef DEBUG
|
|
#include "gui/guiTextListCtrl.h"
|
|
|
|
class GuiTargetManagerListCtrl : public GuiTextListCtrl
|
|
{
|
|
private:
|
|
typedef GuiTextListCtrl Parent;
|
|
bool mServerTargets;
|
|
|
|
public:
|
|
|
|
enum {
|
|
NumCategories = 14
|
|
};
|
|
|
|
GuiTargetManagerListCtrl();
|
|
void onPreRender();
|
|
|
|
static void initPersistFields();
|
|
static void consoleInit();
|
|
|
|
DECLARE_CONOBJECT(GuiTargetManagerListCtrl);
|
|
};
|
|
IMPLEMENT_CONOBJECT(GuiTargetManagerListCtrl);
|
|
|
|
GuiTargetManagerListCtrl::GuiTargetManagerListCtrl()
|
|
{
|
|
mServerTargets = true;
|
|
}
|
|
|
|
void GuiTargetManagerListCtrl::onPreRender()
|
|
{
|
|
RectI bounds = mBounds;
|
|
|
|
clear();
|
|
|
|
// add all the entries
|
|
addEntry(0, "ID\tName\tType\tVoice\tSkin\tPitch\tGroup\tObj\tData\tSensor\tVisMask\tAlways\tNever\tFriend\tFlags");
|
|
|
|
for(U32 i = 32; i < TargetManager::MaxTargets; i++)
|
|
{
|
|
TargetInfo * targInfo = mServerTargets ? gTargetManager->getServerTarget(i) : gTargetManager->getClientTarget(i);
|
|
|
|
if(targInfo->allocated)
|
|
{
|
|
char buf[1024];
|
|
buf[0] = 0;
|
|
|
|
dSprintf(buf, sizeof(buf),
|
|
"%d\t%s\t%s\t%s\t%s\t%f\t%d\t%d\t%s\t%s\t%x\t%x\t%x\t%x\t%x", i,
|
|
gNetStringTable->lookupString(targInfo->nameTag),
|
|
gNetStringTable->lookupString(targInfo->typeTag),
|
|
gNetStringTable->lookupString(targInfo->voiceTag),
|
|
gNetStringTable->lookupString(targInfo->skinTag),
|
|
targInfo->voicePitch,
|
|
targInfo->sensorGroup,
|
|
bool(targInfo->targetObject) ? targInfo->targetObject->getId() : 0,
|
|
bool(targInfo->shapeBaseData) ? targInfo->shapeBaseData->getName() : "<none>",
|
|
bool(targInfo->sensorData) ? targInfo->sensorData->getName() : "<none>",
|
|
targInfo->sensorVisMask,
|
|
targInfo->sensorAlwaysVisMask,
|
|
targInfo->sensorNeverVisMask,
|
|
targInfo->sensorFriendlyMask,
|
|
targInfo->sensorFlags);
|
|
|
|
addEntry(i, buf);
|
|
}
|
|
}
|
|
|
|
resize(bounds.point, mBounds.extent);
|
|
Parent::onPreRender();
|
|
}
|
|
|
|
void GuiTargetManagerListCtrl::initPersistFields()
|
|
{
|
|
Parent::initPersistFields();
|
|
addField("serverTargets", TypeBool, Offset(mServerTargets, GuiTargetManagerListCtrl));
|
|
}
|
|
|
|
static S32 cGetNumColumns(SimObject *, S32, const char **)
|
|
{
|
|
return(GuiTargetManagerListCtrl::NumCategories);
|
|
}
|
|
|
|
void GuiTargetManagerListCtrl::consoleInit()
|
|
{
|
|
Con::addCommand("GuiTargetManagerListCtrl", "getNumColumns", cGetNumColumns, "ctrl.getNumColumns()", 2, 2);
|
|
}
|
|
#endif
|