Add [teaching_anim] for abilities used like weapon specials given by an adjacent unit

When a unit gives adjacent units abilities used like weapon specials, and is not already showing an animation from giving a resistance or leadership effect, a [teaching_anim] can be played instead.
This commit is contained in:
newfrenchy83 2021-03-15 16:30:30 +01:00 committed by GitHub
parent 6db64459d2
commit e3b737cfd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 121 additions and 38 deletions

View file

@ -34,6 +34,7 @@
### WML Engine
* Standard Location Filters now support gives_income=yes|no to make it simpler to match villages regardless of owner
* Fixed ThemeWML `[label] font_rgb=` generating text elements with broken UTF-8 sequences.
* abilities used like weapon can call a [teaching_anim] instead of [leading_anim] now.
### Miscellaneous and Bug Fixes
* Added support for 1.14s tag names in `[terrain_defaults]` (issue #5308).
* Replaced legacy SDL_ttf/FriBidi-based font rendering used in old GUI1 code paths with Pango.

View file

@ -37,12 +37,9 @@
#enddef
#define INITIATIVE_ANIM FULL_IMAGE HALFWAYS_IMAGE
[leading_anim]
[teaching_anim]
[filter_attack]
special_id_active=initiative_anim
[not]
special_type_active=leadership
[/not]
[not]
special_id_active=firststrike
[/not]
@ -51,5 +48,5 @@
[frame]
image={HALFWAYS_IMAGE}:1,{FULL_IMAGE}:250,{HALFWAYS_IMAGE}:1
[/frame]
[/leading_anim]
[/teaching_anim]
#enddef

View file

@ -22,44 +22,42 @@
#enddef
#define LEADING_ANIM FULL_IMAGE HALFWAYS_IMAGE OFFSET_POSITION
# Define an animation of a unit waving/raising their weapon,
# with a gleam of light reflecting off it at the point specified by
# OFFSET_POSITION
{LEADING_ANIM_FILTER {FULL_IMAGE} {HALFWAYS_IMAGE} {OFFSET_POSITION} special_type_active=leadership}
#enddef
#define LEADING_ANIM_FILTER FULL_IMAGE HALFWAYS_IMAGE OFFSET_POSITION ATTACK
# Define an animation of a unit waving/raising their weapon,
# with a gleam of light reflecting off it at the point specified by
# OFFSET_POSITION
[leading_anim]
[filter_attack]
{ATTACK}
[/filter_attack]
{LEADING_BASE {FULL_IMAGE} {HALFWAYS_IMAGE} {OFFSET_POSITION}}
start_time=-126
[frame]
image={HALFWAYS_IMAGE}:1,{FULL_IMAGE}:250,{HALFWAYS_IMAGE}:1
[/frame]
halo_start_time=-100
[halo_frame]
halo="halo/misc/leadership-flare-[1~13].png:20"
halo_x,halo_y={OFFSET_POSITION}
[/halo_frame]
[/leading_anim]
#enddef
#define HELPING_ANIM FULL_IMAGE HALFWAYS_IMAGE OFFSET_POSITION
#define TEACHING_ANIM FULL_IMAGE HALFWAYS_IMAGE OFFSET_POSITION ATTACK
# Define an animation of a unit waving/raising their weapon,
# with a gleam of light reflecting off it at the point specified by
# OFFSET_POSITION
[resistance_anim]
{LEADING_BASE {FULL_IMAGE} {HALFWAYS_IMAGE} {OFFSET_POSITION}}
[/resistance_anim]
#enddef
[teaching_anim]
[filter_attack]
{ATTACK}
[/filter_attack]
start_time=-126
[frame]
image={HALFWAYS_IMAGE}:1,{FULL_IMAGE}:250,{HALFWAYS_IMAGE}:1
[/frame]
#define LEADING_BASE FULL_IMAGE HALFWAYS_IMAGE OFFSET_POSITION
start_time=-126
[frame]
image={HALFWAYS_IMAGE}:1,{FULL_IMAGE}:250,{HALFWAYS_IMAGE}:1
[/frame]
halo_start_time=-100
[halo_frame]
halo="halo/misc/leadership-flare-[1~13].png:20"
halo_x,halo_y={OFFSET_POSITION}
[/halo_frame]
halo_start_time=-100
[halo_frame]
halo="halo/misc/leadership-flare-[1~13].png:20"
halo_x,halo_y={OFFSET_POSITION}
[/halo_frame]
[/teaching_anim]
#enddef
#define DEFENSE_ANIM REACTION_IMAGE BASE_IMAGE HIT_SOUND

View file

@ -152,6 +152,11 @@
max=infinite
super="units/unit_type/$animation"
[/tag]
[tag]
name="teaching_anim"
max=infinite
super="units/unit_type/$animation"
[/tag]
[tag]
name="recruit_anim"
max=infinite

View file

@ -636,6 +636,7 @@ void unit_animation::add_anims( std::vector<unit_animation> & animations, const
add_simple_anim(animations, cfg, "resistance_anim", "resistance");
add_simple_anim(animations, cfg, "leading_anim", "leading");
add_simple_anim(animations, cfg, "teaching_anim", "teaching");
add_simple_anim(animations, cfg, "recruit_anim", "recruited");
add_simple_anim(animations, cfg, "recruiting_anim", "recruiting");
add_simple_anim(animations, cfg, "idle_anim", "idling", display::LAYER_UNIT_DEFAULT, false);
@ -1345,6 +1346,20 @@ void unit_animator::add_animation(unit_const_ptr animated_unit
animated_units_.push_back(std::move(tmp));
}
bool unit_animator::has_animation(unit_const_ptr animated_unit
, const std::string& event
, const map_location &src
, const map_location &dst
, const int value
, const unit_animation::hit_type hit_type
, const_attack_ptr attack
, const_attack_ptr second_attack
, int value2) const
{
display* disp = display::get_singleton();
return (animated_unit && animated_unit->anim_comp().choose_animation(*disp, src, event, dst, value, hit_type, attack, second_attack, value2));
}
void unit_animator::replace_anim_if_invalid(unit_const_ptr animated_unit
, const std::string& event
, const map_location &src

View file

@ -222,6 +222,29 @@ public:
, const_attack_ptr second_attack = nullptr
, int value2 = 0);
/** has_animation : return an boolean value if animated unit present and have animation specified, used for verify prensence of [leading_anim] or [resistance_anim] for playability of [teaching_anim]
* @return True if the @a animated_unit is present and have animation.
* @param animated_unit the unit who is checked.
* @param event the animation who is checked([leading_anim] or [resistance_anim].
* @param src the location of animated_unit.
* @param dst location of unit student(attacker or defender).
* @param value value of damage.
* @param hit_type type of damage inflicted.
* @param attack weapon used by student.
* @param second_attack weapon used by opponent.
* @param value2 i don't understand myself.but this value is used in choose_animation.
*/
bool has_animation(unit_const_ptr animated_unit
, const std::string& event
, const map_location& src = map_location::null_location()
, const map_location& dst = map_location::null_location()
, const int value = 0
, const unit_animation::hit_type hit_type =
unit_animation::hit_type::INVALID
, const_attack_ptr attack = nullptr
, const_attack_ptr second_attack = nullptr
, int value2 = 0) const;
void replace_anim_if_invalid(unit_const_ptr animated_unit
, const std::string& event
, const map_location& src = map_location::null_location()

View file

@ -657,11 +657,9 @@ void unit_attack(display * disp, game_board & board,
animator.add_animation(defender.shared_from_this(), defender_anim, def->get_location(), true, text, {255, 0, 0});
unit_ability_list abilities = attacker.get_abilities_weapons("leadership", weapon, secondary_attack);
for(auto& special : attacker.checking_tags()) {
abilities.append(weapon->list_ability(special));
}
for(const unit_ability& ability : abilities) {
unit_ability_list leadership_list = attacker.get_abilities_weapons("leadership", weapon, secondary_attack);
unit_ability_list resistance_list = defender.get_abilities_weapons("resistance", secondary_attack, weapon);
for(const unit_ability& ability : leadership_list) {
if(ability.teacher_loc == a) {
continue;
}
@ -678,7 +676,7 @@ void unit_attack(display * disp, game_board & board,
hit_type, weapon, secondary_attack, swing);
}
for(const unit_ability& ability : defender.get_abilities_weapons("resistance", secondary_attack, weapon)) {
for(const unit_ability& ability : resistance_list) {
if(ability.teacher_loc == a) {
continue;
}
@ -695,6 +693,52 @@ void unit_attack(display * disp, game_board & board,
hit_type, weapon, secondary_attack, swing);
}
unit_ability_list abilities = att->get_location();
for(auto& special : attacker.checking_tags()) {
abilities.append(weapon->list_ability(special));
}
for(const unit_ability& ability : abilities) {
if(ability.teacher_loc == a) {
continue;
}
if(ability.teacher_loc == b) {
continue;
}
bool leading_playable = false;
bool helping_playable = false;
for(const unit_ability& leader_list : leadership_list) {
if(ability.teacher_loc == leader_list.teacher_loc) {
leading_playable = true;
break;
}
}
for(const unit_ability& helper_list : resistance_list) {
if(ability.teacher_loc == helper_list.teacher_loc) {
helping_playable = true;
break;
}
}
unit_map::const_iterator leader = board.units().find(ability.teacher_loc);
assert(leader.valid());
leader->set_facing(ability.teacher_loc.get_relative_dir(a));
if(animator.has_animation(leader.get_shared_ptr(), "leading", ability.teacher_loc,
att->get_location(), damage, hit_type, weapon, secondary_attack, swing) && leading_playable){
continue;
}
if(animator.has_animation(leader.get_shared_ptr(), "resistance", ability.teacher_loc,
def->get_location(), damage, hit_type, weapon, secondary_attack, swing) && helping_playable){
continue;
}
animator.add_animation(leader.get_shared_ptr(), "teaching", ability.teacher_loc,
att->get_location(), damage, true, "", {0,0,0},
hit_type, weapon, secondary_attack, swing);
}
animator.start_animations();
animator.wait_until(0);