18 #include "precompiled.h"
32 #include <boost/random/uniform_int.hpp>
35 : m_ObjectManager(objectManager)
51 #define EL(x) int el_##x = XeroFile.GetElementID(#x)
52 #define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
107 std::vector<int> variantGroupSizes;
110 if (child.GetNodeName() == el_group)
112 variantGroupSizes.push_back(child.GetChildNodes().Count);
118 for (
size_t i = 0; i < variantGroupSizes.size(); ++i)
125 std::vector<std::vector<Variant> >::iterator currentGroup =
m_VariantGroups.begin();
129 int child_name = child.GetNodeName();
131 if (child_name == el_group)
133 std::vector<Variant>::iterator currentVariant = currentGroup->begin();
136 ENSURE(variant.GetNodeName() == el_variant);
139 if (attr.Name == at_name)
140 currentVariant->m_VariantName = attr.Value.LowerCase();
142 else if (attr.Name == at_frequency)
143 currentVariant->m_Frequency = attr.Value.ToInt();
148 int option_name = option.GetNodeName();
150 if (option_name == el_mesh)
152 currentVariant->m_ModelFilename =
VfsPath(
"art/meshes") / option.GetText().FromUTF8();
154 else if (option_name == el_textures)
158 ENSURE(textures_element.GetNodeName() == el_texture);
163 if (se.Name == at_file)
164 samp.m_SamplerFile =
VfsPath(
"art/textures/skins") / se.Value.FromUTF8();
165 else if (se.Name == at_name)
166 samp.m_SamplerName = se.Value;
168 currentVariant->m_Samplers.push_back(samp);
171 else if (option_name == el_decal)
180 currentVariant->m_Decal = decal;
182 else if (option_name == el_particles)
186 currentVariant->m_Particles = file;
192 else if (option_name == el_colour)
194 currentVariant->m_Color = option.GetText();
196 else if (option_name == el_animations)
200 ENSURE(anim_element.GetNodeName() == el_animation);
205 if (ae.Name == at_name)
207 anim.m_AnimName = ae.Value;
209 else if (ae.Name == at_file)
211 anim.m_FileName =
VfsPath(
"art/animation") / ae.Value.FromUTF8();
213 else if (ae.Name == at_speed)
215 anim.m_Speed = ae.Value.ToInt() / 100.f;
216 if (anim.m_Speed <= 0.0) anim.m_Speed = 1.0f;
218 else if (ae.Name == at_event)
220 float pos = ae.Value.ToFloat();
221 anim.m_ActionPos =
clamp(pos, 0.f, 1.f);
223 else if (ae.Name == at_load)
225 float pos = ae.Value.ToFloat();
226 anim.m_ActionPos2 =
clamp(pos, 0.f, 1.f);
228 else if (ae.Name == at_sound)
230 float pos = ae.Value.ToFloat();
231 anim.m_SoundPos =
clamp(pos, 0.f, 1.f);
234 currentVariant->m_Anims.push_back(anim);
238 else if (option_name == el_props)
242 ENSURE(prop_element.GetNodeName() == el_prop);
247 if (pe.Name == at_attachpoint)
248 prop.m_PropPointName = pe.Value;
249 else if (pe.Name == at_actor)
250 prop.m_ModelName = pe.Value.FromUTF8();
251 else if (pe.Name == at_minheight)
252 prop.m_minHeight = pe.Value.ToFloat();
253 else if (pe.Name == at_maxheight)
254 prop.m_maxHeight = pe.Value.ToFloat();
256 currentVariant->m_Props.push_back(prop);
264 if (currentGroup->size() == 0)
266 LOGERROR(L
"Actor group has zero variants ('%ls')", pathname.
string().c_str());
271 else if (child_name == el_castshadow)
275 else if (child_name == el_float)
279 else if (child_name == el_material)
314 std::vector<u8> choices;
316 std::multimap<CStr, CStrW> chosenProps;
318 for (std::vector<std::vector<CObjectBase::Variant> >::iterator grp =
m_VariantGroups.begin();
324 if (grp->size() == 0)
330 if (grp->size() == 1)
339 for (std::vector<std::set<CStr> >::const_iterator selset = selections.begin(); selset < selections.end(); ++selset)
341 ENSURE(grp->size() < 256);
343 for (
size_t i = 0; i < grp->size(); ++i)
345 if (selset->count((*grp)[i].m_VariantName))
362 choices.push_back(match);
367 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
370 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
371 chosenProps.erase(it->m_PropPointName);
373 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
374 if (! it->m_ModelName.empty())
375 chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName));
380 for (std::multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)
386 choices.insert(choices.end(), propChoices.begin(), propChoices.end());
401 std::vector<std::vector<CObjectBase::Variant> >::iterator grp =
m_VariantGroups.begin();
402 std::vector<u8>::const_iterator match = variationKey.begin();
409 if (grp->size() == 0)
413 if (
id >= grp->size())
416 debug_warn(L
"BuildVariation: invalid variant id");
442 for (std::vector<CObjectBase::Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
443 variation.
props.erase(it->m_PropPointName);
445 for (std::vector<CObjectBase::Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
446 if (! it->m_ModelName.empty())
447 variation.
props.insert(make_pair(it->m_PropPointName, *it));
451 for (std::vector<CObjectBase::Anim>::iterator it = var.
m_Anims.begin(); it != var.
m_Anims.end(); ++it)
452 variation.
anims.erase(it->m_AnimName);
454 for (std::vector<CObjectBase::Anim>::iterator it = var.
m_Anims.begin(); it != var.
m_Anims.end(); ++it)
455 variation.
anims.insert(make_pair(it->m_AnimName, *it));
458 for (std::vector<CObjectBase::Samp>::iterator it = var.
m_Samplers.begin(); it != var.
m_Samplers.end(); ++it)
459 variation.
samplers.erase(it->m_SamplerName);
460 for (std::vector<CObjectBase::Samp>::iterator it = var.
m_Samplers.begin(); it != var.
m_Samplers.end(); ++it)
461 variation.
samplers.insert(make_pair(it->m_SamplerName, *it));
473 remainingSelections.insert(initialSelections.begin(), initialSelections.end());
475 return remainingSelections;
487 std::set<CStr> remainingSelections;
488 std::multimap<CStr, CStrW> chosenProps;
500 for (std::vector<std::vector<Variant> >::iterator grp =
m_VariantGroups.begin();
506 if (grp->size() == 0)
512 if (grp->size() == 1)
522 for (
size_t s = 0; s < initialSelections.size(); ++s)
524 for (
size_t i = 0; i < grp->size(); ++i)
526 if (initialSelections[s].count((*grp)[i].m_VariantName))
543 for (
size_t i = 0; i < grp->size(); ++i)
544 totalFreq += (*grp)[i].m_Frequency;
548 bool allZero = (totalFreq == 0);
549 if (allZero) totalFreq = (int)grp->size();
552 int randNum = boost::uniform_int<>(0, totalFreq-1)(rng);
555 for (
size_t i = 0; i < grp->size(); ++i)
557 randNum -= (allZero ? 1 : (*grp)[i].m_Frequency);
560 remainingSelections.insert((*grp)[i].m_VariantName);
581 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
584 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
585 chosenProps.erase(it->m_PropPointName);
587 for (std::vector<Prop>::iterator it = var.
m_Props.begin(); it != var.
m_Props.end(); ++it)
588 if (! it->m_ModelName.empty())
589 chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName));
594 for (std::multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)
599 std::vector<std::set<CStr> > propInitialSelections = initialSelections;
600 if (!remainingSelections.empty())
601 propInitialSelections.push_back(remainingSelections);
604 remainingSelections.insert(propRemainingSelections.begin(), propRemainingSelections.end());
612 return remainingSelections;
617 std::vector<std::vector<CStr> > groups;
620 std::queue<const CObjectBase*> objectsQueue;
621 objectsQueue.push(
this);
624 std::set<const CObjectBase*> objectsProcessed;
626 while (!objectsQueue.empty())
631 if (objectsProcessed.find(obj) != objectsProcessed.end())
634 objectsProcessed.insert(obj);
640 std::vector<CStr> group;
650 for (
size_t j = 0; j < groups.size(); ++j)
652 if (groups[j] == group)
663 groups.push_back(group);
669 for (
size_t k = 0; k < props.size(); ++k)
671 if (! props[k].m_ModelName.empty())
675 objectsQueue.push(prop);
bool UsesFile(const VfsPath &pathname)
Returns whether this object (including any possible props) uses the given file.
Path VfsPath
VFS path of the form "(dir/)*file?".
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Load from an XML file (with invisible XMB caching).
#define XERO_ITER_ATTR(parent_element, attribute)
const PSRETURN PSRETURN_OK
CObjectBase * FindObjectBase(const CStrW &objname)
bool Load(const VfsPath &pathname)
Initialise this object by loading from the given file.
CObjectBase(CObjectManager &objectManager)
#define XERO_ITER_EL(parent_element, child_element)
std::vector< Prop > m_Props
std::vector< std::vector< Variant > > m_VariantGroups
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
std::vector< u8 > CalculateVariationKey(const std::vector< std::set< CStr > > &selections)
std::multimap< CStr, Samp > samplers
boost::mt19937 rng
Random number generator (Boost Mersenne Twister)
std::vector< Anim > m_Anims
const String & string() const
std::vector< std::vector< CStr > > GetVariantGroups() const
std::vector< Samp > m_Samplers
struct CObjectBase::@7 m_Properties
std::multimap< CStr, Prop > props
CObjectManager & m_ObjectManager
CStr8 GetNamedItem(const int AttributeName) const
std::string GetElementString(const int ID) const
XMBElement GetRoot() const
std::set< CStr > CalculateRandomVariation(uint32_t seed, const std::set< CStr > &initialSelections)
bool Reload()
Reload this object from the file that it was previously loaded from.
std::multimap< CStr, Anim > anims
const Variation BuildVariation(const std::vector< u8 > &variationKey)
#define debug_warn(expr)
display the error dialog with the given text.
std::set< CStr > CalculateRandomRemainingSelections(uint32_t seed, const std::vector< std::set< CStr > > &initialSelections)
T clamp(T value, T min, T max)
boost::unordered_set< VfsPath > m_UsedFiles