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"
65 using namespace NLMISC
;
67 using namespace NLPACS
;
75 extern CEntityAnimationManager
*EAM
;
76 extern UTextContext
*TextContext
;
77 extern UCamera MainCam
;
80 //-----------------------------------------------
83 //-----------------------------------------------
84 CPlayerCL::CPlayerCL()
89 // Resize _Instances to the number of visual slots.
90 _Instances
.resize(SLOTTYPE::NB_SLOT
);
96 // Some default colors.
100 // Not enough information to display the player.
101 _WaitForAppearance
= true;
103 _PlayerCLAsyncTextureLoading
= false;
105 // Light Off and not allocated
110 //-----------------------------------------------
113 //-----------------------------------------------
114 CPlayerCL::~CPlayerCL()
116 // No more sheet pointed.
123 Scene
->deletePointLight(_Light
);
127 //---------------------------------------------------
129 // Return the entity scale. (return 1.0 if there is any problem).
130 //---------------------------------------------------
131 float CPlayerCL::getScale() const // virtual
134 return _CharacterScalePos
;
139 //-----------------------------------------------
141 // retrieve ground fxs for the entity depending on the ground
142 //-----------------------------------------------
143 const std::vector
<CGroundFXSheet
> *CPlayerCL::getGroundFX() const
147 case 0: return &(_PlayerSheet
->GenderInfos
[0].GroundFX
);
148 case 1: return &(_PlayerSheet
->GenderInfos
[1].GroundFX
);
155 //-----------------------------------------------
157 // Return true if this entity is a neutral entity(pvp or not)
158 //-----------------------------------------------
159 bool CPlayerCL::isNeutral() const
161 return (!isEnemy() && !isAlly());
165 //-----------------------------------------------
167 // Return true if this entity is a user's friend.
168 //-----------------------------------------------
169 bool CPlayerCL::isFriend () const
171 return isNeutral() || isAlly();
175 //-----------------------------------------------
177 // true if at least enemy in on pvp mode
178 //-----------------------------------------------
179 bool CPlayerCL::isEnemy () const
181 // Challenge i.e. SOLO FULL PVP
182 if( getPvpMode()&PVP_MODE::PvpChallenge
||
183 UserEntity
->getPvpMode()&PVP_MODE::PvpChallenge
)
189 // if one of 2 players is not in pvp they can't be enemies
190 if( UserEntity
->getPvpMode() == PVP_MODE::None
||
191 getPvpMode() == PVP_MODE::None
)
196 // if one of 2 players is safe they can't be enemies
197 if( UserEntity
->getPvpMode()&PVP_MODE::PvpSafe
||
198 getPvpMode()&PVP_MODE::PvpSafe
)
203 // if one of 2 players are in safe zone and not flagged they can't be enemies
204 if ((UserEntity
->getPvpMode()&PVP_MODE::PvpZoneSafe
&&
205 ((UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
) == 0))
207 (getPvpMode()&PVP_MODE::PvpZoneSafe
&&
208 ((getPvpMode()&PVP_MODE::PvpFactionFlagged
) == 0)))
214 if( getPvpMode()&PVP_MODE::PvpDuel
&&
215 UserEntity
->getPvpMode()&PVP_MODE::PvpDuel
)
221 if ( isAnOutpostEnemy() )
227 if( getPvpMode()&PVP_MODE::PvpZoneFree
&&
228 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFree
)
230 // If not in same Team and not in same League => ennemy
231 if( !isInTeam() && !isInSameLeague() )
236 if( getPvpMode()&PVP_MODE::PvpZoneGuild
&&
237 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneGuild
)
239 // If in same Guild but different Leagues => ennemy
240 if ( isInSameGuild() && oneInLeague() && !isInSameLeague() )
243 if( !isInTeam() && !isInSameLeague() )
248 if( getPvpMode()&PVP_MODE::PvpZoneFaction
&&
249 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFaction
)
251 if (getPvpClan() != UserEntity
->getPvpClan())
255 // Free PVP : Ennemis are not in team AND not in league
256 if ((getPvpMode()&PVP_MODE::PvpFaction
|| getPvpMode()&PVP_MODE::PvpFactionFlagged
) &&
257 (UserEntity
->getPvpMode()&PVP_MODE::PvpFaction
|| UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
))
259 // If in same Guild but different Leagues => ennemy
260 if ( isInSameGuild() && oneInLeague() && !isInSameLeague() )
263 if (!isInTeam() && !isInSameLeague())
272 //-----------------------------------------------
274 // true if at least ally in one pvp mode
275 //-----------------------------------------------
276 bool CPlayerCL::isAlly() const
279 // Challenge i.e. SOLO FULL PVP
280 if( getPvpMode()&PVP_MODE::PvpChallenge
||
281 UserEntity
->getPvpMode()&PVP_MODE::PvpChallenge
)
286 // if one of 2 players is not in pvp they can't be allies
287 if( UserEntity
->getPvpMode() == PVP_MODE::None
||
288 getPvpMode() == PVP_MODE::None
)
293 // if one of 2 players is in safe zone and not other they can't be allies
294 if ((UserEntity
->getPvpMode()&PVP_MODE::PvpSafe
) != (getPvpMode()&PVP_MODE::PvpSafe
))
300 if ( isAnOutpostAlly() )
306 if( getPvpMode()&PVP_MODE::PvpZoneFree
&&
307 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFree
)
309 if( isInTeam() || isInSameLeague() )
314 if( getPvpMode()&PVP_MODE::PvpZoneGuild
&&
315 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneGuild
)
317 if( isInTeam() || isInSameLeague() )
320 if ( isInSameGuild() && !oneInLeague() )
326 if( getPvpMode()&PVP_MODE::PvpZoneFaction
&&
327 UserEntity
->getPvpMode()&PVP_MODE::PvpZoneFaction
)
329 if (getPvpClan() == UserEntity
->getPvpClan())
333 // Free PVP : Allies are in team OR in league
334 if ((getPvpMode()&PVP_MODE::PvpFaction
|| getPvpMode()&PVP_MODE::PvpFactionFlagged
) &&
335 (UserEntity
->getPvpMode()&PVP_MODE::PvpFaction
|| UserEntity
->getPvpMode()&PVP_MODE::PvpFactionFlagged
))
337 if (isInTeam() || isInSameLeague())
340 if ( isInSameGuild() && !oneInLeague() )
349 //-----------------------------------------------
351 //-----------------------------------------------
352 bool CPlayerCL::isNeutralPVP() const
354 // if player is not in pvp they can't be neutral pvp
355 if( getPvpMode() == PVP_MODE::None
)
360 if( UserEntity
->getPvpMode() == PVP_MODE::None
)
365 return (!isEnemy() && !isAlly());
369 //-----------------------------------------------
371 // Build the entity from a sheet.
372 //-----------------------------------------------
373 bool CPlayerCL::build(const CEntitySheet
*sheet
) // virtual
375 // Cast the sheet in the right type.
376 _PlayerSheet
= dynamic_cast<const CRaceStatsSheet
*>(sheet
);
379 pushDebugStr(NLMISC::toString("Player '%d' sheet is not a '.race_stats' -> BIG PROBLEM.", _Slot
));
383 pushInfoStr(NLMISC::toString("Player '%d' sheet is valid.", _Slot
));
385 if(IngameDbMngr
.getNodePtr())
387 CCDBNodeBranch
*nodeRoot
= dynamic_cast<CCDBNodeBranch
*>(IngameDbMngr
.getNodePtr()->getNode(0));
390 _DBEntry
= dynamic_cast<CCDBNodeBranch
*>(nodeRoot
->getNode(_Slot
));
392 pushDebugStr("Cannot get a pointer on the DB entry.");
396 // Compute the first automaton.
397 _CurrentAutomaton
= automatonType() + "_normal.automaton";
399 // Initialize the player look.
401 // Compute the primitive
402 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
403 // Create the collision entity (used to snap the entity to the ground).
404 computeCollisionEntity();
406 // Initialize properties of the client.
412 //-----------------------------------------------
414 // Return the automaton type of the entity (homin, creature, etc.)
415 //-----------------------------------------------
416 std::string
CPlayerCL::automatonType() const // virtual
418 return _PlayerSheet
->Automaton
;
422 //-----------------------------------------------
424 // Initialize the graphic for the player.
425 //-----------------------------------------------
426 void CPlayerCL::init3d()
429 // Initialize the internal time.
430 _LastFrameTime
= ((double)T1
) * 0.001;
434 //-----------------------------------------------
436 // Initialize properties of the entity (according to the class).
437 //-----------------------------------------------
438 void CPlayerCL::initProperties()
440 properties().selectable(true);
441 properties().attackable(false);
442 properties().givable(true);
443 properties().invitable(true);
444 properties().canExchangeItem(true);
445 }// initProperties //
448 //-----------------------------------------------
450 // Set the equipmenent worn.
451 //-----------------------------------------------
452 void CPlayerCL::equip(SLOTTYPE::EVisualSlot slot
, const std::string
&shapeName
, const CItemSheet
*item
, sint color
)
455 if(slot
== SLOTTYPE::HIDDEN_SLOT
|| slot
>= SLOTTYPE::NB_SLOT
)
457 nlwarning("CCharacterCL::equip : slot %d is not valid.", (uint
)slot
);
463 // If exactly the same than before -> return
465 if (!_Instances
[s
].Loading
.empty())
467 if ((_Instances
[s
].LoadingName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
470 else if (!_Instances
[s
].Current
.empty())
472 if ((_Instances
[s
].CurrentName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
476 // Attach to the skeleton.
478 if(!_Skeleton
.empty())
482 case SLOTTYPE::RIGHT_HAND_SLOT
:
483 if( item
&& item
->ItemType
!= ITEM_TYPE::MAGICIAN_STAFF
)
484 stickPoint
= "box_arme";
487 case SLOTTYPE::LEFT_HAND_SLOT
:
488 if(_Items
[slot
].Sheet
&& _Items
[slot
].Sheet
->getAnimSet()=="s")
489 stickPoint
= "Box_bouclier";
491 stickPoint
= "box_arme_gauche";
499 /* If the object is sticked (ie not a skin), decide to delete the Current instance. Why? because the animation
500 is changed according to the equipped item.
502 Hence, For example, if a sword would be changed for a gun, then the new gun animation would take place,
503 while Keeping the old sword shape. BAD.
505 if(!stickPoint
.empty())
506 _Instances
[s
].createLoading(string(), stickPoint
);
508 // Create the instance.
512 _Instances
[s
].createLoading(shapeName
, stickPoint
, color
);
514 _Instances
[s
].createLoading(shapeName
, stickPoint
, item
->MapVariant
);
517 _Instances
[s
].createLoading(shapeName
, stickPoint
);
519 // If shapeName is empty, only clear the slot
520 if(shapeName
.empty())
522 _Items
[slot
].release();
526 if(!_Instances
[s
].Loading
.empty())
528 _Instances
[s
].FXItemSheet
= item
;
530 _Items
[slot
].initFXs(slot
, _Instances
[s
].Loading
);
533 nlwarning("PL::equip(1):%d: cannot create the instance '%s'.", _Slot
, shapeName
.c_str());
535 if (!item
&& (slot
!= SLOTTYPE::RIGHT_HAND_SLOT
) && (slot
!= SLOTTYPE::LEFT_HAND_SLOT
))
536 applyColorSlot(_Instances
[s
], skin(), 6, _HairColor
, _EyesColor
);
540 //-----------------------------------------------
542 // Compute the equipmenent worn.
543 //-----------------------------------------------
544 void CPlayerCL::equip(SLOTTYPE::EVisualSlot slot
, uint index
, uint color
)
546 // Get the sheet according to the visual slot
547 _Items
[slot
].Sheet
= SheetMngr
.getItem(slot
, index
);
548 if(_Items
[slot
].Sheet
)
550 const CItemSheet
*item
= _Items
[slot
].Sheet
;
552 std::string shapeName
= "";
553 if(_Gender
== GSGENDER::male
)
555 switch(_PlayerSheet
->People
)
557 case EGSPD::CPeople::Fyros
:
558 shapeName
= item
->getShapeFyros();
560 case EGSPD::CPeople::Matis
:
561 shapeName
= item
->getShapeMatis();
563 case EGSPD::CPeople::Tryker
:
564 shapeName
= item
->getShapeTryker();
566 case EGSPD::CPeople::Zorai
:
567 shapeName
= item
->getShapeZorai();
573 switch(_PlayerSheet
->People
)
575 case EGSPD::CPeople::Fyros
:
576 shapeName
= item
->getShapeFyrosFemale();
578 case EGSPD::CPeople::Matis
:
579 shapeName
= item
->getShapeMatisFemale();
581 case EGSPD::CPeople::Tryker
:
582 shapeName
= item
->getShapeTrykerFemale();
584 case EGSPD::CPeople::Zorai
:
585 shapeName
= item
->getShapeZoraiFemale();
588 if (shapeName
.empty())
589 shapeName
= item
->getShapeFemale();
591 if (shapeName
.empty())
592 shapeName
= item
->getShape();
595 // use the right type of boots if wearing a caster dress
596 if ((slot
== SLOTTYPE::FEET_SLOT
) && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
|| item
->ItemType
== ITEM_TYPE::MEDIUM_BOOTS
|| item
->ItemType
== ITEM_TYPE::HEAVY_BOOTS
))
598 std::string shapeLegs
;
600 if (!_Instances
[SLOTTYPE::LEGS_SLOT
].Loading
.empty())
602 shapeLegs
= _Instances
[SLOTTYPE::LEGS_SLOT
].LoadingName
;
604 else if (!_Instances
[SLOTTYPE::LEGS_SLOT
].Current
.empty())
606 shapeLegs
= _Instances
[SLOTTYPE::LEGS_SLOT
].CurrentName
;
609 if (!shapeLegs
.empty() && shapeLegs
.find("_caster01_") != std::string::npos
)
611 std::string tmpName
= toLowerAscii(shapeName
);
613 std::string::size_type posBottes
= tmpName
.find("_bottes");
615 if (posBottes
!= std::string::npos
)
617 std::string orgType
= tmpName
.substr(7, posBottes
-7); // underwear, caster01, armor00 or armor01
619 tmpName
.replace(posBottes
+7, 0, "_" + orgType
);
620 tmpName
.replace(7, orgType
.length(), "caster01");
622 if (CPath::exists(tmpName
))
624 // use fixed shape name only if file is present
629 // temporary hack because Fyros light boots don't respect conventions
630 if (tmpName
[0] == 'f' && (item
->ItemType
== ITEM_TYPE::LIGHT_BOOTS
))
632 if (tmpName
[5] == 'f')
634 tmpName
= "fy_hof_caster01_bottes_civil.shape";
638 tmpName
= "fy_hom_caster01_civil01_bottes.shape";
641 // use fixed shape name only if file is present
642 if (CPath::exists(tmpName
))
648 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), shapeName
.c_str());
653 nlwarning("File %s doesn't exist, use %s", tmpName
.c_str(), shapeName
.c_str());
660 // If the gender is a female get the right shape else get the default shape.
661 equip(slot
, shapeName
, item
);
663 // Check there is a shape.
664 UInstance pInst
= _Instances
[slot
].createLoadingFromCurrent();
667 // Set the right texture variation (quality).
668 pInst
.selectTextureSet((uint
)item
->MapVariant
);
669 _Instances
[slot
].TextureSet
= item
->MapVariant
;
671 // If Hair, color is for the head slot.
672 if(slot
== SLOTTYPE::HEAD_SLOT
&& item
->Family
!= ITEMFAMILY::ARMOR
)
673 applyColorSlot(_Instances
[slot
], skin(), 0, color
, _EyesColor
);
676 // Set the User Color.
677 if(item
->Color
== -1)
678 applyColorSlot(_Instances
[slot
], skin(), color
, _HairColor
, _EyesColor
);
679 // Set the Item Color.
680 else if(item
->Color
!= -2)
681 applyColorSlot(_Instances
[slot
], skin(), item
->Color
, _HairColor
, _EyesColor
);
682 // Else let the default color.
684 applyColorSlot(_Instances
[slot
], skin(), 0, _HairColor
, _EyesColor
);
688 // Default equipment.
691 nldebug("PL:equip(2):%d: VS '%d' default equipement used.", _Slot
, slot
);
692 sint idx
= SheetMngr
.getVSIndex(_PlayerSheet
->GenderInfos
[_Gender
].Items
[slot
], slot
);
695 if(SheetMngr
.getItem(slot
, (uint
)idx
))
697 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
699 // If the gender is a female get the right shape else get the default shape.
700 equip(slot
, _Gender
== GSGENDER::female
? itemSheet
->getShapeFemale():itemSheet
->getShape());
706 //-----------------------------------------------
708 // Compute the animation set to use according to weapons, mode and race.
709 //-----------------------------------------------
710 void CPlayerCL::computeAnimSet()
712 // We need a valid Gender to compute the animset.
715 nlwarning("PL:computeAnimSet:%d: not a male or a female (gender=%d).", _Slot
, _Gender
);
719 // Now computing the animset.
720 // Do not count weapons if swimming.
721 if(!::computeAnimSet(_CurrentAnimSet
[MOVE
], _Mode
, _PlayerSheet
->GenderInfos
[_Gender
].AnimSetBaseName
, _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
, !modeWithHiddenItems()))
722 nlwarning("PL:computeAnimSet:%d: pb when computing the animset.", _Slot
);
724 }// computeAnimSet //
727 //-----------------------------------------------
728 // updateVisualPropertyVpa :
729 // Update the Visual Property A.
730 // \todo GUIGUI : use gender enum
731 //-----------------------------------------------
732 void CPlayerCL::updateVisualPropertyVpa(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
734 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
736 // Player will now have enough information to display the character.
737 _WaitForAppearance
= false;
740 SPropVisualA visualA
= *(SPropVisualA
*)(&prop
);
743 _Gender
= (GSGENDER::EGender
)(visualA
.PropertySubData
.Sex
);
744 if(_Gender
!=GSGENDER::male
&& _Gender
!=GSGENDER::female
)
746 nlwarning("PL::updateVPVpa:%d: neither a male nor a female -> male selected.", _Slot
);
747 _Gender
= GSGENDER::male
;
750 // update title when gender changed
751 const string replacement
= STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
, _Gender
== GSGENDER::female
);
752 if (!replacement
.empty() || !ClientCfg
.DebugStringManager
)
755 _NameEx
= replacement
;
756 _Title
= replacement
;
758 // display the new title in player interface
761 CViewText
*pVT
= dynamic_cast<CViewText
*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:player:header_opened:player_title"));
762 if (pVT
!= NULL
) pVT
->setText(_Title
);
765 // rebuild in scene interface
766 buildInSceneInterface();
769 // Setup _CharacterScalePos
770 _CharacterScalePos
= _PlayerSheet
->GenderInfos
[_Gender
].CharacterScalePos
;
772 // Check if skeleton has changed
773 if (_CacheSkeletonShapeName
!= _PlayerSheet
->GenderInfos
[_Gender
].Skelfilename
)
775 _CacheSkeletonShapeName
= _PlayerSheet
->GenderInfos
[_Gender
].Skelfilename
;
777 // Clean the playlist.
779 _PlayList
->resetAllChannels();
781 // We can now build the skeleton so do it now.
782 skeleton(_CacheSkeletonShapeName
);
784 // Invalidate instances cache
785 for (uint i
= 0; i
< _Instances
.size(); ++i
)
787 _Instances
[i
].CurrentName
.clear();
788 _Instances
[i
].LoadingName
.clear();
790 _Face
.CurrentName
.clear();
791 _Face
.LoadingName
.clear();
793 // Check the skeleton.
794 if(skeleton() && !ClientCfg
.Light
)
796 // To re-link the skeleton to the mount if needed.
798 // Set the skeleton scale.
799 // \todo GUIGUI: put scale too in race_stats.
800 // Setup Lod Character skeleton, if skeleton exist
801 // Get Lod Character Id from the sheet.
802 sint clodId
= getLodCharacterId(*Scene
, _PlayerSheet
->GenderInfos
[_Gender
].LodCharacterName
);
805 // Setup Lod Character shape and distance
806 skeleton()->setLodCharacterShape(clodId
);
807 skeleton()->setLodCharacterDistance(_PlayerSheet
->GenderInfos
[_Gender
].LodCharacterDistance
);
813 equip(SLOTTYPE::CHEST_SLOT
, visualA
.PropertySubData
.JacketModel
, visualA
.PropertySubData
.JacketColor
);
815 equip(SLOTTYPE::LEGS_SLOT
, visualA
.PropertySubData
.TrouserModel
, visualA
.PropertySubData
.TrouserColor
);
817 equip(SLOTTYPE::ARMS_SLOT
, visualA
.PropertySubData
.ArmModel
, visualA
.PropertySubData
.ArmColor
);
819 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
820 // OBJECT in the RIGHT HAND
821 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
822 // Equip the weapon(object/tool).
823 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
825 if(_Gender
== GSGENDER::female
)
826 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShapeFemale(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
828 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
830 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
831 if (!itemInstance
.empty())
834 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
835 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
836 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(0);
837 //_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(visualA.PropertySubData.RTrail);
842 // No Valid item in the right hand.
844 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::RIGHT_HAND_SLOT
;
845 string rightHandTag
= getTag(5);
846 if (!rightHandTag
.empty() && rightHandTag
!= "_")
848 sint idx
= SheetMngr
.getVSIndex("stake.sitem", slot
);
849 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
850 vector
<string
> tagInfos
;
851 splitString(rightHandTag
, string("|"), tagInfos
);
854 // Manage cache of items
855 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
858 fromString(tagInfos
[0].substr(1), itemNameId
);
859 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
862 if (tagInfos
.size() == 2)
865 fromString(tagInfos
[1], instTexture
);
866 equip(slot
, tagInfos
[0], itemSheet
);
867 UInstance pInst
= _Instances
[slot
].createLoadingFromCurrent();
869 pInst
.selectTextureSet(instTexture
);
870 _Instances
[slot
].TextureSet
= instTexture
;
874 equip(slot
, tagInfos
[0], itemSheet
);
883 // OBJECT in the LEFT HAND
884 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
885 // Equip the weapon(object/tool).
886 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
888 equip(SLOTTYPE::LEFT_HAND_SLOT
, _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
);
889 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
890 if (!itemInstance
.empty())
893 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
894 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(0);
895 //_Items[SLOTTYPE::LEFT_HAND_SLOT].setTrailSize(2 * (uint) visualA.PropertySubData.LTrail);
900 // No Valid item in the left hand.
901 equip(SLOTTYPE::LEFT_HAND_SLOT
, "");
902 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::LEFT_HAND_SLOT
;
903 string leftHandTag
= getTag(6);
904 if (!leftHandTag
.empty() && leftHandTag
!= "_")
906 vector
<string
> tagInfos
;
907 splitString(leftHandTag
, string("|"), tagInfos
);
910 // Manage cache of items
911 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
914 fromString(tagInfos
[0].substr(1), itemNameId
);
915 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
919 if (tagInfos
.size() == 3 && tagInfos
[2] == ")")
920 idx
= SheetMngr
.getVSIndex("icbss_pvp.sitem", slot
);
922 idx
= SheetMngr
.getVSIndex("icfm1pd.sitem", slot
);
924 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
926 if (tagInfos
.size() >= 2)
929 fromString(tagInfos
[1], instTexture
);
930 equip(slot
, tagInfos
[0], itemSheet
);
931 _Instances
[slot
].selectTextureSet(instTexture
);
932 _Instances
[slot
].TextureSet
= instTexture
;
936 equip(slot
, tagInfos
[0], itemSheet
);
945 // Only create a face when there is no Helmet
946 if(_Items
[SLOTTYPE::HEAD_SLOT
].Sheet
== 0 || _Items
[SLOTTYPE::HEAD_SLOT
].Sheet
->Family
!= ITEMFAMILY::ARMOR
)
948 CItemSheet
*faceItem
= getItem(_PlayerSheet
->GenderInfos
[_Gender
], SLOTTYPE::FACE_SLOT
);
953 if(_Gender
== GSGENDER::female
)
954 sFaceName
= faceItem
->getShapeFemale();
956 sFaceName
= faceItem
->getShape();
958 if (((!_Face
.Loading
.empty()) && (_Face
.LoadingName
!= sFaceName
)) ||
959 ((!_Face
.Current
.empty()) && (_Face
.CurrentName
!= sFaceName
)) ||
960 (_Face
.Current
.empty()))
962 if (!_Face
.Loading
.empty())
964 Scene
->deleteInstance(_Face
.Loading
);
965 _Face
.Loading
= NULL
;
966 _Face
.LoadingName
= sFaceName
;
968 _Face
.Loading
= Scene
->createInstance(sFaceName
);
969 if (!_Face
.Loading
.empty())
971 _Face
.LoadingName
= sFaceName
;
972 if(!skeleton()->bindSkin(_Face
.Loading
))
973 nlwarning("PL::updateVPVpa:%d: Cannot bind the face.", _Slot
);
974 _Face
.Loading
.hide();
975 // set it async for texture
976 _Face
.Loading
.enableAsyncTextureMode(true);
979 nlwarning("PL::updateVPVpa:%d: Cannot create the face.", _Slot
);
981 _Face
.TextureSet
= faceItem
->MapVariant
;
982 applyColorSlot(_Face
, skin(), 0, visualA
.PropertySubData
.HatColor
, 0); // Set a default ruflaket color.
985 nlwarning("PL::updateVPVpa:%d: Face Item '%s' does not exist.", _Slot
,
986 _PlayerSheet
->GenderInfos
[_Gender
].Items
[SLOTTYPE::FACE_SLOT
].c_str());
988 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
990 SLOTTYPE::EVisualSlot slot
= SLOTTYPE::HEAD_SLOT
;
991 string hatTag
= getTag(7);
992 if (!hatTag
.empty() && hatTag
!= "_")
994 sint idx
= SheetMngr
.getVSIndex("eroukan_h.sitem", slot
);
995 const CItemSheet
*itemSheet
= SheetMngr
.getItem(slot
, (uint
)idx
);
996 vector
<string
> tagInfos
;
997 splitString(hatTag
, string("|"), tagInfos
);
1000 // Manage cache of items
1001 if (!tagInfos
[0].empty() && tagInfos
[0][0] == '#')
1004 fromString(tagInfos
[0].substr(1), itemNameId
);
1005 tagInfos
[0] = SheetMngr
.getRpItem(itemNameId
);
1008 if (tagInfos
.size() == 2)
1011 fromString(tagInfos
[1], instTexture
);
1012 equip(slot
, tagInfos
[0], itemSheet
);
1013 _Instances
[slot
].selectTextureSet(instTexture
);
1014 _Instances
[slot
].TextureSet
= instTexture
;
1018 equip(slot
, tagInfos
[0], itemSheet
);
1026 // There is a helmet !
1027 if (!_Face
.Loading
.empty())
1028 Scene
->deleteInstance(_Face
.Loading
);
1029 _Face
.Loading
= NULL
;
1030 _Face
.LoadingName
.clear();
1031 if (!_Face
.Current
.empty())
1032 Scene
->deleteInstance(_Face
.Current
);
1033 _Face
.Current
= NULL
;
1034 _Face
.CurrentName
.clear();
1036 // Now we have a skeleton, we can update VpB and VpC.
1039 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPB
);
1040 vB
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
1041 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPC
);
1042 vC
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
1043 updateVisualPropertyVpb(0, vB
);
1044 updateVisualPropertyVpc(0, vC
);
1046 // Attach The Light if there is one.
1047 if(!_Light
.empty() && _NameBoneId
!=-1)
1048 _Skeleton
.stickObject(_Light
, _NameBoneId
);
1050 // Compute the new animation set to use (due to weapons).
1053 // Set the animation to idle.
1054 setAnim(CAnimationStateSheet::Idle
);
1058 nlwarning("PL::updateVPVpa:%d: Skeleton not allocated.", _Slot
);
1059 }// updateVisualPropertyVpa //
1061 //-----------------------------------------------
1062 // updateVisualPropertyVpb :
1063 // Update the Visual Property B.
1064 //-----------------------------------------------
1065 void CPlayerCL::updateVisualPropertyVpb(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
1067 // Get the property.
1068 SPropVisualB visualB
= *(SPropVisualB
*)(&prop
);
1070 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
1072 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
1073 if (!itemInstance
.empty())
1076 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
1077 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(visualB
.PropertySubData
.RTrail
);
1081 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
1083 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
1084 if (!itemInstance
.empty())
1087 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(2 * (uint
) visualB
.PropertySubData
.LTrail
);
1094 equip(SLOTTYPE::HANDS_SLOT
, visualB
.PropertySubData
.HandsModel
, visualB
.PropertySubData
.HandsColor
);
1096 equip(SLOTTYPE::FEET_SLOT
, visualB
.PropertySubData
.FeetModel
, visualB
.PropertySubData
.FeetColor
);
1099 nlinfo("PL::updateVPVpb:%d: Prop Vpb received before prop Vpa.", _Slot
);
1100 }// updateVisualPropertyVpb //
1102 //-----------------------------------------------
1103 // updateVisualPropertyVpc :
1104 // Update the Visual Property C.
1105 // \todo GUIGUI : factorize tatoos with character creation
1106 //-----------------------------------------------
1107 void CPlayerCL::updateVisualPropertyVpc(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
1111 // Get the property.
1112 SPropVisualC visualC
= *(SPropVisualC
*)(&prop
);
1115 _EyesColor
= visualC
.PropertySubData
.EyesColor
;
1118 // must recreate the face asynchronously (because of color change / makeup change)
1119 inst
= _Face
.createLoadingFromCurrent();
1124 // change eyes color only
1125 applyColorSlot(_Face
, _Face
.ACSkin
, _Face
.ACUser
, _Face
.ACHair
, visualC
.PropertySubData
.EyesColor
);
1128 makeUp(inst
, visualC
.PropertySubData
.Tattoo
);
1131 static const char *baseName
= "visage_00";
1134 const CGenderInfo
*pGI
= &_PlayerSheet
->GenderInfos
[_Gender
];
1138 MTmin
= pGI
->BlendShapeMin
[0];
1139 MTmax
= pGI
->BlendShapeMax
[0];
1140 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1141 inst
.setBlendShapeFactor(baseName
+ toString(0), (float)(visualC
.PropertySubData
.MorphTarget1
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1143 MTmin
= pGI
->BlendShapeMin
[1];
1144 MTmax
= pGI
->BlendShapeMax
[1];
1145 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1146 inst
.setBlendShapeFactor(baseName
+ toString(1), (float)(visualC
.PropertySubData
.MorphTarget2
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1148 MTmin
= pGI
->BlendShapeMin
[2];
1149 MTmax
= pGI
->BlendShapeMax
[2];
1150 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1151 inst
.setBlendShapeFactor(baseName
+ toString(2), (float)(visualC
.PropertySubData
.MorphTarget3
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1153 MTmin
= pGI
->BlendShapeMin
[3];
1154 MTmax
= pGI
->BlendShapeMax
[3];
1155 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1156 inst
.setBlendShapeFactor(baseName
+ toString(3), (float)(visualC
.PropertySubData
.MorphTarget4
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1158 MTmin
= pGI
->BlendShapeMin
[4];
1159 MTmax
= pGI
->BlendShapeMax
[4];
1160 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1161 inst
.setBlendShapeFactor(baseName
+ toString(4), (float)(visualC
.PropertySubData
.MorphTarget5
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1163 MTmin
= pGI
->BlendShapeMin
[5];
1164 MTmax
= pGI
->BlendShapeMax
[5];
1165 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1166 inst
.setBlendShapeFactor(baseName
+ toString(5), (float)(visualC
.PropertySubData
.MorphTarget6
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1168 MTmin
= pGI
->BlendShapeMin
[6];
1169 MTmax
= pGI
->BlendShapeMax
[6];
1170 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1171 inst
.setBlendShapeFactor(baseName
+ toString(6), (float)(visualC
.PropertySubData
.MorphTarget7
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1173 MTmin
= pGI
->BlendShapeMin
[7];
1174 MTmax
= pGI
->BlendShapeMax
[7];
1175 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
1176 inst
.setBlendShapeFactor(baseName
+ toString(7), (float)(visualC
.PropertySubData
.MorphTarget8
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
1180 float characterHeight
= (float)((sint8
)(visualC
.PropertySubData
.CharacterHeight
)-7)/7.f
;
1181 float torsoWidth
= (float)((sint8
)(visualC
.PropertySubData
.TorsoWidth
)-7)/7.f
;
1182 float armsWidth
= (float)((sint8
)(visualC
.PropertySubData
.ArmsWidth
)-7)/7.f
;
1183 float legsWidth
= (float)((sint8
)(visualC
.PropertySubData
.LegsWidth
)-7)/7.f
;
1184 float breastSize
= (float)((sint8
)(visualC
.PropertySubData
.BreastSize
)-7)/7.f
;
1185 float heightScale
, baseHeightScale
;
1186 // TODO : manage breast size
1187 GabaritSet
.applyGabarit(*skeleton(), _Gender
, people(), characterHeight
, torsoWidth
, armsWidth
, legsWidth
, breastSize
, &heightScale
);
1188 baseHeightScale
= GabaritSet
.getRefHeightScale(_Gender
, people());
1190 if(baseHeightScale
!= 0.f
)
1191 _CustomScalePos
= heightScale
/baseHeightScale
;
1194 _CustomScalePos
= 1.f
;
1195 nlwarning("PL::updateVPVpc:'%d': baseHeight == 0.", _Slot
);
1199 nlinfo("PL:updateVPVpc:'%d': Prop Vpc received before prop Vpa.", _Slot
);
1200 }// updateVisualPropertyVpc //
1202 //-----------------------------------------------
1203 //-----------------------------------------------
1204 void CPlayerCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle
&gameCycle
, const sint64
&prop
)
1206 CCharacterCL::updateVisualPropertyPvpMode(gameCycle
, prop
);
1207 // Additionaly, if i am the target, inform interface of the change
1210 CInterfaceManager
*pIM
= CInterfaceManager::getInstance();
1211 CCDBNodeLeaf
*pDB
= NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:USER:TRACK_TARGET_PVP_CHANGE_MODE");
1214 sint32 val
= pDB
->getValue32();
1215 pDB
->setValue32(val
+1);
1221 //-----------------------------------------------
1223 // Get The Entity Skin
1224 //-----------------------------------------------
1225 sint
CPlayerCL::skin() const // virtual
1227 return _PlayerSheet
->Skin
;
1230 //-----------------------------------------------
1232 // Return the People for the entity.
1233 //-----------------------------------------------
1234 EGSPD::CPeople::TPeople
CPlayerCL::people() const// virtual
1237 return _PlayerSheet
->People
;
1239 return EGSPD::CPeople::Unknown
;
1242 //-----------------------------------------------
1244 // Setup the People for the entity.
1245 //-----------------------------------------------
1246 void CPlayerCL::setPeople(EGSPD::CPeople::TPeople
/* people */)
1250 //-----------------------------------------------
1253 //-----------------------------------------------
1254 void CPlayerCL::drawName(const NLMISC::CMatrix
&mat
) // virtual
1257 if(!getEntityName().empty())
1258 TextContext
->render3D(mat
, getEntityName());
1262 //-----------------------------------------------
1264 // Update eyes blink. For the moment, called by updatePos.
1265 //-----------------------------------------------
1266 CEntityCL::SInstanceCL
*CPlayerCL::getFace()
1268 // Implemented in CPlayerCL
1272 //-----------------------------------------------
1274 // Method to return the attack radius of an entity (take the scale into account).
1275 //-----------------------------------------------
1276 double CPlayerCL::attackRadius() const // virtual
1281 //-----------------------------------------------
1282 // Return the position the attacker should have to combat according to the attack angle.
1283 // \param ang : 0 = the front, >0 and <Pi = left side, <0 and >-Pi = right side.
1284 //-----------------------------------------------
1285 CVectorD
CPlayerCL::getAttackerPos(double ang
, double dist
) const
1287 // Compute the local angle
1288 ang
= computeShortestAngle(atan2(front().y
, front().x
), ang
);
1293 // Compute the local position.
1295 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.
1296 p
.y
= 0.5 * cos(ang
) + dist
*cos(ang
);
1299 // Compute the world position.
1300 // Create the target matrix.
1301 CVector vj
= front();
1306 bodyBase
.setRot(vi
,vj
,vk
,true);
1307 bodyBase
.setPos(pos());
1309 // Get the destination in the world.
1310 return bodyBase
* p
;
1311 }// getAttackerPos //
1317 //-----------------------------------------------
1318 // updateAsyncTexture
1319 //-----------------------------------------------
1320 float CPlayerCL::updateAsyncTexture()
1323 float distToCam
= CCharacterCL::updateAsyncTexture();
1325 // Check all instance to know if they need to start async load their textures
1326 if(!_Face
.Loading
.empty())
1329 if(_Face
.Loading
.isAsyncTextureDirty())
1331 // reset instance state.
1332 _Face
.Loading
.setAsyncTextureDirty(false);
1333 // must start loading for this isntance
1334 _Face
.Loading
.startAsyncTextureLoading();
1335 // the entity is now currently loading.
1336 _PlayerCLAsyncTextureLoading
= true;
1337 // The LodTexture need to be recomputed
1338 _LodTextureDirty
= true;
1343 // Update Async Texture loading of all instances.
1344 if(_PlayerCLAsyncTextureLoading
)
1346 bool allLoaded
= true;
1347 // update loading for all instances.
1348 if(!_Face
.Loading
.empty())
1350 // update async texture loading
1351 allLoaded
= allLoaded
&& _Face
.Loading
.isAsyncTextureReady();
1354 // if all are loaded, then End! don't need to check all instances every frame.
1357 _PlayerCLAsyncTextureLoading
= false;
1358 _Face
.updateCurrentFromLoading(_Skeleton
);
1363 // For LOD texture, must update the "texture distance"
1364 if(!_Face
.Current
.empty())
1366 // update async texture loading
1367 _Face
.Current
.setAsyncTextureDistance(distToCam
);
1373 //-----------------------------------------------
1375 //-----------------------------------------------
1376 void CPlayerCL::updateLodTexture()
1378 // if need to recompute, and if Async loading ended
1379 if( _LodTextureDirty
&& !_PlayerCLAsyncTextureLoading
)
1380 // check parent and upadte lod
1381 CCharacterCL::updateLodTexture();
1384 //-----------------------------------------------
1386 // Return the basic max speed for the entity in meter per sec
1387 //-----------------------------------------------
1388 double CPlayerCL::getMaxSpeed() const// virtual
1395 //---------------------------------------------------
1397 // Display Debug Information.
1398 //---------------------------------------------------
1399 void CPlayerCL::displayDebug(float x
, float &y
, float lineStep
) // virtual
1401 CCharacterCL::displayDebug(x
, y
, lineStep
);
1409 //---------------------------------------------------
1411 // Read/Write Variables from/to the stream.
1412 //---------------------------------------------------
1413 void CPlayerCL::readWrite(NLMISC::IStream
&f
)
1415 CCharacterCL::readWrite(f
);
1420 // const CPlayerSheet *_Sheet;
1421 // const CRaceStatsSheet *_PlayerSheet;
1422 // NL3D::UInstance _Face;
1423 f
.serial(_DefaultChest
);
1424 f
.serial(_DefaultLegs
);
1425 f
.serial(_DefaultArms
);
1426 f
.serial(_DefaultHands
);
1427 f
.serial(_DefaultFeet
);
1428 f
.serial(_DefaultHair
);
1429 f
.serial(_HairColor
);
1430 f
.serial(_EyesColor
);
1431 f
.serial(_WaitForAppearance
);
1432 f
.serial(_PlayerCLAsyncTextureLoading
);
1434 // NL3D::UPointLight _Light;
1439 //---------------------------------------------------
1441 // To call after a read from a stream to re-initialize the entity.
1442 //---------------------------------------------------
1443 void CPlayerCL::load() // virtual
1445 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
1447 // If the entity should be in the world already
1448 if(_First_Pos
== false)
1450 // Insert the primitive into the world.
1452 _Primitive
->insertInWorldImage(dynamicWI
);
1453 // Insert the entity into PACS
1458 if(!_WaitForAppearance
)
1460 // Visual properties A
1461 sint64 prop
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->getValue64();
1462 updateVisualPropertyVpa(0, prop
); // Vpa udapte vpb and vpc too.
1466 // *********************************************************************************************
1467 const char *CPlayerCL::getBoneNameFromBodyPart(BODY::TBodyPart part
, BODY::TSide side
) const
1469 if (!_PlayerSheet
) return CCharacterCL::getBoneNameFromBodyPart(part
, side
);
1470 return _PlayerSheet
->BodyToBone
.getBoneName(part
, side
);
1473 // *********************************************************************************************
1474 const CItemSheet
*CPlayerCL::getRightHandItemSheet() const
1476 return _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
1479 // *********************************************************************************************
1480 const CItemSheet
*CPlayerCL::getLeftHandItemSheet() const
1482 return _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
1485 // *********************************************************************************************
1486 const CAttack
*CPlayerCL::getAttack(const CAttackIDSheet
&id
) const
1488 if (!_PlayerSheet
) return NULL
;
1489 return CCharacterCL::getAttack(id
, _PlayerSheet
->AttackLists
);
1492 // *********************************************************************************************
1493 float CPlayerCL::getScaleRef() const
1495 float fyrosRefScale
= GabaritSet
.getRefHeightScale(0, EGSPD::CPeople::Fyros
);
1496 if (fyrosRefScale
== 0) return 1.f
;
1497 return _CustomScalePos
* (GabaritSet
.getRefHeightScale(_Gender
, people()) / fyrosRefScale
);
1501 // *********************************************************************************************
1502 float CPlayerCL::getNamePosZ() const
1508 switch (_ModeWanted
)
1512 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZLow
;
1515 case MBEHAV::MOUNT_NORMAL
:
1516 case MBEHAV::MOUNT_SWIM
:
1517 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZHigh
;
1521 namePosZ
= _PlayerSheet
->GenderInfos
[_Gender
].NamePosZNormal
;
1525 return namePosZ
* _CharacterScalePos
* _CustomScalePos
;
1528 // ***************************************************************************
1529 void CPlayerCL::doSetVisualSelectionBlink(bool bOnOff
, NLMISC::CRGBA emitColor
)
1533 _Face
.setEmissive(emitColor
);
1535 _Face
.restoreEmissive();
1538 CCharacterCL::doSetVisualSelectionBlink(bOnOff
, emitColor
);
1543 //-----------------------------------------------
1544 // computePrimitive :
1545 // Create (or re-create) a primitive.
1546 //-----------------------------------------------
1547 void CPlayerCL::computePrimitive()
1549 // Initialize the primitive.
1550 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
1552 _Primitive
->insertInWorldImage(dynamicWI
);
1553 // Set the position.
1555 }// computePrimitive //