Allowed negative defense values as a way to set upper bounds.
Example: [defense] village=-60 means that the unit cannot have less than 60 def (more than 40% def) on terrains containing villages.
This commit is contained in:
parent
afdf522273
commit
846f06de11
5 changed files with 87 additions and 80 deletions
|
@ -109,6 +109,9 @@ Version 1.9.0+svn:
|
|||
floating-point divide.
|
||||
* Allow time_area to define local time of day on map border (bug #16508)
|
||||
* Fix time of day not changing in time area (bug #16584)
|
||||
* Allowed negative defense values as a way to set upper bounds,
|
||||
e.g. village=-60 means that a unit cannot have less than 60 def (more
|
||||
than 40% def) on terrains containing villages.
|
||||
* Miscellaneous and bug fixes:
|
||||
* Removed: statistics upload code.
|
||||
* Changed: compiler mode set to c++98
|
||||
|
|
|
@ -93,23 +93,13 @@ Xu , Xu , Qxu , Qxu , Ql , Ql
|
|||
availability="musthave"
|
||||
male_name="feral"
|
||||
female_name="female^feral"
|
||||
description="Receive only 40% defense in villages"
|
||||
description="Receive at most 40% defense in villages"
|
||||
[effect]
|
||||
apply_to=new_ability
|
||||
[abilities]
|
||||
[defense]
|
||||
id=feral
|
||||
name=""
|
||||
description=""
|
||||
value=60
|
||||
cumulative=no
|
||||
[filter_self]
|
||||
[filter_location]
|
||||
terrain=*^V*
|
||||
[/filter_location]
|
||||
[/filter_self]
|
||||
[/defense]
|
||||
[/abilities]
|
||||
apply_to=defense
|
||||
replace=yes
|
||||
[defense]
|
||||
village=-60
|
||||
[/defense]
|
||||
[/effect]
|
||||
[/trait]
|
||||
[/modifications]
|
||||
|
|
|
@ -399,7 +399,7 @@ private:
|
|||
int movement_;
|
||||
int max_movement_;
|
||||
mutable std::map<t_translation::t_terrain, int> movement_costs_; // movement cost cache
|
||||
mutable std::map<t_translation::t_terrain, int> defense_mods_; // defense modifiers cache
|
||||
mutable defense_cache defense_mods_; // defense modifiers cache
|
||||
bool hold_position_;
|
||||
bool end_turn_;
|
||||
bool resting_;
|
||||
|
|
|
@ -315,19 +315,6 @@ std::string unit_movement_type::name() const
|
|||
return cfg_["name"];
|
||||
}
|
||||
|
||||
int unit_movement_type::movement_cost(const gamemap& map,
|
||||
t_translation::t_terrain terrain) const
|
||||
{
|
||||
int res = movement_cost_internal(moveCosts_, cfg_, parent_, map, terrain);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unit_movement_type::defense_modifier(const gamemap& map,
|
||||
t_translation::t_terrain terrain) const
|
||||
{
|
||||
return defense_modifier_internal(defenseMods_, cfg_, parent_, map, terrain);
|
||||
}
|
||||
|
||||
int unit_movement_type::resistance_against(const attack_type& attack) const
|
||||
{
|
||||
bool result_found = false;
|
||||
|
@ -454,33 +441,37 @@ int movement_cost_internal(std::map<t_translation::t_terrain, int>& move_costs,
|
|||
return res;
|
||||
}
|
||||
|
||||
int defense_modifier_internal(std::map<t_translation::t_terrain, int>& defense_mods,
|
||||
const defense_range &defense_range_modifier_internal(defense_cache &defense_mods,
|
||||
const config& cfg, const unit_movement_type* parent,
|
||||
const gamemap& map, t_translation::t_terrain terrain, int recurse_count)
|
||||
{
|
||||
const std::map<t_translation::t_terrain, int>::const_iterator i = defense_mods.find(terrain);
|
||||
if (i != defense_mods.end()) return i->second;
|
||||
defense_range dummy = { 0, 100 };
|
||||
std::pair<defense_cache::iterator, bool> ib =
|
||||
defense_mods.insert(defense_cache::value_type(terrain, dummy));
|
||||
if (!ib.second) return ib.first->second;
|
||||
|
||||
bool result_found = false;
|
||||
int res = 100;
|
||||
defense_range &res = ib.first->second;
|
||||
|
||||
// If this is an alias, then select the best of all underlying terrains.
|
||||
const t_translation::t_list& underlying = map.underlying_def_terrain(terrain);
|
||||
assert(!underlying.empty());
|
||||
|
||||
if (underlying.size() != 1 || underlying.front() != terrain) {
|
||||
bool revert = (underlying.front() == t_translation::MINUS ? true : false);
|
||||
bool revert = underlying.front() == t_translation::MINUS;
|
||||
if(recurse_count >= 90) {
|
||||
ERR_CF << "infinite defense_modifier recursion: "
|
||||
<< t_translation::write_terrain_code(terrain)
|
||||
<< " depth " << recurse_count << "\n";
|
||||
}
|
||||
if (recurse_count >= 100) {
|
||||
defense_mods.insert(std::pair<t_translation::t_terrain, int>(terrain, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
res = revert ? 0 : 100;
|
||||
if (revert) {
|
||||
res.max_ = 0;
|
||||
res.min_ = 100;
|
||||
}
|
||||
|
||||
for (t_translation::t_list::const_iterator i = underlying.begin();
|
||||
i != underlying.end(); ++i) {
|
||||
|
||||
|
@ -491,52 +482,59 @@ int defense_modifier_internal(std::map<t_translation::t_terrain, int>& defense_m
|
|||
revert = true;
|
||||
continue;
|
||||
}
|
||||
const int value = defense_modifier_internal(defense_mods, cfg, parent,
|
||||
map, *i, recurse_count + 1);
|
||||
const defense_range &inh = defense_range_modifier_internal
|
||||
(defense_mods, cfg, parent, map, *i, recurse_count + 1);
|
||||
|
||||
if (value < res && !revert) {
|
||||
res = value;
|
||||
} else if (value > res && revert) {
|
||||
res = value;
|
||||
if (!revert) {
|
||||
if (inh.max_ < res.max_) res.max_ = inh.max_;
|
||||
if (inh.min_ > res.min_) res.min_ = inh.min_;
|
||||
} else {
|
||||
if (inh.max_ > res.max_) res.max_ = inh.max_;
|
||||
if (inh.min_ < res.min_) res.min_ = inh.min_;
|
||||
}
|
||||
}
|
||||
|
||||
defense_mods.insert(std::pair<t_translation::t_terrain, int>(terrain, res));
|
||||
return res;
|
||||
goto check;
|
||||
}
|
||||
|
||||
if (const config& defense = cfg.child("defense")) {
|
||||
if (underlying.size() != 1) {
|
||||
ERR_CF << "Terrain '" << terrain << "' has "
|
||||
<< underlying.size() << " underlying names - 0 expected.\n";
|
||||
|
||||
defense_mods.insert(std::pair<t_translation::t_terrain, int>(terrain, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
if (const config& defense = cfg.child("defense"))
|
||||
{
|
||||
const std::string& id = map.get_terrain_info(underlying.front()).id();
|
||||
if (const config::attribute_value *val = defense.get(id)) {
|
||||
res = *val;
|
||||
result_found = true;
|
||||
int def = *val;
|
||||
if (def >= 0) res.max_ = def;
|
||||
else res.max_ = res.min_ = -def;
|
||||
goto check;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result_found && parent != NULL) {
|
||||
res = parent->defense_modifier(map, terrain);
|
||||
if (parent) {
|
||||
return parent->defense_range_modifier(map, terrain);
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
WRN_CF << "Defense '" << res << "' is '< 0' reset to 0 (100% defense).\n";
|
||||
res = 0;
|
||||
} else if (res > 100) {
|
||||
WRN_CF << "Defense '" << res << "' is '> 100' reset to 100 (0% defense).\n";
|
||||
res = 100;
|
||||
check:
|
||||
|
||||
if (res.min_ < 0) {
|
||||
WRN_CF << "Defense '" << res.min_ << "' is '< 0' reset to 0 (100% defense).\n";
|
||||
res.min_ = 0;
|
||||
}
|
||||
if (res.max_ > 100) {
|
||||
WRN_CF << "Defense '" << res.max_ << "' is '> 100' reset to 100 (0% defense).\n";
|
||||
res.max_ = 100;
|
||||
}
|
||||
|
||||
defense_mods.insert(std::pair<t_translation::t_terrain, int>(terrain, res));
|
||||
return res;
|
||||
}
|
||||
|
||||
int defense_modifier_internal(defense_cache &defense_mods,
|
||||
const config &cfg, const unit_movement_type *parent,
|
||||
const gamemap &map, t_translation::t_terrain terrain, int recurse_count)
|
||||
{
|
||||
const defense_range &def = defense_range_modifier_internal(defense_mods,
|
||||
cfg, parent, map, terrain, recurse_count);
|
||||
return (std::max)(def.max_, def.min_);
|
||||
}
|
||||
|
||||
static const unit_race& dummy_race(){
|
||||
static unit_race ur;
|
||||
return ur;
|
||||
|
|
|
@ -103,6 +103,29 @@ private:
|
|||
|
||||
class unit_movement_type;
|
||||
|
||||
/**
|
||||
* Possible range of the defense. When a single value is needed, #max_
|
||||
* (maximum defense) is selected, unless #min_ is bigger.
|
||||
*/
|
||||
struct defense_range
|
||||
{
|
||||
int min_, max_;
|
||||
};
|
||||
|
||||
typedef std::map<t_translation::t_terrain, defense_range> defense_cache;
|
||||
|
||||
const defense_range &defense_range_modifier_internal(defense_cache &defense_mods,
|
||||
const config &cfg, const unit_movement_type *parent,
|
||||
const gamemap &map, t_translation::t_terrain terrain, int recurse_count = 0);
|
||||
|
||||
int defense_modifier_internal(defense_cache &defense_mods,
|
||||
const config &cfg, const unit_movement_type *parent,
|
||||
const gamemap &map, t_translation::t_terrain terrain, int recurse_count = 0);
|
||||
|
||||
int movement_cost_internal(std::map<t_translation::t_terrain, int> &move_costs,
|
||||
const config &cfg, const unit_movement_type *parent,
|
||||
const gamemap &map, t_translation::t_terrain terrain, int recurse_count = 0);
|
||||
|
||||
//the 'unit movement type' is the basic size of the unit - flying, small land,
|
||||
//large land, etc etc.
|
||||
class unit_movement_type
|
||||
|
@ -119,8 +142,12 @@ public:
|
|||
unit_movement_type();
|
||||
|
||||
std::string name() const;
|
||||
int movement_cost(const gamemap& map, t_translation::t_terrain terrain) const;
|
||||
int defense_modifier(const gamemap& map, t_translation::t_terrain terrain) const;
|
||||
int movement_cost(const gamemap &map, t_translation::t_terrain terrain) const
|
||||
{ return movement_cost_internal(moveCosts_, cfg_, parent_, map, terrain); }
|
||||
int defense_modifier(const gamemap &map, t_translation::t_terrain terrain) const
|
||||
{ return defense_modifier_internal(defenseMods_, cfg_, parent_, map, terrain); }
|
||||
const defense_range &defense_range_modifier(const gamemap &map, t_translation::t_terrain terrain) const
|
||||
{ return defense_range_modifier_internal(defenseMods_, cfg_, parent_, map, terrain); }
|
||||
int damage_against(const attack_type& attack) const { return resistance_against(attack); }
|
||||
int resistance_against(const attack_type& attack) const;
|
||||
|
||||
|
@ -129,29 +156,18 @@ public:
|
|||
void set_parent(const unit_movement_type* parent) { parent_ = parent; }
|
||||
|
||||
bool is_flying() const;
|
||||
const std::map<t_translation::t_terrain, int>& movement_costs() const { return moveCosts_; }
|
||||
const std::map<t_translation::t_terrain, int>& defense_mods() const { return defenseMods_; }
|
||||
|
||||
const config& get_cfg() const { return cfg_; }
|
||||
const unit_movement_type* get_parent() const { return parent_; }
|
||||
private:
|
||||
mutable std::map<t_translation::t_terrain, int> moveCosts_;
|
||||
mutable std::map<t_translation::t_terrain, int> defenseMods_;
|
||||
mutable defense_cache defenseMods_;
|
||||
|
||||
const unit_movement_type* parent_;
|
||||
|
||||
config cfg_;
|
||||
};
|
||||
|
||||
int movement_cost_internal(std::map<t_translation::t_terrain, int>& move_costs,
|
||||
const config& cfg, const unit_movement_type* parent,
|
||||
const gamemap& map, t_translation::t_terrain terrain, int recurse_count = 0);
|
||||
|
||||
int defense_modifier_internal(std::map<t_translation::t_terrain, int>& defense_mods,
|
||||
const config& cfg, const unit_movement_type* parent,
|
||||
const gamemap& map, t_translation::t_terrain terrain, int recurse_count = 0);
|
||||
|
||||
|
||||
typedef std::map<std::string,unit_movement_type> movement_type_map;
|
||||
|
||||
class unit_type
|
||||
|
|
Loading…
Add table
Reference in a new issue