Split the 'not_living' unit status into...

...unpoisonable, undrainable and unplagueable
This commit is contained in:
Alexander van Gessel 2012-12-31 01:03:53 +01:00
parent 6a6780af0d
commit d82762b87d
11 changed files with 159 additions and 27 deletions

View File

@ -30,6 +30,8 @@ Version 1.11.1+svn:
* When not replacing values, [effect] apply_to=defense will now modify
absolute values instead of signed values (bug #20242). This allows for
cleaner WML when the unit type is not necessarily known in advance.
* Split the 'not_living' unit status into 'unpoisonable', 'undrainable' and
'unplagueable'. 'not_living' now acts on the whole group
* Miscellaneous and bug fixes:
* The undo stack is preserved across a save-reload.
* Removed several unused private member variables.

View File

@ -24,7 +24,15 @@
description= _ "Immune to drain, poison, and plague"
[effect]
apply_to=status
add=not_living
add=unpoisonable
[/effect]
[effect]
apply_to=status
add=undrainable
[/effect]
[effect]
apply_to=status
add=unplagueable
[/effect]
[/trait]
#enddef
@ -39,7 +47,15 @@
description= _ "Immune to drain, poison, and plague"
[effect]
apply_to=status
add=not_living
add=unpoisonable
[/effect]
[effect]
apply_to=status
add=undrainable
[/effect]
[effect]
apply_to=status
add=unplagueable
[/effect]
[/trait]
#enddef
@ -54,7 +70,15 @@
description= _ "Immune to drain, poison, and plague"
[effect]
apply_to=status
add=not_living
add=unpoisonable
[/effect]
[effect]
apply_to=status
add=undrainable
[/effect]
[effect]
apply_to=status
add=unplagueable
[/effect]
[/trait]
#enddef

View File

@ -3237,6 +3237,92 @@ Result:
[/replace_schedule]
[/event]
[label]
x,y=23,10
text="livingness"
[/label]
[event]
name=moveto
first_time_only=no
[filter]
x,y=23,10
[/filter]
[while]
[variable]
name="choice"
not_equals="done"
[/variable]
[do]
[store_unit]
variable="wml_unit"
[filter]
x=$x1,y=$y1
[/filter]
[/store_unit]
[message]
speaker=narrator
message="Unit statuses in WML:
not_living: $wml_unit.status.not_living
unpoisonable: $wml_unit.status.unpoisonable
undrainable: $wml_unit.status.undrainable
unplagueable: $wml_unit.status.unplagueable"
[/message]
[lua]
code=<<
local args = ...
local unit = wesnoth.get_unit(args.x1, args.y1)
local raw_msg = "Unit statuses in LUA:\
\
not_living: %s\
unpoisonable: %s\
undrainable: %s\
unplagueable: %s"
local msg = string.format(raw_msg, unit.status.not_living, unit.status.unpoisonable, unit.status.undrainable, unit.status.unplagueable)
wesnoth.wml_actions.message({speaker = "narrator", message = msg})
wesnoth.wml_actions.message({speaker = "narrator", message = "Do you want to change any of that?",
{ "option", { message = "Flip not_living",
{ "command", {
{ "set_variable", { name = "choice", value = "not_living" } } } } } },
{ "option", { message = "Flip unpoisonable",
{ "command", {
{ "set_variable", { name = "choice", value = "unpoisonable" } } } } } },
{ "option", { message = "Flip undrainable",
{ "command", {
{ "set_variable", { name = "choice", value = "undrainable" } } } } } },
{ "option", { message = "Flip unplagueable",
{ "command", {
{ "set_variable", { name = "choice", value = "unplagueable" } } } } } },
{ "option", { message = "Nope",
{ "command", {
{ "set_variable", { name = "choice", value = "done" } } } } } }
})
local choice = wesnoth.get_variable("choice")
-- debug :unit will reapply musthave traits, breaking these modifications for undead
-- if you want something more permanent, give the unit an object
if choice == "not_living" then
unit.status.not_living = not unit.status.not_living
elseif choice == "unpoisonable" then
unit.status.unpoisonable = not unit.status.unpoisonable
elseif choice == "undrainable" then
unit.status.undrainable = not unit.status.undrainable
elseif choice == "unplagueable" then
unit.status.unplagueable = not unit.status.unplagueable
end
>>
[args]
x1=$x1
y1=$y1
[/args]
[/lua]
[/do]
[/while]
{CLEAR_VARIABLE choice}
{CLEAR_VARIABLE wml_unit}
[/event]
# Capture connected villages near 13,2 for team 2
[event]
name=prestart

View File

@ -109,18 +109,17 @@ battle_context_unit_stats::battle_context_unit_stats(const unit &u,
weapon->set_specials_context(u_loc, opp_loc, attacking, opp_weapon);
if (opp_weapon)
opp_weapon->set_specials_context(opp_loc, u_loc, !attacking, weapon);
bool not_living = opp.get_state("not_living");
slows = weapon->get_special_bool("slow");
drains = !not_living && weapon->get_special_bool("drains");
drains = !opp.get_state("undrainable") && weapon->get_special_bool("drains");
petrifies = weapon->get_special_bool("petrifies");
poisons = !not_living && weapon->get_special_bool("poison") && !opp.get_state(unit::STATE_POISONED);
poisons = !opp.get_state("unpoisonable") && weapon->get_special_bool("poison") && !opp.get_state(unit::STATE_POISONED);
backstab_pos = is_attacker && backstab_check(u_loc, opp_loc, units, *resources::teams);
rounds = weapon->get_specials("berserk").highest("value", 1).first;
firststrike = weapon->get_special_bool("firststrike");
// Handle plague.
unit_ability_list plague_specials = weapon->get_specials("plague");
plagues = !not_living && !plague_specials.empty() &&
plagues = !opp.get_state("unplagueable") && !plague_specials.empty() &&
strcmp(opp.undead_variation().c_str(), "null") && !resources::game_map->is_village(opp_loc);
if (plagues) {

View File

@ -357,7 +357,7 @@ int ai_default_recruitment_stage::average_resistance_against(const unit_type& a,
// calculation of the average damage taken
bool steadfast = a.has_ability_by_id("steadfast");
bool living = !a.not_living();
bool poisonable = !a.musthave_status("unpoisonable");
const std::vector<attack_type>& attacks = b.attacks();
for (std::vector<attack_type>::const_iterator i = attacks.begin(),
i_end = attacks.end(); i != i_end; ++i)
@ -370,7 +370,7 @@ int ai_default_recruitment_stage::average_resistance_against(const unit_type& a,
int cth = i->get_special_bool("chance_to_hit", true) ? 70 : defense;
int weight = i->damage() * i->num_attacks();
// if cth == 0 the division will do 0/0 so don't execute this part
if (living && cth != 0 && i->get_special_bool("poison", true)) {
if (poisonable && cth != 0 && i->get_special_bool("poison", true)) {
// Compute the probability of not poisoning the unit.
int prob = 100;
for (int j = 0; j < i->num_attacks(); ++j)

View File

@ -404,7 +404,7 @@ int recruitment_phase::average_resistance_against(const unit_type& a, const unit
// calculation of the average damage taken
bool steadfast = a.has_ability_by_id("steadfast");
bool living = !a.not_living();
bool poisonable = !a.musthave_status("unpoisonable");
const std::vector<attack_type>& attacks = b.attacks();
for (std::vector<attack_type>::const_iterator i = attacks.begin(),
i_end = attacks.end(); i != i_end; ++i)
@ -417,7 +417,7 @@ int recruitment_phase::average_resistance_against(const unit_type& a, const unit
int cth = i->get_special_bool("chance_to_hit", true) ? 70 : defense;
int weight = i->damage() * i->num_attacks();
// if cth == 0 the division will do 0/0 so don't execute this part
if (living && cth != 0 && i->get_special_bool("poison", true)) {
if (poisonable && cth != 0 && i->get_special_bool("poison", true)) {
// Compute the probability of not poisoning the unit.
int prob = 100;
for (int j = 0; j < i->num_attacks(); ++j)

View File

@ -289,7 +289,7 @@ static int average_resistance_against(const unit_type& a, const unit_type& b)
// calculation of the average damage taken
bool steadfast = a.has_ability_by_id("steadfast");
bool living = !a.not_living();
bool poisonable = !a.musthave_status("unpoisonable");
const std::vector<attack_type>& attacks = b.attacks();
for (std::vector<attack_type>::const_iterator i = attacks.begin(),
i_end = attacks.end(); i != i_end; ++i)
@ -302,7 +302,7 @@ static int average_resistance_against(const unit_type& a, const unit_type& b)
int cth = i->get_special_bool("chance_to_hit", true) ? 70 : defense;
int weight = i->damage() * i->num_attacks();
// if cth == 0 the division will do 0/0 so don't execute this part
if (living && cth != 0 && i->get_special_bool("poison", true)) {
if (poisonable && cth != 0 && i->get_special_bool("poison", true)) {
// Compute the probability of not poisoning the unit.
int prob = 100;
for (int j = 0; j < i->num_attacks(); ++j)

View File

@ -309,8 +309,12 @@ variant unit_type_callable::get_value(const std::string& key) const
return variant(u_.level());
} else if(key == "total_movement") {
return variant(u_.movement());
} else if(key == "undead") {
return variant(u_.not_living());
} else if(key == "unpoisonable") {
return variant(u_.musthave_status("unpoisonable"));
} else if(key == "undrainable") {
return variant(u_.musthave_status("undrainable"));
} else if(key == "unplagueable") {
return variant(u_.musthave_status("unplagueable"));
} else if(key == "cost") {
return variant(u_.cost());
} else if(key == "usage") {

View File

@ -1208,6 +1208,11 @@ const std::map<std::string,std::string> unit::get_states() const
}
}
// Backwards compatibility for not_living. Don't remove before 1.12
if (all_states.find("undrainable") != all_states.end() &&
all_states.find("unpoisonable") != all_states.end() &&
all_states.find("unplagueable") != all_states.end())
all_states["not_living"] = "yes";
return all_states;
}
@ -1217,6 +1222,12 @@ bool unit::get_state(const std::string &state) const
if (known_boolean_state_id!=STATE_UNKNOWN){
return get_state(known_boolean_state_id);
}
// Backwards compatibility for not_living. Don't remove before 1.12
if (state == "not_living") {
return get_state("undrainable") &&
get_state("unpoisonable") &&
get_state("unplagueable");
}
return states_.find(state) != states_.end();
}
@ -1260,6 +1271,12 @@ void unit::set_state(const std::string &state, bool value)
set_state(known_boolean_state_id, value);
return;
}
// Backwards compatibility for not_living. Don't remove before 1.12
if (state == "not_living") {
set_state("undrainable", value);
set_state("unpoisonable", value);
set_state("unplagueable", value);
}
if (value)
states_.insert(state);
else

View File

@ -1419,15 +1419,15 @@ const unit_race *unit_type_data::find_race(const std::string &key) const
return i != races_.end() ? &i->second : NULL;
}
// This function is only meant to return the likely state of not_living
// This function is only meant to return the likely state a given status
// for a new recruit of this type. It should not be used to check if
// a particular unit is living or not, use get_state("not_living") for that.
bool unit_type::not_living() const
// a particular unit has it, use get_state(status_name) for that.
bool unit_type::musthave_status(const std::string& status_name) const
{
// If a unit hasn't been modified it starts out as living.
bool not_living = false;
// Statuses default to absent.
bool current_status = false;
// Look at all of the "musthave" traits to see if the not_living
// Look at all of the "musthave" traits to see if the
// status gets changed. In the unlikely event it gets changed
// multiple times, we want to try to do it in the same order
// that unit::apply_modifications does things.
@ -1454,16 +1454,16 @@ bool unit_type::not_living() const
if (effect["apply_to"] != "status") {
continue;
}
if (effect["add"] == "not_living") {
not_living = true;
if (effect["add"] == status_name) {
current_status = true;
}
if (effect["remove"] == "not_living") {
not_living = false;
if (effect["remove"] == status_name) {
current_status = false;
}
}
}
return not_living;
return current_status;
}
bool unit_type::has_random_traits() const

View File

@ -283,7 +283,7 @@ public:
bool can_advance() const { return !advances_to_.empty(); }
bool not_living() const;
bool musthave_status(const std::string& status) const;
bool has_zoc() const { return zoc_; }