2023-07-24 22:46:50 +10:00
|
|
|
use super::{combat::change_health, comms::broadcast_to_room};
|
|
|
|
#[double]
|
|
|
|
use crate::db::DBTrans;
|
2023-02-25 23:49:46 +11:00
|
|
|
use crate::{
|
|
|
|
models::{
|
|
|
|
item::Item,
|
2023-07-24 22:46:50 +10:00
|
|
|
task::{Task, TaskDetails, TaskMeta},
|
2023-02-25 23:49:46 +11:00
|
|
|
},
|
2023-07-24 22:46:50 +10:00
|
|
|
regular_tasks::{TaskHandler, TaskRunContext},
|
|
|
|
static_content::possession_type::UseEffect,
|
2023-02-25 23:49:46 +11:00
|
|
|
DResult,
|
|
|
|
};
|
|
|
|
use async_trait::async_trait;
|
|
|
|
use chrono::Utc;
|
|
|
|
use log::info;
|
2023-02-26 00:56:22 +11:00
|
|
|
use mockall_double::double;
|
2023-07-24 22:46:50 +10:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use std::collections::{BTreeMap, VecDeque};
|
|
|
|
use std::time;
|
2023-02-25 23:49:46 +11:00
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
|
|
|
pub struct DelayedHealthEffect {
|
|
|
|
magnitude: i64,
|
|
|
|
delay: u64,
|
|
|
|
message: String,
|
2023-07-24 22:46:50 +10:00
|
|
|
message_nonexp: String,
|
2023-02-25 23:49:46 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-07-24 22:46:50 +10:00
|
|
|
TaskDetails::DelayedHealth {
|
|
|
|
item,
|
|
|
|
ref mut effect_series,
|
|
|
|
} => (item, effect_series),
|
|
|
|
_ => Err("Expected DelayedHealth type")?,
|
2023-02-25 23:49:46 +11:00
|
|
|
};
|
|
|
|
let (item_type, item_code) = match item_effect_series.0.split_once("/") {
|
|
|
|
None => {
|
2023-07-24 22:46:50 +10:00
|
|
|
info!(
|
|
|
|
"Invalid item {} to DelayedHealthTaskHandler",
|
|
|
|
item_effect_series.0
|
|
|
|
);
|
2023-02-25 23:49:46 +11:00
|
|
|
return Ok(None);
|
|
|
|
}
|
2023-07-24 22:46:50 +10:00
|
|
|
Some((item_type, item_code)) => (item_type, item_code),
|
2023-02-25 23:49:46 +11:00
|
|
|
};
|
2023-07-24 22:46:50 +10:00
|
|
|
let item = match ctx
|
|
|
|
.trans
|
|
|
|
.find_item_by_type_code(item_type, item_code)
|
|
|
|
.await?
|
|
|
|
{
|
2023-02-25 23:49:46 +11:00
|
|
|
None => {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
2023-07-24 22:46:50 +10:00
|
|
|
Some(it) => it,
|
2023-02-25 23:49:46 +11:00
|
|
|
};
|
2023-04-23 22:31:31 +10:00
|
|
|
if item.death_data.is_some() {
|
2023-02-26 00:56:22 +11:00
|
|
|
return Ok(None);
|
|
|
|
}
|
2023-02-25 23:49:46 +11:00
|
|
|
match item_effect_series.1.pop_front() {
|
|
|
|
None => Ok(None),
|
2023-07-24 22:46:50 +10:00
|
|
|
Some(DelayedHealthEffect {
|
|
|
|
magnitude,
|
|
|
|
message,
|
|
|
|
message_nonexp,
|
|
|
|
..
|
|
|
|
}) => {
|
2023-02-25 23:49:46 +11:00
|
|
|
let mut item_mut = (*item).clone();
|
2023-07-24 22:46:50 +10:00
|
|
|
change_health(
|
|
|
|
ctx.trans,
|
|
|
|
magnitude,
|
|
|
|
&mut item_mut,
|
|
|
|
&message,
|
|
|
|
&message_nonexp,
|
|
|
|
)
|
|
|
|
.await?;
|
2023-02-25 23:49:46 +11:00
|
|
|
ctx.trans.save_item_model(&item_mut).await?;
|
2023-07-24 22:46:50 +10:00
|
|
|
Ok(item_effect_series
|
|
|
|
.1
|
|
|
|
.front()
|
|
|
|
.map(|it| time::Duration::from_secs(it.delay)))
|
2023-02-25 23:49:46 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-24 22:46:50 +10:00
|
|
|
pub static DELAYED_HEALTH_HANDLER: &'static (dyn TaskHandler + Sync + Send) =
|
|
|
|
&DelayedHealthTaskHandler;
|
2023-02-25 23:49:46 +11:00
|
|
|
|
|
|
|
pub async fn run_effects(
|
2023-07-24 22:46:50 +10:00
|
|
|
trans: &DBTrans,
|
|
|
|
effects: &Vec<UseEffect>,
|
2023-02-25 23:49:46 +11:00
|
|
|
player: &mut Item,
|
|
|
|
item: &Item,
|
|
|
|
// None if target is player
|
|
|
|
target: &mut Option<Item>,
|
|
|
|
level: f64,
|
2023-07-24 22:46:50 +10:00
|
|
|
task_ref: &str,
|
2023-02-25 23:49:46 +11:00
|
|
|
) -> DResult<()> {
|
|
|
|
let mut target_health_series = BTreeMap::<String, VecDeque<DelayedHealthEffect>>::new();
|
|
|
|
for effect in effects {
|
|
|
|
match effect {
|
|
|
|
UseEffect::BroadcastMessage { messagef } => {
|
2023-07-24 22:46:50 +10:00
|
|
|
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,
|
|
|
|
} => {
|
2023-02-25 23:49:46 +11:00
|
|
|
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 {
|
2023-07-24 22:46:50 +10:00
|
|
|
change_health(
|
|
|
|
trans,
|
|
|
|
health_impact,
|
|
|
|
target.as_mut().unwrap_or(player),
|
|
|
|
&msg,
|
|
|
|
&msg_nonexp,
|
|
|
|
)
|
|
|
|
.await?;
|
2023-02-25 23:49:46 +11:00
|
|
|
} else {
|
|
|
|
let target_it = target.as_ref().unwrap_or(player);
|
|
|
|
let fx = DelayedHealthEffect {
|
|
|
|
magnitude: health_impact,
|
|
|
|
delay: *delay_secs,
|
|
|
|
message: msg,
|
2023-07-24 22:46:50 +10:00
|
|
|
message_nonexp: msg_nonexp,
|
2023-02-25 23:49:46 +11:00
|
|
|
};
|
|
|
|
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() {
|
2023-07-24 22:46:50 +10:00
|
|
|
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?;
|
2023-02-25 23:49:46 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|