forked from blasthavers/blastmud
136 lines
4.7 KiB
Rust
136 lines
4.7 KiB
Rust
use crate::{
|
|
models::{
|
|
item::Item,
|
|
task::{
|
|
Task,
|
|
TaskMeta,
|
|
TaskDetails,
|
|
}
|
|
},
|
|
|
|
DResult,
|
|
static_content::{
|
|
possession_type::UseEffect,
|
|
},
|
|
regular_tasks::{
|
|
TaskHandler,
|
|
TaskRunContext,
|
|
}
|
|
};
|
|
use super::{
|
|
comms::broadcast_to_room,
|
|
combat::change_health,
|
|
};
|
|
use async_trait::async_trait;
|
|
use std::time;
|
|
use serde::{Serialize, Deserialize};
|
|
use std::collections::{BTreeMap, VecDeque};
|
|
use chrono::Utc;
|
|
use log::info;
|
|
use mockall_double::double;
|
|
#[double] use crate::db::DBTrans;
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
pub struct DelayedHealthEffect {
|
|
magnitude: i64,
|
|
delay: u64,
|
|
message: String,
|
|
message_nonexp: String
|
|
}
|
|
|
|
pub struct DelayedHealthTaskHandler;
|
|
#[async_trait]
|
|
impl TaskHandler for DelayedHealthTaskHandler {
|
|
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
|
|
let ref mut item_effect_series = match &mut ctx.task.details {
|
|
TaskDetails::DelayedHealth { item, ref mut effect_series } => (item, effect_series),
|
|
_ => Err("Expected DelayedHealth type")?
|
|
};
|
|
let (item_type, item_code) = match item_effect_series.0.split_once("/") {
|
|
None => {
|
|
info!("Invalid item {} to DelayedHealthTaskHandler", item_effect_series.0);
|
|
return Ok(None);
|
|
}
|
|
Some((item_type, item_code)) => (item_type, item_code)
|
|
};
|
|
let item = match ctx.trans.find_item_by_type_code(item_type, item_code).await? {
|
|
None => {
|
|
return Ok(None);
|
|
}
|
|
Some(it) => it
|
|
};
|
|
if item.death_data.is_some() {
|
|
return Ok(None);
|
|
}
|
|
match item_effect_series.1.pop_front() {
|
|
None => Ok(None),
|
|
Some(DelayedHealthEffect { magnitude, message, message_nonexp, .. }) => {
|
|
let mut item_mut = (*item).clone();
|
|
change_health(ctx.trans, magnitude, &mut item_mut, &message, &message_nonexp).await?;
|
|
ctx.trans.save_item_model(&item_mut).await?;
|
|
Ok(item_effect_series.1.front().map(|it| time::Duration::from_secs(it.delay)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pub static DELAYED_HEALTH_HANDLER: &'static (dyn TaskHandler + Sync + Send) = &DelayedHealthTaskHandler;
|
|
|
|
pub async fn run_effects(
|
|
trans: &DBTrans, effects: &Vec<UseEffect>,
|
|
player: &mut Item,
|
|
item: &Item,
|
|
// None if target is player
|
|
target: &mut Option<Item>,
|
|
level: f64,
|
|
task_ref: &str
|
|
) -> DResult<()> {
|
|
let mut target_health_series = BTreeMap::<String, VecDeque<DelayedHealthEffect>>::new();
|
|
for effect in effects {
|
|
match effect {
|
|
UseEffect::BroadcastMessage { messagef } => {
|
|
let (msg_exp, msg_nonexp) = messagef(player, item, target.as_ref().unwrap_or(player));
|
|
broadcast_to_room(trans, &player.location, None, &msg_exp,
|
|
Some(&msg_nonexp)).await?;
|
|
},
|
|
UseEffect::ChangeTargetHealth { delay_secs, base_effect, skill_multiplier, max_effect,
|
|
message } => {
|
|
let health_impact =
|
|
(*base_effect + ((skill_multiplier * level) as i64).min(*max_effect)) as i64;
|
|
let (msg, msg_nonexp) = message(target.as_ref().unwrap_or(player));
|
|
if *delay_secs == 0 {
|
|
change_health(trans, health_impact, target.as_mut().unwrap_or(player), &msg,
|
|
&msg_nonexp).await?;
|
|
} else {
|
|
let target_it = target.as_ref().unwrap_or(player);
|
|
let fx = DelayedHealthEffect {
|
|
magnitude: health_impact,
|
|
delay: *delay_secs,
|
|
message: msg,
|
|
message_nonexp: msg_nonexp
|
|
};
|
|
target_health_series
|
|
.entry(format!("{}/{}", target_it.item_type, target_it.item_code))
|
|
.and_modify(|l| l.push_back(fx.clone()))
|
|
.or_insert(VecDeque::from([fx]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (eff_item, l) in target_health_series.into_iter() {
|
|
trans.upsert_task(&Task {
|
|
meta: TaskMeta {
|
|
task_code: format!("{}/{}", eff_item, task_ref),
|
|
next_scheduled: Utc::now() + chrono::Duration::seconds(l[0].delay as i64),
|
|
..Default::default()
|
|
},
|
|
details: TaskDetails::DelayedHealth {
|
|
effect_series: l,
|
|
item: eff_item,
|
|
}
|
|
}).await?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|