aboutsummaryrefslogtreecommitdiff
path: root/server/src/interaction.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/interaction.rs')
-rw-r--r--server/src/interaction.rs203
1 files changed, 161 insertions, 42 deletions
diff --git a/server/src/interaction.rs b/server/src/interaction.rs
index c0fa5731..e2e4d08b 100644
--- a/server/src/interaction.rs
+++ b/server/src/interaction.rs
@@ -16,24 +16,23 @@
*/
use hurrycurry_client_lib::{Involvement, Item};
-use hurrycurry_protocol::{Gamedata, Recipe, Score, TileIndex};
+use hurrycurry_protocol::{Gamedata, ItemLocation, PacketC, Recipe, Score, TileIndex};
use log::info;
-
-pub enum InteractEffect {
- Put,
- Take,
- Produce,
-}
+use std::collections::VecDeque;
pub fn interact(
data: &Gamedata,
edge: bool,
tile: Option<TileIndex>,
this: &mut Option<Item>,
+ this_loc: ItemLocation,
other: &mut Option<Item>,
+ other_loc: ItemLocation,
score: &mut Score,
+ score_changed: &mut bool,
automated: bool,
-) -> Option<InteractEffect> {
+ packet_out: &mut VecDeque<PacketC>,
+) {
let interactable = automated
|| tile
.map(|tile| data.is_tile_interactable(tile))
@@ -43,16 +42,31 @@ pub fn interact(
if let Some(active) = &mut item.active {
let recipe = &data.recipe(active.recipe);
if recipe.supports_tile(tile) {
- if let Recipe::Active { outputs, .. } = recipe {
+ if let Recipe::Active {
+ outputs, duration, ..
+ } = recipe
+ {
if edge {
- active.working += 1;
+ active.speed += 1. / duration;
} else {
- active.working -= 1;
- if active.progress >= 1. {
- *other = outputs[0].map(|kind| Item { kind, active: None });
- *this = outputs[1].map(|kind| Item { kind, active: None });
- return Some(InteractEffect::Produce);
- }
+ active.speed -= 1. / duration;
+ }
+ if active.position >= 1. {
+ let this_had_item = this.is_some();
+ let other_had_item = other.is_some();
+ *other = outputs[0].map(|kind| Item { kind, active: None });
+ *this = outputs[1].map(|kind| Item { kind, active: None });
+ produce(
+ this_had_item,
+ other_had_item,
+ this,
+ this_loc,
+ other,
+ other_loc,
+ score_changed,
+ packet_out,
+ );
+ return;
}
}
}
@@ -60,7 +74,7 @@ pub fn interact(
}
}
if !edge {
- return None;
+ return;
}
if interactable {
for (ri, recipe) in data.recipes() {
@@ -68,15 +82,17 @@ pub fn interact(
continue;
}
match recipe {
- Recipe::Active { input, .. } => {
+ Recipe::Active {
+ input, duration, ..
+ } => {
if other.is_none() {
if let Some(item) = this {
if item.kind == *input && item.active.is_none() {
info!("start active recipe {ri:?}");
item.active = Some(Involvement {
recipe: ri,
- working: 1,
- progress: 0.,
+ speed: 1. / duration,
+ position: 0.,
warn: false,
});
}
@@ -87,19 +103,23 @@ pub fn interact(
if item.kind == *input {
let mut item = other.take().unwrap();
if let Some(active) = &mut item.active {
- active.working += 1;
+ active.speed += 1. / duration;
} else {
info!("start active recipe {ri:?}");
item.active = Some(Involvement {
recipe: ri,
- working: 1,
- progress: 0.,
+ speed: 1. / duration,
+ position: 0.,
warn: false,
});
}
*this = Some(item);
score.active_recipes += 1;
- return Some(InteractEffect::Put);
+ packet_out.push_back(PacketC::MoveItem {
+ from: other_loc,
+ to: this_loc,
+ });
+ return;
}
}
}
@@ -117,11 +137,24 @@ pub fn interact(
if ok || ok_rev {
info!("instant recipe {ri:?} reversed={ok_rev}");
let ok_rev = ok_rev as usize;
+ let this_had_item = this.is_some();
+ let other_had_item = other.is_some();
*other = outputs[1 - ok_rev].map(|kind| Item { kind, active: None });
*this = outputs[ok_rev].map(|kind| Item { kind, active: None });
score.points += pd;
score.instant_recipes += 1;
- return Some(InteractEffect::Produce);
+ *score_changed = true;
+ produce(
+ this_had_item,
+ other_had_item,
+ this,
+ this_loc,
+ other,
+ other_loc,
+ score_changed,
+ packet_out,
+ );
+ return;
}
}
_ => (),
@@ -132,21 +165,32 @@ pub fn interact(
if interactable && this.is_none() {
if let Some(item) = other.take() {
*this = Some(item);
- return Some(InteractEffect::Put);
+ packet_out.push_back(PacketC::MoveItem {
+ from: other_loc,
+ to: this_loc,
+ });
+ return;
}
}
if other.is_none() {
if let Some(item) = this.take() {
*other = Some(item);
- return Some(InteractEffect::Take);
+ packet_out.push_back(PacketC::MoveItem {
+ from: this_loc,
+ to: other_loc,
+ });
+ return;
}
}
-
- None
}
pub enum TickEffect {
- Progress(bool),
+ Progress {
+ speed: f32,
+ position: f32,
+ warn: bool,
+ },
+ ClearProgress,
Produce,
}
pub fn tick_slot(
@@ -159,35 +203,58 @@ pub fn tick_slot(
if let Some(item) = slot {
if let Some(a) = &mut item.active {
let r = &data.recipe(a.recipe);
- if r.supports_tile(tile) {
- a.progress += a.working as f32 * dt / r.duration().unwrap();
- } else if let Some(revert_duration) = r.revert_duration() {
- a.progress -= dt / revert_duration;
+ let prev_speed = a.speed;
+
+ if !r.supports_tile(tile) {
+ if let Some(revert_duration) = r.revert_duration() {
+ a.speed = -1. / revert_duration
+ }
}
- if a.progress >= 1. {
+
+ if a.position >= 1. {
if let Recipe::Passive { output, .. } = &data.recipe(a.recipe) {
*slot = output.map(|kind| Item { kind, active: None });
score.passive_recipes += 1;
return Some(TickEffect::Produce);
};
- a.progress = 1.;
}
- if a.progress < 0. {
+ if a.position < 0. {
item.active = None;
+ return Some(TickEffect::ClearProgress);
+ }
+
+ a.position += dt * a.speed;
+ a.position = a.position.clamp(0., 1.);
+
+ if a.speed != prev_speed {
+ return Some(TickEffect::Progress {
+ warn: r.warn(),
+ position: a.position,
+ speed: a.speed,
+ });
}
- return Some(TickEffect::Progress(r.warn()));
} else {
for (ri, recipe) in data.recipes() {
if recipe.supports_tile(tile) {
- if let Recipe::Passive { input, warn, .. } = recipe {
+ if let Recipe::Passive {
+ input,
+ warn,
+ duration,
+ ..
+ } = recipe
+ {
if *input == item.kind {
item.active = Some(Involvement {
recipe: ri,
- progress: 0.,
+ position: 0.,
+ warn: *warn,
+ speed: 1. / *duration,
+ });
+ return Some(TickEffect::Progress {
+ position: 0.,
+ speed: 1. / *duration,
warn: *warn,
- working: 1,
});
- return Some(TickEffect::Progress(recipe.warn()));
}
}
}
@@ -196,3 +263,55 @@ pub fn tick_slot(
}
None
}
+
+fn produce(
+ this_had_item: bool,
+ other_had_item: bool,
+ this: &Option<Item>,
+ this_loc: ItemLocation,
+ other: &Option<Item>,
+ other_loc: ItemLocation,
+ score_changed: &mut bool,
+ packet_out: &mut VecDeque<PacketC>,
+) {
+ info!("produce {this_loc} <~ {other_loc}");
+ *score_changed = true;
+ if this_had_item {
+ packet_out.push_back(PacketC::SetProgress {
+ item: this_loc,
+ position: 1.,
+ speed: 0.,
+ warn: false,
+ });
+ packet_out.push_back(PacketC::SetItem {
+ location: this_loc,
+ item: None,
+ });
+ }
+ if other_had_item {
+ packet_out.push_back(PacketC::MoveItem {
+ from: other_loc,
+ to: this_loc,
+ });
+ packet_out.push_back(PacketC::SetItem {
+ location: this_loc,
+ item: None,
+ });
+ }
+ if let Some(i) = &other {
+ packet_out.push_back(PacketC::SetItem {
+ location: this_loc,
+ item: Some(i.kind),
+ });
+ packet_out.push_back(PacketC::MoveItem {
+ from: this_loc,
+ to: other_loc,
+ })
+ }
+ if let Some(i) = &this {
+ packet_out.push_back(PacketC::SetItem {
+ location: this_loc,
+ item: Some(i.kind),
+ });
+ }
+}