// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . ///////////// // INCLUDE // ///////////// #include "stdpch.h" // First include for pre-compiled headers. // Georges #include "nel/georges/u_form_elm.h" // Application #include "character_sheet.h" // Game Share #include "game_share/georges_helper.h" /////////// // USING // /////////// using namespace std; using namespace NLGEORGES; using namespace NLMISC; // *************************************************************************** // Easy macro to translate value from georges #define TRANSLATE_VAL( _Var_, _key_ ) \ if(!item.getValueByName(_Var_, _key_)) \ debug( string("key '") + string(_key_) + string("' not found.") ); ///////////// // METHODS // ///////////// //----------------------------------------------- // CCharacterSheet : // Constructor. //----------------------------------------------- CCharacterSheet::CCharacterSheet() { CharacterScalePos = 1; Scale = 1.f; SoundFamily = 0; SoundVariation = 0; Type = CEntitySheet::FAUNA; Gender = 0; Race = EGSPD::CPeople::EndPeople; IdSkelFilename = 0; IdAnimSetBaseName = 0; IdAutomaton = 0; IdLodCharacterName = 0; LodCharacterDistance = 0.0f; IdFame = 0; DisplayOSD = true; DisplayInRadar = true; DisplayOSDName = true; DisplayOSDBars = true; DisplayOSDForceOver = false; Traversable = true; ClipRadius= 0.f; ClipHeight= 0.f; R2Npc = false; Selectable = false; Talkable = false; Attackable = false; Givable = false; Mountable = false; Turn = false; SelectableBySpace = false; HLState = LHSTATE::NONE; HairColor = 0; Skin = 0; EyesColor = 0; DistToFront = 0.0f; DistToBack = 0.0f; DistToSide = 0.0f; ColRadius = 0.0f; ColHeight = 0.0f; ColLength = 0.0f; ColWidth = 0.0f; MaxSpeed = 0.0f; NamePosZLow = 0.0f; NamePosZNormal = 0.0f; NamePosZHigh = 0.0f; IdStaticFX = 0; SpellCastingPrefix = 0; RegionForce = 0; ForceLevel = 0; Level = 0; }// CCharacterSheet // //----------------------------------------------- // readEquipment : // Read an equipment slot. //----------------------------------------------- void CCharacterSheet::readEquipment(const NLGEORGES::UFormElm &form, const string &key, CEquipment &slot) { // Get the item (or shape) name. string itemName; if(!form.getValueByName(itemName, string(key + ".Item").c_str() )) debug(NLMISC::toString("Key '%s.Item' not found.", key.c_str())); slot.IdItem = ClientSheetsStrings.add(NLMISC::toLower(itemName)); // Get the texture. if(!form.getValueByName(slot.Texture, string(key + ".Texture").c_str() )) debug(NLMISC::toString("Key '%s.Texture' not found.", key.c_str())); // Get the color. if(!form.getValueByName(slot.Color, string(key + ".Color").c_str() )) debug(NLMISC::toString("Key '%s.Color' not found.", key.c_str())); // Get the Bind point. string bindPointName; if(!form.getValueByName(bindPointName, string(key + ".Bind Point").c_str() )) debug(NLMISC::toString("Key '%s.Bind Point' not found.", key.c_str())); slot.IdBindPoint = ClientSheetsStrings.add(bindPointName); }// readEquipment // //----------------------------------------------- // build : // Build the sheet from an external script. //----------------------------------------------- void CCharacterSheet::build(const NLGEORGES::UFormElm &item) { // First Name // string FirstName; // if(!item.getValueByName(FirstName, "Basics.First Name")) // debug("Key 'Basics.First Name' not found."); // IdFirstName = ClientSheetsStrings.add(FirstName); // // Character Name // string LastName; // if(!item.getValueByName(LastName, "Basics.CharacterName")) // debug("Key 'Basics.CharacterName' not found."); // IdLastName = ClientSheetsStrings.add(LastName); // Fame Name string FameName; if(!item.getValueByName(FameName, "Basics.Fame")) debug("Key 'Basics.Fame' not found."); IdFame = ClientSheetsStrings.add(FameName); // Character Race string raceStr; if(!item.getValueByName(raceStr, "Basics.Race")) debug("Key 'Basics.Race' not found."); else if (!raceStr.empty()) { Race = EGSPD::CPeople::fromString(raceStr); if (EGSPD::CPeople::toString(Race) != raceStr) { debug(toString("In sheet '%s': invalid race '%s', race is set to unknow", Id.toString().c_str(), raceStr.c_str())); } } else Race = EGSPD::CPeople::Unknown; // Player Gender. if(!item.getValueByName(Gender, "Basics.Gender")) debug("Key 'Gender' not found."); // Load the skel. string SkelFilename; if(!item.getValueByName(SkelFilename, "3d data.Skel")) debug("Key '3d data.Skel' not found."); IdSkelFilename = ClientSheetsStrings.add(SkelFilename); // BODY readEquipment(item, "Basics.Equipment.Body", Body); // LEGS readEquipment(item, "Basics.Equipment.Legs", Legs); // ARMS readEquipment(item, "Basics.Equipment.Arms", Arms); // HANDS readEquipment(item, "Basics.Equipment.Hands", Hands); // FEET readEquipment(item, "Basics.Equipment.Feet", Feet); // HEAD readEquipment(item, "Basics.Equipment.Head", Head); // FACE readEquipment(item, "Basics.Equipment.Face", Face); // IN RIGHT HAND readEquipment(item, "Basics.Equipment.HandR", ObjectInRightHand); // IN LEFT HAND readEquipment(item, "Basics.Equipment.HandL", ObjectInLeftHand); // Get the animation set Base Name. string AnimSetBaseName; if(item.getValueByName(AnimSetBaseName, "3d data.AnimSetBaseName")) { if(AnimSetBaseName.empty()) debug("AnimSetBaseName is Empty."); else AnimSetBaseName = NLMISC::toLower(AnimSetBaseName); // Force the CASE in UPPER to not be CASE SENSITIVE. } else debug("Key '3d data.AnimSetBaseName' not found."); IdAnimSetBaseName = ClientSheetsStrings.add(AnimSetBaseName); // AUTOMATON TYPE string Automaton; if(item.getValueByName(Automaton, "3d data.Automaton")) { // Check there is an automaton if(Automaton.empty()) debug("Automaton is Empty."); // Lower Case else Automaton = NLMISC::toLower(Automaton); } // Key not Found else debug("Key '3d data.Automaton' not found."); IdAutomaton = ClientSheetsStrings.add(Automaton); // Display OSD if(!item.getValueByName(DisplayOSD, "3d data.DisplayOSD")) { debug("Key '3d data.DisplayOSD' not found -> set 'true'."); DisplayOSD = true; } // New Bot Object flags TRANSLATE_VAL(DisplayInRadar, "3d data.DisplayInRadar"); TRANSLATE_VAL(DisplayOSDName,"3d data.DisplayName"); TRANSLATE_VAL(DisplayOSDBars,"3d data.DisplayBars"); TRANSLATE_VAL(DisplayOSDForceOver, "3d data.DisplayAlwaysNameOver"); TRANSLATE_VAL(Traversable, "Collision.NotTraversable"); // invert Traversable= !Traversable; // CREATURE PROPERTIES (Possible Actions) // Is the character selectable ? if(!item.getValueByName(Selectable, "Properties.Selectable")) { debug("Key 'Properties.Selectable' not found -> set 'false'."); Selectable = false; } // Is the character Talkable ? if(!item.getValueByName(Talkable, "Properties.Talkable")) { debug("Key 'Properties.Talkable' not found -> set 'false'."); Talkable = false; } // Is the character Attackable ? if(!item.getValueByName(Attackable, "Properties.Attackable")) { debug("Key 'Properties.Attackable' not found -> set 'false'."); Attackable = false; } // Is the character Givable ? if(!item.getValueByName(Givable, "Properties.Givable")) { debug("Key 'Properties.Givable' not found -> set 'false'."); Givable = false; } // Is the character Mountable ? if(!item.getValueByName(Mountable, "Properties.Mountable")) { debug("Key 'Properties.Mountable' not found -> set 'false'."); Mountable = false; } // Is the character allowed to turn ? if(!item.getValueByName(Turn, "Properties.Turn")) { debug("Key 'Properties.Turn' not found -> set 'true'."); Turn = true; } // Is the character selectable by pressing space (default) ? if(!item.getValueByName(SelectableBySpace, "Properties.SelectableBySpace")) { debug("Key 'Properties.SelectableBySpace' not found -> set 'true'."); SelectableBySpace = true; } //Get the harvest/loot state string harvestLootStr; if( !item.getValueByName(harvestLootStr, "Properties.LootHarvestState") ) debug("Key 'roperties.LootHarvestState' not found."); else HLState = LHSTATE::stringToLHState(harvestLootStr); // Get the Hair Color. if(!item.getValueByName(HairColor, "3d data.HairColor")) debug("Key '3d data.HairColor' not found."); // Get the Skin Texture. if(!item.getValueByName(Skin, "3d data.Skin")) debug("Key '3d data.Skin' not found."); // Get the Eyes Color. if(!item.getValueByName(EyesColor, "3d data.EyesColor")) debug("Key '3d data.EyesColor' not found."); // Load Lod character name string LodCharacterName; if(!item.getValueByName(LodCharacterName, "3d data.LodCharacterName")) debug("Key '3d data.LodCharacterName' not found."); IdLodCharacterName = ClientSheetsStrings.add(LodCharacterName); // Load Lod character apparition distance if(!item.getValueByName(LodCharacterDistance, "3d data.LodCharacterDistance")) debug("Key '3d data.LodCharacterDistance' not found."); // value to scale the "pos" channel of the animation of the player. if(!item.getValueByName(CharacterScalePos, "3d data.CharacterScalePos")) debug("Key '3d data.CharacterScalePos' not found."); // value to scale the "pos" channel of the animation of the player. if(!item.getValueByName(Scale, "3d data.Scale")) debug("Key '3d data.Scale' not found."); else { if(Scale <= 0.0f) { nlwarning("CCharacterSheet:build: Scale(%f) <= 0.0 so fix scale to 1.0", Scale); Scale = 1.0f; } } // Load name positions on Z axis if(!item.getValueByName(NamePosZLow, "3d data.NamePosZLow")) { NamePosZLow = 0.f; debug("Key '3d data.NamePosZLow' not found."); } if(!item.getValueByName(NamePosZNormal, "3d data.NamePosZNormal")) { NamePosZNormal = 0.f; debug("Key '3d data.NamePosZNormal' not found."); } if(!item.getValueByName(NamePosZHigh, "3d data.NamePosZHigh")) { NamePosZHigh = 0.f; debug("Key '3d data.NamePosZHigh' not found."); } // value to change sound familly if(!item.getValueByName(SoundFamily, "3d data.SoundFamily")) debug("Key '3d data.SoundFamily' not found."); // value to change sound variation if(!item.getValueByName(SoundVariation, "3d data.SoundVariation")) debug("Key '3d data.SoundVariation' not found."); // Get the dist fromm Bip to Mid float tmpBip01ToMid; if(!item.getValueByName(tmpBip01ToMid, "Collision.Dist Bip01 to mid")) { tmpBip01ToMid = 0.f; debug("Key 'Collision.Dist Bip01 to mid' not found."); } // Get the distance from the bip01 to the front. if(!item.getValueByName(DistToFront, "Collision.Dist Bip01 to front")) { DistToFront = 1.f; debug("Key 'Collision.Dist Bip01 to front' not found."); } // Get the distance from the bip01 to the front. if(!item.getValueByName(DistToBack, "Collision.Dist Bip01 to back")) { DistToBack = 1.f; debug("Key 'Collision.Dist Bip01 to back' not found."); } // Get the creature Width. if(!item.getValueByName(ColWidth, "Collision.Width")) { ColWidth = 1.f; debug("Key 'Collision.Width' not found."); } DistToSide = ColWidth; DistToFront = DistToFront-tmpBip01ToMid; DistToBack = tmpBip01ToMid-DistToBack; DistToSide = DistToSide/2.f; // Get the creature collision Radius. if(!item.getValueByName(ColRadius, "Collision.CollisionRadius")) { ColRadius = 0.5f; debug("Key 'Collision.CollisionRadius' not found."); } // Get the creature collision Height. if(!item.getValueByName(ColHeight, "Collision.Height")) { ColHeight = 2.f; debug("Key 'Collision.Height' not found."); } // Get the creature collision Length. if(!item.getValueByName(ColLength, "Collision.Length")) { ColLength = 1.f; debug("Key 'Collision.Length' not found."); } // CLIP if(!item.getValueByName(ClipRadius, "Collision.ClipRadius")) { ClipRadius = 0.f; debug("Key 'Collision.ClipRadius' not found."); } if(!item.getValueByName(ClipHeight, "Collision.ClipHeight")) { ClipHeight = 0.f; debug("Key 'Collision.ClipHeight' not found."); } // SPEED // // Get the creature Max Speed (Run). if(!item.getValueByName(MaxSpeed, "Basics.MovementSpeeds.RunSpeed")) { MaxSpeed = 10.f; debug("Key 'Basics.MovementSpeeds.RunSpeed' not found."); } const UFormElm *elm = NULL; // Get all alternative Clothes. static const char alternativeClothesKey[] = "Basics.Alternative Clothes"; if(item.getNodeByName(&elm, alternativeClothesKey) && elm) { // Check array. if(elm->isArray()) { // Get Array Size uint altClothesArraySize; if(elm->getArraySize(altClothesArraySize)) { // Get values. string altClothes; for(uint i=0; igetArrayValue(altClothes, i)) { if(!altClothes.empty()) { TSStringId IdAltClothes = ClientSheetsStrings.add(altClothes); IdAlternativeClothes.push_back(IdAltClothes); } else debug(toString("'%s' field empty for the index '%d'.", alternativeClothesKey, i)); } else debug(toString("'%s' cannot get the array value for the index '%d'.", alternativeClothesKey, i)); } } else debug(toString("'%s' cannot get the array size.", alternativeClothesKey)); } else debug(toString("'%s' is not an array.", alternativeClothesKey)); } else debug(toString("'%s' key not found.", alternativeClothesKey)); // Hair item list static const char hairItemList[] = "3d data.HairItem"; if(item.getNodeByName(&elm, hairItemList) && elm) { // Check array. if(elm->isArray()) { // Get Array Size uint hairItemArraySize; if(elm->getArraySize(hairItemArraySize)) { if(hairItemArraySize > 0) { // Adjust the array size. HairItemList.resize(hairItemArraySize); // Get values. for(uint i=0; igetArrayNodeName(arrayNodeName, i)) readEquipment(item, string(hairItemList)+"["+toString(i)+"]", HairItemList[i]); } } } else debug(toString("'%s' cannot get the array size.", hairItemList)); } else debug(toString("'%s' is not an array.", hairItemList)); } else debug(toString("'%s' key not found.", hairItemList)); // ground fxs static const char groundFXList[] = "3d data.GroundFX"; if(item.getNodeByName(&elm, groundFXList) && elm) { // Check array. if(elm->isArray()) { // Get Array Size uint groundFXArraySize; if(elm->getArraySize(groundFXArraySize)) { if(groundFXArraySize > 0) { // Adjust the array size. GroundFX.reserve(groundFXArraySize); // Get values. for(uint i=0; i< groundFXArraySize; ++i) { const UFormElm *node; if (elm->getArrayNode(&node, i) && node != NULL) { CGroundFXSheet gfs; if (!gfs.build(*node)) { nlwarning("Error while building node %d", (int) i); } else { uint k; for(k = 0; k < GroundFX.size(); ++k) { if (GroundFX[k].GroundID == gfs.GroundID) { debug("Duplicated material"); GroundFX[k] = gfs; break; } } if (k == GroundFX.size()) { GroundFX.push_back(gfs); } } } } } } else debug(toString("'%s' cannot get the array size.", groundFXList)); } else debug(toString("'%s' is not an array.", groundFXList)); } else debug(toString("'%s' key not found.", groundFXList)); // sort fxs by ground type std::sort(GroundFX.begin(), GroundFX.end()); // Load Ground FX string staticFx; if(!item.getValueByName(staticFx, "3d data.FX")) debug("Key '3d data.FX' not found."); IdStaticFX = ClientSheetsStrings.add(staticFx); BodyToBone.build(item, "Localisation."); // Attack lists for(uint k = 0; k < NumAttackLists; ++k) { std::string attackListName; if(item.getValueByName(attackListName, toString("attack_list%d", (int) k).c_str()) && !attackListName.empty()) { AttackLists.push_back(ClientSheetsStrings.add(attackListName)); } } if(!item.getValueByName(RegionForce, "Basics.RegionForce")) { RegionForce = 0; debug("Key 'Basics.RegionForce' not found."); } if(!item.getValueByName(ForceLevel, "Basics.ForceLevel")) { ForceLevel = 0; debug("Key 'Basics.Regio Force' not found."); } if(!item.getValueByName(Level, "Basics.XPLevel")) { Level = 0; debug("Key 'Basics.XPLevel' not found."); } // offset for projectiles const UFormElm *pElt; nlverify (item.getNodeByName (&pElt, "3d data.ProjectileCastRay")); uint arraySize; if (pElt != NULL) { nlverify (pElt->getArraySize (arraySize)); ProjectileCastRay.reserve(arraySize); for (uint32 i = 0; i < arraySize; ++i) { const UFormElm *pEltOfList; if (pElt->getArrayNode (&pEltOfList, i) && pEltOfList) { const UFormElm *pEltPos; const UFormElm *pEltOrigin; if (pEltOfList->getNodeByName(&pEltPos, "Pos") && pEltOfList->getNodeByName(&pEltOrigin, "Origin")) { CCharacterSheet::CCastRay cr; if (pEltPos->getValueByName(cr.Pos.x, "X") && pEltPos->getValueByName(cr.Pos.y, "Y") && pEltPos->getValueByName(cr.Pos.z, "Z") && pEltOrigin->getValueByName(cr.Origin.x, "X") && pEltOrigin->getValueByName(cr.Origin.y, "Y") && pEltOrigin->getValueByName(cr.Origin.z, "Z") ) { ProjectileCastRay.push_back(cr); } } } } } if(!item.getValueByName(R2Npc, "r2_npc")) { R2Npc = false; debug("Key 'R2Npc' not found."); } }// build // //----------------------------------------------- // serial : // Serialize character sheet into binary data file. //----------------------------------------------- void CCharacterSheet::serial(class NLMISC::IStream &f) throw(NLMISC::EStream) { // Serialize class components. // ClientSheetsStrings.serial(f, IdFirstName); // ClientSheetsStrings.serial(f, IdLastName); f.serial(Gender); f.serialEnum(Race); ClientSheetsStrings.serial(f, IdSkelFilename); ClientSheetsStrings.serial(f, IdAnimSetBaseName); ClientSheetsStrings.serial(f, IdAutomaton); f.serial(Scale); f.serial(SoundFamily); f.serial(SoundVariation); ClientSheetsStrings.serial(f, IdLodCharacterName); f.serial(LodCharacterDistance); f.serial(Selectable); f.serial(Talkable); f.serial(Attackable); f.serial(Givable); f.serial(Mountable); f.serial(Turn); f.serial(SelectableBySpace); f.serialEnum(HLState); f.serial(CharacterScalePos); f.serial(NamePosZLow); f.serial(NamePosZNormal); f.serial(NamePosZHigh); ClientSheetsStrings.serial(f, IdFame); f.serial(Body); f.serial(Legs); f.serial(Arms); f.serial(Hands); f.serial(Feet); f.serial(Head); f.serial(Face); f.serial(ObjectInRightHand); f.serial(ObjectInLeftHand); f.serial(HairColor); f.serial(Skin); f.serial(EyesColor); f.serial(DistToFront); f.serial(DistToBack); f.serial(DistToSide); // Collisions f.serial(ColRadius); f.serial(ColHeight); f.serial(ColLength); f.serial(ColWidth); f.serial(MaxSpeed); // Clip f.serial(ClipRadius); f.serial(ClipHeight); // Alternative Look ClientSheetsStrings.serial(f, IdAlternativeClothes); // Hair Item List f.serialCont(HairItemList); // Ground fxs f.serialCont(GroundFX); // Display OSD f.serial(DisplayOSD); // static FX ClientSheetsStrings.serial(f, IdStaticFX); // body to bone f.serial(BodyToBone); // attack list uint32 size = (uint32)AttackLists.size(); f.serial(size); AttackLists.resize(size); // for(uint k = 0; k < size; ++k) { ClientSheetsStrings.serial(f, AttackLists[k]); } // bot object flags f.serial(DisplayInRadar); f.serial(DisplayOSDName); f.serial(DisplayOSDBars); f.serial(DisplayOSDForceOver); f.serial(Traversable); f.serial(RegionForce); f.serial(ForceLevel); f.serial(Level); f.serialCont(ProjectileCastRay); f.serial(R2Npc); }// serial // // *************************************************************************** void CCharacterSheet::getWholeEquipmentList(std::vector &equipList) const { equipList.clear(); equipList.push_back(&Body); equipList.push_back(&Legs); equipList.push_back(&Arms); equipList.push_back(&Hands); equipList.push_back(&Feet); equipList.push_back(&Head); equipList.push_back(&Face); equipList.push_back(&ObjectInRightHand); equipList.push_back(&ObjectInLeftHand); for(uint i=0;i