1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2012 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
7 // Copyright (C) 2013-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
9 // This program is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU Affero General Public License as
11 // published by the Free Software Foundation, either version 3 of the
12 // License, or (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU Affero General Public License for more details.
19 // You should have received a copy of the GNU Affero General Public License
20 // along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "client_sheets/item_sheet.h"
32 #include "nel/misc/vectord.h"
33 #include "nel/misc/vector_2f.h"
34 #include "nel/misc/bsphere.h"
36 #include "nel/3d/u_driver.h"
37 #include "nel/3d/u_scene.h"
38 #include "nel/3d/u_material.h"
39 #include "nel/3d/u_visual_collision_manager.h"
40 #include "nel/3d/u_play_list.h"
41 #include "nel/3d/u_animation_set.h"
42 #include "nel/3d/u_bone.h"
43 #include "nel/3d/u_track.h"
44 #include "nel/3d/u_instance_material.h"
45 #include "nel/3d/material.h" // for advanced material usage
47 #include "nel/pacs/u_global_position.h"
49 #include "entity_cl.h"
50 #include "entity_animation_manager.h"
51 #include "pacs_client.h"
52 #include "ig_client.h"
53 #include "debug_client.h"
54 #include "time_client.h"
56 #include "ingame_database_manager.h"
57 #include "debug_client.h"
59 #include "client_cfg.h"
60 #include "nel/gui/action_handler.h"
61 #include "interface_v3/interface_manager.h"
62 #include "nel/gui/group_container.h"
63 #include "interface_v3/guild_manager.h"
64 #include "interface_v3/skill_manager.h"
65 #include "user_entity.h"
66 #include "interface_v3/people_interraction.h"
68 #include "color_slot_manager.h"
69 #include "string_manager_client.h"
70 #include "interface_v3/bar_manager.h"
71 #include "continent_manager.h"
72 #include "connection.h"
76 #include "game_share/mission_desc.h"
77 #include "game_share/inventories.h"
78 #include "game_share/animal_type.h"
79 #include "interface_v3/group_in_scene.h"
81 #include "r2/editor.h"
86 using namespace NLMISC
;
88 using namespace NLPACS
;
90 using namespace CLFECOMMON
;
97 extern UDriver
*Driver
;
99 extern UVisualCollisionManager
*CollisionManager
;
100 extern CEntityAnimationManager
*EAM
;
101 extern UCamera MainCam
;
102 extern UTextContext
*TextContext
;
103 extern CLFECOMMON::TCLEntityId SlotUnderCursor
;
104 extern CContinentManager ContinentMngr
;
105 extern bool ShowInterface
;
112 #define RYZOM_EPSILON_SQRT_POSITION (1.f*1.f)
113 NLMISC::CRGBA
CEntityCL::_EntitiesColor
[TypeCount
];
114 NLMISC::CRGBA
CEntityCL::_DeadColor
;
115 NLMISC::CRGBA
CEntityCL::_TargetColor
;
116 NLMISC::CRGBA
CEntityCL::_GroupColor
;
117 NLMISC::CRGBA
CEntityCL::_GuildColor
;
118 NLMISC::CRGBA
CEntityCL::_UserMountColor
;
119 NLMISC::CRGBA
CEntityCL::_UserPackAnimalColor
;
120 NLMISC::CRGBA
CEntityCL::_PvpEnemyColor
;
121 NLMISC::CRGBA
CEntityCL::_PvpNeutralColor
;
122 NLMISC::CRGBA
CEntityCL::_PvpAllyInTeamColor
;
123 NLMISC::CRGBA
CEntityCL::_PvpAllyInLeagueColor
;
124 NLMISC::CRGBA
CEntityCL::_PvpAllyColor
;
125 NLMISC::CRGBA
CEntityCL::_GMTitleColor
[CHARACTER_TITLE::EndGmTitle
- CHARACTER_TITLE::BeginGmTitle
+ 1];
126 uint8
CEntityCL::_InvalidGMTitleCode
= 0xFF;
127 NLMISC::CRefPtr
<CCDBNodeLeaf
> CEntityCL::_OpacityMinNodeLeaf
;
128 NLMISC::CRefPtr
<CCDBNodeLeaf
> CEntityCL::_ShowReticleLeaf
;
132 extern void contextHelp (const std::string
&help
);
139 //-----------------------------------------------
142 //-----------------------------------------------
143 void CEntityCL::SInstanceCL::showStaticFXs()
145 for(std::vector
<UInstance
>::iterator it
= StaticFXs
.begin(); it
!= StaticFXs
.end(); ++it
)
153 } // showStaticFXs //
156 //-----------------------------------------------
159 //-----------------------------------------------
160 void CEntityCL::SInstanceCL::hideStaticFXs()
162 for(std::vector
<UInstance
>::iterator it
= StaticFXs
.begin(); it
!= StaticFXs
.end(); ++it
)
170 } // hideStaticFXs //
173 //---------------------------------------------------
174 //---------------------------------------------------
175 bool CEntityCL::SInstanceCL::createLoading(const string
&strShapeName
, const string
&strStickPoint
, sint texture
, bool clearIfFail
)
177 // create the new instance
179 if(!strShapeName
.empty())
181 newInst
= Scene
->createInstance(strShapeName
);
182 // if fails to create and not clearIfFail, return
183 if(newInst
.empty() && !clearIfFail
)
187 // Remove the old loading instance.
190 Scene
->deleteInstance(Loading
);
194 // if the new instance is NULL, then clean ALL
195 if( newInst
.empty() )
200 Scene
->deleteInstance(Current
);
204 // else setup into loading
208 LoadingName
= strShapeName
;
209 TextureSet
= texture
;
210 StickPoint
= strStickPoint
;
213 // Select the texture.
216 // Set the right texture variation.
217 Loading
.selectTextureSet((uint
) texture
);
221 Loading
.selectTextureSet(computeCurrSeason());
224 // Set Scale (relatively from scale exported by artists)
225 Loading
.setRelativeScale(_Scale
);
227 // Set async loading Texture Mode (faster loading)
228 Loading
.enableAsyncTextureMode(true);
231 // ok only if instance created or if shapeName empty
232 return !newInst
.empty() || strShapeName
.empty();
235 //---------------------------------------------------
236 //---------------------------------------------------
237 void CEntityCL::SInstanceCL::setColors(sint skin
, sint user
, sint hair
, sint eyes
)
247 //---------------------------------------------------
248 //---------------------------------------------------
249 void CEntityCL::SInstanceCL::setScale(const CVector
&scale
)
251 // Bkup for new created loading instances
254 // Set Scale to any created ones (relatively from scale exported by artists)
256 Current
.setRelativeScale(_Scale
);
258 Loading
.setRelativeScale(_Scale
);
261 //---------------------------------------------------
262 //---------------------------------------------------
263 NL3D::UInstance
CEntityCL::SInstanceCL::createLoadingFromCurrent()
265 if (!Loading
.empty()) return Loading
;
266 if (Current
.empty()) return NULL
;
268 createLoading(CurrentName
, StickPoint
, TextureSet
);
271 CColorSlotManager::TIntCouple array
[4];
273 array
[0].first
= (uint
)0; array
[0].second
= (uint
)ACSkin
;
275 array
[1].first
= (uint
)1; array
[1].second
= (uint
)ACUser
;
277 array
[2].first
= (uint
)2; array
[2].second
= (uint
)ACHair
;
279 array
[3].first
= (uint
)3; array
[3].second
= (uint
)ACEyes
;
280 if (!Loading
.empty())
281 ColorSlotManager
.setInstanceSlot(Loading
, array
, 4);
284 // TODO : there is probably a bug for FX here : if we want to create a loading instance from the
285 // current instance and there are some FXs binded to the current instance we have to :
286 // 1 - recreate them onto the loading instance
288 // 2 - unbind them from the current instance and rebind them to the loading instance
293 //---------------------------------------------------
294 void CEntityCL::SInstanceCL::releaseStaticFXs()
298 for(std::vector
<UInstance
>::iterator it
= StaticFXs
.begin(); it
!= StaticFXs
.end(); ++it
)
302 Scene
->deleteInstance(*it
);
309 //---------------------------------------------------
310 bool CEntityCL::isAsyncLoading() const
312 for(uint k
= 0; k
< _Instances
.size(); ++k
)
314 if (!_Instances
[k
].Loading
.empty()) return true;
320 void CEntityCL::SInstanceCL::selectTextureSet(uint8 value
, bool async
)
322 if (!Loading
.empty())
324 Loading
.selectTextureSet(value
);
326 else if (!Current
.empty())
328 Current
.enableAsyncTextureMode(async
);
329 Current
.selectTextureSet(value
);
332 // NB: async case for this function not tested yet!
333 Current
.startAsyncTextureLoading();
338 //---------------------------------------------------
339 void CEntityCL::SInstanceCL::updateCurrentFromLoading(NL3D::USkeleton Skeleton
)
341 if(Loading
.empty()) return;
345 if (!Current
.empty())
348 bShow
= (Current
.getVisibility() == UInstance::Show
);
351 // Delete current instances
352 if (!Current
.empty())
354 Scene
->deleteInstance(Current
);
359 // Assign loading to current
361 CurrentName
= LoadingName
;
366 // If there is a skeleton, bind the skin to the skeleton.
367 if(!Skeleton
.empty())
369 // No Stick Point, try to bind.
370 if(StickPoint
.empty())
372 if(!Skeleton
.bindSkin(Current
))
373 nlwarning("Cannot bind the skin %s to the skeleton in the slot.", CurrentName
.c_str());
375 // Try to Stick Object.
378 sint stickID
= Skeleton
.getBoneIdByName(StickPoint
);
380 Skeleton
.stickObject(Current
, stickID
);
382 nlwarning("Skeleton '%s' is missing bone '%s' for object attachment.", Skeleton
.getShapeName().c_str(), StickPoint
.c_str());
386 // Show current instance
389 if(KeepHiddenWhenLoaded
== false)
394 KeepHiddenWhenLoaded
= false;
400 if (FXItemSheet
&& Scene
)
402 uint numStaticFX
= FXItemSheet
->FX
.getNumStaticFX();
403 StaticFXs
.reserve(numStaticFX
);
404 for(uint k
= 0; k
< numStaticFX
; ++k
)
406 std::string boneName
= FXItemSheet
->FX
.getStaticFXBone(k
);
407 std::string name
= FXItemSheet
->FX
.getStaticFXName(k
);
408 if (!boneName
.empty() && !name
.empty())
410 sint boneID
= Skeleton
.getBoneIdByName(boneName
);
413 UInstance instance
= Scene
->createInstance(name
);
414 if (!instance
.empty())
416 instance
.setTransformMode(UTransform::DirectMatrix
);
418 mat
.setPos(FXItemSheet
->FX
.getStaticFXOffset(k
));
419 instance
.setMatrix(mat
);
420 Skeleton
.stickObject(instance
, boneID
);
421 StaticFXs
.push_back(instance
);
425 nlwarning("Can't create static fx %s sticked on bone %s", name
.c_str(), boneName
.c_str());
430 nlwarning("Can't find bone %s for static fx %s", boneName
.c_str(), name
.c_str());
437 //---------------------------------------------------
438 void CEntityCL::SInstanceCL::setEmissive(NLMISC::CRGBA emit
)
440 // Do it on both Loading and Current, to avoid any problem
444 for(uint i
=0;i
<2;i
++)
446 // test if instance is valid
447 UInstance inst
= insts
[i
];
450 UShape shape
= inst
.getShape();
453 uint numMats
= shape
.getNumMaterials();
456 if(numMats
!=inst
.getNumMaterials())
460 for(uint j
=0;j
<numMats
;j
++)
462 inst
.getMaterial(j
).setEmissive(emit
);
466 //---------------------------------------------------
467 void CEntityCL::SInstanceCL::restoreEmissive()
469 // Do it on both Loading and Current, to avoid any problem
473 for(uint i
=0;i
<2;i
++)
475 // test if instance is valid
476 UInstance inst
= insts
[i
];
479 UShape shape
= inst
.getShape();
482 uint numMats
= shape
.getNumMaterials();
485 if(numMats
!=inst
.getNumMaterials())
489 for(uint j
=0;j
<numMats
;j
++)
490 // restore UShape value
491 inst
.getMaterial(j
).setEmissive(shape
.getMaterial(j
).getEmissive());
495 //---------------------------------------------------
496 void CEntityCL::SInstanceCL::makeInstanceTransparent(uint8 opacity
, uint8 opacityMin
)
498 // ensure correct opacity
499 opacity
= max(opacity
, opacityMin
);
501 // choose to disable ZWrite only when opacity == opacityMin (this that what do actually previous code)
502 bool disableZWrite
= (opacity
!=255) && (opacity
==opacityMin
);
504 // Do it on both Loading and Current, to avoid any problem
508 for(uint i
=0;i
<2;i
++)
510 // test if instance is valid
511 UInstance inst
= insts
[i
];
514 ::makeInstanceTransparent(inst
, opacity
, disableZWrite
);
518 //---------------------------------------------------
519 void CEntityCL::SInstanceCL::setDiffuse(bool onOff
, NLMISC::CRGBA diffuse
)
521 // test if instance is valid
522 ::setDiffuse(Current
, onOff
, diffuse
);
523 ::setDiffuse(Loading
, onOff
, diffuse
);
531 //---------------------------------------------------
533 // Dafault constructor
534 //---------------------------------------------------
535 CEntityCL::CEntityCL()
537 // Initialize the object.
543 _GMTitle
= _InvalidGMTitleCode
;
544 _LastLocalSelectBoxComputeTime
= 0;
545 _InSceneInterfaceEnabled
= true;
548 //---------------------------------------------------
551 //---------------------------------------------------
552 CEntityCL::~CEntityCL()
554 // Remove the visual collision entity (snaped).
555 if(CollisionManager
&& _CollisionEntity
)
557 CollisionManager
->deleteEntity(_CollisionEntity
);
558 _CollisionEntity
= 0;
561 // If there still is a scene -> delete pointers.
565 if(!_Skeleton
.empty())
567 Scene
->deleteSkeleton(_Skeleton
);
571 if(!_Instance
.empty())
573 Scene
->deleteInstance(_Instance
);
578 for(uint i
= 0; i
< _Instances
.size(); ++i
)
580 if(!_Instances
[i
].Loading
.empty())
582 Scene
->deleteInstance(_Instances
[i
].Loading
);
584 if(!_Instances
[i
].Current
.empty())
586 Scene
->deleteInstance(_Instances
[i
].Current
);
590 // No more scene -> reset pointers.
597 // Remove the collision entity.
598 removeCollisionEntity();
599 // Remove the primitive.
602 // Release the animation playlist
605 EAM
->deletePlayList(_PlayList
);
609 if (!_StateFX
.empty() && Scene
)
611 Scene
->deleteInstance(_StateFX
);
612 _StateFXName
.clear();
614 if (!_SelectionFX
.empty() && Scene
)
616 Scene
->deleteInstance(_SelectionFX
);
618 if (!_MouseOverFX
.empty() && Scene
)
620 Scene
->deleteInstance(_MouseOverFX
);
622 // Free the link with the parent
623 parent(CLFECOMMON::INVALID_SLOT
);
624 // Remove Link with children
625 TChildren::iterator it
= _Children
.begin();
626 while(it
!= _Children
.end())
628 // Remove the child from the list if found.
629 if(skeleton() && (*it
) && (*it
)->skeleton())
630 skeleton()->detachSkeletonSon(*((*it
)->skeleton()));
638 //-----------------------------------------------
640 // Initialize the Object with this function for all constructors.
641 //-----------------------------------------------
642 void CEntityCL::init()
645 _Parent
= CLFECOMMON::INVALID_SLOT
;
646 // No entry for the moment.
652 _DisplayInRadar
= true;
653 _DisplayOSDName
= true;
654 _DisplayOSDBars
= true;
655 _DisplayOSDForceOver
= false;
657 _CanTurn
= true; // must be initialized beforce calling front()
658 _ForbidClipping
= false;
661 up(CVector(0.f
, 0.f
, 1.f
));
662 // Orientation of the entity.
663 front(CVector(0.f
, 1.f
, 0.f
));
664 // Current direction for the entity.
665 _DirMatrix
.identity();
666 dir(CVector(0.f
, 1.f
, 0.f
));
667 // Position of the entity.
668 _Position
= CVectorD(0.f
, 0.f
, 0.f
);
669 // Initialize the position limiter
670 _PositionLimiter
= CVectorD(0.0, 0.0, 0.0);
672 // Entity is not flyer at the beginning.
674 // Initialize the mode.
675 _Mode
= MBEHAV::UNKNOWN_MODE
;
676 _TheoreticalMode
= MBEHAV::UNKNOWN_MODE
;
677 // Initialize the behaviour.
678 _CurrentBehaviour
= MBEHAV::IDLE
;
680 // No skeleton at the beginning.
682 // No Instance at the beginning.
684 // No primitive at the beginning.
686 // No collision Entity at the beginning.
687 _CollisionEntity
= 0;
688 // No PlayList at the beginning.
694 CVector min
= CVector(-0.5f
, -0.5f
, 0);
695 CVector max
= CVector( 0.5f
, 0.5f
, 2);
696 aabbox
.setMinMax(min
, max
);
699 // Default Clip Sphere
700 _ClipRadius
= aabbox
.getRadius();
701 _ClipDeltaZ
= aabbox
.getCenter().z
;
703 // 'true' as long as the entity has not received any position.
705 // No position managed for the time so the next one will be the first one.
706 _FirstPosManaged
= true;
708 // No DataSetId initiliazed
709 _DataSetId
= CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
;
711 // The entity is not in any slot for the time.
712 _Slot
= CLFECOMMON::INVALID_SLOT
;
713 // The entity has no target for the time.
714 _TargetSlot
= CLFECOMMON::INVALID_SLOT
;
715 _TargetSlotNoLag
= CLFECOMMON::INVALID_SLOT
;
718 _LogicInfo3D
.Self
= this;
721 _AsyncTextureLoading
= false;
722 _LodTextureDirty
= false;
724 // Angle to have with the target when in combat mode with.
727 // Must do a setGlobalPosition
728 _SetGlobalPositionDone
= false;
729 _SnapToGroundDone
= false;
731 // Entity are not displayed at the beginning.
739 _HasReservedTitle
= false;
740 _EntityName
= "Name";
744 _PermanentStatutIcon
.clear();
746 // Not a mission target by default
747 _MissionTarget
= false;
748 // The entity has not moved for the time.
750 _TranspFactor
= 0.0f
;
753 _IsUserPackAnimal
= false;
756 _GroundTypeCachePos
= CVectorD::Null
;
760 _StateFXName
.clear();
764 _SomeInstanceCastShadowMap
= false;
765 _ShadowMapZDirClamp
= ClientCfg
.ShadowZDirClampLandscape
;
766 _ShadowMapMaxDepth
= ClientCfg
.ShadowMaxDepthLandscape
;
767 _ShadowMapPropertyLastUpdate
= 0;
769 #ifdef TMP_DEBUG_GUIGUI
770 _TheoreticalPosition
= CVectorD(0.f
, 0.f
, 0.f
);
771 _TheoreticalOrientation
= -10.0f
; // Init value to know if it has been changed.
772 #endif // TMP_DEBUG_GUIGUI
774 _VisualSelectionTime
= 0;
775 _VisualSelectionBlinked
= false;
776 _InSceneInterfaceEnabled
= true;
779 //-----------------------------------------------
781 // Method to call to initialize all members of the right class.
782 //-----------------------------------------------
783 void CEntityCL::initialize()
785 // Initialize the primitive.
786 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColNone
, MaskColNone
);
787 // Create the collision entity (used to snap the entity to the ground).
788 computeCollisionEntity();
789 // Initialize properties of the client.
793 //-----------------------------------------------
796 //-----------------------------------------------
797 bool CEntityCL::initPrimitive(float radius
, float height
, float length
, float width
, UMovePrimitive::TReaction reactionType
, UMovePrimitive::TTrigger triggerType
, UMovePrimitive::TCollisionMask occlusionMask
, UMovePrimitive::TCollisionMask collisionMask
, float clipRadius
, float clipHeight
)
799 // Check primitive, there should not be a primitive because it could have been created with another PACS and crash(continent changed).
802 nlwarning("ENT:initPrimitive:%d: There is already a primitive -> _Primitive = 0.", _Slot
);
806 // **** Create the primitive
807 bool primitiveOk
= false;
810 _Primitive
= PACS
->addCollisionablePrimitive(dynamicWI
, 1);
813 _Primitive
->setReactionType(reactionType
);
814 _Primitive
->setTriggerType(triggerType
);
815 _Primitive
->setAbsorbtion(0);
816 // Set the collision if the radius is > 0
819 _Primitive
->setPrimitiveType(UMovePrimitive::_2DOrientedCylinder
);
820 _Primitive
->setRadius( std::min(radius
, (float)(RYZOM_ENTITY_SIZE_MAX
/2)) );
821 _Primitive
->setHeight(height
+ClientCfg
.PrimitiveHeightAddition
);
822 CVector min
= CVector(-radius
, -radius
, 0.0f
);
823 CVector max
= CVector( radius
, radius
, height
);
824 _Aabbox
.setMinMax(min
, max
);
825 _Primitive
->setOcclusionMask(occlusionMask
); // This is an npc.
828 else if(length
> 0.0f
)
830 _Primitive
->setPrimitiveType(UMovePrimitive::_2DOrientedBox
);
831 _Primitive
->setSize(std::min(length
, (float)(RYZOM_ENTITY_SIZE_MAX
/2)), std::min(width
, (float)(RYZOM_ENTITY_SIZE_MAX
/2)));
832 _Primitive
->setHeight(height
+ClientCfg
.PrimitiveHeightAddition
);
835 CVector min
= CVector(-length
, -length
, 0.0f
);
836 CVector max
= CVector( length
, length
, height
);
837 _Aabbox
.setMinMax(min
, max
);
841 CVector min
= CVector(-width
, -width
, 0.0f
);
842 CVector max
= CVector( width
, width
, height
);
843 _Aabbox
.setMinMax(min
, max
);
845 _Primitive
->setOcclusionMask(occlusionMask
); // This is an npc.
847 // Non-collisionnable entity
850 _Primitive
->setOcclusionMask(MaskColNone
); // This is an npc.
851 // still have some _Aabbox for ???? use width for radius
852 float maxRad
= max(width
, 0.5f
);
853 CVector min
= CVector(-maxRad
, -maxRad
, 0.0f
);
854 CVector max
= CVector( maxRad
, maxRad
, height
);
855 _Aabbox
.setMinMax(min
, max
);
857 _Primitive
->setCollisionMask(collisionMask
);
858 _Primitive
->setObstacle(true);
859 _Primitive
->UserData
= UserDataEntity
;
861 if (_DataSetId
!= CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
862 _Primitive
->UserData
+= (((uint64
)_DataSetId
)<<16);
867 nlwarning("CEntityCL::initPrimitive:%d: Cannot create the _Primitive.", _Slot
);
870 nlwarning("CEntityCL::initPrimitive:%d: PACS not allocated -> _Primitive not created.", _Slot
);
872 // **** setup the 3D Clip Sphere.
873 // if clip radius not specified, deduce from collision
876 // Cylinder Colision?
882 else if(length
> 0.0f
)
884 clipRadius
= max(width
, length
);
886 // Non-collisionnable entity
889 // Backward compatibility: use width for radius
893 // at least 0.5f clip radius
894 clipRadius
= max(clipRadius
, 0.5f
);
896 // if clip height not specified
899 // at least 0.5f clip height, with height from collision
900 clipHeight
= max(height
, 0.5f
);
902 // Mount the sphere around the Clip cylinder (over estimate)
904 clipBox
.setMinMax(CVector(-clipRadius
, -clipRadius
, 0.0f
), CVector( clipRadius
, clipRadius
, clipHeight
));
905 // Compute the local Sphere info
906 _ClipRadius
= clipBox
.getRadius();
907 _ClipDeltaZ
= clipBox
.getCenter().z
; // NB different from radius, since radius>center.z
914 //-----------------------------------------------
916 // Initialize properties of the entity (according to the class).
917 //-----------------------------------------------
918 void CEntityCL::initProperties()
920 properties().selectable(true);
921 }// initProperties //
924 //-----------------------------------------------
925 // updateVisualProperty :
926 // Update a visual property from the database.
927 // \param gameCycle : when this was sent.
928 // \param prop : the property to udapte.
929 //-----------------------------------------------
930 void CEntityCL::updateVisualProperty(const NLMISC::TGameCycle
&gameCycle
, const uint
&prop
, const NLMISC::TGameCycle
&predictedInterval
)
932 CCDBNodeBranch
*nodePtr
= IngameDbMngr
.getNodePtr();
935 CCDBNodeBranch
*nodeRoot
= dynamic_cast<CCDBNodeBranch
*>(nodePtr
->getNode(0));
938 nlwarning("CEntityCL::updateVisualProperty : There is no entry in the DB for entities (current slot %d).", _Slot
);
942 CCDBNodeBranch
*nodGrp
= dynamic_cast<CCDBNodeBranch
*>(nodeRoot
->getNode(_Slot
));
945 nlwarning("CEntityCL::updateVisualProperty : Cannot find the entity '%d' in the database.", _Slot
);
949 // Get The property ptr.
950 CCDBNodeLeaf
*nodeProp
= dynamic_cast<CCDBNodeLeaf
*>(nodGrp
->getNode(prop
));
953 nlwarning("CEntityCL::updateVisualProperty : Cannot find the property '%d' for the slot %d.", prop
, _Slot
);
959 case PROPERTY_POSITION
:
960 updateVisualPropertyPos(gameCycle
, nodeProp
->getValue64(), predictedInterval
);
963 case PROPERTY_ORIENTATION
:
964 updateVisualPropertyOrient(gameCycle
, nodeProp
->getValue64());
967 case PROPERTY_BEHAVIOUR
:
968 updateVisualPropertyBehaviour(gameCycle
, nodeProp
->getValue64());
971 case PROPERTY_NAME_STRING_ID
:
972 updateVisualPropertyName(gameCycle
, nodeProp
->getValue64());
975 case PROPERTY_TARGET_ID
:
976 updateVisualPropertyTarget(gameCycle
, nodeProp
->getValue64());
981 updateVisualPropertyMode(gameCycle
, nodeProp
->getValue64());
985 updateVisualPropertyVpa(gameCycle
, nodeProp
->getValue64());
989 updateVisualPropertyVpb(gameCycle
, nodeProp
->getValue64());
993 updateVisualPropertyVpc(gameCycle
, nodeProp
->getValue64());
996 case PROPERTY_ENTITY_MOUNTED_ID
:
997 updateVisualPropertyEntityMounted(gameCycle
, nodeProp
->getValue64());
1000 case PROPERTY_RIDER_ENTITY_ID
:
1001 updateVisualPropertyRiderEntity(gameCycle
, nodeProp
->getValue64());
1004 case PROPERTY_TARGET_LIST_0
:
1005 case PROPERTY_TARGET_LIST_1
:
1006 case PROPERTY_TARGET_LIST_2
:
1007 case PROPERTY_TARGET_LIST_3
:
1008 updateVisualPropertyTargetList(gameCycle
, nodeProp
->getValue64(), prop
- PROPERTY_TARGET_LIST_0
);
1011 case PROPERTY_VISUAL_FX
:
1012 updateVisualPropertyVisualFX(gameCycle
, nodeProp
->getValue64());
1015 // Property to update the contextual menu, and some important status
1016 case PROPERTY_CONTEXTUAL
:
1017 updateVisualPropertyContextual(gameCycle
, nodeProp
->getValue64());
1021 updateVisualPropertyBars(gameCycle
, nodeProp
->getValue64());
1024 case PROPERTY_GUILD_SYMBOL
:
1025 updateVisualPropertyGuildSymbol(gameCycle
, nodeProp
->getValue64());
1028 case PROPERTY_GUILD_NAME_ID
:
1029 updateVisualPropertyGuildNameID(gameCycle
, nodeProp
->getValue64());
1032 case PROPERTY_EVENT_FACTION_ID
:
1033 updateVisualPropertyEventFactionID(gameCycle
, nodeProp
->getValue64());
1036 case PROPERTY_PVP_MODE
:
1037 updateVisualPropertyPvpMode(gameCycle
, nodeProp
->getValue64());
1040 case PROPERTY_PVP_CLAN
:
1041 updateVisualPropertyPvpClan(gameCycle
, nodeProp
->getValue64());
1044 case PROPERTY_OWNER_PEOPLE
:
1045 updateVisualPropertyOwnerPeople(gameCycle
, nodeProp
->getValue64());
1048 case PROPERTY_OUTPOST_INFOS
:
1049 updateVisualPropertyOutpostInfos(gameCycle
, nodeProp
->getValue64());
1052 // case PROPERTY_STATUS:
1053 // updateVisualPropertyStatus(gameCycle, nodeProp->getValue64());
1057 nlwarning("CEntityCL::updateVisualProperty : Unknown Property '%d' for the entity in the slot '%d'.", prop
, _Slot
);
1061 }// updateVisualProperty //
1064 //-----------------------------------------------
1065 // updateVisualPropertyContextual
1066 //-----------------------------------------------
1067 void CEntityCL::updateVisualPropertyContextual(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
1069 _Properties
.selectable( CProperties( (uint16
) prop
).selectable() );
1070 _Properties
.talkableTo( CProperties( (uint16
) prop
).talkableTo() );
1071 _Properties
.attackable( CProperties( (uint16
) prop
).attackable() );
1072 _Properties
.mountable( CProperties( (uint16
) prop
).mountable() );
1073 _Properties
.lootable( CProperties( (uint16
) prop
).lootable() );
1074 _Properties
.harvestable( CProperties( (uint16
) prop
).harvestable() );
1075 _Properties
.afk( CProperties( (uint16
) prop
).afk() );
1078 //-----------------------------------------------
1080 // Set the skeleton for the entity or an empty string to remove a skeleton.
1081 // \param filename : file with the skeleton to apply to the entity or empty string to remove a skeleton.
1082 //-----------------------------------------------
1083 USkeleton
*CEntityCL::skeleton(const string
&filename
)
1085 // Check there is a scene.
1088 pushDebugStr("No scene allocated -> Cannot create the skeleton.");
1093 // Remove the old skeleton.
1094 if(!_Skeleton
.empty())
1096 Scene
->deleteSkeleton(_Skeleton
);
1099 // If the filename is not empty -> changes the skeleton.
1100 if(filename
.empty())
1102 pushDebugStr("skeleton filename is empty -> Cannot create the skeleton.");
1106 // Create the skeleton.
1107 _Skeleton
= Scene
->createSkeleton(filename
);
1108 if(!_Skeleton
.empty())
1110 // Set default Transform mode -> RotQuat.
1111 _Skeleton
.setTransformMode(UTransformable::RotQuat
);
1112 // Initialize the playlist a bit.
1115 // Register the skeleton to the playlist.
1116 _PlayList
->registerTransform(_Skeleton
);
1118 // \todo GUIGUI : is this location right for this ?
1119 // Animation should not move alone.
1120 uint posTmp
= EAM
->getAnimationSet()->getChannelIdByName("pos");
1121 if(posTmp
!= UAnimationSet::NotFound
)
1122 _PlayList
->enableChannel(posTmp
, false);
1124 pushDebugStr("Channel 'pos' not found.");
1126 // Animation should not rotate alone.
1127 uint rotquatTmp
= EAM
->getAnimationSet()->getChannelIdByName("rotquat");
1128 if(rotquatTmp
!= UAnimationSet::NotFound
)
1129 _PlayList
->enableChannel(rotquatTmp
, false);
1131 pushDebugStr("Channel 'rotquat' not found.");
1135 pushDebugStr("Playlist no allocated -> skeleton not registered.");
1137 // Attach Light Information request to the skeleton
1138 _Skeleton
.setLogicInfo(&_LogicInfo3D
);
1140 // Enable user clipping
1141 _Skeleton
.setUserClipping (true);
1144 updateCastShadowMap();
1147 pushDebugStr(toString("Cannot create the Skeleton '%s', the file probably not exist.", filename
.c_str()));
1149 // Return the skeleton pointer.
1154 //-----------------------------------------------
1156 // Add an instance to the list of instance composing the entity.
1157 // \param shapeName : shape filename.
1158 // \param stickPoint : Name of the bone to stick on.
1159 // \param texture : texture to use (in multi texture) or -1 for default texture.
1160 // \param instIdx : if not CEntityCL::BadIndex, the instance will replace the one at this index.
1161 // \return uint32 : index of the instance created, or CEntityCL::BadIndex.
1162 //-----------------------------------------------
1163 uint32
CEntityCL::addInstance(const string
&shapeName
, const std::string
&stickPoint
, sint texture
, uint32 instIdx
)
1165 // Future Index for the instance.
1168 if(instIdx
< _Instances
.size()) // And so instIdx != CEntityCL::BadIndex
1170 // Index given from parameters so do not change.
1175 if(instIdx
!= CEntityCL::BadIndex
)
1176 nlwarning("CEntityCL::addInst:%d: given index '%d' is not valid.", _Slot
, instIdx
);
1177 idx
= instIdx
= CEntityCL::BadIndex
;
1180 // If the shape is empty, just clean and leave.
1181 if(shapeName
.empty())
1183 if(instIdx
== CEntityCL::BadIndex
)
1184 nlwarning("CEntityCL::addInst:%d: shape empty but given index was invalid, so nothing to clean and cannot add an empty shape.", _Slot
);
1186 // clean the instance
1187 if(instIdx
<_Instances
.size())
1188 _Instances
[instIdx
].createLoading(string(), stickPoint
, texture
);
1195 // Create new instance slot?
1196 if(instIdx
== CEntityCL::BadIndex
)
1198 idx
= (uint32
)_Instances
.size();
1199 _Instances
.push_back(SInstanceCL());
1202 // load, but dont replace instance if fails (yoyo: I keep the same behavior than before )
1203 if( !_Instances
[idx
].createLoading(shapeName
, stickPoint
, texture
, false) )
1205 // If fails to load....
1206 nlwarning("CEntityCL::addInstance : Cannot create the instance '%s' for the slot %d.", shapeName
.c_str(), _Slot
);
1208 // if the index was just being created, erase array entry
1209 if(instIdx
== CEntityCL::BadIndex
)
1211 _Instances
.pop_back();
1212 idx
= CEntityCL::BadIndex
;
1217 // Return the instance index.
1222 //---------------------------------------------------
1224 // Show or Hide the entity.
1225 // \param s : if 'true' = entity visible, else invisible.
1226 //---------------------------------------------------
1227 void CEntityCL::show(bool s
)
1229 if(!_Skeleton
.empty())
1236 else if(!_Instance
.empty())
1247 for(std::vector
<SInstanceCL
>::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
1249 if (!it
->Current
.empty()) it
->Current
.show();
1254 for(std::vector
<SInstanceCL
>::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
1256 if (!it
->Current
.empty()) it
->Current
.hide();
1262 //-----------------------------------------------
1264 // hide the entity Skin (all entity instances).
1265 // todo GUIGUI : for video, it shouldn't be a problem, but we should improve with the current which could not be ready yet while loading not done
1266 //-----------------------------------------------
1267 void CEntityCL::hideSkin()
1269 const uint nbInst
= (uint
)_Instances
.size();
1270 for(uint i
= 0; i
<nbInst
; ++i
)
1272 if(!_Instances
[i
].Current
.empty())
1273 _Instances
[i
].Current
.hide();
1278 //---------------------------------------------------
1280 // Set the vector up of the entity and normalize.
1281 //---------------------------------------------------
1282 void CEntityCL::up(const CVector
&vect
)
1284 // If the param is vector Null -> problem so do not changed the vector.
1285 if(vect
== CVector::Null
)
1287 nlwarning("CEntityCL::up : attempt to set the vector up with a vector Null. Up not changed !");
1291 // Compute the up vector
1296 //---------------------------------------------------
1298 // Change the entity front vector.
1299 // \param vect : new vector to use for the front.
1300 // \param compute : adjust the param 'vect' to be valid or leave the old front unchanged if impossible.
1301 // \param check : warning if the param 'vect' is not valid to be the front (vector Null) even with compute=true.
1302 // \param forceTurn : set front even if the entity cannot turn
1303 // \return bool : 'true' if the front has been filled, else 'false'.
1304 //---------------------------------------------------
1305 bool CEntityCL::front(const CVector
&vect
, bool compute
, bool check
, bool forceTurn
)
1307 if (!forceTurn
&& !_CanTurn
)
1309 return setVect(_Front
, vect
, compute
, check
);
1312 //---------------------------------------------------
1314 // Change the entity direction vector.
1315 // \param vect : new vector to use for the direction.
1316 // \param compute : adjust the param 'vect' to be valid or leave the old direction unchanged if impossible.
1317 // \param check : warning if the param 'vect' is not valid to be the direction (vector Null) even with compute=true.
1318 // \return bool : 'true' if the direction has been filled, else 'false'.
1319 //---------------------------------------------------
1320 bool CEntityCL::dir(const CVector
&vect
, bool compute
, bool check
)
1322 if(setVect(_Dir
, vect
, compute
, check
))
1324 // Compute the direction Matrix
1325 CVector vi
= _Dir
^up();
1326 CVector vk
= vi
^_Dir
;
1327 _DirMatrix
.setRot(vi
, _Dir
, vk
, true);
1334 //---------------------------------------------------
1336 // Change the box position.
1337 // \param pos contains the new box position.
1338 //---------------------------------------------------
1339 void CEntityCL::posBox(const CVector
&pos
)
1341 CVector halfSize
= _Aabbox
.getHalfSize();
1342 halfSize
.x
= 0; halfSize
.y
= 0;
1343 _Aabbox
.setCenter(pos
+halfSize
);
1346 //---------------------------------------------------
1349 // \param box : an axis aligned bounding box to apply to the entity.
1350 //---------------------------------------------------
1351 void CEntityCL::box(const CAABBox
&box
)
1355 // position the box around the entity.
1360 //-----------------------------------------------
1361 // lastFramePACSPos :
1362 // Return the last frame PACS position.
1363 //-----------------------------------------------
1364 bool CEntityCL::lastFramePACSPos(NLPACS::UGlobalPosition
&result
) const
1368 result
= _LastFramePACSPos
;
1369 if(result
.InstanceId
!= -1)
1376 }// lastFramePACSPos //
1378 //-----------------------------------------------
1380 // Return the current PACS position.
1381 //-----------------------------------------------
1382 bool CEntityCL::currentPACSPos(NLPACS::UGlobalPosition
&result
) const
1386 _Primitive
->getGlobalPosition(result
, dynamicWI
);
1387 if(result
.InstanceId
!= -1)
1394 }// currentPACSPos //
1397 //---------------------------------------------------
1399 // Change the PACS position and the entity position too.
1400 // \todo GUIGUI : do we have to get the position from pacs or from the parameter ?
1401 //---------------------------------------------------
1402 void CEntityCL::pacsPos(const CVectorD
&vect
, const UGlobalPosition
&globPos
)
1404 // Set then entity position
1412 nlwarning("CEntityCL::pacsPos : Global Retriever not allocated.");
1416 // Use the precise PACS position if possible
1417 if( globPos
.InstanceId
!= -1 /*&& ContinentMngr.getCurrentContinentSelectName() == "newbieland"*/ )
1419 _Primitive
->setGlobalPosition(globPos
, dynamicWI
);
1421 // NB: else use the 3D position. => the Z may be different than the Z wanted! (according to the pacs pos found)
1424 _Primitive
->setGlobalPosition(vect
, dynamicWI
, UGlobalPosition::Unspecified
);
1428 // Get the global position
1429 UGlobalPosition gPos
;
1430 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
1431 _FinalPacsPos
= GR
->getDoubleGlobalPosition(gPos
);
1433 // Check the new position is valid
1434 if (gPos
.InstanceId
!= -1)
1436 _SetGlobalPositionDone
= true;
1437 _LastRetrievedPosition
= vect
;
1438 _LastRetrievedPacsPosition
= gPos
;
1441 // If the entity do not fly, update Z value (X,Y should be the same or close and to avoid a pb with a too small move, just keep them)
1443 pos().z
= _FinalPacsPos
.z
;
1448 //---------------------------------------------------
1450 // Move the PACS position and the entity position too.
1451 //---------------------------------------------------
1452 void CEntityCL::pacsMove(const CVectorD
&vect
)
1454 // Entity has not moved.
1456 // If there is a PACS primitive -> changes the PACS position.
1459 // Set then entity position
1467 // Set then entity position
1470 nlwarning("CEntityCL::pacsMove : Global Retriever not allocated.");
1474 if ( _SetGlobalPositionDone
)
1476 // Change the position of the entity in PACS and apply the new position to the entity.
1477 CVectorD
deltaPos ((vect
.x
- _FinalPacsPos
.x
)/ DT
, (vect
.y
- _FinalPacsPos
.y
)/ DT
, 0);
1478 if ((fabs (deltaPos
.x
) > 0.05) || (fabs (deltaPos
.y
) > 0.05))
1481 _Primitive
->move (deltaPos
, dynamicWI
);
1486 _Primitive
->setGlobalPosition(vect
, dynamicWI
);
1488 // Check the new position is valid
1489 UGlobalPosition gPos
;
1490 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
1491 if (gPos
.InstanceId
!= -1)
1493 _SetGlobalPositionDone
= true;
1494 _LastRetrievedPosition
= vect
;
1495 _LastRetrievedPacsPosition
= gPos
;
1499 // Set the entity position
1504 //-----------------------------------------------
1506 // Update the PACS position after the evalCollision. The entity position is set too. This is fast.
1507 // If the entity position is too far from its PACS position, setGlobalPosition is called.
1508 // After this call, the position.z is valid.
1509 //-----------------------------------------------
1510 void CEntityCL::pacsFinalizeMove() // virtual
1517 // Get the global position
1518 _FinalPacsPos
= _Primitive
->getFinalPosition (dynamicWI
);
1520 // Get the global position
1521 UGlobalPosition gPos
;
1522 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
1523 if (gPos
.InstanceId
!= -1)
1525 if(ClientCfg
.UsePACSForAll
&& (_Mode
== MBEHAV::COMBAT
|| _Mode
== MBEHAV::COMBAT_FLOAT
))
1531 // Delta between real and evaluated position
1532 CVectorD deltaPos
= pos();
1533 deltaPos
-= _FinalPacsPos
;
1535 // Too far from real value ?
1536 if ( ((deltaPos
.x
*deltaPos
.x
+deltaPos
.y
*deltaPos
.y
) > (double)RYZOM_EPSILON_SQRT_POSITION
) )
1541 // If the entity do not fly, update Z value (X,Y should be the same or close and to avoid a pb with a too small move, just keep them)
1543 pos().z
= _FinalPacsPos
.z
;
1548 _SetGlobalPositionDone
= false;
1549 _SnapToGroundDone
= false;
1551 }// pacsFinalizeMove //
1553 //---------------------------------------------------
1555 // Get the entity position and set all visual stuff with it.
1556 // \todo GUIGUI : put this method 'virtual' to have a different code for the user (no playlist).
1557 // \todo GUIGUI : manage the parent better.
1558 //---------------------------------------------------
1559 void CEntityCL::updateDisplay(CEntityCL
* /* parent */)
1561 }// updateDisplay //
1564 //-----------------------------------------------
1566 // Set the cluster system for the current entity and all of its chidren.
1567 //-----------------------------------------------
1568 void CEntityCL::setClusterSystem(UInstanceGroup
*cluster
)
1570 // Place the skeleton in the right cluster.
1571 if(!_Skeleton
.empty())
1572 _Skeleton
.setClusterSystem(cluster
);
1573 else if(!_Instance
.empty())
1574 _Instance
.setClusterSystem(cluster
);
1577 for(std::vector
<SInstanceCL
>::iterator it
= _Instances
.begin(); it
!= _Instances
.end(); ++it
)
1579 if (!it
->Current
.empty())
1581 it
->Current
.setClusterSystem(cluster
);
1586 // Update the children display.
1587 std::list
<CEntityCL
*>::iterator it
= _Children
.begin();
1588 while(it
!= _Children
.end())
1590 // Update the display for the child
1591 (*it
)->setClusterSystem(cluster
);
1597 // *****************************************************************************************************
1598 NL3D::UInstanceGroup
*CEntityCL::getClusterSystem()
1600 if (!_Skeleton
.empty()) return _Skeleton
.getClusterSystem();
1601 if (!_Instance
.empty()) return _Instance
.getClusterSystem();
1605 //-----------------------------------------------
1607 // Choose the right cluster according to the entity position.
1608 //-----------------------------------------------
1609 void CEntityCL::updateCluster()
1611 // Check there is a primitive.
1614 // Get the global position.
1615 UGlobalPosition gPos
;
1617 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
1618 // Set the new cluster.
1619 setClusterSystem(getCluster(gPos
));
1621 }// updateCluster //
1624 //---------------------------------------------------
1626 // Snap entity to the ground.
1627 //---------------------------------------------------
1628 void CEntityCL::snapToGround()
1630 // While PACS not done, do not try to snap.
1631 if(_SetGlobalPositionDone
== false)
1634 // If the entity is a flyer no snap to ground will be done.
1638 bool needSnap
= true;
1640 // Check there is a primitive.
1641 if(_Primitive
&& GR
)
1643 // Get the right pos from PACS.
1644 UGlobalPosition gPos
;
1645 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
1647 // Get the final position from pacs and after the snap if on landscape.
1648 vect
= GR
->getGlobalPosition(gPos
);
1649 // if on interior, no need to snap
1650 if(GR
->isInterior(gPos
))
1652 // if on water, snap on water
1655 float waterHeight
= 0.0f
;
1656 if(GR
->isWaterPosition(gPos
, waterHeight
))
1658 if ( isUser() || isPlayer() || isNPC())
1661 float waterOffset
= ClientCfg
.WaterOffset
;
1664 case EGSPD::CPeople::Unknown
:
1666 case EGSPD::CPeople::Fyros
:
1667 waterOffset
= ClientCfg
.FyrosWaterOffset
;
1669 case EGSPD::CPeople::Matis
:
1670 waterOffset
= ClientCfg
.MatisWaterOffset
;
1672 case EGSPD::CPeople::Tryker
:
1673 waterOffset
= ClientCfg
.TrykerWaterOffset
;
1675 case EGSPD::CPeople::Zorai
:
1676 waterOffset
= ClientCfg
.ZoraiWaterOffset
;
1682 vect
.z
= waterHeight
+ waterOffset
;
1686 vect
.z
= waterHeight
+ ClientCfg
.WaterOffsetCreature
;
1693 // No primitive, vect = current pos.
1697 // Snap to the ground.
1698 if(needSnap
&& _CollisionEntity
)
1700 // for Snap on landscape, use always current 3d position, for snap cache performance.
1703 // Have i to force the snap to ground ?
1704 if (!_SnapToGroundDone
)
1706 CVector vectNull
= CVector::Null
;
1707 _CollisionEntity
->snapToGround(vectNull
);
1709 _SnapToGroundDone
= _CollisionEntity
->snapToGround(vect
);
1712 // Change the entity position.
1716 // Set the box position.
1721 //---------------------------------------------------
1724 //---------------------------------------------------
1725 string
chooseRandom( const vector
<string
>& sounds
, uint32
& previousIndex
)
1727 uint32 randomIndex
= rand()%sounds
.size();
1728 if( randomIndex
== previousIndex
)
1730 randomIndex
= (randomIndex
+1)%sounds
.size();
1732 previousIndex
= randomIndex
;
1735 return sounds
[randomIndex
];
1739 //---------------------------------------------------
1740 // CEntityLogicInfo3D::getStaticLightSetup() callBack
1741 //---------------------------------------------------
1742 void CEntityLogicInfo3D::getStaticLightSetup(NLMISC::CRGBA sunAmbient
, std::vector
<NL3D::CPointLightInfluence
> &pointLightList
,
1743 uint8
&sunContribution
, NLMISC::CRGBA
&localAmbient
)
1745 // Is the instance in a InstanceGroup???
1746 UInstanceGroup
*igUnderInstance
= NULL
;
1747 const UMovePrimitive
*movePrim
= Self
->getPrimitive();
1748 if(Self
->skeleton() && movePrim
)
1749 igUnderInstance
= Self
->skeleton()->getClusterSystem();
1751 // if it is, retrieve static light from the IG.
1754 // get the logic position of the entity.
1755 UGlobalPosition gPos
;
1756 movePrim
->getGlobalPosition(gPos
, dynamicWI
);
1758 // retrieve collision identifier from Pacs.
1759 uint localRetrieverId
= GR
->getLocalRetrieverId(gPos
);
1761 // get static light info from ig
1762 igUnderInstance
->getStaticLightSetup(sunAmbient
, localRetrieverId
, gPos
.LocalPosition
.Surface
,
1763 gPos
.LocalPosition
.Estimation
, pointLightList
, sunContribution
, localAmbient
);
1765 // else retrieve from landscape
1768 // Use VisualCollisionEntity to retrieve info from landscape.
1769 UVisualCollisionEntity
*colEnt
= Self
->getCollisionEntity();
1772 colEnt
->getStaticLightSetup(sunAmbient
, Self
->pos(), pointLightList
, sunContribution
, localAmbient
);
1779 //-----------------------------------------------
1780 // computePrimitive :
1781 // Create (or re-create) a primitive.
1782 //-----------------------------------------------
1783 void CEntityCL::computePrimitive()
1785 // Initialize the primitive.
1786 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColNone
, MaskColNone
);
1787 // Set the position.
1789 }// computePrimitive //
1791 //---------------------------------------------------
1792 // removePrimitive :
1793 // remove the entity primitive from PACS
1794 //---------------------------------------------------
1795 void CEntityCL::removePrimitive()
1797 // If there is a Primitive -> remove it.
1800 // Remove the primitive if PACS allocated
1802 PACS
->removePrimitive(_Primitive
);
1803 // Primitive removed
1806 }// removePrimitive //
1809 //-----------------------------------------------
1810 // computeCollisionEntity :
1811 // Create the collision entity.
1812 //-----------------------------------------------
1813 void CEntityCL::computeCollisionEntity()
1815 // Check for an old collision entity not removed.
1816 if(_CollisionEntity
)
1818 nlwarning("CEntityCL::computeCollisionEntity: There is already a collision entity in the slot %d.", _Slot
);
1819 _CollisionEntity
= 0;
1822 // Is there a collision manager.
1823 if(CollisionManager
)
1825 // Create the collision entity.
1826 _CollisionEntity
= CollisionManager
->createEntity();
1827 if(_CollisionEntity
== 0)
1828 nlwarning("CEntityCL::computeCollisionEntity : Cannot create the _CollisionEntity for the slot %d.", _Slot
);
1830 _CollisionEntity
->setSnapToRenderedTesselation(false);
1832 }// computeCollisionEntity //
1834 //-----------------------------------------------
1835 // removeCollisionEntity :
1836 // Remove the collision entity.
1837 //-----------------------------------------------
1838 void CEntityCL::removeCollisionEntity()
1840 // If there is a collision entity -> remove it.
1841 if(_CollisionEntity
)
1843 // Remove it if there is a collision manager.
1844 if(CollisionManager
)
1845 CollisionManager
->deleteEntity(_CollisionEntity
);
1846 // Collision Entity Removed.
1847 _CollisionEntity
= 0;
1849 }// removeCollisionEntity //
1852 //-----------------------------------------------
1854 // Method to return the attack radius of an entity
1855 //-----------------------------------------------
1856 double CEntityCL::attackRadius() const
1861 //-----------------------------------------------
1862 //-----------------------------------------------
1863 CVectorD
CEntityCL::getAttackerPos(double /* ang */, double /* dist */) const
1872 //-----------------------------------------------
1873 // updateAsyncTexture
1874 //-----------------------------------------------
1875 float CEntityCL::updateAsyncTexture()
1877 H_AUTO ( RZ_Client_Entity_CL_Update_Async_Texture
)
1881 // Check all instance to know if they need to start async load their textures
1882 for (i
= 0; i
< _Instances
.size(); i
++)
1884 if (!_Instances
[i
].Loading
.empty())
1886 UParticleSystemInstance psi
;
1887 psi
.cast (_Instances
[i
].Loading
);
1889 if (_Instances
[i
].Loading
.isAsyncTextureDirty() || !psi
.empty())
1891 // reset instance state.
1892 _Instances
[i
].Loading
.setAsyncTextureDirty(false);
1893 // must start loading for this isntance
1894 _Instances
[i
].Loading
.startAsyncTextureLoading();
1895 // the entity is now currently loading.
1896 _AsyncTextureLoading
= true;
1897 // The LodTexture need to be recomputed
1898 _LodTextureDirty
= true;
1904 // Update Async Texture loading of all instances.
1905 if (_AsyncTextureLoading
)
1907 bool allLoaded
= true;
1908 // update loading for all instances.
1909 for (i
= 0; i
< _Instances
.size(); i
++)
1911 if(!_Instances
[i
].Loading
.empty())
1913 // update async texture loading
1914 allLoaded
= allLoaded
&& _Instances
[i
].Loading
.isAsyncTextureReady();
1918 // if all are loaded, then End! don't need to check all instances every frame.
1921 _AsyncTextureLoading
= false;
1923 // Transfert InstancesLoading to Instances
1924 for(i
= 0; i
< _Instances
.size(); i
++)
1926 _Instances
[i
].updateCurrentFromLoading(_Skeleton
);
1927 if(_Skeleton
.empty() && !_Instances
[i
].Current
.empty())
1929 _Instances
[i
].Current
.setPos(pos()); // force update right now (else the object would be at 0, 0, 0 for first frame)
1934 // additionally, if their is no skeleton (bot objects), may enable cast shadow here
1935 updateCastShadowMap();
1940 // compute distance to camera.
1941 // For lesser update, take the refine position (else in 3th person view, rotation will cause lot of update)
1942 // \todo GUIGUI : make sure pos() will return the world position all the time even when a child.
1943 float distToCam
= (View
.refinePos() - pos()).norm();
1945 // For LOD texture, must update the "texture distance"
1946 for(i
= 0; i
< _Instances
.size(); i
++)
1948 if(!_Instances
[i
].Current
.empty())
1950 // update async texture loading
1951 _Instances
[i
].Current
.setAsyncTextureDistance(distToCam
);
1959 //-----------------------------------------------
1961 //-----------------------------------------------
1962 void CEntityCL::updateLodTexture()
1964 H_AUTO ( RZ_Client_Entity_CL_Update_Lod_Texture
)
1966 // if need to recompute, and if Async loading ended
1967 if( _LodTextureDirty
&& !_AsyncTextureLoading
)
1970 _LodTextureDirty
= false;
1972 if(!_Skeleton
.empty())
1973 _Skeleton
.computeLodTexture();
1979 //-----------------------------------------------
1981 // Add a new child pointer.
1982 //-----------------------------------------------
1983 void CEntityCL::addChild(CEntityCL
*c
)
1987 nlwarning("ENT:addChild:%d: Try to add a child with a Null Pointer.", _Slot
);
1992 _Children
.push_back(c
);
1994 if(skeleton() && c
->skeleton())
1996 const string stickBone
= "stick_1";
1997 sint idBones
= skeleton()->getBoneIdByName(stickBone
);
2000 // Child position is relative to the parent so set its position to 0 0 0.
2001 c
->skeleton()->setPos(CVector::Null
);
2002 skeleton()->stickObjectEx(*(c
->skeleton()), idBones
, true);
2005 nlwarning("ENT:addChild:%d: the Bone '%s' does not exist", _Slot
, stickBone
.c_str());
2009 //-----------------------------------------------
2011 // Remove a new child pointer.
2012 //-----------------------------------------------
2013 void CEntityCL::delChild(CEntityCL
*c
)
2017 nlwarning("ENT:delChild:%d: Try to remove a child with a Null Pointer.", _Slot
);
2021 TChildren::iterator it
= _Children
.begin();
2022 while(it
!= _Children
.end())
2024 // Remove the child from the list if found.
2027 if(skeleton() && c
->skeleton())
2028 skeleton()->detachSkeletonSon(*(c
->skeleton()));
2029 _Children
.erase(it
);
2038 //-----------------------------------------------
2040 // Set the new parent
2041 //-----------------------------------------------
2042 void CEntityCL::parent(CLFECOMMON::TCLEntityId p
)
2044 // Remove the entity from the old parent.
2045 CEntityCL
*parent
= EntitiesMngr
.entity(_Parent
);
2047 parent
->delChild(this);
2049 // Initialize the new parent.
2052 // Remove the entity from the old parent.
2053 parent
= EntitiesMngr
.entity(_Parent
);
2055 parent
->addChild(this);
2058 bool CEntityCL::clipped (const std::vector
<NLMISC::CPlane
> &clippingPlanes
, const CVector
&camPos
)
2060 // If the entity still have no position, and still have no mode, entity should not be displayed.
2061 if(mode() == MBEHAV::UNKNOWN_MODE
|| _First_Pos
)
2064 // If the entity is not displayable, count it as clipped.
2068 // Use Clip position (sphere clip)
2069 CVector clipPos
= _Aabbox
.getCenter();
2070 clipPos
.z
+= _ClipDeltaZ
- _Aabbox
.getHalfSize().z
; // _ClipDeltaZ is relative to pos on ground
2072 if (!_ForbidClipping
)
2074 // Speed Clip: clip just the sphere.
2076 // if out of only plane, entirely out.
2077 const uint count
= (uint
)clippingPlanes
.size ();
2079 for(i
=0;i
<count
;i
++)
2081 // We are sure that pyramid has normalized plane normals.
2082 // if SpherMax OUT return true.
2083 float d
= clippingPlanes
[i
]*clipPos
;
2090 float sqrdist
= (camPos
- clipPos
).sqrnorm();
2091 return (sqrdist
> (ClientCfg
.CharacterFarClip
*ClientCfg
.CharacterFarClip
));
2095 //---------------------------------------------------
2097 // Set the name of the entity. Handle replacement tag if any
2098 // to insert NPC task translated.
2099 //---------------------------------------------------
2100 void CEntityCL::setEntityName(const std::string
&name
)
2107 //---------------------------------------------------
2109 // Display Debug Information.
2110 //---------------------------------------------------
2111 void CEntityCL::displayDebug(float x
, float &y
, float lineStep
) // virtual
2114 TextContext
->printfAt(x
, y
, "Type: %d - Slot: %d", Type
, _Slot
);
2117 TextContext
->printfAt(x
, y
, "Outpost id:%d side:%s",this->getOutpostId(),OUTPOSTENUMS::toString(this->getOutpostSide()).c_str() );
2120 if(!getEntityName().empty())
2121 TextContext
->printAt(x
, y
, getEntityName());
2123 TextContext
->printfAt(x
, y
, "Name not received");
2125 // Target and DataSet Id
2126 TextContext
->printfAt(x
, y
, "Target: %d - DataSet Id: %u", _TargetSlot
, _DataSetId
);
2129 TextContext
->printfAt(x
, y
, "Sheet: %d(%s)", _SheetId
.asInt(), _SheetId
.toString().c_str());
2132 TextContext
->printfAt(x
, y
, "NPCAlias: %u", _NPCAlias
);
2135 #ifndef TMP_DEBUG_GUIGUI
2136 TextContext
->printfAt(x
, y
, "Pos: %f %f %f", pos().x
, pos().y
, pos().z
);
2138 TextContext
->printfAt(x
, y
, "Pos: %f %f %f (Theoretical : %f %f %f)", pos().x
, pos().y
, pos().z
, _TheoreticalPosition
.x
, _TheoreticalPosition
.y
, _TheoreticalPosition
.z
);
2141 // Display the Target Mode.
2142 TextContext
->printfAt(x
, y
, "Mode: %d(%s) (Theoretical : %d(%s))", (sint
)mode(), MBEHAV::modeToString(mode()).c_str(), (sint
)_TheoreticalMode
, MBEHAV::modeToString(_TheoreticalMode
).c_str());
2144 // Display the Target Behaviour.
2145 TextContext
->printfAt(x
, y
, "Behaviour: %d(%s)", (sint
)behaviour(), MBEHAV::behaviourToString(behaviour()).c_str());
2148 #ifndef TMP_DEBUG_GUIGUI
2149 TextContext
->printfAt(x
, y
, "%f(%f,%f,%f) front", frontYaw(), front().x
, front().y
, front().z
);
2151 TextContext
->printfAt(x
, y
, "%f(%f,%f,%f) front (Theoretical : %f)", frontYaw(), front().x
, front().y
, front().z
, _TheoreticalOrientation
);
2155 TextContext
->printfAt(x
, y
, "%f(%f,%f,%f) dir", atan2(dir().y
, dir().x
), dir().x
, dir().y
, dir().z
);
2157 // Last Retrieved pacs
2158 TextContext
->printfAt(x
, y
, "Last PACS: (%.4f,%.4f,%.4f) (%d,%d,%.4f,%.4f,%.4f)", _LastRetrievedPosition
.x
, _LastRetrievedPosition
.y
, _LastRetrievedPosition
.z
,
2159 _LastRetrievedPacsPosition
.InstanceId
, _LastRetrievedPacsPosition
.LocalPosition
.Surface
,
2160 _LastRetrievedPacsPosition
.LocalPosition
.Estimation
.x
, _LastRetrievedPacsPosition
.LocalPosition
.Estimation
.y
, _LastRetrievedPacsPosition
.LocalPosition
.Estimation
.z
);
2165 _Primitive
->getGlobalPosition(gp
, dynamicWI
);
2166 float waterHeight
= 0.0f
;
2167 bool water
= (GR
? GR
->isWaterPosition(gp
, waterHeight
) : false);
2168 TextContext
->printfAt(x
, y
, "Current PACS: (%d,%d,%.4f,%.4f,%.4f) %s %.1f", gp
.InstanceId
, gp
.LocalPosition
.Surface
,
2169 gp
.LocalPosition
.Estimation
.x
, gp
.LocalPosition
.Estimation
.y
, gp
.LocalPosition
.Estimation
.z
,
2170 (water
? "WATER" : "LANDSCAPE"), waterHeight
);
2175 //-----------------------------------------------
2176 //-----------------------------------------------
2177 void CEntityCL::displayDebugPropertyStages(float /* x */, float &y
, float /* lineStep */)
2182 //-----------------------------------------------
2184 // Serialize entity.
2185 //-----------------------------------------------
2186 void CEntityCL::serial(NLMISC::IStream
&f
)
2193 //-----------------------------------------------
2195 // Read/Write Variables from/to the stream.
2196 //-----------------------------------------------
2197 void CEntityCL::readWrite(NLMISC::IStream
&f
) // virtual
2204 f
.serial(_DataSetId
);
2206 // NL3D::UPlayList *_PlayList;
2207 // NL3D::UPlayList *_FacePlayList;
2208 // NL3D::UVisualCollisionEntity *_CollisionEntity;
2209 // NL3D::USkeleton *_Skeleton;
2211 f
.serial(_TargetSlot
);
2212 f
.serial(_Position
);
2213 f
.serialEnum(_Mode
);
2214 f
.serial(_CurrentBehaviour
);
2215 f
.serial(_Properties
);
2216 f
.serial(_EntityName
);
2217 f
.serial(_PermanentStatutIcon
);
2218 // f.serial(_NameEx);
2219 // NLPACS::UMovePrimitive *_Primitive;
2220 // CEntityLogicInfo3D _LogicInfo3D;
2221 bool asyncTextureLoading
= _AsyncTextureLoading
;
2222 f
.serial(asyncTextureLoading
);
2223 _AsyncTextureLoading
= asyncTextureLoading
;
2224 bool lodTextureDirty
= _LodTextureDirty
;
2225 f
.serial(lodTextureDirty
);
2226 _LodTextureDirty
= lodTextureDirty
;
2229 // TChildren _Children;
2230 // UInstance _Instance;
2231 // std::vector<UInstance> _Instances;
2235 f
.serial(_DirMatrix
);
2236 f
.serial(_LastFramePos
);
2237 bool firstPos
= _First_Pos
;
2239 _First_Pos
= firstPos
;
2240 bool firstPosManaged
= _FirstPosManaged
;
2241 f
.serial(firstPosManaged
);
2242 _FirstPosManaged
= firstPosManaged
;
2244 bool flyier
= _Flyer
;
2247 f
.serial(_TargetAngle
);
2252 //-----------------------------------------------
2254 // To call after a read from a stream to re-initialize the entity.
2255 //-----------------------------------------------
2256 void CEntityCL::load() // virtual
2261 //-----------------------------------------------
2262 // onStringAvailable :
2263 // Callback when the name is arrived.
2264 //-----------------------------------------------
2265 void CEntityCL::onStringAvailable(uint
/* stringId */, const std::string
&value
)
2267 _EntityName
= value
;
2269 // remove the shard name if possible
2270 _EntityName
= removeShardFromName(_EntityName
);
2275 _HasReservedTitle
= false;
2277 // check if there is any replacement tag in the string
2278 string::size_type p1
= _EntityName
.find('$');
2279 if (p1
!= string::npos
)
2281 // we found a replacement point begin tag
2282 string::size_type p2
= _EntityName
.find('$', p1
+1);
2283 if (p2
!= string::npos
)
2285 // ok, we have the second replacement point!
2286 // extract the replacement id
2287 string id
= _EntityName
.substr(p1
+1, p2
-p1
-1);
2288 // retrieve the translated string
2290 // string replacement = CI18N::get(strNewTitle);
2291 bool womanTitle
= false;
2292 CCharacterCL
* c
= dynamic_cast<CCharacterCL
*>(this);
2295 womanTitle
= ( c
->getGender() == GSGENDER::female
);
2298 string replacement
= STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
, womanTitle
);
2300 // Sometimes translation contains another title
2302 string::size_type pos
= replacement
.find('$');
2303 if (pos
!= string::npos
)
2305 _EntityName
= _EntityName
= STRING_MANAGER::CStringManagerClient::getLocalizedName(replacement
.substr(0, pos
));
2306 string::size_type pos2
= replacement
.find('$', pos
+ 1);
2307 _TitleRaw
= replacement
.substr(pos
+1, pos2
- pos
- 1);
2308 replacement
= STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
, womanTitle
);
2312 _Tags
= STRING_MANAGER::CStringManagerClient::getTitleInfos(_TitleRaw
, womanTitle
);
2314 if (!replacement
.empty() || !ClientCfg
.DebugStringManager
)
2316 // build the final name
2317 p1
= _EntityName
.find('$');
2318 _EntityName
= STRING_MANAGER::CStringManagerClient::getLocalizedName(_EntityName
.substr(0, p1
)); // + _Name.substr(p2+1)
2319 // Get extended name
2320 _NameEx
= replacement
;
2323 CHARACTER_TITLE::ECharacterTitle titleEnum
= CHARACTER_TITLE::toCharacterTitle( _TitleRaw
);
2324 if ( titleEnum
>= CHARACTER_TITLE::BeginGmTitle
&& titleEnum
<= CHARACTER_TITLE::EndGmTitle
)
2326 _GMTitle
= titleEnum
- CHARACTER_TITLE::BeginGmTitle
;
2327 _HasReservedTitle
= true;
2331 _GMTitle
= _InvalidGMTitleCode
;
2332 if ( titleEnum
== CHARACTER_TITLE::FBT
)
2333 _HasReservedTitle
= true;
2338 _EntityName
= STRING_MANAGER::CStringManagerClient::getLocalizedName(_EntityName
);
2342 // Is the first title or a new title ?
2343 if ( !_Title
.empty() && (_Slot
==0) )
2346 contextHelp ("title");
2350 // Update interface with new title
2353 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2354 CViewText
*pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:player:header_opened:player_title"));
2355 if (pVT
!= NULL
) pVT
->setText(_Title
);
2357 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:player"));
2358 if (pGC
!= NULL
) pGC
->setTitle(_EntityName
);
2360 CSkillManager
*pSM
= CSkillManager::getInstance();
2361 pSM
->setPlayerTitle(_TitleRaw
);
2364 // Must rebuild the in scene interface 'cause name has changed
2365 buildInSceneInterface ();
2367 sint64 prop
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->getValue64();
2368 updateVisualPropertyVpa(0, prop
);
2370 }// onStringAvailable //
2372 //-----------------------------------------------
2374 //-----------------------------------------------
2375 std::string
CEntityCL::getTitleFromName(const std::string
&name
)
2377 std::string::size_type p1
= name
.find('$');
2378 if (p1
!= string::npos
)
2380 std::string::size_type p2
= name
.find('$', p1
+ 1);
2381 if (p2
!= std::string::npos
)
2382 return name
.substr(p1
+1, p2
-p1
-1);
2385 return std::string();
2386 }// getTitleFromName //
2388 //-----------------------------------------------
2389 // removeTitleFromName
2390 //-----------------------------------------------
2391 std::string
CEntityCL::removeTitleFromName(const std::string
&name
)
2393 std::string::size_type p1
= name
.find('$');
2394 if (p1
== string::npos
)
2400 std::string::size_type p2
= name
.find('$', p1
+ 1);
2401 if (p2
!= string::npos
)
2403 return name
.substr(0, p1
) + name
.substr(p2
+ 1);
2407 return name
.substr(0, p1
);
2410 }// removeTitleFromName //
2412 //-----------------------------------------------
2413 // removeShardFromName
2414 //-----------------------------------------------
2415 std::string
CEntityCL::removeShardFromName(const std::string
&name
)
2417 // The string must contains a '(' and a ')'
2418 std::string::size_type p0
= name
.find('(');
2419 std::string::size_type p1
= name
.find(')');
2420 if(p0
==std::string::npos
|| p1
==std::string::npos
|| p1
<=p0
)
2423 // if it is the same as the shard name of the user, remove it
2424 if (!NLMISC::compareCaseInsensitive(name
.c_str() + p0
+ 1, p1
-p0
-1, PlayerSelectedHomeShardName
.c_str(), PlayerSelectedHomeShardName
.size()))
2425 return name
.substr(0,p0
) + name
.substr(p1
+1);
2426 // else don't modify
2431 //-----------------------------------------------
2432 // removeTitleAndShardFromName
2433 //-----------------------------------------------
2434 std::string
CEntityCL::removeTitleAndShardFromName(const std::string
&name
)
2436 return removeTitleFromName(removeShardFromName(name
));
2440 //-----------------------------------------------
2442 class CUpdateEntitiesColor
: public IActionHandler
2445 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
2447 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2449 CEntityCL::_EntitiesColor
[CEntityCL::User
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:USER")->getValueRGBA();
2450 CEntityCL::_EntitiesColor
[CEntityCL::Player
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PLAYER")->getValueRGBA();
2451 CEntityCL::_EntitiesColor
[CEntityCL::NPC
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:NPC")->getValueRGBA();
2452 CEntityCL::_EntitiesColor
[CEntityCL::Fauna
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:FAUNA")->getValueRGBA();
2453 CEntityCL::_EntitiesColor
[CEntityCL::ForageSource
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:SOURCE")->getValueRGBA();
2454 CEntityCL::_DeadColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:DEAD")->getValueRGBA();
2455 CEntityCL::_TargetColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:TARGET")->getValueRGBA();
2456 CEntityCL::_GroupColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GROUP")->getValueRGBA();
2457 CEntityCL::_GuildColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GUILD")->getValueRGBA();
2458 CEntityCL::_UserMountColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:MOUNT")->getValueRGBA();
2459 CEntityCL::_UserPackAnimalColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:BEAST")->getValueRGBA();
2460 CEntityCL::_PvpEnemyColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPENEMY")->getValueRGBA();
2461 CEntityCL::_PvpAllyColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLY")->getValueRGBA();
2462 CEntityCL::_PvpAllyInTeamColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLYINTEAM")->getValueRGBA();
2463 CEntityCL::_PvpNeutralColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPNEUTRAL")->getValueRGBA();
2465 // don't save these colors in .icfg because players can't change them
2466 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::SGM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SGM")->getValueRGBA();
2467 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::GM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:GM")->getValueRGBA();
2468 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::VG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:VG")->getValueRGBA();
2469 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::SG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SG")->getValueRGBA();
2470 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::G
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:G")->getValueRGBA();
2472 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::CM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:CM")->getValueRGBA();
2473 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::EM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EM")->getValueRGBA();
2474 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::EG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EG")->getValueRGBA();
2475 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::OBSERVER
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:OBSERVER")->getValueRGBA();
2478 REGISTER_ACTION_HANDLER (CUpdateEntitiesColor
, "update_entities_color");
2480 //-----------------------------------------------
2482 bool CEntityCL::isTarget () const
2484 return UserEntity
&& UserEntity
->selection() == _Slot
;
2487 //-----------------------------------------------
2489 bool CEntityCL::isInSameGuild () const
2491 if (Type
!= Player
&& Type
!= User
)
2494 const uint32 guildNameId
= this->getGuildNameID();
2495 if (guildNameId
!= 0 && UserEntity
&& guildNameId
== UserEntity
->getGuildNameID())
2501 //-----------------------------------------------
2503 bool CEntityCL::oneInLeague () const
2505 if (Type
!= Player
&& Type
!= User
)
2508 const uint32 leagueID
= getLeagueID();
2509 if ((UserEntity
&& (UserEntity
->getLeagueID() != 0)) || leagueID
!= 0)
2515 //-----------------------------------------------
2517 bool CEntityCL::isInSameLeague () const
2519 if (Type
!= Player
&& Type
!= User
)
2522 const uint32 leagueID
= getLeagueID();
2523 if ((leagueID
!= 0) && UserEntity
&& (leagueID
== UserEntity
->getLeagueID()))
2528 //-----------------------------------------------
2530 NLMISC::CRGBA
CEntityCL::getColor () const
2534 return _TargetColor
;
2540 return _UserMountColor
;
2542 if (isUserPackAnimal())
2543 return _UserPackAnimalColor
;
2545 if ( ( Type
== Player
|| Type
== User
) && _GMTitle
!= _InvalidGMTitleCode
)
2547 return _GMTitleColor
[_GMTitle
];
2550 if (Type
== Player
|| Type
== NPC
)
2555 if (isAnOutpostEnemy())
2557 return _PvpEnemyColor
;
2564 if (getPvpMode()&PVP_MODE::PvpFaction
)
2565 return CRGBA(min(255, _PvpEnemyColor
.R
+150), min(255, _PvpEnemyColor
.G
+150), min(255, _PvpEnemyColor
.B
+150),_PvpEnemyColor
.A
);
2567 return _PvpEnemyColor
;
2574 if (getPvpMode() & PVP_MODE::PvpFactionFlagged
)
2576 if(isInSameLeague())
2577 return CRGBA(max(0, _PvpAllyColor
.R
-100), max(0, _PvpAllyColor
.G
-100), max(0, _PvpAllyColor
.B
-100),_PvpAllyColor
.A
);
2578 return CRGBA(max(0, _PvpAllyInTeamColor
.R
-100), max(0, _PvpAllyInTeamColor
.G
-100), max(0, _PvpAllyInTeamColor
.B
-100),_PvpAllyInTeamColor
.A
);
2582 if(isInSameLeague())
2583 return _PvpAllyColor
;
2584 return _PvpAllyInTeamColor
;
2590 return _PvpNeutralColor
;
2597 if (isInSameLeague())
2598 return CRGBA(min(255, _GroupColor
.R
+50), min(255, _GroupColor
.G
+50), min(255, _GroupColor
.B
+50),_GroupColor
.A
);
2600 if (isInSameGuild())
2603 return _EntitiesColor
[Type
];
2607 //---------------------------------------------------
2609 // Return true if the current position is an indoor position.
2610 //---------------------------------------------------
2611 bool CEntityCL::indoor() const
2613 if(_Primitive
&& GR
)
2615 UGlobalPosition gPos
;
2616 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
2617 return GR
->isInterior(gPos
);
2619 // Return false if any problem
2624 //-----------------------------------------------
2626 //-----------------------------------------------
2627 void CEntityCL::pos(const NLMISC::CVectorD
&vect
)
2629 CVectorD checkDist
= _PositionLimiter
-vect
;
2631 if(checkDist
!= CVectorD::Null
)
2633 if(checkDist
.norm() > ClientCfg
.PositionLimiterRadius
)
2635 checkDist
.normalize();
2636 _PositionLimiter
= vect
+ checkDist
*ClientCfg
.PositionLimiterRadius
/2.0;
2643 //-----------------------------------------------
2645 void CEntityCL::updateMissionTarget()
2647 // Update the mission target flag
2648 _MissionTarget
= false;
2651 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2653 for (i
=0; i
<MAX_NUM_MISSIONS
; i
++)
2654 for (j
=0; j
<MAX_NUM_MISSION_TARGETS
; j
++)
2657 CCDBNodeLeaf
*prop
= EntitiesMngr
.getMissionTargetTitleDB(i
, j
); // NLGUI::CDBManager::getInstance()->getDbProp("SERVER:MISSIONS:"+toString(i)+":TARGET"+toString(j)+":TITLE", false);
2660 _MissionTarget
= _NameId
== (uint32
)prop
->getValue32();
2668 //-----------------------------------------------
2669 uint
CEntityCL::getGroundType() const
2672 const float srqCacheDistLimit
= 1;
2674 // If the user is not too far from cached pos, return same value
2675 if((_GroundTypeCachePos
-pos()).sqrnorm() < srqCacheDistLimit
)
2677 return _GroundTypeCache
;
2686 UGlobalPosition gPos
;
2687 getPrimitive()->getGlobalPosition(gPos
, dynamicWI
);
2688 gt
= GR
->getMaterial(gPos
);
2696 NL3D::CSurfaceInfo si
;
2697 _CollisionEntity
->getSurfaceInfo(pos(), si
);
2698 gt
= si
.UserSurfaceData
;
2702 _GroundTypeCachePos
= pos();
2703 _GroundTypeCache
= gt
;
2708 //---------------------------------------------------
2709 void CEntityCL::makeTransparent(bool t
)
2712 _TranspFactor
+= ((float)(DT
)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND
);
2714 _TranspFactor
-= ((float)(DT
)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND
);
2716 if (_TranspFactor
< 0.0) _TranspFactor
= 0.0;
2717 if (_TranspFactor
> 1.0) _TranspFactor
= 1.0;
2719 uint32 opaMin
= getOpacityMin();
2720 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
2722 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2724 _Instances
[i
].makeInstanceTransparent(opacity
, (uint8
)opaMin
);
2727 }// makeTransparent //
2729 //---------------------------------------------------
2730 void CEntityCL::makeTransparent(float factor
)
2732 clamp(factor
, 0.f
, 1.f
);
2733 _TranspFactor
= 1.f
- factor
;
2734 uint32 opaMin
= getOpacityMin();
2735 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
2737 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2739 _Instances
[i
].makeInstanceTransparent(opacity
, (uint8
)opaMin
);
2743 // ***************************************************************************
2744 void CEntityCL::setDiffuse(bool onOff
, NLMISC::CRGBA diffuse
)
2746 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2748 _Instances
[i
].setDiffuse(onOff
, diffuse
);
2753 // ***************************************************************************
2754 CCDBNodeLeaf
*CEntityCL::getOpacityDBNode()
2756 if (!_OpacityMinNodeLeaf
)
2758 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2759 _OpacityMinNodeLeaf
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:USER_CHAR_OPA_MIN", false);
2761 return _OpacityMinNodeLeaf
;
2764 // ***************************************************************************
2765 uint32
CEntityCL::getOpacityMin()
2767 CCDBNodeLeaf
*pNL
= getOpacityDBNode();
2770 uint32 val
= pNL
->getValue32();
2771 clamp(val
, (uint32
)0, (uint32
)255);
2775 // this is an error case...
2779 // ***************************************************************************
2780 void CEntityCL::setOpacityMin(uint32 value
)
2782 CCDBNodeLeaf
*pNL
= getOpacityDBNode();
2785 clamp(value
, (uint32
)0, (uint32
)255);
2786 pNL
->setValue32(value
);
2791 // ***************************************************************************
2793 * Return true if the in-scene interface must be shown
2795 bool CEntityCL::mustShowInsceneInterface( bool enabledInSheet
) const
2798 (enabledInSheet
/*&& !CNPCIconCache::getInstance().getNPCIcon(this).getTextureMain().empty()*/) &&
2799 (_InSceneInterfaceEnabled
) &&
2800 ( ClientCfg
.Names
||
2802 ((getDisplayOSDForceOver() || ClientCfg
.ShowNameUnderCursor
) && slot()==SlotUnderCursor
) ||
2803 (ClientCfg
.ShowNameSelected
&& UserEntity
&& slot()==UserEntity
->selection()) ||
2804 (isInTeam() && !isUser ()) ||
2805 (UserEntity
&& ((UserEntity
->pos()-pos()).sqrnorm() < ClientCfg
.ShowNameBelowDistanceSqr
) && !isUser ())
2812 //-----------------------------------------------
2813 const char *CEntityCL::getBoneNameFromBodyPart(BODY::TBodyPart part
, BODY::TSide side
) const
2815 BODY::TBodyPart hominPart
= BODY::getMatchingHominBodyPart(part
);
2818 case BODY::HHead
: return "Bip01 Head";
2819 case BODY::HChest
: return "Bip01 Spine2";
2820 case BODY::HArms
: return side
== BODY::Left
? "Bip01 L UpperArm" : "Bip01 R UpperArm";
2821 case BODY::HHands
: return side
== BODY::Left
? "Bip01 L Hand" : "Bip01 R Hand";
2822 case BODY::HLegs
: return side
== BODY::Left
? "Bip01 L Calf" : "Bip01 R Calf";
2823 case BODY::HFeet
: return side
== BODY::Left
? "Bip01 L Foot" : "Bip01 R Foot";
2829 //-----------------------------------------------
2831 // Return a pointer on an instance structure.
2832 //-----------------------------------------------
2833 CEntityCL::SInstanceCL
*CEntityCL::idx2Inst(uint idx
)
2835 if(idx
< _Instances
.size()) // CEntityCL::BadIndex is the max so idx < ... mean idx != CEntityCL::BadIndex too
2836 return &_Instances
[idx
];
2843 //-----------------------------------------------
2844 void CEntityCL::updateIsInTeam ()
2846 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2850 // if UId not set, false
2851 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2854 for (uint i
=0; i
<MaxNumPeopleInTeam
; i
++)
2857 CCDBNodeLeaf
*uidProp
= EntitiesMngr
.getGroupMemberUidDB(i
);
2858 CCDBNodeLeaf
*presentProp
= EntitiesMngr
.getGroupMemberNameDB(i
);
2859 // If same Entity uid than the one in the Database, ok the entity is in the Player TEAM!!
2860 if (uidProp
&& uidProp
->getValue32() == (sint32
)dataSetId() &&
2861 presentProp
&& presentProp
->getValueBool() )
2864 buildInSceneInterface();
2868 buildInSceneInterface();
2871 //-----------------------------------------------
2872 void CEntityCL::updateIsUserAnimal ()
2874 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2876 _IsUserMount
= false;
2877 _IsUserPackAnimal
= false;
2879 // if UId not set, false
2880 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2883 // Am i a pack animal?
2884 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2887 CCDBNodeLeaf
*uidProp
= EntitiesMngr
.getBeastUidDB(i
);
2888 CCDBNodeLeaf
*statusProp
= EntitiesMngr
.getBeastStatusDB(i
);
2889 CCDBNodeLeaf
*typeProp
= EntitiesMngr
.getBeastTypeDB(i
);
2890 // I must have the same Id, and the animal entry must be ok.
2891 if(uidProp
&& statusProp
&& typeProp
&& uidProp
->getValue32() == (sint32
)dataSetId() &&
2892 ANIMAL_STATUS::isSpawned((ANIMAL_STATUS::EAnimalStatus
)(statusProp
->getValue32()) ))
2894 switch(typeProp
->getValue16())
2896 case ANIMAL_TYPE::Mount
: _IsUserMount
= true; break;
2899 case ANIMAL_TYPE::Packer
: _IsUserPackAnimal
= true; break;
2907 //-----------------------------------------------
2908 ANIMAL_STATUS::EAnimalStatus
CEntityCL::getPackAnimalStatus() const
2910 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2912 if(! (isUserPackAnimal() || isUserMount()))
2915 // Am i a pack animal?
2916 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2919 CCDBNodeLeaf
*uidProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i
), false);
2920 CCDBNodeLeaf
*statusProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i
), false);
2921 // I must have the same Id, and the animal entry must be ok.
2922 if(uidProp
&& statusProp
&& uidProp
->getValue32() == (sint32
)dataSetId())
2923 return (ANIMAL_STATUS::EAnimalStatus
)(statusProp
->getValue32());
2929 //-----------------------------------------------
2930 bool CEntityCL::getPackAnimalIndexInDB(sint
&dbIndex
) const
2932 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2934 if(! (isUserPackAnimal() || isUserMount()))
2937 // Am i a pack animal?
2938 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2941 CCDBNodeLeaf
*uidProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i
), false);
2942 CCDBNodeLeaf
*statusProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i
), false);
2943 // I must have the same Id, and the animal entry must be ok.
2944 if(uidProp
&& statusProp
&& uidProp
->getValue32() == (sint32
)dataSetId())
2954 //-----------------------------------------------
2955 void CEntityCL::dataSetId(CLFECOMMON::TClientDataSetIndex dataSet
)
2957 _DataSetId
= dataSet
;
2959 if (_Primitive
&& _Primitive
->UserData
== UserDataEntity
)
2960 _Primitive
->UserData
|= (((uint64
)_DataSetId
)<<16);
2962 // additionaly, on a UID change, must check the IsInTeam and IsAniml flags
2964 updateIsUserAnimal();
2966 // and update Bar Manager, only if correctly init
2967 if(_Slot
!=CLFECOMMON::INVALID_SLOT
&& _DataSetId
!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2968 CBarManager::getInstance()->addEntity(_Slot
, _DataSetId
);
2971 // ***************************************************************************
2972 void CEntityCL::updateVisible(const NLMISC::TTime
&/* time */, CEntityCL
* /* target */)
2974 // update some shadowmap properties
2975 updateShadowMapProperties();
2977 // For Skeleton Spawn Animation, must update some pos
2978 if(!_Skeleton
.empty())
2980 _Skeleton
.setSSSWOPos(pos());
2981 _Skeleton
.setSSSWODir(front());
2984 if (!R2::isEditionCurrent())
2986 // NB : if editor is enabled, then highlighting is managed in another fashion (there may be multiple-semihighlights)
2988 // Selection Highlight
2989 if(_VisualSelectionTime
!= 0)
2991 bool blinkOn
= false;
2992 sint64 t
= T1
-_VisualSelectionTime
;
2993 // hardcoded blink animation
2997 _VisualSelectionTime
= 0;
2999 setVisualSelectionBlink(blinkOn
, CRGBA::White
);
3003 // If i am the target
3005 // set semi-highlight
3006 setVisualSelectionBlink(true, CRGBA(100,100,100));
3007 // else If i am under cursor
3008 else if(ShowInterface
&& isUnderCursor())
3010 setVisualSelectionBlink(true, CRGBA::White
);
3012 // disable hightlight
3013 setVisualSelectionBlink(false, CRGBA::White
);
3018 // ***************************************************************************
3019 void CEntityCL::updateSomeClipped(const NLMISC::TTime
&/* time */, CEntityCL
* /* target */)
3021 // update some shadowmap properties
3022 updateShadowMapProperties();
3025 // ***************************************************************************
3026 void CEntityCL::updateClipped(const NLMISC::TTime
&/* currentTimeInMs */, CEntityCL
* /* target */)
3028 // hide only if I am not the target
3031 if (!_SelectionFX
.empty() && Scene
)
3033 Scene
->deleteInstance(_SelectionFX
);
3034 _SelectionFX
= NULL
;
3036 if (!_MouseOverFX
.empty() && Scene
)
3038 Scene
->deleteInstance(_MouseOverFX
);
3039 _MouseOverFX
= NULL
;
3045 // ***************************************************************************
3046 void CEntityCL::updateVisiblePostPos(const NLMISC::TTime
&/* currentTimeInMs */, CEntityCL
* /* target */)
3048 if (R2::isEditionCurrent()) return; // selection managed by r2 editor in edition mode
3050 bool bShowReticle
= true;
3052 CCDBNodeLeaf
*node
= (CCDBNodeLeaf
*)_ShowReticleLeaf
? &*_ShowReticleLeaf
3053 : &*(_ShowReticleLeaf
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_RETICLE", false));
3057 bShowReticle
= node
->getValueBool();
3060 // No-op if I am not the current UserEntity Target
3061 if(bShowReticle
&& isTarget())
3063 // activate selection fx
3064 if (_SelectionFX
.empty())
3066 // Keep a static instance of the selection FX
3067 NL3D::UInstance instance
= Scene
->createInstance(ClientCfg
.SelectionFX
);
3068 if (!instance
.empty())
3070 _SelectionFX
.cast (instance
);
3071 _SelectionFX
.setLoadBalancingGroup("SelectionFx");
3072 if (_SelectionFX
.empty())
3074 // shape found, but not a particle system
3075 Scene
->deleteInstance(instance
);
3083 if (!_SelectionFX
.empty() && Scene
)
3085 Scene
->deleteInstance(_SelectionFX
);
3089 // Mouse over SFX, only if the entity is selectable
3090 if (bShowReticle
&& ShowInterface
&& !isTarget() && isUnderCursor() && properties().selectable())
3092 // activate selection fx
3093 if (_MouseOverFX
.empty())
3095 // Keep a static instance of the selection FX
3096 NL3D::UInstance instance
= Scene
->createInstance(ClientCfg
.MouseOverFX
);
3097 if (!instance
.empty())
3099 _MouseOverFX
.cast (instance
);
3100 _MouseOverFX
.setLoadBalancingGroup("SelectionFx");
3101 if (_MouseOverFX
.empty())
3103 // shape found, but not a particle system
3104 Scene
->deleteInstance(instance
);
3112 if (!_MouseOverFX
.empty() && Scene
)
3114 Scene
->deleteInstance(_MouseOverFX
);
3118 if (!_StateFX
.empty())
3120 // Build a matrix for the fx
3121 NLMISC::CMatrix mat
;
3125 const CVector
&boxes
= _SelectBox
.getHalfSize ();
3126 // take mean of XY and Z
3127 float halfwidth
= std::max(boxes
.x
, boxes
.y
);
3128 halfwidth
= (halfwidth
+ boxes
.z
)/2;
3129 mat
.setScale (halfwidth
);
3131 // Pos. Avoid Flick in XY, but take precise Z
3133 position
= pos().asVector();
3134 position
.z
= _SelectBox
.getMin().z
;
3135 mat
.setPos(position
);
3136 mat
.setRot(dirMatrix());
3138 _StateFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3139 _StateFX
.setMatrix(mat
);
3141 _StateFX
.setClusterSystem(skeleton()->getClusterSystem());
3144 if (!_SelectionFX
.empty() || !_MouseOverFX
.empty())
3146 // Build a matrix for the fx
3147 NLMISC::CMatrix mat
;
3151 const CVector
&boxes
= _SelectBox
.getHalfSize ();
3152 // take mean of XY and Z
3153 float halfwidth
= std::max(boxes
.x
, boxes
.y
);
3154 halfwidth
= (halfwidth
+ boxes
.z
)/2;
3155 mat
.setScale (halfwidth
* 2 * ClientCfg
.SelectionFXSize
);
3157 // Pos. Avoid Flick in XY, but take precise Z
3159 position
= pos().asVector();
3160 position
.z
= _SelectBox
.getCenter().z
;
3161 mat
.setPos(position
);
3163 if (!_SelectionFX
.empty())
3165 _SelectionFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3166 _SelectionFX
.setMatrix(mat
);
3168 _SelectionFX
.setClusterSystem(skeleton()->getClusterSystem());
3169 // Colorize the selection depending of the level of the creature
3171 CRGBA col
= CRGBA(0,0,0);
3172 uint8 nForce
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:TARGET:FORCE_RATIO")->getValue8();
3173 _SelectionFX
.setUserParam(0, 0.1f
*nForce
+ 0.1f
);
3176 if (!_MouseOverFX
.empty())
3178 _MouseOverFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3179 _MouseOverFX
.setMatrix(mat
);
3181 _MouseOverFX
.setClusterSystem(skeleton()->getClusterSystem());
3187 // ***************************************************************************
3188 void CEntityCL::buildInSceneInterface ()
3192 // ***************************************************************************
3193 void CEntityCL::doSetVisualSelectionBlink(bool bOnOff
, CRGBA emitColor
)
3195 // blink all instances
3196 for(uint i
= 0; i
< instances().size(); ++i
)
3198 SInstanceCL
&inst
= instances()[i
];
3200 inst
.setEmissive(emitColor
);
3202 inst
.restoreEmissive();
3205 // also blink skeleton in CLod form
3206 if(!_Skeleton
.empty())
3209 _Skeleton
.setLodEmit(emitColor
);
3211 _Skeleton
.setLodEmit(CRGBA::Black
);
3215 // ***************************************************************************
3216 void CEntityCL::visualSelectionStart()
3218 _VisualSelectionTime
= T1
;
3221 // ***************************************************************************
3222 void CEntityCL::visualSelectionStop()
3224 _VisualSelectionTime
= 0;
3227 // ***************************************************************************
3228 bool CEntityCL::canCastShadowMap() const
3230 return ClientCfg
.Shadows
;
3233 // ***************************************************************************
3234 void CEntityCL::updateCastShadowMap()
3236 bool shadowOn
= canCastShadowMap();
3238 // if the entity has a skeleton
3241 // then shadow will be done through the skeleton
3242 skeleton()->enableCastShadowMap(shadowOn
);
3243 // disable shadows on instances
3244 if(_SomeInstanceCastShadowMap
)
3246 for(uint i
= 0; i
< _Instances
.size(); i
++)
3248 if(!_Instances
[i
].Current
.empty())
3249 _Instances
[i
].Current
.enableCastShadowMap(false);
3251 _SomeInstanceCastShadowMap
= false;
3256 // enable/disable cast shadow on instances instead (eg: on bot objects)
3257 // NB: must do it at each updateCastShadowMap(), cause don't know if an instance has been added or not
3258 for(uint i
= 0; i
< _Instances
.size(); i
++)
3260 if(!_Instances
[i
].Current
.empty())
3262 _Instances
[i
].Current
.enableCastShadowMap(shadowOn
);
3266 _SomeInstanceCastShadowMap
= shadowOn
;
3269 // if shadow enabled, update the shadow properties
3274 skeleton()->setShadowMapDirectionZThreshold(_ShadowMapZDirClamp
);
3275 skeleton()->setShadowMapMaxDepth(_ShadowMapMaxDepth
);
3279 for(uint i
= 0; i
< _Instances
.size(); i
++)
3281 if(!_Instances
[i
].Current
.empty())
3283 _Instances
[i
].Current
.setShadowMapDirectionZThreshold(_ShadowMapZDirClamp
);
3284 _Instances
[i
].Current
.setShadowMapMaxDepth(_ShadowMapMaxDepth
);
3291 // ***************************************************************************
3292 void CEntityCL::updateShadowMapProperties()
3295 Choose the z clamp direction whether or not the player is on "interior" stuff.
3296 In "interior" stuff, the ZClamp direction is lesser, to avoid some problems of
3297 "cast shadow behind the walls"
3299 Also choose the MaxDepth of shadow map whether or not the player is on "interior" stuff.
3300 In "interior" stuff, the MaxDepth is lesser to, to avoid some problems with the "bud":
3301 when the player go up stairs and when in the "bud", the shadow still appears on landscape
3303 float zDirClampWanted
= ClientCfg
.ShadowZDirClampLandscape
;
3304 float maxDepth
= ClientCfg
.ShadowMaxDepthLandscape
;
3307 zDirClampWanted
= ClientCfg
.ShadowZDirClampInterior
;
3308 maxDepth
= ClientCfg
.ShadowMaxDepthInterior
;
3312 if(_ShadowMapZDirClamp
!=zDirClampWanted
|| _ShadowMapMaxDepth
!=maxDepth
)
3314 // if some time passed since last update
3315 sint64 dt
= T1
-_ShadowMapPropertyLastUpdate
;
3318 // update _ShadowMapZDirClamp
3319 if(_ShadowMapZDirClamp
<zDirClampWanted
)
3321 _ShadowMapZDirClamp
+= ClientCfg
.ShadowZDirClampSmoothSpeed
* 0.001f
* dt
;
3322 if(_ShadowMapZDirClamp
>zDirClampWanted
)
3323 _ShadowMapZDirClamp
= zDirClampWanted
;
3325 else if(_ShadowMapZDirClamp
>zDirClampWanted
)
3327 _ShadowMapZDirClamp
-= ClientCfg
.ShadowZDirClampSmoothSpeed
* 0.001f
* dt
;
3328 if(_ShadowMapZDirClamp
<zDirClampWanted
)
3329 _ShadowMapZDirClamp
= zDirClampWanted
;
3332 // update _ShadowMapMaxDepth
3333 if(_ShadowMapMaxDepth
<maxDepth
)
3335 _ShadowMapMaxDepth
+= ClientCfg
.ShadowMaxDepthSmoothSpeed
* 0.001f
* dt
;
3336 if(_ShadowMapMaxDepth
>maxDepth
)
3337 _ShadowMapMaxDepth
=maxDepth
;
3339 else if(_ShadowMapMaxDepth
>maxDepth
)
3341 _ShadowMapMaxDepth
-= ClientCfg
.ShadowMaxDepthSmoothSpeed
* 0.001f
* dt
;
3342 if(_ShadowMapMaxDepth
<maxDepth
)
3343 _ShadowMapMaxDepth
=maxDepth
;
3346 // update shadowMap, to update the clamp zdirection, and the shadow depth
3347 updateCastShadowMap();
3351 // bkup last time of update
3352 _ShadowMapPropertyLastUpdate
= T1
;
3355 // ***************************************************************************
3356 void CEntityCL::setOrderingLayer(uint layer
)
3358 if (!_Skeleton
.empty()) _Skeleton
.setOrderingLayer(layer
);
3362 void CEntityCL::displayable(bool d
)
3365 // :KLUDGE: Hide selection FX
3366 if (!_Displayable
&& !_SelectionFX
.empty() && Scene
)
3368 Scene
->deleteInstance(_SelectionFX
);
3372 // ***************************************************************************
3373 EGSPD::CPeople::TPeople
CEntityCL::people() const
3375 return EGSPD::CPeople::Unknown
;
3378 // ***************************************************************************
3379 void CEntityCL::setPeople(EGSPD::CPeople::TPeople
/* people */)
3383 // ***************************************************************************
3384 void CEntityCL::forceEvalAnim()
3388 // find highest father in the hierarchy
3389 CEntityCL
*parentEntity
= this;
3392 CEntityCL
*nextParent
= EntitiesMngr
.entity(parentEntity
->parent());
3393 if (!nextParent
) break;
3394 parentEntity
= nextParent
;
3397 // Snap the parent entity to the ground.
3399 H_AUTO ( RZ_Client_Entity_CL_Update_Snap_To_Ground
)
3400 parentEntity
->snapToGround();
3403 // Animate the parent entity (and also child entities)
3405 H_AUTO ( RZ_Client_Entity_CL_Update_Display
)
3406 parentEntity
->updateDisplay();
3412 // ***************************************************************************
3413 const NLMISC::CAABBox
&CEntityCL::localSelectBox()
3415 // recompute the selection box?
3416 if(_LastLocalSelectBoxComputeTime
<T1
)
3418 _LastLocalSelectBoxComputeTime
=T1
;
3421 // if skeleton, compute aabox from precise skeleton method
3422 if(!_Skeleton
.empty())
3424 // Don't compute if in LOD form (else flick because sometimes valid because of shadow animation)
3425 if(!_Skeleton
.isDisplayedAsLodCharacter())
3429 static volatile bool useBoneSphere = true;
3430 if (useBoneSphere) computed = _Skeleton.computeRenderedBBoxWithBoneSphere(_LocalSelectBox, false);
3431 else computed = _Skeleton.computeRenderedBBox(_LocalSelectBox);
3435 // apply local offset due to skeleton animation
3436 CMatrix invMat = _DirMatrix;
3437 invMat.setPos(pos());
3439 CVector localOffset = invMat * _Skeleton.getPos();
3440 _LocalSelectBox.setCenter(_LocalSelectBox.getCenter() + localOffset);
3441 static volatile float rot = -1.f;
3443 rotMat.rotateZ((float) Pi * rot / 2);
3444 CVector newHalfSize = rotMat * _LocalSelectBox.getHalfSize();
3445 newHalfSize.x = fabsf(newHalfSize.x);
3446 newHalfSize.y = fabsf(newHalfSize.y);
3447 newHalfSize.z = fabsf(newHalfSize.z);
3448 _LocalSelectBox.setHalfSize(newHalfSize);
3451 if (_Skeleton
.computeRenderedBBoxWithBoneSphere(_LocalSelectBox
, false))
3454 // apply local offset due to skeleton animation
3455 CMatrix invMat
= _DirMatrix
;
3456 invMat
.setPos(pos());
3458 CMatrix localMat
= invMat
* _Skeleton
.getMatrix();
3459 _LocalSelectBox
= CAABBox::transformAABBox(localMat
, _LocalSelectBox
);
3463 // else compute from static bot object
3467 // try with _Instances array first
3468 if(!_Instances
.empty())
3469 inst
= _Instances
[0].Current
;
3470 // Fallback to _Instance (??)
3474 // if static instance found
3477 inst
.getShapeAABBox(_LocalSelectBox
);
3483 // if not found, fallback to default bbox
3486 _LocalSelectBox
.setCenter(_Aabbox
.getCenter() - pos().asVector());
3487 _LocalSelectBox
.setHalfSize(_Aabbox
.getHalfSize());
3492 getMeshDefaultScale(scale
);
3493 const CVector
&halfSize
= _LocalSelectBox
.getHalfSize();
3494 const CVector
¢er
= _LocalSelectBox
.getCenter();
3495 _LocalSelectBox
.setHalfSize(CVector(halfSize
.x
* scale
.x
, halfSize
.y
* scale
.y
, halfSize
.z
* scale
.z
));
3496 _LocalSelectBox
.setCenter(CVector(center
.x
* scale
.x
, center
.y
* scale
.y
, center
.z
* scale
.z
));
3500 // Return the selection box.
3501 return _LocalSelectBox
;
3504 //----------------------------------------------------------------------
3505 void CEntityCL::getMeshDefaultScale(NLMISC::CVector
&scale
) const
3507 scale
.set(1.f
, 1.f
, 1.f
);
3508 if (!_Skeleton
.empty()) return; // scale already applied to skeleton
3509 if (!_Instance
.empty())
3511 const_cast<UInstance
&>(_Instance
).getScale(scale
);
3513 else if (!_Instances
.empty())
3515 if (!_Instances
[0].Current
.empty())
3517 const_cast<UInstance
&>(_Instances
[0].Current
).getScale(scale
);
3519 else if (!_Instances
[0].Loading
.empty())
3521 const_cast<UInstance
&>(_Instances
[0].Loading
).getScale(scale
);
3527 //----------------------------------------------------------------------
3528 bool CEntityCL::isAnOutpostEnemy() const
3530 if ( getOutpostId() != 0 )
3532 if( UserEntity
->getOutpostId() == getOutpostId() )
3534 if( UserEntity
->getOutpostSide() != getOutpostSide() )
3536 // same outpost but different side
3545 //----------------------------------------------------------------------
3546 bool CEntityCL::isAnOutpostAlly() const
3548 if ( getOutpostId() != 0 )
3550 if( UserEntity
->getOutpostId() == getOutpostId() )
3552 if( UserEntity
->getOutpostSide() == getOutpostSide() )
3554 // same outpost and same side
3563 //----------------------------------------------------------------------
3564 CVector
CEntityCL::dirToTarget() const
3567 CEntityCL
* target
= EntitiesMngr
.entity( targetSlot() );
3570 dir2Target
= target
->pos() - pos();
3572 dir2Target
.normalize();
3581 //----------------------------------------------------------------------
3582 void CEntityCL::setStateFx(const std::string
&fxName
)
3584 if (fxName
!= _StateFXName
)
3586 if (!_StateFX
.empty() && Scene
)
3588 Scene
->deleteInstance(_StateFX
);
3591 NL3D::UInstance instance
= Scene
->createInstance(fxName
);
3593 if (!instance
.empty())
3595 _StateFX
.cast (instance
);
3596 if (_StateFX
.empty())
3598 // shape found, but not a particle system
3599 Scene
->deleteInstance(instance
);
3603 _StateFX
.setScale(0.5, 0.5, 0.5);
3604 _StateFXName
= fxName
;
3610 //----------------------------------------------------------------------
3611 void CEntityCL::removeStateFx()
3613 if (!_StateFX
.empty() && Scene
)
3615 Scene
->deleteInstance(_StateFX
);
3616 _StateFXName
.clear();