2012-05-29 13:31:11 +00:00
|
|
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as
|
|
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "stdpch.h"
|
|
|
|
|
|
|
|
#include "mirrors.h"
|
|
|
|
#include "game_share/tick_event_handler.h"
|
|
|
|
#include "nel/net/service.h"
|
|
|
|
#include "game_share/misc_const.h"
|
|
|
|
#include "game_share/fame.h"
|
|
|
|
#include "ai_bot_npc.h"
|
|
|
|
#include "ai_grp_npc.h"
|
|
|
|
#include "server_share/r2_variables.h"
|
|
|
|
#include "server_share/r2_vision.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "ai.h"
|
|
|
|
#include "ai_player.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace NLMISC;
|
|
|
|
using namespace NLNET;
|
|
|
|
using namespace MBEHAV;
|
|
|
|
|
|
|
|
CMirror CMirrors::Mirror;
|
|
|
|
CMirroredDataSet *CMirrors::DataSet = NULL;
|
|
|
|
CMirroredDataSet *CMirrors::FameDataSet = NULL;
|
|
|
|
|
|
|
|
const uint MAX_NB_ENTITIES_ISOLATED = 25000;
|
|
|
|
CEntityId *IsolatedEntityId = NULL;
|
|
|
|
sint32 *IsolatedX = NULL;
|
|
|
|
sint32 *IsolatedY = NULL;
|
|
|
|
sint32 *IsolatedZ = NULL;
|
|
|
|
float *IsolatedTheta = NULL;
|
|
|
|
uint32 *IsolatedSheet = NULL;
|
|
|
|
uint32 *IsolatedSheetServer = NULL;
|
|
|
|
TDataSetRow *IsolatedTarget = NULL; // sint32
|
|
|
|
uint32 *IsolatedMode = NULL; // only mode enum
|
|
|
|
uint32 *IsolatedBehaviour = NULL;
|
|
|
|
uint32 *IsolatedCurrentHitPoints = NULL;
|
|
|
|
uint32 *IsolatedMaxHitPoints = NULL;
|
|
|
|
uint32 *IsolatedBestRoleLevel = NULL;
|
|
|
|
uint8 *IsolatedCombatState = NULL;
|
|
|
|
|
|
|
|
extern CVariable<double> RingMaxSelectDist;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialisation 2
|
|
|
|
*/
|
|
|
|
void cbMirrorIsReady( CMirror *mirror )
|
|
|
|
{
|
|
|
|
CMirrors::initMirror();
|
|
|
|
}
|
|
|
|
|
|
|
|
void cbMirrorReadyForAddEntity( CMirror *mirror )
|
|
|
|
{
|
|
|
|
|
|
|
|
// Init fx manager
|
|
|
|
const TDeclaredEntityRangeOfType& declERT = TheDataset.getDeclaredEntityRanges();
|
|
|
|
{
|
|
|
|
TDeclaredEntityRangeOfType::const_iterator it = declERT.find( RYZOMID::fx_entity );
|
|
|
|
const TDeclaredEntityRange& range = GET_ENTITY_TYPE_RANGE(it);
|
|
|
|
CFxEntityManager::getInstance()->init( range.baseIndex(), range.size() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define initIsolatedPropTable( name, thetype, defaultvalue ) \
|
|
|
|
name = new thetype [MAX_NB_ENTITIES_ISOLATED]; \
|
|
|
|
for ( i=0; i!=MAX_NB_ENTITIES_ISOLATED; ++i ) \
|
|
|
|
name[i] = defaultvalue
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialisation 1
|
|
|
|
*/
|
|
|
|
void CMirrors::init( void (*cbUpdate)(), void (*cbSync)(), void (*cbRelease)() )
|
|
|
|
{
|
|
|
|
// Init the mirror system
|
|
|
|
vector<string> datasetNames;
|
|
|
|
datasetNames.push_back( "fe_temp" );
|
|
|
|
datasetNames.push_back( "fame" );
|
|
|
|
Mirror.init( datasetNames, cbMirrorIsReady, cbUpdate, cbSync, cbRelease, AISTag );
|
|
|
|
Mirror.addCallbackWhenMirrorReadyForUse( cbMirrorReadyForAddEntity );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Init after the mirror init
|
|
|
|
*/
|
|
|
|
void CMirrors::initMirror()
|
|
|
|
{
|
|
|
|
//Mirror.declareEntityTypeUser( RYZOMID::player );
|
|
|
|
|
|
|
|
Mirror.declareEntityTypeOwner( RYZOMID::npc, TotalMaxNpc.get() );
|
|
|
|
Mirror.declareEntityTypeOwner( RYZOMID::creature, TotalMaxFauna.get()+TotalMaxPet.get() );
|
|
|
|
Mirror.declareEntityTypeOwner( RYZOMID::fx_entity, TotalMaxFx );
|
|
|
|
|
|
|
|
DataSet = &(Mirror.getDataSet("fe_temp"));
|
|
|
|
DataSet->declareProperty( "AIInstance", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "X", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "Y", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "Z", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "Theta", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "Sheet", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "SheetServer", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "NPCAlias", PSOWriteOnly );
|
|
|
|
DataSet->declareProperty( "Mode", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "Behaviour", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "Target", PSOReadWrite | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "CurrentHitPoints", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "CurrentRunSpeed", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "CurrentWalkSpeed", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "MaxHitPoints", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "BestRoleLevel", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "CombatState", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "TeamId", PSOReadOnly | PSONotifyChanges );
|
|
|
|
DataSet->declareProperty( "InOutpostZoneAlias", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "InOutpostZoneSide", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "VisualPropertyA", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "VisualPropertyB", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "VisualPropertyC", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "ActionFlags", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "VisionCounter", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "Fuel", PSOReadOnly );
|
|
|
|
DataSet->declareProperty( "WhoSeesMe", PSOReadWrite );
|
|
|
|
DataSet->declareProperty( "ContextualProperty", PSOReadWrite );
|
|
|
|
|
|
|
|
initRyzomVisualPropertyIndices( *DataSet );
|
|
|
|
|
|
|
|
// init fame dataset
|
|
|
|
FameDataSet = &(Mirror.getDataSet("fame"));
|
|
|
|
CFameInterface::getInstance().setFameDataSet(FameDataSet);
|
|
|
|
|
|
|
|
Mirror.setNotificationCallback( CMirrors::processMirrorUpdates );
|
|
|
|
}
|
|
|
|
|
|
|
|
// a big bad global var !
|
|
|
|
extern CAIEntityPhysical *TempSpeaker;
|
|
|
|
extern CBotPlayer *TempPlayer;
|
|
|
|
|
|
|
|
|
|
|
|
void CMirrors::processMirrorUpdates()
|
|
|
|
{
|
|
|
|
TDataSetRow entityIndex;
|
|
|
|
CEntityId *pEntityId;
|
|
|
|
|
|
|
|
CFameInterface &fi = CFameInterface::getInstance();
|
|
|
|
|
|
|
|
// Process added entities
|
|
|
|
DataSet->beginAddedEntities();
|
|
|
|
while ((entityIndex = DataSet->getNextAddedEntity()) != LAST_CHANGED)
|
|
|
|
{
|
|
|
|
const CEntityId& entityId = DataSet->getEntityId(entityIndex);
|
|
|
|
|
|
|
|
// Create CAIPlayer object and add to maps
|
|
|
|
if (entityId.getType() != RYZOMID::player)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
{
|
|
|
|
CMirrorPropValue<uint32> _instanceNumber(*DataSet, entityIndex, DSPropertyAI_INSTANCE);
|
|
|
|
const uint32 askedInstance=_instanceNumber();
|
|
|
|
CAIInstance *const aii = CAIS::instance().getAIInstance(askedInstance);
|
|
|
|
|
|
|
|
if (!aii)
|
|
|
|
{
|
|
|
|
// The player is not in an AIInstance of that ais.
|
|
|
|
// Floods on player connections, so no warning
|
|
|
|
// nlwarning("AIInstance %d not found to spawn player %s", askedInstance, entityId.toString().c_str());
|
|
|
|
// FOREACH(it,CCont<CAIInstance>, CAIS::instance().AIList())
|
|
|
|
// {
|
|
|
|
// nlwarning("exist AIInstance %d at index %d", (*it)->getInstanceNumber(), (*it)->getIndex());
|
|
|
|
// }
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// store the player in the correct instance.
|
|
|
|
aii->getPlayerMgr()->addSpawnedPlayer(entityIndex, entityId);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
DataSet->endAddedEntities();
|
|
|
|
|
|
|
|
FameDataSet->beginAddedEntities();
|
|
|
|
while( (entityIndex = FameDataSet->getNextAddedEntity()) != LAST_CHANGED )
|
|
|
|
{
|
|
|
|
fi.createFameOwner(*FameDataSet, entityIndex);
|
|
|
|
}
|
|
|
|
FameDataSet->endAddedEntities();
|
|
|
|
|
|
|
|
// Process removed entities
|
|
|
|
DataSet->beginRemovedEntities();
|
|
|
|
while( (entityIndex = DataSet->getNextRemovedEntity(&pEntityId)) != LAST_CHANGED )
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhysPtr = CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
// just to check if its a player .. and remove it from Manager and Maps ..
|
|
|
|
if ( entityPhysPtr
|
|
|
|
&& entityPhysPtr->getRyzomType()==RYZOMID::player)
|
|
|
|
{
|
|
|
|
CBotPlayer *botPlayer=NLMISC::safe_cast<CBotPlayer*>(entityPhysPtr);
|
|
|
|
botPlayer->getOwner()->removeDespawnedPlayer(entityIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
DataSet->endRemovedEntities();
|
|
|
|
|
|
|
|
FameDataSet->beginRemovedEntities();
|
|
|
|
while( (entityIndex = FameDataSet->getNextRemovedEntity(&pEntityId)) != LAST_CHANGED )
|
|
|
|
{
|
|
|
|
fi.removeFameOwner(*FameDataSet, entityIndex);
|
|
|
|
}
|
|
|
|
FameDataSet->endRemovedEntities();
|
|
|
|
|
|
|
|
// Process properties changed and notified in the mirror
|
|
|
|
TPropertyIndex propIndex;
|
|
|
|
DataSet->beginChangedValues();
|
|
|
|
DataSet->getNextChangedValue( entityIndex, propIndex );
|
|
|
|
while (entityIndex != LAST_CHANGED)
|
|
|
|
{
|
|
|
|
if (propIndex == DSPropertyPOSX || propIndex == DSPropertyPOSX )
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
if (player)
|
|
|
|
{
|
|
|
|
CAIInstance* aiInstance = player->getAIInstance();
|
|
|
|
aiInstance->updateZoneTrigger(player);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (propIndex == DSPropertyTEAM_ID)
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
if (player)
|
|
|
|
player->getOwner()->updatePlayerTeam(entityIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (propIndex == DSPropertyAI_INSTANCE)
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
// this player is already in a manager, despawn it
|
|
|
|
CBotPlayer *const botPlayer=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
botPlayer->getOwner()->removeDespawnedPlayer(entityIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// could be done with mirrored values. (!?).
|
|
|
|
CMirrorPropValue<uint32> _instanceNumber(*DataSet, entityIndex, DSPropertyAI_INSTANCE);
|
|
|
|
const uint32 askedInstance=_instanceNumber();
|
|
|
|
|
|
|
|
CAIInstance *aii = CAIS::instance().getAIInstance(askedInstance);
|
|
|
|
|
|
|
|
if (aii!=NULL)
|
|
|
|
{
|
|
|
|
// store the player in the correct instance.
|
|
|
|
aii->getPlayerMgr()->addSpawnedPlayer(entityIndex, entityId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-12-17 13:35:48 +00:00
|
|
|
if (askedInstance!=std::numeric_limits<uint32>::max())
|
2012-05-29 13:31:11 +00:00
|
|
|
{
|
|
|
|
// no need to warn for ai number instance not in this AIS !
|
|
|
|
// nlwarning("AIInstance %u not found on AIInstance changement for player %s", askedInstance, entityId.toString().c_str());
|
|
|
|
// FOREACH(it,CCont<CAIInstance>, CAIS::instance().AIList())
|
|
|
|
// {
|
|
|
|
// nlwarning("exist AIInstance %d at index %d", (*it)->getInstanceNumber(), (*it)->getIndex());
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (propIndex == DSPropertyTARGET_ID)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
|
|
|
|
// check if target is a local npc bot then handle bot targeted event
|
|
|
|
CMirrorPropValueRO<TYPE_TARGET_ID> tgt(TheDataset, entityIndex, DSPropertyTARGET_ID);
|
|
|
|
CAIEntityPhysical *target = CAIS::instance().getEntityPhysical(tgt());
|
|
|
|
|
|
|
|
// update the targering list
|
|
|
|
if (entityIndex==TDataSetRow()) // no target.
|
|
|
|
{
|
|
|
|
player->setTarget(NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (player->isAggressive())
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *oldTarget=player->getTarget();
|
|
|
|
if ( !oldTarget
|
|
|
|
|| oldTarget!=target )
|
|
|
|
player->setTarget(target);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *oldTarget=player->getVisualTarget();
|
|
|
|
if ( !oldTarget
|
|
|
|
|| oldTarget!=target )
|
|
|
|
player->setVisualTarget(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CSpawnBotNpc *bnpc = dynamic_cast<CSpawnBotNpc *>(target);
|
|
|
|
if (bnpc)
|
|
|
|
{
|
|
|
|
TempSpeaker = bnpc;
|
|
|
|
TempPlayer = player;
|
|
|
|
CGroupNpc &grpNpc = bnpc->getPersistent().grp();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (IsRingShard)
|
|
|
|
{
|
|
|
|
CAIPos playerPos(player->pos());
|
|
|
|
CAIPos npcPos(bnpc->pos());
|
|
|
|
double dist = npcPos.quickDistTo(playerPos);
|
|
|
|
bool dm = false;
|
|
|
|
|
|
|
|
uint64 whoSeesMe = CMirrors::whoSeesMe(player->dataSetRow());
|
|
|
|
if (!R2_VISION::isEntityVisibleToPlayers(whoSeesMe))
|
|
|
|
{
|
|
|
|
// The player is invisible, its a Dm / Gm: no zone event must be triggered
|
|
|
|
dm = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!dm && dist <= RingMaxSelectDist)
|
|
|
|
{
|
|
|
|
grpNpc.processStateEvent(grpNpc.getEventContainer().EventPlayerTargetNpc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// generate en event on this bot group
|
|
|
|
grpNpc.processStateEvent(grpNpc.getEventContainer().EventPlayerTargetNpc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// grpNpc.processStateEvent(grpNpc.getEventContainer().EventPlayerTargetNpc);
|
|
|
|
// grpNpc.getEventContainer().EventPlayerTargetNpc.processStateEvent(&grpNpc);
|
|
|
|
|
|
|
|
// if player is in follow mode, then generate an suplementary event
|
|
|
|
if (player->getFollowMode())
|
|
|
|
grpNpc.processStateEvent(grpNpc.getEventContainer().EventPlayerFollowNpc);
|
|
|
|
// grpNpc.getEventContainer().EventPlayerFollowNpc.processStateEvent(&grpNpc);
|
|
|
|
|
|
|
|
TempPlayer = NULL;
|
|
|
|
TempSpeaker = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (propIndex == DSPropertyMODE)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
|
|
|
|
// if the player have a target, move it to the correct target list.
|
|
|
|
|
|
|
|
if (player->isAggressive())
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *target=player->getVisualTarget();
|
|
|
|
if (target)
|
|
|
|
player->setTarget(target);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *target=player->getTarget();
|
|
|
|
if (target)
|
|
|
|
player->setVisualTarget(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* else if (propIndex == DSPropertyBEHAVIOUR)
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
|
|
|
|
if (entityPhys)
|
|
|
|
{
|
|
|
|
const CEntityId &entityId=DataSet->getEntityId(entityIndex);
|
|
|
|
if (entityId.getType() == RYZOMID::player)
|
|
|
|
{
|
|
|
|
CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
|
|
|
|
|
|
|
|
MBEHAV::EBehaviour const behaviour = player->getBehaviour();
|
|
|
|
if( behaviour == MBEHAV::CAST_OFF_SUCCESS );
|
|
|
|
{
|
|
|
|
CAIEntityPhysical *target=player->getVisualTarget();
|
|
|
|
if (target)
|
|
|
|
player->setTarget(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/ DataSet->getNextChangedValue( entityIndex, propIndex );
|
|
|
|
}
|
|
|
|
DataSet->endChangedValues();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::release()
|
|
|
|
{
|
|
|
|
Mirror.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CMirrors::mirrorIsReady()
|
|
|
|
{
|
|
|
|
return Mirror.mirrorIsReady();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------------
|
|
|
|
// Methods for retrieving data from mirrors
|
|
|
|
|
|
|
|
TDataSetRow CMirrors::createEntity( CEntityId& entityId )
|
|
|
|
{
|
|
|
|
// in ais, we always use entityId auto asigment by mirror
|
|
|
|
if (Mirror.createEntity( entityId , true))
|
|
|
|
return DataSet->getDataSetRow( entityId );
|
|
|
|
else
|
|
|
|
return TDataSetRow();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMirrors::declareEntity( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
DataSet->declareEntity( entityIndex ); // only in the main dataset
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMirrors::removeEntity( const CEntityId& entityId )
|
|
|
|
{
|
|
|
|
Mirror.removeEntity( entityId );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CMirrors::exists( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
/// is that a bug??
|
|
|
|
return DataSet->getEntityId( entityIndex ).asUint64() == 0;
|
|
|
|
//return ! ((uint64)(DataSet->getEntityId( entityIndex )) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
const NLMISC::CEntityId& CMirrors::getEntityId( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
return DataSet->getEntityId( entityIndex );
|
|
|
|
}
|
|
|
|
|
|
|
|
TDataSetRow CMirrors::getDataSetRow( const NLMISC::CEntityId& entityId )
|
|
|
|
{
|
|
|
|
return DataSet->getDataSetRow( entityId );
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 CMirrors::getTeamId(const TDataSetRow& entityIndex)
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_TEAM_ID> value( *DataSet, entityIndex, DSPropertyTEAM_ID );
|
|
|
|
// if ( value()==0 )
|
|
|
|
// return CTEAM::InvalidTeamId;
|
|
|
|
return value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CAICoord CMirrors::x( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_POSX> value( *DataSet, entityIndex, DSPropertyPOSX );
|
|
|
|
if ( value()==0 )
|
|
|
|
return CAICoord();
|
|
|
|
return CAICoord((double)value()/(double)1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
CAICoord CMirrors::y( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_POSY> value( *DataSet, entityIndex, DSPropertyPOSY );
|
|
|
|
if ( value()==0 )
|
|
|
|
return CAICoord();
|
|
|
|
return CAICoord((double)value()/(double)1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
sint32 CMirrors::z( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_POSZ> value( *DataSet, entityIndex, DSPropertyPOSZ );
|
|
|
|
return value();
|
|
|
|
}
|
|
|
|
|
|
|
|
float CMirrors::theta( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_ORIENTATION> value( *DataSet, entityIndex, DSPropertyORIENTATION );
|
|
|
|
return value();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMirrors::setPosAndTheta( const TDataSetRow& entityIndex, sint32 posX, sint32 posY, sint32 posZ, float angleRad )
|
|
|
|
{
|
|
|
|
#ifdef NL_DEBUG
|
|
|
|
//nldebug( "%d: E%d: Setting pos to %d %d", CTickEventHandler::getGameCycle(), entityIndex, posX, posY );
|
|
|
|
/*if ( posX == 0 )
|
|
|
|
nldebug( "E%d: X is zero", entityIndex );
|
|
|
|
if ( posY == 0 )
|
|
|
|
nldebug( "E%d: Y is zero", entityIndex );*/
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CMirrorPropValue<TYPE_POSX> valueX( *DataSet, entityIndex, DSPropertyPOSX );
|
|
|
|
CMirrorPropValue<TYPE_POSY> valueY( *DataSet, entityIndex, DSPropertyPOSY );
|
|
|
|
CMirrorPropValue<TYPE_POSZ> valueZ( *DataSet, entityIndex, DSPropertyPOSZ );
|
|
|
|
CMirrorPropValue<TYPE_ORIENTATION> valueT( *DataSet, entityIndex, DSPropertyORIENTATION );
|
|
|
|
valueX = posX;
|
|
|
|
valueY = posY;
|
|
|
|
valueZ = posZ;
|
|
|
|
valueT = angleRad;
|
|
|
|
//nldebug( "%u: Pos&theta of E%d set", CTickEventHandler::getGameCycle(), entityIndex );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMirrors::setTheta( const TDataSetRow& entityIndex, float angleRad )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<TYPE_ORIENTATION> valueT( *DataSet, entityIndex, DSPropertyORIENTATION );
|
|
|
|
valueT = angleRad;
|
|
|
|
//nldebug( "%u: Theta of E%d set", CTickEventHandler::getGameCycle(), entityIndex );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NLMISC::CSheetId CMirrors::sheet( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_SHEET> value( *DataSet, entityIndex, DSPropertySHEET );
|
|
|
|
return NLMISC::CSheetId(value());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::initSheet( const TDataSetRow& entityIndex, const NLMISC::CSheetId& sheetId )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<TYPE_SHEET> value( *DataSet, entityIndex, DSPropertySHEET );
|
|
|
|
value = sheetId.asInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
NLMISC::CSheetId CMirrors::sheetServer( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_SHEET> value( *DataSet, entityIndex, DSPropertySHEET_SERVER );
|
|
|
|
return NLMISC::CSheetId(value());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::initSheetServer( const TDataSetRow& entityIndex, const NLMISC::CSheetId& sheetId )
|
|
|
|
{
|
|
|
|
nlassert(sheetId != NLMISC::CSheetId::Unknown);
|
|
|
|
CMirrorPropValue<TYPE_SHEET> value( *DataSet, entityIndex, DSPropertySHEET_SERVER );
|
|
|
|
value = sheetId.asInt();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::initNPCAlias( const TDataSetRow& entityIndex, TAIAlias alias )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<TYPE_ALIAS> value( *DataSet, entityIndex, DSPropertyNPC_ALIAS );
|
|
|
|
value = alias;
|
|
|
|
}
|
|
|
|
|
|
|
|
TDataSetRow CMirrors::target( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_TARGET_ID> value( *DataSet, entityIndex, DSPropertyTARGET_ID );
|
|
|
|
return value();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::setVPA( const TDataSetRow& entityIndex, const SAltLookProp &prop )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<SAltLookProp> value( *DataSet, entityIndex, DSPropertyVPA );
|
|
|
|
value = prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::setVisualPropertyA( const TDataSetRow& entityIndex, const SPropVisualA &prop )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<SPropVisualA> value( *DataSet, entityIndex, DSPropertyVPA );
|
|
|
|
value = prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::setVisualPropertyB( const TDataSetRow& entityIndex, const SPropVisualB &prop )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<SPropVisualB> value( *DataSet, entityIndex, DSPropertyVPB );
|
|
|
|
value = prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::setVisualPropertyC( const TDataSetRow& entityIndex, const SPropVisualC &prop )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<SPropVisualC> value( *DataSet, entityIndex, DSPropertyVPC );
|
|
|
|
value = prop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMirrors::setBehaviour( const TDataSetRow& entityIndex, MBEHAV::EBehaviour b )
|
|
|
|
{
|
|
|
|
CMirrorPropValue<MBEHAV::CBehaviour> value( *DataSet, entityIndex, DSPropertyBEHAVIOUR );
|
|
|
|
value = b;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CMirrors::bestRoleLevel( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
CMirrorPropValueRO<TYPE_BEST_ROLE_LEVEL> value( *DataSet, entityIndex, DSPropertyBEST_ROLE_LEVEL );
|
|
|
|
return value();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64 CMirrors::whoSeesMe( const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
BOMB_IF( !DataSet->isAccessible(entityIndex), "Try to access to the WhoSeesMe property in the mirror but with an invalid ", return 0L);
|
|
|
|
CMirrorPropValueRO<TYPE_WHO_SEES_ME> value( *DataSet, entityIndex, DSPropertyWHO_SEES_ME );
|
|
|
|
return value();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set target (row)
|
|
|
|
*/
|
|
|
|
void CMirrors::setTarget(const TDataSetRow& entityIndex, const TDataSetRow& target)
|
|
|
|
{
|
|
|
|
CMirrorPropValue<TYPE_TARGET_ID> value( *DataSet, entityIndex, DSPropertyTARGET_ID );
|
|
|
|
value = target;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// :KLUDGE: This method implementation should be in game_share instead of AIS and EGS. Both me and the other one are lazy bastards.
|
|
|
|
void MBEHAV::TMode::setModeAndPos( EMode mode, const TDataSetRow& entityIndex )
|
|
|
|
{
|
|
|
|
Mode = mode;
|
|
|
|
CMirrorPropValueRO<TYPE_POSX> propX( TheDataset, entityIndex, DSPropertyPOSX );
|
|
|
|
Pos.X16 = (uint16)(propX() >> 4);
|
|
|
|
CMirrorPropValueRO<TYPE_POSY> propY( TheDataset, entityIndex, DSPropertyPOSY );
|
|
|
|
Pos.Y16 = (uint16)(propY() >> 4);
|
|
|
|
//nldebug( "Setting MODE %s for E%u with current pos %d, %d", modeToString( mode ).c_str(), entityIndex.getIndex(), propX(), propY() );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "event_reaction_include.h"
|