Give some weapons a chance at causing crit status effects.
This commit is contained in:
parent
2350e22f5f
commit
6ac3f676be
@ -1122,6 +1122,14 @@ impl DBTrans {
|
||||
.get(0))
|
||||
}
|
||||
|
||||
pub async fn alloc_task_code(&self) -> DResult<i64> {
|
||||
Ok(self
|
||||
.pg_trans()?
|
||||
.query_one("SELECT NEXTVAL('task_seq')", &[])
|
||||
.await?
|
||||
.get(0))
|
||||
}
|
||||
|
||||
pub async fn get_online_info(&self) -> DResult<Vec<OnlineInfo>> {
|
||||
Ok(self
|
||||
.pg_trans()?
|
||||
|
@ -228,7 +228,11 @@ pub async fn describe_normal_item(
|
||||
));
|
||||
}
|
||||
|
||||
if item.active_effects.contains(&EffectType::Bandages) {
|
||||
if item
|
||||
.active_effects
|
||||
.iter()
|
||||
.any(|e| e.0 == EffectType::Bandages)
|
||||
{
|
||||
contents_desc.push_str(&format!(
|
||||
"{} is wrapped up in bandages.\n",
|
||||
&language::caps_first(&item.pronouns.subject)
|
||||
|
@ -252,9 +252,8 @@ impl QueueCommandHandler for QueueHandler {
|
||||
&actual_effects,
|
||||
ctx.item,
|
||||
&item,
|
||||
&mut target_mut,
|
||||
target_mut.as_mut(),
|
||||
skilllvl,
|
||||
use_data.task_ref,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub enum EffectType {
|
||||
Ephemeral, // i.e. no enduring impact to show in status.
|
||||
Bandages,
|
||||
Bleed,
|
||||
}
|
||||
|
||||
pub struct EffectSet {
|
||||
|
@ -495,7 +495,7 @@ pub struct Item {
|
||||
pub queue: VecDeque<QueueCommand>,
|
||||
pub urges: Option<Urges>,
|
||||
pub liquid_details: Option<LiquidDetails>,
|
||||
pub active_effects: Vec<EffectType>,
|
||||
pub active_effects: Vec<(EffectType, i64)>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
|
@ -35,7 +35,9 @@ use chrono::Utc;
|
||||
use mockall_double::double;
|
||||
use rand::{prelude::IteratorRandom, Rng};
|
||||
use rand_distr::{Distribution, Normal};
|
||||
use std::time;
|
||||
use std::{sync::Arc, time};
|
||||
|
||||
use super::effect::{default_effects_for_type, run_effects};
|
||||
|
||||
pub async fn soak_damage<DamageDist: DamageDistribution>(
|
||||
trans: &DBTrans,
|
||||
@ -129,6 +131,7 @@ pub async fn soak_damage<DamageDist: DamageDistribution>(
|
||||
async fn process_attack(
|
||||
ctx: &mut TaskRunContext<'_>,
|
||||
attacker_item: &mut Item,
|
||||
weapon_item: &Item,
|
||||
victim_item: &mut Item,
|
||||
attack: &WeaponAttackData,
|
||||
weapon: &WeaponData,
|
||||
@ -226,8 +229,6 @@ async fn process_attack(
|
||||
// Determine body part...
|
||||
let part = victim_item.species.sample_body_part();
|
||||
|
||||
// TODO: Armour / soaks
|
||||
|
||||
let mut mean_damage: f64 = attack.mean_damage;
|
||||
for scaling in attack.skill_scaling.iter() {
|
||||
let skill = *attacker_item
|
||||
@ -287,6 +288,29 @@ async fn process_attack(
|
||||
ctx.trans.save_item_model(victim_item).await?;
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// Consider applying a crit effect...
|
||||
let mut crit_rand = rand::thread_rng().gen::<f64>();
|
||||
for (p, eff_type) in &attack.crit_effects {
|
||||
if victim_item.active_effects.iter().any(|e| e.0 == *eff_type) {
|
||||
continue;
|
||||
}
|
||||
if *p >= crit_rand {
|
||||
if let Some(effect_set) = default_effects_for_type().get(eff_type) {
|
||||
run_effects(
|
||||
ctx.trans,
|
||||
&effect_set,
|
||||
attacker_item,
|
||||
weapon_item,
|
||||
Some(victim_item),
|
||||
0.0,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
crit_rand -= *p;
|
||||
}
|
||||
}
|
||||
ctx.trans.save_item_model(victim_item).await?;
|
||||
}
|
||||
|
||||
@ -314,11 +338,11 @@ impl TaskHandler for AttackTaskHandler {
|
||||
.task_code
|
||||
.split_once("/")
|
||||
.ok_or("Invalid AttackTick task code")?;
|
||||
let mut attacker_item = match ctx.trans.find_item_by_type_code(ctype, ccode).await? {
|
||||
let attacker_item = match ctx.trans.find_item_by_type_code(ctype, ccode).await? {
|
||||
None => {
|
||||
return Ok(None);
|
||||
} // Player is gone
|
||||
Some(item) => (*item).clone(),
|
||||
Some(item) => item,
|
||||
};
|
||||
|
||||
let (vtype, vcode) = match attacker_item
|
||||
@ -341,11 +365,13 @@ impl TaskHandler for AttackTaskHandler {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let weapon = what_wielded(ctx.trans, &attacker_item).await?;
|
||||
let (weapon_it, weapon) = what_wielded(ctx.trans, &attacker_item).await?;
|
||||
|
||||
let mut attacker_item_mut = (*attacker_item).clone();
|
||||
process_attack(
|
||||
ctx,
|
||||
&mut attacker_item,
|
||||
&mut attacker_item_mut,
|
||||
&weapon_it,
|
||||
&mut victim_item,
|
||||
&weapon.normal_attack,
|
||||
&weapon,
|
||||
@ -355,7 +381,7 @@ impl TaskHandler for AttackTaskHandler {
|
||||
// We re-check this on the next tick, rather than going off if the victim
|
||||
// died. That prevents a bug when re-focusing where we re-schedule and then
|
||||
// re-delete the task.
|
||||
Ok(Some(attack_speed(&attacker_item)))
|
||||
Ok(Some(attack_speed(&attacker_item_mut)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,7 +711,10 @@ pub async fn stop_attacking(trans: &DBTrans, by_whom: &Item, to_whom: &Item) ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn what_wielded(trans: &DBTrans, who: &Item) -> DResult<&'static WeaponData> {
|
||||
async fn what_wielded(
|
||||
trans: &DBTrans,
|
||||
who: &Arc<Item>,
|
||||
) -> DResult<(Arc<Item>, &'static WeaponData)> {
|
||||
if let Some(item) = trans
|
||||
.find_by_action_and_location(&who.refstr(), &LocationActionType::Wielded)
|
||||
.await?
|
||||
@ -697,7 +726,7 @@ async fn what_wielded(trans: &DBTrans, who: &Item) -> DResult<&'static WeaponDat
|
||||
.and_then(|pt| possession_data().get(&pt))
|
||||
.and_then(|pd| pd.weapon_data.as_ref())
|
||||
{
|
||||
return Ok(dat);
|
||||
return Ok((item.clone(), dat));
|
||||
}
|
||||
}
|
||||
|
||||
@ -711,11 +740,11 @@ async fn what_wielded(trans: &DBTrans, who: &Item) -> DResult<&'static WeaponDat
|
||||
.get(intrinsic)
|
||||
.and_then(|p| p.weapon_data.as_ref())
|
||||
{
|
||||
return Ok(weapon);
|
||||
return Ok((who.clone(), weapon));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(fist())
|
||||
Ok((who.clone(), fist()))
|
||||
}
|
||||
|
||||
fn attack_speed(_who: &Item) -> time::Duration {
|
||||
@ -786,7 +815,7 @@ pub async fn start_attack_mut(
|
||||
&to_whom.display_for_sentence(false, 1, false)
|
||||
));
|
||||
|
||||
let wielded = what_wielded(trans, by_whom).await?;
|
||||
let (_, wielded) = what_wielded(trans, &Arc::new(by_whom.clone())).await?;
|
||||
msg_exp.push_str(&(wielded.normal_attack.start_message(by_whom, to_whom, true) + ".\n"));
|
||||
msg_nonexp.push_str(&(wielded.normal_attack.start_message(by_whom, to_whom, false) + ".\n"));
|
||||
|
||||
|
@ -8,12 +8,15 @@ use crate::{
|
||||
task::{Task, TaskDetails, TaskMeta},
|
||||
},
|
||||
regular_tasks::{TaskHandler, TaskRunContext},
|
||||
static_content::species::SpeciesType,
|
||||
DResult,
|
||||
};
|
||||
use ansi::ansi;
|
||||
use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use log::info;
|
||||
use mockall_double::double;
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::time;
|
||||
@ -183,7 +186,7 @@ impl TaskHandler for DispelEffectTaskHandler {
|
||||
target_mut
|
||||
.active_effects
|
||||
.iter()
|
||||
.position(|e| e == effect_type)
|
||||
.position(|e| e.0 == *effect_type)
|
||||
.map(|p| target_mut.active_effects.remove(p));
|
||||
ctx.trans.save_item_model(&target_mut).await?;
|
||||
Ok(None)
|
||||
@ -195,37 +198,43 @@ pub static DISPEL_EFFECT_HANDLER: &'static (dyn TaskHandler + Sync + Send) =
|
||||
pub async fn run_effects(
|
||||
trans: &DBTrans,
|
||||
effects: &EffectSet,
|
||||
player: &mut Item,
|
||||
mut player: &mut Item,
|
||||
item: &Item,
|
||||
// None if target is player
|
||||
target: &mut Option<Item>,
|
||||
mut target: Option<&mut Item>,
|
||||
level: f64,
|
||||
task_ref: &str,
|
||||
) -> DResult<()> {
|
||||
let mut target_health_series = BTreeMap::<String, VecDeque<DelayedHealthEffect>>::new();
|
||||
let mut target_message_series = BTreeMap::<String, VecDeque<DelayedMessageEffect>>::new();
|
||||
let mut dispel_time_secs: u64 = 0;
|
||||
|
||||
for effect in &effects.effects {
|
||||
match effect {
|
||||
Effect::BroadcastMessage {
|
||||
delay_secs,
|
||||
messagef,
|
||||
} => {
|
||||
let (msg_exp, msg_nonexp) =
|
||||
messagef(player, item, target.as_ref().unwrap_or(player));
|
||||
let (msg_exp, msg_nonexp) = messagef(
|
||||
player,
|
||||
item,
|
||||
target.as_ref().map(|t| &**t).unwrap_or(player),
|
||||
);
|
||||
if *delay_secs == 0 {
|
||||
broadcast_to_room(trans, &player.location, None, &msg_exp, Some(&msg_nonexp))
|
||||
.await?;
|
||||
} else {
|
||||
dispel_time_secs = dispel_time_secs.max(*delay_secs);
|
||||
let target_it = target.as_ref().unwrap_or(player);
|
||||
let fx = DelayedMessageEffect {
|
||||
delay: *delay_secs,
|
||||
message: msg_exp,
|
||||
message_nonexp: msg_nonexp,
|
||||
};
|
||||
let actual_target: &mut Item = *target.as_mut().unwrap_or(&mut player);
|
||||
target_message_series
|
||||
.entry(format!("{}/{}", target_it.item_type, target_it.item_code))
|
||||
.entry(format!(
|
||||
"{}/{}",
|
||||
actual_target.item_type, actual_target.item_code
|
||||
))
|
||||
.and_modify(|l| l.push_back(fx.clone()))
|
||||
.or_insert(VecDeque::from([fx]));
|
||||
}
|
||||
@ -238,20 +247,20 @@ pub async fn run_effects(
|
||||
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));
|
||||
(*base_effect + ((skill_multiplier * level) as i64)).min(*max_effect) as i64;
|
||||
let (msg, msg_nonexp) = message(target.as_ref().map(|t| &**t).unwrap_or(player));
|
||||
if *delay_secs == 0 {
|
||||
change_health(
|
||||
trans,
|
||||
health_impact,
|
||||
target.as_mut().unwrap_or(player),
|
||||
*target.as_mut().unwrap_or(&mut player),
|
||||
&msg,
|
||||
&msg_nonexp,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
dispel_time_secs = dispel_time_secs.max(*delay_secs);
|
||||
let target_it = target.as_ref().unwrap_or(player);
|
||||
let target_it = target.as_ref().map(|t| &**t).unwrap_or(player);
|
||||
let fx = DelayedHealthEffect {
|
||||
magnitude: health_impact,
|
||||
delay: *delay_secs,
|
||||
@ -267,19 +276,22 @@ pub async fn run_effects(
|
||||
}
|
||||
}
|
||||
|
||||
let task_ref = trans.alloc_task_code().await?;
|
||||
if dispel_time_secs > 0 && effects.effect_type != EffectType::Ephemeral {
|
||||
let target_item = target.as_mut().unwrap_or(player);
|
||||
target_item.active_effects.push(effects.effect_type.clone());
|
||||
let actual_target: &mut Item = *target.as_mut().unwrap_or(&mut player);
|
||||
actual_target
|
||||
.active_effects
|
||||
.push((effects.effect_type.clone(), task_ref.clone()));
|
||||
|
||||
trans
|
||||
.upsert_task(&Task {
|
||||
meta: TaskMeta {
|
||||
task_code: format!("{}/{}", &target_item.refstr(), task_ref),
|
||||
task_code: format!("{}/{}", &actual_target.refstr(), task_ref),
|
||||
next_scheduled: Utc::now() + chrono::Duration::seconds(dispel_time_secs as i64),
|
||||
..Default::default()
|
||||
},
|
||||
details: TaskDetails::DispelEffect {
|
||||
target: target_item.refstr(),
|
||||
target: actual_target.refstr(),
|
||||
effect_type: effects.effect_type.clone(),
|
||||
},
|
||||
})
|
||||
@ -290,7 +302,7 @@ pub async fn run_effects(
|
||||
trans
|
||||
.upsert_task(&Task {
|
||||
meta: TaskMeta {
|
||||
task_code: format!("{}/{}", eff_item, task_ref),
|
||||
task_code: format!("{}/{}", eff_item, trans.alloc_task_code().await?),
|
||||
next_scheduled: Utc::now() + chrono::Duration::seconds(l[0].delay as i64),
|
||||
..Default::default()
|
||||
},
|
||||
@ -319,3 +331,121 @@ pub async fn run_effects(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn default_effects_for_type() -> &'static BTreeMap<EffectType, EffectSet> {
|
||||
static MAP: OnceCell<BTreeMap<EffectType, EffectSet>> = OnceCell::new();
|
||||
MAP.get_or_init(|| {
|
||||
vec![(
|
||||
EffectType::Bleed,
|
||||
EffectSet {
|
||||
effect_type: EffectType::Bleed,
|
||||
effects: vec![
|
||||
Effect::BroadcastMessage {
|
||||
delay_secs: 0,
|
||||
messagef: Box::new(|_player, _item, target| (
|
||||
format!(ansi!("<red>You notice that {} has a fresh gaping wound that looks like it's about to {}!<reset>\n"),
|
||||
target.display_for_sentence(true, 1, false),
|
||||
if target.species == SpeciesType::Robot { "leak coolant" } else { "bleed" }
|
||||
),
|
||||
format!(ansi!("<red>You notice that {} has a fresh gaping wound that looks like it's about to {}!<reset>\n"),
|
||||
target.display_for_sentence(false, 1, false),
|
||||
if target.species == SpeciesType::Robot { "leak coolant" } else { "bleed" }
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 10,
|
||||
base_effect: -12,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -12,
|
||||
message: Box::new(|target| (
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 20,
|
||||
base_effect: -10,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -10,
|
||||
message: Box::new(|target| (
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 30,
|
||||
base_effect: -8,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -8,
|
||||
message: Box::new(|target| (
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 40,
|
||||
base_effect: -6,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -6,
|
||||
message: Box::new(|target| (
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 50,
|
||||
base_effect: -4,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -4,
|
||||
message: Box::new(|target| (
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("{} pulses from {}'s wound",
|
||||
if target.species == SpeciesType::Robot { "Coolant" } else { "Blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
Effect::ChangeTargetHealth {
|
||||
delay_secs: 60,
|
||||
base_effect: -2,
|
||||
skill_multiplier: 0.0,
|
||||
max_effect: -2,
|
||||
message: Box::new(|target| (
|
||||
format!("A final tiny drop of {} oozes from {}'s wound as it heals",
|
||||
if target.species == SpeciesType::Robot { "coolant" } else { "blood" },
|
||||
target.display_for_sentence(true, 1, false),
|
||||
),
|
||||
format!("A final tiny drop of {} oozes from {}'s wound as it clots",
|
||||
if target.species == SpeciesType::Robot { "coolant" } else { "blood" },
|
||||
target.display_for_sentence(false, 1, false),
|
||||
)))
|
||||
},
|
||||
],
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect()
|
||||
})
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
message_handler::user_commands::{UResult, VerbContext},
|
||||
models::{
|
||||
consent::ConsentType,
|
||||
effect::EffectSet,
|
||||
effect::{EffectSet, EffectType},
|
||||
item::{Item, ItemFlag, LiquidType, Pronouns, SkillType},
|
||||
},
|
||||
regular_tasks::queued_command::QueuedCommandContext,
|
||||
@ -82,6 +82,7 @@ pub struct WeaponAttackData {
|
||||
pub stdev_damage: f64,
|
||||
pub base_damage_type: DamageType,
|
||||
pub other_damage_types: Vec<(f64, DamageType)>, // Allocation fractions.
|
||||
pub crit_effects: Vec<(f64, EffectType)>, // Probability, add up to <1 unless one guaranteed.
|
||||
pub skill_scaling: Vec<SkillScaling>,
|
||||
}
|
||||
|
||||
@ -108,6 +109,7 @@ impl Default for WeaponAttackData {
|
||||
stdev_damage: 2.0,
|
||||
base_damage_type: DamageType::Slash,
|
||||
other_damage_types: vec![],
|
||||
crit_effects: vec![],
|
||||
skill_scaling: vec![],
|
||||
}
|
||||
}
|
||||
@ -170,7 +172,6 @@ pub struct UseData {
|
||||
pub fail_effects: Option<EffectSet>,
|
||||
pub success_effects: Option<EffectSet>,
|
||||
pub errorf: Box<dyn Fn(&Item, &Item) -> Option<String> + Sync + Send>,
|
||||
pub task_ref: &'static str,
|
||||
pub needs_consent_check: Option<ConsentType>,
|
||||
}
|
||||
|
||||
@ -183,7 +184,6 @@ impl Default for UseData {
|
||||
fail_effects: None,
|
||||
success_effects: None,
|
||||
errorf: Box::new(|_it, _target| None),
|
||||
task_ref: "set me",
|
||||
needs_consent_check: None,
|
||||
}
|
||||
}
|
||||
|
@ -238,14 +238,13 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
|
||||
}
|
||||
),
|
||||
}),
|
||||
task_ref: "bandage",
|
||||
errorf: Box::new(
|
||||
|item, target|
|
||||
if target.death_data.is_some() {
|
||||
Some(format!("It is too late, {}'s dead", target.pronouns.subject))
|
||||
} else if target.item_type != "player" && target.item_type != "npc" {
|
||||
Some("It only works on animals.".to_owned())
|
||||
} else if target.active_effects.contains(&EffectType::Bandages) {
|
||||
} else if target.active_effects.iter().any(|e| e.0 == EffectType::Bandages) {
|
||||
Some(format!(
|
||||
"You see no reason to use {} on {}",
|
||||
item.display_for_sentence(false, 1, false),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::{DamageType, PossessionData, PossessionType, WeaponAttackData, WeaponData};
|
||||
use crate::models::item::SkillType;
|
||||
use crate::models::{effect::EffectType, item::SkillType};
|
||||
use once_cell::sync::OnceCell;
|
||||
|
||||
pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
|
||||
@ -76,6 +76,7 @@ pub fn data() -> &'static Vec<(PossessionType, PossessionData)> {
|
||||
mean_damage: 4.0,
|
||||
stdev_damage: 2.0,
|
||||
base_damage_type: DamageType::Beat,
|
||||
crit_effects: vec![(0.05, EffectType::Bleed)],
|
||||
other_damage_types: vec!((0.25, DamageType::Slash)),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -168,9 +168,8 @@ impl TaskHandler for SeePatientTaskHandler {
|
||||
},
|
||||
&mut who_mut,
|
||||
&who,
|
||||
&mut None,
|
||||
None,
|
||||
0.0,
|
||||
"bandages",
|
||||
)
|
||||
.await?;
|
||||
ctx.trans.save_item_model(&who_mut).await?;
|
||||
|
@ -70,6 +70,8 @@ CREATE UNIQUE INDEX tasks_by_code_type ON tasks((details->>'task_code'), (detail
|
||||
CREATE INDEX tasks_by_static ON tasks((cast(details->>'is_static' as boolean)));
|
||||
CREATE INDEX tasks_by_scheduled ON tasks((details->>'next_scheduled'));
|
||||
|
||||
CREATE SEQUENCE task_seq;
|
||||
|
||||
CREATE TABLE corps (
|
||||
corp_id BIGSERIAL NOT NULL PRIMARY KEY,
|
||||
details JSONB NOT NULL
|
||||
|
Loading…
Reference in New Issue
Block a user