widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #16095
[Merge] lp:~widelands-dev/widelands/bug-1817664-overlooping-eva_fail into lp:widelands
Benedikt Straub has proposed merging lp:~widelands-dev/widelands/bug-1817664-overlooping-eva_fail into lp:widelands.
Commit message:
Shorten a soldier's last evade_failure animation if the soldier is about to die to prevent overlooping. The health bar falls gradually during an attack instead of one-shot.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #1817664 in widelands: "Bug in fight"
https://bugs.launchpad.net/widelands/+bug/1817664
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/bug-1817664-overlooping-eva_fail/+merge/363679
During battles, the evade_failure animation may overloop. If the soldier dies immediately afterwards, this can look like he is attacking while he dies (especially noticeable with ATL vs FRI). Shorten the last eva_fail anim if the soldier is going to die.
Debugging this, I also implemented that the soldier´s health bar falls gradually while he is being attacked, instead of one-shot half a second after the attack is visually over.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/bug-1817664-overlooping-eva_fail into lp:widelands.
=== modified file 'src/logic/map_objects/tribes/battle.cc'
--- src/logic/map_objects/tribes/battle.cc 2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/battle.cc 2019-02-26 18:55:11 +0000
@@ -137,6 +137,13 @@
return other_soldier;
}
+uint32_t Battle::get_pending_damage(const Soldier* for_whom) const {
+ if (for_whom == (first_strikes_ ? first_ : second_)) {
+ return damage_;
+ }
+ return 0;
+}
+
// TODO(unknown): Couldn't this code be simplified tremendously by doing all scheduling
// for one soldier and letting the other sleep until the battle is over?
// Could be, but we need to be able change the animations of the soldiers
@@ -167,10 +174,11 @@
// Apply pending damage
if (damage_ && oneReadyToFight) {
// Current attacker is last defender, so damage goes to current attacker
- if (first_strikes_)
+ if (first_strikes_) {
first_->damage(damage_);
- else
+ } else {
second_->damage(damage_);
+ }
damage_ = 0;
}
@@ -184,8 +192,9 @@
return schedule_destroy(game);
}
- if (!first_ || !second_)
+ if (!first_ || !second_) {
return soldier.skip_act();
+ }
// Here is a timeout to prevent battle freezes
if (waitingForOpponent && (game.get_gametime() - creationtime_) > 90 * 1000) {
@@ -248,10 +257,12 @@
molog("[battle] (%u) vs (%u) is %d, first strikes %d, last hit %d\n", soldier.serial(),
opponent(soldier)->serial(), this_soldier_is, first_strikes_, last_attack_hits_);
+ bool shorten = false;
if (this_soldier_is == 1) {
if (first_strikes_) {
if (last_attack_hits_) {
what_anim = "evade_failure_e";
+ shorten = true;
} else {
what_anim = "evade_success_e";
}
@@ -272,13 +283,17 @@
} else {
if (last_attack_hits_) {
what_anim = "evade_failure_w";
+ shorten = true;
} else {
what_anim = "evade_success_w";
}
}
}
+ // If the soldier will die as soon as the animation is complete, don't
+ // show it for the full length to prevent overlooping (bug 1817664)
+ shorten &= damage_ >= soldier.get_current_health();
molog("[battle] Starting animation %s for soldier %d\n", what_anim.c_str(), soldier.serial());
- soldier.start_task_idle(game, soldier.descr().get_rand_anim(game, what_anim.c_str()), 1000);
+ soldier.start_task_idle(game, soldier.descr().get_rand_anim(game, what_anim.c_str()), shorten ? 850 : 1000);
}
void Battle::calculate_round(Game& game) {
=== modified file 'src/logic/map_objects/tribes/battle.h'
--- src/logic/map_objects/tribes/battle.h 2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/battle.h 2019-02-26 18:55:11 +0000
@@ -74,6 +74,8 @@
return second_;
}
+ uint32_t get_pending_damage(const Soldier* for_whom) const;
+
// Returns the other soldier involved in this battle. CHECKs that the given
// soldier is participating in this battle. Can return nullptr, probably when the
// opponent has died.
=== modified file 'src/logic/map_objects/tribes/soldier.cc'
--- src/logic/map_objects/tribes/soldier.cc 2019-02-23 11:00:49 +0000
+++ src/logic/map_objects/tribes/soldier.cc 2019-02-26 18:55:11 +0000
@@ -505,7 +505,26 @@
kSoldierHealthBarWidth * 2 * scale, 5 * scale);
dst->fill_rect(energy_outer, RGBColor(255, 255, 255));
- int health_width = 2 * (kSoldierHealthBarWidth - 1) * current_health_ / get_max_health();
+ uint32_t health_to_show = current_health_;
+ if (battle_) {
+ uint32_t pending_damage = battle_->get_pending_damage(this);
+ if (pending_damage) {
+ int32_t timeshift = owner().egbase().get_gametime() - get_animstart();
+ if (timeshift < 0) {
+ timeshift = 0;
+ } else if (timeshift > 1000) {
+ timeshift = 1000;
+ }
+ pending_damage *= timeshift;
+ pending_damage /= 1000;
+ if (pending_damage > health_to_show) {
+ health_to_show = 0;
+ } else {
+ health_to_show -= pending_damage;
+ }
+ }
+ }
+ int health_width = 2 * (kSoldierHealthBarWidth - 1) * health_to_show / get_max_health();
Recti energy_inner(draw_position + Vector2i(-kSoldierHealthBarWidth + 1, 1) * scale,
health_width * scale, 3 * scale);
Recti energy_complement(energy_inner.origin() + Vector2i(health_width, 0) * scale,
Follow ups