Fix classique titles display
[ryzomcore.git] / ryzom / client / src / entity_cl.cpp
blobb82d5482f386004054cc80fa667e9a2a3c9279f2
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 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 sint64 prop = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA))->getValue64();
2368 updateVisualPropertyVpa(0, prop);
2370 }// onStringAvailable //
2372 //-----------------------------------------------
2373 // getTitleFromName
2374 //-----------------------------------------------
2375 std::string CEntityCL::getTitleFromName(const std::string &name)
2377 std::string::size_type p1 = name.find('$');
2378 if (p1 != string::npos)
2380 std::string::size_type p2 = name.find('$', p1 + 1);
2381 if (p2 != std::string::npos)
2382 return name.substr(p1+1, p2-p1-1);
2385 return std::string();
2386 }// getTitleFromName //
2388 //-----------------------------------------------
2389 // removeTitleFromName
2390 //-----------------------------------------------
2391 std::string CEntityCL::removeTitleFromName(const std::string &name)
2393 std::string::size_type p1 = name.find('$');
2394 if (p1 == string::npos)
2396 return name;
2398 else
2400 std::string::size_type p2 = name.find('$', p1 + 1);
2401 if (p2 != string::npos)
2403 return name.substr(0, p1) + name.substr(p2 + 1);
2405 else
2407 return name.substr(0, p1);
2410 }// removeTitleFromName //
2412 //-----------------------------------------------
2413 // removeShardFromName
2414 //-----------------------------------------------
2415 std::string CEntityCL::removeShardFromName(const std::string &name)
2417 // The string must contains a '(' and a ')'
2418 std::string::size_type p0= name.find('(');
2419 std::string::size_type p1= name.find(')');
2420 if(p0==std::string::npos || p1==std::string::npos || p1<=p0)
2421 return name;
2423 // if it is the same as the shard name of the user, remove it
2424 if (!NLMISC::compareCaseInsensitive(name.c_str() + p0 + 1, p1-p0-1, PlayerSelectedHomeShardName.c_str(), PlayerSelectedHomeShardName.size()))
2425 return name.substr(0,p0) + name.substr(p1+1);
2426 // else don't modify
2427 else
2428 return name;
2431 //-----------------------------------------------
2432 // removeTitleAndShardFromName
2433 //-----------------------------------------------
2434 std::string CEntityCL::removeTitleAndShardFromName(const std::string &name)
2436 return removeTitleFromName(removeShardFromName(name));
2440 //-----------------------------------------------
2442 class CUpdateEntitiesColor : public IActionHandler
2444 public:
2445 virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
2447 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2449 CEntityCL::_EntitiesColor[CEntityCL::User] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:USER")->getValueRGBA();
2450 CEntityCL::_EntitiesColor[CEntityCL::Player] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PLAYER")->getValueRGBA();
2451 CEntityCL::_EntitiesColor[CEntityCL::NPC] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:NPC")->getValueRGBA();
2452 CEntityCL::_EntitiesColor[CEntityCL::Fauna] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:FAUNA")->getValueRGBA();
2453 CEntityCL::_EntitiesColor[CEntityCL::ForageSource] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:SOURCE")->getValueRGBA();
2454 CEntityCL::_DeadColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:DEAD")->getValueRGBA();
2455 CEntityCL::_TargetColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:TARGET")->getValueRGBA();
2456 CEntityCL::_GroupColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GROUP")->getValueRGBA();
2457 CEntityCL::_GuildColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:GUILD")->getValueRGBA();
2458 CEntityCL::_UserMountColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:MOUNT")->getValueRGBA();
2459 CEntityCL::_UserPackAnimalColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:BEAST")->getValueRGBA();
2460 CEntityCL::_PvpEnemyColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPENEMY")->getValueRGBA();
2461 CEntityCL::_PvpAllyColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLY")->getValueRGBA();
2462 CEntityCL::_PvpAllyInTeamColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLYINTEAM")->getValueRGBA();
2463 CEntityCL::_PvpNeutralColor = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:ENTITY:COLORS:PVPNEUTRAL")->getValueRGBA();
2465 // don't save these colors in .icfg because players can't change them
2466 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::SGM - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SGM")->getValueRGBA();
2467 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::GM - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:GM")->getValueRGBA();
2468 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::VG - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:VG")->getValueRGBA();
2469 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::SG - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:SG")->getValueRGBA();
2470 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::G - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:G")->getValueRGBA();
2472 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::CM - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:CM")->getValueRGBA();
2473 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::EM - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EM")->getValueRGBA();
2474 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::EG - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:EG")->getValueRGBA();
2475 CEntityCL::_GMTitleColor[ CHARACTER_TITLE::OBSERVER - CHARACTER_TITLE::BeginGmTitle ] = NLGUI::CDBManager::getInstance()->getDbProp("UI:INTERFACE:ENTITY:COLORS:OBSERVER")->getValueRGBA();
2478 REGISTER_ACTION_HANDLER (CUpdateEntitiesColor, "update_entities_color");
2480 //-----------------------------------------------
2482 bool CEntityCL::isTarget () const
2484 return UserEntity && UserEntity->selection() == _Slot;
2487 //-----------------------------------------------
2489 bool CEntityCL::isInSameGuild () const
2491 if (Type != Player && Type != User)
2492 return false;
2494 const uint32 guildNameId = this->getGuildNameID();
2495 if (guildNameId != 0 && UserEntity && guildNameId == UserEntity->getGuildNameID())
2496 return true;
2498 return false;
2501 //-----------------------------------------------
2503 bool CEntityCL::oneInLeague () const
2505 if (Type != Player && Type != User)
2506 return false;
2508 const uint32 leagueID = getLeagueID();
2509 if ((UserEntity && (UserEntity->getLeagueID() != 0)) || leagueID != 0)
2510 return true;
2512 return false;
2515 //-----------------------------------------------
2517 bool CEntityCL::isInSameLeague () const
2519 if (Type != Player && Type != User)
2520 return false;
2522 const uint32 leagueID = getLeagueID();
2523 if ((leagueID != 0) && UserEntity && (leagueID == UserEntity->getLeagueID()))
2524 return true;
2526 return false;
2528 //-----------------------------------------------
2530 NLMISC::CRGBA CEntityCL::getColor () const
2532 // target
2533 if (isTarget())
2534 return _TargetColor;
2535 // dead
2536 if (isReallyDead())
2537 return _DeadColor;
2538 // mount
2539 if (isUserMount())
2540 return _UserMountColor;
2541 // pack animal
2542 if (isUserPackAnimal())
2543 return _UserPackAnimalColor;
2544 // GM
2545 if ( ( Type == Player || Type == User ) && _GMTitle != _InvalidGMTitleCode )
2547 return _GMTitleColor[_GMTitle];
2550 if (Type == Player || Type == NPC)
2552 // enemy
2553 if( Type == NPC )
2555 if (isAnOutpostEnemy())
2557 return _PvpEnemyColor;
2560 else
2562 if (isEnemy())
2564 if (getPvpMode()&PVP_MODE::PvpFaction)
2565 return CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A);
2566 else
2567 return _PvpEnemyColor;
2571 // ally
2572 if (isAlly())
2574 if (getPvpMode() & PVP_MODE::PvpFactionFlagged)
2576 if(isInSameLeague())
2577 return CRGBA(max(0, _PvpAllyColor.R-100), max(0, _PvpAllyColor.G-100), max(0, _PvpAllyColor.B-100),_PvpAllyColor.A);
2578 return CRGBA(max(0, _PvpAllyInTeamColor.R-100), max(0, _PvpAllyInTeamColor.G-100), max(0, _PvpAllyInTeamColor.B-100),_PvpAllyInTeamColor.A);
2580 else
2582 if(isInSameLeague())
2583 return _PvpAllyColor;
2584 return _PvpAllyInTeamColor;
2588 // neutral pvp
2589 if (isNeutralPVP())
2590 return _PvpNeutralColor;
2592 // neutral
2593 if (isInTeam())
2594 return _GroupColor;
2596 // neutral
2597 if (isInSameLeague())
2598 return CRGBA(min(255, _GroupColor.R+50), min(255, _GroupColor.G+50), min(255, _GroupColor.B+50),_GroupColor.A);
2600 if (isInSameGuild())
2601 return _GuildColor;
2603 return _EntitiesColor[Type];
2607 //---------------------------------------------------
2608 // indoor :
2609 // Return true if the current position is an indoor position.
2610 //---------------------------------------------------
2611 bool CEntityCL::indoor() const
2613 if(_Primitive && GR)
2615 UGlobalPosition gPos;
2616 _Primitive->getGlobalPosition(gPos, dynamicWI);
2617 return GR->isInterior(gPos);
2619 // Return false if any problem
2620 return false;
2621 }// indoor //
2624 //-----------------------------------------------
2625 // pos :
2626 //-----------------------------------------------
2627 void CEntityCL::pos(const NLMISC::CVectorD &vect)
2629 CVectorD checkDist = _PositionLimiter-vect;
2630 checkDist.z = 0.0;
2631 if(checkDist != CVectorD::Null)
2633 if(checkDist.norm() > ClientCfg.PositionLimiterRadius)
2635 checkDist.normalize();
2636 _PositionLimiter = vect + checkDist*ClientCfg.PositionLimiterRadius/2.0;
2639 _Position = vect;
2640 }// pos //
2643 //-----------------------------------------------
2645 void CEntityCL::updateMissionTarget()
2647 // Update the mission target flag
2648 _MissionTarget = false;
2649 if (_NameId)
2651 CInterfaceManager *pIM = CInterfaceManager::getInstance();
2652 uint i,j;
2653 for (i=0; i<MAX_NUM_MISSIONS; i++)
2654 for (j=0; j<MAX_NUM_MISSION_TARGETS; j++)
2656 // Get the db prop
2657 CCDBNodeLeaf *prop = EntitiesMngr.getMissionTargetTitleDB(i, j); // NLGUI::CDBManager::getInstance()->getDbProp("SERVER:MISSIONS:"+toString(i)+":TARGET"+toString(j)+":TITLE", false);
2658 if (prop)
2660 _MissionTarget = _NameId == (uint32)prop->getValue32();
2661 if (_MissionTarget)
2662 return;
2668 //-----------------------------------------------
2669 uint CEntityCL::getGroundType() const
2671 // default: 1 meter
2672 const float srqCacheDistLimit= 1;
2674 // If the user is not too far from cached pos, return same value
2675 if((_GroundTypeCachePos-pos()).sqrnorm() < srqCacheDistLimit)
2677 return _GroundTypeCache;
2680 uint gt;
2682 if (indoor())
2684 if(GR)
2686 UGlobalPosition gPos;
2687 getPrimitive()->getGlobalPosition(gPos, dynamicWI);
2688 gt= GR->getMaterial(gPos);
2690 else
2691 gt= 0;
2693 else
2695 // outside
2696 NL3D::CSurfaceInfo si;
2697 _CollisionEntity->getSurfaceInfo(pos(), si);
2698 gt= si.UserSurfaceData;
2701 // store in cache
2702 _GroundTypeCachePos= pos();
2703 _GroundTypeCache= gt;
2705 return gt;
2708 //---------------------------------------------------
2709 void CEntityCL::makeTransparent(bool t)
2711 if (t == true)
2712 _TranspFactor += ((float)(DT)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND);
2713 else
2714 _TranspFactor -= ((float)(DT)) / ((float)RZ_TIME_TO_BECOME_TRANSPARENT_IN_SECOND);
2716 if (_TranspFactor < 0.0) _TranspFactor = 0.0;
2717 if (_TranspFactor > 1.0) _TranspFactor = 1.0;
2719 uint32 opaMin= getOpacityMin();
2720 uint8 opacity = (uint8)(opaMin + (255-opaMin) * (1.0 - _TranspFactor));
2722 for (uint32 i = 0; i < _Instances.size(); ++i)
2724 _Instances[i].makeInstanceTransparent(opacity, (uint8)opaMin);
2727 }// makeTransparent //
2729 //---------------------------------------------------
2730 void CEntityCL::makeTransparent(float factor)
2732 clamp(factor, 0.f, 1.f);
2733 _TranspFactor = 1.f - factor;
2734 uint32 opaMin= getOpacityMin();
2735 uint8 opacity = (uint8)(opaMin + (255-opaMin) * (1.0 - _TranspFactor));
2737 for (uint32 i = 0; i < _Instances.size(); ++i)
2739 _Instances[i].makeInstanceTransparent(opacity, (uint8)opaMin);
2743 // ***************************************************************************
2744 void CEntityCL::setDiffuse(bool onOff, NLMISC::CRGBA diffuse)
2746 for (uint32 i = 0; i < _Instances.size(); ++i)
2748 _Instances[i].setDiffuse(onOff, diffuse);
2753 // ***************************************************************************
2754 CCDBNodeLeaf *CEntityCL::getOpacityDBNode()
2756 if (!_OpacityMinNodeLeaf)
2758 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2759 _OpacityMinNodeLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:USER_CHAR_OPA_MIN", false);
2761 return _OpacityMinNodeLeaf;
2764 // ***************************************************************************
2765 uint32 CEntityCL::getOpacityMin()
2767 CCDBNodeLeaf *pNL = getOpacityDBNode();
2768 if(pNL)
2770 uint32 val= pNL->getValue32();
2771 clamp(val, (uint32)0, (uint32)255);
2772 return val;
2774 else
2775 // this is an error case...
2776 return 128;
2779 // ***************************************************************************
2780 void CEntityCL::setOpacityMin(uint32 value)
2782 CCDBNodeLeaf *pNL = getOpacityDBNode();
2783 if(pNL)
2785 clamp(value, (uint32)0, (uint32)255);
2786 pNL->setValue32(value);
2791 // ***************************************************************************
2793 * Return true if the in-scene interface must be shown
2795 bool CEntityCL::mustShowInsceneInterface( bool enabledInSheet ) const
2797 return (
2798 (enabledInSheet /*&& !CNPCIconCache::getInstance().getNPCIcon(this).getTextureMain().empty()*/) &&
2799 (_InSceneInterfaceEnabled) &&
2800 ( ClientCfg.Names ||
2801 isUser () ||
2802 ((getDisplayOSDForceOver() || ClientCfg.ShowNameUnderCursor) && slot()==SlotUnderCursor) ||
2803 (ClientCfg.ShowNameSelected && UserEntity && slot()==UserEntity->selection()) ||
2804 (isInTeam() && !isUser ()) ||
2805 (UserEntity && ((UserEntity->pos()-pos()).sqrnorm() < ClientCfg.ShowNameBelowDistanceSqr) && !isUser ())
2812 //-----------------------------------------------
2813 const char *CEntityCL::getBoneNameFromBodyPart(BODY::TBodyPart part, BODY::TSide side) const
2815 BODY::TBodyPart hominPart = BODY::getMatchingHominBodyPart(part);
2816 switch(hominPart)
2818 case BODY::HHead: return "Bip01 Head";
2819 case BODY::HChest: return "Bip01 Spine2";
2820 case BODY::HArms: return side == BODY::Left ? "Bip01 L UpperArm" : "Bip01 R UpperArm";
2821 case BODY::HHands: return side == BODY::Left ? "Bip01 L Hand" : "Bip01 R Hand";
2822 case BODY::HLegs: return side == BODY::Left ? "Bip01 L Calf" : "Bip01 R Calf";
2823 case BODY::HFeet: return side == BODY::Left ? "Bip01 L Foot" : "Bip01 R Foot";
2824 default: break;
2826 return NULL;
2829 //-----------------------------------------------
2830 // idx2Inst :
2831 // Return a pointer on an instance structure.
2832 //-----------------------------------------------
2833 CEntityCL::SInstanceCL *CEntityCL::idx2Inst(uint idx)
2835 if(idx < _Instances.size()) // CEntityCL::BadIndex is the max so idx < ... mean idx != CEntityCL::BadIndex too
2836 return &_Instances[idx];
2838 return NULL;
2839 }// idx2Inst //
2843 //-----------------------------------------------
2844 void CEntityCL::updateIsInTeam ()
2846 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2848 _IsInTeam= false;
2850 // if UId not set, false
2851 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
2852 return;
2854 for (uint i=0; i<MaxNumPeopleInTeam; i++)
2856 // Get the db prop
2857 CCDBNodeLeaf *uidProp = EntitiesMngr.getGroupMemberUidDB(i);
2858 CCDBNodeLeaf *presentProp = EntitiesMngr.getGroupMemberNameDB(i);
2859 // If same Entity uid than the one in the Database, ok the entity is in the Player TEAM!!
2860 if (uidProp && uidProp->getValue32() == (sint32)dataSetId() &&
2861 presentProp && presentProp->getValueBool() )
2863 _IsInTeam= true;
2864 buildInSceneInterface();
2865 return;
2868 buildInSceneInterface();
2871 //-----------------------------------------------
2872 void CEntityCL::updateIsUserAnimal ()
2874 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2876 _IsUserMount= false;
2877 _IsUserPackAnimal= false;
2879 // if UId not set, false
2880 if(dataSetId()==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
2881 return;
2883 // Am i a pack animal?
2884 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2886 // Get the db prop
2887 CCDBNodeLeaf *uidProp = EntitiesMngr.getBeastUidDB(i);
2888 CCDBNodeLeaf *statusProp = EntitiesMngr.getBeastStatusDB(i);
2889 CCDBNodeLeaf *typeProp = EntitiesMngr.getBeastTypeDB(i);
2890 // I must have the same Id, and the animal entry must be ok.
2891 if(uidProp && statusProp && typeProp && uidProp->getValue32() == (sint32)dataSetId() &&
2892 ANIMAL_STATUS::isSpawned((ANIMAL_STATUS::EAnimalStatus)(statusProp->getValue32()) ))
2894 switch(typeProp->getValue16())
2896 case ANIMAL_TYPE::Mount: _IsUserMount = true; break;
2898 default:
2899 case ANIMAL_TYPE::Packer: _IsUserPackAnimal = true; break;
2902 return;
2907 //-----------------------------------------------
2908 ANIMAL_STATUS::EAnimalStatus CEntityCL::getPackAnimalStatus() const
2910 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2912 if(! (isUserPackAnimal() || isUserMount()))
2913 return 0;
2915 // Am i a pack animal?
2916 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2918 // Get the db prop
2919 CCDBNodeLeaf *uidProp = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i), false);
2920 CCDBNodeLeaf *statusProp = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i), false);
2921 // I must have the same Id, and the animal entry must be ok.
2922 if(uidProp && statusProp && uidProp->getValue32() == (sint32)dataSetId())
2923 return (ANIMAL_STATUS::EAnimalStatus)(statusProp->getValue32());
2926 return 0;
2929 //-----------------------------------------------
2930 bool CEntityCL::getPackAnimalIndexInDB(sint &dbIndex) const
2932 CInterfaceManager *pIM= CInterfaceManager::getInstance();
2934 if(! (isUserPackAnimal() || isUserMount()))
2935 return false;
2937 // Am i a pack animal?
2938 for (uint i=0; i<MAX_INVENTORY_ANIMAL; i++)
2940 // Get the db prop
2941 CCDBNodeLeaf *uidProp = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:UID", i), false);
2942 CCDBNodeLeaf *statusProp = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:STATUS", i), false);
2943 // I must have the same Id, and the animal entry must be ok.
2944 if(uidProp && statusProp && uidProp->getValue32() == (sint32)dataSetId())
2946 dbIndex= i;
2947 return true;
2951 return false;
2954 //-----------------------------------------------
2955 void CEntityCL::dataSetId(CLFECOMMON::TClientDataSetIndex dataSet)
2957 _DataSetId = dataSet;
2959 if (_Primitive && _Primitive->UserData == UserDataEntity)
2960 _Primitive->UserData |= (((uint64)_DataSetId)<<16);
2962 // additionaly, on a UID change, must check the IsInTeam and IsAniml flags
2963 updateIsInTeam();
2964 updateIsUserAnimal();
2966 // and update Bar Manager, only if correctly init
2967 if(_Slot!=CLFECOMMON::INVALID_SLOT && _DataSetId!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
2968 CBarManager::getInstance()->addEntity(_Slot, _DataSetId);
2971 // ***************************************************************************
2972 void CEntityCL::updateVisible(const NLMISC::TTime &/* time */, CEntityCL * /* target */)
2974 // update some shadowmap properties
2975 updateShadowMapProperties();
2977 // For Skeleton Spawn Animation, must update some pos
2978 if(!_Skeleton.empty())
2980 _Skeleton.setSSSWOPos(pos());
2981 _Skeleton.setSSSWODir(front());
2984 if (!R2::isEditionCurrent())
2986 // NB : if editor is enabled, then highlighting is managed in another fashion (there may be multiple-semihighlights)
2988 // Selection Highlight
2989 if(_VisualSelectionTime != 0)
2991 bool blinkOn = false;
2992 sint64 t= T1 -_VisualSelectionTime;
2993 // hardcoded blink animation
2994 if(t>150 && t<300)
2995 blinkOn= true;
2996 if(t>450)
2997 _VisualSelectionTime = 0;
2999 setVisualSelectionBlink(blinkOn, CRGBA::White);
3001 else
3003 // If i am the target
3004 if(isTarget())
3005 // set semi-highlight
3006 setVisualSelectionBlink(true, CRGBA(100,100,100));
3007 // else If i am under cursor
3008 else if(ShowInterface && isUnderCursor())
3009 // highlight
3010 setVisualSelectionBlink(true, CRGBA::White);
3011 else
3012 // disable hightlight
3013 setVisualSelectionBlink(false, CRGBA::White);
3018 // ***************************************************************************
3019 void CEntityCL::updateSomeClipped(const NLMISC::TTime &/* time */, CEntityCL * /* target */)
3021 // update some shadowmap properties
3022 updateShadowMapProperties();
3025 // ***************************************************************************
3026 void CEntityCL::updateClipped(const NLMISC::TTime &/* currentTimeInMs */, CEntityCL * /* target */)
3028 // hide only if I am not the target
3029 if (! isTarget())
3031 if (!_SelectionFX.empty() && Scene)
3033 Scene->deleteInstance(_SelectionFX);
3034 _SelectionFX = NULL;
3036 if (!_MouseOverFX.empty() && Scene)
3038 Scene->deleteInstance(_MouseOverFX);
3039 _MouseOverFX = NULL;
3045 // ***************************************************************************
3046 void CEntityCL::updateVisiblePostPos(const NLMISC::TTime &/* currentTimeInMs */, CEntityCL * /* target */)
3048 if (R2::isEditionCurrent()) return; // selection managed by r2 editor in edition mode
3050 bool bShowReticle = true;
3052 CCDBNodeLeaf *node = (CCDBNodeLeaf *)_ShowReticleLeaf ? &*_ShowReticleLeaf
3053 : &*(_ShowReticleLeaf = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:SHOW_RETICLE", false));
3055 if (node)
3057 bShowReticle = node->getValueBool();
3060 // No-op if I am not the current UserEntity Target
3061 if(bShowReticle && isTarget())
3063 // activate selection fx
3064 if (_SelectionFX.empty())
3066 // Keep a static instance of the selection FX
3067 NL3D::UInstance instance = Scene->createInstance(ClientCfg.SelectionFX);
3068 if (!instance.empty())
3070 _SelectionFX.cast (instance);
3071 _SelectionFX.setLoadBalancingGroup("SelectionFx");
3072 if (_SelectionFX.empty())
3074 // shape found, but not a particle system
3075 Scene->deleteInstance(instance);
3080 else
3082 // No selection FX
3083 if (!_SelectionFX.empty() && Scene)
3085 Scene->deleteInstance(_SelectionFX);
3089 // Mouse over SFX, only if the entity is selectable
3090 if (bShowReticle && ShowInterface && !isTarget() && isUnderCursor() && properties().selectable())
3092 // activate selection fx
3093 if (_MouseOverFX.empty())
3095 // Keep a static instance of the selection FX
3096 NL3D::UInstance instance = Scene->createInstance(ClientCfg.MouseOverFX);
3097 if (!instance.empty())
3099 _MouseOverFX.cast (instance);
3100 _MouseOverFX.setLoadBalancingGroup("SelectionFx");
3101 if (_MouseOverFX.empty())
3103 // shape found, but not a particle system
3104 Scene->deleteInstance(instance);
3109 else
3111 // No selection FX
3112 if (!_MouseOverFX.empty() && Scene)
3114 Scene->deleteInstance(_MouseOverFX);
3118 if (!_StateFX.empty())
3120 // Build a matrix for the fx
3121 NLMISC::CMatrix mat;
3122 mat.identity();
3124 // Scale
3125 const CVector &boxes = _SelectBox.getHalfSize ();
3126 // take mean of XY and Z
3127 float halfwidth = std::max(boxes.x, boxes.y);
3128 halfwidth = (halfwidth + boxes.z)/2;
3129 mat.setScale (halfwidth);
3131 // Pos. Avoid Flick in XY, but take precise Z
3132 CVector position;
3133 position = pos().asVector();
3134 position.z= _SelectBox.getMin().z;
3135 mat.setPos(position);
3136 mat.setRot(dirMatrix());
3138 _StateFX.setTransformMode(NL3D::UTransformable::DirectMatrix);
3139 _StateFX.setMatrix(mat);
3140 if (skeleton())
3141 _StateFX.setClusterSystem(skeleton()->getClusterSystem());
3144 if (!_SelectionFX.empty() || !_MouseOverFX.empty())
3146 // Build a matrix for the fx
3147 NLMISC::CMatrix mat;
3148 mat.identity();
3150 // Scale
3151 const CVector &boxes = _SelectBox.getHalfSize ();
3152 // take mean of XY and Z
3153 float halfwidth = std::max(boxes.x, boxes.y);
3154 halfwidth = (halfwidth + boxes.z)/2;
3155 mat.setScale (halfwidth * 2 * ClientCfg.SelectionFXSize);
3157 // Pos. Avoid Flick in XY, but take precise Z
3158 CVector position;
3159 position = pos().asVector();
3160 position.z= _SelectBox.getCenter().z;
3161 mat.setPos(position);
3163 if (!_SelectionFX.empty())
3165 _SelectionFX.setTransformMode(NL3D::UTransformable::DirectMatrix);
3166 _SelectionFX.setMatrix(mat);
3167 if (skeleton())
3168 _SelectionFX.setClusterSystem(skeleton()->getClusterSystem());
3169 // Colorize the selection depending of the level of the creature
3171 CRGBA col = CRGBA(0,0,0);
3172 uint8 nForce = NLGUI::CDBManager::getInstance()->getDbProp("SERVER:TARGET:FORCE_RATIO")->getValue8();
3173 _SelectionFX.setUserParam(0, 0.1f*nForce + 0.1f);
3176 if (!_MouseOverFX.empty())
3178 _MouseOverFX.setTransformMode(NL3D::UTransformable::DirectMatrix);
3179 _MouseOverFX.setMatrix(mat);
3180 if (skeleton())
3181 _MouseOverFX.setClusterSystem(skeleton()->getClusterSystem());
3187 // ***************************************************************************
3188 void CEntityCL::buildInSceneInterface ()
3192 // ***************************************************************************
3193 void CEntityCL::doSetVisualSelectionBlink(bool bOnOff, CRGBA emitColor)
3195 // blink all instances
3196 for(uint i = 0; i < instances().size(); ++i)
3198 SInstanceCL &inst = instances()[i];
3199 if(bOnOff)
3200 inst.setEmissive(emitColor);
3201 else
3202 inst.restoreEmissive();
3205 // also blink skeleton in CLod form
3206 if(!_Skeleton.empty())
3208 if(bOnOff)
3209 _Skeleton.setLodEmit(emitColor);
3210 else
3211 _Skeleton.setLodEmit(CRGBA::Black);
3215 // ***************************************************************************
3216 void CEntityCL::visualSelectionStart()
3218 _VisualSelectionTime= T1;
3221 // ***************************************************************************
3222 void CEntityCL::visualSelectionStop()
3224 _VisualSelectionTime= 0;
3227 // ***************************************************************************
3228 bool CEntityCL::canCastShadowMap() const
3230 return ClientCfg.Shadows;
3233 // ***************************************************************************
3234 void CEntityCL::updateCastShadowMap()
3236 bool shadowOn= canCastShadowMap();
3238 // if the entity has a skeleton
3239 if(skeleton())
3241 // then shadow will be done through the skeleton
3242 skeleton()->enableCastShadowMap(shadowOn);
3243 // disable shadows on instances
3244 if(_SomeInstanceCastShadowMap)
3246 for(uint i = 0; i < _Instances.size(); i++)
3248 if(!_Instances[i].Current.empty())
3249 _Instances[i].Current.enableCastShadowMap(false);
3251 _SomeInstanceCastShadowMap= false;
3254 else
3256 // enable/disable cast shadow on instances instead (eg: on bot objects)
3257 // NB: must do it at each updateCastShadowMap(), cause don't know if an instance has been added or not
3258 for(uint i = 0; i < _Instances.size(); i++)
3260 if(!_Instances[i].Current.empty())
3262 _Instances[i].Current.enableCastShadowMap(shadowOn);
3266 _SomeInstanceCastShadowMap= shadowOn;
3269 // if shadow enabled, update the shadow properties
3270 if(shadowOn)
3272 if(skeleton())
3274 skeleton()->setShadowMapDirectionZThreshold(_ShadowMapZDirClamp);
3275 skeleton()->setShadowMapMaxDepth(_ShadowMapMaxDepth);
3277 else
3279 for(uint i = 0; i < _Instances.size(); i++)
3281 if(!_Instances[i].Current.empty())
3283 _Instances[i].Current.setShadowMapDirectionZThreshold(_ShadowMapZDirClamp);
3284 _Instances[i].Current.setShadowMapMaxDepth(_ShadowMapMaxDepth);
3291 // ***************************************************************************
3292 void CEntityCL::updateShadowMapProperties()
3295 Choose the z clamp direction whether or not the player is on "interior" stuff.
3296 In "interior" stuff, the ZClamp direction is lesser, to avoid some problems of
3297 "cast shadow behind the walls"
3299 Also choose the MaxDepth of shadow map whether or not the player is on "interior" stuff.
3300 In "interior" stuff, the MaxDepth is lesser to, to avoid some problems with the "bud":
3301 when the player go up stairs and when in the "bud", the shadow still appears on landscape
3303 float zDirClampWanted= ClientCfg.ShadowZDirClampLandscape;
3304 float maxDepth= ClientCfg.ShadowMaxDepthLandscape;
3305 if(indoor())
3307 zDirClampWanted= ClientCfg.ShadowZDirClampInterior;
3308 maxDepth= ClientCfg.ShadowMaxDepthInterior;
3311 // smooth over time
3312 if(_ShadowMapZDirClamp!=zDirClampWanted || _ShadowMapMaxDepth!=maxDepth)
3314 // if some time passed since last update
3315 sint64 dt= T1-_ShadowMapPropertyLastUpdate;
3316 if(dt!=0)
3318 // update _ShadowMapZDirClamp
3319 if(_ShadowMapZDirClamp<zDirClampWanted)
3321 _ShadowMapZDirClamp+= ClientCfg.ShadowZDirClampSmoothSpeed * 0.001f * dt;
3322 if(_ShadowMapZDirClamp>zDirClampWanted)
3323 _ShadowMapZDirClamp= zDirClampWanted;
3325 else if(_ShadowMapZDirClamp>zDirClampWanted)
3327 _ShadowMapZDirClamp-= ClientCfg.ShadowZDirClampSmoothSpeed * 0.001f * dt;
3328 if(_ShadowMapZDirClamp<zDirClampWanted)
3329 _ShadowMapZDirClamp= zDirClampWanted;
3332 // update _ShadowMapMaxDepth
3333 if(_ShadowMapMaxDepth<maxDepth)
3335 _ShadowMapMaxDepth+= ClientCfg.ShadowMaxDepthSmoothSpeed * 0.001f * dt;
3336 if(_ShadowMapMaxDepth>maxDepth)
3337 _ShadowMapMaxDepth=maxDepth;
3339 else if(_ShadowMapMaxDepth>maxDepth)
3341 _ShadowMapMaxDepth-= ClientCfg.ShadowMaxDepthSmoothSpeed * 0.001f * dt;
3342 if(_ShadowMapMaxDepth<maxDepth)
3343 _ShadowMapMaxDepth=maxDepth;
3346 // update shadowMap, to update the clamp zdirection, and the shadow depth
3347 updateCastShadowMap();
3351 // bkup last time of update
3352 _ShadowMapPropertyLastUpdate= T1;
3355 // ***************************************************************************
3356 void CEntityCL::setOrderingLayer(uint layer)
3358 if (!_Skeleton.empty()) _Skeleton.setOrderingLayer(layer);
3362 void CEntityCL::displayable(bool d)
3364 _Displayable = d;
3365 // :KLUDGE: Hide selection FX
3366 if (!_Displayable && !_SelectionFX.empty() && Scene)
3368 Scene->deleteInstance(_SelectionFX);
3372 // ***************************************************************************
3373 EGSPD::CPeople::TPeople CEntityCL::people() const
3375 return EGSPD::CPeople::Unknown;
3378 // ***************************************************************************
3379 void CEntityCL::setPeople(EGSPD::CPeople::TPeople /* people */)
3383 // ***************************************************************************
3384 void CEntityCL::forceEvalAnim()
3386 if (getLastClip())
3388 // find highest father in the hierarchy
3389 CEntityCL *parentEntity = this;
3390 for(;;)
3392 CEntityCL *nextParent = EntitiesMngr.entity(parentEntity->parent());
3393 if (!nextParent) break;
3394 parentEntity = nextParent;
3397 // Snap the parent entity to the ground.
3399 H_AUTO ( RZ_Client_Entity_CL_Update_Snap_To_Ground )
3400 parentEntity->snapToGround();
3403 // Animate the parent entity (and also child entities)
3405 H_AUTO ( RZ_Client_Entity_CL_Update_Display )
3406 parentEntity->updateDisplay();
3412 // ***************************************************************************
3413 const NLMISC::CAABBox &CEntityCL::localSelectBox()
3415 // recompute the selection box?
3416 if(_LastLocalSelectBoxComputeTime<T1)
3418 _LastLocalSelectBoxComputeTime=T1;
3419 bool found= false;
3421 // if skeleton, compute aabox from precise skeleton method
3422 if(!_Skeleton.empty())
3424 // Don't compute if in LOD form (else flick because sometimes valid because of shadow animation)
3425 if(!_Skeleton.isDisplayedAsLodCharacter())
3428 bool computed;
3429 static volatile bool useBoneSphere = true;
3430 if (useBoneSphere) computed = _Skeleton.computeRenderedBBoxWithBoneSphere(_LocalSelectBox, false);
3431 else computed = _Skeleton.computeRenderedBBox(_LocalSelectBox);
3432 if (computed)
3434 found= true;
3435 // apply local offset due to skeleton animation
3436 CMatrix invMat = _DirMatrix;
3437 invMat.setPos(pos());
3438 invMat.invert();
3439 CVector localOffset = invMat * _Skeleton.getPos();
3440 _LocalSelectBox.setCenter(_LocalSelectBox.getCenter() + localOffset);
3441 static volatile float rot = -1.f;
3442 CMatrix rotMat;
3443 rotMat.rotateZ((float) Pi * rot / 2);
3444 CVector newHalfSize = rotMat * _LocalSelectBox.getHalfSize();
3445 newHalfSize.x = fabsf(newHalfSize.x);
3446 newHalfSize.y = fabsf(newHalfSize.y);
3447 newHalfSize.z = fabsf(newHalfSize.z);
3448 _LocalSelectBox.setHalfSize(newHalfSize);
3451 if (_Skeleton.computeRenderedBBoxWithBoneSphere(_LocalSelectBox, false))
3453 found= true;
3454 // apply local offset due to skeleton animation
3455 CMatrix invMat = _DirMatrix;
3456 invMat.setPos(pos());
3457 invMat.invert();
3458 CMatrix localMat = invMat * _Skeleton.getMatrix();
3459 _LocalSelectBox = CAABBox::transformAABBox(localMat, _LocalSelectBox);
3463 // else compute from static bot object
3464 else
3466 UInstance inst;
3467 // try with _Instances array first
3468 if(!_Instances.empty())
3469 inst= _Instances[0].Current;
3470 // Fallback to _Instance (??)
3471 if(inst.empty())
3472 inst= _Instance;
3474 // if static instance found
3475 if(!inst.empty())
3477 inst.getShapeAABBox(_LocalSelectBox);
3478 found= true;
3483 // if not found, fallback to default bbox
3484 if(!found)
3486 _LocalSelectBox.setCenter(_Aabbox.getCenter() - pos().asVector());
3487 _LocalSelectBox.setHalfSize(_Aabbox.getHalfSize());
3489 else
3491 CVector scale;
3492 getMeshDefaultScale(scale);
3493 const CVector &halfSize = _LocalSelectBox.getHalfSize();
3494 const CVector &center = _LocalSelectBox.getCenter();
3495 _LocalSelectBox.setHalfSize(CVector(halfSize.x * scale.x, halfSize.y * scale.y, halfSize.z * scale.z));
3496 _LocalSelectBox.setCenter(CVector(center.x * scale.x, center.y * scale.y, center.z * scale.z));
3500 // Return the selection box.
3501 return _LocalSelectBox;
3504 //----------------------------------------------------------------------
3505 void CEntityCL::getMeshDefaultScale(NLMISC::CVector &scale) const
3507 scale.set(1.f, 1.f, 1.f);
3508 if (!_Skeleton.empty()) return; // scale already applied to skeleton
3509 if (!_Instance.empty())
3511 const_cast<UInstance &>(_Instance).getScale(scale);
3513 else if (!_Instances.empty())
3515 if (!_Instances[0].Current.empty())
3517 const_cast<UInstance &>(_Instances[0].Current).getScale(scale);
3519 else if (!_Instances[0].Loading.empty())
3521 const_cast<UInstance &>(_Instances[0].Loading).getScale(scale);
3527 //----------------------------------------------------------------------
3528 bool CEntityCL::isAnOutpostEnemy() const
3530 if ( getOutpostId() != 0 )
3532 if( UserEntity->getOutpostId() == getOutpostId() )
3534 if( UserEntity->getOutpostSide() != getOutpostSide() )
3536 // same outpost but different side
3537 return true;
3541 return false;
3545 //----------------------------------------------------------------------
3546 bool CEntityCL::isAnOutpostAlly() const
3548 if ( getOutpostId() != 0 )
3550 if( UserEntity->getOutpostId() == getOutpostId() )
3552 if( UserEntity->getOutpostSide() == getOutpostSide() )
3554 // same outpost and same side
3555 return true;
3559 return false;
3563 //----------------------------------------------------------------------
3564 CVector CEntityCL::dirToTarget() const
3566 CVector dir2Target;
3567 CEntityCL * target = EntitiesMngr.entity( targetSlot() );
3568 if( target )
3570 dir2Target = target->pos() - pos();
3571 dir2Target.z = 0;
3572 dir2Target.normalize();
3574 else
3576 dir2Target = dir();
3578 return dir2Target;
3581 //----------------------------------------------------------------------
3582 void CEntityCL::setStateFx(const std::string &fxName)
3584 if (fxName != _StateFXName)
3586 if (!_StateFX.empty() && Scene)
3588 Scene->deleteInstance(_StateFX);
3591 NL3D::UInstance instance = Scene->createInstance(fxName);
3593 if (!instance.empty())
3595 _StateFX.cast (instance);
3596 if (_StateFX.empty())
3598 // shape found, but not a particle system
3599 Scene->deleteInstance(instance);
3601 else
3603 _StateFX.setScale(0.5, 0.5, 0.5);
3604 _StateFXName = fxName;
3610 //----------------------------------------------------------------------
3611 void CEntityCL::removeStateFx()
3613 if (!_StateFX.empty() && Scene)
3615 Scene->deleteInstance(_StateFX);
3616 _StateFXName.clear();