Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/graphics/ObjectBase.cpp
Show First 20 Lines • Show All 528 Lines • ▼ Show 20 Lines | std::set<CStr> CObjectBase::CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr>>& initialSelections) const | ||||
// In each group, if one of the variants has a name matching a string in | // In each group, if one of the variants has a name matching a string in | ||||
// 'selections', use that one. | // 'selections', use that one. | ||||
// If more than one matches, choose randomly from those matching ones. | // If more than one matches, choose randomly from those matching ones. | ||||
// If none match, choose randomly from all variants. | // If none match, choose randomly from all variants. | ||||
// | // | ||||
// When choosing randomly, make use of each variant's frequency. If all | // When choosing randomly, make use of each variant's frequency. If all | ||||
// variants have frequency 0, treat them as if they were 1. | // variants have frequency 0, treat them as if they were 1. | ||||
CObjectManager::VariantDiversity diversity = m_ObjectManager.GetVariantDiversity(); | |||||
for (std::vector<std::vector<Variant> >::const_iterator grp = m_VariantGroups.begin(); | for (std::vector<std::vector<Variant> >::const_iterator grp = m_VariantGroups.begin(); | ||||
grp != m_VariantGroups.end(); | grp != m_VariantGroups.end(); | ||||
++grp) | ++grp) | ||||
{ | { | ||||
// Ignore groups with nothing inside. (A warning will have been | // Ignore groups with nothing inside. (A warning will have been | ||||
// emitted by the loading code.) | // emitted by the loading code.) | ||||
if (grp->size() == 0) | if (grp->size() == 0) | ||||
continue; | continue; | ||||
Show All 33 Lines | else | ||||
// Sum the frequencies | // Sum the frequencies | ||||
int totalFreq = 0; | int totalFreq = 0; | ||||
for (size_t i = 0; i < grp->size(); ++i) | for (size_t i = 0; i < grp->size(); ++i) | ||||
totalFreq += (*grp)[i].m_Frequency; | totalFreq += (*grp)[i].m_Frequency; | ||||
// Someone might be silly and set all variants to have freq==0, in | // Someone might be silly and set all variants to have freq==0, in | ||||
// which case we just pretend they're all 1 | // which case we just pretend they're all 1 | ||||
bool allZero = (totalFreq == 0); | bool allZero = (totalFreq == 0); | ||||
if (allZero) totalFreq = (int)grp->size(); | if (allZero) | ||||
totalFreq = (int)grp->size(); | |||||
// Choose a random number in the interval [0..totalFreq) | |||||
int randNum = boost::random::uniform_int_distribution<int>(0, totalFreq-1)(rng); | |||||
// and use that to choose one of the variants | // Choose a random number in the interval [0..totalFreq) to choose one of the variants. | ||||
// If the diversity is "none", force 0 to return the first valid variant. | |||||
int randNum = diversity == CObjectManager::VariantDiversity::NONE ? 0 : boost::random::uniform_int_distribution<int>(0, totalFreq-1)(rng); | |||||
for (size_t i = 0; i < grp->size(); ++i) | for (size_t i = 0; i < grp->size(); ++i) | ||||
{ | { | ||||
randNum -= (allZero ? 1 : (*grp)[i].m_Frequency); | randNum -= (allZero ? 1 : (*grp)[i].m_Frequency); | ||||
if (randNum < 0) | if (randNum < 0) | ||||
{ | { | ||||
remainingSelections.insert((*grp)[i].m_VariantName); | |||||
// (If this change to 'remainingSelections' interferes with earlier choices, then | // (If this change to 'remainingSelections' interferes with earlier choices, then | ||||
// we'll get some non-fatal inconsistencies that just break the randomness. But that | // we'll get some non-fatal inconsistencies that just break the randomness. But that | ||||
// shouldn't happen, much.) | // shouldn't happen, much.) | ||||
// (As an example, suppose you have a group with variants "a" and "b", and another | // (As an example, suppose you have a group with variants "a" and "b", and another | ||||
// with variants "a" and "c"; now if random selection choses "b" for the first | // with variants "a" and "c"; now if random selection choses "b" for the first | ||||
// and "a" for the second, then the selection of "a" from the second group will | // and "a" for the second, then the selection of "a" from the second group will | ||||
// cause "a" to be used in the first instead of the "b"). | // cause "a" to be used in the first instead of the "b"). | ||||
match = (int)i; | match = (int)i; | ||||
// In limited diversity, somewhat-randomly continue. This cuts variants to about a third, | |||||
// though not quite because we must pick a variant so the actual probability is more complex. | |||||
// (It's also dependent on actor files not containing too many 0-frequency variants) | |||||
if (diversity == CObjectManager::VariantDiversity::LIMITED && (i % 3 != 0)) | |||||
{ | |||||
// Reset to 0 or we'll just pick every subsequent variant. | |||||
randNum = 0; | |||||
continue; | |||||
} | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
ENSURE(randNum < 0); | ENSURE(match != -1); | ||||
// This should always succeed; otherwise it | // This should always succeed; otherwise it | ||||
// wouldn't have chosen any of the variants. | // wouldn't have chosen any of the variants. | ||||
remainingSelections.insert((*grp)[match].m_VariantName); | |||||
} | } | ||||
} | } | ||||
// Remember which props were chosen, so we can call CalculateRandomVariation on them | // Remember which props were chosen, so we can call CalculateRandomVariation on them | ||||
// at the end. | // at the end. | ||||
const Variant& var ((*grp)[match]); | const Variant& var ((*grp)[match]); | ||||
// Erase all existing props which are overridden by this variant: | // Erase all existing props which are overridden by this variant: | ||||
for (const Prop& prop : var.m_Props) | for (const Prop& prop : var.m_Props) | ||||
▲ Show 20 Lines • Show All 378 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator