Add buff reward + fix resolver bug
This commit is contained in:
parent
657ec807e0
commit
dbaf477f49
@ -1023,7 +1023,7 @@ impl DBTrans {
|
||||
WHERE \
|
||||
(lower(details->>'display') LIKE $1) \
|
||||
OR EXISTS (SELECT 1 FROM jsonb_array_elements(aliases) AS al(alias) WHERE \
|
||||
LOWER(alias#>>'{{}}') LIKE $1)) {} \
|
||||
LOWER(alias#>>'{{}}') LIKE $1) {} \
|
||||
ORDER BY {} ABS(length(details->>'display')-$3) ASC \
|
||||
LIMIT $4 OFFSET $2",
|
||||
&cte_str, &extra_where, &extra_order
|
||||
|
@ -151,6 +151,7 @@ impl QueueCommandHandler for QueueHandler {
|
||||
if wear_data.dodge_penalty != 0.0 {
|
||||
ctx.item.temporary_buffs.push(Buff {
|
||||
description: "Dodge penalty".to_owned(),
|
||||
code: "dodge".to_owned(),
|
||||
cause: BuffCause::ByItem {
|
||||
item_type: item_mut.item_type.clone(),
|
||||
item_code: item_mut.item_code.clone(),
|
||||
|
@ -33,12 +33,28 @@ pub enum BuffImpact {
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd)]
|
||||
#[serde(default)]
|
||||
pub struct Buff {
|
||||
pub description: String,
|
||||
pub code: String,
|
||||
pub cause: BuffCause,
|
||||
pub impacts: Vec<BuffImpact>,
|
||||
}
|
||||
|
||||
impl Default for Buff {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
description: "Default".to_owned(),
|
||||
code: "default".to_owned(),
|
||||
cause: BuffCause::WaitingTask {
|
||||
task_code: "default".to_owned(),
|
||||
task_type: "default".to_owned(),
|
||||
},
|
||||
impacts: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum SkillType {
|
||||
Appraise,
|
||||
|
@ -10,6 +10,7 @@ pub enum JournalType {
|
||||
JoinedHackerClub,
|
||||
// Misc
|
||||
Died,
|
||||
SharedWithPlayer,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Ord, PartialOrd, Eq, PartialEq)]
|
||||
|
@ -69,6 +69,10 @@ pub enum TaskDetails {
|
||||
target: String,
|
||||
effect_type: EffectType,
|
||||
},
|
||||
ExpireBuff {
|
||||
item: String,
|
||||
code: String,
|
||||
},
|
||||
}
|
||||
impl TaskDetails {
|
||||
pub fn name(self: &Self) -> &'static str {
|
||||
@ -94,6 +98,7 @@ impl TaskDetails {
|
||||
ResetSpawns => "ResetSpawns",
|
||||
ResetHanoi => "ResetHanoi",
|
||||
HospitalERSeePatient { .. } => "HospitalERSeePatient",
|
||||
ExpireBuff { .. } => "ExpireBuff",
|
||||
// Don't forget to add to TASK_HANDLER_REGISTRY in regular_tasks.rs too.
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
listener::{ListenerMap, ListenerSend},
|
||||
message_handler::user_commands::{delete, drop, hire, open, rent},
|
||||
models::task::Task,
|
||||
services::{combat, effect, sharing, spawn, urges},
|
||||
services::{combat, effect, sharing, spawn, tempbuff, urges},
|
||||
static_content::{
|
||||
npc::{self, computer_museum_npcs},
|
||||
room::general_hospital,
|
||||
@ -67,6 +67,7 @@ fn task_handler_registry(
|
||||
("ResetSpawns", spawn::RESET_SPAWNS_HANDLER),
|
||||
("ResetHanoi", computer_museum_npcs::RESET_GAME_HANDLER),
|
||||
("HospitalERSeePatient", general_hospital::SEE_PATIENT_TASK),
|
||||
("ExpireBuff", tempbuff::EXPIRE_BUFF_TASK),
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
|
@ -24,6 +24,7 @@ pub mod effect;
|
||||
pub mod sharing;
|
||||
pub mod skills;
|
||||
pub mod spawn;
|
||||
pub mod tempbuff;
|
||||
pub mod urges;
|
||||
|
||||
pub fn check_one_consent(consent: &Consent, action: &str, target: &Item) -> bool {
|
||||
|
@ -12,12 +12,15 @@ use crate::{
|
||||
models::{
|
||||
consent::ConsentType,
|
||||
item::{
|
||||
ActiveConversation, ConversationIntensity, ConversationTopic,
|
||||
ConversationalInterestType, ConversationalStyle, Item, ItemFlag, SkillType,
|
||||
ActiveConversation, Buff, BuffCause, BuffImpact, ConversationIntensity,
|
||||
ConversationTopic, ConversationalInterestType, ConversationalStyle, Item, ItemFlag,
|
||||
SkillType, StatType,
|
||||
},
|
||||
journal::JournalType,
|
||||
task::{Task, TaskDetails, TaskMeta},
|
||||
},
|
||||
regular_tasks::{TaskHandler, TaskRunContext},
|
||||
static_content::journals::award_journal_if_needed,
|
||||
DResult,
|
||||
};
|
||||
use ansi::ansi;
|
||||
@ -302,6 +305,7 @@ impl TaskHandler for ShareTaskHandler {
|
||||
.or_insert(growth.max(0) as u64)
|
||||
});
|
||||
}
|
||||
|
||||
let res = compute_conversation_result(&p1, &p1_conv, &p2, &p2_conv);
|
||||
p1_mut.active_conversation.as_mut().map(|ac| {
|
||||
ac.peak_total_interest = res.my_total_interest.max(ac.peak_total_interest);
|
||||
@ -408,7 +412,9 @@ async fn inform_player_convo_change_ready(
|
||||
}
|
||||
|
||||
fn share_skill_to_base_transition_time(skill: f64) -> f64 {
|
||||
((13.6666666666666666666667 - skill) * 3.0).max(1.0)
|
||||
((13.6666666666666666666667 - skill) * 3.0)
|
||||
.max(1.0)
|
||||
.min(23.0)
|
||||
}
|
||||
|
||||
fn compute_conversation_result(
|
||||
@ -436,8 +442,8 @@ fn compute_conversation_result(
|
||||
let their_transition_time =
|
||||
share_skill_to_base_transition_time(their_theoretical_skill_level) as u64;
|
||||
|
||||
let my_total_interest = my_direct_interest * their_transition_time;
|
||||
let their_total_interest = their_direct_interest * my_transition_time;
|
||||
let my_total_interest = my_direct_interest + 1363 * (their_transition_time - 1);
|
||||
let their_total_interest = their_direct_interest + 1363 * (my_transition_time - 1);
|
||||
|
||||
ConversationResult {
|
||||
my_total_interest,
|
||||
@ -551,7 +557,7 @@ pub async fn start_conversation(
|
||||
if initiator.item_type != "player" {
|
||||
user_error("Only players can initiate conversation with players".to_owned())?;
|
||||
}
|
||||
let (_other_sess, _other_sessdat) =
|
||||
let _ =
|
||||
trans
|
||||
.find_session_for_player(&acceptor.item_code)
|
||||
.await?
|
||||
@ -670,6 +676,116 @@ pub async fn start_conversation(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn apply_conversation_buff(trans: &DBTrans, to_player: &mut Item) -> DResult<()> {
|
||||
let peak = to_player
|
||||
.active_conversation
|
||||
.as_ref()
|
||||
.map(|ac| ac.peak_total_interest)
|
||||
.unwrap_or(0);
|
||||
let mut buffs: Vec<BuffImpact> = vec![];
|
||||
const BASE: u64 = 7691;
|
||||
if peak >= BASE * 7 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Cool,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Cool,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
if peak >= BASE * 8 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Brains,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE * 2 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Brains,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
if peak >= BASE * 9 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Senses,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE * 3 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Senses,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
if peak >= BASE * 10 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Endurance,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE * 4 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Endurance,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
if peak >= BASE * 11 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Brawn,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE * 5 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Brawn,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
if peak >= BASE * 12 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Reflexes,
|
||||
magnitude: 2.0,
|
||||
});
|
||||
} else if peak >= BASE * 6 {
|
||||
buffs.push(BuffImpact::ChangeStat {
|
||||
stat: StatType::Reflexes,
|
||||
magnitude: 1.0,
|
||||
});
|
||||
}
|
||||
|
||||
let exp_task_code = format!("sharing/{}/{}", &to_player.item_type, &to_player.item_code);
|
||||
|
||||
to_player.temporary_buffs.retain(|b| match b.cause {
|
||||
BuffCause::WaitingTask {
|
||||
ref task_type,
|
||||
ref task_code,
|
||||
} if task_type == "ExpireBuff" && task_code == &exp_task_code => true,
|
||||
_ => false,
|
||||
});
|
||||
to_player.temporary_buffs.push(Buff {
|
||||
description: "Sharing knowledge improved you (for a while)".to_owned(),
|
||||
code: "sharing".to_owned(),
|
||||
cause: BuffCause::WaitingTask {
|
||||
task_type: "ExpireBuff".to_owned(),
|
||||
task_code: exp_task_code.clone(),
|
||||
},
|
||||
impacts: buffs,
|
||||
});
|
||||
trans
|
||||
.upsert_task(&Task {
|
||||
meta: TaskMeta {
|
||||
task_code: exp_task_code.clone(),
|
||||
next_scheduled: Utc::now() + chrono::Duration::seconds(600),
|
||||
..Default::default()
|
||||
},
|
||||
details: TaskDetails::ExpireBuff {
|
||||
item: to_player.refstr(),
|
||||
code: "sharing".to_owned(),
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn stop_conversation_mut(
|
||||
trans: &DBTrans,
|
||||
participant: &mut Item,
|
||||
@ -693,8 +809,39 @@ pub async fn stop_conversation_mut(
|
||||
};
|
||||
let mut partner_mut = (*partner).clone();
|
||||
|
||||
apply_conversation_buff(trans, &mut partner_mut).await?;
|
||||
apply_conversation_buff(trans, participant).await?;
|
||||
|
||||
participant.active_conversation = None;
|
||||
partner_mut.active_conversation = None;
|
||||
|
||||
if participant.item_type == "player" && partner_mut.item_type == "player" {
|
||||
if let Some(mut participant_user) = trans.find_by_username(&participant.item_code).await? {
|
||||
if award_journal_if_needed(
|
||||
trans,
|
||||
&mut participant_user,
|
||||
participant,
|
||||
JournalType::SharedWithPlayer,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
trans.save_user_model(&participant_user).await?;
|
||||
}
|
||||
}
|
||||
if let Some(mut partner_user) = trans.find_by_username(&partner.item_code).await? {
|
||||
if award_journal_if_needed(
|
||||
trans,
|
||||
&mut partner_user,
|
||||
&mut partner_mut,
|
||||
JournalType::SharedWithPlayer,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
trans.save_user_model(&partner_user).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trans.save_item_model(&partner_mut).await?;
|
||||
|
||||
broadcast_to_room(
|
||||
|
42
blastmud_game/src/services/tempbuff.rs
Normal file
42
blastmud_game/src/services/tempbuff.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use crate::{
|
||||
models::task::TaskDetails,
|
||||
regular_tasks::{TaskHandler, TaskRunContext},
|
||||
DResult,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use std::time;
|
||||
|
||||
pub struct ExpireBuffTask;
|
||||
#[async_trait]
|
||||
impl TaskHandler for ExpireBuffTask {
|
||||
async fn do_task(&self, ctx: &mut TaskRunContext) -> DResult<Option<time::Duration>> {
|
||||
let (item_ref, code) = match ctx.task.details {
|
||||
TaskDetails::ExpireBuff { ref item, ref code } => Ok((item, code)),
|
||||
_ => Err("Bad task type for ExpireBuffTask"),
|
||||
}?;
|
||||
|
||||
let (item_type, item_code) = match item_ref.split_once("/") {
|
||||
Some(v) => Ok(v),
|
||||
None => Err("Invalid item for ExpireBuffTask"),
|
||||
}?;
|
||||
|
||||
let item = ctx
|
||||
.trans
|
||||
.find_item_by_type_code(item_type, item_code)
|
||||
.await?;
|
||||
let mut item = match item {
|
||||
None => return Ok(None),
|
||||
Some(i) => (*i).clone(),
|
||||
};
|
||||
|
||||
item.temporary_buffs = item
|
||||
.temporary_buffs
|
||||
.into_iter()
|
||||
.filter(|b| &b.code != code)
|
||||
.collect();
|
||||
ctx.trans.save_item_model(&item).await?;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
pub static EXPIRE_BUFF_TASK: &'static (dyn TaskHandler + Sync + Send) = &ExpireBuffTask;
|
@ -61,7 +61,12 @@ pub fn journal_types() -> &'static BTreeMap<JournalType, JournalData> {
|
||||
name: "Carked it",
|
||||
details: "dying for the first time. Fortunately, you can come back by recloning in to a fresh body, just with fewer credits, a bit less experience, and a bruised ego! All your stuff is still on your body, so better go find it, or give up on it.",
|
||||
xp: 150
|
||||
})
|
||||
}),
|
||||
(JournalType::SharedWithPlayer, JournalData {
|
||||
name: "Learned to share",
|
||||
details: "sharing knowledge in a conversation [with another player]",
|
||||
xp: 200,
|
||||
}),
|
||||
).into_iter().collect());
|
||||
}
|
||||
|
||||
|
@ -22,3 +22,9 @@ This is expected to be 0 - haven't seen any instances of it deviating, so any bu
|
||||
select i1.details->>'item_code' as i1_code, i1.details->>'active_combat' as i1_combat, i1.details->>'location' as i1_loc, i2.details->>'item_code' as i2_code, i2.details->>'active_combat' as i2_combat, i2.details->>'location' as i2_loc from items i1 join items i2 on i2.details->>'item_type' = (regexp_split_to_array(i1.details->'active_combat'->>'attacking', '/'))[1] and i2.details->>'item_code' = (regexp_split_to_array(i1.details->'active_combat'->>'attacking', '/'))[2] where not exists (select 1 from jsonb_array_elements_text(i2.details->'active_combat'->'attacked_by') e where e = ((i1.details->>'item_type') || '/' || (i1.details->>'item_code')));
|
||||
|
||||
This should be empty, but there has been a bug breaking this.
|
||||
|
||||
# Other types of migrations
|
||||
## Rename a skill
|
||||
|
||||
Something like this:
|
||||
with fexdet as (select item_id, jsonb_strip_nulls(jsonb_set(details, '{total_skills,Fuck}', 'null')) as details, details->'total_skills'->'Fuck' as f from items), amenddet as (select jsonb_set(details :: jsonb, '{total_skills,Share}', f :: jsonb) as details, item_id from fexdet where f is not null) update items i set details = a.details from amenddet a where i.item_id = a.item_id;
|
||||
|
Loading…
Reference in New Issue
Block a user