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>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "nel/misc/time_nl.h"
30 #include "player_r2_cl.h"
31 #include "ingame_database_manager.h"
32 #include "net_manager.h"
33 #include "time_client.h"
34 #include "entity_animation_manager.h"
35 #include "sheet_manager.h"
36 #include "color_slot_manager.h"
37 #include "debug_client.h"
39 #include "interface_v3/interface_manager.h"
41 #include "pacs_client.h"
42 #include "motion/user_controls.h"
43 #include "client_cfg.h"
44 #include "user_entity.h"
46 #include "client_sheets/player_sheet.h"
48 #include "nel/3d/u_scene.h"
49 #include "nel/3d/u_instance_material.h"
50 #include "nel/3d/u_play_list.h"
51 #include "nel/3d/u_bone.h"
52 #include "nel/3d/u_particle_system_instance.h"
53 #include "nel/3d/u_point_light.h"
55 #include "game_share/player_visual_properties.h"
56 #include "game_share/gender.h"
57 #include "game_share/bot_chat_types.h"
63 using namespace NLMISC
;
65 using namespace NLPACS
;
73 extern CEntityAnimationManager
*EAM
;
74 extern UTextContext
*TextContext
;
75 extern UCamera MainCam
;
78 //-----------------------------------------------
81 //-----------------------------------------------
82 CPlayerR2CL::CPlayerR2CL()
87 // Resize _Instances to the number of visual slots.
88 _Instances
.resize(SLOTTYPE::NB_SLOT
);
94 // Some default colors.
98 // Not enough information to display the player.
99 _WaitForAppearance
= true;
101 _PlayerCLAsyncTextureLoading
= false;
103 // Light Off and not allocated
108 //-----------------------------------------------
111 //-----------------------------------------------
112 CPlayerR2CL::~CPlayerR2CL()
114 // No more sheet pointed.
121 Scene
->deletePointLight(_Light
);
125 CGenderInfo
* CPlayerR2CL::getGenderInfo()
127 EGSPD::CPeople::TPeople ePeople
= _Sheet
->Race
;
128 bool bMale
= (_Sheet
->Gender
== GSGENDER::male
);
130 // Read in the race_stats forms the default equipement
134 case EGSPD::CPeople::Tryker
: RSid
= CSheetId("tryker.race_stats"); break;
135 case EGSPD::CPeople::Matis
: RSid
= CSheetId("matis.race_stats"); break;
136 case EGSPD::CPeople::Zorai
: RSid
= CSheetId("zorai.race_stats"); break;
137 case EGSPD::CPeople::Fyros
:
139 RSid
= CSheetId("fyros.race_stats"); break;
141 CRaceStatsSheet
*pRSS
= dynamic_cast<CRaceStatsSheet
*>(SheetMngr
.get (RSid
));
145 nlwarning ("cannot find sheet for people:%d male:%d", ePeople
, bMale
);
149 // Choose default stuff is we are male or female
152 pGI
= &pRSS
->GenderInfos
[0];
154 pGI
= &pRSS
->GenderInfos
[1];
161 //---------------------------------------------------
163 // Return the entity scale. (return 1.0 if there is any problem).
164 //---------------------------------------------------
165 float CPlayerR2CL::getScale() const // virtual
168 return _CharacterScalePos
;
173 //-----------------------------------------------
175 // retrieve ground fxs for the entity depending on the ground
176 //-----------------------------------------------
177 const std::vector<CGroundFXSheet> *CPlayerR2CL::getGroundFX() const
181 case 0: return &(_PlayerSheet->GenderInfos[0].GroundFX);
182 case 1: return &(_PlayerSheet->GenderInfos[1].GroundFX);
190 //-----------------------------------------------
192 // Build the entity from a sheet.
193 //-----------------------------------------------
194 bool CPlayerR2CL::build(const CEntitySheet
*sheet
) // virtual
196 // Cast the sheet in the right type.
197 _Sheet
= dynamic_cast<const CCharacterSheet
*>(sheet
);
200 pushDebugStr(NLMISC::toString("R2 Player '%d' sheet is not a '.creature' -> BIG PROBLEM.", _Slot
));
204 pushInfoStr(NLMISC::toString("R2 Player '%d' sheet is valid.", _Slot
));
206 if(IngameDbMngr
.getNodePtr())
208 CCDBNodeBranch
*nodeRoot
= dynamic_cast<CCDBNodeBranch
*>(IngameDbMngr
.getNodePtr()->getNode(0));
211 _DBEntry
= dynamic_cast<CCDBNodeBranch
*>(nodeRoot
->getNode(_Slot
));
213 pushDebugStr("Cannot get a pointer on the DB entry.");
217 // Compute the first automaton.
218 _CurrentAutomaton
= automatonType() + "_normal.automaton";
220 // Initialize the player look.
222 // Compute the primitive
223 initPrimitive(0.5f
, 2.0f
, 0.0f
, 0.0f
, UMovePrimitive::DoNothing
, UMovePrimitive::NotATrigger
, MaskColPlayer
, MaskColNone
);
224 // Create the collision entity (used to snap the entity to the ground).
225 computeCollisionEntity();
227 // Initialize properties of the client.
234 //-----------------------------------------------
236 // Return the automaton type of the entity (homin, creature, etc.)
237 //-----------------------------------------------
238 std::string CPlayerR2CL::automatonType() const // virtual
240 return _PlayerSheet->Automaton;
241 }// automatonType //*/
244 //-----------------------------------------------
246 // Initialize the graphic for the player.
247 //-----------------------------------------------
248 void CPlayerR2CL::init3d()
251 // Initialize the internal time.
252 _LastFrameTime
= ((double)T1
) * 0.001;
256 //-----------------------------------------------
258 // Initialize properties of the entity (according to the class).
259 //-----------------------------------------------
260 void CPlayerR2CL::initProperties()
262 properties().selectable(true);
263 properties().attackable(false);
264 properties().givable(true);
265 properties().invitable(true);
266 properties().canExchangeItem(true);
267 }// initProperties //
270 //-----------------------------------------------
272 // Set the equipmenent worn.
273 //-----------------------------------------------
274 void CPlayerR2CL::equip(SLOTTYPE::EVisualSlot slot
, const std::string
&shapeName
, const CItemSheet
*item
)
277 if(slot
== SLOTTYPE::HIDDEN_SLOT
|| slot
>= SLOTTYPE::NB_SLOT
)
279 nlwarning("CCharacterCL::equip : slot %d is not valid.", (uint
)slot
);
285 // If exactly the same than before -> return
287 if (!_Instances
[s
].Loading
.empty())
289 if ((_Instances
[s
].LoadingName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
292 else if (!_Instances
[s
].Current
.empty())
294 if ((_Instances
[s
].CurrentName
== shapeName
) && (_Instances
[s
].FXItemSheet
== item
))
300 // Attach to the skeleton.
302 if(!_Skeleton
.empty())
306 case SLOTTYPE::RIGHT_HAND_SLOT
:
307 if( item
&& item
->ItemType
!= ITEM_TYPE::MAGICIAN_STAFF
)
308 stickPoint
= "box_arme";
311 case SLOTTYPE::LEFT_HAND_SLOT
:
312 if(_Items
[slot
].Sheet
&& _Items
[slot
].Sheet
->getAnimSet()=="s")
313 stickPoint
= "Box_bouclier";
315 stickPoint
= "box_arme_gauche";
323 /* If the object is sticked (ie not a skin), decide to delete the Current instance. Why? because the animation
324 is changed according to the equipped item.
326 Hence, For example, if a sword would be changed for a gun, then the new gun animation would take place,
327 while Keeping the old sword shape. BAD.
329 if(!stickPoint
.empty())
330 _Instances
[s
].createLoading(string(), stickPoint
);
332 // Create the instance.
334 _Instances
[s
].createLoading(shapeName
, stickPoint
, item
->MapVariant
);
336 _Instances
[s
].createLoading(shapeName
, stickPoint
);
338 // If shapeName is empty, only clear the slot
339 if(shapeName
.empty())
341 _Items
[slot
].release();
345 if(!_Instances
[s
].Loading
.empty())
347 _Instances
[s
].FXItemSheet
= item
;
349 _Items
[slot
].initFXs(slot
, _Instances
[s
].Loading
);
352 nlwarning("PL::equip(1):%d: cannot create the instance '%s'.", _Slot
, shapeName
.c_str());
354 if ((slot
!= SLOTTYPE::RIGHT_HAND_SLOT
) && (slot
!= SLOTTYPE::LEFT_HAND_SLOT
))
355 applyColorSlot(_Instances
[s
], skin(), 0, _HairColor
, _EyesColor
);
359 //-----------------------------------------------
361 // Compute the equipmenent worn.
362 //-----------------------------------------------
363 void CPlayerR2CL::equip(SLOTTYPE::EVisualSlot slot
, uint index
, uint color
)
365 // Get the sheet according to the visual slot
366 _Items
[slot
].Sheet
= SheetMngr
.getItem(slot
, index
);
367 if(_Items
[slot
].Sheet
)
369 const CItemSheet
*item
= _Items
[slot
].Sheet
;
371 // If the gender is a female get the right shape.
372 if(_Gender
== GSGENDER::female
)
373 equip(slot
, item
->getShapeFemale(), item
);
374 // Else get the default shape.
376 equip(slot
, item
->getShape(), item
);
378 // Check there is a shape.
379 UInstance pInst
= _Instances
[slot
].createLoadingFromCurrent();
382 // Set the right texture variation (quality).
383 pInst
.selectTextureSet((uint
)item
->MapVariant
);
384 _Instances
[slot
].TextureSet
= item
->MapVariant
;
386 // If Hair, color is for the head slot.
387 if(slot
== SLOTTYPE::HEAD_SLOT
&& item
->Family
!= ITEMFAMILY::ARMOR
)
388 applyColorSlot(_Instances
[slot
], skin(), 0, color
, _EyesColor
);
391 // Set the User Color.
392 if(item
->Color
== -1)
393 applyColorSlot(_Instances
[slot
], skin(), color
, _HairColor
, _EyesColor
);
394 // Set the Item Color.
395 else if(item
->Color
!= -2)
396 applyColorSlot(_Instances
[slot
], skin(), item
->Color
, _HairColor
, _EyesColor
);
397 // Else let the default color.
399 applyColorSlot(_Instances
[slot
], skin(), 0, _HairColor
, _EyesColor
);
403 // Default equipment.
406 nldebug("PL:equip(2):%d: VS '%d' default equipement used.", _Slot
, slot
);
407 //sint idx = SheetMngr.getVSIndex(_PlayerSheet->GenderInfos[_Gender].Items[slot], slot);
408 sint idx
= SheetMngr
.getVSIndex(getGenderInfo()->Items
[slot
], slot
);
412 if(SheetMngr
.getItem(slot
, (uint
)idx
))
414 // If the gender is a female get the right shape.
415 if(_Gender
== GSGENDER::female
)
416 equip(slot
, SheetMngr
.getItem(slot
, (uint
)idx
)->getShapeFemale());
417 // Else get the default shape.
419 equip(slot
, SheetMngr
.getItem(slot
, (uint
)idx
)->getShape());
425 //-----------------------------------------------
426 // updateVisualPropertyVpa :
427 // Update the Visual Property A.
428 // \todo GUIGUI : use gender enum.
429 //-----------------------------------------------
430 void CPlayerR2CL::updateVisualPropertyVpa(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
432 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
434 // Player will now have enough information to display the character.
435 _WaitForAppearance
= false;
438 SPropVisualA visualA
= *(SPropVisualA
*)(&prop
);
441 _Gender
= (GSGENDER::EGender
)_Sheet
->Gender
;
442 if(_Gender
!=GSGENDER::male
&& _Gender
!=GSGENDER::female
)
444 nlwarning("PL::updateVPVpa:%d: neither a male nor a female -> male selected.", _Slot
);
445 _Gender
= GSGENDER::male
;
448 // update title when gender changed
449 const string
replacement(STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw
,_Gender
== GSGENDER::female
));
450 if (!replacement
.empty())
453 _NameEx
= replacement
;
454 _Title
= replacement
;
456 // rebuild in scene interface
457 buildInSceneInterface();
460 // Setup _CharacterScalePos
461 _CharacterScalePos
= _Sheet
->CharacterScalePos
;
463 // Check if skeleton has changed
464 if (_CacheSkeletonShapeName
!= _Sheet
->getSkelFilename())
466 _CacheSkeletonShapeName
= _Sheet
->getSkelFilename();
468 // Clean the playlist.
470 _PlayList
->resetAllChannels();
472 // We can now build the skeleton so do it now.
473 skeleton(_CacheSkeletonShapeName
);
475 // Invalidate instances cache
476 for (uint i
= 0; i
< _Instances
.size(); ++i
)
478 _Instances
[i
].CurrentName
.clear();
479 _Instances
[i
].LoadingName
.clear();
482 _Face
.CurrentName
.clear();
483 _Face
.LoadingName
.clear();
485 // Check the skeleton.
486 if(skeleton() && !ClientCfg
.Light
)
488 // To re-link the skeleton to the mount if needed.
490 // Set the skeleton scale.
491 // \todo GUIGUI: mettre le scale aussi dans race_stats.
492 // Setup Lod Character skeleton, if skeleton exist
493 // Get Lod Character Id from the sheet.
494 sint clodId
= getLodCharacterId(*Scene
, _Sheet
->getLodCharacterName());
497 // Setup Lod Character shape and distance
498 skeleton()->setLodCharacterShape(clodId
);
499 skeleton()->setLodCharacterDistance(_Sheet
->LodCharacterDistance
);
505 equip(SLOTTYPE::CHEST_SLOT
, visualA
.PropertySubData
.JacketModel
, visualA
.PropertySubData
.JacketColor
);
507 equip(SLOTTYPE::LEGS_SLOT
, visualA
.PropertySubData
.TrouserModel
, visualA
.PropertySubData
.TrouserColor
);
509 equip(SLOTTYPE::ARMS_SLOT
, visualA
.PropertySubData
.ArmModel
, visualA
.PropertySubData
.ArmColor
);
511 equip(SLOTTYPE::HEAD_SLOT
, visualA
.PropertySubData
.HatModel
, visualA
.PropertySubData
.HatColor
);
512 // OBJECT in the RIGHT HAND
513 bool changeWeapon
= false;
514 const CItemSheet
* oldRightSheet
= _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
515 const CItemSheet
* newRightSheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
516 if((oldRightSheet
&& newRightSheet
&& oldRightSheet
->Id
!=newRightSheet
->Id
) || (!oldRightSheet
&& newRightSheet
))
520 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::RIGHT_HAND_SLOT
, visualA
.PropertySubData
.WeaponRightHand
);
521 // Equip the weapon(object/tool).
522 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
524 if(_Gender
== GSGENDER::female
)
525 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShapeFemale(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
527 equip(SLOTTYPE::RIGHT_HAND_SLOT
, _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
);
529 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
530 if (!itemInstance
.empty())
533 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
534 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
535 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(0);
536 //_Items[SLOTTYPE::RIGHT_HAND_SLOT].setTrailSize(visualA.PropertySubData.RTrail);
541 // No Valid item in the right hand.
542 equip(SLOTTYPE::RIGHT_HAND_SLOT
, "");
545 // OBJECT in the LEFT HAND
546 const CItemSheet
* oldLeftSheet
= _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
547 const CItemSheet
* newLeftSheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
548 if((oldLeftSheet
&& newLeftSheet
&& oldLeftSheet
->Id
!=newLeftSheet
->Id
) || (!oldLeftSheet
&& newLeftSheet
))
553 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
= SheetMngr
.getItem(SLOTTYPE::LEFT_HAND_SLOT
, visualA
.PropertySubData
.WeaponLeftHand
);
554 // Equip the weapon(object/tool).
555 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
557 equip(SLOTTYPE::LEFT_HAND_SLOT
, _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
->getShape(), _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
);
558 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
559 if (!itemInstance
.empty())
562 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].enableAdvantageFX(itemInstance
);
563 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(0);
564 //_Items[SLOTTYPE::LEFT_HAND_SLOT].setTrailSize(2 * (uint) visualA.PropertySubData.LTrail);
569 // No Valid item in the left hand.
570 equip(SLOTTYPE::LEFT_HAND_SLOT
, "");
573 // Only create a face when there is no Helmet
574 if(_Items
[SLOTTYPE::HEAD_SLOT
].Sheet
== 0 || _Items
[SLOTTYPE::HEAD_SLOT
].Sheet
->Family
!= ITEMFAMILY::ARMOR
)
576 CItemSheet
*faceItem
= getItem(*getGenderInfo(), SLOTTYPE::FACE_SLOT
);
581 if(_Gender
== GSGENDER::female
)
582 sFaceName
= faceItem
->getShapeFemale();
584 sFaceName
= faceItem
->getShape();
586 if (((!_Face
.Loading
.empty()) && (_Face
.LoadingName
!= sFaceName
)) ||
587 ((!_Face
.Current
.empty()) && (_Face
.CurrentName
!= sFaceName
)) ||
588 (_Face
.Current
.empty()))
590 if (!_Face
.Loading
.empty())
592 Scene
->deleteInstance(_Face
.Loading
);
593 _Face
.Loading
= NULL
;
594 _Face
.LoadingName
= sFaceName
;
596 _Face
.Loading
= Scene
->createInstance(sFaceName
);
597 if (!_Face
.Loading
.empty())
599 _Face
.LoadingName
= sFaceName
;
600 if(!skeleton()->bindSkin(_Face
.Loading
))
601 nlwarning("PL::updateVPVpa:%d: Cannot bind the face.", _Slot
);
602 _Face
.Loading
.hide();
603 // set it async for texture
604 _Face
.Loading
.enableAsyncTextureMode(true);
607 nlwarning("PL::updateVPVpa:%d: Cannot create the face.", _Slot
);
609 _Face
.TextureSet
= faceItem
->MapVariant
;
610 applyColorSlot(_Face
, skin(), 0, visualA
.PropertySubData
.HatColor
, 0); // Set a default ruflaket color.
613 nlwarning("PL::updateVPVpa:%d: Face Item '%s' does not exist.", _Slot
,
614 getGenderInfo()->Items
[SLOTTYPE::FACE_SLOT
].c_str());
618 // There is a helmet !
619 if (!_Face
.Loading
.empty())
620 Scene
->deleteInstance(_Face
.Loading
);
621 _Face
.Loading
= NULL
;
622 _Face
.LoadingName
.clear();
623 if (!_Face
.Current
.empty())
624 Scene
->deleteInstance(_Face
.Current
);
625 _Face
.Current
= NULL
;
626 _Face
.CurrentName
.clear();
628 // Now we have a skeleton, we can update VpB and VpC.
631 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPB
);
632 vB
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
633 propName
= toString("SERVER:Entities:E%d:P%d", _Slot
, CLFECOMMON::PROPERTY_VPC
);
634 vC
= NLGUI::CDBManager::getInstance()->getDbProp(propName
)->getValue64();
635 updateVisualPropertyVpb(0, vB
);
636 updateVisualPropertyVpc(0, vC
);
638 // Attach The Light if there is one.
639 if(!_Light
.empty() && _NameBoneId
!=-1)
640 _Skeleton
.stickObject(_Light
, _NameBoneId
);
644 // Compute the new animation set to use (due to weapons).
647 // Set the animation to idle.
648 setAnim(CAnimationStateSheet::Idle
);
653 nlwarning("PL::updateVPVpa:%d: Skeleton not allocated.", _Slot
);
654 }// updateVisualPropertyVpa //
656 //-----------------------------------------------
657 // updateVisualPropertyVpb :
658 // Update the Visual Property B.
659 //-----------------------------------------------
660 void CPlayerR2CL::updateVisualPropertyVpb(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
663 SPropVisualB visualB
= *(SPropVisualB
*)(&prop
);
665 if(_Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
)
667 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::RIGHT_HAND_SLOT
].Current
;
668 if (!itemInstance
.empty())
671 if ( _CurrentBehaviour
.Behaviour
!= MBEHAV::EXTRACTING
)
672 _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].setTrailSize(visualB
.PropertySubData
.RTrail
);
676 if(_Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
)
678 NL3D::UInstance itemInstance
= (!_Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
.empty()) ? _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Loading
: _Instances
[SLOTTYPE::LEFT_HAND_SLOT
].Current
;
679 if (!itemInstance
.empty())
682 _Items
[SLOTTYPE::LEFT_HAND_SLOT
].setTrailSize(2 * (uint
) visualB
.PropertySubData
.LTrail
);
689 equip(SLOTTYPE::HANDS_SLOT
, visualB
.PropertySubData
.HandsModel
, visualB
.PropertySubData
.HandsColor
);
691 equip(SLOTTYPE::FEET_SLOT
, visualB
.PropertySubData
.FeetModel
, visualB
.PropertySubData
.FeetColor
);
694 nlinfo("PL::updateVPVpb:%d: Prop Vpb received before prop Vpa.", _Slot
);
695 }// updateVisualPropertyVpb //
697 //-----------------------------------------------
698 // updateVisualPropertyVpc :
699 // Update the Visual Property C.
700 // \todo GUIGUI : factorize tatoos with character creation
701 //-----------------------------------------------
703 void CPlayerR2CL::updateVisualPropertyVpc(const NLMISC::TGameCycle
&/* gameCycle */, const sint64
&prop
)
708 SPropVisualC visualC
= *(SPropVisualC
*)(&prop
);
711 _EyesColor
= visualC
.PropertySubData
.EyesColor
;
714 // must recreate the face asynchronously (because of color change / makeup change)
715 inst
= _Face
.createLoadingFromCurrent();
720 // change eyes color only
721 applyColorSlot(_Face
, _Face
.ACSkin
, _Face
.ACUser
, _Face
.ACHair
, visualC
.PropertySubData
.EyesColor
);
724 makeUp(inst
, visualC
.PropertySubData
.Tattoo
);
727 static const char *baseName
= "visage_00";
730 CGenderInfo
*pGI
= getGenderInfo();
734 MTmin
= pGI
->BlendShapeMin
[0];
735 MTmax
= pGI
->BlendShapeMax
[0];
736 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
737 inst
.setBlendShapeFactor(baseName
+ toString(0), (float)(visualC
.PropertySubData
.MorphTarget1
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
739 MTmin
= pGI
->BlendShapeMin
[1];
740 MTmax
= pGI
->BlendShapeMax
[1];
741 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
742 inst
.setBlendShapeFactor(baseName
+ toString(1), (float)(visualC
.PropertySubData
.MorphTarget2
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
744 MTmin
= pGI
->BlendShapeMin
[2];
745 MTmax
= pGI
->BlendShapeMax
[2];
746 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
747 inst
.setBlendShapeFactor(baseName
+ toString(2), (float)(visualC
.PropertySubData
.MorphTarget3
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
749 MTmin
= pGI
->BlendShapeMin
[3];
750 MTmax
= pGI
->BlendShapeMax
[3];
751 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
752 inst
.setBlendShapeFactor(baseName
+ toString(3), (float)(visualC
.PropertySubData
.MorphTarget4
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
754 MTmin
= pGI
->BlendShapeMin
[4];
755 MTmax
= pGI
->BlendShapeMax
[4];
756 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
757 inst
.setBlendShapeFactor(baseName
+ toString(4), (float)(visualC
.PropertySubData
.MorphTarget5
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
759 MTmin
= pGI
->BlendShapeMin
[5];
760 MTmax
= pGI
->BlendShapeMax
[5];
761 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
762 inst
.setBlendShapeFactor(baseName
+ toString(5), (float)(visualC
.PropertySubData
.MorphTarget6
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
764 MTmin
= pGI
->BlendShapeMin
[6];
765 MTmax
= pGI
->BlendShapeMax
[6];
766 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
767 inst
.setBlendShapeFactor(baseName
+ toString(6), (float)(visualC
.PropertySubData
.MorphTarget7
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
769 MTmin
= pGI
->BlendShapeMin
[7];
770 MTmax
= pGI
->BlendShapeMax
[7];
771 if (!ClientCfg
.BlendShapePatched
) { MTmin
= 0.0f
; MTmax
= 100.0f
; }
772 inst
.setBlendShapeFactor(baseName
+ toString(7), (float)(visualC
.PropertySubData
.MorphTarget8
) / 7.f
* (MTmax
-MTmin
) + MTmin
, true);
776 float characterHeight
= (float)((sint8
)(visualC
.PropertySubData
.CharacterHeight
)-7)/7.f
;
777 float torsoWidth
= (float)((sint8
)(visualC
.PropertySubData
.TorsoWidth
)-7)/7.f
;
778 float armsWidth
= (float)((sint8
)(visualC
.PropertySubData
.ArmsWidth
)-7)/7.f
;
779 float legsWidth
= (float)((sint8
)(visualC
.PropertySubData
.LegsWidth
)-7)/7.f
;
780 float breastSize
= (float)((sint8
)(visualC
.PropertySubData
.BreastSize
)-7)/7.f
;
781 float heightScale
, baseHeightScale
;
782 // TODO : manage breast size
783 GabaritSet
.applyGabarit(*skeleton(), _Gender
, people(), characterHeight
, torsoWidth
, armsWidth
, legsWidth
, breastSize
, &heightScale
);
784 baseHeightScale
= GabaritSet
.getRefHeightScale(_Gender
, people());
786 if(baseHeightScale
!= 0.f
)
787 _CustomScalePos
= heightScale
/baseHeightScale
;
790 _CustomScalePos
= 1.f
;
791 nlwarning("PL::updateVPVpc:'%d': baseHeight == 0.", _Slot
);
795 nlinfo("PL:updateVPVpc:'%d': Prop Vpc received before prop Vpa.", _Slot
);
796 }// updateVisualPropertyVpc //
799 //-----------------------------------------------
801 // Get The Entity Skin
802 //-----------------------------------------------
803 sint CPlayerR2CL::skin() const // virtual
805 return _PlayerSheet->Skin;
809 //-----------------------------------------------
811 // Return the People for the entity.
812 //-----------------------------------------------
813 EGSPD::CPeople::TPeople CPlayerR2CL::people() const// virtual
816 return _PlayerSheet->People;
818 return EGSPD::CPeople::Unknown;
822 //-----------------------------------------------
824 // Setup the People for the entity.
825 //-----------------------------------------------
826 void CPlayerR2CL::setPeople(EGSPD::CPeople::TPeople people)
830 //-----------------------------------------------
833 //-----------------------------------------------
834 void CPlayerR2CL::drawName(const NLMISC::CMatrix
&mat
) // virtual
837 if(!getEntityName().empty())
838 TextContext
->render3D(mat
, getEntityName());
842 //-----------------------------------------------
844 // Update eyes blink. For the moment, called by updatePos.
845 //-----------------------------------------------
846 CEntityCL::SInstanceCL
*CPlayerR2CL::getFace()
848 // Implemented in CPlayerR2CL
852 //-----------------------------------------------
854 // Method to return the attack radius of an entity (take the scale into account).
855 //-----------------------------------------------
856 double CPlayerR2CL::attackRadius() const // virtual
861 //-----------------------------------------------
862 // Return the position the attacker should have to combat according to the attack angle.
863 // \param ang : 0 = the front, >0 and <Pi = left side, <0 and >-Pi = right side.
864 //-----------------------------------------------
865 CVectorD
CPlayerR2CL::getAttackerPos(double ang
, double dist
) const
867 // Compute the local angle
868 ang
= computeShortestAngle(atan2(front().y
, front().x
), ang
);
873 // Compute the local position.
875 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.
876 p
.y
= 0.5 * cos(ang
) + dist
*cos(ang
);
879 // Compute the world position.
880 // Create the target matrix.
881 CVector vj
= front();
886 bodyBase
.setRot(vi
,vj
,vk
,true);
887 bodyBase
.setPos(pos());
889 // Get the destination in the world.
891 }// getAttackerPos //
897 //-----------------------------------------------
898 // updateAsyncTexture
899 //-----------------------------------------------
900 float CPlayerR2CL::updateAsyncTexture()
903 float distToCam
= CCharacterCL::updateAsyncTexture();
905 // Check all instance to know if they need to start async load their textures
906 if(!_Face
.Loading
.empty())
909 if(_Face
.Loading
.isAsyncTextureDirty())
911 // reset instance state.
912 _Face
.Loading
.setAsyncTextureDirty(false);
913 // must start loading for this isntance
914 _Face
.Loading
.startAsyncTextureLoading();
915 // the entity is now currently loading.
916 _PlayerCLAsyncTextureLoading
= true;
917 // The LodTexture need to be recomputed
918 _LodTextureDirty
= true;
923 // Update Async Texture loading of all instances.
924 if(_PlayerCLAsyncTextureLoading
)
926 bool allLoaded
= true;
927 // update loading for all instances.
928 if(!_Face
.Loading
.empty())
930 // update async texture loading
931 allLoaded
= allLoaded
&& _Face
.Loading
.isAsyncTextureReady();
934 // if all are loaded, then End! don't need to check all instances every frame.
937 _PlayerCLAsyncTextureLoading
= false;
938 _Face
.updateCurrentFromLoading(_Skeleton
);
943 // For LOD texture, must update the "texture distance"
944 if(!_Face
.Current
.empty())
946 // update async texture loading
947 _Face
.Current
.setAsyncTextureDistance(distToCam
);
953 //-----------------------------------------------
955 //-----------------------------------------------
956 void CPlayerR2CL::updateLodTexture()
958 // if need to recompute, and if Async loading ended
959 if( _LodTextureDirty
&& !_PlayerCLAsyncTextureLoading
)
960 // check parent and upadte lod
961 CCharacterCL::updateLodTexture();
964 //-----------------------------------------------
966 // Return the basic max speed for the entity in meter per sec
967 //-----------------------------------------------
968 double CPlayerR2CL::getMaxSpeed() const// virtual
975 //---------------------------------------------------
977 // Display Debug Information.
978 //---------------------------------------------------
979 void CPlayerR2CL::displayDebug(float x
, float &y
, float lineStep
) // virtual
981 CCharacterCL::displayDebug(x
, y
, lineStep
);
989 //---------------------------------------------------
991 // Read/Write Variables from/to the stream.
992 //---------------------------------------------------
993 void CPlayerR2CL::readWrite(NLMISC::IStream
&f
)
995 CCharacterCL::readWrite(f
);
1000 // const CPlayerSheet *_Sheet;
1001 // const CRaceStatsSheet *_PlayerSheet;
1002 // NL3D::UInstance _Face;
1003 f
.serial(_DefaultChest
);
1004 f
.serial(_DefaultLegs
);
1005 f
.serial(_DefaultArms
);
1006 f
.serial(_DefaultHands
);
1007 f
.serial(_DefaultFeet
);
1008 f
.serial(_DefaultHair
);
1009 f
.serial(_HairColor
);
1010 f
.serial(_EyesColor
);
1011 f
.serial(_WaitForAppearance
);
1012 f
.serial(_PlayerCLAsyncTextureLoading
);
1014 // NL3D::UPointLight _Light;
1019 //---------------------------------------------------
1021 // To call after a read from a stream to re-initialize the entity.
1022 //---------------------------------------------------
1023 void CPlayerR2CL::load() // virtual
1025 CInterfaceManager
*IM
= CInterfaceManager::getInstance ();
1027 // If the entity should be in the world already
1028 if(_First_Pos
== false)
1030 // Insert the primitive into the world.
1032 _Primitive
->insertInWorldImage(dynamicWI
);
1033 // Insert the entity into PACS
1038 if(!_WaitForAppearance
)
1040 // Visual properties A
1041 sint64 prop
= NLGUI::CDBManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", _Slot
)+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA
))->getValue64();
1042 updateVisualPropertyVpa(0, prop
); // Vpa udapte vpb and vpc too.
1046 // *********************************************************************************************
1048 const char *CPlayerR2CL::getBoneNameFromBodyPart(BODY::TBodyPart part, BODY::TSide side) const
1050 if (!_PlayerSheet) return CCharacterCL::getBoneNameFromBodyPart(part, side);
1051 return _PlayerSheet->BodyToBone.getBoneName(part, side);
1054 // *********************************************************************************************
1055 const CItemSheet
*CPlayerR2CL::getRightHandItemSheet() const
1057 return _Items
[SLOTTYPE::RIGHT_HAND_SLOT
].Sheet
;
1060 // *********************************************************************************************
1061 const CItemSheet
*CPlayerR2CL::getLeftHandItemSheet() const
1063 return _Items
[SLOTTYPE::LEFT_HAND_SLOT
].Sheet
;
1066 // *********************************************************************************************
1067 /*const CAttack *CPlayerR2CL::getAttack(const CAttackIDSheet &id) const
1069 if (!_PlayerSheet) return NULL;
1070 return CCharacterCL::getAttack(id, _PlayerSheet->AttackLists);
1073 // *********************************************************************************************
1074 float CPlayerR2CL::getScaleRef() const
1076 float fyrosRefScale
= GabaritSet
.getRefHeightScale(0, EGSPD::CPeople::Fyros
);
1077 if (fyrosRefScale
== 0) return 1.f
;
1078 return _CustomScalePos
* (GabaritSet
.getRefHeightScale(_Gender
, people()) / fyrosRefScale
);
1082 // *********************************************************************************************
1084 float CPlayerR2CL::getNamePosZ() const
1090 switch (_ModeWanted)
1094 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZLow;
1097 case MBEHAV::MOUNT_NORMAL:
1098 case MBEHAV::MOUNT_SWIM:
1099 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZHigh;
1103 namePosZ = _PlayerSheet->GenderInfos[_Gender].NamePosZNormal;
1107 return namePosZ * _CharacterScalePos * _CustomScalePos;
1110 // ***************************************************************************
1111 void CPlayerR2CL::doSetVisualSelectionBlink(bool bOnOff
, NLMISC::CRGBA emitColor
)
1115 _Face
.setEmissive(emitColor
);
1117 _Face
.restoreEmissive();
1120 CCharacterCL::doSetVisualSelectionBlink(bOnOff
, emitColor
);
1123 // ***************************************************************************
1124 void CPlayerR2CL::makeTransparent(bool t
)
1126 CCharacterCL::makeTransparent(t
);
1128 uint32 opaMin
= getOpacityMin();
1129 uint8 opacity
= (uint8
)(opaMin
+ (255-opaMin
) * (1.0 - _TranspFactor
));
1131 _Face
.makeInstanceTransparent(opacity
, (uint8
)opaMin
);
1132 }// makeTransparent //
1134 // ***************************************************************************
1135 void CPlayerR2CL::setDiffuse(bool onOff
, NLMISC::CRGBA diffuse
)
1137 CCharacterCL::setDiffuse(onOff
, diffuse
);
1138 _Face
.setDiffuse(onOff
, diffuse
);