Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / entity_cl.cpp
blob8f96cb96bda6920b7e79474f61b06ff14b5b7f01
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
3 //
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>
8 //
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/>.
25 /////////////
26 // INCLUDE //
27 /////////////
28 #include "stdpch.h"
29 // Sheets
30 #include "client_sheets/item_sheet.h"
31 // Misc
32 #include "nel/misc/vectord.h"
33 #include "nel/misc/vector_2f.h"
34 #include "nel/misc/bsphere.h"
35 // Interface 3D
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
46 // Pacs Interface
47 #include "nel/pacs/u_global_position.h"
48 // Client
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"
55 #include "entities.h"
56 #include "ingame_database_manager.h"
57 #include "debug_client.h"
58 #include "misc.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"
67 #include "view.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"
73 #include "weather.h"
74 #include "npc_icon.h"
75 // Game share
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"
83 ///////////
84 // USING //
85 ///////////
86 using namespace NLMISC;
87 using namespace NL3D;
88 using namespace NLPACS;
89 using namespace std;
90 using namespace CLFECOMMON;
94 ////////////
95 // EXTERN //
96 ////////////
97 extern UDriver *Driver;
98 extern UScene *Scene;
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;
108 ////////////
109 // GLOBAL //
110 ////////////
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;
131 // Context help
132 extern void contextHelp (const std::string &help);
134 /////////////
135 // METHODS //
136 /////////////
139 //-----------------------------------------------
140 // showStaticFXs
142 //-----------------------------------------------
143 void CEntityCL::SInstanceCL::showStaticFXs()
145 for(std::vector<UInstance>::iterator it = StaticFXs.begin(); it != StaticFXs.end(); ++it)
147 if (!it->empty())
149 (*it).show();
153 } // showStaticFXs //
156 //-----------------------------------------------
157 // hideStaticFXs
159 //-----------------------------------------------
160 void CEntityCL::SInstanceCL::hideStaticFXs()
162 for(std::vector<UInstance>::iterator it = StaticFXs.begin(); it != StaticFXs.end(); ++it)
164 if (!it->empty())
166 (*it).hide();
170 } // hideStaticFXs //
173 //---------------------------------------------------
174 //---------------------------------------------------
175 bool CEntityCL::SInstanceCL::createLoading(const string &strShapeName, const string &strStickPoint, sint texture, bool clearIfFail)
177 // create the new instance
178 UInstance newInst;
179 if(!strShapeName.empty())
181 newInst= Scene->createInstance(strShapeName);
182 // if fails to create and not clearIfFail, return
183 if(newInst.empty() && !clearIfFail)
184 return false;
187 // Remove the old loading instance.
188 if(!Loading.empty())
190 Scene->deleteInstance(Loading);
191 LoadingName.clear();
194 // if the new instance is NULL, then clean ALL
195 if( newInst.empty() )
197 if(!Current.empty())
199 releaseStaticFXs();
200 Scene->deleteInstance(Current);
201 CurrentName.clear();
204 // else setup into loading
205 else
207 Loading = newInst;
208 LoadingName = strShapeName;
209 TextureSet = texture;
210 StickPoint = strStickPoint;
211 Loading.hide();
213 // Select the texture.
214 if(texture != -1)
216 // Set the right texture variation.
217 Loading.selectTextureSet((uint) texture);
219 else
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)
239 ApplyColor = true;
241 ACSkin = skin;
242 ACUser = user;
243 ACHair = hair;
244 ACEyes = eyes;
247 //---------------------------------------------------
248 //---------------------------------------------------
249 void CEntityCL::SInstanceCL::setScale(const CVector &scale)
251 // Bkup for new created loading instances
252 _Scale= scale;
254 // Set Scale to any created ones (relatively from scale exported by artists)
255 if(!Current.empty())
256 Current.setRelativeScale(_Scale);
257 if(!Loading.empty())
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);
269 if (ApplyColor)
271 CColorSlotManager::TIntCouple array[4];
272 // Skin
273 array[0].first = (uint)0; array[0].second = (uint)ACSkin;
274 // User Color
275 array[1].first = (uint)1; array[1].second = (uint)ACUser;
276 // Hair Color
277 array[2].first = (uint)2; array[2].second = (uint)ACHair;
278 // Eyes Color
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
287 // or
288 // 2 - unbind them from the current instance and rebind them to the loading instance
290 return Loading;
293 //---------------------------------------------------
294 void CEntityCL::SInstanceCL::releaseStaticFXs()
296 if (Scene)
298 for(std::vector<UInstance>::iterator it = StaticFXs.begin(); it != StaticFXs.end(); ++it)
300 if (!it->empty())
302 Scene->deleteInstance(*it);
306 StaticFXs.clear();
309 //---------------------------------------------------
310 bool CEntityCL::isAsyncLoading() const
312 for(uint k = 0; k < _Instances.size(); ++k)
314 if (!_Instances[k].Loading.empty()) return true;
316 return false;
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);
330 if (async)
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;
343 bool bShow = true;
345 if (!Current.empty())
347 // copy temp info
348 bShow = (Current.getVisibility() == UInstance::Show);
351 // Delete current instances
352 if (!Current.empty())
354 Scene->deleteInstance(Current);
355 CurrentName.clear();
359 // Assign loading to current
360 Current = Loading;
361 CurrentName = LoadingName;
362 Loading = NULL;
363 LoadingName.clear();
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.
376 else
378 sint stickID = Skeleton.getBoneIdByName(StickPoint);
379 if(stickID != -1)
380 Skeleton.stickObject(Current, stickID);
381 else
382 nlwarning("Skeleton '%s' is missing bone '%s' for object attachment.", Skeleton.getShapeName().c_str(), StickPoint.c_str());
386 // Show current instance
387 if(bShow)
389 if(KeepHiddenWhenLoaded == false)
391 Current.show();
393 else
394 KeepHiddenWhenLoaded = false;
397 releaseStaticFXs();
399 // Add static fxs
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);
411 if (boneID != -1)
413 UInstance instance = Scene->createInstance(name);
414 if (!instance.empty())
416 instance.setTransformMode(UTransform::DirectMatrix);
417 CMatrix mat;
418 mat.setPos(FXItemSheet->FX.getStaticFXOffset(k));
419 instance.setMatrix(mat);
420 Skeleton.stickObject(instance, boneID);
421 StaticFXs.push_back(instance);
423 else
425 nlwarning("Can't create static fx %s sticked on bone %s", name.c_str(), boneName.c_str());
428 else
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
441 UInstance insts[2];
442 insts[0]= Current;
443 insts[1]= Loading;
444 for(uint i=0;i<2;i++)
446 // test if instance is valid
447 UInstance inst= insts[i];
448 if(inst.empty())
449 continue;
450 UShape shape= inst.getShape();
451 if(shape.empty())
452 continue;
453 uint numMats= shape.getNumMaterials();
454 if(numMats==0)
455 continue;
456 if(numMats!=inst.getNumMaterials())
457 continue;
459 // For all materials
460 for(uint j=0;j<numMats;j++)
461 // set emit
462 inst.getMaterial(j).setEmissive(emit);
466 //---------------------------------------------------
467 void CEntityCL::SInstanceCL::restoreEmissive()
469 // Do it on both Loading and Current, to avoid any problem
470 UInstance insts[2];
471 insts[0]= Current;
472 insts[1]= Loading;
473 for(uint i=0;i<2;i++)
475 // test if instance is valid
476 UInstance inst= insts[i];
477 if(inst.empty())
478 continue;
479 UShape shape= inst.getShape();
480 if(shape.empty())
481 continue;
482 uint numMats= shape.getNumMaterials();
483 if(numMats==0)
484 continue;
485 if(numMats!=inst.getNumMaterials())
486 continue;
488 // For all materials
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
505 UInstance insts[2];
506 insts[0]= Current;
507 insts[1]= Loading;
508 for(uint i=0;i<2;i++)
510 // test if instance is valid
511 UInstance inst= insts[i];
512 if(inst.empty())
513 continue;
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);
528 /////////////
529 // METHODS //
530 /////////////
531 //---------------------------------------------------
532 // CEntityCL :
533 // Dafault constructor
534 //---------------------------------------------------
535 CEntityCL::CEntityCL()
537 // Initialize the object.
538 init();
539 Type = Entity;
540 _SelectionFX = NULL;
541 _MouseOverFX = NULL;
542 _StateFX = NULL;
543 _GMTitle = _InvalidGMTitleCode;
544 _LastLocalSelectBoxComputeTime = 0;
545 _InSceneInterfaceEnabled = true;
546 }// CEntityCL //
548 //---------------------------------------------------
549 // ~CEntityCL :
550 // Destructor
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.
562 if(Scene)
564 // Remove skeleton.
565 if(!_Skeleton.empty())
567 Scene->deleteSkeleton(_Skeleton);
568 _Skeleton = 0;
570 // Remove Instance.
571 if(!_Instance.empty())
573 Scene->deleteInstance(_Instance);
574 _Instance = 0;
577 // Delete Instances.
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.
591 else
593 _Skeleton = 0;
594 _Instance = 0;
597 // Remove the collision entity.
598 removeCollisionEntity();
599 // Remove the primitive.
600 removePrimitive();
602 // Release the animation playlist
603 if(_PlayList)
605 EAM->deletePlayList(_PlayList);
606 _PlayList = 0;
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()));
631 // Next Child
632 it++;
634 // Remove the list
635 _Children.clear();
636 }// ~CEntityCL //
638 //-----------------------------------------------
639 // init :
640 // Initialize the Object with this function for all constructors.
641 //-----------------------------------------------
642 void CEntityCL::init()
644 // No parent.
645 _Parent = CLFECOMMON::INVALID_SLOT;
646 // No entry for the moment.
647 _DBEntry = 0;
649 // _Name = NULL;
651 // Bot Objects flags
652 _DisplayInRadar= true;
653 _DisplayOSDName= true;
654 _DisplayOSDBars= true;
655 _DisplayOSDForceOver= false;
656 _Traversable= true;
657 _CanTurn = true; // must be initialized beforce calling front()
658 _ForbidClipping = false;
660 // Entity Up.
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.
673 _Flyer = false;
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.
681 _Skeleton = 0;
682 // No Instance at the beginning.
683 _Instance = 0;
684 // No primitive at the beginning.
685 _Primitive = 0;
686 // No collision Entity at the beginning.
687 _CollisionEntity = 0;
688 // No PlayList at the beginning.
689 _PlayList = 0;
690 _FacePlayList = 0;
692 // AABBox
693 CAABBox aabbox;
694 CVector min = CVector(-0.5f, -0.5f, 0);
695 CVector max = CVector( 0.5f, 0.5f, 2);
696 aabbox.setMinMax(min, max);
697 box(aabbox);
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.
704 _First_Pos = true;
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;
710 _NPCAlias = 0;
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;
717 // init _LogicInfo3D
718 _LogicInfo3D.Self= this;
720 // Async texture
721 _AsyncTextureLoading= false;
722 _LodTextureDirty= false;
724 // Angle to have with the target when in combat mode with.
725 _TargetAngle = 0.0;
727 // Must do a setGlobalPosition
728 _SetGlobalPositionDone = false;
729 _SnapToGroundDone = false;
731 // Entity are not displayed at the beginning.
732 _Displayable = true;
734 _Clipped = false;
736 if (ClientCfg.Local)
738 _Title = "Newbie";
739 _HasReservedTitle = false;
740 _EntityName = "Name";
742 _NameId = 0;
744 _PermanentStatutIcon.clear();
746 // Not a mission target by default
747 _MissionTarget = false;
748 // The entity has not moved for the time.
749 _HasMoved = false;
750 _TranspFactor = 0.0f;
751 _IsInTeam= false;
752 _IsUserMount= false;
753 _IsUserPackAnimal= false;
755 // GroundTypeCache
756 _GroundTypeCachePos= CVectorD::Null;
757 _GroundTypeCache= 0;
759 _StateFX = NULL;
760 _StateFXName.clear();
761 _SelectionFX = NULL;
762 _MouseOverFX = NULL;
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;
777 }// init //
779 //-----------------------------------------------
780 // initialize :
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.
790 initProperties();
791 }// initialize //
793 //-----------------------------------------------
794 // initPrimitive :
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).
800 if(_Primitive)
802 nlwarning("ENT:initPrimitive:%d: There is already a primitive -> _Primitive = 0.", _Slot);
803 _Primitive = 0;
806 // **** Create the primitive
807 bool primitiveOk= false;
808 if(PACS)
810 _Primitive = PACS->addCollisionablePrimitive(dynamicWI, 1);
811 if(_Primitive)
813 _Primitive->setReactionType(reactionType);
814 _Primitive->setTriggerType(triggerType);
815 _Primitive->setAbsorbtion(0);
816 // Set the collision if the radius is > 0
817 if(radius > 0.0f)
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.
827 // Maybe be a Box
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);
833 if(length > width)
835 CVector min = CVector(-length, -length, 0.0f);
836 CVector max = CVector( length, length, height);
837 _Aabbox.setMinMax(min, max);
839 else
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
848 else
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);
864 primitiveOk= true;
866 else
867 nlwarning("CEntityCL::initPrimitive:%d: Cannot create the _Primitive.", _Slot);
869 else
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
874 if(clipRadius<=0.f)
876 // Cylinder Colision?
877 if(radius > 0.0f)
879 clipRadius= radius;
881 // Box Colision?
882 else if(length > 0.0f)
884 clipRadius= max(width, length);
886 // Non-collisionnable entity
887 else
889 // Backward compatibility: use width for radius
890 clipRadius= width;
893 // at least 0.5f clip radius
894 clipRadius= max(clipRadius, 0.5f);
896 // if clip height not specified
897 if(clipHeight<=0.f)
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)
903 CAABBox clipBox;
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
910 return primitiveOk;
911 }// initPrimitive //
914 //-----------------------------------------------
915 // initProperties :
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();
933 if (nodePtr)
935 CCDBNodeBranch *nodeRoot = dynamic_cast<CCDBNodeBranch*>(nodePtr->getNode(0));
936 if(!nodeRoot)
938 nlwarning("CEntityCL::updateVisualProperty : There is no entry in the DB for entities (current slot %d).", _Slot);
939 return;
942 CCDBNodeBranch *nodGrp = dynamic_cast<CCDBNodeBranch*>(nodeRoot->getNode(_Slot));
943 if(nodGrp == 0)
945 nlwarning("CEntityCL::updateVisualProperty : Cannot find the entity '%d' in the database.", _Slot);
946 return;
949 // Get The property ptr.
950 CCDBNodeLeaf *nodeProp = dynamic_cast<CCDBNodeLeaf*>(nodGrp->getNode(prop));
951 if(nodeProp == 0)
953 nlwarning("CEntityCL::updateVisualProperty : Cannot find the property '%d' for the slot %d.", prop, _Slot);
954 return;
957 switch(prop)
959 case PROPERTY_POSITION:
960 updateVisualPropertyPos(gameCycle, nodeProp->getValue64(), predictedInterval);
961 break;
963 case PROPERTY_ORIENTATION:
964 updateVisualPropertyOrient(gameCycle, nodeProp->getValue64());
965 break;
967 case PROPERTY_BEHAVIOUR:
968 updateVisualPropertyBehaviour(gameCycle, nodeProp->getValue64());
969 break;
971 case PROPERTY_NAME_STRING_ID:
972 updateVisualPropertyName(gameCycle, nodeProp->getValue64());
973 break;
975 case PROPERTY_TARGET_ID:
976 updateVisualPropertyTarget(gameCycle, nodeProp->getValue64());
978 break;
980 case PROPERTY_MODE:
981 updateVisualPropertyMode(gameCycle, nodeProp->getValue64());
982 break;
984 case PROPERTY_VPA:
985 updateVisualPropertyVpa(gameCycle, nodeProp->getValue64());
986 break;
988 case PROPERTY_VPB:
989 updateVisualPropertyVpb(gameCycle, nodeProp->getValue64());
990 break;
992 case PROPERTY_VPC:
993 updateVisualPropertyVpc(gameCycle, nodeProp->getValue64());
994 break;
996 case PROPERTY_ENTITY_MOUNTED_ID:
997 updateVisualPropertyEntityMounted(gameCycle, nodeProp->getValue64());
998 break;
1000 case PROPERTY_RIDER_ENTITY_ID:
1001 updateVisualPropertyRiderEntity(gameCycle, nodeProp->getValue64());
1002 break;
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);
1009 break;
1011 case PROPERTY_VISUAL_FX:
1012 updateVisualPropertyVisualFX(gameCycle, nodeProp->getValue64());
1013 break;
1015 // Property to update the contextual menu, and some important status
1016 case PROPERTY_CONTEXTUAL:
1017 updateVisualPropertyContextual(gameCycle, nodeProp->getValue64());
1018 break;
1020 case PROPERTY_BARS:
1021 updateVisualPropertyBars(gameCycle, nodeProp->getValue64());
1022 break;
1024 case PROPERTY_GUILD_SYMBOL:
1025 updateVisualPropertyGuildSymbol(gameCycle, nodeProp->getValue64());
1026 break;
1028 case PROPERTY_GUILD_NAME_ID:
1029 updateVisualPropertyGuildNameID(gameCycle, nodeProp->getValue64());
1030 break;
1032 case PROPERTY_EVENT_FACTION_ID:
1033 updateVisualPropertyEventFactionID(gameCycle, nodeProp->getValue64());
1034 break;
1036 case PROPERTY_PVP_MODE:
1037 updateVisualPropertyPvpMode(gameCycle, nodeProp->getValue64());
1038 break;
1040 case PROPERTY_PVP_CLAN:
1041 updateVisualPropertyPvpClan(gameCycle, nodeProp->getValue64());
1042 break;
1044 case PROPERTY_OWNER_PEOPLE:
1045 updateVisualPropertyOwnerPeople(gameCycle, nodeProp->getValue64());
1046 break;
1048 case PROPERTY_OUTPOST_INFOS:
1049 updateVisualPropertyOutpostInfos(gameCycle, nodeProp->getValue64());
1050 break;
1052 // case PROPERTY_STATUS:
1053 // updateVisualPropertyStatus(gameCycle, nodeProp->getValue64());
1054 // break;
1056 default:
1057 nlwarning("CEntityCL::updateVisualProperty : Unknown Property '%d' for the entity in the slot '%d'.", prop, _Slot);
1058 break;
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 //-----------------------------------------------
1079 // skeleton :
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.
1086 if(!Scene)
1088 pushDebugStr("No scene allocated -> Cannot create the skeleton.");
1089 _Skeleton = 0;
1090 return 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.");
1103 return 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.
1113 if(_PlayList)
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);
1123 else
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);
1130 else
1131 pushDebugStr("Channel 'rotquat' not found.");
1134 else
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);
1143 // Update Shadow
1144 updateCastShadowMap();
1146 else
1147 pushDebugStr(toString("Cannot create the Skeleton '%s', the file probably not exist.", filename.c_str()));
1149 // Return the skeleton pointer.
1150 return skeleton();
1151 }// skeleton //
1154 //-----------------------------------------------
1155 // addInstance :
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.
1166 uint32 idx;
1167 // Replace Instance
1168 if(instIdx < _Instances.size()) // And so instIdx != CEntityCL::BadIndex
1170 // Index given from parameters so do not change.
1171 idx = instIdx;
1173 else
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);
1190 return idx;
1192 // else create
1193 else
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.
1218 return idx;
1219 }// addInstance //
1222 //---------------------------------------------------
1223 // show :
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())
1231 if(s)
1232 _Skeleton.show();
1233 else
1234 _Skeleton.hide();
1236 else if(!_Instance.empty())
1238 if(s)
1239 _Instance.show();
1240 else
1241 _Instance.hide();
1243 else
1245 if (s)
1247 for(std::vector<SInstanceCL>::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
1249 if (!it->Current.empty()) it->Current.show();
1252 else
1254 for(std::vector<SInstanceCL>::iterator it = _Instances.begin(); it != _Instances.end(); ++it)
1256 if (!it->Current.empty()) it->Current.hide();
1260 }// show //
1262 //-----------------------------------------------
1263 // hideSkin :
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();
1275 }// hideSkin //
1278 //---------------------------------------------------
1279 // up :
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 !");
1288 return;
1291 // Compute the up vector
1292 _Up = vect;
1293 _Up.normalize();
1294 }// up //
1296 //---------------------------------------------------
1297 // front :
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)
1308 return false;
1309 return setVect(_Front, vect, compute, check);
1310 }// front //
1312 //---------------------------------------------------
1313 // dir :
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);
1328 return true;
1330 return false;
1331 }// dir //
1334 //---------------------------------------------------
1335 // posBox :
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);
1344 }// posBox //
1346 //---------------------------------------------------
1347 // box :
1348 // Set the box.
1349 // \param box : an axis aligned bounding box to apply to the entity.
1350 //---------------------------------------------------
1351 void CEntityCL::box(const CAABBox &box)
1353 // Copy the Box.
1354 _Aabbox = box;
1355 // position the box around the entity.
1356 posBox(pos());
1357 }// box //
1360 //-----------------------------------------------
1361 // lastFramePACSPos :
1362 // Return the last frame PACS position.
1363 //-----------------------------------------------
1364 bool CEntityCL::lastFramePACSPos(NLPACS::UGlobalPosition &result) const
1366 if(_Primitive)
1368 result = _LastFramePACSPos;
1369 if(result.InstanceId != -1)
1370 return true;
1371 else
1372 return false;
1374 else
1375 return false;
1376 }// lastFramePACSPos //
1378 //-----------------------------------------------
1379 // currentPACSPos :
1380 // Return the current PACS position.
1381 //-----------------------------------------------
1382 bool CEntityCL::currentPACSPos(NLPACS::UGlobalPosition &result) const
1384 if(_Primitive)
1386 _Primitive->getGlobalPosition(result, dynamicWI);
1387 if(result.InstanceId != -1)
1388 return true;
1389 else
1390 return false;
1392 else
1393 return false;
1394 }// currentPACSPos //
1397 //---------------------------------------------------
1398 // pacsPos :
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
1405 pos(vect);
1407 if(!_Primitive)
1408 return;
1410 if(!GR)
1412 nlwarning("CEntityCL::pacsPos : Global Retriever not allocated.");
1413 return;
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)
1422 else
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)
1442 if(!flyer())
1443 pos().z = _FinalPacsPos.z;
1444 }// pacsPos //
1448 //---------------------------------------------------
1449 // pacsMove :
1450 // Move the PACS position and the entity position too.
1451 //---------------------------------------------------
1452 void CEntityCL::pacsMove(const CVectorD &vect)
1454 // Entity has not moved.
1455 _HasMoved = false;
1456 // If there is a PACS primitive -> changes the PACS position.
1457 if(!_Primitive)
1459 // Set then entity position
1460 pos(vect);
1462 return;
1465 if(!GR)
1467 // Set then entity position
1468 pos(vect);
1470 nlwarning("CEntityCL::pacsMove : Global Retriever not allocated.");
1471 return;
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))
1480 _HasMoved = true;
1481 _Primitive->move (deltaPos, dynamicWI);
1484 else
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
1500 pos(vect);
1502 }// pacsMove //
1504 //-----------------------------------------------
1505 // updateDisplay :
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
1512 if(_Primitive == 0)
1514 return;
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))
1527 pos(_FinalPacsPos);
1529 else
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) )
1538 pacsPos (pos ());
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)
1542 if(!flyer())
1543 pos().z = _FinalPacsPos.z;
1546 else
1548 _SetGlobalPositionDone = false;
1549 _SnapToGroundDone = false;
1551 }// pacsFinalizeMove //
1553 //---------------------------------------------------
1554 // updateDisplay :
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 //-----------------------------------------------
1565 // setCluster :
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);
1575 else
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);
1592 // Next Child.
1593 ++it;
1595 }// setCluster //
1597 // *****************************************************************************************************
1598 NL3D::UInstanceGroup *CEntityCL::getClusterSystem()
1600 if (!_Skeleton.empty()) return _Skeleton.getClusterSystem();
1601 if (!_Instance.empty()) return _Instance.getClusterSystem();
1602 return NULL;
1605 //-----------------------------------------------
1606 // updateCluster :
1607 // Choose the right cluster according to the entity position.
1608 //-----------------------------------------------
1609 void CEntityCL::updateCluster()
1611 // Check there is a primitive.
1612 if(_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 //---------------------------------------------------
1625 // snapToGround :
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)
1632 return;
1634 // If the entity is a flyer no snap to ground will be done.
1635 if(!flyer())
1637 CVector vect;
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))
1651 needSnap = false;
1652 // if on water, snap on water
1653 else
1655 float waterHeight = 0.0f;
1656 if(GR->isWaterPosition(gPos, waterHeight))
1658 if ( isUser() || isPlayer() || isNPC())
1661 float waterOffset = ClientCfg.WaterOffset;
1662 switch(people())
1664 case EGSPD::CPeople::Unknown :
1665 break;
1666 case EGSPD::CPeople::Fyros :
1667 waterOffset = ClientCfg.FyrosWaterOffset;
1668 break;
1669 case EGSPD::CPeople::Matis :
1670 waterOffset = ClientCfg.MatisWaterOffset;
1671 break;
1672 case EGSPD::CPeople::Tryker :
1673 waterOffset = ClientCfg.TrykerWaterOffset;
1674 break;
1675 case EGSPD::CPeople::Zorai :
1676 waterOffset = ClientCfg.ZoraiWaterOffset;
1677 break;
1678 default:
1679 break;
1682 vect.z = waterHeight + waterOffset;
1684 else // creature
1686 vect.z = waterHeight + ClientCfg.WaterOffsetCreature;
1689 needSnap= false;
1693 // No primitive, vect = current pos.
1694 else
1695 vect = pos();
1697 // Snap to the ground.
1698 if(needSnap && _CollisionEntity)
1700 // for Snap on landscape, use always current 3d position, for snap cache performance.
1701 vect = pos();
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.
1713 pos().z = vect.z;
1716 // Set the box position.
1717 posBox(pos());
1718 }// snapToGround //
1721 //---------------------------------------------------
1722 // chooseRandom :
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];
1736 }// chooseRandom //
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.
1752 if(igUnderInstance)
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
1766 else
1768 // Use VisualCollisionEntity to retrieve info from landscape.
1769 UVisualCollisionEntity *colEnt= Self->getCollisionEntity();
1770 if(colEnt)
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.
1788 pacsPos(pos());
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.
1798 if(_Primitive)
1800 // Remove the primitive if PACS allocated
1801 if(PACS)
1802 PACS->removePrimitive(_Primitive);
1803 // Primitive removed
1804 _Primitive = 0;
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);
1829 else
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 //-----------------------------------------------
1853 // attackRadius :
1854 // Method to return the attack radius of an entity
1855 //-----------------------------------------------
1856 double CEntityCL::attackRadius() const
1858 return 0.5;
1859 }// attackRadius //
1861 //-----------------------------------------------
1862 //-----------------------------------------------
1863 CVectorD CEntityCL::getAttackerPos(double /* ang */, double /* dist */) const
1865 return pos();
1869 ///////////////
1870 // 3D SYSTEM //
1871 ///////////////
1872 //-----------------------------------------------
1873 // updateAsyncTexture
1874 //-----------------------------------------------
1875 float CEntityCL::updateAsyncTexture()
1877 H_AUTO ( RZ_Client_Entity_CL_Update_Async_Texture )
1879 uint i;
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);
1888 // dirty?
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.
1919 if(allLoaded)
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);
1955 return distToCam;
1959 //-----------------------------------------------
1960 // updateLodTexture
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 )
1969 // clean
1970 _LodTextureDirty= false;
1971 // compute
1972 if(!_Skeleton.empty())
1973 _Skeleton.computeLodTexture();
1979 //-----------------------------------------------
1980 // addChild :
1981 // Add a new child pointer.
1982 //-----------------------------------------------
1983 void CEntityCL::addChild(CEntityCL *c)
1985 if(c == 0)
1987 nlwarning("ENT:addChild:%d: Try to add a child with a Null Pointer.", _Slot);
1988 return;
1991 delChild(c);
1992 _Children.push_back(c);
1994 if(skeleton() && c->skeleton())
1996 const string stickBone = "stick_1";
1997 sint idBones = skeleton()->getBoneIdByName(stickBone);
1998 if(idBones != -1)
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);
2004 else
2005 nlwarning("ENT:addChild:%d: the Bone '%s' does not exist", _Slot, stickBone.c_str());
2007 }// addChild //
2009 //-----------------------------------------------
2010 // delChild :
2011 // Remove a new child pointer.
2012 //-----------------------------------------------
2013 void CEntityCL::delChild(CEntityCL *c)
2015 if(c == 0)
2017 nlwarning("ENT:delChild:%d: Try to remove a child with a Null Pointer.", _Slot);
2018 return;
2021 TChildren::iterator it = _Children.begin();
2022 while(it != _Children.end())
2024 // Remove the child from the list if found.
2025 if((*it) == c)
2027 if(skeleton() && c->skeleton())
2028 skeleton()->detachSkeletonSon(*(c->skeleton()));
2029 _Children.erase(it);
2030 break;
2033 // Next Child
2034 it++;
2036 }// delChild //
2038 //-----------------------------------------------
2039 // parent :
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);
2046 if(parent)
2047 parent->delChild(this);
2049 // Initialize the new parent.
2050 _Parent = p;
2052 // Remove the entity from the old parent.
2053 parent = EntitiesMngr.entity(_Parent);
2054 if(parent)
2055 parent->addChild(this);
2056 }// parent //
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)
2062 return true;
2064 // If the entity is not displayable, count it as clipped.
2065 if(!_Displayable)
2066 return true;
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 ();
2078 uint i;
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;
2084 if(d>_ClipRadius)
2085 return true;
2089 // Character clip
2090 float sqrdist = (camPos - clipPos).sqrnorm();
2091 return (sqrdist > (ClientCfg.CharacterFarClip*ClientCfg.CharacterFarClip));
2095 //---------------------------------------------------
2096 // setName :
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)
2102 _EntityName = name;
2107 //---------------------------------------------------
2108 // displayDebug :
2109 // Display Debug Information.
2110 //---------------------------------------------------
2111 void CEntityCL::displayDebug(float x, float &y, float lineStep) // virtual
2113 // Type and slot
2114 TextContext->printfAt(x, y, "Type: %d - Slot: %d", Type, _Slot);
2115 y += lineStep;
2116 // Outpost
2117 TextContext->printfAt(x, y, "Outpost id:%d side:%s",this->getOutpostId(),OUTPOSTENUMS::toString(this->getOutpostSide()).c_str() );
2118 y += lineStep;
2119 // Name
2120 if(!getEntityName().empty())
2121 TextContext->printAt(x, y, getEntityName());
2122 else
2123 TextContext->printfAt(x, y, "Name not received");
2124 y += lineStep;
2125 // Target and DataSet Id
2126 TextContext->printfAt(x, y, "Target: %d - DataSet Id: %u", _TargetSlot, _DataSetId);
2127 y += lineStep;
2128 // Sheet Id
2129 TextContext->printfAt(x, y, "Sheet: %d(%s)", _SheetId.asInt(), _SheetId.toString().c_str());
2130 y += lineStep;
2131 // NPC Alias
2132 TextContext->printfAt(x, y, "NPCAlias: %u", _NPCAlias);
2133 y += lineStep;
2134 // Position
2135 #ifndef TMP_DEBUG_GUIGUI
2136 TextContext->printfAt(x, y, "Pos: %f %f %f", pos().x, pos().y, pos().z);
2137 #else
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);
2139 #endif
2140 y += lineStep;
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());
2143 y += lineStep;
2144 // Display the Target Behaviour.
2145 TextContext->printfAt(x, y, "Behaviour: %d(%s)", (sint)behaviour(), MBEHAV::behaviourToString(behaviour()).c_str());
2146 y += lineStep;
2147 // Front
2148 #ifndef TMP_DEBUG_GUIGUI
2149 TextContext->printfAt(x, y, "%f(%f,%f,%f) front", frontYaw(), front().x, front().y, front().z);
2150 #else
2151 TextContext->printfAt(x, y, "%f(%f,%f,%f) front (Theoretical : %f)", frontYaw(), front().x, front().y, front().z, _TheoreticalOrientation);
2152 #endif
2153 y += lineStep;
2154 // Direction
2155 TextContext->printfAt(x, y, "%f(%f,%f,%f) dir", atan2(dir().y, dir().x), dir().x, dir().y, dir().z);
2156 y += lineStep;
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);
2161 y += lineStep;
2162 // Current pacs
2163 UGlobalPosition gp;
2164 if (_Primitive)
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);
2171 y += lineStep;
2172 }// displayDebug //
2175 //-----------------------------------------------
2176 //-----------------------------------------------
2177 void CEntityCL::displayDebugPropertyStages(float /* x */, float &y, float /* lineStep */)
2182 //-----------------------------------------------
2183 // serial :
2184 // Serialize entity.
2185 //-----------------------------------------------
2186 void CEntityCL::serial(NLMISC::IStream &f)
2188 readWrite(f);
2189 if(f.isReading())
2190 load();
2191 }// serial //
2193 //-----------------------------------------------
2194 // readWrite :
2195 // Read/Write Variables from/to the stream.
2196 //-----------------------------------------------
2197 void CEntityCL::readWrite(NLMISC::IStream &f) // virtual
2199 f.serialVersion(4);
2201 // PUBLIC
2203 // PROTECTED
2204 f.serial(_DataSetId);
2205 f.serial(_SheetId);
2206 // NL3D::UPlayList *_PlayList;
2207 // NL3D::UPlayList *_FacePlayList;
2208 // NL3D::UVisualCollisionEntity *_CollisionEntity;
2209 // NL3D::USkeleton *_Skeleton;
2210 f.serial(_Slot);
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;
2227 f.serial(_Aabbox);
2228 f.serial(_Parent);
2229 // TChildren _Children;
2230 // UInstance _Instance;
2231 // std::vector<UInstance> _Instances;
2232 f.serial(_Front);
2233 f.serial(_Up);
2234 f.serial(_Dir);
2235 f.serial(_DirMatrix);
2236 f.serial(_LastFramePos);
2237 bool firstPos = _First_Pos;
2238 f.serial(firstPos);
2239 _First_Pos = firstPos;
2240 bool firstPosManaged = _FirstPosManaged;
2241 f.serial(firstPosManaged);
2242 _FirstPosManaged = firstPosManaged;
2244 bool flyier = _Flyer;
2245 f.serial(flyier);
2246 _Flyer = flyier;
2247 f.serial(_TargetAngle);
2249 // PRIVATE
2250 }// readWrite //
2252 //-----------------------------------------------
2253 // load :
2254 // To call after a read from a stream to re-initialize the entity.
2255 //-----------------------------------------------
2256 void CEntityCL::load() // virtual
2258 }// load //
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);
2272 // New title
2273 string newtitle;
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
2289 _TitleRaw = id;
2290 // string replacement = CI18N::get(strNewTitle);
2291 bool womanTitle = false;
2292 CCharacterCL * c = dynamic_cast<CCharacterCL*>(this);
2293 if(c)
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;
2321 newtitle = _NameEx;
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;
2329 else
2331 _GMTitle = _InvalidGMTitleCode;
2332 if ( titleEnum == CHARACTER_TITLE::FBT )
2333 _HasReservedTitle = true;
2336 else
2338 _EntityName = STRING_MANAGER::CStringManagerClient::getLocalizedName(_EntityName);
2342 // Is the first title or a new title ?
2343 if ( !_Title.empty() && (_Slot==0) )
2345 // Context help
2346 contextHelp ("title");
2348 _Title = newtitle;
2350 // Update interface with new title
2351 if (_Slot == 0)
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 //-----------------------------------------------
2370 // getTitleFromName
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)
2393 return name;
2395 else
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);
2402 else
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)
2418 return name;
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
2424 else
2425 return name;
2428 //-----------------------------------------------
2429 // removeTitleAndShardFromName
2430 //-----------------------------------------------
2431 std::string CEntityCL::removeTitleAndShardFromName(const std::string &name)
2433 return removeTitleFromName(removeShardFromName(name));
2437 //-----------------------------------------------
2439 class CUpdateEntitiesColor : public IActionHandler
2441 public:
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)
2489 return false;
2491 const uint32 guildNameId = this->getGuildNameID();
2492 if (guildNameId != 0 && UserEntity && guildNameId == UserEntity->getGuildNameID())
2493 return true;
2495 return false;
2498 //-----------------------------------------------
2500 bool CEntityCL::oneInLeague () const
2502 if (Type != Player && Type != User)
2503 return false;
2505 const uint32 leagueID = getLeagueID();
2506 if ((UserEntity && (UserEntity->getLeagueID() != 0)) || leagueID != 0)
2507 return true;
2509 return false;
2512 //-----------------------------------------------
2514 bool CEntityCL::isInSameLeague () const
2516 if (Type != Player && Type != User)
2517 return false;
2519 const uint32 leagueID = getLeagueID();
2520 if ((leagueID != 0) && UserEntity && (leagueID == UserEntity->getLeagueID()))
2521 return true;
2523 return false;
2525 //-----------------------------------------------
2527 NLMISC::CRGBA CEntityCL::getColor () const
2529 // target
2530 if (isTarget())
2531 return _TargetColor;
2532 // dead
2533 if (isReallyDead())
2534 return _DeadColor;
2535 // mount
2536 if (isUserMount())
2537 return _UserMountColor;
2538 // pack animal
2539 if (isUserPackAnimal())
2540 return _UserPackAnimalColor;
2541 // GM
2542 if ( ( Type == Player || Type == User ) && _GMTitle != _InvalidGMTitleCode )
2544 return _GMTitleColor[_GMTitle];
2547 if (Type == Player || Type == NPC)
2549 // enemy
2550 if( Type == NPC )
2552 if (isAnOutpostEnemy())
2554 return _PvpEnemyColor;
2557 else
2559 if (isEnemy())
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);
2563 else
2564 return _PvpEnemyColor;
2568 // ally
2569 if (isAlly())
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);
2577 else
2579 if(isInSameLeague())
2580 return _PvpAllyColor;
2581 return _PvpAllyInTeamColor;
2585 // neutral pvp
2586 if (isNeutralPVP())
2587 return _PvpNeutralColor;
2589 // neutral
2590 if (isInTeam())
2591 return _GroupColor;
2593 // neutral
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())
2598 return _GuildColor;
2600 return _EntitiesColor[Type];
2604 //---------------------------------------------------
2605 // indoor :
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
2617 return false;
2618 }// indoor //
2621 //-----------------------------------------------
2622 // pos :
2623 //-----------------------------------------------
2624 void CEntityCL::pos(const NLMISC::CVectorD &vect)
2626 CVectorD checkDist = _PositionLimiter-vect;
2627 checkDist.z = 0.0;
2628 if(checkDist != CVectorD::Null)
2630 if(checkDist.norm() > ClientCfg.PositionLimiterRadius)
2632 checkDist.normalize();
2633 _PositionLimiter = vect + checkDist*ClientCfg.PositionLimiterRadius/2.0;
2636 _Position = vect;
2637 }// pos //
2640 //-----------------------------------------------
2642 void CEntityCL::updateMissionTarget()
2644 // Update the mission target flag
2645 _MissionTarget = false;
2646 if (_NameId)
2648 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2649 uint i,j;
2650 for (i=0; i<MAX_NUM_MISSIONS; i++)
2651 for (j=0; j<MAX_NUM_MISSION_TARGETS; j++)
2653 // Get the db prop
2654 CCDBNodeLeaf *prop = EntitiesMngr.getMissionTargetTitleDB(i, j); // NLGUI::CDBManager::getInstance()->getDbProp("SERVER:MISSIONS:"+toString(i)+":TARGET"+toString(j)+":TITLE", false);
2655 if (prop)
2657 _MissionTarget = _NameId == (uint32)prop->getValue32();
2658 if (_MissionTarget)
2659 return;
2665 //-----------------------------------------------
2666 uint CEntityCL::getGroundType() const
2668 // default: 1 meter
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;
2677 uint gt;
2679 if (indoor())
2681 if(GR)
2683 UGlobalPosition gPos;
2684 getPrimitive()->getGlobalPosition(gPos, dynamicWI);
2685 gt= GR->getMaterial(gPos);
2687 else
2688 gt= 0;
2690 else
2692 // outside
2693 NL3D::CSurfaceInfo si;
2694 _CollisionEntity->getSurfaceInfo(pos(), si);
2695 gt= si.UserSurfaceData;
2698 // store in cache
2699 _GroundTypeCachePos= pos();
2700 _GroundTypeCache= gt;
2702 return gt;
2705 //---------------------------------------------------
2706 void CEntityCL::makeTransparent(bool t)
2708 if (t == true)
2709 _TranspFactor += ((float)(DT)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND);
2710 else
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();
2765 if(pNL)
2767 uint32 val= pNL->getValue32();
2768 clamp(val, (uint32)0, (uint32)255);
2769 return val;
2771 else
2772 // this is an error case...
2773 return 128;
2776 // ***************************************************************************
2777 void CEntityCL::setOpacityMin(uint32 value)
2779 CCDBNodeLeaf *pNL = getOpacityDBNode();
2780 if(pNL)
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
2794 return (
2795 (enabledInSheet /*&& !CNPCIconCache::getInstance().getNPCIcon(this).getTextureMain().empty()*/) &&
2796 (_InSceneInterfaceEnabled) &&
2797 ( ClientCfg.Names ||
2798 isUser () ||
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);
2813 switch(hominPart)
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";
2821 default: break;
2823 return NULL;
2826 //-----------------------------------------------
2827 // idx2Inst :
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];
2835 return NULL;
2836 }// idx2Inst //
2840 //-----------------------------------------------
2841 void CEntityCL::updateIsInTeam ()
2843 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2845 _IsInTeam= false;
2847 // if UId not set, false
2848 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
2849 return;
2851 for (uint i=0; i<MaxNumPeopleInTeam; i++)
2853 // Get the db prop
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() )
2860 _IsInTeam= true;
2861 buildInSceneInterface();
2862 return;
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)
2878 return;
2880 // Am i a pack animal?
2881 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2883 // Get the db prop
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;
2895 default:
2896 case ANIMAL_TYPE::Packer: _IsUserPackAnimal = true; break;
2899 return;
2904 //-----------------------------------------------
2905 ANIMAL_STATUS::EAnimalStatus CEntityCL::getPackAnimalStatus() const
2907 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2909 if(! (isUserPackAnimal() || isUserMount()))
2910 return 0;
2912 // Am i a pack animal?
2913 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2915 // Get the db prop
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());
2923 return 0;
2926 //-----------------------------------------------
2927 bool CEntityCL::getPackAnimalIndexInDB(sint &dbIndex) const
2929 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2931 if(! (isUserPackAnimal() || isUserMount()))
2932 return false;
2934 // Am i a pack animal?
2935 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2937 // Get the db prop
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())
2943 dbIndex= i;
2944 return true;
2948 return false;
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
2960 updateIsInTeam();
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
2991 if(t>150 && t<300)
2992 blinkOn= true;
2993 if(t>450)
2994 _VisualSelectionTime = 0;
2996 setVisualSelectionBlink(blinkOn, CRGBA::White);
2998 else
3000 // If i am the target
3001 if(isTarget())
3002 // set semi-highlight
3003 setVisualSelectionBlink(true, CRGBA(100,100,100));
3004 // else If i am under cursor
3005 else if(ShowInterface && isUnderCursor())
3006 // highlight
3007 setVisualSelectionBlink(true, CRGBA::White);
3008 else
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
3026 if (! isTarget())
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));
3052 if (node)
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);
3077 else
3079 // No selection FX
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);
3106 else
3108 // No selection FX
3109 if (!_MouseOverFX.empty() && Scene)
3111 Scene->deleteInstance(_MouseOverFX);
3115 if (!_StateFX.empty())
3117 // Build a matrix for the fx
3118 NLMISC::CMatrix mat;
3119 mat.identity();
3121 // Scale
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
3129 CVector position;
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);
3137 if (skeleton())
3138 _StateFX.setClusterSystem(skeleton()->getClusterSystem());
3141 if (!_SelectionFX.empty() || !_MouseOverFX.empty())
3143 // Build a matrix for the fx
3144 NLMISC::CMatrix mat;
3145 mat.identity();
3147 // Scale
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
3155 CVector position;
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);
3164 if (skeleton())
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);
3177 if (skeleton())
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];
3196 if(bOnOff)
3197 inst.setEmissive(emitColor);
3198 else
3199 inst.restoreEmissive();
3202 // also blink skeleton in CLod form
3203 if(!_Skeleton.empty())
3205 if(bOnOff)
3206 _Skeleton.setLodEmit(emitColor);
3207 else
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
3236 if(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;
3251 else
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
3267 if(shadowOn)
3269 if(skeleton())
3271 skeleton()->setShadowMapDirectionZThreshold(_ShadowMapZDirClamp);
3272 skeleton()->setShadowMapMaxDepth(_ShadowMapMaxDepth);
3274 else
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;
3302 if(indoor())
3304 zDirClampWanted= ClientCfg.ShadowZDirClampInterior;
3305 maxDepth= ClientCfg.ShadowMaxDepthInterior;
3308 // smooth over time
3309 if(_ShadowMapZDirClamp!=zDirClampWanted || _ShadowMapMaxDepth!=maxDepth)
3311 // if some time passed since last update
3312 sint64 dt= T1-_ShadowMapPropertyLastUpdate;
3313 if(dt!=0)
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)
3361 _Displayable = 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()
3383 if (getLastClip())
3385 // find highest father in the hierarchy
3386 CEntityCL *parentEntity = this;
3387 for(;;)
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;
3416 bool found= false;
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())
3425 bool computed;
3426 static volatile bool useBoneSphere = true;
3427 if (useBoneSphere) computed = _Skeleton.computeRenderedBBoxWithBoneSphere(_LocalSelectBox, false);
3428 else computed = _Skeleton.computeRenderedBBox(_LocalSelectBox);
3429 if (computed)
3431 found= true;
3432 // apply local offset due to skeleton animation
3433 CMatrix invMat = _DirMatrix;
3434 invMat.setPos(pos());
3435 invMat.invert();
3436 CVector localOffset = invMat * _Skeleton.getPos();
3437 _LocalSelectBox.setCenter(_LocalSelectBox.getCenter() + localOffset);
3438 static volatile float rot = -1.f;
3439 CMatrix rotMat;
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))
3450 found= true;
3451 // apply local offset due to skeleton animation
3452 CMatrix invMat = _DirMatrix;
3453 invMat.setPos(pos());
3454 invMat.invert();
3455 CMatrix localMat = invMat * _Skeleton.getMatrix();
3456 _LocalSelectBox = CAABBox::transformAABBox(localMat, _LocalSelectBox);
3460 // else compute from static bot object
3461 else
3463 UInstance inst;
3464 // try with _Instances array first
3465 if(!_Instances.empty())
3466 inst= _Instances[0].Current;
3467 // Fallback to _Instance (??)
3468 if(inst.empty())
3469 inst= _Instance;
3471 // if static instance found
3472 if(!inst.empty())
3474 inst.getShapeAABBox(_LocalSelectBox);
3475 found= true;
3480 // if not found, fallback to default bbox
3481 if(!found)
3483 _LocalSelectBox.setCenter(_Aabbox.getCenter() - pos().asVector());
3484 _LocalSelectBox.setHalfSize(_Aabbox.getHalfSize());
3486 else
3488 CVector scale;
3489 getMeshDefaultScale(scale);
3490 const CVector &halfSize = _LocalSelectBox.getHalfSize();
3491 const CVector &center = _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
3534 return true;
3538 return false;
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
3552 return true;
3556 return false;
3560 //----------------------------------------------------------------------
3561 CVector CEntityCL::dirToTarget() const
3563 CVector dir2Target;
3564 CEntityCL * target = EntitiesMngr.entity( targetSlot() );
3565 if( target )
3567 dir2Target = target->pos() - pos();
3568 dir2Target.z = 0;
3569 dir2Target.normalize();
3571 else
3573 dir2Target = dir();
3575 return dir2Target;
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);
3598 else
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();