This puts back 2007-08-15T13:11:46Z!bruno@wolff.to with a couple of changes...

...to cope with code drift and
to throw an error on unknown unit types.
This commit is contained in:
Bruno Wolff III 2007-08-18 04:04:45 +00:00
parent 99c250c11b
commit 45eff316cd
2 changed files with 86 additions and 18 deletions

View file

@ -19,6 +19,7 @@
# Units with trait Undead cannot be drained, poisoned or plagued.
[trait]
id=undead
availability="musthave"
male_name= _ "undead"
female_name= _ "female^undead"
description= _ "Immune to drain, poison and plague"
@ -33,6 +34,7 @@
# Units with trait Mechanical cannot be drained, poisoned or plagued.
[trait]
id=mechanical
availability="musthave"
male_name= _ "mechanical"
female_name= _ "female^mechanical"
description= _ "Immune to drain, poison and plague"

View file

@ -364,20 +364,83 @@ void unit::set_game_context(const game_data* gamedata, unit_map* unitmap, const
teams_ = teams;
}
// Apply mandatory traits (e.g. undead, mechanical) to a unit and then
// fill out with avaiable (leaders have a restircted set of available traits)
// traits until no more are available or the unit has its maximum number
// of traits.
// This routine does not apply the effects of added traits to a unit.
// That must be done by the caller.
// Note that random numbers used in config files don't work in multiplayer,
// so that leaders should be barred from all random traits until that
// is fixed. Later the restrictions will be based on play balance.
void unit::generate_traits()
{
if(!traits_description_.empty())
return;
wassert(gamedata_ != NULL);
const game_data::unit_type_map::const_iterator type = gamedata_->unit_types.find(id());
// Calculate the unit's traits
if (type == gamedata_->unit_types.end()) {
throw game::game_error("Unknown unit type '" + id() + "'");
}
std::vector<config*> candidate_traits = type->second.possible_traits();
std::vector<config*> traits;
const size_t num_traits = type->second.num_traits();
for(size_t n = 0; n != num_traits && candidate_traits.empty() == false; ++n) {
const int num = get_random()%candidate_traits.size();
// First remove traits the unit already has from consideration.
// And count them so that we can figure out how many more are needed.
size_t t = 0;
config::child_list const &mods = modifications_.get_children("trait");
for(config::child_list::const_iterator j = mods.begin(), j_end = mods.end(); j != j_end; ++j) {
++t;
size_t m = 0;
for(size_t n = 0; n < candidate_traits.size(); ++n) {
if((**(candidate_traits.begin()+m))["id"] == (**j)["id"]) {
candidate_traits.erase(candidate_traits.begin()+m);
}
else {
++m;
}
}
}
// Next add in any manditory traits. These aren't limited by the
// number of traits allowed for a unit. They also don't use
// any random numbers for assignment. (And hence don't cause
// problems for multiplayer.)
size_t num_traits = candidate_traits.size();
size_t m = 0;
for(size_t n = 0; n < num_traits; ++n) {
if(!(**(candidate_traits.begin()+m))["availability"].empty() &&
(**(candidate_traits.begin()+m))["availability"] == "musthave") {
traits.push_back(candidate_traits[m]);
candidate_traits.erase(candidate_traits.begin()+m);
++t;
}
else {
++m;
}
}
// Next for leaders remove any traits that are not available to
// the "any" category.
if(can_recruit()) {
num_traits = candidate_traits.size();
m = 0;
for(size_t n = 0; n < num_traits; ++n) {
if(!(**(candidate_traits.begin()+m))["availability"].empty() ||
(**(candidate_traits.begin()+m))["availability"] != "any") {
candidate_traits.erase(candidate_traits.begin()+m);
}
else {
++m;
}
}
}
// Now randomly fill out to the number of traits required or until
// there aren't any more traits.
num_traits = type->second.num_traits();
for(size_t n = t; n < num_traits && candidate_traits.empty() == false; ++n) {
const size_t num = get_random()%candidate_traits.size();
traits.push_back(candidate_traits[num]);
candidate_traits.erase(candidate_traits.begin()+num);
}
@ -386,7 +449,9 @@ void unit::generate_traits()
modifications_.add_child("trait",**j);
}
apply_modifications();
// Once random traits are added, don't do it again.
// Such as when restoring a saved character.
cfg_["random_traits"]="no";
}
//! Advance this unit to another type
@ -466,6 +531,8 @@ void unit::advance_to(const unit_type* t)
poison_animations_ = t->poison_animations_;
flag_rgb_ = t->flag_rgb();
backup_state();
if(id()!=t->id() || cfg_["gender"] != cfg_["gender_id"]) {
heal_all();
id_ = unit_id_test(t->id());
@ -473,20 +540,20 @@ void unit::advance_to(const unit_type* t)
cfg_["gender_id"] = cfg_["gender"];
}
backup_state();
// This will add new traits to an advancing unit, if either
// the new unit type has new "musthave" traits or the new unit type
// the new unit type has new "musthave" traits or the new unit type
// grants more traits than the unit currently has.
// This is meant to handle living units advancing to nonliving units.
// This is meant to handle living units advancing to nonliving units.
// Note that adding random traits in multiplayer games will cause
// OOS errors. However, none of the standard advancement patterns
// add traits, only reduce them.
generate_traits();
// Apply modifications etc, refresh the unit.
// Apply modifications etc, refresh the unit.
// This needs to be after type and gender are fixed,
// since there can be filters on the modifications
// that may result in different effects after the advancement.
// since there can be filters on the modifications
// that may result in different effects after the advancement.
apply_modifications();
game_events::add_events(cfg_.get_children("event"),id_);
@ -1150,13 +1217,12 @@ void unit::read(const config& cfg)
}
if(!type_set) {
backup_state();
if(cfg["random_traits"].empty() ||
utils::string_bool(cfg["random_traits"])) {
generate_traits();
}
apply_modifications();
}
if(utils::string_bool(cfg["random_traits"]) ||
race_->name() == "undead") {
generate_traits();
cfg_["random_traits"] = "";
}
if(cfg["hitpoints"] != "") {
hit_points_ = lexical_cast_default<int>(cfg["hitpoints"]);
} else {