From 8de658b093498856c1767152e5a697e49d6cd169 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 3 Dec 2024 02:04:23 -0800 Subject: [PATCH] Losing The Game --- engine/src/actions/events.rs | 17 +++++- engine/src/floor.rs | 7 ++- engine/src/floor/mutators.rs | 46 +++++++++++++++- godot-glue/src/events.rs | 53 +++++++++++++++++-- godot/Crawler/FloorView/Entity/Entity.tscn | 1 + .../Crawler/FloorView/Entity/EntitySprite.gd | 2 + godot/Crawler/FloorView/Entity/UnclipTail.gd | 1 + godot/Crawler/FloorView/FloorView.gd | 44 ++++++++++++++- 8 files changed, 157 insertions(+), 14 deletions(-) diff --git a/engine/src/actions/events.rs b/engine/src/actions/events.rs index 70b3ea1..8d83994 100644 --- a/engine/src/actions/events.rs +++ b/engine/src/actions/events.rs @@ -20,7 +20,9 @@ pub enum FloorEvent { KnockbackEvent(KnockbackEvent), KnockdownEvent(KnockdownEvent), Wakeup(WakeupEvent), - Die(DieEvent), + GetDowned(GetDownedEvent), + Exit(ExitEvent), + MissionFailed(MissionFailedEvent), } #[derive(Debug, PartialEq, Eq, Clone)] @@ -90,6 +92,17 @@ pub struct WakeupEvent { } #[derive(Debug, PartialEq, Eq, Clone)] -pub struct DieEvent { +pub struct GetDownedEvent { pub subject: EntityId, } + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct ExitEvent { + pub subject: EntityId, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MissionFailedEvent { + pub subject: EntityId, + pub downed_party: Vec, +} diff --git a/engine/src/floor.rs b/engine/src/floor.rs index 6f05076..5830496 100644 --- a/engine/src/floor.rs +++ b/engine/src/floor.rs @@ -180,10 +180,9 @@ impl Floor { .map(|id| (*id, &self.entities[*id])) .collect::>(); - let log = self - .downing - .as_ref() - .map(|some| some.mutate_entities(self.get_current_round(), &mut new_set)); + let log = self.downing.as_ref().map(|some| { + some.mutate_entities(self.get_current_round(), &self.entities, &mut new_set) + }); let mut next_entities = self.entities.clone(); for (new_id, new) in new_set { diff --git a/engine/src/floor/mutators.rs b/engine/src/floor/mutators.rs index 3775c96..a9602bb 100644 --- a/engine/src/floor/mutators.rs +++ b/engine/src/floor/mutators.rs @@ -4,10 +4,12 @@ use rkyv::Archive; use rkyv::Deserialize; use rkyv::Serialize; -use crate::actions::events::DieEvent; use crate::actions::events::FloorEvent; +use crate::actions::events::GetDownedEvent; +use crate::actions::events::MissionFailedEvent; use crate::entity::Entity; use crate::entity::EntityId; +use crate::entity::EntitySet; use crate::entity::EntityState; use crate::writer::Writer; @@ -25,17 +27,57 @@ impl DownedStateMutator { pub fn mutate_entities( &self, current_round: u32, + old_set: &EntitySet, new_set: &mut HashMap, ) -> Writer { let mut out = Writer::new(self.clone()); + for (id, e) in new_set.iter_mut() { if e.health <= 0 && !matches!(e.state, EntityState::Downed { .. }) { e.state = EntityState::Downed { round_downed: current_round, }; - out = out.log(FloorEvent::Die(DieEvent { subject: *id })); + out = out.log(FloorEvent::GetDowned(GetDownedEvent { subject: *id })); + } + } + + let downed_party = new_set + .iter() + .filter_map(|(id, e)| { + if e.is_player_friendly && matches!(e.state, EntityState::Downed { .. }) { + Some(*id) + } else { + None + } + }) + .collect::>(); + if !downed_party.is_empty() { + let alive_party = old_set + .iter() + .filter_map(|(id, e)| { + if e.is_player_friendly && !downed_party.contains(&id) { + Some(id) + } else { + None + } + }) + .collect::>(); + + // Do a better split. + if let Some((head, tail)) = alive_party.split_first() { + out = out.log(FloorEvent::MissionFailed(MissionFailedEvent { + subject: *head, + downed_party, + })); + for e in tail { + out = out.log(FloorEvent::MissionFailed(MissionFailedEvent { + subject: *e, + downed_party: Vec::new(), + })); + } } } + out } } diff --git a/godot-glue/src/events.rs b/godot-glue/src/events.rs index 45920f6..d120fa0 100644 --- a/godot-glue/src/events.rs +++ b/godot-glue/src/events.rs @@ -45,7 +45,9 @@ impl FloorEvent { (KnockbackEvent, KnockbackEvent), (KnockdownEvent, KnockdownEvent), (Wakeup, WakeupEvent), - (Die, DieEvent), + (GetDowned, GetDownedEvent), + (Exit, ExitEvent), + (MissionFailed, MissionFailedEvent), ) } } @@ -253,15 +255,58 @@ impl WakeupEvent { #[derive(GodotClass)] #[class(no_init)] -struct DieEvent { +struct GetDownedEvent { #[var(get)] subject: Gd, } -impl DieEvent { - fn new(id_cache: &mut EntityIdCache, event: engine::actions::events::DieEvent) -> Gd { +impl GetDownedEvent { + fn new( + id_cache: &mut EntityIdCache, + event: engine::actions::events::GetDownedEvent, + ) -> Gd { + Gd::from_object(Self { + subject: id_cache.get_or_insert(event.subject), + }) + } +} + +#[derive(GodotClass)] +#[class(no_init)] +struct ExitEvent { + #[var(get)] + subject: Gd, +} + +impl ExitEvent { + fn new(id_cache: &mut EntityIdCache, event: engine::actions::events::ExitEvent) -> Gd { + Gd::from_object(Self { + subject: id_cache.get_or_insert(event.subject), + }) + } +} + +#[derive(GodotClass)] +#[class(no_init)] +struct MissionFailedEvent { + #[var(get)] + subject: Gd, + #[var(get)] + downed_party: Array>, +} + +impl MissionFailedEvent { + fn new( + id_cache: &mut EntityIdCache, + event: engine::actions::events::MissionFailedEvent, + ) -> Gd { Gd::from_object(Self { subject: id_cache.get_or_insert(event.subject), + downed_party: event + .downed_party + .into_iter() + .map(|x| id_cache.get_or_insert(x)) + .collect(), }) } } diff --git a/godot/Crawler/FloorView/Entity/Entity.tscn b/godot/Crawler/FloorView/Entity/Entity.tscn index 94efbb6..8b5c983 100644 --- a/godot/Crawler/FloorView/Entity/Entity.tscn +++ b/godot/Crawler/FloorView/Entity/Entity.tscn @@ -389,6 +389,7 @@ libraries = { } [node name="Arrow" type="Node3D" parent="."] +visible = false [node name="Tip" type="MeshInstance3D" parent="Arrow"] transform = Transform3D(0.8, 0, 0, 0, 0, -0.1, 0, 0.3, 0, 0, 0, 0.3) diff --git a/godot/Crawler/FloorView/Entity/EntitySprite.gd b/godot/Crawler/FloorView/Entity/EntitySprite.gd index 5a643f4..f0cd51e 100644 --- a/godot/Crawler/FloorView/Entity/EntitySprite.gd +++ b/godot/Crawler/FloorView/Entity/EntitySprite.gd @@ -41,6 +41,8 @@ func _process(delta): spin_around(camera_direction) + #self.transparency = clamp((self.position.y - 4)/2.0, 0, 1) + func spin_around(camera_direction): if not self.get_parent(): diff --git a/godot/Crawler/FloorView/Entity/UnclipTail.gd b/godot/Crawler/FloorView/Entity/UnclipTail.gd index fd63b0a..2ee12d4 100644 --- a/godot/Crawler/FloorView/Entity/UnclipTail.gd +++ b/godot/Crawler/FloorView/Entity/UnclipTail.gd @@ -7,3 +7,4 @@ func _process(_delta: float) -> void: get_parent().animation, get_parent().frame ) self.flip_h = get_parent().flip_h + self.visible = get_parent().transparency == 0 diff --git a/godot/Crawler/FloorView/FloorView.gd b/godot/Crawler/FloorView/FloorView.gd index b6c1989..15d4132 100644 --- a/godot/Crawler/FloorView/FloorView.gd +++ b/godot/Crawler/FloorView/FloorView.gd @@ -11,6 +11,8 @@ var test_event_delay = 0 var test_visions: Dictionary # of EntityIds to their most recent vision. +var stop_processing: bool = false + func _ready(): desynced_from_floor = true @@ -20,6 +22,9 @@ func _ready(): func _process_floor(delta, floor: ActiveFloor): + if stop_processing: + return + if test_event_delay > 0: test_event_delay -= delta return @@ -53,7 +58,7 @@ func _process_floor(delta, floor: ActiveFloor): func clear_queue(delta, floor: ActiveFloor): - while event_index < len(floor.log): + while event_index < len(floor.log) and !stop_processing: var event = floor.log[event_index] if event is MoveEvent: @@ -181,7 +186,7 @@ func clear_queue(delta, floor: ActiveFloor): event_index += 1 - elif event is DieEvent: + elif event is GetDownedEvent: var subject = id_to_node[event.subject] if subject.is_important_animating(): return @@ -190,6 +195,41 @@ func clear_queue(delta, floor: ActiveFloor): event_index += 1 + elif event is MissionFailedEvent: + if id_to_node.values().any(func(x): return x.is_animating()): + return + + stop_processing = true + + var subject = id_to_node[event.subject] + subject.get_node("AnimationPlayer").play("RESET") + + var tween: Tween = subject.create_tween() + tween.tween_interval(1) + var the_position = subject.position + for entity in event.downed_party.map(func(x): return id_to_node[x]): + tween.tween_property( + subject, + "basis", + Basis.looking_at(entity.position - the_position, Vector3.UP, true), + 0 + ) + ( + tween + . tween_property(subject, "position", entity.position, 20 / 60.0) + . set_trans(Tween.TRANS_EXPO) + . set_ease(Tween.EASE_OUT) + ) + tween.tween_interval(0.1) + tween.tween_property(entity, "visible", false, 0) + tween.tween_interval(0.1) + + the_position = entity.position + + tween.tween_property(subject.get_node("AnimatedSprite3D"), "position:y", 300, 10) + + event_index += 1 + else: printerr("Unknown Event! ", event) event_index += 1