1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include "nel/misc/time_nl.h"
31 #include "player_cl.h"
32 #include "ingame_database_manager.h"
33 #include "net_manager.h"
34 #include "time_client.h"
35 #include "entity_animation_manager.h"
36 #include "sheet_manager.h"
37 #include "color_slot_manager.h"
38 #include "debug_client.h"
40 #include "interface_v3/interface_manager.h"
42 #include "pacs_client.h"
43 #include "motion/user_controls.h"
44 #include "client_cfg.h"
45 #include "user_entity.h"
46 #include "faction_war_manager.h"
48 #include "client_sheets/player_sheet.h"
50 #include "nel/3d/u_scene.h"
51 #include "nel/3d/u_instance_material.h"
52 #include "nel/3d/u_play_list.h"
53 #include "nel/3d/u_bone.h"
54 #include "nel/3d/u_particle_system_instance.h"
55 #include "nel/3d/u_point_light.h"
57 #include "game_share/player_visual_properties.h"
58 #include "game_share/gender.h"
59 #include "game_share/bot_chat_types.h"
60 #include "interface_v3/lua_ihm_ryzom.h"
66 using namespace NLMISC
;
68 using namespace NLPACS
;
76 extern CEntityAnimationManager
*EAM
;
77 extern UTextContext
*TextContext
;
78 extern UCamera MainCam
;
81 //-----------------------------------------------
84 //-----------------------------------------------
85 CPlayerCL::CPlayerCL()
90 // Resize _Instances to the number of visual slots.
91 _Instances
.resize(SLOTTYPE::NB_SLOT
);
97 // Some default colors.
101 // Not enough information to display the player.
102 _WaitForAppearance
= true;
104 _PlayerCLAsyncTextureLoading
= false;
106 // Light Off and not allocated
111 //-----------------------------------------------
114 //-----------------------------------------------
115 CPlayerCL::~CPlayerCL()
117 // No more sheet pointed.
124 Scene
->deletePointLight(_Light
);
128 //---------------------------------------------------
130 // Return the entity scale. (return 1.0 if there is any problem).
131 //---------------------------------------------------
132 float CPlayerCL::getScale() const // virtual
135 return _CharacterScalePos
;
140 //-----------------------------------------------
142 // retrieve ground fxs for the entity depending on the ground
143 //-----------------------------------------------
144 const std::vector
<CGroundFXSheet
> *CPlayerCL::getGroundFX() const
148 case 0: return &(_PlayerSheet
->GenderInfos
[0].GroundFX
);
149 case 1: return &(_PlayerSheet
->GenderInfos
[1].GroundFX
);
156 //-----------------------------------------------
158 // Return true if this entity is a neutral entity(pvp or not)
159 //-----------------------------------------------
160 bool CPlayerCL::isNeutral() const
162 return (!isEnemy() && !isAlly());
166 //-----------------------------------------------
168 // Return true if this entity is a user's friend.
169 //-----------------------------------------------
170 bool CPlayerCL::isFriend () const
172 return isNeutral() || isAlly();
176 //-----------------------------------------------
178 // true if at least enemy in on pvp mode
179 //-----------------------------------------------
180 bool CPlayerCL::isEnemy () const
182 // Challenge i.e. SOLO FULL PVP
183 if( getPvpMode()&PVP_MODE::PvpChallenge
||
184 UserEntity
->getPvpMode()&PVP_MODE::PvpChallenge
)
190 // if one of 2 players is not in pvp they can't be enemies
191 if( UserEntity
->getPvpMode() == PVP_MODE::None
||
192 getPvpMode() == PVP_MODE::None
)
197 // if one of 2 players is safe they can't be enemies
198 if( UserEntity
->getPvpMode()&PVP_MODE::PvpSafe
||
199 getPvpMode()&PVP_MODE::PvpSafe
)
204 // if one of 2 players are in safe zone and not flagged they can't be enemies
205 if ((UserEntity
->getPvpMode()&PVP_MODE::PvpZoneSafe
&&
206 ((UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
) == 0))
208 (getPvpMode()&PVP_MODE::PvpZoneSafe
&&
209 ((getPvpMode()&PVP_MODE::PvpFactionFlagged
) == 0)))
215 if( getPvpMode()&PVP_MODE::PvpDuel
&&
216 UserEntity
->getPvpMode()&PVP_MODE::PvpDuel
)
222 if ( isAnOutpostEnemy() )
228 if( getPvpMode()&PVP_MODE::PvpZoneFree
&&
229 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFree
)
231 // If not in same Team and not in same League => ennemy
232 if( !isInTeam() && !isInSameLeague() )
237 if( getPvpMode()&PVP_MODE::PvpZoneGuild
&&
238 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneGuild
)
240 // If in same Guild but different Leagues => ennemy
241 if ( isInSameGuild() && oneInLeague() && !isInSameLeague() )
244 if( !isInTeam() && !isInSameLeague() )
249 if( getPvpMode()&PVP_MODE::PvpZoneFaction
&&
250 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFaction
)
252 if (getPvpClan() != UserEntity
->getPvpClan())
256 // Free PVP : Ennemis are not in team AND not in league
257 if ((getPvpMode()&PVP_MODE::PvpFaction
|| getPvpMode()&PVP_MODE::PvpFactionFlagged
) &&
258 (UserEntity
->getPvpMode()&PVP_MODE::PvpFaction
|| UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
))
260 // If in same Guild but different Leagues => ennemy
261 if ( isInSameGuild() && oneInLeague() && !isInSameLeague() )
264 if (!isInTeam() && !isInSameLeague())
273 //-----------------------------------------------
275 // true if at least ally in one pvp mode
276 //-----------------------------------------------
277 bool CPlayerCL::isAlly() const
280 // Challenge i.e. SOLO FULL PVP
281 if( getPvpMode()&PVP_MODE::PvpChallenge
||
282 UserEntity
->getPvpMode()&PVP_MODE::PvpChallenge
)
287 // if one of 2 players is not in pvp they can't be allies
288 if( UserEntity
->getPvpMode() == PVP_MODE::None
||
289 getPvpMode() == PVP_MODE::None
)
294 // if one of 2 players is in safe zone and not other they can't be allies
295 if ((UserEntity
->getPvpMode()&PVP_MODE::PvpSafe
) != (getPvpMode()&PVP_MODE::PvpSafe
))
301 if ( isAnOutpostAlly() )
307 if( getPvpMode()&PVP_MODE::PvpZoneFree
&&
308 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFree
)
310 if( isInTeam() || isInSameLeague() )
315 if( getPvpMode()&PVP_MODE::PvpZoneGuild
&&
316 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneGuild
)
318 if( isInTeam() || isInSameLeague() )
321 if ( isInSameGuild() && !oneInLeague() )
327 if( getPvpMode()&PVP_MODE::PvpZoneFaction
&&
328 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFaction
)
330 if (getPvpClan() == UserEntity
->getPvpClan())
334 // Free PVP : Allies are in team OR in league
335 if ((getPvpMode()&PVP_MODE::PvpFaction
|| getPvpMode()&PVP_MODE::PvpFactionFlagged
) &&
336 (UserEntity
->getPvpMode()&PVP_MODE::PvpFaction
|| UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
))
338 if (isInTeam() || isInSameLeague())
341 if ( isInSameGuild() && !oneInLeague() )
350 //-----------------------------------------------
352 //-----------------------------------------------
353 bool CPlayerCL::isNeutralPVP() const
355 // if player is not in pvp they can't be neutral pvp
356 if( getPvpMode() == PVP_MODE::None
)
361 if( UserEntity
->getPvpMode() == PVP_MODE::None
)
366 return (!isEnemy() && !isAlly());
370 //-----------------------------------------------
372 // Build the entity from a sheet.
373 //-----------------------------------------------
374 bool CPlayerCL::build(const CEntitySheet
*sheet
) // virtual
376 // Cast the sheet in the right type.
377 _PlayerSheet
= dynamic_cast<const CRaceStatsSheet
*>(sheet
);
380 pushDebugStr(NLMISC::toString("Player '%d' sheet is not a '.race_stats' -> BIG PROBLEM.", _Slot
));
384 pushInfoStr(NLMISC::toString("Player '%d' sheet is valid.", _Slot
));
386 if(IngameDbMngr
.getNodePtr())
388 CCDBNodeBranch
*nodeRoot
= dynamic_cast<CCDBNodeBranch
*>(IngameDbMngr
.getNodePtr()->getNode(0));
391 _DBEntry
= dynamic_cast<CCDBNodeBranch
*>(nodeRoot
->getNode(_Slot
));
393 pushDebugStr("Cannot get a pointer on the DB entry.");
397 // Compute the first automaton.
398 _CurrentAutomaton
= automatonType() + "_normal.automaton";
400 // Initialize the player look.
402 // Compute the primitive
403 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
404 // Create the collision entity (used to snap the entity to the ground).
405 computeCollisionEntity();
407 // Initialize properties of the client.
413 //-----------------------------------------------
415 // Return the automaton type of the entity (homin, creature, etc.)
416 //-----------------------------------------------
417 std::string
CPlayerCL::automatonType() const // virtual
419 return _PlayerSheet
->Automaton
;
423 //-----------------------------------------------
425 // Initialize the graphic for the player.
426 //-----------------------------------------------
427 void CPlayerCL::init3d()
430 // Initialize the internal time.
431 _LastFrameTime
= ((double)T1
) * 0.001;
435 //-----------------------------------------------
437 // Initialize properties of the entity (according to the class).
438 //-----------------------------------------------
439 void CPlayerCL::initProperties()
441 properties().selectable(true);
442 properties().attackable(false);
443 properties().givable(true);
444 properties().invitable(true);
445 properties().canExchangeItem(true);
446 }// initProperties //
449 //-----------------------------------------------
451 // Set the equipmenent worn.
452 //-----------------------------------------------
453 void CPlayerCL::equip(SLOTTYPE::EVisualSlot slot
, const std::string
&shapeName
, const CItemSheet
*item
, sint color
)
456 if(slot
== SLOTTYPE::HIDDEN_SLOT
|| slot
>= SLOTTYPE::NB_SLOT
)
458 nlwarning("CCharacterCL::equip : slot %d is not valid.", (uint
)slot
);
464 // If exactly the same than before -> return
466 if (!_Instances
[s
].Loading
.empty())
468 if ((_Instances
[s
].LoadingName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
471 else if (!_Instances
[s
].Current
.empty())
473 if ((_Instances
[s
].CurrentName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
477 // Attach to the skeleton.
479 if(!_Skeleton
.empty())
483 case SLOTTYPE::RIGHT_HAND_SLOT
:
484 if( item
&& item
->ItemType
!= ITEM_TYPE::MAGICIAN_STAFF
)
485 stickPoint
= "box_arme";
488 case SLOTTYPE::LEFT_HAND_SLOT
:
489 if((_Items
[slot
].Sheet
&& _Items
[slot
].Sheet
->getAnimSet() == "s") || (item
&& item
->getAnimSet() == "s"))
490 stickPoint
= "Box_bouclier";
492 stickPoint
= "box_arme_gauche";
500 /* If the object is sticked (ie not a skin), decide to delete the Current instance. Why? because the animation
501 is changed according to the equipped item.
503 Hence, For example, if a sword would be changed for a gun, then the new gun animation would take place,
504 while Keeping the old sword shape. BAD.
506 if(!stickPoint
.empty())
507 _Instances
[s
].createLoading(string(), stickPoint
);
509 // Create the instance.
511 _Instances
[s
].createLoading(shapeName
, stickPoint
, color
);
515 _Instances
[s
].createLoading(shapeName
, stickPoint
, item
->MapVariant
);
517 _Instances
[s
].createLoading(shapeName
, stickPoint
);
520 // If shapeName is empty, only clear the slot
521 if(shapeName
.empty())
523 _Items
[slot
].release();
527 if(!_Instances
[s
].Loading
.empty())
529 _Instances
[s
].FXItemSheet
= item
;
531 _Items
[slot
].initFXs(slot
, _Instances
[s
].Loading
);
534 nlwarning("PL::equip(1):%d: cannot create the instance '%s'.", _Slot
, shapeName
.c_str());
536 if (!item
&& (slot
!= SLOTTYPE::RIGHT_HAND_SLOT
) && (slot
!= SLOTTYPE::LEFT_HAND_SLOT
))
537 applyColorSlot(_Instances
[s
], skin(), 6, _HairColor
, _EyesColor
);
541 //-----------------------------------------------
543 // Compute the equipmenent worn.
544 //-----------------------------------------------
545 void CPlayerCL::equip(SLOTTYPE::EVisualSlot slot
, uint index
, uint color
)
547 // Get the sheet according to the visual slot
548 _Items
[slot
].Sheet
= SheetMngr
.getItem(slot
, index
);
549 if(_Items
[slot
].Sheet
)
551 const CItemSheet
*item
= _Items
[slot
].Sheet
;
553 std::string shapeName
= "";
554 if(_Gender
== GSGENDER::male
)
556 switch(_PlayerSheet
->People
)
558 case EGSPD::CPeople::Fyros
:
559 shapeName
= item
->getShapeFyros();
561 case EGSPD::CPeople::Matis
:
562 shapeName
= item
->getShapeMatis();
564 case EGSPD::CPeople::Tryker
:
565 shapeName
= item
->getShapeTryker();
567 case EGSPD::CPeople::Zorai
:
568 shapeName
= item
->getShapeZorai();
574 switch(_PlayerSheet
->People
)
576 case EGSPD::CPeople::Fyros
:
577 shapeName
= item
->getShapeFyrosFemale();
579 case EGSPD::CPeople::Matis
:
580 shapeName
= item
->getShapeMatisFemale();
582 case EGSPD::CPeople::Tryker
:
583 shapeName
= item
->getShapeTrykerFemale();
585 case EGSPD::CPeople::Zorai
:
586 shapeName
= item
->getShapeZoraiFemale();
589 if (shapeName
.empty())
590 shapeName
= item
->getShapeFemale();
592 if (shapeName
.empty())
593 shapeName
= item
->getShape();
596 // use the right type of boots if wearing a caster dress
597 if ((slot
== SLOTTYPE::FEET_SLOT
) && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
|| item
->ItemType
== ITEM_TYPE::MEDIUM_BOOTS
|| item
->ItemType
== ITEM_TYPE::HEAVY_BOOTS
))
599 std::string shapeLegs
;
601 if (!_Instances
[SLOTTYPE::LEGS_SLOT
].Loading
.empty())
603 shapeLegs
= _Instances
[SLOTTYPE::LEGS_SLOT
].LoadingName
;
605 else if (!_Instances
[SLOTTYPE::LEGS_SLOT
].Current
.empty())
607 shapeLegs
= _Instances
[SLOTTYPE::LEGS_SLOT
].CurrentName
;
610 if (!shapeLegs
.empty() && shapeLegs
.find("_caster01_") != std::string::npos
)
612 std::string tmpName
= toLowerAscii(shapeName
);
614 std::string::size_type posBottes
= tmpName
.find("_bottes");
616 if (posBottes
!= std::string::npos
)
618 std::string orgType
= tmpName
.substr(7, posBottes
-7); // underwear, caster01, armor00 or armor01
620 tmpName
.replace(posBottes
+7, 0, "_" + orgType
);
621 tmpName
.replace(7, orgType
.length(), "caster01");
623 if (CPath::exists(tmpName
))
625 // use fixed shape name only if file is present
630 // temporary hack because Fyros light boots don't respect conventions
631 if (tmpName
[0] == 'f' && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
))
633 if (tmpName
[5] == 'f')
635 tmpName
= "fy_hof_caster01_bottes_civil.shape";
639 tmpName
= "fy_hom_caster01_civil01_bottes.shape";
642 // use fixed shape name only if file is present
643 if (CPath::exists(tmpName
))
649 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), shapeName
.c_str());
654 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), shapeName
.c_str());
661 // If the gender is a female get the right shape else get the default shape.
662 equip(slot
, shapeName
, item
);
664 // Check there is a shape.
665 UInstance pInst
= _Instances
[slot
].createLoadingFromCurrent();
668 // Set the right texture variation (quality).
669 pInst
.selectTextureSet((uint
)item
->MapVariant
);
670 _Instances
[slot
].TextureSet
= item
->MapVariant
;
672 // If Hair, color is for the head slot.
673 if(slot
== SLOTTYPE::HEAD_SLOT
&& item
->Family
!= ITEMFAMILY::ARMOR
)
674 applyColorSlot(_Instances
[slot
], skin(), 0, color
, _EyesColor
);
677 // Set the User Color.
678 if(item
->Color
== -1)
679 applyColorSlot(_Instances
[slot
], skin(), color
, _HairColor
, _EyesColor
);
680 // Set the Item Color.
681 else if(item
->Color
!= -2)
682 applyColorSlot(_Instances
[slot
], skin(), item
->Color
, _HairColor
, _EyesColor
);
683 // Else let the default color.
685 applyColorSlot(_Instances
[slot
], skin(), 0, _HairColor
, _EyesColor
);
689 // Default equipment.
692 nldebug("PL:equip(2):%d: VS '%d' default equipement used.", _Slot
, slot
);
693 sint idx
= SheetMngr
.getVSIndex(_PlayerSheet
->GenderInfos
[_Gender
].Items
[slot
], slot
);
696 if(SheetMngr
.getItem(slot
, (uint
)idx
))
698 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
700 // If the gender is a female get the right shape else get the default shape.
701 equip(slot
, _Gender
== GSGENDER::female
? itemSheet
->getShapeFemale():itemSheet
->getShape());
707 //-----------------------------------------------
709 // Compute the animation set to use according to weapons, mode and race.
710 //-----------------------------------------------
711 void CPlayerCL::computeAnimSet(sint32 fakeLeftHand
, sint32 fakeRightHand
)
713 // We need a valid Gender to compute the animset.
716 nlwarning("PL:computeAnimSet:%d: not a male or a female (gender=%d).", _Slot
, _Gender
);
720 // Now computing the animset.
721 // Do not count weapons if swimming.
722 const CItemSheet
*leftHand
= _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
723 const CItemSheet
*rightHand
= _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
725 if (fakeLeftHand
>= 0)
726 leftHand
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, fakeLeftHand
);
727 if (fakeRightHand
>= 0)
728 rightHand
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, fakeRightHand
);
730 if(!::computeAnimSet(_CurrentAnimSet
[MOVE
], _Mode
, _PlayerSheet
->GenderInfos
[_Gender
].AnimSetBaseName
, leftHand
, rightHand
, !modeWithHiddenItems()))
731 nlwarning("PL:computeAnimSet:%d: pb when computing the animset.", _Slot
);
733 }// computeAnimSet //
736 //-----------------------------------------------
737 // updateVisualPropertyVpa :
738 // Update the Visual Property A.
739 // \todo GUIGUI : use gender enum
740 //-----------------------------------------------
741 void CPlayerCL::updateVisualPropertyVpa(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
743 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
745 // Player will now have enough information to display the character.
746 _WaitForAppearance
= false;
749 SPropVisualA visualA
= *(SPropVisualA
*)(&prop
);
751 sint32 fakeLeftHand
= -1;
752 sint32 fakeRightHand
= -1;
755 _Gender
= (GSGENDER::EGender
)(visualA
.PropertySubData
.Sex
);
756 if(_Gender
!=GSGENDER::male
&& _Gender
!=GSGENDER::female
)
758 nlwarning("PL::updateVPVpa:%d: neither a male nor a female -> male selected.", _Slot
);
759 _Gender
= GSGENDER::male
;
762 // update title when gender changed
763 const string replacement
= STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
, _Gender
== GSGENDER::female
);
764 if (!replacement
.empty() || !ClientCfg
.DebugStringManager
)
767 _NameEx
= replacement
;
768 _Title
= replacement
;
770 // display the new title in player interface
773 CViewText
*pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:player:header_opened:player_title"));
774 if (pVT
!= NULL
) pVT
->setText(_Title
);
777 // rebuild in scene interface
778 buildInSceneInterface();
781 // Setup _CharacterScalePos
782 _CharacterScalePos
= _PlayerSheet
->GenderInfos
[_Gender
].CharacterScalePos
;
784 // Check if skeleton has changed
785 if (_CacheSkeletonShapeName
!= _PlayerSheet
->GenderInfos
[_Gender
].Skelfilename
)
787 _CacheSkeletonShapeName
= _PlayerSheet
->GenderInfos
[_Gender
].Skelfilename
;
789 // Clean the playlist.
791 _PlayList
->resetAllChannels();
793 // We can now build the skeleton so do it now.
794 skeleton(_CacheSkeletonShapeName
);
796 // Invalidate instances cache
797 for (uint i
= 0; i
< _Instances
.size(); ++i
)
799 _Instances
[i
].CurrentName
.clear();
800 _Instances
[i
].LoadingName
.clear();
802 _Face
.CurrentName
.clear();
803 _Face
.LoadingName
.clear();
805 // Check the skeleton.
806 if(skeleton() && !ClientCfg
.Light
)
808 string rightHandTag
, leftHandTag
;
809 // To re-link the skeleton to the mount if needed.
811 // Set the skeleton scale.
812 // \todo GUIGUI: put scale too in race_stats.
813 // Setup Lod Character skeleton, if skeleton exist
814 // Get Lod Character Id from the sheet.
815 sint clodId
= getLodCharacterId(*Scene
, _PlayerSheet
->GenderInfos
[_Gender
].LodCharacterName
);
818 // Setup Lod Character shape and distance
819 skeleton()->setLodCharacterShape(clodId
);
820 skeleton()->setLodCharacterDistance(_PlayerSheet
->GenderInfos
[_Gender
].LodCharacterDistance
);
826 equip(SLOTTYPE::CHEST_SLOT
, visualA
.PropertySubData
.JacketModel
, visualA
.PropertySubData
.JacketColor
);
828 equip(SLOTTYPE::LEGS_SLOT
, visualA
.PropertySubData
.TrouserModel
, visualA
.PropertySubData
.TrouserColor
);
830 equip(SLOTTYPE::ARMS_SLOT
, visualA
.PropertySubData
.ArmModel
, visualA
.PropertySubData
.ArmColor
);
832 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
833 // OBJECT in the RIGHT HAND
834 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
835 // Equip the weapon(object/tool).
836 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
838 if(_Gender
== GSGENDER::female
)
839 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShapeFemale(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
841 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
843 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
844 if (!itemInstance
.empty())
847 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
848 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
849 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(0);
850 //_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(visualA.PropertySubData.RTrail);
855 // No Valid item in the right hand.
856 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::RIGHT_HAND_SLOT
;
857 rightHandTag
= getTag(5);
858 if (!rightHandTag
.empty() && rightHandTag
!= "_")
861 vector
<string
> tagInfos
;
862 splitString(rightHandTag
, string("|"), tagInfos
);
865 // Manage cache of items
866 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
869 fromString(tagInfos
[0].substr(1), itemNameId
);
870 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
873 if (tagInfos
.size() >= 3 && tagInfos
[2] == "2H")
874 fakeRightHand
= SheetMngr
.getVSIndex("ic_candy_stick.sitem", slot
);
876 fakeRightHand
= SheetMngr
.getVSIndex("stake.sitem", slot
);
878 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)fakeRightHand
);
880 if (tagInfos
.size() >= 2)
883 fromString(tagInfos
[1], instTexture
);
884 equip(slot
, tagInfos
[0], itemSheet
, instTexture
);
888 equip(slot
, tagInfos
[0], itemSheet
);
897 // OBJECT in the LEFT HAND
898 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
899 // Equip the weapon(object/tool).
900 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
902 equip(SLOTTYPE::LEFT_HAND_SLOT
, _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
);
903 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
904 if (!itemInstance
.empty())
907 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
908 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(0);
909 //_Items[SLOTTYPE::LEFT_HAND_SLOT].setTrailSize(2 * (uint) visualA.PropertySubData.LTrail);
914 // No Valid item in the left hand.
915 equip(SLOTTYPE::LEFT_HAND_SLOT
, "");
916 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::LEFT_HAND_SLOT
;
917 leftHandTag
= getTag(6);
918 if (!leftHandTag
.empty() && leftHandTag
!= "_")
920 vector
<string
> tagInfos
;
921 splitString(leftHandTag
, string("|"), tagInfos
);
924 // Manage cache of items
925 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
928 fromString(tagInfos
[0].substr(1), itemNameId
);
929 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
933 if (tagInfos
.size() >= 3 && tagInfos
[2] == "S")
934 fakeLeftHand
= SheetMngr
.getVSIndex("icbss_pvp.sitem", slot
);
936 fakeLeftHand
= SheetMngr
.getVSIndex("icfm1pd.sitem", slot
);
938 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)fakeLeftHand
);
940 if (tagInfos
.size() >= 2)
943 fromString(tagInfos
[1], instTexture
);
944 equip(slot
, tagInfos
[0], itemSheet
, instTexture
);
948 equip(slot
, tagInfos
[0], itemSheet
);
956 CLuaManager::getInstance().executeLuaScript(toString("game:updateRpItems('%s', '%s')", leftHandTag
.c_str(), rightHandTag
.c_str()), 0);
959 // Only create a face when there is no Helmet
960 if(_Items
[SLOTTYPE::HEAD_SLOT
].Sheet
== 0 || _Items
[SLOTTYPE::HEAD_SLOT
].Sheet
->Family
!= ITEMFAMILY::ARMOR
)
962 CItemSheet
*faceItem
= getItem(_PlayerSheet
->GenderInfos
[_Gender
], SLOTTYPE::FACE_SLOT
);
967 if(_Gender
== GSGENDER::female
)
968 sFaceName
= faceItem
->getShapeFemale();
970 sFaceName
= faceItem
->getShape();
972 if (((!_Face
.Loading
.empty()) && (_Face
.LoadingName
!= sFaceName
)) ||
973 ((!_Face
.Current
.empty()) && (_Face
.CurrentName
!= sFaceName
)) ||
974 (_Face
.Current
.empty()))
976 if (!_Face
.Loading
.empty())
978 Scene
->deleteInstance(_Face
.Loading
);
979 _Face
.Loading
= NULL
;
980 _Face
.LoadingName
= sFaceName
;
982 _Face
.Loading
= Scene
->createInstance(sFaceName
);
983 if (!_Face
.Loading
.empty())
985 _Face
.LoadingName
= sFaceName
;
986 if(!skeleton()->bindSkin(_Face
.Loading
))
987 nlwarning("PL::updateVPVpa:%d: Cannot bind the face.", _Slot
);
988 _Face
.Loading
.hide();
989 // set it async for texture
990 _Face
.Loading
.enableAsyncTextureMode(true);
993 nlwarning("PL::updateVPVpa:%d: Cannot create the face.", _Slot
);
995 _Face
.TextureSet
= faceItem
->MapVariant
;
996 applyColorSlot(_Face
, skin(), 0, visualA
.PropertySubData
.HatColor
, 0); // Set a default ruflaket color.
999 nlwarning("PL::updateVPVpa:%d: Face Item '%s' does not exist.", _Slot
,
1000 _PlayerSheet
->GenderInfos
[_Gender
].Items
[SLOTTYPE::FACE_SLOT
].c_str());
1002 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
1004 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::HEAD_SLOT
;
1005 string hatTag
= getTag(7);
1006 if (!hatTag
.empty() && hatTag
!= "_")
1008 sint idx
= SheetMngr
.getVSIndex("eroukan_h.sitem", slot
);
1009 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
1010 vector
<string
> tagInfos
;
1011 splitString(hatTag
, string("|"), tagInfos
);
1014 // Manage cache of items
1015 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
1018 fromString(tagInfos
[0].substr(1), itemNameId
);
1019 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
1022 if (tagInfos
.size() == 2)
1025 fromString(tagInfos
[1], instTexture
);
1026 equip(slot
, tagInfos
[0], itemSheet
);
1027 _Instances
[slot
].selectTextureSet(instTexture
);
1028 _Instances
[slot
].TextureSet
= instTexture
;
1032 equip(slot
, tagInfos
[0], itemSheet
);
1040 // There is a helmet !
1041 if (!_Face
.Loading
.empty())
1042 Scene
->deleteInstance(_Face
.Loading
);
1043 _Face
.Loading
= NULL
;
1044 _Face
.LoadingName
.clear();
1045 if (!_Face
.Current
.empty())
1046 Scene
->deleteInstance(_Face
.Current
);
1047 _Face
.Current
= NULL
;
1048 _Face
.CurrentName
.clear();
1050 // Now we have a skeleton, we can update VpB and VpC.
1053 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPB
);
1054 vB
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
1055 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPC
);
1056 vC
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
1057 updateVisualPropertyVpb(0, vB
);
1058 updateVisualPropertyVpc(0, vC
);
1060 // Attach The Light if there is one.
1061 if(!_Light
.empty() && _NameBoneId
!=-1)
1062 _Skeleton
.stickObject(_Light
, _NameBoneId
);
1064 // Compute the new animation set to use (due to weapons).
1065 computeAnimSet(fakeLeftHand
, fakeRightHand
);
1067 // Set the animation to idle.
1068 setAnim(CAnimationStateSheet::Idle
);
1072 nlwarning("PL::updateVPVpa:%d: Skeleton not allocated.", _Slot
);
1073 }// updateVisualPropertyVpa //
1075 //-----------------------------------------------
1076 // updateVisualPropertyVpb :
1077 // Update the Visual Property B.
1078 //-----------------------------------------------
1079 void CPlayerCL::updateVisualPropertyVpb(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
1081 // Get the property.
1082 SPropVisualB visualB
= *(SPropVisualB
*)(&prop
);
1084 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
1086 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
1087 if (!itemInstance
.empty())
1090 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
1091 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(visualB
.PropertySubData
.RTrail
);
1095 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
1097 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
1098 if (!itemInstance
.empty())
1101 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(2 * (uint
) visualB
.PropertySubData
.LTrail
);
1108 equip(SLOTTYPE::HANDS_SLOT
, visualB
.PropertySubData
.HandsModel
, visualB
.PropertySubData
.HandsColor
);
1110 equip(SLOTTYPE::FEET_SLOT
, visualB
.PropertySubData
.FeetModel
, visualB
.PropertySubData
.FeetColor
);
1113 nlinfo("PL::updateVPVpb:%d: Prop Vpb received before prop Vpa.", _Slot
);
1114 }// updateVisualPropertyVpb //
1116 //-----------------------------------------------
1117 // updateVisualPropertyVpc :
1118 // Update the Visual Property C.
1119 // \todo GUIGUI : factorize tatoos with character creation
1120 //-----------------------------------------------
1121 void CPlayerCL::updateVisualPropertyVpc(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
1125 // Get the property.
1126 SPropVisualC visualC
= *(SPropVisualC
*)(&prop
);
1129 _EyesColor
= visualC
.PropertySubData
.EyesColor
;
1132 // must recreate the face asynchronously (because of color change / makeup change)
1133 inst
= _Face
.createLoadingFromCurrent();
1138 // change eyes color only
1139 applyColorSlot(_Face
, _Face
.ACSkin
, _Face
.ACUser
, _Face
.ACHair
, visualC
.PropertySubData
.EyesColor
);
1142 makeUp(inst
, visualC
.PropertySubData
.Tattoo
);
1145 static const char *baseName
= "visage_00";
1148 const CGenderInfo
*pGI
= &_PlayerSheet
->GenderInfos
[_Gender
];
1152 MTmin
= pGI
->BlendShapeMin
[0];
1153 MTmax
= pGI
->BlendShapeMax
[0];
1154 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1155 inst
.setBlendShapeFactor(baseName
+ toString(0), (float)(visualC
.PropertySubData
.MorphTarget1
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1157 MTmin
= pGI
->BlendShapeMin
[1];
1158 MTmax
= pGI
->BlendShapeMax
[1];
1159 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1160 inst
.setBlendShapeFactor(baseName
+ toString(1), (float)(visualC
.PropertySubData
.MorphTarget2
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1162 MTmin
= pGI
->BlendShapeMin
[2];
1163 MTmax
= pGI
->BlendShapeMax
[2];
1164 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1165 inst
.setBlendShapeFactor(baseName
+ toString(2), (float)(visualC
.PropertySubData
.MorphTarget3
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1167 MTmin
= pGI
->BlendShapeMin
[3];
1168 MTmax
= pGI
->BlendShapeMax
[3];
1169 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1170 inst
.setBlendShapeFactor(baseName
+ toString(3), (float)(visualC
.PropertySubData
.MorphTarget4
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1172 MTmin
= pGI
->BlendShapeMin
[4];
1173 MTmax
= pGI
->BlendShapeMax
[4];
1174 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1175 inst
.setBlendShapeFactor(baseName
+ toString(4), (float)(visualC
.PropertySubData
.MorphTarget5
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1177 MTmin
= pGI
->BlendShapeMin
[5];
1178 MTmax
= pGI
->BlendShapeMax
[5];
1179 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1180 inst
.setBlendShapeFactor(baseName
+ toString(5), (float)(visualC
.PropertySubData
.MorphTarget6
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1182 MTmin
= pGI
->BlendShapeMin
[6];
1183 MTmax
= pGI
->BlendShapeMax
[6];
1184 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1185 inst
.setBlendShapeFactor(baseName
+ toString(6), (float)(visualC
.PropertySubData
.MorphTarget7
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1187 MTmin
= pGI
->BlendShapeMin
[7];
1188 MTmax
= pGI
->BlendShapeMax
[7];
1189 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1190 inst
.setBlendShapeFactor(baseName
+ toString(7), (float)(visualC
.PropertySubData
.MorphTarget8
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1194 float characterHeight
= (float)((sint8
)(visualC
.PropertySubData
.CharacterHeight
)-7)/7.f
;
1195 float torsoWidth
= (float)((sint8
)(visualC
.PropertySubData
.TorsoWidth
)-7)/7.f
;
1196 float armsWidth
= (float)((sint8
)(visualC
.PropertySubData
.ArmsWidth
)-7)/7.f
;
1197 float legsWidth
= (float)((sint8
)(visualC
.PropertySubData
.LegsWidth
)-7)/7.f
;
1198 float breastSize
= (float)((sint8
)(visualC
.PropertySubData
.BreastSize
)-7)/7.f
;
1199 float heightScale
, baseHeightScale
;
1200 // TODO : manage breast size
1201 GabaritSet
.applyGabarit(*skeleton(), _Gender
, people(), characterHeight
, torsoWidth
, armsWidth
, legsWidth
, breastSize
, &heightScale
);
1202 baseHeightScale
= GabaritSet
.getRefHeightScale(_Gender
, people());
1204 if(baseHeightScale
!= 0.f
)
1205 _CustomScalePos
= heightScale
/baseHeightScale
;
1208 _CustomScalePos
= 1.f
;
1209 nlwarning("PL::updateVPVpc:'%d': baseHeight == 0.", _Slot
);
1213 nlinfo("PL:updateVPVpc:'%d': Prop Vpc received before prop Vpa.", _Slot
);
1214 }// updateVisualPropertyVpc //
1216 //-----------------------------------------------
1217 //-----------------------------------------------
1218 void CPlayerCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle
&gameCycle
, const sint64
&prop
)
1220 CCharacterCL::updateVisualPropertyPvpMode(gameCycle
, prop
);
1221 // Additionaly, if i am the target, inform interface of the change
1224 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1225 CCDBNodeLeaf
*pDB
= NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:USER:TRACK_TARGET_PVP_CHANGE_MODE");
1228 sint32 val
= pDB
->getValue32();
1229 pDB
->setValue32(val
+1);
1235 //-----------------------------------------------
1237 // Get The Entity Skin
1238 //-----------------------------------------------
1239 sint
CPlayerCL::skin() const // virtual
1241 return _PlayerSheet
->Skin
;
1244 //-----------------------------------------------
1246 // Return the People for the entity.
1247 //-----------------------------------------------
1248 EGSPD::CPeople::TPeople
CPlayerCL::people() const// virtual
1251 return _PlayerSheet
->People
;
1253 return EGSPD::CPeople::Unknown
;
1256 //-----------------------------------------------
1258 // Setup the People for the entity.
1259 //-----------------------------------------------
1260 void CPlayerCL::setPeople(EGSPD::CPeople::TPeople
/* people */)
1264 //-----------------------------------------------
1267 //-----------------------------------------------
1268 void CPlayerCL::drawName(const NLMISC::CMatrix
&mat
) // virtual
1271 if(!getEntityName().empty())
1272 TextContext
->render3D(mat
, getEntityName());
1276 //-----------------------------------------------
1278 // Update eyes blink. For the moment, called by updatePos.
1279 //-----------------------------------------------
1280 CEntityCL::SInstanceCL
*CPlayerCL::getFace()
1282 // Implemented in CPlayerCL
1286 //-----------------------------------------------
1288 // Method to return the attack radius of an entity (take the scale into account).
1289 //-----------------------------------------------
1290 double CPlayerCL::attackRadius() const // virtual
1295 //-----------------------------------------------
1296 // Return the position the attacker should have to combat according to the attack angle.
1297 // \param ang : 0 = the front, >0 and <Pi = left side, <0 and >-Pi = right side.
1298 //-----------------------------------------------
1299 CVectorD
CPlayerCL::getAttackerPos(double ang
, double dist
) const
1301 // Compute the local angle
1302 ang
= computeShortestAngle(atan2(front().y
, front().x
), ang
);
1307 // Compute the local position.
1309 p
.x
= 0.5 * sin(-ang
) + dist
*sin(-ang
); // or: pos.x = _Sheet->DistToSide*cos(ang) + dist*cos(ang); but 0 should be right side.
1310 p
.y
= 0.5 * cos(ang
) + dist
*cos(ang
);
1313 // Compute the world position.
1314 // Create the target matrix.
1315 CVector vj
= front();
1320 bodyBase
.setRot(vi
,vj
,vk
,true);
1321 bodyBase
.setPos(pos());
1323 // Get the destination in the world.
1324 return bodyBase
* p
;
1325 }// getAttackerPos //
1331 //-----------------------------------------------
1332 // updateAsyncTexture
1333 //-----------------------------------------------
1334 float CPlayerCL::updateAsyncTexture()
1337 float distToCam
= CCharacterCL::updateAsyncTexture();
1339 // Check all instance to know if they need to start async load their textures
1340 if(!_Face
.Loading
.empty())
1343 if(_Face
.Loading
.isAsyncTextureDirty())
1345 // reset instance state.
1346 _Face
.Loading
.setAsyncTextureDirty(false);
1347 // must start loading for this isntance
1348 _Face
.Loading
.startAsyncTextureLoading();
1349 // the entity is now currently loading.
1350 _PlayerCLAsyncTextureLoading
= true;
1351 // The LodTexture need to be recomputed
1352 _LodTextureDirty
= true;
1357 // Update Async Texture loading of all instances.
1358 if(_PlayerCLAsyncTextureLoading
)
1360 bool allLoaded
= true;
1361 // update loading for all instances.
1362 if(!_Face
.Loading
.empty())
1364 // update async texture loading
1365 allLoaded
= allLoaded
&& _Face
.Loading
.isAsyncTextureReady();
1368 // if all are loaded, then End! don't need to check all instances every frame.
1371 _PlayerCLAsyncTextureLoading
= false;
1372 _Face
.updateCurrentFromLoading(_Skeleton
);
1377 // For LOD texture, must update the "texture distance"
1378 if(!_Face
.Current
.empty())
1380 // update async texture loading
1381 _Face
.Current
.setAsyncTextureDistance(distToCam
);
1387 //-----------------------------------------------
1389 //-----------------------------------------------
1390 void CPlayerCL::updateLodTexture()
1392 // if need to recompute, and if Async loading ended
1393 if( _LodTextureDirty
&& !_PlayerCLAsyncTextureLoading
)
1394 // check parent and upadte lod
1395 CCharacterCL::updateLodTexture();
1398 //-----------------------------------------------
1400 // Return the basic max speed for the entity in meter per sec
1401 //-----------------------------------------------
1402 double CPlayerCL::getMaxSpeed() const// virtual
1409 //---------------------------------------------------
1411 // Display Debug Information.
1412 //---------------------------------------------------
1413 void CPlayerCL::displayDebug(float x
, float &y
, float lineStep
) // virtual
1415 CCharacterCL::displayDebug(x
, y
, lineStep
);
1423 //---------------------------------------------------
1425 // Read/Write Variables from/to the stream.
1426 //---------------------------------------------------
1427 void CPlayerCL::readWrite(NLMISC::IStream
&f
)
1429 CCharacterCL::readWrite(f
);
1434 // const CPlayerSheet *_Sheet;
1435 // const CRaceStatsSheet *_PlayerSheet;
1436 // NL3D::UInstance _Face;
1437 f
.serial(_DefaultChest
);
1438 f
.serial(_DefaultLegs
);
1439 f
.serial(_DefaultArms
);
1440 f
.serial(_DefaultHands
);
1441 f
.serial(_DefaultFeet
);
1442 f
.serial(_DefaultHair
);
1443 f
.serial(_HairColor
);
1444 f
.serial(_EyesColor
);
1445 f
.serial(_WaitForAppearance
);
1446 f
.serial(_PlayerCLAsyncTextureLoading
);
1448 // NL3D::UPointLight _Light;
1453 //---------------------------------------------------
1455 // To call after a read from a stream to re-initialize the entity.
1456 //---------------------------------------------------
1457 void CPlayerCL::load() // virtual
1459 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
1461 // If the entity should be in the world already
1462 if(_First_Pos
== false)
1464 // Insert the primitive into the world.
1466 _Primitive
->insertInWorldImage(dynamicWI
);
1467 // Insert the entity into PACS
1472 if(!_WaitForAppearance
)
1474 // Visual properties A
1475 sint64 prop
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->getValue64();
1476 updateVisualPropertyVpa(0, prop
); // Vpa udapte vpb and vpc too.
1480 // *********************************************************************************************
1481 const char *CPlayerCL::getBoneNameFromBodyPart(BODY::TBodyPart part
, BODY::TSide side
) const
1483 if (!_PlayerSheet
) return CCharacterCL::getBoneNameFromBodyPart(part
, side
);
1484 return _PlayerSheet
->BodyToBone
.getBoneName(part
, side
);
1487 // *********************************************************************************************
1488 const CItemSheet
*CPlayerCL::getRightHandItemSheet() const
1490 return _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
1493 // *********************************************************************************************
1494 const CItemSheet
*CPlayerCL::getLeftHandItemSheet() const
1496 return _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
1499 // *********************************************************************************************
1500 const CAttack
*CPlayerCL::getAttack(const CAttackIDSheet
&id
) const
1502 if (!_PlayerSheet
) return NULL
;
1503 return CCharacterCL::getAttack(id
, _PlayerSheet
->AttackLists
);
1506 // *********************************************************************************************
1507 float CPlayerCL::getScaleRef() const
1509 float fyrosRefScale
= GabaritSet
.getRefHeightScale(0, EGSPD::CPeople::Fyros
);
1510 if (fyrosRefScale
== 0) return 1.f
;
1511 return _CustomScalePos
* (GabaritSet
.getRefHeightScale(_Gender
, people()) / fyrosRefScale
);
1515 // *********************************************************************************************
1516 float CPlayerCL::getNamePosZ() const
1522 switch (_ModeWanted
)
1526 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZLow
;
1529 case MBEHAV::MOUNT_NORMAL
:
1530 case MBEHAV::MOUNT_SWIM
:
1531 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZHigh
;
1535 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZNormal
;
1539 return namePosZ
* _CharacterScalePos
* _CustomScalePos
;
1542 // ***************************************************************************
1543 void CPlayerCL::doSetVisualSelectionBlink(bool bOnOff
, NLMISC::CRGBA emitColor
)
1547 _Face
.setEmissive(emitColor
);
1549 _Face
.restoreEmissive();
1552 CCharacterCL::doSetVisualSelectionBlink(bOnOff
, emitColor
);
1557 //-----------------------------------------------
1558 // computePrimitive :
1559 // Create (or re-create) a primitive.
1560 //-----------------------------------------------
1561 void CPlayerCL::computePrimitive()
1563 // Initialize the primitive.
1564 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
1566 _Primitive
->insertInWorldImage(dynamicWI
);
1567 // Set the position.
1569 }// computePrimitive //