1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 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_r2_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"
47 #include "client_sheets/player_sheet.h"
49 #include "nel/3d/u_scene.h"
50 #include "nel/3d/u_instance_material.h"
51 #include "nel/3d/u_play_list.h"
52 #include "nel/3d/u_bone.h"
53 #include "nel/3d/u_particle_system_instance.h"
54 #include "nel/3d/u_point_light.h"
56 #include "game_share/player_visual_properties.h"
57 #include "game_share/gender.h"
58 #include "game_share/bot_chat_types.h"
64 using namespace NLMISC
;
66 using namespace NLPACS
;
74 extern CEntityAnimationManager
*EAM
;
75 extern UTextContext
*TextContext
;
76 extern UCamera MainCam
;
79 //-----------------------------------------------
82 //-----------------------------------------------
83 CPlayerR2CL::CPlayerR2CL()
88 // Resize _Instances to the number of visual slots.
89 _Instances
.resize(SLOTTYPE::NB_SLOT
);
95 // Some default colors.
99 // Not enough information to display the player.
100 _WaitForAppearance
= true;
102 _PlayerCLAsyncTextureLoading
= false;
104 // Light Off and not allocated
109 //-----------------------------------------------
112 //-----------------------------------------------
113 CPlayerR2CL::~CPlayerR2CL()
115 // No more sheet pointed.
122 Scene
->deletePointLight(_Light
);
126 CGenderInfo
* CPlayerR2CL::getGenderInfo()
128 EGSPD::CPeople::TPeople ePeople
= _Sheet
->Race
;
129 bool bMale
= (_Sheet
->Gender
== GSGENDER::male
);
131 // Read in the race_stats forms the default equipement
135 case EGSPD::CPeople::Tryker
: RSid
= CSheetId("tryker.race_stats"); break;
136 case EGSPD::CPeople::Matis
: RSid
= CSheetId("matis.race_stats"); break;
137 case EGSPD::CPeople::Zorai
: RSid
= CSheetId("zorai.race_stats"); break;
138 case EGSPD::CPeople::Fyros
:
140 RSid
= CSheetId("fyros.race_stats"); break;
142 CRaceStatsSheet
*pRSS
= dynamic_cast<CRaceStatsSheet
*>(SheetMngr
.get (RSid
));
146 nlwarning ("cannot find sheet for people:%d male:%d", ePeople
, bMale
);
150 // Choose default stuff is we are male or female
153 pGI
= &pRSS
->GenderInfos
[0];
155 pGI
= &pRSS
->GenderInfos
[1];
162 //---------------------------------------------------
164 // Return the entity scale. (return 1.0 if there is any problem).
165 //---------------------------------------------------
166 float CPlayerR2CL::getScale() const // virtual
169 return _CharacterScalePos
;
174 //-----------------------------------------------
176 // retrieve ground fxs for the entity depending on the ground
177 //-----------------------------------------------
178 const std::vector<CGroundFXSheet> *CPlayerR2CL::getGroundFX() const
182 case 0: return &(_PlayerSheet->GenderInfos[0].GroundFX);
183 case 1: return &(_PlayerSheet->GenderInfos[1].GroundFX);
191 //-----------------------------------------------
193 // Build the entity from a sheet.
194 //-----------------------------------------------
195 bool CPlayerR2CL::build(const CEntitySheet
*sheet
) // virtual
197 // Cast the sheet in the right type.
198 _Sheet
= dynamic_cast<const CCharacterSheet
*>(sheet
);
201 pushDebugStr(NLMISC::toString("R2 Player '%d' sheet is not a '.creature' -> BIG PROBLEM.", _Slot
));
205 pushInfoStr(NLMISC::toString("R2 Player '%d' sheet is valid.", _Slot
));
207 if(IngameDbMngr
.getNodePtr())
209 CCDBNodeBranch
*nodeRoot
= dynamic_cast<CCDBNodeBranch
*>(IngameDbMngr
.getNodePtr()->getNode(0));
212 _DBEntry
= dynamic_cast<CCDBNodeBranch
*>(nodeRoot
->getNode(_Slot
));
214 pushDebugStr("Cannot get a pointer on the DB entry.");
218 // Compute the first automaton.
219 _CurrentAutomaton
= automatonType() + "_normal.automaton";
221 // Initialize the player look.
223 // Compute the primitive
224 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
225 // Create the collision entity (used to snap the entity to the ground).
226 computeCollisionEntity();
228 // Initialize properties of the client.
235 //-----------------------------------------------
237 // Return the automaton type of the entity (homin, creature, etc.)
238 //-----------------------------------------------
239 std::string CPlayerR2CL::automatonType() const // virtual
241 return _PlayerSheet->Automaton;
242 }// automatonType //*/
245 //-----------------------------------------------
247 // Initialize the graphic for the player.
248 //-----------------------------------------------
249 void CPlayerR2CL::init3d()
252 // Initialize the internal time.
253 _LastFrameTime
= ((double)T1
) * 0.001;
257 //-----------------------------------------------
259 // Initialize properties of the entity (according to the class).
260 //-----------------------------------------------
261 void CPlayerR2CL::initProperties()
263 properties().selectable(true);
264 properties().attackable(false);
265 properties().givable(true);
266 properties().invitable(true);
267 properties().canExchangeItem(true);
268 }// initProperties //
271 //-----------------------------------------------
273 // Set the equipmenent worn.
274 //-----------------------------------------------
275 void CPlayerR2CL::equip(SLOTTYPE::EVisualSlot slot
, const std::string
&shapeName
, const CItemSheet
*item
)
278 if(slot
== SLOTTYPE::HIDDEN_SLOT
|| slot
>= SLOTTYPE::NB_SLOT
)
280 nlwarning("CCharacterCL::equip : slot %d is not valid.", (uint
)slot
);
286 // If exactly the same than before -> return
288 if (!_Instances
[s
].Loading
.empty())
290 if ((_Instances
[s
].LoadingName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
293 else if (!_Instances
[s
].Current
.empty())
295 if ((_Instances
[s
].CurrentName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
301 // Attach to the skeleton.
303 if(!_Skeleton
.empty())
307 case SLOTTYPE::RIGHT_HAND_SLOT
:
308 if( item
&& item
->ItemType
!= ITEM_TYPE::MAGICIAN_STAFF
)
309 stickPoint
= "box_arme";
312 case SLOTTYPE::LEFT_HAND_SLOT
:
313 if(_Items
[slot
].Sheet
&& _Items
[slot
].Sheet
->getAnimSet()=="s")
314 stickPoint
= "Box_bouclier";
316 stickPoint
= "box_arme_gauche";
324 /* If the object is sticked (ie not a skin), decide to delete the Current instance. Why? because the animation
325 is changed according to the equipped item.
327 Hence, For example, if a sword would be changed for a gun, then the new gun animation would take place,
328 while Keeping the old sword shape. BAD.
330 if(!stickPoint
.empty())
331 _Instances
[s
].createLoading(string(), stickPoint
);
333 // Create the instance.
335 _Instances
[s
].createLoading(shapeName
, stickPoint
, item
->MapVariant
);
337 _Instances
[s
].createLoading(shapeName
, stickPoint
);
339 // If shapeName is empty, only clear the slot
340 if(shapeName
.empty())
342 _Items
[slot
].release();
346 if(!_Instances
[s
].Loading
.empty())
348 _Instances
[s
].FXItemSheet
= item
;
350 _Items
[slot
].initFXs(slot
, _Instances
[s
].Loading
);
353 nlwarning("PL::equip(1):%d: cannot create the instance '%s'.", _Slot
, shapeName
.c_str());
355 if ((slot
!= SLOTTYPE::RIGHT_HAND_SLOT
) && (slot
!= SLOTTYPE::LEFT_HAND_SLOT
))
356 applyColorSlot(_Instances
[s
], skin(), 0, _HairColor
, _EyesColor
);
360 //-----------------------------------------------
362 // Compute the equipmenent worn.
363 //-----------------------------------------------
364 void CPlayerR2CL::equip(SLOTTYPE::EVisualSlot slot
, uint index
, uint color
)
366 // Get the sheet according to the visual slot
367 _Items
[slot
].Sheet
= SheetMngr
.getItem(slot
, index
);
368 if(_Items
[slot
].Sheet
)
370 const CItemSheet
*item
= _Items
[slot
].Sheet
;
372 // If the gender is a female get the right shape.
373 if(_Gender
== GSGENDER::female
)
374 equip(slot
, item
->getShapeFemale(), item
);
375 // Else get the default shape.
377 equip(slot
, item
->getShape(), item
);
379 // Check there is a shape.
380 UInstance pInst
= _Instances
[slot
].createLoadingFromCurrent();
383 // Set the right texture variation (quality).
384 pInst
.selectTextureSet((uint
)item
->MapVariant
);
385 _Instances
[slot
].TextureSet
= item
->MapVariant
;
387 // If Hair, color is for the head slot.
388 if(slot
== SLOTTYPE::HEAD_SLOT
&& item
->Family
!= ITEMFAMILY::ARMOR
)
389 applyColorSlot(_Instances
[slot
], skin(), 0, color
, _EyesColor
);
392 // Set the User Color.
393 if(item
->Color
== -1)
394 applyColorSlot(_Instances
[slot
], skin(), color
, _HairColor
, _EyesColor
);
395 // Set the Item Color.
396 else if(item
->Color
!= -2)
397 applyColorSlot(_Instances
[slot
], skin(), item
->Color
, _HairColor
, _EyesColor
);
398 // Else let the default color.
400 applyColorSlot(_Instances
[slot
], skin(), 0, _HairColor
, _EyesColor
);
404 // Default equipment.
407 nldebug("PL:equip(2):%d: VS '%d' default equipement used.", _Slot
, slot
);
408 //sint idx = SheetMngr.getVSIndex(_PlayerSheet->GenderInfos[_Gender].Items[slot], slot);
409 sint idx
= SheetMngr
.getVSIndex(getGenderInfo()->Items
[slot
], slot
);
413 if(SheetMngr
.getItem(slot
, (uint
)idx
))
415 // If the gender is a female get the right shape.
416 if(_Gender
== GSGENDER::female
)
417 equip(slot
, SheetMngr
.getItem(slot
, (uint
)idx
)->getShapeFemale());
418 // Else get the default shape.
420 equip(slot
, SheetMngr
.getItem(slot
, (uint
)idx
)->getShape());
426 //-----------------------------------------------
427 // updateVisualPropertyVpa :
428 // Update the Visual Property A.
429 // \todo GUIGUI : use gender enum.
430 //-----------------------------------------------
431 void CPlayerR2CL::updateVisualPropertyVpa(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
433 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
435 // Player will now have enough information to display the character.
436 _WaitForAppearance
= false;
439 SPropVisualA visualA
= *(SPropVisualA
*)(&prop
);
442 _Gender
= (GSGENDER::EGender
)_Sheet
->Gender
;
443 if(_Gender
!=GSGENDER::male
&& _Gender
!=GSGENDER::female
)
445 nlwarning("PL::updateVPVpa:%d: neither a male nor a female -> male selected.", _Slot
);
446 _Gender
= GSGENDER::male
;
449 // update title when gender changed
450 const string
replacement(STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
,_Gender
== GSGENDER::female
));
451 if (!replacement
.empty())
454 _NameEx
= replacement
;
455 _Title
= replacement
;
457 // rebuild in scene interface
458 buildInSceneInterface();
461 // Setup _CharacterScalePos
462 _CharacterScalePos
= _Sheet
->CharacterScalePos
;
464 // Check if skeleton has changed
465 if (_CacheSkeletonShapeName
!= _Sheet
->getSkelFilename())
467 _CacheSkeletonShapeName
= _Sheet
->getSkelFilename();
469 // Clean the playlist.
471 _PlayList
->resetAllChannels();
473 // We can now build the skeleton so do it now.
474 skeleton(_CacheSkeletonShapeName
);
476 // Invalidate instances cache
477 for (uint i
= 0; i
< _Instances
.size(); ++i
)
479 _Instances
[i
].CurrentName
.clear();
480 _Instances
[i
].LoadingName
.clear();
483 _Face
.CurrentName
.clear();
484 _Face
.LoadingName
.clear();
486 // Check the skeleton.
487 if(skeleton() && !ClientCfg
.Light
)
489 // To re-link the skeleton to the mount if needed.
491 // Set the skeleton scale.
492 // \todo GUIGUI: mettre le scale aussi dans race_stats.
493 // Setup Lod Character skeleton, if skeleton exist
494 // Get Lod Character Id from the sheet.
495 sint clodId
= getLodCharacterId(*Scene
, _Sheet
->getLodCharacterName());
498 // Setup Lod Character shape and distance
499 skeleton()->setLodCharacterShape(clodId
);
500 skeleton()->setLodCharacterDistance(_Sheet
->LodCharacterDistance
);
506 equip(SLOTTYPE::CHEST_SLOT
, visualA
.PropertySubData
.JacketModel
, visualA
.PropertySubData
.JacketColor
);
508 equip(SLOTTYPE::LEGS_SLOT
, visualA
.PropertySubData
.TrouserModel
, visualA
.PropertySubData
.TrouserColor
);
510 equip(SLOTTYPE::ARMS_SLOT
, visualA
.PropertySubData
.ArmModel
, visualA
.PropertySubData
.ArmColor
);
512 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
513 // OBJECT in the RIGHT HAND
514 bool changeWeapon
= false;
515 const CItemSheet
* oldRightSheet
= _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
516 const CItemSheet
* newRightSheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
517 if((oldRightSheet
&& newRightSheet
&& oldRightSheet
->Id
!=newRightSheet
->Id
) || (!oldRightSheet
&& newRightSheet
))
521 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
522 // Equip the weapon(object/tool).
523 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
525 if(_Gender
== GSGENDER::female
)
526 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShapeFemale(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
528 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
530 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
531 if (!itemInstance
.empty())
534 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
535 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
536 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(0);
537 //_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(visualA.PropertySubData.RTrail);
542 // No Valid item in the right hand.
543 equip(SLOTTYPE::RIGHT_HAND_SLOT
, "");
546 // OBJECT in the LEFT HAND
547 const CItemSheet
* oldLeftSheet
= _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
548 const CItemSheet
* newLeftSheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
549 if((oldLeftSheet
&& newLeftSheet
&& oldLeftSheet
->Id
!=newLeftSheet
->Id
) || (!oldLeftSheet
&& newLeftSheet
))
554 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
555 // Equip the weapon(object/tool).
556 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
558 equip(SLOTTYPE::LEFT_HAND_SLOT
, _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
);
559 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
560 if (!itemInstance
.empty())
563 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
564 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(0);
565 //_Items[SLOTTYPE::LEFT_HAND_SLOT].setTrailSize(2 * (uint) visualA.PropertySubData.LTrail);
570 // No Valid item in the left hand.
571 equip(SLOTTYPE::LEFT_HAND_SLOT
, "");
574 // Only create a face when there is no Helmet
575 if(_Items
[SLOTTYPE::HEAD_SLOT
].Sheet
== 0 || _Items
[SLOTTYPE::HEAD_SLOT
].Sheet
->Family
!= ITEMFAMILY::ARMOR
)
577 CItemSheet
*faceItem
= getItem(*getGenderInfo(), SLOTTYPE::FACE_SLOT
);
582 if(_Gender
== GSGENDER::female
)
583 sFaceName
= faceItem
->getShapeFemale();
585 sFaceName
= faceItem
->getShape();
587 if (((!_Face
.Loading
.empty()) && (_Face
.LoadingName
!= sFaceName
)) ||
588 ((!_Face
.Current
.empty()) && (_Face
.CurrentName
!= sFaceName
)) ||
589 (_Face
.Current
.empty()))
591 if (!_Face
.Loading
.empty())
593 Scene
->deleteInstance(_Face
.Loading
);
594 _Face
.Loading
= NULL
;
595 _Face
.LoadingName
= sFaceName
;
597 _Face
.Loading
= Scene
->createInstance(sFaceName
);
598 if (!_Face
.Loading
.empty())
600 _Face
.LoadingName
= sFaceName
;
601 if(!skeleton()->bindSkin(_Face
.Loading
))
602 nlwarning("PL::updateVPVpa:%d: Cannot bind the face.", _Slot
);
603 _Face
.Loading
.hide();
604 // set it async for texture
605 _Face
.Loading
.enableAsyncTextureMode(true);
608 nlwarning("PL::updateVPVpa:%d: Cannot create the face.", _Slot
);
610 _Face
.TextureSet
= faceItem
->MapVariant
;
611 applyColorSlot(_Face
, skin(), 0, visualA
.PropertySubData
.HatColor
, 0); // Set a default ruflaket color.
614 nlwarning("PL::updateVPVpa:%d: Face Item '%s' does not exist.", _Slot
,
615 getGenderInfo()->Items
[SLOTTYPE::FACE_SLOT
].c_str());
619 // There is a helmet !
620 if (!_Face
.Loading
.empty())
621 Scene
->deleteInstance(_Face
.Loading
);
622 _Face
.Loading
= NULL
;
623 _Face
.LoadingName
.clear();
624 if (!_Face
.Current
.empty())
625 Scene
->deleteInstance(_Face
.Current
);
626 _Face
.Current
= NULL
;
627 _Face
.CurrentName
.clear();
629 // Now we have a skeleton, we can update VpB and VpC.
632 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPB
);
633 vB
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
634 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPC
);
635 vC
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
636 updateVisualPropertyVpb(0, vB
);
637 updateVisualPropertyVpc(0, vC
);
639 // Attach The Light if there is one.
640 if(!_Light
.empty() && _NameBoneId
!=-1)
641 _Skeleton
.stickObject(_Light
, _NameBoneId
);
645 // Compute the new animation set to use (due to weapons).
648 // Set the animation to idle.
649 setAnim(CAnimationStateSheet::Idle
);
654 nlwarning("PL::updateVPVpa:%d: Skeleton not allocated.", _Slot
);
655 }// updateVisualPropertyVpa //
657 //-----------------------------------------------
658 // updateVisualPropertyVpb :
659 // Update the Visual Property B.
660 //-----------------------------------------------
661 void CPlayerR2CL::updateVisualPropertyVpb(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
664 SPropVisualB visualB
= *(SPropVisualB
*)(&prop
);
666 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
668 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
669 if (!itemInstance
.empty())
672 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
673 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(visualB
.PropertySubData
.RTrail
);
677 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
679 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
680 if (!itemInstance
.empty())
683 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(2 * (uint
) visualB
.PropertySubData
.LTrail
);
690 equip(SLOTTYPE::HANDS_SLOT
, visualB
.PropertySubData
.HandsModel
, visualB
.PropertySubData
.HandsColor
);
692 equip(SLOTTYPE::FEET_SLOT
, visualB
.PropertySubData
.FeetModel
, visualB
.PropertySubData
.FeetColor
);
695 nlinfo("PL::updateVPVpb:%d: Prop Vpb received before prop Vpa.", _Slot
);
696 }// updateVisualPropertyVpb //
698 //-----------------------------------------------
699 // updateVisualPropertyVpc :
700 // Update the Visual Property C.
701 // \todo GUIGUI : factorize tatoos with character creation
702 //-----------------------------------------------
704 void CPlayerR2CL::updateVisualPropertyVpc(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
709 SPropVisualC visualC
= *(SPropVisualC
*)(&prop
);
712 _EyesColor
= visualC
.PropertySubData
.EyesColor
;
715 // must recreate the face asynchronously (because of color change / makeup change)
716 inst
= _Face
.createLoadingFromCurrent();
721 // change eyes color only
722 applyColorSlot(_Face
, _Face
.ACSkin
, _Face
.ACUser
, _Face
.ACHair
, visualC
.PropertySubData
.EyesColor
);
725 makeUp(inst
, visualC
.PropertySubData
.Tattoo
);
728 static const char *baseName
= "visage_00";
731 CGenderInfo
*pGI
= getGenderInfo();
735 MTmin
= pGI
->BlendShapeMin
[0];
736 MTmax
= pGI
->BlendShapeMax
[0];
737 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
738 inst
.setBlendShapeFactor(baseName
+ toString(0), (float)(visualC
.PropertySubData
.MorphTarget1
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
740 MTmin
= pGI
->BlendShapeMin
[1];
741 MTmax
= pGI
->BlendShapeMax
[1];
742 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
743 inst
.setBlendShapeFactor(baseName
+ toString(1), (float)(visualC
.PropertySubData
.MorphTarget2
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
745 MTmin
= pGI
->BlendShapeMin
[2];
746 MTmax
= pGI
->BlendShapeMax
[2];
747 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
748 inst
.setBlendShapeFactor(baseName
+ toString(2), (float)(visualC
.PropertySubData
.MorphTarget3
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
750 MTmin
= pGI
->BlendShapeMin
[3];
751 MTmax
= pGI
->BlendShapeMax
[3];
752 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
753 inst
.setBlendShapeFactor(baseName
+ toString(3), (float)(visualC
.PropertySubData
.MorphTarget4
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
755 MTmin
= pGI
->BlendShapeMin
[4];
756 MTmax
= pGI
->BlendShapeMax
[4];
757 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
758 inst
.setBlendShapeFactor(baseName
+ toString(4), (float)(visualC
.PropertySubData
.MorphTarget5
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
760 MTmin
= pGI
->BlendShapeMin
[5];
761 MTmax
= pGI
->BlendShapeMax
[5];
762 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
763 inst
.setBlendShapeFactor(baseName
+ toString(5), (float)(visualC
.PropertySubData
.MorphTarget6
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
765 MTmin
= pGI
->BlendShapeMin
[6];
766 MTmax
= pGI
->BlendShapeMax
[6];
767 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
768 inst
.setBlendShapeFactor(baseName
+ toString(6), (float)(visualC
.PropertySubData
.MorphTarget7
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
770 MTmin
= pGI
->BlendShapeMin
[7];
771 MTmax
= pGI
->BlendShapeMax
[7];
772 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
773 inst
.setBlendShapeFactor(baseName
+ toString(7), (float)(visualC
.PropertySubData
.MorphTarget8
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
777 float characterHeight
= (float)((sint8
)(visualC
.PropertySubData
.CharacterHeight
)-7)/7.f
;
778 float torsoWidth
= (float)((sint8
)(visualC
.PropertySubData
.TorsoWidth
)-7)/7.f
;
779 float armsWidth
= (float)((sint8
)(visualC
.PropertySubData
.ArmsWidth
)-7)/7.f
;
780 float legsWidth
= (float)((sint8
)(visualC
.PropertySubData
.LegsWidth
)-7)/7.f
;
781 float breastSize
= (float)((sint8
)(visualC
.PropertySubData
.BreastSize
)-7)/7.f
;
782 float heightScale
, baseHeightScale
;
783 // TODO : manage breast size
784 GabaritSet
.applyGabarit(*skeleton(), _Gender
, people(), characterHeight
, torsoWidth
, armsWidth
, legsWidth
, breastSize
, &heightScale
);
785 baseHeightScale
= GabaritSet
.getRefHeightScale(_Gender
, people());
787 if(baseHeightScale
!= 0.f
)
788 _CustomScalePos
= heightScale
/baseHeightScale
;
791 _CustomScalePos
= 1.f
;
792 nlwarning("PL::updateVPVpc:'%d': baseHeight == 0.", _Slot
);
796 nlinfo("PL:updateVPVpc:'%d': Prop Vpc received before prop Vpa.", _Slot
);
797 }// updateVisualPropertyVpc //
800 //-----------------------------------------------
802 // Get The Entity Skin
803 //-----------------------------------------------
804 sint CPlayerR2CL::skin() const // virtual
806 return _PlayerSheet->Skin;
810 //-----------------------------------------------
812 // Return the People for the entity.
813 //-----------------------------------------------
814 EGSPD::CPeople::TPeople CPlayerR2CL::people() const// virtual
817 return _PlayerSheet->People;
819 return EGSPD::CPeople::Unknown;
823 //-----------------------------------------------
825 // Setup the People for the entity.
826 //-----------------------------------------------
827 void CPlayerR2CL::setPeople(EGSPD::CPeople::TPeople people)
831 //-----------------------------------------------
834 //-----------------------------------------------
835 void CPlayerR2CL::drawName(const NLMISC::CMatrix
&mat
) // virtual
838 if(!getEntityName().empty())
839 TextContext
->render3D(mat
, getEntityName());
843 //-----------------------------------------------
845 // Update eyes blink. For the moment, called by updatePos.
846 //-----------------------------------------------
847 CEntityCL::SInstanceCL
*CPlayerR2CL::getFace()
849 // Implemented in CPlayerR2CL
853 //-----------------------------------------------
855 // Method to return the attack radius of an entity (take the scale into account).
856 //-----------------------------------------------
857 double CPlayerR2CL::attackRadius() const // virtual
862 //-----------------------------------------------
863 // Return the position the attacker should have to combat according to the attack angle.
864 // \param ang : 0 = the front, >0 and <Pi = left side, <0 and >-Pi = right side.
865 //-----------------------------------------------
866 CVectorD
CPlayerR2CL::getAttackerPos(double ang
, double dist
) const
868 // Compute the local angle
869 ang
= computeShortestAngle(atan2(front().y
, front().x
), ang
);
874 // Compute the local position.
876 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.
877 p
.y
= 0.5 * cos(ang
) + dist
*cos(ang
);
880 // Compute the world position.
881 // Create the target matrix.
882 CVector vj
= front();
887 bodyBase
.setRot(vi
,vj
,vk
,true);
888 bodyBase
.setPos(pos());
890 // Get the destination in the world.
892 }// getAttackerPos //
898 //-----------------------------------------------
899 // updateAsyncTexture
900 //-----------------------------------------------
901 float CPlayerR2CL::updateAsyncTexture()
904 float distToCam
= CCharacterCL::updateAsyncTexture();
906 // Check all instance to know if they need to start async load their textures
907 if(!_Face
.Loading
.empty())
910 if(_Face
.Loading
.isAsyncTextureDirty())
912 // reset instance state.
913 _Face
.Loading
.setAsyncTextureDirty(false);
914 // must start loading for this isntance
915 _Face
.Loading
.startAsyncTextureLoading();
916 // the entity is now currently loading.
917 _PlayerCLAsyncTextureLoading
= true;
918 // The LodTexture need to be recomputed
919 _LodTextureDirty
= true;
924 // Update Async Texture loading of all instances.
925 if(_PlayerCLAsyncTextureLoading
)
927 bool allLoaded
= true;
928 // update loading for all instances.
929 if(!_Face
.Loading
.empty())
931 // update async texture loading
932 allLoaded
= allLoaded
&& _Face
.Loading
.isAsyncTextureReady();
935 // if all are loaded, then End! don't need to check all instances every frame.
938 _PlayerCLAsyncTextureLoading
= false;
939 _Face
.updateCurrentFromLoading(_Skeleton
);
944 // For LOD texture, must update the "texture distance"
945 if(!_Face
.Current
.empty())
947 // update async texture loading
948 _Face
.Current
.setAsyncTextureDistance(distToCam
);
954 //-----------------------------------------------
956 //-----------------------------------------------
957 void CPlayerR2CL::updateLodTexture()
959 // if need to recompute, and if Async loading ended
960 if( _LodTextureDirty
&& !_PlayerCLAsyncTextureLoading
)
961 // check parent and upadte lod
962 CCharacterCL::updateLodTexture();
965 //-----------------------------------------------
967 // Return the basic max speed for the entity in meter per sec
968 //-----------------------------------------------
969 double CPlayerR2CL::getMaxSpeed() const// virtual
976 //---------------------------------------------------
978 // Display Debug Information.
979 //---------------------------------------------------
980 void CPlayerR2CL::displayDebug(float x
, float &y
, float lineStep
) // virtual
982 CCharacterCL::displayDebug(x
, y
, lineStep
);
990 //---------------------------------------------------
992 // Read/Write Variables from/to the stream.
993 //---------------------------------------------------
994 void CPlayerR2CL::readWrite(NLMISC::IStream
&f
)
996 CCharacterCL::readWrite(f
);
1001 // const CPlayerSheet *_Sheet;
1002 // const CRaceStatsSheet *_PlayerSheet;
1003 // NL3D::UInstance _Face;
1004 f
.serial(_DefaultChest
);
1005 f
.serial(_DefaultLegs
);
1006 f
.serial(_DefaultArms
);
1007 f
.serial(_DefaultHands
);
1008 f
.serial(_DefaultFeet
);
1009 f
.serial(_DefaultHair
);
1010 f
.serial(_HairColor
);
1011 f
.serial(_EyesColor
);
1012 f
.serial(_WaitForAppearance
);
1013 f
.serial(_PlayerCLAsyncTextureLoading
);
1015 // NL3D::UPointLight _Light;
1020 //---------------------------------------------------
1022 // To call after a read from a stream to re-initialize the entity.
1023 //---------------------------------------------------
1024 void CPlayerR2CL::load() // virtual
1026 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
1028 // If the entity should be in the world already
1029 if(_First_Pos
== false)
1031 // Insert the primitive into the world.
1033 _Primitive
->insertInWorldImage(dynamicWI
);
1034 // Insert the entity into PACS
1039 if(!_WaitForAppearance
)
1041 // Visual properties A
1042 sint64 prop
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->getValue64();
1043 updateVisualPropertyVpa(0, prop
); // Vpa udapte vpb and vpc too.
1047 // *********************************************************************************************
1049 const char *CPlayerR2CL::getBoneNameFromBodyPart(BODY::TBodyPart part, BODY::TSide side) const
1051 if (!_PlayerSheet) return CCharacterCL::getBoneNameFromBodyPart(part, side);
1052 return _PlayerSheet->BodyToBone.getBoneName(part, side);
1055 // *********************************************************************************************
1056 const CItemSheet
*CPlayerR2CL::getRightHandItemSheet() const
1058 return _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
1061 // *********************************************************************************************
1062 const CItemSheet
*CPlayerR2CL::getLeftHandItemSheet() const
1064 return _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
1067 // *********************************************************************************************
1068 /*const CAttack *CPlayerR2CL::getAttack(const CAttackIDSheet &id) const
1070 if (!_PlayerSheet) return NULL;
1071 return CCharacterCL::getAttack(id, _PlayerSheet->AttackLists);
1074 // *********************************************************************************************
1075 float CPlayerR2CL::getScaleRef() const
1077 float fyrosRefScale
= GabaritSet
.getRefHeightScale(0, EGSPD::CPeople::Fyros
);
1078 if (fyrosRefScale
== 0) return 1.f
;
1079 return _CustomScalePos
* (GabaritSet
.getRefHeightScale(_Gender
, people()) / fyrosRefScale
);
1083 // *********************************************************************************************
1085 float CPlayerR2CL::getNamePosZ() const
1091 switch (_ModeWanted)
1095 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZLow;
1098 case MBEHAV::MOUNT_NORMAL:
1099 case MBEHAV::MOUNT_SWIM:
1100 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZHigh;
1104 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZNormal;
1108 return namePosZ * _CharacterScalePos * _CustomScalePos;
1111 // ***************************************************************************
1112 void CPlayerR2CL::doSetVisualSelectionBlink(bool bOnOff
, NLMISC::CRGBA emitColor
)
1116 _Face
.setEmissive(emitColor
);
1118 _Face
.restoreEmissive();
1121 CCharacterCL::doSetVisualSelectionBlink(bOnOff
, emitColor
);
1124 // ***************************************************************************
1125 void CPlayerR2CL::makeTransparent(bool t
)
1127 CCharacterCL::makeTransparent(t
);
1129 uint32 opaMin
= getOpacityMin();
1130 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
1132 _Face
.makeInstanceTransparent(opacity
, (uint8
)opaMin
);
1133 }// makeTransparent //
1135 // ***************************************************************************
1136 void CPlayerR2CL::setDiffuse(bool onOff
, NLMISC::CRGBA diffuse
)
1138 CCharacterCL::setDiffuse(onOff
, diffuse
);
1139 _Face
.setDiffuse(onOff
, diffuse
);