changing slow again, now it halves damage

This commit is contained in:
Jérémy Rosen 2005-12-17 10:34:07 +00:00
parent fa4abb9255
commit b14612d88d
6 changed files with 87 additions and 39 deletions

View file

@ -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

View file

@ -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."

View file

@ -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

View file

@ -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;

View file

@ -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");

View file

@ -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