Add FalukantFamilyWorker and related SQL queries: Introduced the FalukantFamilyWorker to manage family-related logic, including marriage satisfaction and relationship states. Added new SQL queries for handling lover relationships and marriage updates, enhancing the overall functionality of family dynamics in the application.
This commit is contained in:
@@ -16,6 +16,7 @@ use worker::{
|
||||
CharacterCreationWorker, ConnectionPool, DirectorWorker, EventsWorker, HouseWorker,
|
||||
PoliticsWorker, ProduceWorker, StockageManager, TransportWorker, UndergroundWorker,
|
||||
UserCharacterWorker, ValueRecalculationWorker, WeatherWorker, Worker,
|
||||
FalukantFamilyWorker,
|
||||
};
|
||||
|
||||
static KEEP_RUNNING: AtomicBool = AtomicBool::new(true);
|
||||
@@ -137,6 +138,10 @@ fn create_workers(pool: ConnectionPool, broker: MessageBroker) -> Vec<Box<dyn Wo
|
||||
pool.clone(),
|
||||
broker.clone(),
|
||||
)),
|
||||
Box::new(FalukantFamilyWorker::new(
|
||||
pool.clone(),
|
||||
broker.clone(),
|
||||
)),
|
||||
Box::new(HouseWorker::new(pool.clone(), broker.clone())),
|
||||
Box::new(PoliticsWorker::new(pool.clone(), broker.clone())),
|
||||
Box::new(TransportWorker::new(pool.clone(), broker.clone())),
|
||||
|
||||
766
src/worker/falukant_family.rs
Normal file
766
src/worker/falukant_family.rs
Normal file
@@ -0,0 +1,766 @@
|
||||
//! Liebhaber, Ehezufriedenheit, Ansehen, Monatskosten (Handoff: docs/FALUKANT_DAEMON_HANDOFF.md).
|
||||
//! Benötigt `migrations/001_falukant_family_lovers.sql` (ggf. `002` bei Altbestand).
|
||||
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use rand::distributions::{Distribution, Uniform};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
use super::base::{BaseWorker, Worker, WorkerState};
|
||||
use super::sql::{
|
||||
QUERY_FAMILY_SCHEMA_READY, QUERY_GET_ACTIVE_LOVER_ROWS_FOR_DAILY,
|
||||
QUERY_GET_ACTIVE_LOVER_ROWS_FOR_MONTHLY, QUERY_GET_LOVER_PREGNANCY_CANDIDATES,
|
||||
QUERY_GET_MARRIAGE_ROWS, QUERY_INSERT_CHILD, QUERY_INSERT_CHILD_RELATION_LOVER,
|
||||
QUERY_LOVER_BIRTH_PENALTY_MARRIAGE, QUERY_LOVER_BIRTH_PENALTY_REPUTATION,
|
||||
QUERY_MARK_LOVER_DAILY_DONE, QUERY_MARK_LOVER_MONTHLY_DONE,
|
||||
QUERY_MARRIAGE_SUBTRACT_SATISFACTION, QUERY_RESET_LOVER_UNDERPAY_COUNTERS,
|
||||
QUERY_UPDATE_CHARACTER_REPUTATION, QUERY_UPDATE_LOVER_UNDERPAY_STATE,
|
||||
QUERY_UPDATE_LOVER_VISIBILITY_DISCRETION, QUERY_UPDATE_MARRIAGE_STATE,
|
||||
};
|
||||
use crate::db::{ConnectionPool, DbError};
|
||||
use crate::message_broker::MessageBroker;
|
||||
|
||||
const DAILY_INTERVAL: Duration = Duration::from_secs(24 * 3600);
|
||||
const MONTHLY_INTERVAL: Duration = Duration::from_secs(30 * 24 * 3600);
|
||||
|
||||
pub struct FalukantFamilyWorker {
|
||||
base: BaseWorker,
|
||||
rng: StdRng,
|
||||
dist: Uniform<f64>,
|
||||
last_daily: Option<Instant>,
|
||||
last_monthly: Option<Instant>,
|
||||
schema_ready: bool,
|
||||
}
|
||||
|
||||
impl FalukantFamilyWorker {
|
||||
pub fn new(pool: ConnectionPool, broker: MessageBroker) -> Self {
|
||||
Self {
|
||||
base: BaseWorker::new("FalukantFamilyWorker", pool, broker),
|
||||
rng: StdRng::from_entropy(),
|
||||
dist: Uniform::from(0.0..1.0),
|
||||
last_daily: None,
|
||||
last_monthly: None,
|
||||
schema_ready: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn run_iteration(&mut self, state: &WorkerState) {
|
||||
self.base.set_current_step("FalukantFamilyWorker iteration");
|
||||
let now = Instant::now();
|
||||
|
||||
if !self.schema_ready {
|
||||
if let Ok(true) = self.check_schema() {
|
||||
self.schema_ready = true;
|
||||
} else {
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if Self::should_run(self.last_daily, now, DAILY_INTERVAL) {
|
||||
if let Err(e) = self.process_daily() {
|
||||
eprintln!("[FalukantFamilyWorker] process_daily: {e}");
|
||||
}
|
||||
self.last_daily = Some(now);
|
||||
}
|
||||
|
||||
if Self::should_run(self.last_monthly, now, MONTHLY_INTERVAL) {
|
||||
if let Err(e) = self.process_monthly() {
|
||||
eprintln!("[FalukantFamilyWorker] process_monthly: {e}");
|
||||
}
|
||||
self.last_monthly = Some(now);
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_secs(1));
|
||||
if !state.running_worker.load(Ordering::Relaxed) {
|
||||
// stopping
|
||||
}
|
||||
}
|
||||
|
||||
fn should_run(last: Option<Instant>, now: Instant, interval: Duration) -> bool {
|
||||
match last {
|
||||
None => true,
|
||||
Some(t) => now.saturating_duration_since(t) >= interval,
|
||||
}
|
||||
}
|
||||
|
||||
fn check_schema(&mut self) -> Result<bool, DbError> {
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
conn.prepare("family_schema", QUERY_FAMILY_SCHEMA_READY)?;
|
||||
let rows = conn.execute("family_schema", &[])?;
|
||||
Ok(rows
|
||||
.first()
|
||||
.and_then(|r| r.get("ready"))
|
||||
.map(|v| v == "true" || v == "t")
|
||||
.unwrap_or(false))
|
||||
}
|
||||
|
||||
fn process_daily(&mut self) -> Result<(), DbError> {
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
|
||||
conn.prepare("get_lovers", QUERY_GET_ACTIVE_LOVER_ROWS_FOR_DAILY)?;
|
||||
let lover_rows = conn.execute("get_lovers", &[])?;
|
||||
|
||||
conn.prepare("get_marriages", QUERY_GET_MARRIAGE_ROWS)?;
|
||||
let marriage_rows = conn.execute("get_marriages", &[])?;
|
||||
|
||||
let marriages: Vec<MarriageData> = marriage_rows
|
||||
.into_iter()
|
||||
.filter_map(|r| {
|
||||
Some(MarriageData {
|
||||
id: parse_i32(&r, "marriage_id", -1),
|
||||
m1: parse_i32(&r, "m1", -1),
|
||||
m2: parse_i32(&r, "m2", -1),
|
||||
satisfaction: parse_i32(&r, "marriage_satisfaction", 55),
|
||||
drift_high: parse_i32(&r, "marriage_drift_high", 0),
|
||||
drift_low: parse_i32(&r, "marriage_drift_low", 0),
|
||||
title1_tr: r.get("title1_tr").cloned().unwrap_or_default(),
|
||||
title2_tr: r.get("title2_tr").cloned().unwrap_or_default(),
|
||||
})
|
||||
})
|
||||
.filter(|m| m.id > 0)
|
||||
.collect();
|
||||
|
||||
let mut lovers: Vec<LoverData> = lover_rows
|
||||
.into_iter()
|
||||
.filter_map(|r| {
|
||||
Some(LoverData {
|
||||
rel_id: parse_i32(&r, "rel_id", -1),
|
||||
c1: parse_i32(&r, "c1", -1),
|
||||
c2: parse_i32(&r, "c2", -1),
|
||||
lover_role: r.get("lover_role").cloned().unwrap_or_default(),
|
||||
affection: parse_i32(&r, "affection", 50),
|
||||
visibility: parse_i32(&r, "visibility", 0),
|
||||
discretion: parse_i32(&r, "discretion", 50),
|
||||
maintenance_level: parse_i32(&r, "maintenance_level", 50),
|
||||
status_fit: parse_i32(&r, "status_fit", 0),
|
||||
scandal_extra: parse_i32(&r, "scandal_extra_daily_pct", 0),
|
||||
title1_tr: r.get("title1_tr").cloned().unwrap_or_default(),
|
||||
title2_tr: r.get("title2_tr").cloned().unwrap_or_default(),
|
||||
})
|
||||
})
|
||||
.filter(|l| l.rel_id > 0)
|
||||
.collect();
|
||||
|
||||
let mut char_lover_count: std::collections::HashMap<i32, usize> =
|
||||
std::collections::HashMap::new();
|
||||
for l in &lovers {
|
||||
*char_lover_count.entry(l.c1).or_insert(0) += 1;
|
||||
*char_lover_count.entry(l.c2).or_insert(0) += 1;
|
||||
}
|
||||
|
||||
conn.prepare("upd_vd", QUERY_UPDATE_LOVER_VISIBILITY_DISCRETION)?;
|
||||
for l in &mut lovers {
|
||||
let ehe_conflict = marriages.iter().any(|m| {
|
||||
(m.m1 == l.c1 || m.m2 == l.c1 || m.m1 == l.c2 || m.m2 == l.c2) && m.satisfaction < 40
|
||||
});
|
||||
|
||||
let mut v_net = 0i32;
|
||||
if l.maintenance_level < 35 {
|
||||
v_net += 1;
|
||||
}
|
||||
if l.affection < 30 {
|
||||
v_net += 1;
|
||||
}
|
||||
if l.status_fit == -2 {
|
||||
v_net += 2;
|
||||
}
|
||||
if ehe_conflict {
|
||||
v_net += 1;
|
||||
}
|
||||
if l.discretion >= 60 {
|
||||
v_net -= 1;
|
||||
}
|
||||
if l.maintenance_level >= 70 {
|
||||
v_net -= 1;
|
||||
}
|
||||
let new_vis = clamp_i32(l.visibility + v_net, 0, 100);
|
||||
|
||||
let mut d_net = 0i32;
|
||||
if l.maintenance_level >= 70 {
|
||||
d_net += 1;
|
||||
}
|
||||
if l.maintenance_level < 35 {
|
||||
d_net -= 1;
|
||||
}
|
||||
if l.visibility > 60 {
|
||||
d_net -= 1;
|
||||
}
|
||||
let new_disc = clamp_i32(l.discretion + d_net, 0, 100);
|
||||
|
||||
conn.execute(
|
||||
"upd_vd",
|
||||
&[&new_vis, &new_disc, &l.rel_id],
|
||||
)?;
|
||||
l.visibility = new_vis;
|
||||
l.discretion = new_disc;
|
||||
}
|
||||
|
||||
conn.prepare("mark_daily", QUERY_MARK_LOVER_DAILY_DONE)?;
|
||||
for l in &lovers {
|
||||
conn.execute("mark_daily", &[&l.rel_id])?;
|
||||
}
|
||||
|
||||
for m in &marriages {
|
||||
let touching: Vec<&LoverData> = lovers
|
||||
.iter()
|
||||
.filter(|l| {
|
||||
let (a, b) = (l.c1, l.c2);
|
||||
((a == m.m1 && b != m.m2) || (b == m.m1 && a != m.m2))
|
||||
|| ((a == m.m2 && b != m.m1) || (b == m.m2 && a != m.m1))
|
||||
})
|
||||
.collect();
|
||||
|
||||
if touching.is_empty() {
|
||||
let mut sat = m.satisfaction;
|
||||
let mut dh = m.drift_high;
|
||||
let mut dl = m.drift_low;
|
||||
if sat > 55 {
|
||||
dh += 1;
|
||||
if dh >= 3 {
|
||||
sat = (sat - 1).max(0);
|
||||
dh = 0;
|
||||
}
|
||||
} else if sat < 55 {
|
||||
dl += 1;
|
||||
if dl >= 5 {
|
||||
sat = (sat + 1).min(100);
|
||||
dl = 0;
|
||||
}
|
||||
}
|
||||
conn.prepare("upd_marriage", QUERY_UPDATE_MARRIAGE_STATE)?;
|
||||
conn.execute(
|
||||
"upd_marriage",
|
||||
&[&sat, &dh, &dl, &m.id],
|
||||
)?;
|
||||
continue;
|
||||
}
|
||||
|
||||
let mg = marriage_rank_group(&m.title1_tr, &m.title2_tr);
|
||||
let mistress_n = touching
|
||||
.iter()
|
||||
.filter(|l| l.lover_role == "mistress_or_favorite")
|
||||
.count();
|
||||
let total_lovers_here = touching.len();
|
||||
let mut delta = 0i32;
|
||||
for l in &touching {
|
||||
delta += lover_marriage_daily_delta(
|
||||
mg,
|
||||
l,
|
||||
m.satisfaction,
|
||||
mistress_n,
|
||||
total_lovers_here,
|
||||
);
|
||||
}
|
||||
if touching.iter().any(|l| l.visibility >= 60) {
|
||||
delta -= 2;
|
||||
}
|
||||
if total_lovers_here >= 2 {
|
||||
delta -= 2;
|
||||
}
|
||||
if touching
|
||||
.iter()
|
||||
.any(|l| l.lover_role == "mistress_or_favorite" && l.maintenance_level < 35)
|
||||
{
|
||||
delta -= 1;
|
||||
}
|
||||
|
||||
let sat = clamp_i32(m.satisfaction + delta, 0, 100);
|
||||
conn.prepare("upd_marriage", QUERY_UPDATE_MARRIAGE_STATE)?;
|
||||
conn.execute(
|
||||
"upd_marriage",
|
||||
&[&sat, &m.drift_high, &m.drift_low, &m.id],
|
||||
)?;
|
||||
}
|
||||
|
||||
conn.prepare("upd_rep", QUERY_UPDATE_CHARACTER_REPUTATION)?;
|
||||
for l in &lovers {
|
||||
let g = pair_rank_group(&l.title1_tr, &l.title2_tr);
|
||||
let scandal = l.visibility > 70;
|
||||
let rm = rank_rep_modifier(g, scandal);
|
||||
let vf = 0.4 + (l.visibility as f64 / 100.0) * 1.6;
|
||||
let base = match l.lover_role.as_str() {
|
||||
"secret_affair" => -0.2,
|
||||
"lover" => -0.4,
|
||||
"mistress_or_favorite" => -0.6,
|
||||
_ => -0.4,
|
||||
};
|
||||
let mut delta = base * vf * rm;
|
||||
|
||||
let order_ok = l.maintenance_level >= 65
|
||||
&& l.discretion >= 60
|
||||
&& l.visibility <= 35
|
||||
&& mistress_count_for_pair(&lovers, l.c1, l.c2) <= 1;
|
||||
if l.lover_role == "mistress_or_favorite" && order_ok {
|
||||
if g == 2 {
|
||||
delta = 0.1;
|
||||
} else if g == 3 {
|
||||
delta = 0.2;
|
||||
}
|
||||
}
|
||||
|
||||
delta = delta.clamp(-3.0, 1.0);
|
||||
|
||||
for cid in [l.c1, l.c2] {
|
||||
let cur = fetch_reputation(&mut conn, cid)?;
|
||||
let new_rep = (cur + delta).clamp(0.0, 100.0);
|
||||
let s = format!("{:.2}", new_rep);
|
||||
conn.execute("upd_rep", &[&s, &cid])?;
|
||||
}
|
||||
|
||||
let married_c1 = marriages
|
||||
.iter()
|
||||
.any(|m| m.m1 == l.c1 || m.m2 == l.c1);
|
||||
let married_c2 = marriages
|
||||
.iter()
|
||||
.any(|m| m.m1 == l.c2 || m.m2 == l.c2);
|
||||
let mut p = 1.0
|
||||
+ (l.visibility as f64) / 25.0
|
||||
+ if married_c1 || married_c2 { 2.0 } else { 0.0 }
|
||||
+ if l.status_fit == -2 { 2.0 } else { 0.0 }
|
||||
+ if l.maintenance_level < 25 { 3.0 } else { 0.0 }
|
||||
+ if char_lover_count.get(&l.c1).copied().unwrap_or(0) >= 2
|
||||
|| char_lover_count.get(&l.c2).copied().unwrap_or(0) >= 2
|
||||
{
|
||||
3.0
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
+ l.scandal_extra as f64;
|
||||
if l.discretion >= 75 {
|
||||
p -= 2.0;
|
||||
}
|
||||
if g == 3
|
||||
&& l.lover_role == "mistress_or_favorite"
|
||||
&& l.maintenance_level >= 65
|
||||
&& l.visibility <= 40
|
||||
{
|
||||
p -= 2.0;
|
||||
}
|
||||
p = p.clamp(0.0, 25.0);
|
||||
if self.dist.sample(&mut self.rng) * 100.0 < p {
|
||||
let _ = self.base.broker.publish(format!(
|
||||
r#"{{"event":"falukant_family_scandal_hint","relationship_id":{}}}"#,
|
||||
l.rel_id
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_monthly(&mut self) -> Result<(), DbError> {
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
|
||||
conn.prepare("get_lovers_m", QUERY_GET_ACTIVE_LOVER_ROWS_FOR_MONTHLY)?;
|
||||
let lover_rows = conn.execute("get_lovers_m", &[])?;
|
||||
|
||||
conn.prepare("upd_under", QUERY_UPDATE_LOVER_UNDERPAY_STATE)?;
|
||||
conn.prepare("reset_under", QUERY_RESET_LOVER_UNDERPAY_COUNTERS)?;
|
||||
conn.prepare("mar_sub", QUERY_MARRIAGE_SUBTRACT_SATISFACTION)?;
|
||||
conn.prepare("mark_monthly", QUERY_MARK_LOVER_MONTHLY_DONE)?;
|
||||
|
||||
for r in lover_rows {
|
||||
let rel_id = parse_i32(&r, "rel_id", -1);
|
||||
if rel_id < 0 {
|
||||
continue;
|
||||
}
|
||||
let lover_role = r.get("lover_role").cloned().unwrap_or_default();
|
||||
let maintenance_level = parse_i32(&r, "maintenance_level", 50);
|
||||
let status_fit = parse_i32(&r, "status_fit", 0);
|
||||
let mut base = parse_i32(&r, "monthly_base_cost", 0);
|
||||
if base <= 0 {
|
||||
base = match lover_role.as_str() {
|
||||
"secret_affair" => 10,
|
||||
"lover" => 30,
|
||||
"mistress_or_favorite" => 80,
|
||||
_ => 30,
|
||||
};
|
||||
}
|
||||
let title1 = r.get("title1_tr").cloned().unwrap_or_default();
|
||||
let title2 = r.get("title2_tr").cloned().unwrap_or_default();
|
||||
let g = pair_rank_group(&title1, &title2);
|
||||
let rank_m = rank_cost_multiplier(g);
|
||||
let maint_f = 0.6 + (maintenance_level as f64 / 100.0) * 1.2;
|
||||
let sf_m = match status_fit {
|
||||
-2 => 1.35,
|
||||
-1 => 1.15,
|
||||
_ => 1.0,
|
||||
};
|
||||
let cost = ((base as f64) * rank_m * maint_f * sf_m).round() as i32;
|
||||
|
||||
let u1 = parse_opt_i32(&r, "user1_id");
|
||||
let u2 = parse_opt_i32(&r, "user2_id");
|
||||
let payer = u1.or(u2).filter(|x| *x > 0);
|
||||
|
||||
let affection = parse_i32(&r, "affection", 50);
|
||||
let visibility = parse_i32(&r, "visibility", 0);
|
||||
let discretion = parse_i32(&r, "discretion", 50);
|
||||
let mut consec = parse_i32(&r, "months_underfunded", 0);
|
||||
let mut scandal_extra = parse_i32(&r, "scandal_extra_daily_pct", 0);
|
||||
|
||||
if let Some(uid) = payer {
|
||||
let money = self.get_user_money(uid)?;
|
||||
if money >= cost as f64 {
|
||||
self.base.change_falukant_user_money(
|
||||
uid,
|
||||
-(cost as f64),
|
||||
"lover maintenance",
|
||||
)?;
|
||||
conn.execute("reset_under", &[&rel_id])?;
|
||||
} else {
|
||||
let new_aff = clamp_i32(affection - 8, 0, 100);
|
||||
let new_disc = clamp_i32(discretion - 6, 0, 100);
|
||||
let new_vis = clamp_i32(visibility + 8, 0, 100);
|
||||
consec += 1;
|
||||
if consec >= 2 {
|
||||
scandal_extra = (scandal_extra + 2).min(100);
|
||||
}
|
||||
conn.execute(
|
||||
"upd_under",
|
||||
&[
|
||||
&new_aff,
|
||||
&new_disc,
|
||||
&new_vis,
|
||||
&consec,
|
||||
&scandal_extra,
|
||||
&rel_id,
|
||||
],
|
||||
)?;
|
||||
|
||||
for cid in [parse_i32(&r, "c1", 0), parse_i32(&r, "c2", 0)] {
|
||||
if cid <= 0 {
|
||||
continue;
|
||||
}
|
||||
if let Ok(Some(mid)) = marriage_id_for_character(&mut conn, cid) {
|
||||
conn.execute("mar_sub", &[&mid, &4])?;
|
||||
}
|
||||
}
|
||||
|
||||
if visibility >= 40 {
|
||||
for cid in [parse_i32(&r, "c1", 0), parse_i32(&r, "c2", 0)] {
|
||||
if cid > 0 {
|
||||
let cur = fetch_reputation(&mut conn, cid)?;
|
||||
let s = format!("{:.2}", (cur - 1.0).max(0.0));
|
||||
conn.prepare("upd_rep", QUERY_UPDATE_CHARACTER_REPUTATION)?;
|
||||
conn.execute("upd_rep", &[&s, &cid])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
conn.execute("mark_monthly", &[&rel_id])?;
|
||||
}
|
||||
|
||||
drop(conn);
|
||||
self.process_lover_births()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_user_money(&mut self, user_id: i32) -> Result<f64, DbError> {
|
||||
use super::sql::{QUERY_GET_CURRENT_MONEY};
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
conn.prepare("gcm", QUERY_GET_CURRENT_MONEY)?;
|
||||
let rows = conn.execute("gcm", &[&user_id])?;
|
||||
Ok(rows
|
||||
.first()
|
||||
.and_then(|r| r.get("sum"))
|
||||
.and_then(|v| v.parse::<f64>().ok())
|
||||
.unwrap_or(0.0))
|
||||
}
|
||||
|
||||
fn process_lover_births(&mut self) -> Result<(), DbError> {
|
||||
let mut conn = self
|
||||
.base
|
||||
.pool
|
||||
.get()
|
||||
.map_err(|e| DbError::new(format!("DB-Verbindung fehlgeschlagen: {e}")))?;
|
||||
|
||||
conn.prepare("lover_preg", QUERY_GET_LOVER_PREGNANCY_CANDIDATES)?;
|
||||
let rows = conn.execute("lover_preg", &[])?;
|
||||
|
||||
conn.prepare("insert_child", QUERY_INSERT_CHILD)?;
|
||||
conn.prepare("insert_child_rel_lover", QUERY_INSERT_CHILD_RELATION_LOVER)?;
|
||||
conn.prepare("pen_mar", QUERY_LOVER_BIRTH_PENALTY_MARRIAGE)?;
|
||||
conn.prepare("pen_rep", QUERY_LOVER_BIRTH_PENALTY_REPUTATION)?;
|
||||
|
||||
for row in rows {
|
||||
let father_cid = parse_i32(&row, "father_cid", -1);
|
||||
let mother_cid = parse_i32(&row, "mother_cid", -1);
|
||||
if father_cid < 0 || mother_cid < 0 {
|
||||
continue;
|
||||
}
|
||||
let title_of_nobility = parse_i32(&row, "title_of_nobility", 0);
|
||||
let last_name = parse_i32(&row, "last_name", 0);
|
||||
let region_id = parse_i32(&row, "region_id", 0);
|
||||
let father_uid = parse_opt_i32(&row, "father_uid");
|
||||
let mother_uid = parse_opt_i32(&row, "mother_uid");
|
||||
|
||||
let gender = if self.dist.sample(&mut self.rng) < 0.5 {
|
||||
"male"
|
||||
} else {
|
||||
"female"
|
||||
};
|
||||
|
||||
let inserted =
|
||||
conn.execute("insert_child", &[®ion_id, &gender, &last_name, &title_of_nobility])?;
|
||||
let child_cid = inserted
|
||||
.first()
|
||||
.and_then(|r| r.get("child_cid"))
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(-1);
|
||||
if child_cid < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
conn.execute(
|
||||
"insert_child_rel_lover",
|
||||
&[&father_cid, &mother_cid, &child_cid],
|
||||
)?;
|
||||
|
||||
conn.execute("pen_mar", &[&father_cid])?;
|
||||
conn.execute("pen_mar", &[&mother_cid])?;
|
||||
conn.execute("pen_rep", &[&father_cid])?;
|
||||
conn.execute("pen_rep", &[&mother_cid])?;
|
||||
|
||||
if let Some(uid) = father_uid {
|
||||
self.publish_children(uid);
|
||||
}
|
||||
if let Some(uid) = mother_uid {
|
||||
self.publish_children(uid);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn publish_children(&self, user_id: i32) {
|
||||
let children_update =
|
||||
format!(r#"{{"event":"children_update","user_id":{}}}"#, user_id);
|
||||
self.base.broker.publish(children_update);
|
||||
let update_status =
|
||||
format!(r#"{{"event":"falukantUpdateStatus","user_id":{}}}"#, user_id);
|
||||
self.base.broker.publish(update_status);
|
||||
}
|
||||
}
|
||||
|
||||
struct MarriageData {
|
||||
id: i32,
|
||||
m1: i32,
|
||||
m2: i32,
|
||||
satisfaction: i32,
|
||||
drift_high: i32,
|
||||
drift_low: i32,
|
||||
title1_tr: String,
|
||||
title2_tr: String,
|
||||
}
|
||||
|
||||
struct LoverData {
|
||||
rel_id: i32,
|
||||
c1: i32,
|
||||
c2: i32,
|
||||
lover_role: String,
|
||||
affection: i32,
|
||||
visibility: i32,
|
||||
discretion: i32,
|
||||
maintenance_level: i32,
|
||||
status_fit: i32,
|
||||
scandal_extra: i32,
|
||||
title1_tr: String,
|
||||
title2_tr: String,
|
||||
}
|
||||
|
||||
fn parse_i32(row: &crate::db::Row, key: &str, default: i32) -> i32 {
|
||||
row.get(key)
|
||||
.and_then(|v| v.parse::<i32>().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn parse_opt_i32(row: &crate::db::Row, key: &str) -> Option<i32> {
|
||||
row.get(key).and_then(|v| v.parse::<i32>().ok())
|
||||
}
|
||||
|
||||
fn clamp_i32(v: i32, lo: i32, hi: i32) -> i32 {
|
||||
v.max(lo).min(hi)
|
||||
}
|
||||
|
||||
fn title_group(tr: &str) -> u8 {
|
||||
match tr {
|
||||
"noncivil" | "civil" | "sir" => 0,
|
||||
"townlord" | "by" | "landlord" => 1,
|
||||
"knight" | "baron" | "count" | "palsgrave" | "margrave" | "landgrave" => 2,
|
||||
"ruler" | "elector"
|
||||
| "imperial-prince"
|
||||
| "duke"
|
||||
| "grand-duke"
|
||||
| "prince-regent"
|
||||
| "king" => 3,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn marriage_rank_group(t1: &str, t2: &str) -> u8 {
|
||||
title_group(t1).max(title_group(t2))
|
||||
}
|
||||
|
||||
fn pair_rank_group(t1: &str, t2: &str) -> u8 {
|
||||
title_group(t1).max(title_group(t2))
|
||||
}
|
||||
|
||||
fn rank_cost_multiplier(g: u8) -> f64 {
|
||||
match g {
|
||||
0 => 1.0,
|
||||
1 => 1.6,
|
||||
2 => 2.6,
|
||||
3 => 4.0,
|
||||
_ => 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn rank_rep_modifier(g: u8, scandal: bool) -> f64 {
|
||||
if g == 3 && scandal {
|
||||
return 1.5;
|
||||
}
|
||||
match g {
|
||||
0 => 1.8,
|
||||
1 => 1.3,
|
||||
2 => 1.0,
|
||||
3 => 0.7,
|
||||
_ => 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn lover_marriage_daily_delta(
|
||||
mg: u8,
|
||||
l: &LoverData,
|
||||
m_sat: i32,
|
||||
mistress_n: usize,
|
||||
total_lovers: usize,
|
||||
) -> i32 {
|
||||
let role = l.lover_role.as_str();
|
||||
match mg {
|
||||
0 => match role {
|
||||
"secret_affair" => -1,
|
||||
"lover" => -2,
|
||||
"mistress_or_favorite" => -3,
|
||||
_ => -2,
|
||||
},
|
||||
1 => match role {
|
||||
"secret_affair" => -1,
|
||||
"lover" => -1,
|
||||
"mistress_or_favorite" => -2,
|
||||
_ => -1,
|
||||
},
|
||||
2 => match role {
|
||||
"secret_affair" => -1,
|
||||
"lover" => -1,
|
||||
"mistress_or_favorite" => -1,
|
||||
_ => -1,
|
||||
},
|
||||
3 => {
|
||||
if role == "mistress_or_favorite" {
|
||||
if l.visibility <= 35
|
||||
&& l.maintenance_level >= 65
|
||||
&& m_sat >= 45
|
||||
&& mistress_n <= 1
|
||||
&& total_lovers <= 1
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if l.visibility > 50 || l.maintenance_level < 40 {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if role == "secret_affair" {
|
||||
return 0;
|
||||
}
|
||||
if role == "lover" {
|
||||
return 0;
|
||||
}
|
||||
0
|
||||
}
|
||||
_ => -1,
|
||||
}
|
||||
}
|
||||
|
||||
fn mistress_count_for_pair(lovers: &[LoverData], c1: i32, c2: i32) -> usize {
|
||||
lovers
|
||||
.iter()
|
||||
.filter(|l| {
|
||||
(l.c1 == c1 || l.c2 == c1 || l.c1 == c2 || l.c2 == c2)
|
||||
&& l.lover_role == "mistress_or_favorite"
|
||||
})
|
||||
.count()
|
||||
}
|
||||
|
||||
fn fetch_reputation(conn: &mut crate::db::DbConnection, cid: i32) -> Result<f64, DbError> {
|
||||
conn.prepare("fr", "SELECT COALESCE(reputation, 50)::float8 AS r FROM falukant_data.character WHERE id = $1")?;
|
||||
let rows = conn.execute("fr", &[&cid])?;
|
||||
Ok(rows
|
||||
.first()
|
||||
.and_then(|r| r.get("r"))
|
||||
.and_then(|v| v.parse::<f64>().ok())
|
||||
.unwrap_or(50.0))
|
||||
}
|
||||
|
||||
fn marriage_id_for_character(
|
||||
conn: &mut crate::db::DbConnection,
|
||||
cid: i32,
|
||||
) -> Result<Option<i32>, DbError> {
|
||||
conn.prepare(
|
||||
"mid",
|
||||
r#"SELECT r.id FROM falukant_data.relationship r
|
||||
JOIN falukant_type.relationship rt ON rt.id = r.relationship_type_id
|
||||
AND rt.tr IN ('married', 'engaged', 'wooing')
|
||||
WHERE r.character1_id = $1 OR r.character2_id = $1 LIMIT 1"#,
|
||||
)?;
|
||||
let rows = conn.execute("mid", &[&cid])?;
|
||||
Ok(rows
|
||||
.first()
|
||||
.and_then(|r| r.get("id"))
|
||||
.and_then(|v| v.parse::<i32>().ok()))
|
||||
}
|
||||
|
||||
impl Worker for FalukantFamilyWorker {
|
||||
fn start_worker_thread(&mut self) {
|
||||
let pool = self.base.pool.clone();
|
||||
let broker = self.base.broker.clone();
|
||||
|
||||
self.base
|
||||
.start_worker_with_loop(move |state: Arc<WorkerState>| {
|
||||
let mut worker = FalukantFamilyWorker::new(pool.clone(), broker.clone());
|
||||
while state.running_worker.load(Ordering::Relaxed) {
|
||||
worker.run_iteration(&state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn stop_worker_thread(&mut self) {
|
||||
self.base.stop_worker();
|
||||
}
|
||||
|
||||
fn enable_watchdog(&mut self) {
|
||||
self.base.start_watchdog();
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ mod user_character;
|
||||
mod transport;
|
||||
mod weather;
|
||||
mod events;
|
||||
mod falukant_family;
|
||||
mod sql;
|
||||
|
||||
pub use base::Worker;
|
||||
@@ -27,4 +28,5 @@ pub use user_character::UserCharacterWorker;
|
||||
pub use transport::TransportWorker;
|
||||
pub use weather::WeatherWorker;
|
||||
pub use events::EventsWorker;
|
||||
pub use falukant_family::FalukantFamilyWorker;
|
||||
|
||||
|
||||
@@ -1677,7 +1677,10 @@ pub const QUERY_SET_MARRIAGES_BY_PARTY: &str = r#"
|
||||
SELECT id
|
||||
FROM falukant_type.relationship AS rt
|
||||
WHERE rt.tr = 'married'
|
||||
)
|
||||
),
|
||||
marriage_satisfaction = 55,
|
||||
marriage_drift_high = 0,
|
||||
marriage_drift_low = 0
|
||||
WHERE rel.id IN (
|
||||
SELECT rel2.id
|
||||
FROM falukant_data.party AS p
|
||||
@@ -2005,3 +2008,266 @@ pub const QUERY_GET_CHARACTERS_FOR_CHURCH_OFFICE: &str = r#"
|
||||
LIMIT $2;
|
||||
"#;
|
||||
|
||||
// --- Falukant: Familie / Liebhaber / Ehezufriedenheit (siehe migrations/001_falukant_family_lovers.sql) ---
|
||||
|
||||
pub const QUERY_FAMILY_SCHEMA_READY: &str = r#"
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'falukant_data'
|
||||
AND table_name = 'relationship_state'
|
||||
AND column_name = 'last_daily_processed_at'
|
||||
) AS ready;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_ACTIVE_LOVER_ROWS_FOR_DAILY: &str = r#"
|
||||
SELECT
|
||||
r.id AS rel_id,
|
||||
r.character1_id AS c1,
|
||||
r.character2_id AS c2,
|
||||
rs.lover_role,
|
||||
rs.affection,
|
||||
rs.visibility,
|
||||
rs.discretion,
|
||||
rs.maintenance_level,
|
||||
rs.status_fit,
|
||||
rs.monthly_base_cost,
|
||||
rs.scandal_extra_daily_pct,
|
||||
rs.months_underfunded,
|
||||
c1.gender AS g1,
|
||||
c2.gender AS g2,
|
||||
COALESCE(t1.tr, '') AS title1_tr,
|
||||
COALESCE(t2.tr, '') AS title2_tr,
|
||||
COALESCE(c1.reputation, 50)::float8 AS rep1,
|
||||
COALESCE(c2.reputation, 50)::float8 AS rep2,
|
||||
fu1.id AS user1_id,
|
||||
fu2.id AS user2_id
|
||||
FROM falukant_data.relationship r
|
||||
JOIN falukant_type.relationship rt
|
||||
ON rt.id = r.relationship_type_id AND rt.tr = 'lover'
|
||||
JOIN falukant_data.relationship_state rs ON rs.relationship_id = r.id
|
||||
JOIN falukant_data.character c1 ON c1.id = r.character1_id
|
||||
JOIN falukant_data.character c2 ON c2.id = r.character2_id
|
||||
LEFT JOIN falukant_type.title t1 ON t1.id = c1.title_of_nobility
|
||||
LEFT JOIN falukant_type.title t2 ON t2.id = c2.title_of_nobility
|
||||
LEFT JOIN falukant_data.falukant_user fu1 ON fu1.id = c1.user_id
|
||||
LEFT JOIN falukant_data.falukant_user fu2 ON fu2.id = c2.user_id
|
||||
WHERE rs.active = true
|
||||
AND (
|
||||
rs.last_daily_processed_at IS NULL
|
||||
OR (rs.last_daily_processed_at::date < CURRENT_DATE)
|
||||
);
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_ACTIVE_LOVER_ROWS_FOR_MONTHLY: &str = r#"
|
||||
SELECT
|
||||
r.id AS rel_id,
|
||||
r.character1_id AS c1,
|
||||
r.character2_id AS c2,
|
||||
rs.lover_role,
|
||||
rs.affection,
|
||||
rs.visibility,
|
||||
rs.discretion,
|
||||
rs.maintenance_level,
|
||||
rs.status_fit,
|
||||
rs.monthly_base_cost,
|
||||
rs.scandal_extra_daily_pct,
|
||||
rs.months_underfunded,
|
||||
c1.gender AS g1,
|
||||
c2.gender AS g2,
|
||||
COALESCE(t1.tr, '') AS title1_tr,
|
||||
COALESCE(t2.tr, '') AS title2_tr,
|
||||
COALESCE(c1.reputation, 50)::float8 AS rep1,
|
||||
COALESCE(c2.reputation, 50)::float8 AS rep2,
|
||||
fu1.id AS user1_id,
|
||||
fu2.id AS user2_id
|
||||
FROM falukant_data.relationship r
|
||||
JOIN falukant_type.relationship rt
|
||||
ON rt.id = r.relationship_type_id AND rt.tr = 'lover'
|
||||
JOIN falukant_data.relationship_state rs ON rs.relationship_id = r.id
|
||||
JOIN falukant_data.character c1 ON c1.id = r.character1_id
|
||||
JOIN falukant_data.character c2 ON c2.id = r.character2_id
|
||||
LEFT JOIN falukant_type.title t1 ON t1.id = c1.title_of_nobility
|
||||
LEFT JOIN falukant_type.title t2 ON t2.id = c2.title_of_nobility
|
||||
LEFT JOIN falukant_data.falukant_user fu1 ON fu1.id = c1.user_id
|
||||
LEFT JOIN falukant_data.falukant_user fu2 ON fu2.id = c2.user_id
|
||||
WHERE rs.active = true
|
||||
AND (
|
||||
rs.last_monthly_processed_at IS NULL
|
||||
OR date_trunc('month', rs.last_monthly_processed_at) < date_trunc('month', CURRENT_TIMESTAMP)
|
||||
);
|
||||
"#;
|
||||
|
||||
pub const QUERY_UPDATE_LOVER_VISIBILITY_DISCRETION: &str = r#"
|
||||
UPDATE falukant_data.relationship_state
|
||||
SET visibility = $1::smallint,
|
||||
discretion = $2::smallint
|
||||
WHERE relationship_id = $3::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_UPDATE_LOVER_UNDERPAY_STATE: &str = r#"
|
||||
UPDATE falukant_data.relationship_state
|
||||
SET affection = $1::smallint,
|
||||
discretion = $2::smallint,
|
||||
visibility = $3::smallint,
|
||||
months_underfunded = $4::smallint,
|
||||
scandal_extra_daily_pct = $5::smallint
|
||||
WHERE relationship_id = $6::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_MARRIAGE_ROWS: &str = r#"
|
||||
SELECT
|
||||
r.id AS marriage_id,
|
||||
r.character1_id AS m1,
|
||||
r.character2_id AS m2,
|
||||
r.marriage_satisfaction,
|
||||
r.marriage_drift_high,
|
||||
r.marriage_drift_low,
|
||||
COALESCE(t1.tr, '') AS title1_tr,
|
||||
COALESCE(t2.tr, '') AS title2_tr
|
||||
FROM falukant_data.relationship r
|
||||
JOIN falukant_type.relationship rt ON rt.id = r.relationship_type_id
|
||||
AND rt.tr IN ('married', 'engaged', 'wooing')
|
||||
JOIN falukant_data.character c1 ON c1.id = r.character1_id
|
||||
JOIN falukant_data.character c2 ON c2.id = r.character2_id
|
||||
LEFT JOIN falukant_type.title t1 ON t1.id = c1.title_of_nobility
|
||||
LEFT JOIN falukant_type.title t2 ON t2.id = c2.title_of_nobility;
|
||||
"#;
|
||||
|
||||
pub const QUERY_UPDATE_MARRIAGE_STATE: &str = r#"
|
||||
UPDATE falukant_data.relationship
|
||||
SET marriage_satisfaction = $1::smallint,
|
||||
marriage_drift_high = $2::smallint,
|
||||
marriage_drift_low = $3::smallint
|
||||
WHERE id = $4::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_MARRIAGE_SUBTRACT_SATISFACTION: &str = r#"
|
||||
UPDATE falukant_data.relationship r
|
||||
SET marriage_satisfaction = GREATEST(0, r.marriage_satisfaction - $2::int)
|
||||
FROM falukant_type.relationship rt
|
||||
WHERE rt.id = r.relationship_type_id
|
||||
AND rt.tr IN ('married', 'engaged', 'wooing')
|
||||
AND r.id = $1::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_RESET_LOVER_UNDERPAY_COUNTERS: &str = r#"
|
||||
UPDATE falukant_data.relationship_state
|
||||
SET months_underfunded = 0
|
||||
WHERE relationship_id = $1::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_MARK_LOVER_DAILY_DONE: &str = r#"
|
||||
UPDATE falukant_data.relationship_state
|
||||
SET last_daily_processed_at = NOW()
|
||||
WHERE relationship_id = $1::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_MARK_LOVER_MONTHLY_DONE: &str = r#"
|
||||
UPDATE falukant_data.relationship_state
|
||||
SET last_monthly_processed_at = NOW()
|
||||
WHERE relationship_id = $1::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_UPDATE_CHARACTER_REPUTATION: &str = r#"
|
||||
UPDATE falukant_data.character
|
||||
SET reputation = $1::numeric,
|
||||
updated_at = NOW()
|
||||
WHERE id = $2::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_GET_LOVER_PREGNANCY_CANDIDATES: &str = r#"
|
||||
SELECT
|
||||
CASE WHEN c1.gender = 'male' THEN c1.id ELSE c2.id END AS father_cid,
|
||||
CASE WHEN c1.gender = 'female' THEN c1.id ELSE c2.id END AS mother_cid,
|
||||
CASE WHEN c1.gender = 'male' THEN c1.title_of_nobility ELSE c2.title_of_nobility END AS title_of_nobility,
|
||||
CASE WHEN c1.gender = 'male' THEN c1.last_name ELSE c2.last_name END AS last_name,
|
||||
CASE WHEN c1.gender = 'male' THEN c1.region_id ELSE c2.region_id END AS region_id,
|
||||
CASE WHEN c1.gender = 'male' THEN fu1.id ELSE fu2.id END AS father_uid,
|
||||
CASE WHEN c1.gender = 'female' THEN fu1.id ELSE fu2.id END AS mother_uid,
|
||||
(CURRENT_DATE - c_female.birthdate::date)::int AS mother_age_days
|
||||
FROM falukant_data.relationship r
|
||||
JOIN falukant_type.relationship rt ON rt.id = r.relationship_type_id AND rt.tr = 'lover'
|
||||
JOIN falukant_data.relationship_state rs ON rs.relationship_id = r.id AND rs.active = true
|
||||
JOIN falukant_data.character c1 ON c1.id = r.character1_id
|
||||
JOIN falukant_data.character c2 ON c2.id = r.character2_id
|
||||
JOIN falukant_data.character c_female ON c_female.id = (
|
||||
CASE WHEN c1.gender = 'female' THEN c1.id ELSE c2.id END
|
||||
)
|
||||
LEFT JOIN falukant_data.falukant_user fu1 ON fu1.id = c1.user_id
|
||||
LEFT JOIN falukant_data.falukant_user fu2 ON fu2.id = c2.user_id
|
||||
WHERE (c1.gender = 'female' AND c2.gender = 'male')
|
||||
OR (c1.gender = 'male' AND c2.gender = 'female')
|
||||
AND rs.affection >= 45
|
||||
AND rs.maintenance_level >= 30
|
||||
AND rs.last_monthly_processed_at IS NOT NULL
|
||||
AND date_trunc('month', rs.last_monthly_processed_at) = date_trunc('month', CURRENT_TIMESTAMP)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM falukant_data.child_relation cr
|
||||
WHERE cr.father_character_id = (CASE WHEN c1.gender = 'male' THEN c1.id ELSE c2.id END)
|
||||
AND cr.mother_character_id = (CASE WHEN c1.gender = 'female' THEN c1.id ELSE c2.id END)
|
||||
AND cr.created_at >= date_trunc('month', CURRENT_TIMESTAMP)
|
||||
)
|
||||
AND (CURRENT_DATE - c_female.birthdate::date) >= 4380
|
||||
AND (CURRENT_DATE - c_female.birthdate::date) < 18993
|
||||
AND random() * 100.0 < (
|
||||
LEAST(12.0, GREATEST(0.0,
|
||||
CASE rs.lover_role
|
||||
WHEN 'secret_affair' THEN 2.0
|
||||
WHEN 'lover' THEN 4.0
|
||||
WHEN 'mistress_or_favorite' THEN 6.0
|
||||
ELSE 0.0
|
||||
END
|
||||
+ CASE WHEN rs.affection >= 75 THEN 2.0 ELSE 0.0 END
|
||||
+ CASE WHEN rs.visibility >= 70 AND rs.affection < 50 THEN -2.0 ELSE 0.0 END
|
||||
+ CASE
|
||||
WHEN (CURRENT_DATE - c_female.birthdate::date) > 14600
|
||||
THEN -3.0
|
||||
ELSE 0.0
|
||||
END
|
||||
))
|
||||
);
|
||||
"#;
|
||||
|
||||
pub const QUERY_LOVER_BIRTH_PENALTY_MARRIAGE: &str = r#"
|
||||
UPDATE falukant_data.relationship r
|
||||
SET marriage_satisfaction = GREATEST(0, r.marriage_satisfaction - 8)
|
||||
FROM falukant_type.relationship rt
|
||||
WHERE rt.id = r.relationship_type_id
|
||||
AND rt.tr IN ('married', 'engaged', 'wooing')
|
||||
AND (r.character1_id = $1::int OR r.character2_id = $1::int);
|
||||
"#;
|
||||
|
||||
pub const QUERY_LOVER_BIRTH_PENALTY_REPUTATION: &str = r#"
|
||||
UPDATE falukant_data.character
|
||||
SET reputation = GREATEST(0::numeric, COALESCE(reputation, 50::numeric) - 4::numeric),
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::int;
|
||||
"#;
|
||||
|
||||
pub const QUERY_INSERT_CHILD_RELATION_LOVER: &str = r#"
|
||||
INSERT INTO falukant_data.child_relation (
|
||||
father_character_id,
|
||||
mother_character_id,
|
||||
child_character_id,
|
||||
name_set,
|
||||
legitimacy,
|
||||
birth_context,
|
||||
public_known,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (
|
||||
$1::int,
|
||||
$2::int,
|
||||
$3::int,
|
||||
FALSE,
|
||||
'hidden_bastard',
|
||||
'lover',
|
||||
FALSE,
|
||||
NOW(),
|
||||
NOW()
|
||||
);
|
||||
"#;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user