1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "game_share/tick_event_handler.h"
26 #include "nel/net/service.h"
27 #include "game_share/misc_const.h"
28 #include "game_share/fame.h"
29 #include "ai_bot_npc.h"
30 #include "ai_grp_npc.h"
31 #include "server_share/r2_variables.h"
32 #include "server_share/r2_vision.h"
36 #include "ai_player.h"
39 using namespace NLMISC
;
40 using namespace NLNET
;
41 using namespace MBEHAV
;
43 CMirror
CMirrors::Mirror
;
44 CMirroredDataSet
*CMirrors::DataSet
= NULL
;
45 CMirroredDataSet
*CMirrors::FameDataSet
= NULL
;
47 const uint MAX_NB_ENTITIES_ISOLATED
= 25000;
48 CEntityId
*IsolatedEntityId
= NULL
;
49 sint32
*IsolatedX
= NULL
;
50 sint32
*IsolatedY
= NULL
;
51 sint32
*IsolatedZ
= NULL
;
52 float *IsolatedTheta
= NULL
;
53 uint32
*IsolatedSheet
= NULL
;
54 uint32
*IsolatedSheetServer
= NULL
;
55 TDataSetRow
*IsolatedTarget
= NULL
; // sint32
56 uint32
*IsolatedMode
= NULL
; // only mode enum
57 uint32
*IsolatedBehaviour
= NULL
;
58 uint32
*IsolatedCurrentHitPoints
= NULL
;
59 uint32
*IsolatedMaxHitPoints
= NULL
;
60 uint32
*IsolatedBestRoleLevel
= NULL
;
61 uint8
*IsolatedCombatState
= NULL
;
63 extern CVariable
<double> RingMaxSelectDist
;
68 void cbMirrorIsReady( CMirror
*mirror
)
70 CMirrors::initMirror();
73 void cbMirrorReadyForAddEntity( CMirror
*mirror
)
77 const TDeclaredEntityRangeOfType
& declERT
= TheDataset
.getDeclaredEntityRanges();
79 TDeclaredEntityRangeOfType::const_iterator it
= declERT
.find( RYZOMID::fx_entity
);
80 const TDeclaredEntityRange
& range
= GET_ENTITY_TYPE_RANGE(it
);
81 CFxEntityManager::getInstance()->init( range
.baseIndex(), range
.size() );
86 #define initIsolatedPropTable( name, thetype, defaultvalue ) \
87 name = new thetype [MAX_NB_ENTITIES_ISOLATED]; \
88 for ( i=0; i!=MAX_NB_ENTITIES_ISOLATED; ++i ) \
89 name[i] = defaultvalue
94 void CMirrors::init( void (*cbUpdate
)(), void (*cbSync
)(), void (*cbRelease
)() )
96 // Init the mirror system
97 vector
<string
> datasetNames
;
98 datasetNames
.push_back( "fe_temp" );
99 datasetNames
.push_back( "fame" );
100 Mirror
.init( datasetNames
, cbMirrorIsReady
, cbUpdate
, cbSync
, cbRelease
, AISTag
);
101 Mirror
.addCallbackWhenMirrorReadyForUse( cbMirrorReadyForAddEntity
);
106 * Init after the mirror init
108 void CMirrors::initMirror()
110 //Mirror.declareEntityTypeUser( RYZOMID::player );
112 Mirror
.declareEntityTypeOwner( RYZOMID::npc
, TotalMaxNpc
.get() );
113 Mirror
.declareEntityTypeOwner( RYZOMID::creature
, TotalMaxFauna
.get()+TotalMaxPet
.get() );
114 Mirror
.declareEntityTypeOwner( RYZOMID::fx_entity
, TotalMaxFx
);
116 DataSet
= &(Mirror
.getDataSet("fe_temp"));
117 DataSet
->declareProperty( "AIInstance", PSOReadWrite
| PSONotifyChanges
);
118 DataSet
->declareProperty( "X", PSOReadWrite
| PSONotifyChanges
);
119 DataSet
->declareProperty( "Y", PSOReadWrite
| PSONotifyChanges
);
120 DataSet
->declareProperty( "Z", PSOReadWrite
);
121 DataSet
->declareProperty( "Theta", PSOReadWrite
);
122 DataSet
->declareProperty( "Sheet", PSOReadWrite
);
123 DataSet
->declareProperty( "SheetServer", PSOReadWrite
);
124 DataSet
->declareProperty( "NPCAlias", PSOWriteOnly
);
125 DataSet
->declareProperty( "Mode", PSOReadWrite
| PSONotifyChanges
);
126 DataSet
->declareProperty( "Behaviour", PSOReadWrite
| PSONotifyChanges
);
127 DataSet
->declareProperty( "Target", PSOReadWrite
| PSONotifyChanges
);
128 DataSet
->declareProperty( "CurrentHitPoints", PSOReadOnly
);
129 DataSet
->declareProperty( "CurrentRunSpeed", PSOReadOnly
);
130 DataSet
->declareProperty( "CurrentWalkSpeed", PSOReadOnly
);
131 DataSet
->declareProperty( "MaxHitPoints", PSOReadOnly
);
132 DataSet
->declareProperty( "BestRoleLevel", PSOReadOnly
);
133 DataSet
->declareProperty( "CombatState", PSOReadOnly
);
134 DataSet
->declareProperty( "TeamId", PSOReadOnly
| PSONotifyChanges
);
135 DataSet
->declareProperty( "InOutpostZoneAlias", PSOReadWrite
);
136 DataSet
->declareProperty( "InOutpostZoneSide", PSOReadWrite
);
137 DataSet
->declareProperty( "VisualPropertyA", PSOReadWrite
);
138 DataSet
->declareProperty( "VisualPropertyB", PSOReadWrite
);
139 DataSet
->declareProperty( "VisualPropertyC", PSOReadWrite
);
140 DataSet
->declareProperty( "ActionFlags", PSOReadWrite
);
141 DataSet
->declareProperty( "VisionCounter", PSOReadOnly
);
142 DataSet
->declareProperty( "Fuel", PSOReadOnly
);
143 DataSet
->declareProperty( "WhoSeesMe", PSOReadWrite
);
144 DataSet
->declareProperty( "ContextualProperty", PSOReadWrite
);
146 initRyzomVisualPropertyIndices( *DataSet
);
149 FameDataSet
= &(Mirror
.getDataSet("fame"));
150 CFameInterface::getInstance().setFameDataSet(FameDataSet
);
152 Mirror
.setNotificationCallback( CMirrors::processMirrorUpdates
);
155 // a big bad global var !
156 extern CAIEntityPhysical
*TempSpeaker
;
157 extern CBotPlayer
*TempPlayer
;
160 void CMirrors::processMirrorUpdates()
162 TDataSetRow entityIndex
;
163 CEntityId
*pEntityId
;
165 CFameInterface
&fi
= CFameInterface::getInstance();
167 // Process added entities
168 DataSet
->beginAddedEntities();
169 while ((entityIndex
= DataSet
->getNextAddedEntity()) != LAST_CHANGED
)
171 const CEntityId
& entityId
= DataSet
->getEntityId(entityIndex
);
173 // Create CAIPlayer object and add to maps
174 if (entityId
.getType() != RYZOMID::player
)
178 CMirrorPropValue
<uint32
> _instanceNumber(*DataSet
, entityIndex
, DSPropertyAI_INSTANCE
);
179 const uint32 askedInstance
=_instanceNumber();
180 CAIInstance
*const aii
= CAIS::instance().getAIInstance(askedInstance
);
184 // The player is not in an AIInstance of that ais.
185 // Floods on player connections, so no warning
186 // nlwarning("AIInstance %d not found to spawn player %s", askedInstance, entityId.toString().c_str());
187 // FOREACH(it,CCont<CAIInstance>, CAIS::instance().AIList())
189 // nlwarning("exist AIInstance %d at index %d", (*it)->getInstanceNumber(), (*it)->getIndex());
193 // store the player in the correct instance.
194 aii
->getPlayerMgr()->addSpawnedPlayer(entityIndex
, entityId
);
198 DataSet
->endAddedEntities();
200 FameDataSet
->beginAddedEntities();
201 while( (entityIndex
= FameDataSet
->getNextAddedEntity()) != LAST_CHANGED
)
203 fi
.createFameOwner(*FameDataSet
, entityIndex
);
205 FameDataSet
->endAddedEntities();
207 // Process removed entities
208 DataSet
->beginRemovedEntities();
209 while( (entityIndex
= DataSet
->getNextRemovedEntity(&pEntityId
)) != LAST_CHANGED
)
211 CAIEntityPhysical
*entityPhysPtr
= CAIS::instance().getEntityPhysical(entityIndex
);
212 // just to check if its a player .. and remove it from Manager and Maps ..
214 && entityPhysPtr
->getRyzomType()==RYZOMID::player
)
216 CBotPlayer
*botPlayer
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhysPtr
);
217 botPlayer
->getOwner()->removeDespawnedPlayer(entityIndex
);
221 DataSet
->endRemovedEntities();
223 FameDataSet
->beginRemovedEntities();
224 while( (entityIndex
= FameDataSet
->getNextRemovedEntity(&pEntityId
)) != LAST_CHANGED
)
226 fi
.removeFameOwner(*FameDataSet
, entityIndex
);
228 FameDataSet
->endRemovedEntities();
230 // Process properties changed and notified in the mirror
231 TPropertyIndex propIndex
;
232 DataSet
->beginChangedValues();
233 DataSet
->getNextChangedValue( entityIndex
, propIndex
);
234 while (entityIndex
!= LAST_CHANGED
)
236 if (propIndex
== DSPropertyPOSX
|| propIndex
== DSPropertyPOSY
)
238 const CEntityId
&entityId
=DataSet
->getEntityId(entityIndex
);
239 if (entityId
.getType() == RYZOMID::player
)
241 CAIEntityPhysical
*entityPhys
=CAIS::instance().getEntityPhysical(entityIndex
);
244 CBotPlayer
*player
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhys
);
247 CAIInstance
* aiInstance
= player
->getAIInstance();
248 aiInstance
->updateZoneTrigger(player
);
253 else if (propIndex
== DSPropertyTEAM_ID
)
255 const CEntityId
&entityId
=DataSet
->getEntityId(entityIndex
);
256 if (entityId
.getType() == RYZOMID::player
)
258 CAIEntityPhysical
*entityPhys
=CAIS::instance().getEntityPhysical(entityIndex
);
261 CBotPlayer
*player
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhys
);
263 player
->getOwner()->updatePlayerTeam(entityIndex
);
269 else if (propIndex
== DSPropertyAI_INSTANCE
)
271 const CEntityId
&entityId
=DataSet
->getEntityId(entityIndex
);
272 if (entityId
.getType() == RYZOMID::player
)
274 CAIEntityPhysical
*entityPhys
=CAIS::instance().getEntityPhysical(entityIndex
);
277 // this player is already in a manager, despawn it
278 CBotPlayer
*const botPlayer
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhys
);
279 botPlayer
->getOwner()->removeDespawnedPlayer(entityIndex
);
282 // could be done with mirrored values. (!?).
283 CMirrorPropValue
<uint32
> _instanceNumber(*DataSet
, entityIndex
, DSPropertyAI_INSTANCE
);
284 const uint32 askedInstance
=_instanceNumber();
286 CAIInstance
*aii
= CAIS::instance().getAIInstance(askedInstance
);
290 // store the player in the correct instance.
291 aii
->getPlayerMgr()->addSpawnedPlayer(entityIndex
, entityId
);
295 if (askedInstance
!=std::numeric_limits
<uint32
>::max())
297 // no need to warn for ai number instance not in this AIS !
298 // nlwarning("AIInstance %u not found on AIInstance changement for player %s", askedInstance, entityId.toString().c_str());
299 // FOREACH(it,CCont<CAIInstance>, CAIS::instance().AIList())
301 // nlwarning("exist AIInstance %d at index %d", (*it)->getInstanceNumber(), (*it)->getIndex());
307 else if (propIndex
== DSPropertyTARGET_ID
)
309 CAIEntityPhysical
*entityPhys
=CAIS::instance().getEntityPhysical(entityIndex
);
312 const CEntityId
&entityId
=DataSet
->getEntityId(entityIndex
);
313 if (entityId
.getType() == RYZOMID::player
)
315 CBotPlayer
*player
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhys
);
317 // check if target is a local npc bot then handle bot targeted event
318 CMirrorPropValueRO
<TYPE_TARGET_ID
> tgt(TheDataset
, entityIndex
, DSPropertyTARGET_ID
);
319 CAIEntityPhysical
*target
= CAIS::instance().getEntityPhysical(tgt());
321 // update the targering list
322 if (entityIndex
==TDataSetRow()) // no target.
324 player
->setTarget(NULL
);
328 if (player
->isAggressive())
330 CAIEntityPhysical
*oldTarget
=player
->getTarget();
332 || oldTarget
!=target
)
333 player
->setTarget(target
);
337 CAIEntityPhysical
*oldTarget
=player
->getVisualTarget();
339 || oldTarget
!=target
)
340 player
->setVisualTarget(target
);
344 CSpawnBotNpc
*bnpc
= dynamic_cast<CSpawnBotNpc
*>(target
);
349 CGroupNpc
&grpNpc
= bnpc
->getPersistent().grp();
355 CAIPos
playerPos(player
->pos());
356 CAIPos
npcPos(bnpc
->pos());
357 double dist
= npcPos
.quickDistTo(playerPos
);
360 uint64 whoSeesMe
= CMirrors::whoSeesMe(player
->dataSetRow());
361 if (!R2_VISION::isEntityVisibleToPlayers(whoSeesMe
))
363 // The player is invisible, its a Dm / Gm: no zone event must be triggered
367 if (!dm
&& dist
<= RingMaxSelectDist
)
369 grpNpc
.processStateEvent(grpNpc
.getEventContainer().EventPlayerTargetNpc
);
374 // generate en event on this bot group
375 grpNpc
.processStateEvent(grpNpc
.getEventContainer().EventPlayerTargetNpc
);
380 // grpNpc.processStateEvent(grpNpc.getEventContainer().EventPlayerTargetNpc);
381 // grpNpc.getEventContainer().EventPlayerTargetNpc.processStateEvent(&grpNpc);
383 // if player is in follow mode, then generate an suplementary event
384 if (player
->getFollowMode())
385 grpNpc
.processStateEvent(grpNpc
.getEventContainer().EventPlayerFollowNpc
);
386 // grpNpc.getEventContainer().EventPlayerFollowNpc.processStateEvent(&grpNpc);
394 else if (propIndex
== DSPropertyMODE
)
396 CAIEntityPhysical
*entityPhys
=CAIS::instance().getEntityPhysical(entityIndex
);
399 const CEntityId
&entityId
=DataSet
->getEntityId(entityIndex
);
400 if (entityId
.getType() == RYZOMID::player
)
402 CBotPlayer
*player
=NLMISC::safe_cast
<CBotPlayer
*>(entityPhys
);
404 // if the player have a target, move it to the correct target list.
406 if (player
->isAggressive())
408 CAIEntityPhysical
*target
=player
->getVisualTarget();
410 player
->setTarget(target
);
414 CAIEntityPhysical
*target
=player
->getTarget();
416 player
->setVisualTarget(target
);
421 /* else if (propIndex == DSPropertyBEHAVIOUR)
423 CAIEntityPhysical *entityPhys=CAIS::instance().getEntityPhysical(entityIndex);
426 const CEntityId &entityId=DataSet->getEntityId(entityIndex);
427 if (entityId.getType() == RYZOMID::player)
429 CBotPlayer *player=NLMISC::safe_cast<CBotPlayer*>(entityPhys);
431 MBEHAV::EBehaviour const behaviour = player->getBehaviour();
432 if( behaviour == MBEHAV::CAST_OFF_SUCCESS );
434 CAIEntityPhysical *target=player->getVisualTarget();
436 player->setTarget(target);
441 */ DataSet
->getNextChangedValue( entityIndex
, propIndex
);
443 DataSet
->endChangedValues();
446 void CMirrors::release()
452 bool CMirrors::mirrorIsReady()
454 return Mirror
.mirrorIsReady();
458 //---------------------------------------------------------------------------------
459 // Methods for retrieving data from mirrors
461 TDataSetRow
CMirrors::createEntity( CEntityId
& entityId
)
463 // in ais, we always use entityId auto asigment by mirror
464 if (Mirror
.createEntity( entityId
, true))
465 return DataSet
->getDataSetRow( entityId
);
467 return TDataSetRow();
471 void CMirrors::declareEntity( const TDataSetRow
& entityIndex
)
473 DataSet
->declareEntity( entityIndex
); // only in the main dataset
477 void CMirrors::removeEntity( const CEntityId
& entityId
)
479 Mirror
.removeEntity( entityId
);
483 bool CMirrors::exists( const TDataSetRow
& entityIndex
)
486 return DataSet
->getEntityId( entityIndex
).asUint64() == 0;
487 //return ! ((uint64)(DataSet->getEntityId( entityIndex )) != 0);
490 const NLMISC::CEntityId
& CMirrors::getEntityId( const TDataSetRow
& entityIndex
)
492 return DataSet
->getEntityId( entityIndex
);
495 TDataSetRow
CMirrors::getDataSetRow( const NLMISC::CEntityId
& entityId
)
497 return DataSet
->getDataSetRow( entityId
);
500 uint16
CMirrors::getTeamId(const TDataSetRow
& entityIndex
)
502 CMirrorPropValueRO
<TYPE_TEAM_ID
> value( *DataSet
, entityIndex
, DSPropertyTEAM_ID
);
504 // return CTEAM::InvalidTeamId;
510 CAICoord
CMirrors::x( const TDataSetRow
& entityIndex
)
512 CMirrorPropValueRO
<TYPE_POSX
> value( *DataSet
, entityIndex
, DSPropertyPOSX
);
515 return CAICoord((double)value()/(double)1000);
518 CAICoord
CMirrors::y( const TDataSetRow
& entityIndex
)
520 CMirrorPropValueRO
<TYPE_POSY
> value( *DataSet
, entityIndex
, DSPropertyPOSY
);
523 return CAICoord((double)value()/(double)1000);
526 sint32
CMirrors::z( const TDataSetRow
& entityIndex
)
528 CMirrorPropValueRO
<TYPE_POSZ
> value( *DataSet
, entityIndex
, DSPropertyPOSZ
);
532 float CMirrors::theta( const TDataSetRow
& entityIndex
)
534 CMirrorPropValueRO
<TYPE_ORIENTATION
> value( *DataSet
, entityIndex
, DSPropertyORIENTATION
);
539 void CMirrors::setPosAndTheta( const TDataSetRow
& entityIndex
, sint32 posX
, sint32 posY
, sint32 posZ
, float angleRad
)
542 //nldebug( "%d: E%d: Setting pos to %d %d", CTickEventHandler::getGameCycle(), entityIndex, posX, posY );
544 nldebug( "E%d: X is zero", entityIndex );
546 nldebug( "E%d: Y is zero", entityIndex );*/
549 CMirrorPropValue
<TYPE_POSX
> valueX( *DataSet
, entityIndex
, DSPropertyPOSX
);
550 CMirrorPropValue
<TYPE_POSY
> valueY( *DataSet
, entityIndex
, DSPropertyPOSY
);
551 CMirrorPropValue
<TYPE_POSZ
> valueZ( *DataSet
, entityIndex
, DSPropertyPOSZ
);
552 CMirrorPropValue
<TYPE_ORIENTATION
> valueT( *DataSet
, entityIndex
, DSPropertyORIENTATION
);
557 //nldebug( "%u: Pos&theta of E%d set", CTickEventHandler::getGameCycle(), entityIndex );
561 void CMirrors::setTheta( const TDataSetRow
& entityIndex
, float angleRad
)
563 CMirrorPropValue
<TYPE_ORIENTATION
> valueT( *DataSet
, entityIndex
, DSPropertyORIENTATION
);
565 //nldebug( "%u: Theta of E%d set", CTickEventHandler::getGameCycle(), entityIndex );
569 NLMISC::CSheetId
CMirrors::sheet( const TDataSetRow
& entityIndex
)
571 CMirrorPropValueRO
<TYPE_SHEET
> value( *DataSet
, entityIndex
, DSPropertySHEET
);
572 return NLMISC::CSheetId(value());
575 void CMirrors::initSheet( const TDataSetRow
& entityIndex
, const NLMISC::CSheetId
& sheetId
)
577 CMirrorPropValue
<TYPE_SHEET
> value( *DataSet
, entityIndex
, DSPropertySHEET
);
578 value
= sheetId
.asInt();
581 NLMISC::CSheetId
CMirrors::sheetServer( const TDataSetRow
& entityIndex
)
583 CMirrorPropValueRO
<TYPE_SHEET
> value( *DataSet
, entityIndex
, DSPropertySHEET_SERVER
);
584 return NLMISC::CSheetId(value());
587 void CMirrors::initSheetServer( const TDataSetRow
& entityIndex
, const NLMISC::CSheetId
& sheetId
)
589 nlassert(sheetId
!= NLMISC::CSheetId::Unknown
);
590 CMirrorPropValue
<TYPE_SHEET
> value( *DataSet
, entityIndex
, DSPropertySHEET_SERVER
);
591 value
= sheetId
.asInt();
594 void CMirrors::initNPCAlias( const TDataSetRow
& entityIndex
, TAIAlias alias
)
596 CMirrorPropValue
<TYPE_ALIAS
> value( *DataSet
, entityIndex
, DSPropertyNPC_ALIAS
);
600 TDataSetRow
CMirrors::target( const TDataSetRow
& entityIndex
)
602 CMirrorPropValueRO
<TYPE_TARGET_ID
> value( *DataSet
, entityIndex
, DSPropertyTARGET_ID
);
606 void CMirrors::setVPA( const TDataSetRow
& entityIndex
, const SAltLookProp
&prop
)
608 CMirrorPropValue
<SAltLookProp
> value( *DataSet
, entityIndex
, DSPropertyVPA
);
612 void CMirrors::setVisualPropertyA( const TDataSetRow
& entityIndex
, const SPropVisualA
&prop
)
614 CMirrorPropValue
<SPropVisualA
> value( *DataSet
, entityIndex
, DSPropertyVPA
);
618 void CMirrors::setVisualPropertyB( const TDataSetRow
& entityIndex
, const SPropVisualB
&prop
)
620 CMirrorPropValue
<SPropVisualB
> value( *DataSet
, entityIndex
, DSPropertyVPB
);
624 void CMirrors::setVisualPropertyC( const TDataSetRow
& entityIndex
, const SPropVisualC
&prop
)
626 CMirrorPropValue
<SPropVisualC
> value( *DataSet
, entityIndex
, DSPropertyVPC
);
630 void CMirrors::setBehaviour( const TDataSetRow
& entityIndex
, MBEHAV::EBehaviour b
)
632 CMirrorPropValue
<MBEHAV::CBehaviour
> value( *DataSet
, entityIndex
, DSPropertyBEHAVIOUR
);
636 uint32
CMirrors::bestRoleLevel( const TDataSetRow
& entityIndex
)
638 CMirrorPropValueRO
<TYPE_BEST_ROLE_LEVEL
> value( *DataSet
, entityIndex
, DSPropertyBEST_ROLE_LEVEL
);
642 uint64
CMirrors::whoSeesMe( const TDataSetRow
& entityIndex
)
644 BOMB_IF( !DataSet
->isAccessible(entityIndex
), "Try to access to the WhoSeesMe property in the mirror but with an invalid ", return 0L);
645 CMirrorPropValueRO
<TYPE_WHO_SEES_ME
> value( *DataSet
, entityIndex
, DSPropertyWHO_SEES_ME
);
652 void CMirrors::setTarget(const TDataSetRow
& entityIndex
, const TDataSetRow
& target
)
654 CMirrorPropValue
<TYPE_TARGET_ID
> value( *DataSet
, entityIndex
, DSPropertyTARGET_ID
);
658 /// :KLUDGE: This method implementation should be in game_share instead of AIS and EGS. Both me and the other one are lazy bastards.
659 void MBEHAV::TMode::setModeAndPos( EMode mode
, const TDataSetRow
& entityIndex
)
662 CMirrorPropValueRO
<TYPE_POSX
> propX( TheDataset
, entityIndex
, DSPropertyPOSX
);
663 Pos
.X16
= (uint16
)(propX() >> 4);
664 CMirrorPropValueRO
<TYPE_POSY
> propY( TheDataset
, entityIndex
, DSPropertyPOSY
);
665 Pos
.Y16
= (uint16
)(propY() >> 4);
666 //nldebug( "Setting MODE %s for E%u with current pos %d, %d", modeToString( mode ).c_str(), entityIndex.getIndex(), propX(), propY() );
669 #include "event_reaction_include.h"