khanat-opennel-code/code/ryzom/client/src/client_sheets/race_stats_sheet.cpp

320 lines
9 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// 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 <http://www.gnu.org/licenses/>.
/////////////
// INCLUDE //
/////////////
#include "stdpch.h" // First include for pre-compiled headers.
// Application
#include "race_stats_sheet.h"
// Game Share
#include "game_share/characs_build.h"
// Georges
#include "nel/georges/u_form_elm.h"
///////////
// USING //
///////////
using namespace std;
/////////////
// METHODS //
/////////////
const string CGenderInfo::UnknownItemName = "";
// description of a visual slot that must be read by CGenderInfo
struct CSlotInfo
{
SLOTTYPE::EVisualSlot Slot;
const char *Suffix; // suffix in the sheet
};
static const CSlotInfo UsedVisualSlots[] =
{
{ SLOTTYPE::CHEST_SLOT, "DefaultChest" },
{ SLOTTYPE::LEGS_SLOT, "DefaultLegs" },
{ SLOTTYPE::HEAD_SLOT, "DefaultHair" },
{ SLOTTYPE::ARMS_SLOT, "DefaultArms" },
{ SLOTTYPE::FACE_SLOT, "DefaultFace" },
{ SLOTTYPE::HANDS_SLOT, "DefaultHands" },
{ SLOTTYPE::FEET_SLOT, "DefaultFeet" }
};
static const uint NumUsedVisualSlots = sizeof(UsedVisualSlots) / sizeof(UsedVisualSlots[0]);
/////////////////
// CGenderInfo //
/////////////////
//===============================================================
CGenderInfo::CGenderInfo()
{
CharacterScalePos = 1;
for (uint32 i = 0; i < 8; ++i)
{
BlendShapeMin[i] = 0.0f;
BlendShapeMax[i] = 100.0f;
}
NamePosZLow = 0.f;
NamePosZNormal = 0.f;
NamePosZHigh = 0.f;
}
//===============================================================
void CGenderInfo::build(const NLGEORGES::UFormElm &item, const std::string &prefix)
{
// Get equipment items
// get slots
for(uint k = 0; k < NumUsedVisualSlots; ++k)
{
if (!item.getValueByName(Items[UsedVisualSlots[k].Slot], (prefix + UsedVisualSlots[k].Suffix).c_str()))
{
nlwarning("Can't get %s from race_stats sheet", UsedVisualSlots[k].Suffix);
}
}
// Get skeleton
if (!item.getValueByName(Skelfilename, (prefix + "Skel").c_str()))
{
nlwarning("Can't get skeleton");
}
// get base animation name
if (!item.getValueByName(AnimSetBaseName, (prefix + "AnimSetBaseName").c_str()))
{
nlwarning("Can't get AnimSetBaseName");
}
// Load Lod character name
if(!item.getValueByName(LodCharacterName, (prefix + "LodCharacterName").c_str()))
nlwarning("CGenderInfo::build: Key 'LodCharacterName' not found.");
// Load Lod character apparition distance
if(!item.getValueByName(LodCharacterDistance, (prefix + "LodCharacterDistance").c_str()))
nlwarning("CGenderInfo::build: Key 'LodCharacterDistance' not found.");
// value to scale the "pos" channel of the animation of the player.
if(!item.getValueByName(CharacterScalePos, (prefix + "CharacterScalePos").c_str()))
nlwarning("CGenderInfo::build: Key 'CharacterScalePos' not found.");
for (uint32 i = 0; i < 8; ++i)
{
if(!item.getValueByName(BlendShapeMin[i], (prefix+"MorphTargetMin"+NLMISC::toString(i)).c_str()))
nlwarning("CGenderInfo::build: Key 'MorphTargetMin%d' not found.",i);
if(!item.getValueByName(BlendShapeMax[i], (prefix+"MorphTargetMax"+NLMISC::toString(i)).c_str()))
nlwarning("CGenderInfo::build: Key 'MorphTargetMax%d' not found.",i);
}
if(!item.getValueByName(NamePosZLow, (prefix + "NamePosZLow").c_str()))
nlwarning("CGenderInfo::build: Key 'NamePosZLow' not found.");
if(!item.getValueByName(NamePosZNormal, (prefix + "NamePosZNormal").c_str()))
nlwarning("CGenderInfo::build: Key 'NamePosZNormal' not found.");
if(!item.getValueByName(NamePosZHigh, (prefix + "NamePosZHigh").c_str()))
nlwarning("CGenderInfo::build: Key 'NamePosZHigh' not found.");
}
//===============================================================
void CGenderInfo::serial(class NLMISC::IStream &f) throw(NLMISC::EStream)
{
// serial used slots
for(uint k = 0; k < NumUsedVisualSlots; ++k)
{
f.serial(Items[UsedVisualSlots[k].Slot]);
}
f.serial(Skelfilename);
f.serial(AnimSetBaseName);
f.serial(LodCharacterName);
f.serial(LodCharacterDistance);
f.serial(CharacterScalePos);
f.serialCont(GroundFX);
for (uint32 i = 0; i < 8; ++i)
{
f.serial(BlendShapeMin[i]);
f.serial(BlendShapeMax[i]);
}
f.serial(NamePosZLow);
f.serial(NamePosZNormal);
f.serial(NamePosZHigh);
}
//-----------------------------------------------
// getItemName :
// Get the item name for a given slot.
//-----------------------------------------------
const string &CGenderInfo::getItemName(SLOTTYPE::EVisualSlot slot) const
{
// Check the slot.
if(slot >= SLOTTYPE::NB_SLOT)
{
// Bad Slot.
nlwarning("CGenderInfo::getItemName: slot '%d' invalid.", slot);
return UnknownItemName;
}
// Return the name of the default item for this slot.
return Items[slot];
}// getItemName //
/////////////////////
// CRaceStatsSheet //
/////////////////////
//===============================================================
CRaceStatsSheet::CRaceStatsSheet()
{
std::fill(CharacStartValue, CharacStartValue + CHARACTERISTICS::NUM_CHARACTERISTICS, 0);
// Initialize the type.
Type = CEntitySheet::RACE_STATS;
}
//===============================================================
void CRaceStatsSheet::build(const NLGEORGES::UFormElm &item)
{
GenderInfos[0].build(item, "DefaultEquipment.Male equipment.");
GenderInfos[1].build(item, "DefaultEquipment.Female equipment.");
// build base characs
loadCharacteristicsFromSheet(item, "Characteristics.", CharacStartValue);
// Get race
std::string race;
item.getValueByName(race, "Race");
People = EGSPD::CPeople::fromString(race);
// Get the skin to use.
if(!item.getValueByName(Skin, "Skin"))
nlwarning("CRaceStatsSheet::build: Cannot find the key 'Skin'.");
//
buildGroundFXs(item, "GroundFXMale", GenderInfos[0].GroundFX);
buildGroundFXs(item, "GroundFXFemale", GenderInfos[1].GroundFX);
// get Automaton Type
if(!item.getValueByName(Automaton, "Automaton"))
nlwarning("CRaceStatsSheet::build: Can't get 'Automaton'.");
BodyToBone.build(item, "Localisation.");
// Attack lists
for(uint k = 0; k < NumAttackLists; ++k)
{
std::string attackListName;
if(item.getValueByName(attackListName, NLMISC::toString("attack_list%d", (int) k).c_str()) && !attackListName.empty())
{
AttackLists.push_back(ClientSheetsStrings.add(attackListName));
}
}
}
//===============================================================
void CRaceStatsSheet::buildGroundFXs(const NLGEORGES::UFormElm &item, const std::string &name, std::vector<CGroundFXSheet> &dest)
{
// ground fxs
const NLGEORGES::UFormElm *elm;
if(item.getNodeByName(&elm, name.c_str()) && elm)
{
// Check array.
if(elm->isArray())
{
// Get Array Size
uint groundFXArraySize;
if(elm->getArraySize(groundFXArraySize))
{
if(groundFXArraySize > 0)
{
// Adjust the array size.
dest.reserve(groundFXArraySize);
// Get values.
for(uint i=0; i< groundFXArraySize; ++i)
{
const NLGEORGES::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 < dest.size(); ++k)
{
if (dest[k].GroundID == gfs.GroundID)
{
debug("Duplicated material");
dest[k] = gfs;
break;
}
}
if (k == dest.size())
{
dest.push_back(gfs);
}
}
}
}
}
}
else
debug(NLMISC::toString("'%s' cannot get the array size.", name.c_str()));
}
else
debug(NLMISC::toString("'%s' is not an array.", name.c_str()));
}
else
debug(NLMISC::toString("'%s' key not found.", name.c_str()));
// sort fxs by ground type
std::sort(dest.begin(), dest.end());
}
//===============================================================
void CRaceStatsSheet::serial(class NLMISC::IStream &f) throw(NLMISC::EStream)
{
for(uint k = 0; k < CHARACTERISTICS::NUM_CHARACTERISTICS; ++k)
{
f.serial(CharacStartValue[k]);
}
f.serial(GenderInfos[0], GenderInfos[1]);
if(f.isReading())
{
uint8 people;
f.serial(people);
People = (EGSPD::CPeople::TPeople)people;
}
else
{
uint8 people = (uint8)People;
f.serial(people);
}
f.serial(Skin); // The skin
f.serial(Automaton);
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]);
}
}