changing slow again, now it halves damage
This commit is contained in:
parent
fa4abb9255
commit
b14612d88d
6 changed files with 87 additions and 39 deletions
|
@ -116,10 +116,8 @@ SVN trunk (1.1.x):
|
|||
* backstab now works if opposite unit is non-incapacitated enemy of defender
|
||||
* prevented stoned units from being healed
|
||||
* slow does not remove an attack anymore
|
||||
* hitting with slow changes attack order to allow attacker to strike again
|
||||
* slowed units lose initiative on fight
|
||||
* slow still temporarily doubles movement cost
|
||||
* slowed units do not emit zone of control (ZOC)
|
||||
* slowed units see the damage they deal halved immediately
|
||||
* unit modifications now round toward original value instead of truncating
|
||||
* changed resilient trait bonus from +7hp to +10%+3hp
|
||||
* decreased strong trait hitpoints bonus from 2 to 1
|
||||
|
|
|
@ -26,7 +26,7 @@ tip_of_day25= _ "Read the hotkeys list in the preferences menu."
|
|||
tip_of_day26= _ "If you move a unit, but don't attack or discover any additional information, you can undo your move by pressing 'u'."
|
||||
tip_of_day27= _ "You can see how far enemy units can move by moving the mouse cursor over them."
|
||||
tip_of_day28= _ "Use healers to support your attacks - they will win you battles without needing to attack anything themselves."
|
||||
tip_of_day29= _ "The 'slow' attack ability makes enemy units move slower, but it also removes their zone of control, allowing your wounded units to escape or helping you reach fleeing enemy units."
|
||||
tip_of_day29= _ "The 'slow' attack ability makes enemy units move slower, but it also halves the damage they do on all attack."
|
||||
tip_of_day30= _ "Holy attacks are very powerful against undead."
|
||||
tip_of_day31= _ "Units are healed when they advance a level. Used wisely, this can turn a fight."
|
||||
tip_of_day32= _ "Charging units are best used against enemies they can kill with a single blow."
|
||||
|
|
|
@ -708,18 +708,26 @@ void attack(display& gui, const gamemap& map,
|
|||
int orig_defends = stats.ndefends;
|
||||
|
||||
int to_the_death = stats.to_the_death ? 30 : 0;
|
||||
bool slow_affects_attacker = a->second.has_flag("slowed");
|
||||
bool slow_affects_defender = d->second.has_flag("slowed");
|
||||
|
||||
static const std::string poison_string("poison");
|
||||
|
||||
while(stats.nattacks > 0 || stats.ndefends > 0) {
|
||||
LOG_NG << "start of attack loop...\n";
|
||||
|
||||
if(stats.nattacks > 0 && stats.defender_strikes_first == false && slow_affects_attacker == false) {
|
||||
if(stats.nattacks > 0 && stats.defender_strikes_first == false) {
|
||||
const int ran_num = get_random();
|
||||
bool hits = (ran_num%100) < stats.chance_to_hit_defender;
|
||||
|
||||
int damage_defender_takes;
|
||||
if(hits) {
|
||||
if(a->second.has_flag("slowed")) {
|
||||
damage_defender_takes = round_damage(stats.damage_defender_takes,1,2);
|
||||
} else {
|
||||
damage_defender_takes = stats.damage_defender_takes;
|
||||
}
|
||||
} else {
|
||||
damage_defender_takes = 0;
|
||||
}
|
||||
//make sure that if we're serializing a game here,
|
||||
//we got the same results as the game did originally
|
||||
const config* ran_results = get_random_results();
|
||||
|
@ -746,18 +754,18 @@ void attack(display& gui, const gamemap& map,
|
|||
<< " (over-riding game calculations with data source results)\n";
|
||||
hits = results_hits;
|
||||
}
|
||||
if(results_damage != stats.damage_defender_takes) {
|
||||
if(results_damage != damage_defender_takes) {
|
||||
ERR_NW << "SYNC: In attack " << unit_dump(*a) << " vs " << unit_dump(*d)
|
||||
<< ": the data source says the hit did " << results_damage
|
||||
<< " damage, while in-game calculations show the hit doing "
|
||||
<< stats.damage_defender_takes
|
||||
<< damage_defender_takes
|
||||
<< " damage (over-riding game calculations with data source results)\n";
|
||||
stats.damage_defender_takes = results_damage;
|
||||
damage_defender_takes = results_damage;
|
||||
}
|
||||
}
|
||||
|
||||
bool dies = unit_display::unit_attack(gui,units,map,attacker,defender,
|
||||
hits ? stats.damage_defender_takes : 0,
|
||||
damage_defender_takes,
|
||||
a->second.attacks()[attack_with]);
|
||||
|
||||
LOG_NG << "done attacking\n";
|
||||
|
@ -771,7 +779,7 @@ void attack(display& gui, const gamemap& map,
|
|||
cfg["hits"] = (hits ? "yes" : "no");
|
||||
cfg["dies"] = (dies ? "yes" : "no");
|
||||
|
||||
cfg["damage"] = lexical_cast<std::string>(stats.damage_defender_takes);
|
||||
cfg["damage"] = lexical_cast<std::string>(damage_defender_takes);
|
||||
cfg["chance"] = lexical_cast<std::string>(stats.chance_to_hit_defender);
|
||||
|
||||
set_random_results(cfg);
|
||||
|
@ -790,10 +798,16 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
if(dies || hits) {
|
||||
if(stats.amount_attacker_drains > 0) {
|
||||
int amount_drained;
|
||||
if(a->second.has_flag("slowed")) {
|
||||
amount_drained = round_damage(stats.amount_attacker_drains,1,2);
|
||||
} else {
|
||||
amount_drained = stats.amount_attacker_drains;
|
||||
}
|
||||
char buf[50];
|
||||
snprintf(buf,sizeof(buf),"%d",stats.amount_attacker_drains);
|
||||
snprintf(buf,sizeof(buf),"%d",amount_drained);
|
||||
gui.float_label(a->first,buf,0,255,0);
|
||||
a->second.heal(stats.amount_attacker_drains);
|
||||
a->second.heal(amount_drained);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -860,8 +874,7 @@ void attack(display& gui, const gamemap& map,
|
|||
d->second.set_flag("poisoned");
|
||||
}
|
||||
|
||||
if(stats.attacker_slows) {
|
||||
slow_affects_defender = true;
|
||||
if(stats.attacker_slows && d->second.has_flag("slowed") == false) {
|
||||
gui.float_label(d->first,_("slowed"),255,0,0);
|
||||
d->second.set_flag("slowed");
|
||||
}
|
||||
|
@ -879,20 +892,26 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
--stats.nattacks;
|
||||
}
|
||||
// slow and initiative are cumulative
|
||||
if(!stats.defender_strikes_first) {
|
||||
slow_affects_attacker = false;
|
||||
}
|
||||
|
||||
//if the defender got to strike first, they use it up here.
|
||||
stats.defender_strikes_first = false;
|
||||
|
||||
if(stats.ndefends > 0 && slow_affects_defender == false) {
|
||||
if(stats.ndefends > 0 ) {
|
||||
LOG_NG << "doing defender attack...\n";
|
||||
|
||||
const int ran_num = get_random();
|
||||
bool hits = (ran_num%100) < stats.chance_to_hit_attacker;
|
||||
|
||||
int damage_attacker_takes;
|
||||
if(hits) {
|
||||
if(d->second.has_flag("slowed")) {
|
||||
damage_attacker_takes = round_damage(stats.damage_attacker_takes,1,2);
|
||||
} else {
|
||||
damage_attacker_takes = stats.damage_attacker_takes;
|
||||
}
|
||||
} else {
|
||||
damage_attacker_takes = 0;
|
||||
}
|
||||
//make sure that if we're serializing a game here,
|
||||
//we got the same results as the game did originally
|
||||
const config* ran_results = get_random_results();
|
||||
|
@ -919,18 +938,18 @@ void attack(display& gui, const gamemap& map,
|
|||
<< " (over-riding game calculations with data source results)\n";
|
||||
hits = results_hits;
|
||||
}
|
||||
if(results_damage != stats.damage_attacker_takes) {
|
||||
if(results_damage != damage_attacker_takes) {
|
||||
ERR_NW << "SYNC: In defend " << unit_dump(*a) << " vs " << unit_dump(*d)
|
||||
<< ": the data source says the hit did " << results_damage
|
||||
<< " damage, while in-game calculations show the hit doing "
|
||||
<< stats.damage_attacker_takes
|
||||
<< damage_attacker_takes
|
||||
<< " damage (over-riding game calculations with data source results)\n";
|
||||
stats.damage_attacker_takes = results_damage;
|
||||
damage_attacker_takes = results_damage;
|
||||
}
|
||||
}
|
||||
|
||||
bool dies = unit_display::unit_attack(gui,units,map,defender,attacker,
|
||||
hits ? stats.damage_attacker_takes : 0,
|
||||
damage_attacker_takes,
|
||||
d->second.attacks()[stats.defend_with]);
|
||||
|
||||
attack_stats.defend_result(hits ? (dies ? statistics::attack_context::KILLS : statistics::attack_context::HITS)
|
||||
|
@ -940,7 +959,7 @@ void attack(display& gui, const gamemap& map,
|
|||
config cfg;
|
||||
cfg["hits"] = (hits ? "yes" : "no");
|
||||
cfg["dies"] = (dies ? "yes" : "no");
|
||||
cfg["damage"] = lexical_cast<std::string>(stats.damage_attacker_takes);
|
||||
cfg["damage"] = lexical_cast<std::string>(damage_attacker_takes);
|
||||
cfg["chance"] = lexical_cast<std::string>(stats.chance_to_hit_attacker);
|
||||
|
||||
set_random_results(cfg);
|
||||
|
@ -959,10 +978,16 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
if(hits || dies){
|
||||
if(stats.amount_defender_drains > 0) {
|
||||
int amount_drained;
|
||||
if(d->second.has_flag("slowed")) {
|
||||
amount_drained = round_damage(stats.amount_defender_drains,1,2);
|
||||
} else {
|
||||
amount_drained = stats.amount_defender_drains;
|
||||
}
|
||||
char buf[50];
|
||||
snprintf(buf,sizeof(buf),"%d",stats.amount_defender_drains);
|
||||
snprintf(buf,sizeof(buf),"%d",amount_drained);
|
||||
gui.float_label(d->first,buf,0,255,0);
|
||||
d->second.heal(stats.amount_defender_drains);
|
||||
d->second.heal(amount_drained);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1026,8 +1051,7 @@ void attack(display& gui, const gamemap& map,
|
|||
a->second.set_flag("poisoned");
|
||||
}
|
||||
|
||||
if(stats.defender_slows) {
|
||||
slow_affects_attacker = true;
|
||||
if(stats.defender_slows && a->second.has_flag("slowed") == false) {
|
||||
gui.float_label(a->first,_("slowed"),255,0,0);
|
||||
a->second.set_flag("slowed");
|
||||
}
|
||||
|
@ -1046,7 +1070,6 @@ void attack(display& gui, const gamemap& map,
|
|||
|
||||
--stats.ndefends;
|
||||
}
|
||||
slow_affects_defender = false;
|
||||
|
||||
// continue the fight to death; if one of the units got stoned,
|
||||
// either nattacks or ndefends is -1
|
||||
|
|
|
@ -418,6 +418,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
|
||||
int defenderxp = 0;
|
||||
|
||||
bool defender_slowed= defend_it->second.has_flag("slowed");
|
||||
|
||||
int defhp = target_hp;
|
||||
for(size_t i = 0; i != movements.size() && defhp; ++i) {
|
||||
|
@ -435,6 +436,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
}
|
||||
|
||||
const bool on_village = map.is_village(movements[i].second);
|
||||
bool attacker_slowed= att->second.has_flag("slowed");
|
||||
|
||||
//up to double the value of a unit based on experience
|
||||
cost += (double(att->second.experience())/
|
||||
|
@ -449,17 +451,26 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
if(attacks && !defender_strikes_first) {
|
||||
const int roll = rand()%100;
|
||||
if(roll < stat.chance_to_hit_defender) {
|
||||
defhp -= stat.damage_defender_takes;
|
||||
if(attacker_slowed) {
|
||||
defhp -= round_damage(stat.damage_defender_takes,1,2);
|
||||
atthp += round_damage(stat.amount_attacker_drains,1,2);
|
||||
} else {
|
||||
defhp -= stat.damage_defender_takes;
|
||||
atthp += stat.amount_attacker_drains;
|
||||
}
|
||||
if(defhp <= 0) {
|
||||
defhp = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
atthp += stat.amount_attacker_drains;
|
||||
if(atthp > hitpoints[i]) {
|
||||
atthp = hitpoints[i];
|
||||
}
|
||||
|
||||
if(stat.attacker_slows ) {
|
||||
defender_slowed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
--attacks;
|
||||
|
@ -470,7 +481,13 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
if(defends) {
|
||||
const int roll = rand()%100;
|
||||
if(roll < stat.chance_to_hit_attacker) {
|
||||
atthp -= stat.damage_attacker_takes;
|
||||
if(attacker_slowed) {
|
||||
atthp -= round_damage(stat.damage_attacker_takes,1,2);
|
||||
defhp += round_damage(stat.amount_defender_drains,1,2);
|
||||
} else {
|
||||
atthp -= stat.damage_attacker_takes;
|
||||
defhp += stat.amount_defender_drains;
|
||||
}
|
||||
if(atthp <= 0) {
|
||||
atthp = 0;
|
||||
|
||||
|
@ -481,10 +498,12 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units, int num_s
|
|||
break;
|
||||
}
|
||||
|
||||
defhp += stat.amount_defender_drains;
|
||||
if(defhp > target_max_hp) {
|
||||
defhp = target_max_hp;
|
||||
}
|
||||
if(stat.defender_slows) {
|
||||
attacker_slowed = true;
|
||||
}
|
||||
}
|
||||
|
||||
--defends;
|
||||
|
|
|
@ -137,7 +137,7 @@ report generate_report(TYPE type, const gamemap& map, const unit_map& units,
|
|||
}
|
||||
if(u->second.has_flag("slowed")) {
|
||||
unit_status << "misc/slowed.png";
|
||||
tooltip << _("slowed: ") << _("This unit has been slowed. It emits no zone of control, moves at half speed and enemies will be able to strike earlier once during a fight.");
|
||||
tooltip << _("slowed: ") << _("This unit has been slowed. It will only deal half its normal damage when attacking.");
|
||||
res.add_image(unit_status,tooltip);
|
||||
}
|
||||
if(u->second.has_flag("poisoned")) {
|
||||
|
@ -234,11 +234,19 @@ Units cannot be killed by poison alone. The poison will not reduce it below 1 HP
|
|||
const std::string& lang_type = gettext(at_it->type().c_str());
|
||||
str.str("");
|
||||
str << "<245,230,193>";
|
||||
str << at_it->damage() << "-" ;
|
||||
if(u->second.has_flag("slowed")) {
|
||||
str << round_damage(at_it->damage(),1,2) << "-" ;
|
||||
} else {
|
||||
str << at_it->damage() << "-" ;
|
||||
}
|
||||
str << at_it->num_swarm_attacks(u->second.hitpoints(), u->second.max_hitpoints());
|
||||
str << " " << at_it->name();
|
||||
tooltip << at_it->name() << "\n";
|
||||
tooltip << at_it->damage() << " " << _("damage") << ", ";
|
||||
if(u->second.has_flag("slowed")) {
|
||||
tooltip << round_damage(at_it->damage(),1,2) << " " << _("damage") << ", ";
|
||||
} else {
|
||||
tooltip << at_it->damage() << " " << _("damage") << ", ";
|
||||
}
|
||||
tooltip << at_it->num_swarm_attacks(u->second.hitpoints(), u->second.max_hitpoints());
|
||||
tooltip << " " << _("attacks");
|
||||
|
||||
|
|
|
@ -518,7 +518,7 @@ bool unit::has_goto() const
|
|||
|
||||
bool unit::emits_zoc() const
|
||||
{
|
||||
return type().has_zoc() && stone() == false && !has_flag("slowed");
|
||||
return type().has_zoc() && stone() == false;
|
||||
}
|
||||
|
||||
bool unit::matches_filter(const config& cfg) const
|
||||
|
|
Loading…
Add table
Reference in a new issue