1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 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 }// onStringAvailable //
2369 //-----------------------------------------------
2371 //-----------------------------------------------
2372 std::string
CEntityCL::getTitleFromName(const std::string
&name
)
2374 std::string::size_type p1
= name
.find('$');
2375 if (p1
!= string::npos
)
2377 std::string::size_type p2
= name
.find('$', p1
+ 1);
2378 if (p2
!= std::string::npos
)
2379 return name
.substr(p1
+1, p2
-p1
-1);
2382 return std::string();
2383 }// getTitleFromName //
2385 //-----------------------------------------------
2386 // removeTitleFromName
2387 //-----------------------------------------------
2388 std::string
CEntityCL::removeTitleFromName(const std::string
&name
)
2390 std::string::size_type p1
= name
.find('$');
2391 if (p1
== string::npos
)
2397 std::string::size_type p2
= name
.find('$', p1
+ 1);
2398 if (p2
!= string::npos
)
2400 return name
.substr(0, p1
) + name
.substr(p2
+ 1);
2404 return name
.substr(0, p1
);
2407 }// removeTitleFromName //
2409 //-----------------------------------------------
2410 // removeShardFromName
2411 //-----------------------------------------------
2412 std::string
CEntityCL::removeShardFromName(const std::string
&name
)
2414 // The string must contains a '(' and a ')'
2415 std::string::size_type p0
= name
.find('(');
2416 std::string::size_type p1
= name
.find(')');
2417 if(p0
==std::string::npos
|| p1
==std::string::npos
|| p1
<=p0
)
2420 // if it is the same as the shard name of the user, remove it
2421 if (!NLMISC::compareCaseInsensitive(name
.c_str() + p0
+ 1, p1
-p0
-1, PlayerSelectedHomeShardName
.c_str(), PlayerSelectedHomeShardName
.size()))
2422 return name
.substr(0,p0
) + name
.substr(p1
+1);
2423 // else don't modify
2428 //-----------------------------------------------
2429 // removeTitleAndShardFromName
2430 //-----------------------------------------------
2431 std::string
CEntityCL::removeTitleAndShardFromName(const std::string
&name
)
2433 return removeTitleFromName(removeShardFromName(name
));
2437 //-----------------------------------------------
2439 class CUpdateEntitiesColor
: public IActionHandler
2442 virtual void execute (CCtrlBase
* /* pCaller */, const string
&/* Params */)
2444 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2446 CEntityCL::_EntitiesColor
[CEntityCL::User
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:USER")->getValueRGBA();
2447 CEntityCL::_EntitiesColor
[CEntityCL::Player
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PLAYER")->getValueRGBA();
2448 CEntityCL::_EntitiesColor
[CEntityCL::NPC
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:NPC")->getValueRGBA();
2449 CEntityCL::_EntitiesColor
[CEntityCL::Fauna
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:FAUNA")->getValueRGBA();
2450 CEntityCL::_EntitiesColor
[CEntityCL::ForageSource
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:SOURCE")->getValueRGBA();
2451 CEntityCL::_DeadColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:DEAD")->getValueRGBA();
2452 CEntityCL::_TargetColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:TARGET")->getValueRGBA();
2453 CEntityCL::_GroupColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GROUP")->getValueRGBA();
2454 CEntityCL::_GuildColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GUILD")->getValueRGBA();
2455 CEntityCL::_UserMountColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:MOUNT")->getValueRGBA();
2456 CEntityCL::_UserPackAnimalColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:BEAST")->getValueRGBA();
2457 CEntityCL::_PvpEnemyColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPENEMY")->getValueRGBA();
2458 CEntityCL::_PvpAllyColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLY")->getValueRGBA();
2459 CEntityCL::_PvpAllyInTeamColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLYINTEAM")->getValueRGBA();
2460 CEntityCL::_PvpNeutralColor
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPNEUTRAL")->getValueRGBA();
2462 // don't save these colors in .icfg because players can't change them
2463 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::SGM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SGM")->getValueRGBA();
2464 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::GM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:GM")->getValueRGBA();
2465 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::VG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:VG")->getValueRGBA();
2466 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::SG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SG")->getValueRGBA();
2467 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::G
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:G")->getValueRGBA();
2469 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::CM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:CM")->getValueRGBA();
2470 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::EM
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EM")->getValueRGBA();
2471 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::EG
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EG")->getValueRGBA();
2472 CEntityCL::_GMTitleColor
[ CHARACTER_TITLE::OBSERVER
- CHARACTER_TITLE::BeginGmTitle
] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:OBSERVER")->getValueRGBA();
2475 REGISTER_ACTION_HANDLER (CUpdateEntitiesColor
, "update_entities_color");
2477 //-----------------------------------------------
2479 bool CEntityCL::isTarget () const
2481 return UserEntity
&& UserEntity
->selection() == _Slot
;
2484 //-----------------------------------------------
2486 bool CEntityCL::isInSameGuild () const
2488 if (Type
!= Player
&& Type
!= User
)
2491 const uint32 guildNameId
= this->getGuildNameID();
2492 if (guildNameId
!= 0 && UserEntity
&& guildNameId
== UserEntity
->getGuildNameID())
2498 //-----------------------------------------------
2500 bool CEntityCL::oneInLeague () const
2502 if (Type
!= Player
&& Type
!= User
)
2505 const uint32 leagueID
= getLeagueID();
2506 if ((UserEntity
&& (UserEntity
->getLeagueID() != 0)) || leagueID
!= 0)
2512 //-----------------------------------------------
2514 bool CEntityCL::isInSameLeague () const
2516 if (Type
!= Player
&& Type
!= User
)
2519 const uint32 leagueID
= getLeagueID();
2520 if ((leagueID
!= 0) && UserEntity
&& (leagueID
== UserEntity
->getLeagueID()))
2525 //-----------------------------------------------
2527 NLMISC::CRGBA
CEntityCL::getColor () const
2531 return _TargetColor
;
2537 return _UserMountColor
;
2539 if (isUserPackAnimal())
2540 return _UserPackAnimalColor
;
2542 if ( ( Type
== Player
|| Type
== User
) && _GMTitle
!= _InvalidGMTitleCode
)
2544 return _GMTitleColor
[_GMTitle
];
2547 if (Type
== Player
|| Type
== NPC
)
2552 if (isAnOutpostEnemy())
2554 return _PvpEnemyColor
;
2561 if (getPvpMode()&PVP_MODE::PvpFaction
)
2562 return CRGBA(min(255, _PvpEnemyColor
.R
+150), min(255, _PvpEnemyColor
.G
+150), min(255, _PvpEnemyColor
.B
+150),_PvpEnemyColor
.A
);
2564 return _PvpEnemyColor
;
2571 if (getPvpMode() & PVP_MODE::PvpFactionFlagged
)
2573 if(isInSameLeague())
2574 return CRGBA(max(0, _PvpAllyColor
.R
-100), max(0, _PvpAllyColor
.G
-100), max(0, _PvpAllyColor
.B
-100),_PvpAllyColor
.A
);
2575 return CRGBA(max(0, _PvpAllyInTeamColor
.R
-100), max(0, _PvpAllyInTeamColor
.G
-100), max(0, _PvpAllyInTeamColor
.B
-100),_PvpAllyInTeamColor
.A
);
2579 if(isInSameLeague())
2580 return _PvpAllyColor
;
2581 return _PvpAllyInTeamColor
;
2587 return _PvpNeutralColor
;
2594 if (isInSameLeague())
2595 return CRGBA(min(255, _GroupColor
.R
+50), min(255, _GroupColor
.G
+50), min(255, _GroupColor
.B
+50),_GroupColor
.A
);
2597 if (isInSameGuild())
2600 return _EntitiesColor
[Type
];
2604 //---------------------------------------------------
2606 // Return true if the current position is an indoor position.
2607 //---------------------------------------------------
2608 bool CEntityCL::indoor() const
2610 if(_Primitive
&& GR
)
2612 UGlobalPosition gPos
;
2613 _Primitive
->getGlobalPosition(gPos
, dynamicWI
);
2614 return GR
->isInterior(gPos
);
2616 // Return false if any problem
2621 //-----------------------------------------------
2623 //-----------------------------------------------
2624 void CEntityCL::pos(const NLMISC::CVectorD
&vect
)
2626 CVectorD checkDist
= _PositionLimiter
-vect
;
2628 if(checkDist
!= CVectorD::Null
)
2630 if(checkDist
.norm() > ClientCfg
.PositionLimiterRadius
)
2632 checkDist
.normalize();
2633 _PositionLimiter
= vect
+ checkDist
*ClientCfg
.PositionLimiterRadius
/2.0;
2640 //-----------------------------------------------
2642 void CEntityCL::updateMissionTarget()
2644 // Update the mission target flag
2645 _MissionTarget
= false;
2648 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2650 for (i
=0; i
<MAX_NUM_MISSIONS
; i
++)
2651 for (j
=0; j
<MAX_NUM_MISSION_TARGETS
; j
++)
2654 CCDBNodeLeaf
*prop
= EntitiesMngr
.getMissionTargetTitleDB(i
, j
); // NLGUI::CDBManager::getInstance()->getDbProp("SERVER:MISSIONS:"+toString(i)+":TARGET"+toString(j)+":TITLE", false);
2657 _MissionTarget
= _NameId
== (uint32
)prop
->getValue32();
2665 //-----------------------------------------------
2666 uint
CEntityCL::getGroundType() const
2669 const float srqCacheDistLimit
= 1;
2671 // If the user is not too far from cached pos, return same value
2672 if((_GroundTypeCachePos
-pos()).sqrnorm() < srqCacheDistLimit
)
2674 return _GroundTypeCache
;
2683 UGlobalPosition gPos
;
2684 getPrimitive()->getGlobalPosition(gPos
, dynamicWI
);
2685 gt
= GR
->getMaterial(gPos
);
2693 NL3D::CSurfaceInfo si
;
2694 _CollisionEntity
->getSurfaceInfo(pos(), si
);
2695 gt
= si
.UserSurfaceData
;
2699 _GroundTypeCachePos
= pos();
2700 _GroundTypeCache
= gt
;
2705 //---------------------------------------------------
2706 void CEntityCL::makeTransparent(bool t
)
2709 _TranspFactor
+= ((float)(DT
)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND
);
2711 _TranspFactor
-= ((float)(DT
)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND
);
2713 if (_TranspFactor
< 0.0) _TranspFactor
= 0.0;
2714 if (_TranspFactor
> 1.0) _TranspFactor
= 1.0;
2716 uint32 opaMin
= getOpacityMin();
2717 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
2719 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2721 _Instances
[i
].makeInstanceTransparent(opacity
, (uint8
)opaMin
);
2724 }// makeTransparent //
2726 //---------------------------------------------------
2727 void CEntityCL::makeTransparent(float factor
)
2729 clamp(factor
, 0.f
, 1.f
);
2730 _TranspFactor
= 1.f
- factor
;
2731 uint32 opaMin
= getOpacityMin();
2732 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
2734 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2736 _Instances
[i
].makeInstanceTransparent(opacity
, (uint8
)opaMin
);
2740 // ***************************************************************************
2741 void CEntityCL::setDiffuse(bool onOff
, NLMISC::CRGBA diffuse
)
2743 for (uint32 i
= 0; i
< _Instances
.size(); ++i
)
2745 _Instances
[i
].setDiffuse(onOff
, diffuse
);
2750 // ***************************************************************************
2751 CCDBNodeLeaf
*CEntityCL::getOpacityDBNode()
2753 if (!_OpacityMinNodeLeaf
)
2755 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2756 _OpacityMinNodeLeaf
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:USER_CHAR_OPA_MIN", false);
2758 return _OpacityMinNodeLeaf
;
2761 // ***************************************************************************
2762 uint32
CEntityCL::getOpacityMin()
2764 CCDBNodeLeaf
*pNL
= getOpacityDBNode();
2767 uint32 val
= pNL
->getValue32();
2768 clamp(val
, (uint32
)0, (uint32
)255);
2772 // this is an error case...
2776 // ***************************************************************************
2777 void CEntityCL::setOpacityMin(uint32 value
)
2779 CCDBNodeLeaf
*pNL
= getOpacityDBNode();
2782 clamp(value
, (uint32
)0, (uint32
)255);
2783 pNL
->setValue32(value
);
2788 // ***************************************************************************
2790 * Return true if the in-scene interface must be shown
2792 bool CEntityCL::mustShowInsceneInterface( bool enabledInSheet
) const
2795 (enabledInSheet
/*&& !CNPCIconCache::getInstance().getNPCIcon(this).getTextureMain().empty()*/) &&
2796 (_InSceneInterfaceEnabled
) &&
2797 ( ClientCfg
.Names
||
2799 ((getDisplayOSDForceOver() || ClientCfg
.ShowNameUnderCursor
) && slot()==SlotUnderCursor
) ||
2800 (ClientCfg
.ShowNameSelected
&& UserEntity
&& slot()==UserEntity
->selection()) ||
2801 (isInTeam() && !isUser ()) ||
2802 (UserEntity
&& ((UserEntity
->pos()-pos()).sqrnorm() < ClientCfg
.ShowNameBelowDistanceSqr
) && !isUser ())
2809 //-----------------------------------------------
2810 const char *CEntityCL::getBoneNameFromBodyPart(BODY::TBodyPart part
, BODY::TSide side
) const
2812 BODY::TBodyPart hominPart
= BODY::getMatchingHominBodyPart(part
);
2815 case BODY::HHead
: return "Bip01 Head";
2816 case BODY::HChest
: return "Bip01 Spine2";
2817 case BODY::HArms
: return side
== BODY::Left
? "Bip01 L UpperArm" : "Bip01 R UpperArm";
2818 case BODY::HHands
: return side
== BODY::Left
? "Bip01 L Hand" : "Bip01 R Hand";
2819 case BODY::HLegs
: return side
== BODY::Left
? "Bip01 L Calf" : "Bip01 R Calf";
2820 case BODY::HFeet
: return side
== BODY::Left
? "Bip01 L Foot" : "Bip01 R Foot";
2826 //-----------------------------------------------
2828 // Return a pointer on an instance structure.
2829 //-----------------------------------------------
2830 CEntityCL::SInstanceCL
*CEntityCL::idx2Inst(uint idx
)
2832 if(idx
< _Instances
.size()) // CEntityCL::BadIndex is the max so idx < ... mean idx != CEntityCL::BadIndex too
2833 return &_Instances
[idx
];
2840 //-----------------------------------------------
2841 void CEntityCL::updateIsInTeam ()
2843 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2847 // if UId not set, false
2848 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2851 for (uint i
=0; i
<MaxNumPeopleInTeam
; i
++)
2854 CCDBNodeLeaf
*uidProp
= EntitiesMngr
.getGroupMemberUidDB(i
);
2855 CCDBNodeLeaf
*presentProp
= EntitiesMngr
.getGroupMemberNameDB(i
);
2856 // If same Entity uid than the one in the Database, ok the entity is in the Player TEAM!!
2857 if (uidProp
&& uidProp
->getValue32() == (sint32
)dataSetId() &&
2858 presentProp
&& presentProp
->getValueBool() )
2861 buildInSceneInterface();
2865 buildInSceneInterface();
2868 //-----------------------------------------------
2869 void CEntityCL::updateIsUserAnimal ()
2871 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2873 _IsUserMount
= false;
2874 _IsUserPackAnimal
= false;
2876 // if UId not set, false
2877 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2880 // Am i a pack animal?
2881 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2884 CCDBNodeLeaf
*uidProp
= EntitiesMngr
.getBeastUidDB(i
);
2885 CCDBNodeLeaf
*statusProp
= EntitiesMngr
.getBeastStatusDB(i
);
2886 CCDBNodeLeaf
*typeProp
= EntitiesMngr
.getBeastTypeDB(i
);
2887 // I must have the same Id, and the animal entry must be ok.
2888 if(uidProp
&& statusProp
&& typeProp
&& uidProp
->getValue32() == (sint32
)dataSetId() &&
2889 ANIMAL_STATUS::isSpawned((ANIMAL_STATUS::EAnimalStatus
)(statusProp
->getValue32()) ))
2891 switch(typeProp
->getValue16())
2893 case ANIMAL_TYPE::Mount
: _IsUserMount
= true; break;
2896 case ANIMAL_TYPE::Packer
: _IsUserPackAnimal
= true; break;
2904 //-----------------------------------------------
2905 ANIMAL_STATUS::EAnimalStatus
CEntityCL::getPackAnimalStatus() const
2907 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2909 if(! (isUserPackAnimal() || isUserMount()))
2912 // Am i a pack animal?
2913 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2916 CCDBNodeLeaf
*uidProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i
), false);
2917 CCDBNodeLeaf
*statusProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i
), false);
2918 // I must have the same Id, and the animal entry must be ok.
2919 if(uidProp
&& statusProp
&& uidProp
->getValue32() == (sint32
)dataSetId())
2920 return (ANIMAL_STATUS::EAnimalStatus
)(statusProp
->getValue32());
2926 //-----------------------------------------------
2927 bool CEntityCL::getPackAnimalIndexInDB(sint
&dbIndex
) const
2929 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
2931 if(! (isUserPackAnimal() || isUserMount()))
2934 // Am i a pack animal?
2935 for (uint i
=0; i
<MAX_INVENTORY_ANIMAL
; i
++)
2938 CCDBNodeLeaf
*uidProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i
), false);
2939 CCDBNodeLeaf
*statusProp
= NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i
), false);
2940 // I must have the same Id, and the animal entry must be ok.
2941 if(uidProp
&& statusProp
&& uidProp
->getValue32() == (sint32
)dataSetId())
2951 //-----------------------------------------------
2952 void CEntityCL::dataSetId(CLFECOMMON::TClientDataSetIndex dataSet
)
2954 _DataSetId
= dataSet
;
2956 if (_Primitive
&& _Primitive
->UserData
== UserDataEntity
)
2957 _Primitive
->UserData
|= (((uint64
)_DataSetId
)<<16);
2959 // additionaly, on a UID change, must check the IsInTeam and IsAniml flags
2961 updateIsUserAnimal();
2963 // and update Bar Manager, only if correctly init
2964 if(_Slot
!=CLFECOMMON::INVALID_SLOT
&& _DataSetId
!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX
)
2965 CBarManager::getInstance()->addEntity(_Slot
, _DataSetId
);
2968 // ***************************************************************************
2969 void CEntityCL::updateVisible(const NLMISC::TTime
&/* time */, CEntityCL
* /* target */)
2971 // update some shadowmap properties
2972 updateShadowMapProperties();
2974 // For Skeleton Spawn Animation, must update some pos
2975 if(!_Skeleton
.empty())
2977 _Skeleton
.setSSSWOPos(pos());
2978 _Skeleton
.setSSSWODir(front());
2981 if (!R2::isEditionCurrent())
2983 // NB : if editor is enabled, then highlighting is managed in another fashion (there may be multiple-semihighlights)
2985 // Selection Highlight
2986 if(_VisualSelectionTime
!= 0)
2988 bool blinkOn
= false;
2989 sint64 t
= T1
-_VisualSelectionTime
;
2990 // hardcoded blink animation
2994 _VisualSelectionTime
= 0;
2996 setVisualSelectionBlink(blinkOn
, CRGBA::White
);
3000 // If i am the target
3002 // set semi-highlight
3003 setVisualSelectionBlink(true, CRGBA(100,100,100));
3004 // else If i am under cursor
3005 else if(ShowInterface
&& isUnderCursor())
3007 setVisualSelectionBlink(true, CRGBA::White
);
3009 // disable hightlight
3010 setVisualSelectionBlink(false, CRGBA::White
);
3015 // ***************************************************************************
3016 void CEntityCL::updateSomeClipped(const NLMISC::TTime
&/* time */, CEntityCL
* /* target */)
3018 // update some shadowmap properties
3019 updateShadowMapProperties();
3022 // ***************************************************************************
3023 void CEntityCL::updateClipped(const NLMISC::TTime
&/* currentTimeInMs */, CEntityCL
* /* target */)
3025 // hide only if I am not the target
3028 if (!_SelectionFX
.empty() && Scene
)
3030 Scene
->deleteInstance(_SelectionFX
);
3031 _SelectionFX
= NULL
;
3033 if (!_MouseOverFX
.empty() && Scene
)
3035 Scene
->deleteInstance(_MouseOverFX
);
3036 _MouseOverFX
= NULL
;
3042 // ***************************************************************************
3043 void CEntityCL::updateVisiblePostPos(const NLMISC::TTime
&/* currentTimeInMs */, CEntityCL
* /* target */)
3045 if (R2::isEditionCurrent()) return; // selection managed by r2 editor in edition mode
3047 bool bShowReticle
= true;
3049 CCDBNodeLeaf
*node
= (CCDBNodeLeaf
*)_ShowReticleLeaf
? &*_ShowReticleLeaf
3050 : &*(_ShowReticleLeaf
= NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_RETICLE", false));
3054 bShowReticle
= node
->getValueBool();
3057 // No-op if I am not the current UserEntity Target
3058 if(bShowReticle
&& isTarget())
3060 // activate selection fx
3061 if (_SelectionFX
.empty())
3063 // Keep a static instance of the selection FX
3064 NL3D::UInstance instance
= Scene
->createInstance(ClientCfg
.SelectionFX
);
3065 if (!instance
.empty())
3067 _SelectionFX
.cast (instance
);
3068 _SelectionFX
.setLoadBalancingGroup("SelectionFx");
3069 if (_SelectionFX
.empty())
3071 // shape found, but not a particle system
3072 Scene
->deleteInstance(instance
);
3080 if (!_SelectionFX
.empty() && Scene
)
3082 Scene
->deleteInstance(_SelectionFX
);
3086 // Mouse over SFX, only if the entity is selectable
3087 if (bShowReticle
&& ShowInterface
&& !isTarget() && isUnderCursor() && properties().selectable())
3089 // activate selection fx
3090 if (_MouseOverFX
.empty())
3092 // Keep a static instance of the selection FX
3093 NL3D::UInstance instance
= Scene
->createInstance(ClientCfg
.MouseOverFX
);
3094 if (!instance
.empty())
3096 _MouseOverFX
.cast (instance
);
3097 _MouseOverFX
.setLoadBalancingGroup("SelectionFx");
3098 if (_MouseOverFX
.empty())
3100 // shape found, but not a particle system
3101 Scene
->deleteInstance(instance
);
3109 if (!_MouseOverFX
.empty() && Scene
)
3111 Scene
->deleteInstance(_MouseOverFX
);
3115 if (!_StateFX
.empty())
3117 // Build a matrix for the fx
3118 NLMISC::CMatrix mat
;
3122 const CVector
&boxes
= _SelectBox
.getHalfSize ();
3123 // take mean of XY and Z
3124 float halfwidth
= std::max(boxes
.x
, boxes
.y
);
3125 halfwidth
= (halfwidth
+ boxes
.z
)/2;
3126 mat
.setScale (halfwidth
);
3128 // Pos. Avoid Flick in XY, but take precise Z
3130 position
= pos().asVector();
3131 position
.z
= _SelectBox
.getMin().z
;
3132 mat
.setPos(position
);
3133 mat
.setRot(dirMatrix());
3135 _StateFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3136 _StateFX
.setMatrix(mat
);
3138 _StateFX
.setClusterSystem(skeleton()->getClusterSystem());
3141 if (!_SelectionFX
.empty() || !_MouseOverFX
.empty())
3143 // Build a matrix for the fx
3144 NLMISC::CMatrix mat
;
3148 const CVector
&boxes
= _SelectBox
.getHalfSize ();
3149 // take mean of XY and Z
3150 float halfwidth
= std::max(boxes
.x
, boxes
.y
);
3151 halfwidth
= (halfwidth
+ boxes
.z
)/2;
3152 mat
.setScale (halfwidth
* 2 * ClientCfg
.SelectionFXSize
);
3154 // Pos. Avoid Flick in XY, but take precise Z
3156 position
= pos().asVector();
3157 position
.z
= _SelectBox
.getCenter().z
;
3158 mat
.setPos(position
);
3160 if (!_SelectionFX
.empty())
3162 _SelectionFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3163 _SelectionFX
.setMatrix(mat
);
3165 _SelectionFX
.setClusterSystem(skeleton()->getClusterSystem());
3166 // Colorize the selection depending of the level of the creature
3168 CRGBA col
= CRGBA(0,0,0);
3169 uint8 nForce
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:TARGET:FORCE_RATIO")->getValue8();
3170 _SelectionFX
.setUserParam(0, 0.1f
*nForce
+ 0.1f
);
3173 if (!_MouseOverFX
.empty())
3175 _MouseOverFX
.setTransformMode(NL3D::UTransformable::DirectMatrix
);
3176 _MouseOverFX
.setMatrix(mat
);
3178 _MouseOverFX
.setClusterSystem(skeleton()->getClusterSystem());
3184 // ***************************************************************************
3185 void CEntityCL::buildInSceneInterface ()
3189 // ***************************************************************************
3190 void CEntityCL::doSetVisualSelectionBlink(bool bOnOff
, CRGBA emitColor
)
3192 // blink all instances
3193 for(uint i
= 0; i
< instances().size(); ++i
)
3195 SInstanceCL
&inst
= instances()[i
];
3197 inst
.setEmissive(emitColor
);
3199 inst
.restoreEmissive();
3202 // also blink skeleton in CLod form
3203 if(!_Skeleton
.empty())
3206 _Skeleton
.setLodEmit(emitColor
);
3208 _Skeleton
.setLodEmit(CRGBA::Black
);
3212 // ***************************************************************************
3213 void CEntityCL::visualSelectionStart()
3215 _VisualSelectionTime
= T1
;
3218 // ***************************************************************************
3219 void CEntityCL::visualSelectionStop()
3221 _VisualSelectionTime
= 0;
3224 // ***************************************************************************
3225 bool CEntityCL::canCastShadowMap() const
3227 return ClientCfg
.Shadows
;
3230 // ***************************************************************************
3231 void CEntityCL::updateCastShadowMap()
3233 bool shadowOn
= canCastShadowMap();
3235 // if the entity has a skeleton
3238 // then shadow will be done through the skeleton
3239 skeleton()->enableCastShadowMap(shadowOn
);
3240 // disable shadows on instances
3241 if(_SomeInstanceCastShadowMap
)
3243 for(uint i
= 0; i
< _Instances
.size(); i
++)
3245 if(!_Instances
[i
].Current
.empty())
3246 _Instances
[i
].Current
.enableCastShadowMap(false);
3248 _SomeInstanceCastShadowMap
= false;
3253 // enable/disable cast shadow on instances instead (eg: on bot objects)
3254 // NB: must do it at each updateCastShadowMap(), cause don't know if an instance has been added or not
3255 for(uint i
= 0; i
< _Instances
.size(); i
++)
3257 if(!_Instances
[i
].Current
.empty())
3259 _Instances
[i
].Current
.enableCastShadowMap(shadowOn
);
3263 _SomeInstanceCastShadowMap
= shadowOn
;
3266 // if shadow enabled, update the shadow properties
3271 skeleton()->setShadowMapDirectionZThreshold(_ShadowMapZDirClamp
);
3272 skeleton()->setShadowMapMaxDepth(_ShadowMapMaxDepth
);
3276 for(uint i
= 0; i
< _Instances
.size(); i
++)
3278 if(!_Instances
[i
].Current
.empty())
3280 _Instances
[i
].Current
.setShadowMapDirectionZThreshold(_ShadowMapZDirClamp
);
3281 _Instances
[i
].Current
.setShadowMapMaxDepth(_ShadowMapMaxDepth
);
3288 // ***************************************************************************
3289 void CEntityCL::updateShadowMapProperties()
3292 Choose the z clamp direction whether or not the player is on "interior" stuff.
3293 In "interior" stuff, the ZClamp direction is lesser, to avoid some problems of
3294 "cast shadow behind the walls"
3296 Also choose the MaxDepth of shadow map whether or not the player is on "interior" stuff.
3297 In "interior" stuff, the MaxDepth is lesser to, to avoid some problems with the "bud":
3298 when the player go up stairs and when in the "bud", the shadow still appears on landscape
3300 float zDirClampWanted
= ClientCfg
.ShadowZDirClampLandscape
;
3301 float maxDepth
= ClientCfg
.ShadowMaxDepthLandscape
;
3304 zDirClampWanted
= ClientCfg
.ShadowZDirClampInterior
;
3305 maxDepth
= ClientCfg
.ShadowMaxDepthInterior
;
3309 if(_ShadowMapZDirClamp
!=zDirClampWanted
|| _ShadowMapMaxDepth
!=maxDepth
)
3311 // if some time passed since last update
3312 sint64 dt
= T1
-_ShadowMapPropertyLastUpdate
;
3315 // update _ShadowMapZDirClamp
3316 if(_ShadowMapZDirClamp
<zDirClampWanted
)
3318 _ShadowMapZDirClamp
+= ClientCfg
.ShadowZDirClampSmoothSpeed
* 0.001f
* dt
;
3319 if(_ShadowMapZDirClamp
>zDirClampWanted
)
3320 _ShadowMapZDirClamp
= zDirClampWanted
;
3322 else if(_ShadowMapZDirClamp
>zDirClampWanted
)
3324 _ShadowMapZDirClamp
-= ClientCfg
.ShadowZDirClampSmoothSpeed
* 0.001f
* dt
;
3325 if(_ShadowMapZDirClamp
<zDirClampWanted
)
3326 _ShadowMapZDirClamp
= zDirClampWanted
;
3329 // update _ShadowMapMaxDepth
3330 if(_ShadowMapMaxDepth
<maxDepth
)
3332 _ShadowMapMaxDepth
+= ClientCfg
.ShadowMaxDepthSmoothSpeed
* 0.001f
* dt
;
3333 if(_ShadowMapMaxDepth
>maxDepth
)
3334 _ShadowMapMaxDepth
=maxDepth
;
3336 else if(_ShadowMapMaxDepth
>maxDepth
)
3338 _ShadowMapMaxDepth
-= ClientCfg
.ShadowMaxDepthSmoothSpeed
* 0.001f
* dt
;
3339 if(_ShadowMapMaxDepth
<maxDepth
)
3340 _ShadowMapMaxDepth
=maxDepth
;
3343 // update shadowMap, to update the clamp zdirection, and the shadow depth
3344 updateCastShadowMap();
3348 // bkup last time of update
3349 _ShadowMapPropertyLastUpdate
= T1
;
3352 // ***************************************************************************
3353 void CEntityCL::setOrderingLayer(uint layer
)
3355 if (!_Skeleton
.empty()) _Skeleton
.setOrderingLayer(layer
);
3359 void CEntityCL::displayable(bool d
)
3362 // :KLUDGE: Hide selection FX
3363 if (!_Displayable
&& !_SelectionFX
.empty() && Scene
)
3365 Scene
->deleteInstance(_SelectionFX
);
3369 // ***************************************************************************
3370 EGSPD::CPeople::TPeople
CEntityCL::people() const
3372 return EGSPD::CPeople::Unknown
;
3375 // ***************************************************************************
3376 void CEntityCL::setPeople(EGSPD::CPeople::TPeople
/* people */)
3380 // ***************************************************************************
3381 void CEntityCL::forceEvalAnim()
3385 // find highest father in the hierarchy
3386 CEntityCL
*parentEntity
= this;
3389 CEntityCL
*nextParent
= EntitiesMngr
.entity(parentEntity
->parent());
3390 if (!nextParent
) break;
3391 parentEntity
= nextParent
;
3394 // Snap the parent entity to the ground.
3396 H_AUTO ( RZ_Client_Entity_CL_Update_Snap_To_Ground
)
3397 parentEntity
->snapToGround();
3400 // Animate the parent entity (and also child entities)
3402 H_AUTO ( RZ_Client_Entity_CL_Update_Display
)
3403 parentEntity
->updateDisplay();
3409 // ***************************************************************************
3410 const NLMISC::CAABBox
&CEntityCL::localSelectBox()
3412 // recompute the selection box?
3413 if(_LastLocalSelectBoxComputeTime
<T1
)
3415 _LastLocalSelectBoxComputeTime
=T1
;
3418 // if skeleton, compute aabox from precise skeleton method
3419 if(!_Skeleton
.empty())
3421 // Don't compute if in LOD form (else flick because sometimes valid because of shadow animation)
3422 if(!_Skeleton
.isDisplayedAsLodCharacter())
3426 static volatile bool useBoneSphere = true;
3427 if (useBoneSphere) computed = _Skeleton.computeRenderedBBoxWithBoneSphere(_LocalSelectBox, false);
3428 else computed = _Skeleton.computeRenderedBBox(_LocalSelectBox);
3432 // apply local offset due to skeleton animation
3433 CMatrix invMat = _DirMatrix;
3434 invMat.setPos(pos());
3436 CVector localOffset = invMat * _Skeleton.getPos();
3437 _LocalSelectBox.setCenter(_LocalSelectBox.getCenter() + localOffset);
3438 static volatile float rot = -1.f;
3440 rotMat.rotateZ((float) Pi * rot / 2);
3441 CVector newHalfSize = rotMat * _LocalSelectBox.getHalfSize();
3442 newHalfSize.x = fabsf(newHalfSize.x);
3443 newHalfSize.y = fabsf(newHalfSize.y);
3444 newHalfSize.z = fabsf(newHalfSize.z);
3445 _LocalSelectBox.setHalfSize(newHalfSize);
3448 if (_Skeleton
.computeRenderedBBoxWithBoneSphere(_LocalSelectBox
, false))
3451 // apply local offset due to skeleton animation
3452 CMatrix invMat
= _DirMatrix
;
3453 invMat
.setPos(pos());
3455 CMatrix localMat
= invMat
* _Skeleton
.getMatrix();
3456 _LocalSelectBox
= CAABBox::transformAABBox(localMat
, _LocalSelectBox
);
3460 // else compute from static bot object
3464 // try with _Instances array first
3465 if(!_Instances
.empty())
3466 inst
= _Instances
[0].Current
;
3467 // Fallback to _Instance (??)
3471 // if static instance found
3474 inst
.getShapeAABBox(_LocalSelectBox
);
3480 // if not found, fallback to default bbox
3483 _LocalSelectBox
.setCenter(_Aabbox
.getCenter() - pos().asVector());
3484 _LocalSelectBox
.setHalfSize(_Aabbox
.getHalfSize());
3489 getMeshDefaultScale(scale
);
3490 const CVector
&halfSize
= _LocalSelectBox
.getHalfSize();
3491 const CVector
¢er
= _LocalSelectBox
.getCenter();
3492 _LocalSelectBox
.setHalfSize(CVector(halfSize
.x
* scale
.x
, halfSize
.y
* scale
.y
, halfSize
.z
* scale
.z
));
3493 _LocalSelectBox
.setCenter(CVector(center
.x
* scale
.x
, center
.y
* scale
.y
, center
.z
* scale
.z
));
3497 // Return the selection box.
3498 return _LocalSelectBox
;
3501 //----------------------------------------------------------------------
3502 void CEntityCL::getMeshDefaultScale(NLMISC::CVector
&scale
) const
3504 scale
.set(1.f
, 1.f
, 1.f
);
3505 if (!_Skeleton
.empty()) return; // scale already applied to skeleton
3506 if (!_Instance
.empty())
3508 const_cast<UInstance
&>(_Instance
).getScale(scale
);
3510 else if (!_Instances
.empty())
3512 if (!_Instances
[0].Current
.empty())
3514 const_cast<UInstance
&>(_Instances
[0].Current
).getScale(scale
);
3516 else if (!_Instances
[0].Loading
.empty())
3518 const_cast<UInstance
&>(_Instances
[0].Loading
).getScale(scale
);
3524 //----------------------------------------------------------------------
3525 bool CEntityCL::isAnOutpostEnemy() const
3527 if ( getOutpostId() != 0 )
3529 if( UserEntity
->getOutpostId() == getOutpostId() )
3531 if( UserEntity
->getOutpostSide() != getOutpostSide() )
3533 // same outpost but different side
3542 //----------------------------------------------------------------------
3543 bool CEntityCL::isAnOutpostAlly() const
3545 if ( getOutpostId() != 0 )
3547 if( UserEntity
->getOutpostId() == getOutpostId() )
3549 if( UserEntity
->getOutpostSide() == getOutpostSide() )
3551 // same outpost and same side
3560 //----------------------------------------------------------------------
3561 CVector
CEntityCL::dirToTarget() const
3564 CEntityCL
* target
= EntitiesMngr
.entity( targetSlot() );
3567 dir2Target
= target
->pos() - pos();
3569 dir2Target
.normalize();
3578 //----------------------------------------------------------------------
3579 void CEntityCL::setStateFx(const std::string
&fxName
)
3581 if (fxName
!= _StateFXName
)
3583 if (!_StateFX
.empty() && Scene
)
3585 Scene
->deleteInstance(_StateFX
);
3588 NL3D::UInstance instance
= Scene
->createInstance(fxName
);
3590 if (!instance
.empty())
3592 _StateFX
.cast (instance
);
3593 if (_StateFX
.empty())
3595 // shape found, but not a particle system
3596 Scene
->deleteInstance(instance
);
3600 _StateFX
.setScale(0.5, 0.5, 0.5);
3601 _StateFXName
= fxName
;
3607 //----------------------------------------------------------------------
3608 void CEntityCL::removeStateFx()
3610 if (!_StateFX
.empty() && Scene
)
3612 Scene
->deleteInstance(_StateFX
);
3613 _StateFXName
.clear();