Ticket #979: entity_randomization_svn_25feb12.patch
File entity_randomization_svn_25feb12.patch, 10.3 KB (added by , 12 years ago) |
---|
-
source/graphics/ObjectBase.cpp
1 /* Copyright (C) 201 1Wildfire Games.1 /* Copyright (C) 2012 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 335 335 336 336 // Remember which props were chosen, so we can call CalculateVariationKey on them 337 337 // at the end. 338 CObjectBase::Variant& var ((*grp)[match]);339 for (std::vector< CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)338 Variant& var ((*grp)[match]); 339 for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 340 340 { 341 341 // Erase all existing props which are overridden by this variant: 342 for (std::vector< CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)342 for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 343 343 chosenProps.erase(it->m_PropPointName); 344 344 // and then insert the new ones: 345 for (std::vector< CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)345 for (std::vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 346 346 if (! it->m_ModelName.empty()) 347 347 chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName)); 348 348 } … … 437 437 { 438 438 rng_t rng; 439 439 rng.seed(seed); 440 return CalculateRandomVariation(rng, initialSelections); 440 441 std::set<CStr> remainingSelections = CalculateRandomRemainingSelections(rng, std::vector<std::set<CStr> >(1, initialSelections)); 442 remainingSelections.insert(initialSelections.begin(), initialSelections.end()); 443 444 return remainingSelections; // now actually a complete set of selections 441 445 } 442 446 443 std::set<CStr> CObjectBase::CalculateRandom Variation(rng_t& rng, const std::set<CStr>& initialSelections)447 std::set<CStr> CObjectBase::CalculateRandomRemainingSelections(uint32_t seed, const std::vector<std::set<CStr> >& initialSelections) 444 448 { 445 std::set<CStr> selections = initialSelections; 449 rng_t rng; 450 rng.seed(seed); 451 return CalculateRandomRemainingSelections(rng, initialSelections); 452 } 446 453 447 std::multimap<CStr, CStrW> chosenProps; 454 std::set<CStr> CObjectBase::CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr> >& initialSelections) 455 { 456 using std::set; 457 using std::vector; 458 using std::multimap; 448 459 460 set<CStr> remainingSelections; 461 multimap<CStr, CStrW> chosenProps; 462 449 463 // Calculate a complete list of selections, so there is at least one 450 464 // (and in most cases only one) per group. 451 465 // In each group, if one of the variants has a name matching a string in … … 456 470 // When choosing randomly, make use of each variant's frequency. If all 457 471 // variants have frequency 0, treat them as if they were 1. 458 472 459 for ( std::vector<std::vector<CObjectBase::Variant> >::iterator grp = m_VariantGroups.begin();473 for (vector<vector<Variant> >::iterator grp = m_VariantGroups.begin(); 460 474 grp != m_VariantGroups.end(); 461 475 ++grp) 462 476 { … … 475 489 else 476 490 { 477 491 // See if a variant (or several, but we only care about the first) 478 // is already matched by the selections we've made 492 // is already matched by the selections we've made, keeping their 493 // priority order into account 479 494 480 for (size_t i = 0; i < grp->size(); ++i)495 for (size_t s = 0; s < initialSelections.size(); ++s) 481 496 { 482 if (selections.count((*grp)[i].m_VariantName))497 for (size_t i = 0; i < grp->size(); ++i) 483 498 { 484 match = (int)i; 499 if (initialSelections[s].count((*grp)[i].m_VariantName)) 500 { 501 match = (int)i; 502 break; 503 } 504 } 505 506 if (match >= 0) 485 507 break; 486 }487 508 } 488 509 489 510 // If there was one, we don't need to do anything now because there's … … 509 530 randNum -= (allZero ? 1 : (*grp)[i].m_Frequency); 510 531 if (randNum < 0) 511 532 { 512 selections.insert((*grp)[i].m_VariantName); 513 // (If this change to 'selections' interferes with earlier 514 // choices, then we'll get some non-fatal inconsistencies 515 // that just break the randomness. But that shouldn't 516 // happen, much.) 533 remainingSelections.insert((*grp)[i].m_VariantName); 534 // (If this change to 'remainingSelections' interferes with earlier choices, then 535 // we'll get some non-fatal inconsistencies that just break the randomness. But that 536 // shouldn't happen, much.) 537 // (As an example, suppose you have a group with variants "a" and "b", and another 538 // with variants "a" and "c"; now if random selection choses "b" for the first 539 // and "a" for the second, then the selection of "a" from the second group will 540 // cause "a" to be used in the first instead of the "b"). 517 541 match = (int)i; 518 542 break; 519 543 } … … 526 550 527 551 // Remember which props were chosen, so we can call CalculateRandomVariation on them 528 552 // at the end. 529 CObjectBase::Variant& var ((*grp)[match]);530 for ( std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)553 Variant& var ((*grp)[match]); 554 for (vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 531 555 { 532 556 // Erase all existing props which are overridden by this variant: 533 for ( std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)557 for (vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 534 558 chosenProps.erase(it->m_PropPointName); 535 559 // and then insert the new ones: 536 for ( std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)560 for (vector<Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it) 537 561 if (! it->m_ModelName.empty()) 538 562 chosenProps.insert(make_pair(it->m_PropPointName, it->m_ModelName)); 539 563 } 540 564 } 541 565 542 566 // Load each prop, and add their required selections to ours: 543 for ( std::multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)567 for (multimap<CStr, CStrW>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it) 544 568 { 545 569 CObjectBase* prop = m_ObjectManager.FindObjectBase(it->second); 546 570 if (prop) 547 571 { 548 std::set<CStr> propSelections = prop->CalculateRandomVariation(rng, selections); 549 // selections = union(propSelections, selections) 550 std::set<CStr> newSelections; 551 std::set_union(propSelections.begin(), propSelections.end(), 552 selections.begin(), selections.end(), 553 std::inserter(newSelections, newSelections.begin())); 554 selections.swap(newSelections); 572 vector<set<CStr> > propInitialSelections = initialSelections; 573 if (remainingSelections.size() > 0) 574 propInitialSelections.push_back(remainingSelections); 555 575 576 set<CStr> propRemainingSelections = prop->CalculateRandomRemainingSelections(rng, propInitialSelections); 577 remainingSelections.insert(propRemainingSelections.begin(), propRemainingSelections.end()); 578 556 579 // Add the prop's used files to our own (recursively) so we can hotload 557 580 // when any prop is changed 558 581 m_UsedFiles.insert(prop->m_UsedFiles.begin(), prop->m_UsedFiles.end()); 559 582 } 560 583 } 561 584 562 return selections;585 return remainingSelections; 563 586 } 564 587 565 588 std::vector<std::vector<CStr> > CObjectBase::GetVariantGroups() const -
source/graphics/ObjectBase.h
1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2012 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 113 113 // and choosing randomly where a choice is necessary. 114 114 std::set<CStr> CalculateRandomVariation(uint32_t seed, const std::set<CStr>& initialSelections); 115 115 116 // Given a prioritized vector of selection string sets that partially specify 117 // a variation, calculates a remaining set of selection strings such that the resulting 118 // set merged with the initial selections fully specifies an exact variation of 119 // the actor. The resulting selections are selected randomly, but only where a choice 120 // is necessary (i.e. where there are multiple variants but the initial selections, 121 // applied in priority order, fail to select one). 122 std::set<CStr> CalculateRandomRemainingSelections(uint32_t seed, const std::vector<std::set<CStr> >& initialSelections); 123 116 124 // Get a list of variant groups for this object, plus for all possible 117 125 // props. Duplicated groups are removed, if several props share the same 118 126 // variant names. … … 160 168 // so use a better one that appears to avoid those patterns 161 169 typedef boost::mt19937 rng_t; 162 170 163 std::set<CStr> CalculateRandom Variation(rng_t& rng, const std::set<CStr>& initialSelections);171 std::set<CStr> CalculateRandomRemainingSelections(rng_t& rng, const std::vector<std::set<CStr> >& initialSelections); 164 172 165 173 std::vector< std::vector<Variant> > m_VariantGroups; 166 174 CObjectManager& m_ObjectManager; -
source/graphics/Unit.cpp
1 /* Copyright (C) 201 0Wildfire Games.1 /* Copyright (C) 2012 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 105 105 selections.push_back(m_EntitySelections); 106 106 selections.push_back(m_ActorSelections); 107 107 108 // randomly select any remain selections necessary to completely identify a variation (e.g., the new selection 109 // made might define some additional props that require a random variant choice). Also, FindObjectVariation 110 // expects the selectors passed to it to be complete. 111 // see http://trac.wildfiregames.com/ticket/979 112 113 // Use the entity ID as randomization seed (same as when the unit was first created) 114 std::set<CStr> remainingSelections = m_Object->m_Base->CalculateRandomRemainingSelections(m_ID, selections); 115 if (remainingSelections.size() > 0) 116 selections.push_back(remainingSelections); 117 108 118 // If these selections give a different object, change this unit to use it 109 119 CObjectEntry* newObject = m_ObjectManager.FindObjectVariation(m_Object->m_Base, selections); 110 120 if (newObject && newObject != m_Object)