Compare commits
1
Commits
5e39cfca8e
...
ebddf353d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebddf353d4 |
@@ -8,6 +8,7 @@ use bevy::prelude::*;
|
|||||||
use bevy_ggrs::{Rollback, RollbackApp, prelude::GgrsSchedule};
|
use bevy_ggrs::{Rollback, RollbackApp, prelude::GgrsSchedule};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::fighter::FighterInvulnerabilityState;
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::{
|
fighter::{
|
||||||
Fighter, FighterAttributes, FighterFacingDirection, FighterHitboxes,
|
Fighter, FighterAttributes, FighterFacingDirection, FighterHitboxes,
|
||||||
@@ -112,7 +113,7 @@ impl KnockbackType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct Knockback(FGi32);
|
pub struct Knockback(FGi32);
|
||||||
|
|
||||||
impl Knockback {
|
impl Knockback {
|
||||||
@@ -157,6 +158,23 @@ impl AttackAngle {
|
|||||||
pub fn make_sakurai() -> Self {
|
pub fn make_sakurai() -> Self {
|
||||||
Self::Sakurai
|
Self::Sakurai
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_angle(&self, knockback: &Knockback, is_receiver_grounded: bool, game_settings: &GameSettings) -> FGi32 {
|
||||||
|
match self {
|
||||||
|
AttackAngle::Normal(angle) => {
|
||||||
|
*angle
|
||||||
|
},
|
||||||
|
AttackAngle::Sakurai => {
|
||||||
|
if !is_receiver_grounded {
|
||||||
|
game_settings.fighter_common.sakurai_angle_aerial_angle
|
||||||
|
} else if knockback.0 > game_settings.fighter_common.sakurai_angle_knockback_threshold {
|
||||||
|
game_settings.fighter_common.sakurai_angle_high_knockback_angle
|
||||||
|
} else {
|
||||||
|
game_settings.fighter_common.sakurai_angle_low_knockback_angle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Reflect, PartialEq, Eq, Hash, Clone, Debug, Default, Copy)]
|
#[derive(Serialize, Deserialize, Reflect, PartialEq, Eq, Hash, Clone, Debug, Default, Copy)]
|
||||||
@@ -526,21 +544,27 @@ pub fn intersect_attacks_with_hurtboxes(
|
|||||||
&Player,
|
&Player,
|
||||||
&FighterStaleMoveQueue,
|
&FighterStaleMoveQueue,
|
||||||
)>,
|
)>,
|
||||||
query_attacked: Query<(Entity, &FighterSolvedHurtboxes)>,
|
query_attacked: Query<(Entity, &FighterSolvedHurtboxes, &FighterInvulnerabilityState)>,
|
||||||
mut pending_hits: ResMut<FighterPendingHits>,
|
mut pending_hits: ResMut<FighterPendingHits>,
|
||||||
attack_scripts: Res<Assets<FighterAttackScript>>,
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
) {
|
) {
|
||||||
pending_hits.0.clear();
|
pending_hits.0.clear();
|
||||||
|
|
||||||
for &entity_receiving in &roster.0 {
|
for &entity_receiving in &roster.0 {
|
||||||
let Ok((_, hurtboxes)) = query_attacked.get(entity_receiving) else {
|
let Ok((_, hurtboxes, invuln_state)) = query_attacked.get(entity_receiving) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if matches!(*invuln_state, FighterInvulnerabilityState::Intangible { .. }) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for &entity_hurting in &roster.0 {
|
for &entity_hurting in &roster.0 {
|
||||||
if entity_hurting == entity_receiving {
|
if entity_hurting == entity_receiving {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let Ok((_, mut hitboxes, _, _, _)) = query_attacker.get_mut(entity_hurting) else {
|
let Ok((_, mut hitboxes, _, _, _)) = query_attacker.get_mut(entity_hurting) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -581,8 +605,7 @@ pub fn intersect_attacks_with_hurtboxes(
|
|||||||
attack_kind: active_attack.kind,
|
attack_kind: active_attack.kind,
|
||||||
hitbox_index: hitting_hitbox_idx,
|
hitbox_index: hitting_hitbox_idx,
|
||||||
});
|
});
|
||||||
info!("Hit by hitbox {}!!!!", hitting_hitbox_idx);
|
|
||||||
|
|
||||||
active_attack.hit_fighters.push(entity_receiving);
|
active_attack.hit_fighters.push(entity_receiving);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,16 @@ use bevy_ggrs::prelude::GgrsSchedule;
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
fighter::{
|
fighter::{
|
||||||
Fighter, FighterFacingDirection, FighterHitboxes, FighterHitstop, FighterHitstopShake, FighterHitstopShakeKind, FighterHitstopShakeRole, FighterPendingHitReaction, FighterStaleMoveQueue, errors::FighterErrors, manifest::FighterManifest, state::FighterState,
|
Fighter, FighterFacingDirection, FighterHitboxes, FighterHitstop, FighterHitstopShake,
|
||||||
}, game_settings::GameSettings, math::{int::FGi32}, player::Player, schedule::GameplaySet, scripting::FighterAttackScript,
|
FighterHitstopShakeKind, FighterHitstopShakeRole, FighterPendingHitReaction,
|
||||||
|
FighterStaleMoveQueue, FighterSurfaceState, errors::FighterErrors,
|
||||||
|
manifest::FighterManifest, state::FighterState,
|
||||||
|
},
|
||||||
|
game_settings::GameSettings,
|
||||||
|
math::int::FGi32,
|
||||||
|
player::Player,
|
||||||
|
schedule::GameplaySet,
|
||||||
|
scripting::FighterAttackScript,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn resolve_fighter_hits(
|
pub fn resolve_fighter_hits(
|
||||||
@@ -18,7 +26,14 @@ pub fn resolve_fighter_hits(
|
|||||||
&mut FighterHitstop,
|
&mut FighterHitstop,
|
||||||
&mut FighterHitstopShake,
|
&mut FighterHitstopShake,
|
||||||
)>,
|
)>,
|
||||||
mut receiver: Query<(&mut FighterDamage, &Fighter, &mut FighterPendingHitReaction, &FighterState)>,
|
mut receiver: Query<(
|
||||||
|
&mut FighterDamage,
|
||||||
|
&Fighter,
|
||||||
|
&mut FighterPendingHitReaction,
|
||||||
|
&FighterState,
|
||||||
|
&FighterInvulnerabilityState,
|
||||||
|
&FighterSurfaceState,
|
||||||
|
)>,
|
||||||
attack_scripts: Res<Assets<FighterAttackScript>>,
|
attack_scripts: Res<Assets<FighterAttackScript>>,
|
||||||
game_settings: Res<GameSettings>,
|
game_settings: Res<GameSettings>,
|
||||||
fighter_manifests: Res<Assets<FighterManifest>>,
|
fighter_manifests: Res<Assets<FighterManifest>>,
|
||||||
@@ -33,7 +48,14 @@ pub fn resolve_fighter_hits(
|
|||||||
.position(|hit| hit.defender != defender)
|
.position(|hit| hit.defender != defender)
|
||||||
.map_or(hits.len(), |offset| hit_offset + offset);
|
.map_or(hits.len(), |offset| hit_offset + offset);
|
||||||
|
|
||||||
let Ok((mut receiver_damage, fighter, mut pending_reaction, receiver_state)) = receiver.get_mut(defender)
|
let Ok((
|
||||||
|
mut receiver_damage,
|
||||||
|
fighter,
|
||||||
|
mut pending_reaction,
|
||||||
|
receiver_state,
|
||||||
|
invuln_state,
|
||||||
|
receiver_surface_state,
|
||||||
|
)) = receiver.get_mut(defender)
|
||||||
else {
|
else {
|
||||||
hit_offset = next_defender;
|
hit_offset = next_defender;
|
||||||
continue;
|
continue;
|
||||||
@@ -79,10 +101,12 @@ pub fn resolve_fighter_hits(
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
let angle = match &hitbox.angle {
|
let angle = hitbox.angle.get_angle(
|
||||||
AttackAngle::Normal(angle) => *angle,
|
&knockback,
|
||||||
AttackAngle::Sakurai => FGi32::lit("32.0"),
|
receiver_surface_state.is_grounded(),
|
||||||
};
|
&game_settings,
|
||||||
|
);
|
||||||
|
dbg!(knockback, angle);
|
||||||
let launch_angle = if facing_left {
|
let launch_angle = if facing_left {
|
||||||
FGi32::lit("180.0") - angle
|
FGi32::lit("180.0") - angle
|
||||||
} else {
|
} else {
|
||||||
@@ -100,15 +124,21 @@ pub fn resolve_fighter_hits(
|
|||||||
hitstun_frames: knockback.get_hitstun_frames(&game_settings),
|
hitstun_frames: knockback.get_hitstun_frames(&game_settings),
|
||||||
hitstop_frames: hitstop,
|
hitstop_frames: hitstop,
|
||||||
kind: HitReactionKind::Flinch,
|
kind: HitReactionKind::Flinch,
|
||||||
damage: FighterDamage(attack_damage)
|
damage: FighterDamage(attack_damage),
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
receiver_damage.0 += total_damage_received_this_frame;
|
match invuln_state {
|
||||||
|
FighterInvulnerabilityState::Vulnerable => {
|
||||||
|
receiver_damage.0 += total_damage_received_this_frame
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
for (attacker_entity, _, reaction) in &reactions {
|
for (attacker_entity, _, reaction) in &reactions {
|
||||||
let Ok((.., _, mut hitstop, mut hitstop_shake)) = attacker.get_mut(*attacker_entity) else {
|
let Ok((.., _, mut hitstop, mut hitstop_shake)) = attacker.get_mut(*attacker_entity)
|
||||||
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,7 +149,9 @@ pub fn resolve_fighter_hits(
|
|||||||
FighterHitstopShakeKind::Vertical
|
FighterHitstopShakeKind::Vertical
|
||||||
};
|
};
|
||||||
hitstop.remaining_frames = reaction.hitstop_frames.0;
|
hitstop.remaining_frames = reaction.hitstop_frames.0;
|
||||||
let shake_frames = reaction.hitstop_frames.calculate_shake_frames(&game_settings);
|
let shake_frames = reaction
|
||||||
|
.hitstop_frames
|
||||||
|
.calculate_shake_frames(&game_settings);
|
||||||
hitstop_shake.total_frames = shake_frames;
|
hitstop_shake.total_frames = shake_frames;
|
||||||
hitstop_shake.remaining_frames = shake_frames;
|
hitstop_shake.remaining_frames = shake_frames;
|
||||||
hitstop_shake.kind = shake_kind;
|
hitstop_shake.kind = shake_kind;
|
||||||
@@ -127,16 +159,23 @@ pub fn resolve_fighter_hits(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pending_reaction.0 = reactions
|
match invuln_state {
|
||||||
.into_iter()
|
FighterInvulnerabilityState::Vulnerable => {
|
||||||
.min_by(|(_, port_a, _), (_, port_b, _)| port_a.cmp(port_b))
|
pending_reaction.0 = reactions
|
||||||
.map(|(_, _, reaction)| reaction);
|
.into_iter()
|
||||||
|
.min_by(|(_, port_a, _), (_, port_b, _)| port_a.cmp(port_b))
|
||||||
|
.map(|(_, _, reaction)| reaction);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
hit_offset = next_defender;
|
hit_offset = next_defender;
|
||||||
}
|
}
|
||||||
|
|
||||||
for hit in hits {
|
for hit in hits {
|
||||||
let Ok((mut stale_move_queue, _facing_direction, mut hitboxes, ..)) = attacker.get_mut(hit.attacker) else {
|
let Ok((mut stale_move_queue, _facing_direction, mut hitboxes, ..)) =
|
||||||
|
attacker.get_mut(hit.attacker)
|
||||||
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+35
-4
@@ -85,12 +85,12 @@ pub struct FighterHitstop {
|
|||||||
pub remaining_frames: u32,
|
pub remaining_frames: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Default, Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Component, Default, Copy, Clone, Hash)]
|
||||||
pub enum FighterInvulnerabilityState {
|
pub enum FighterInvulnerabilityState {
|
||||||
#[default]
|
#[default]
|
||||||
Vulnerable,
|
Vulnerable,
|
||||||
Invulnerable,
|
Invulnerable { frames_remaining: Option<u32> },
|
||||||
Intangible
|
Intangible { frames_remaining: Option<u32> }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FighterFacingDirection {
|
impl FighterFacingDirection {
|
||||||
@@ -179,7 +179,7 @@ impl Plugin for FighterPlugin {
|
|||||||
)
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
GgrsSchedule,
|
GgrsSchedule,
|
||||||
(state::state_update_system, decay_hitstop)
|
(state::state_update_system, decay_hitstop, decay_invulnerability)
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(GameplaySet::StateUpdate),
|
.in_set(GameplaySet::StateUpdate),
|
||||||
)
|
)
|
||||||
@@ -360,3 +360,34 @@ pub fn decay_hitstop(query: Query<(&mut FighterHitstop, &mut FighterHitstopShake
|
|||||||
hitstop_shake.remaining_frames = hitstop_shake.remaining_frames.saturating_sub(1);
|
hitstop_shake.remaining_frames = hitstop_shake.remaining_frames.saturating_sub(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decay_invulnerability(query: Query<&mut FighterInvulnerabilityState>) {
|
||||||
|
for invuln_state in query {
|
||||||
|
let invuln_state = invuln_state.into_inner();
|
||||||
|
let frames_remaining = match invuln_state {
|
||||||
|
FighterInvulnerabilityState::Vulnerable => None,
|
||||||
|
FighterInvulnerabilityState::Invulnerable { frames_remaining } => {
|
||||||
|
if let Some(frames_remaining) = frames_remaining {
|
||||||
|
*frames_remaining = frames_remaining.saturating_sub(1);
|
||||||
|
Some(*frames_remaining)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FighterInvulnerabilityState::Intangible { frames_remaining } => {
|
||||||
|
if let Some(frames_remaining) = frames_remaining {
|
||||||
|
*frames_remaining = frames_remaining.saturating_sub(1);
|
||||||
|
Some(*frames_remaining)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(frames_remaining) = frames_remaining {
|
||||||
|
if frames_remaining == 0 {
|
||||||
|
*invuln_state = FighterInvulnerabilityState::Vulnerable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,14 +33,9 @@ impl FighterStateImpl for AirDodgeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, state_context: &mut UpdateContext) {
|
fn update(&mut self, state_context: &mut UpdateContext) {
|
||||||
let airdodge_intangible_end = state_context.fighter_attributes.air_dodge_intangible_start
|
let airdodge_intangible_end = state_context.fighter_attributes.air_dodge_intangible_start + state_context.fighter_attributes.air_dodge_intangible_duration;
|
||||||
+ state_context
|
if state_context.animation_frame == state_context.fighter_attributes.air_dodge_intangible_start {
|
||||||
.fighter_attributes
|
*state_context.vulnerability = FighterInvulnerabilityState::Intangible { frames_remaining: Some(state_context.fighter_attributes.air_dodge_intangible_duration) };
|
||||||
.air_dodge_intangible_duration;
|
|
||||||
if state_context.animation_frame
|
|
||||||
== state_context.fighter_attributes.air_dodge_intangible_start
|
|
||||||
{
|
|
||||||
*state_context.vulnerability = FighterInvulnerabilityState::Intangible;
|
|
||||||
} else if state_context.animation_frame >= airdodge_intangible_end {
|
} else if state_context.animation_frame >= airdodge_intangible_end {
|
||||||
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
|
*state_context.vulnerability = FighterInvulnerabilityState::Vulnerable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{fighter::{animation::AnimKind, state::{FighterState, FighterStateImpl, air::AirborneStateCommon, fall::FallState}}, math::vec::FGVec2};
|
use crate::{fighter::{FighterInvulnerabilityState, animation::AnimKind, state::{FighterState, FighterStateImpl, air::AirborneStateCommon, fall::FallState}}, math::vec::FGVec2};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct AngelState {
|
pub struct AngelState {
|
||||||
@@ -38,6 +38,7 @@ impl FighterStateImpl for AngelState {
|
|||||||
fn on_enter(&mut self, state_context: &mut super::EnterContext) {
|
fn on_enter(&mut self, state_context: &mut super::EnterContext) {
|
||||||
state_context.play_animation(AnimKind::Wait, true);
|
state_context.play_animation(AnimKind::Wait, true);
|
||||||
state_context.velocity.0 = FGVec2::ZERO;
|
state_context.velocity.0 = FGVec2::ZERO;
|
||||||
|
*state_context.vulnerability = FighterInvulnerabilityState::Invulnerable { frames_remaining: Some(state_context.game_settings.fighter_common.angel_platform_invulnerability_duration) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_collision_interrupt(
|
fn check_collision_interrupt(
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ pub struct EnterContext<'a> {
|
|||||||
pub facing_direction: &'a mut FighterFacingDirection,
|
pub facing_direction: &'a mut FighterFacingDirection,
|
||||||
pub animation_frame: &'a mut FighterAnimationFrame,
|
pub animation_frame: &'a mut FighterAnimationFrame,
|
||||||
pub surface: &'a mut FighterSurfaceState,
|
pub surface: &'a mut FighterSurfaceState,
|
||||||
|
pub vulnerability: &'a mut FighterInvulnerabilityState,
|
||||||
pub fighter_attributes: &'a FighterAttributes,
|
pub fighter_attributes: &'a FighterAttributes,
|
||||||
pub attack_script_assets: &'a FighterAttackScriptAssets,
|
pub attack_script_assets: &'a FighterAttackScriptAssets,
|
||||||
pub game_settings: &'a GameSettings,
|
pub game_settings: &'a GameSettings,
|
||||||
@@ -329,6 +330,7 @@ impl<'w, 's> FighterFrameQueryItem<'w, 's> {
|
|||||||
facing_direction: &mut self.facing_direction,
|
facing_direction: &mut self.facing_direction,
|
||||||
animation_frame: &mut self.animation_frame,
|
animation_frame: &mut self.animation_frame,
|
||||||
surface: &mut self.surface,
|
surface: &mut self.surface,
|
||||||
|
vulnerability: &mut self.vulnerability,
|
||||||
fighter_attributes: attributes,
|
fighter_attributes: attributes,
|
||||||
attack_script_assets,
|
attack_script_assets,
|
||||||
game_settings,
|
game_settings,
|
||||||
@@ -599,7 +601,11 @@ pub fn state_collision_interrupt_system(
|
|||||||
|
|
||||||
if pending_respawn.0 {
|
if pending_respawn.0 {
|
||||||
**pending_respawn = false;
|
**pending_respawn = false;
|
||||||
let respawn_state = FighterState::Angel(angel::AngelState::new(60 * 3));
|
let respawn_state = FighterState::Angel(angel::AngelState::new(
|
||||||
|
game_settings
|
||||||
|
.fighter_common
|
||||||
|
.angel_platform_invulnerability_duration,
|
||||||
|
));
|
||||||
|
|
||||||
// Find the angel platform position
|
// Find the angel platform position
|
||||||
let respawn_point = stage_manifest
|
let respawn_point = stage_manifest
|
||||||
|
|||||||
+28
-8
@@ -11,9 +11,27 @@ pub struct FighterAnimations {
|
|||||||
pub baked: Handle<BakedFighterAnimations>,
|
pub baked: Handle<BakedFighterAnimations>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Default, PartialEq)]
|
||||||
|
pub enum LastKnownInvulnerabilityState {
|
||||||
|
#[default]
|
||||||
|
Vulnerable,
|
||||||
|
Intangible,
|
||||||
|
Invulnerable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&FighterInvulnerabilityState> for LastKnownInvulnerabilityState {
|
||||||
|
fn from(value: &FighterInvulnerabilityState) -> Self {
|
||||||
|
match value {
|
||||||
|
FighterInvulnerabilityState::Vulnerable => Self::Vulnerable,
|
||||||
|
FighterInvulnerabilityState::Invulnerable { .. } => Self::Invulnerable,
|
||||||
|
FighterInvulnerabilityState::Intangible { .. } => Self::Intangible,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Component, Clone, Default)]
|
#[derive(Component, Clone, Default)]
|
||||||
pub struct FighterInvulnerabilityVisualState {
|
pub struct FighterInvulnerabilityVisualState {
|
||||||
pub last_known_state: FighterInvulnerabilityState,
|
pub last_known_state: LastKnownInvulnerabilityState,
|
||||||
pub frames_in_state: u32,
|
pub frames_in_state: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,8 +45,10 @@ pub fn update_status_colors(
|
|||||||
game_settings: Res<GameSettings>,
|
game_settings: Res<GameSettings>,
|
||||||
) {
|
) {
|
||||||
for (invuln_state, mut invuln_state_visual) in &mut fighters {
|
for (invuln_state, mut invuln_state_visual) in &mut fighters {
|
||||||
if *invuln_state != invuln_state_visual.last_known_state {
|
let curr_state = invuln_state.into();
|
||||||
invuln_state_visual.last_known_state = *invuln_state;
|
let last_known_state = invuln_state_visual.last_known_state;
|
||||||
|
if curr_state != last_known_state {
|
||||||
|
invuln_state_visual.last_known_state = curr_state;
|
||||||
invuln_state_visual.frames_in_state = 0;
|
invuln_state_visual.frames_in_state = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,18 +58,18 @@ pub fn update_status_colors(
|
|||||||
.expect("Material should have relevant fighter available");
|
.expect("Material should have relevant fighter available");
|
||||||
|
|
||||||
let status_color = match invuln_state_visual.last_known_state {
|
let status_color = match invuln_state_visual.last_known_state {
|
||||||
FighterInvulnerabilityState::Vulnerable => bevy::color::palettes::css::WHITE.into(),
|
LastKnownInvulnerabilityState::Vulnerable => bevy::color::palettes::css::WHITE.into(),
|
||||||
FighterInvulnerabilityState::Invulnerable => {
|
LastKnownInvulnerabilityState::Invulnerable => {
|
||||||
game_settings.fighter_common.intangible_color
|
game_settings.fighter_common.intangible_color
|
||||||
}
|
}
|
||||||
FighterInvulnerabilityState::Intangible => {
|
LastKnownInvulnerabilityState::Intangible => {
|
||||||
game_settings.fighter_common.intangible_color
|
game_settings.fighter_common.intangible_color
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let intensity = match invuln_state_visual.last_known_state {
|
let intensity = match invuln_state_visual.last_known_state {
|
||||||
FighterInvulnerabilityState::Vulnerable => 0.0,
|
LastKnownInvulnerabilityState::Vulnerable => 0.0,
|
||||||
FighterInvulnerabilityState::Invulnerable | FighterInvulnerabilityState::Intangible => {
|
LastKnownInvulnerabilityState::Invulnerable | LastKnownInvulnerabilityState::Intangible => {
|
||||||
let cycle_frames = invuln_state_visual.frames_in_state
|
let cycle_frames = invuln_state_visual.frames_in_state
|
||||||
% game_settings.fighter_common.intangible_pulse_duration;
|
% game_settings.fighter_common.intangible_pulse_duration;
|
||||||
1.0 - cycle_frames as f32
|
1.0 - cycle_frames as f32
|
||||||
|
|||||||
@@ -45,6 +45,17 @@ pub struct FighterSettingsCommon {
|
|||||||
|
|
||||||
pub intangible_color: Color,
|
pub intangible_color: Color,
|
||||||
pub intangible_pulse_duration: u32,
|
pub intangible_pulse_duration: u32,
|
||||||
|
|
||||||
|
pub angel_platform_invulnerability_duration: u32,
|
||||||
|
|
||||||
|
/// When hit while the receiver is in the air, use this angle
|
||||||
|
pub sakurai_angle_aerial_angle: FGi32,
|
||||||
|
/// When hit while the receiver is in the ground and at low knockback, use this angle
|
||||||
|
pub sakurai_angle_low_knockback_angle: FGi32,
|
||||||
|
/// When hit while the receiver is in the ground and at high knockback, use this angle
|
||||||
|
pub sakurai_angle_high_knockback_angle: FGi32,
|
||||||
|
/// past this threshold, the knockback is considered high, so it will use [sakurai_angle_high_knockback_angle]
|
||||||
|
pub sakurai_angle_knockback_threshold: FGi32,
|
||||||
}
|
}
|
||||||
#[derive(Reflect, Serialize, Deserialize, Clone)]
|
#[derive(Reflect, Serialize, Deserialize, Clone)]
|
||||||
#[reflect(opaque)]
|
#[reflect(opaque)]
|
||||||
|
|||||||
Reference in New Issue
Block a user