Simplify healing as per multiple discussions:
No limit of hitpoints per cure/heal, heal at start of healer turn. Healing still doesn't stack (you can only be healed by one thing), but standing next to allies healer can get you double-healing. If healers are now too powerful, simplest would be to limit number of patients each healer can treat. If allied healers are too powerful, we could extend limit across entire turn, so unit cannot be treated by more than one healer per turn, even allies.
This commit is contained in:
parent
8fdcfa7358
commit
01751ea84e
14 changed files with 183 additions and 352 deletions
37
MANUAL
37
MANUAL
|
@ -226,35 +226,20 @@ HEALING
|
||||||
Injured units in villages will recover 8 hitpoints every turn. Injured
|
Injured units in villages will recover 8 hitpoints every turn. Injured
|
||||||
units that are adjacent to units with the 'heal' or 'cure' abilities
|
units that are adjacent to units with the 'heal' or 'cure' abilities
|
||||||
will also heal. A unit that does not move or fight during a turn is
|
will also heal. A unit that does not move or fight during a turn is
|
||||||
'resting' and will recover 2 hitpoints. Hitpoints recovered through
|
'resting' and will recover an additional 2 hitpoints.
|
||||||
'resting' are added on top of hitpoints recovered through healing or
|
|
||||||
regenerating.
|
|
||||||
|
|
||||||
A unit with the 'heals' ability may heal up to 8 hitpoints total per
|
A unit with the 'heals' ability will heal adjacent allied units by up
|
||||||
turn. A unit with the 'cures' ability may heal up to 18 hitpoints total
|
to 4 hitpoints each, at the beginning of the healer's turn. Poisoned
|
||||||
per turn.
|
units will have their poison damage stopped by the healer, instead.
|
||||||
|
|
||||||
Units next to unit(s) with the 'heals' ability will recover a maximum of
|
A unit with the 'cures' ability will heal adjacent allied units by up
|
||||||
4 hitpoints per turn; units next to unit(s) with the 'cures' ability
|
to 8 hitpoints each, at the beginning of the curer's turn. Poisoned
|
||||||
will recover a maximum of 8 hitpoints per turn. The more units around a
|
units will have their poison cured by healer, instead.
|
||||||
unit that can heal, the less each one will be healed.
|
|
||||||
|
|
||||||
An example of 'heals' with multiple adjacent units:
|
No unit can be healed or cured by more than one thing at a time: the
|
||||||
|
effects are not cumulative. For example, a unit standing in a village
|
||||||
Two units next to a 'healer' will receive 4 hitpoints each.
|
gains no additional benefit from a curer standing next to it. A unit
|
||||||
|
standing next to two healers and a curer will not use the two healers.
|
||||||
3 units next to a 'healer' will NOT receive 4 hitpoints each:
|
|
||||||
two will receive 3 hitpoints and one will receive 2 hitpoints.
|
|
||||||
|
|
||||||
A unit may be healed a maximum of 8 hitpoints per turn, with a possible
|
|
||||||
2 hitpoints extra if resting. Trolls, which have the regenerate
|
|
||||||
ability, will only recover 8 hitpoints when residing in a village, not
|
|
||||||
16. Nor will a unit inside a village get extra healing from adjacent
|
|
||||||
healers.
|
|
||||||
|
|
||||||
'Heals' prevents poison from causing damage while 'cures' removes
|
|
||||||
poison. When poison is cured or prevented the unit does not gain or lose
|
|
||||||
hitpoints on that turn due to healing/poisoning.
|
|
||||||
|
|
||||||
For more information see the in-game help.
|
For more information see the in-game help.
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,8 @@ ability_ambush= _ "ambush"
|
||||||
cures_description= _ "Cures:
|
cures_description= _ "Cures:
|
||||||
This unit combines herbal remedies with magic to heal units more quickly than is normally possible on the battlefield.
|
This unit combines herbal remedies with magic to heal units more quickly than is normally possible on the battlefield.
|
||||||
|
|
||||||
This unit will care for all adjacent friendly units that are injured at the beginning of each turn.
|
This unit will care for all adjacent friendly units that are injured at the beginning of its turn.
|
||||||
A unit cared for by a curer may heal up to 8 HP per turn.
|
Each non-poisoned unit cared for by a curer will heal by up to 8 HP per turn.
|
||||||
A curer may heal a total of 18 HP per turn, for all units it cares for.
|
|
||||||
A curer can cure a unit of poison, although that unit will receive no additional healing on the turn it is cured of the poison."
|
A curer can cure a unit of poison, although that unit will receive no additional healing on the turn it is cured of the poison."
|
||||||
|
|
||||||
ability_cures= _ "cures"
|
ability_cures= _ "cures"
|
||||||
|
@ -35,9 +34,9 @@ ability_cures= _ "cures"
|
||||||
heals_description= _ "Heals:
|
heals_description= _ "Heals:
|
||||||
Allows the unit to heal adjacent friendly units at the beginning of each turn.
|
Allows the unit to heal adjacent friendly units at the beginning of each turn.
|
||||||
|
|
||||||
A unit cared for by a healer may heal up to 4 HP per turn.
|
This unit will care for all adjacent friendly units that are injured at the beginning of its turn.
|
||||||
A healer may heal a total of 8 HP per turn, for all units it cares for.
|
Each non-poisoned unit cared for by a healer will heal up to 4 HP per turn.
|
||||||
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
|
A healer will stop the damage done by poison on the current turn, but cannot cure it: the poisoned unit must seek the care of a village or a unit that can cure."
|
||||||
|
|
||||||
ability_heals= _ "heals"
|
ability_heals= _ "heals"
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,7 @@ default=yes
|
||||||
base_income=2
|
base_income=2
|
||||||
village_income=1
|
village_income=1
|
||||||
heal_amount=4
|
heal_amount=4
|
||||||
healer_heals_per_turn=8
|
|
||||||
cure_amount=8
|
cure_amount=8
|
||||||
curer_heals_per_turn=18
|
|
||||||
rest_heal_amount=2
|
rest_heal_amount=2
|
||||||
recall_cost=20
|
recall_cost=20
|
||||||
kill_experience=8
|
kill_experience=8
|
||||||
|
|
|
@ -216,10 +216,10 @@ text= _ "In combat, your units will inevitably take damage. When a unit <ref>dst
|
||||||
Resting: A unit which neither moves, attacks, nor is attacked will heal 2HP in its next turn." + _"
|
Resting: A unit which neither moves, attacks, nor is attacked will heal 2HP in its next turn." + _"
|
||||||
Villages: A unit which starts a turn in a village will heal 8HP." + _"
|
Villages: A unit which starts a turn in a village will heal 8HP." + _"
|
||||||
<ref>dst=ability_regenerates text=Regeneration</ref>: Certain units (such as trolls) will automatically heal 8HP every turn." + _"
|
<ref>dst=ability_regenerates text=Regeneration</ref>: Certain units (such as trolls) will automatically heal 8HP every turn." + _"
|
||||||
Healing units: Units with the <ref>dst=ability_heals text=Heals</ref> ability will heal up to 8HP of damage per turn, as well as preventing Poison from causing damage. Only those units will be healed that are adjacent to and are fighting on the same side as the healing unit, and only up to 4HP per unit." + _"
|
Healing units: Units with the <ref>dst=ability_heals text=Heals</ref> ability will heal up to 4HP of damage from each allied adjacent unit, per turn, or prevent Poison from causing that unit damage." + _"
|
||||||
Curing units: Units with the <ref>dst=ability_cures text=Cures</ref> ability will heal up to 18HP of damage per turn, as well as curing Poison. Only those units will be healed or cured that are adjacent to and are fighting on the same side as the healing unit, and only up to 8HP per unit." + _"
|
Curing units: Units with the <ref>dst=ability_cures text=Cures</ref> ability will heal up to 8HP of damage from each allied adjacent unit, per turn, or cure Poison in that unit." + _"
|
||||||
|
|
||||||
Resting can be combined with other forms of healing, but villages, regeneration, healing and curing cannot combine with each other. A healing or curing unit whose attention is split between many wounded will be less effective at healing their individual wounds. Finally, units heal fully between scenarios."
|
Resting can be combined with other forms of healing, but villages, regeneration, healing and curing cannot combine with each other: the best option will be used. Finally, units heal fully between scenarios."
|
||||||
[/topic]
|
[/topic]
|
||||||
|
|
||||||
[topic]
|
[topic]
|
||||||
|
|
420
src/actions.cpp
420
src/actions.cpp
|
@ -1384,317 +1384,189 @@ unit_map::const_iterator find_leader(const unit_map& units, int side)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
struct patient
|
||||||
//function which returns true iff the unit at 'loc' will heal a unit from side 'side'
|
|
||||||
//on this turn.
|
|
||||||
//
|
|
||||||
//units heal other units if they are (1) on the same side as them; or (2) are on a
|
|
||||||
//different but allied side, and there are no 'higher priority' sides also adjacent
|
|
||||||
//to the healer
|
|
||||||
bool will_heal(const gamemap::location& loc, int side, const std::vector<team>& teams,
|
|
||||||
const unit_map& units)
|
|
||||||
{
|
{
|
||||||
const unit_map::const_iterator healer_it = units.find(loc);
|
patient(unit &un, bool allied)
|
||||||
if(healer_it == units.end() || healer_it->second.type().heals() == false) {
|
: u(un), healing(0), poison_stopped(false), ally(allied) { }
|
||||||
return false;
|
|
||||||
|
unit &u;
|
||||||
|
|
||||||
|
// How much have we been healed?
|
||||||
|
int healing;
|
||||||
|
|
||||||
|
// Was our poison stopped / cured?
|
||||||
|
bool poison_stopped;
|
||||||
|
|
||||||
|
// Are we an ally? In which case we only get healed.
|
||||||
|
bool ally;
|
||||||
|
|
||||||
|
void heal(int amount, bool allies_too);
|
||||||
|
void harm(int amount);
|
||||||
|
void rest();
|
||||||
|
};
|
||||||
|
|
||||||
|
void patient::heal(int amount, bool allies_too)
|
||||||
|
{
|
||||||
|
if (ally && !allies_too)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (u.poisoned()) {
|
||||||
|
if (amount >= game_config::cure_amount)
|
||||||
|
u.remove_flag("poisoned");
|
||||||
|
poison_stopped = true;
|
||||||
|
} else {
|
||||||
|
healing = minimum(u.max_hitpoints() - u.hitpoints(), amount);
|
||||||
|
std::cerr << "healing by " << lexical_cast<std::string>(healing) << " of potential "
|
||||||
|
<< lexical_cast<std::string>(u.max_hitpoints() - u.hitpoints()) << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const unit& healer = healer_it->second;
|
void patient::harm(int amount)
|
||||||
|
{
|
||||||
if(healer.incapacitated()) {
|
if (ally)
|
||||||
return false;
|
return;
|
||||||
|
wassert(!healing && !poison_stopped);
|
||||||
|
healing = -minimum(u.hitpoints() - 1, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((int)healer.side() == side) {
|
void patient::rest()
|
||||||
return true;
|
{
|
||||||
}
|
if (ally)
|
||||||
|
return;
|
||||||
if(size_t(side-1) >= teams.size() || size_t(healer.side()-1) >= teams.size()) {
|
healing += minimum(u.max_hitpoints() - (u.hitpoints() + healing), game_config::rest_heal_amount);
|
||||||
return false;
|
std::cerr << "resting by " << lexical_cast<std::string>(minimum(u.max_hitpoints() - (u.hitpoints() + healing), game_config::rest_heal_amount)) << "\n";
|
||||||
}
|
|
||||||
|
|
||||||
//if the healer is an enemy, it won't heal
|
|
||||||
if(teams[healer.side()-1].is_enemy(side)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the best adjacent healer.
|
||||||
|
unit_map::iterator find_healer(const gamemap::location &loc, std::map<gamemap::location,unit>& units,
|
||||||
|
unsigned int side)
|
||||||
|
{
|
||||||
gamemap::location adjacent[6];
|
gamemap::location adjacent[6];
|
||||||
|
unit_map::iterator healer = units.end();
|
||||||
|
|
||||||
get_adjacent_tiles(loc, adjacent);
|
get_adjacent_tiles(loc, adjacent);
|
||||||
for(int n = 0; n != 6; ++n) {
|
for (unsigned int n = 0; n != 6U; ++n) {
|
||||||
const unit_map::const_iterator u = units.find(adjacent[n]);
|
unit_map::iterator i = units.find(adjacent[n]);
|
||||||
if(u != units.end() && (u->second.hitpoints() < u->second.max_hitpoints() || u->second.poisoned())) {
|
if (i != units.end()) {
|
||||||
//ignore stoned units
|
if (i->second.incapacitated())
|
||||||
if(!u->second.healable())
|
|
||||||
continue;
|
continue;
|
||||||
|
if (i->second.side() != side)
|
||||||
const int unit_side = u->second.side();
|
continue;
|
||||||
|
if (!i->second.type().heals())
|
||||||
//the healer won't heal an ally if there is a wounded unit on the same
|
continue;
|
||||||
//side next to her
|
if (healer == units.end() || i->second.type().heals() > healer->second.type().heals())
|
||||||
if(unit_side == (int)healer.side())
|
healer = i;
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
//choose an arbitrary order for healing
|
return healer;
|
||||||
if(unit_side > side)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//there's no-one of higher priority nearby, so the ally will heal
|
void reset_resting(std::map<gamemap::location,unit>& units, unsigned int side)
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void calculate_healing(display& disp, const gamestatus& status, const gamemap& map,
|
|
||||||
std::map<gamemap::location,unit>& units, int side,
|
|
||||||
const std::vector<team>& teams, bool update_display)
|
|
||||||
{
|
{
|
||||||
std::map<gamemap::location,int> healed_units, max_healing;
|
for (unit_map::iterator i = units.begin(); i != units.end(); ++i) {
|
||||||
|
if (i->second.side() == side)
|
||||||
//a map of healed units to their healers
|
|
||||||
std::multimap<gamemap::location,gamemap::location> healers;
|
|
||||||
|
|
||||||
std::map<gamemap::location,unit>::iterator i;
|
|
||||||
int amount_healed;
|
|
||||||
for(i = units.begin(); i != units.end(); ++i) {
|
|
||||||
amount_healed = 0;
|
|
||||||
|
|
||||||
if (!i->second.healable())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//the unit heals if it's on this side, and it's on a village or
|
|
||||||
//it has regeneration, and it is wounded
|
|
||||||
if((int)i->second.side() == side) {
|
|
||||||
if(i->second.hitpoints() < i->second.max_hitpoints() || i->second.poisoned()){
|
|
||||||
if(map.gives_healing(i->first)) {
|
|
||||||
amount_healed = maximum<int>(amount_healed,game_config::cure_amount);
|
|
||||||
}
|
|
||||||
if(i->second.type().regenerates()) {
|
|
||||||
amount_healed = maximum<int>(amount_healed,i->second.type().regenerate_amount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(amount_healed != 0)
|
|
||||||
healed_units.insert(std::pair<gamemap::location,int>(
|
|
||||||
i->first, amount_healed));
|
|
||||||
}
|
|
||||||
|
|
||||||
//otherwise find the maximum healing for the unit
|
|
||||||
if(amount_healed == 0) {
|
|
||||||
int max_heal = 0;
|
|
||||||
gamemap::location adjacent[6];
|
|
||||||
get_adjacent_tiles(i->first,adjacent);
|
|
||||||
for(int j = 0; j != 6; ++j) {
|
|
||||||
if(will_heal(adjacent[j],i->second.side(),teams,units)) {
|
|
||||||
const unit_map::const_iterator healer = units.find(adjacent[j]);
|
|
||||||
max_heal = maximum(max_heal,healer->second.type().heals());
|
|
||||||
|
|
||||||
healers.insert(std::pair<gamemap::location,gamemap::location>(i->first,adjacent[j]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(max_heal > 0) {
|
|
||||||
max_healing.insert(std::pair<gamemap::location,int>(i->first,max_heal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//now see about units that can heal other units
|
|
||||||
for(i = units.begin(); i != units.end(); ++i) {
|
|
||||||
|
|
||||||
if(will_heal(i->first,side,teams,units)) {
|
|
||||||
gamemap::location adjacent[6];
|
|
||||||
bool gets_healed[6];
|
|
||||||
get_adjacent_tiles(i->first,adjacent);
|
|
||||||
|
|
||||||
int nhealed = 0;
|
|
||||||
int j;
|
|
||||||
for(j = 0; j != 6; ++j) {
|
|
||||||
const std::map<gamemap::location,unit>::const_iterator adj =
|
|
||||||
units.find(adjacent[j]);
|
|
||||||
if(adj != units.end() &&
|
|
||||||
adj->second.hitpoints() < adj->second.max_hitpoints() &&
|
|
||||||
(int)adj->second.side() == side &&
|
|
||||||
healed_units[adj->first] < max_healing[adj->first] &&
|
|
||||||
adj->second.healable()) {
|
|
||||||
++nhealed;
|
|
||||||
gets_healed[j] = true;
|
|
||||||
} else {
|
|
||||||
gets_healed[j] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nhealed == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const int healing_per_unit = i->second.type().max_unit_healing()/nhealed;
|
|
||||||
|
|
||||||
for(j = 0; j != 6; ++j) {
|
|
||||||
if(!gets_healed[j])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
wassert(units.find(adjacent[j]) != units.end());
|
|
||||||
|
|
||||||
healed_units[adjacent[j]]
|
|
||||||
= minimum(max_healing[adjacent[j]],
|
|
||||||
healed_units[adjacent[j]]+healing_per_unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//poisoned units will take the same amount of damage per turn, as
|
|
||||||
//curing heals until they are reduced to 1 hitpoint. If they are
|
|
||||||
//cured on a turn, they recover 0 hitpoints that turn, but they
|
|
||||||
//are no longer poisoned
|
|
||||||
for(i = units.begin(); i != units.end(); ++i) {
|
|
||||||
|
|
||||||
if((int)i->second.side() == side && i->second.poisoned() && i->second.healable()) {
|
|
||||||
const int damage = minimum<int>(game_config::cure_amount,
|
|
||||||
i->second.hitpoints()-1);
|
|
||||||
|
|
||||||
if(damage > 0) {
|
|
||||||
healed_units.insert(std::pair<gamemap::location,int>(i->first,-damage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = units.begin(); i != units.end(); ++i) {
|
|
||||||
if((int)i->second.side() == side && i->second.healable()) {
|
|
||||||
if(i->second.hitpoints() < i->second.max_hitpoints() ||
|
|
||||||
i->second.poisoned()){
|
|
||||||
if(i->second.is_resting()) {
|
|
||||||
const std::map<gamemap::location,int>::iterator u =
|
|
||||||
healed_units.find(i->first);
|
|
||||||
if(u != healed_units.end()) {
|
|
||||||
healed_units[i->first] += game_config::rest_heal_amount;
|
|
||||||
} else {
|
|
||||||
healed_units.insert(std::pair<gamemap::location,int>(i->first,game_config::rest_heal_amount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i->second.set_resting(true);
|
i->second.set_resting(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::map<gamemap::location,int>::iterator h = healed_units.begin();
|
// Simple algorithm: no maximum number of patients per healer.
|
||||||
h != healed_units.end(); ++h) {
|
void calculate_healing(display& disp, const gamestatus& status, const gamemap& map,
|
||||||
|
std::map<gamemap::location,unit>& units, unsigned int side,
|
||||||
|
const std::vector<team>& teams, bool update_display)
|
||||||
|
{
|
||||||
|
// We look for all allied units, then we see if our healer is near them.
|
||||||
|
for (unit_map::iterator i = units.begin(); i != units.end(); ++i) {
|
||||||
|
if (teams[i->second.side()-1].is_enemy(side))
|
||||||
|
continue;
|
||||||
|
|
||||||
const gamemap::location& loc = h->first;
|
if (!i->second.healable())
|
||||||
|
continue;
|
||||||
|
|
||||||
wassert(units.count(loc) == 1);
|
patient p(i->second, i->second.side() != side);
|
||||||
|
unit_map::iterator healer = units.end();
|
||||||
|
|
||||||
unit& u = units.find(loc)->second;
|
if (p.u.type().regenerates())
|
||||||
|
p.heal(p.u.type().regenerate_amount(), false);
|
||||||
const bool show_healing = !disp.turbo() && !recorder.is_skipping() &&
|
else if (map.gives_healing(i->first))
|
||||||
!disp.fogged(loc.x,loc.y) && update_display &&
|
p.heal(game_config::cure_amount, false);
|
||||||
(!u.invisible(map.underlying_union_terrain(map[h->first.x][h->first.y]),
|
else {
|
||||||
status.get_time_of_day().lawful_bonus,h->first,units,teams) ||
|
healer = find_healer(i->first, units, side);
|
||||||
teams[disp.viewing_team()].is_enemy(side) == false);
|
if (healer != units.end())
|
||||||
|
p.heal(healer->second.type().heals(), true);
|
||||||
typedef std::multimap<gamemap::location,gamemap::location>::const_iterator healer_itor;
|
|
||||||
const std::pair<healer_itor,healer_itor> healer_itors = healers.equal_range(loc);
|
|
||||||
|
|
||||||
// time at which we start all anmations
|
|
||||||
int start_time = 0;
|
|
||||||
if(show_healing) {
|
|
||||||
disp.scroll_to_tile(loc.x,loc.y,display::ONSCREEN);
|
|
||||||
disp.select_hex(loc);
|
|
||||||
|
|
||||||
|
|
||||||
//iterate over any units that are healing this unit, and make them
|
|
||||||
//enter their healing frame
|
|
||||||
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
|
|
||||||
wassert(units.count(i->second));
|
|
||||||
unit& healer = units.find(i->second)->second;
|
|
||||||
healer.set_healing(disp);
|
|
||||||
start_time = minimum<int>(start_time,healer.get_animation()->get_first_frame_time());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (p.u.poisoned() && !p.poison_stopped)
|
||||||
|
p.harm(game_config::cure_amount);
|
||||||
|
if (p.u.is_resting())
|
||||||
|
p.rest();
|
||||||
|
|
||||||
|
if (!p.healing && !p.poison_stopped)
|
||||||
|
continue;
|
||||||
|
|
||||||
LOG_NG << "unit is poisoned? " << (u.has_flag("poisoned") ? "yes" : "no") << ","
|
if (disp.turbo() || recorder.is_skipping()
|
||||||
<< h->second << "," << max_healing[h->first] << "\n";
|
|| disp.fogged(i->first.x, i->first.y)
|
||||||
|
|| !update_display
|
||||||
if(u.has_flag("poisoned") && h->second > 0) {
|
|| (p.u.invisible(map.underlying_union_terrain(map[i->first.x][i->first.y]),
|
||||||
|
status.get_time_of_day().lawful_bonus,i->first,units,teams) &&
|
||||||
//poison is purged only if we are on a village or next to a curer
|
teams[disp.viewing_team()].is_enemy(side))) {
|
||||||
if(h->second >= game_config::cure_amount ||
|
// Simple path.
|
||||||
max_healing[h->first] >= game_config::cure_amount) {
|
if (p.healing > 0)
|
||||||
u.remove_flag("poisoned");
|
p.u.heal(p.healing);
|
||||||
|
else if (p.healing < 0)
|
||||||
events::pump();
|
p.u.gets_hit(-p.healing);
|
||||||
if(show_healing) {
|
|
||||||
|
|
||||||
sound::play_sound("heal.wav");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h->second = 0;
|
|
||||||
} else {
|
|
||||||
if(h->second > 0 && h->second > u.max_hitpoints()-u.hitpoints()) {
|
|
||||||
h->second = u.max_hitpoints()-u.hitpoints();
|
|
||||||
if(h->second <= 0)
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(h->second < 0) {
|
// This is all the pretty stuff.
|
||||||
if(show_healing) {
|
int start_time = 0;
|
||||||
|
disp.scroll_to_tile(i->first.x, i->first.y, display::ONSCREEN);
|
||||||
|
disp.select_hex(i->first);
|
||||||
|
|
||||||
|
if (healer != units.end()) {
|
||||||
|
healer->second.set_healing(disp);
|
||||||
|
start_time = healer->second.get_animation()->get_first_frame_time();
|
||||||
|
}
|
||||||
|
if (p.healing < 0) {
|
||||||
|
p.u.set_poisoned(disp, -p.healing);
|
||||||
|
start_time = minimum<int>(start_time, p.u.get_animation()->get_first_frame_time());
|
||||||
sound::play_sound("groan.wav");
|
sound::play_sound("groan.wav");
|
||||||
disp.float_label(h->first,lexical_cast<std::string>(h->second*-1),255,0,0);
|
disp.float_label(i->first, lexical_cast<std::string>(-p.healing), 255,0,0);
|
||||||
}
|
} else {
|
||||||
} else if(h->second > 0) {
|
p.u.set_healed(disp, p.healing);
|
||||||
if(show_healing) {
|
start_time = minimum<int>(start_time, p.u.get_animation()->get_first_frame_time());
|
||||||
sound::play_sound("heal.wav");
|
sound::play_sound("heal.wav");
|
||||||
disp.float_label(h->first,lexical_cast<std::string>(h->second),0,255,0);
|
disp.float_label(i->first, lexical_cast<std::string>(p.healing), 0,255,0);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// restart both anims in a synchronized way
|
||||||
|
p.u.restart_animation(disp, start_time);
|
||||||
|
if (healer != units.end())
|
||||||
|
healer->second.restart_animation(disp, start_time);
|
||||||
|
|
||||||
if(h->second >= 0) {
|
bool finished;
|
||||||
u.set_healed(disp,h->second);
|
do {
|
||||||
start_time = minimum<int>(start_time,u.get_animation()->get_first_frame_time());
|
finished = (p.u.get_animation()->animation_finished());
|
||||||
|
disp.draw_tile(i->first.x, i->first.y);
|
||||||
|
if (healer != units.end()) {
|
||||||
|
finished &= healer->second.get_animation()->animation_finished();
|
||||||
|
disp.draw_tile(healer->first.x, healer->first.y);
|
||||||
}
|
}
|
||||||
if(h->second < 0) {
|
if (p.healing > 0) {
|
||||||
u.set_poisoned(disp,-h->second);
|
p.u.heal(1);
|
||||||
start_time = minimum<int>(start_time,u.get_animation()->get_first_frame_time());
|
--p.healing;
|
||||||
|
} else if (p.healing < 0) {
|
||||||
|
p.u.gets_hit(1);
|
||||||
|
++p.healing;
|
||||||
}
|
}
|
||||||
//std::vector<unit*>::iterator itor;
|
finished &= (!p.healing);
|
||||||
// restart all anims in a synchronized way
|
|
||||||
u.restart_animation(disp,start_time);
|
|
||||||
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
|
|
||||||
unit& healer = units.find(i->second)->second;
|
|
||||||
healer.set_facing(i->first.get_relative_dir(i->second));
|
|
||||||
healer.restart_animation(disp,start_time);
|
|
||||||
}
|
|
||||||
bool finished = false;
|
|
||||||
while(!finished) {
|
|
||||||
healer_itor i;
|
|
||||||
finished = (u.get_animation()->animation_finished());
|
|
||||||
disp.draw_tile(loc.x,loc.y);
|
|
||||||
for(i = healer_itors.first; i != healer_itors.second; ++i) {
|
|
||||||
unit& healer = units.find(i->second)->second;
|
|
||||||
finished &= healer.get_animation()->animation_finished();
|
|
||||||
disp.draw_tile(i->second.x,i->second.y);
|
|
||||||
}
|
|
||||||
if(h->second > 0) {
|
|
||||||
u.heal(1);
|
|
||||||
--h->second;
|
|
||||||
} else if (h->second <0) {
|
|
||||||
u.gets_hit(1);
|
|
||||||
++h->second;
|
|
||||||
}
|
|
||||||
finished &= (h->second ==0);
|
|
||||||
disp.update_display();
|
disp.update_display();
|
||||||
events::pump();
|
events::pump();
|
||||||
if(!disp.turbo()) SDL_Delay(10);
|
SDL_Delay(10);
|
||||||
|
} while (!finished);
|
||||||
|
|
||||||
}
|
p.u.set_standing(disp);
|
||||||
u.set_standing(disp);
|
if (healer != units.end())
|
||||||
for(healer_itor i = healer_itors.first; i != healer_itors.second; ++i) {
|
healer->second.set_standing(disp);
|
||||||
unit& healer = units.find(i->second)->second;
|
|
||||||
healer.set_standing(disp);
|
|
||||||
}
|
|
||||||
disp.update_display();
|
disp.update_display();
|
||||||
events::pump();
|
events::pump();
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,13 @@ unit_map::const_iterator find_leader(const unit_map& units, int side);
|
||||||
//calculates healing for all units for the given side. Should be called
|
//calculates healing for all units for the given side. Should be called
|
||||||
//at the beginning of a side's turn.
|
//at the beginning of a side's turn.
|
||||||
void calculate_healing(display& disp, const gamestatus& status, const gamemap& map,
|
void calculate_healing(display& disp, const gamestatus& status, const gamemap& map,
|
||||||
std::map<gamemap::location,unit>& units, int side,
|
std::map<gamemap::location,unit>& units, unsigned int side,
|
||||||
const std::vector<team>& teams, bool update_display);
|
const std::vector<team>& teams, bool update_display);
|
||||||
|
|
||||||
|
// Resets resting for all units on this side: should be called after calculate_healing().
|
||||||
|
// FIXME: Try moving this to unit::new_turn, then move it above calculate_healing().
|
||||||
|
void reset_resting(std::map<gamemap::location,unit>& units, unsigned int side);
|
||||||
|
|
||||||
//function which, given the location of a unit that is advancing, and the
|
//function which, given the location of a unit that is advancing, and the
|
||||||
//name of the unit it is advancing to, will return the advanced version of
|
//name of the unit it is advancing to, will return the advanced version of
|
||||||
//this unit. (with traits and items retained).
|
//this unit. (with traits and items retained).
|
||||||
|
|
|
@ -25,9 +25,7 @@ namespace game_config
|
||||||
int base_income = 2;
|
int base_income = 2;
|
||||||
int village_income = 1;
|
int village_income = 1;
|
||||||
int heal_amount = 4;
|
int heal_amount = 4;
|
||||||
int healer_heals_per_turn = 8;
|
|
||||||
int cure_amount = 8;
|
int cure_amount = 8;
|
||||||
int curer_heals_per_turn = 18;
|
|
||||||
int rest_heal_amount= 2;
|
int rest_heal_amount= 2;
|
||||||
int recall_cost = 20;
|
int recall_cost = 20;
|
||||||
int kill_experience = 8;
|
int kill_experience = 8;
|
||||||
|
@ -100,9 +98,7 @@ namespace game_config
|
||||||
base_income = atoi(v["base_income"].c_str());
|
base_income = atoi(v["base_income"].c_str());
|
||||||
village_income = atoi(v["village_income"].c_str());
|
village_income = atoi(v["village_income"].c_str());
|
||||||
heal_amount = atoi(v["heal_amount"].c_str());
|
heal_amount = atoi(v["heal_amount"].c_str());
|
||||||
healer_heals_per_turn = atoi(v["healer_heals_per_turn"].c_str());
|
|
||||||
cure_amount = atoi(v["cure_amount"].c_str());
|
cure_amount = atoi(v["cure_amount"].c_str());
|
||||||
curer_heals_per_turn = atoi(v["curer_heals_per_turn"].c_str());
|
|
||||||
rest_heal_amount = atoi(v["rest_heal_amount"].c_str());
|
rest_heal_amount = atoi(v["rest_heal_amount"].c_str());
|
||||||
recall_cost = atoi(v["recall_cost"].c_str());
|
recall_cost = atoi(v["recall_cost"].c_str());
|
||||||
kill_experience = atoi(v["kill_experience"].c_str());
|
kill_experience = atoi(v["kill_experience"].c_str());
|
||||||
|
|
|
@ -27,9 +27,7 @@ namespace game_config
|
||||||
extern int base_income;
|
extern int base_income;
|
||||||
extern int village_income;
|
extern int village_income;
|
||||||
extern int heal_amount;
|
extern int heal_amount;
|
||||||
extern int healer_heals_per_turn;
|
|
||||||
extern int cure_amount;
|
extern int cure_amount;
|
||||||
extern int curer_heals_per_turn;
|
|
||||||
extern int rest_heal_amount;
|
extern int rest_heal_amount;
|
||||||
extern int recall_cost;
|
extern int recall_cost;
|
||||||
extern int kill_experience;
|
extern int kill_experience;
|
||||||
|
|
|
@ -431,6 +431,7 @@ LEVEL_RESULT play_level(const game_data& gameinfo, const config& game_config,
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_healing(gui,status,map,units,player_number,teams, !skip_replay);
|
calculate_healing(gui,status,map,units,player_number,teams, !skip_replay);
|
||||||
|
reset_resting(units, player_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
team_it->set_time_of_day(int(status.turn()),status.get_time_of_day());
|
team_it->set_time_of_day(int(status.turn()),status.get_time_of_day());
|
||||||
|
|
|
@ -434,6 +434,7 @@ void replay_controller::play_side(const int team_index){
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_healing((*gui_),status_,map_,units_,player_number_,teams_, !recorder.is_skipping());
|
calculate_healing((*gui_),status_,map_,units_,player_number_,teams_, !recorder.is_skipping());
|
||||||
|
reset_resting(units_, player_number_);
|
||||||
}
|
}
|
||||||
|
|
||||||
current_team.set_time_of_day(int(status_.turn()),status_.get_time_of_day());
|
current_team.set_time_of_day(int(status_.turn()),status_.get_time_of_day());
|
||||||
|
|
|
@ -98,7 +98,6 @@ heals_ability::heals_ability(const config* cfg)
|
||||||
: ability(cfg)
|
: ability(cfg)
|
||||||
{
|
{
|
||||||
amount_=lexical_cast_default<int>((*cfg)["amount"],game_config::healer_heals_per_turn);
|
amount_=lexical_cast_default<int>((*cfg)["amount"],game_config::healer_heals_per_turn);
|
||||||
max_=lexical_cast_default<int>((*cfg)["max"],game_config::heal_amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int heals_ability::amount() const
|
const int heals_ability::amount() const
|
||||||
|
@ -106,15 +105,9 @@ const int heals_ability::amount() const
|
||||||
return amount_;
|
return amount_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int heals_ability::max() const
|
void heals_ability::set_heal(int amount)
|
||||||
{
|
|
||||||
return max_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void heals_ability::set_heal(int amount, int max)
|
|
||||||
{
|
{
|
||||||
amount_=amount;
|
amount_=amount;
|
||||||
max_=max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// regenerates_ability ///
|
/// regenerates_ability ///
|
||||||
|
|
|
@ -46,11 +46,9 @@ class heals_ability : public ability
|
||||||
public :
|
public :
|
||||||
heals_ability(const config* cfg);
|
heals_ability(const config* cfg);
|
||||||
const int amount() const;
|
const int amount() const;
|
||||||
const int max() const;
|
void set_heal(int amount);
|
||||||
void set_heal(int amount, int max);
|
|
||||||
private :
|
private :
|
||||||
int amount_;
|
int amount_;
|
||||||
int max_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class regenerates_ability : public ability
|
class regenerates_ability : public ability
|
||||||
|
|
|
@ -603,7 +603,7 @@ void ability_filter::add_filters(const config* cfg)
|
||||||
unit_type::unit_type(const unit_type& o)
|
unit_type::unit_type(const unit_type& o)
|
||||||
: variations_(o.variations_), cfg_(o.cfg_), race_(o.race_),
|
: variations_(o.variations_), cfg_(o.cfg_), race_(o.race_),
|
||||||
alpha_(o.alpha_), abilities_(o.abilities_),ability_tooltips_(o.ability_tooltips_),
|
alpha_(o.alpha_), abilities_(o.abilities_),ability_tooltips_(o.ability_tooltips_),
|
||||||
heals_filter_(o.heals_filter_), max_heals_(o.max_heals_), heals_(o.heals_),
|
heals_filter_(o.heals_filter_), heals_(o.heals_),
|
||||||
regenerates_filter_(o.regenerates_filter_),regenerates_(o.regenerates_),
|
regenerates_filter_(o.regenerates_filter_),regenerates_(o.regenerates_),
|
||||||
regeneration_(o.regeneration_),
|
regeneration_(o.regeneration_),
|
||||||
leadership_filter_(o.leadership_filter_), leadership_(o.leadership_),
|
leadership_filter_(o.leadership_filter_), leadership_(o.leadership_),
|
||||||
|
@ -700,7 +700,6 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
|
||||||
possibleTraits_.insert(possibleTraits_.end(),unit_traits.begin(),unit_traits.end());
|
possibleTraits_.insert(possibleTraits_.end(),unit_traits.begin(),unit_traits.end());
|
||||||
|
|
||||||
heals_ = 0;
|
heals_ = 0;
|
||||||
max_heals_ = 0;
|
|
||||||
regenerates_ = false;
|
regenerates_ = false;
|
||||||
regeneration_ = 0;
|
regeneration_ = 0;
|
||||||
steadfast_ = false;
|
steadfast_ = false;
|
||||||
|
@ -725,15 +724,13 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
|
||||||
if(!deprecated_abilities.empty()) {
|
if(!deprecated_abilities.empty()) {
|
||||||
LOG_STREAM(err, config) << "unit " << id() << " uses the ability=list tag, which is deprecated\n";
|
LOG_STREAM(err, config) << "unit " << id() << " uses the ability=list tag, which is deprecated\n";
|
||||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"heals") != deprecated_abilities.end()) {
|
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"heals") != deprecated_abilities.end()) {
|
||||||
heals_ = game_config::healer_heals_per_turn;
|
heals_ = game_config::heal_amount;
|
||||||
max_heals_ = game_config::heal_amount;
|
|
||||||
heals_filter_.unfilter();
|
heals_filter_.unfilter();
|
||||||
abilities_.push_back("heals");
|
abilities_.push_back("heals");
|
||||||
ability_tooltips_.push_back("heals");
|
ability_tooltips_.push_back("heals");
|
||||||
}
|
}
|
||||||
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"cures") != deprecated_abilities.end()) {
|
if(std::find(deprecated_abilities.begin(),deprecated_abilities.end(),"cures") != deprecated_abilities.end()) {
|
||||||
heals_ = game_config::curer_heals_per_turn;
|
heals_ = game_config::cure_amount;
|
||||||
max_heals_ = game_config::cure_amount;
|
|
||||||
heals_filter_.unfilter();
|
heals_filter_.unfilter();
|
||||||
abilities_.push_back("cures");
|
abilities_.push_back("cures");
|
||||||
ability_tooltips_.push_back("cures");
|
ability_tooltips_.push_back("cures");
|
||||||
|
@ -804,8 +801,7 @@ unit_type::unit_type(const config& cfg, const movement_type_map& mv_types,
|
||||||
} else {
|
} else {
|
||||||
ability_tooltips_.push_back("heals");
|
ability_tooltips_.push_back("heals");
|
||||||
}
|
}
|
||||||
heals_ = maximum<int>(heals_, lexical_cast_default<int>((**ab)["amount"],game_config::healer_heals_per_turn));
|
heals_ = maximum<int>(heals_, lexical_cast_default<int>((**ab)["amount"],game_config::heal_amount));
|
||||||
max_heals_ = maximum<int>(max_heals_, lexical_cast_default<int>((**ab)["max"],game_config::heal_amount));
|
|
||||||
heals_filter_.add_filters((*ab)->child("filter"));
|
heals_filter_.add_filters((*ab)->child("filter"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1285,11 +1281,6 @@ const std::vector<std::string>& unit_type::ability_tooltips() const
|
||||||
return ability_tooltips_;
|
return ability_tooltips_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_type::max_unit_healing() const
|
|
||||||
{
|
|
||||||
return max_heals_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int unit_type::heals() const
|
int unit_type::heals() const
|
||||||
{
|
{
|
||||||
return heals_;
|
return heals_;
|
||||||
|
|
|
@ -216,10 +216,6 @@ public:
|
||||||
const std::vector<std::string>& abilities() const;
|
const std::vector<std::string>& abilities() const;
|
||||||
const std::vector<std::string>& ability_tooltips() const;
|
const std::vector<std::string>& ability_tooltips() const;
|
||||||
|
|
||||||
//max_unit_healing returns the maximum hitpoints a unit next to this
|
|
||||||
//unit can heal per turn. heals returns the total amount of hitpoints
|
|
||||||
//this unit can heal out of all adjacent units
|
|
||||||
int max_unit_healing() const;
|
|
||||||
int heals() const;
|
int heals() const;
|
||||||
bool regenerates() const;
|
bool regenerates() const;
|
||||||
int regenerate_amount() const;
|
int regenerate_amount() const;
|
||||||
|
@ -280,7 +276,6 @@ private:
|
||||||
mutable std::string id_;
|
mutable std::string id_;
|
||||||
|
|
||||||
ability_filter heals_filter_;
|
ability_filter heals_filter_;
|
||||||
int max_heals_;
|
|
||||||
int heals_;
|
int heals_;
|
||||||
|
|
||||||
ability_filter regenerates_filter_;
|
ability_filter regenerates_filter_;
|
||||||
|
|
Loading…
Add table
Reference in a new issue