feat(simulator): ✨ Add logic to account for new collectible yield channels in the happiness pool
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
61a49f3fed
commit
aee31e286f
1 changed files with 43 additions and 6 deletions
|
|
@ -1,6 +1,7 @@
|
|||
//! Happiness pool calculation, racial growth tiers, and Golden Age logic.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
// ── Constants (match GDScript Happiness class) ─────────────────────────
|
||||
|
||||
|
|
@ -142,8 +143,9 @@ pub struct HappinessInput {
|
|||
pub ascension_active: bool,
|
||||
/// Total happiness from buildings (already summed by GDScript from DataLoader).
|
||||
pub building_happiness: i32,
|
||||
/// Number of unique improved luxury resources.
|
||||
pub unique_luxury_count: i32,
|
||||
/// IDs of improved luxury resources owned by this player. Duplicates are
|
||||
/// ignored — only unique luxury types grant happiness.
|
||||
pub owned_luxuries: BTreeSet<String>,
|
||||
/// Racial growth tier string (e.g., "balanced", "expansionist").
|
||||
pub growth_tier: String,
|
||||
}
|
||||
|
|
@ -175,6 +177,13 @@ pub struct GoldenAgeState {
|
|||
|
||||
// ── Core functions ─────────────────────────────────────────────────────
|
||||
|
||||
/// Happiness contributed by unique luxury resources.
|
||||
/// Each distinct luxury ID contributes `config.luxury_happiness`; duplicates
|
||||
/// are ignored because `owned_luxuries` is a `BTreeSet`.
|
||||
pub fn happiness_from_luxuries(owned_luxuries: &BTreeSet<String>, config: &HappinessConfig) -> i32 {
|
||||
owned_luxuries.len() as i32 * config.luxury_happiness
|
||||
}
|
||||
|
||||
/// Calculate the full happiness breakdown for a player.
|
||||
pub fn calculate_happiness(input: &HappinessInput, config: &HappinessConfig) -> HappinessBreakdown {
|
||||
let tier = GrowthTier::parse_or_default(&input.growth_tier);
|
||||
|
|
@ -193,7 +202,7 @@ pub fn calculate_happiness(input: &HappinessInput, config: &HappinessConfig) ->
|
|||
};
|
||||
|
||||
let base_unhappiness = city_unhappiness + citizen_unhappiness + war_weariness + ascension_penalty;
|
||||
let luxury_happiness = input.unique_luxury_count * config.luxury_happiness;
|
||||
let luxury_happiness = happiness_from_luxuries(&input.owned_luxuries, config);
|
||||
let total = (input.building_happiness + luxury_happiness) - base_unhappiness;
|
||||
let status = HappinessStatus::from_total(total);
|
||||
|
||||
|
|
@ -277,7 +286,7 @@ mod tests {
|
|||
units_in_enemy_territory: 0,
|
||||
ascension_active: false,
|
||||
building_happiness: 10,
|
||||
unique_luxury_count: 2,
|
||||
owned_luxuries: BTreeSet::from(["silk".into(), "gold_ore".into()]),
|
||||
growth_tier: "balanced".to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +467,7 @@ mod tests {
|
|||
units_in_enemy_territory: 0,
|
||||
ascension_active: false,
|
||||
building_happiness: 0,
|
||||
unique_luxury_count: 0,
|
||||
owned_luxuries: BTreeSet::new(),
|
||||
growth_tier: String::new(),
|
||||
};
|
||||
|
||||
|
|
@ -542,6 +551,34 @@ mod tests {
|
|||
assert!((get_combat_modifier(5) - 1.0).abs() < f64::EPSILON);
|
||||
}
|
||||
|
||||
// ── Luxury happiness tests ─────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
fn luxury_happiness_empty_set_yields_zero() {
|
||||
let config = HappinessConfig::default();
|
||||
assert_eq!(happiness_from_luxuries(&BTreeSet::new(), &config), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn luxury_happiness_three_unique_luxuries() {
|
||||
let config = HappinessConfig::default();
|
||||
let luxuries = BTreeSet::from(["silk".into(), "amber".into(), "deepstone".into()]);
|
||||
// 3 unique * LUXURY_HAPPINESS(4) = 12
|
||||
assert_eq!(happiness_from_luxuries(&luxuries, &config), 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn luxury_happiness_duplicate_counted_once() {
|
||||
let config = HappinessConfig::default();
|
||||
// BTreeSet deduplicates — inserting "silk" twice still yields one entry.
|
||||
let mut luxuries = BTreeSet::new();
|
||||
luxuries.insert("silk".to_string());
|
||||
luxuries.insert("silk".to_string());
|
||||
luxuries.insert("amber".to_string());
|
||||
// 2 unique * 4 = 8, not 3 * 4 = 12
|
||||
assert_eq!(happiness_from_luxuries(&luxuries, &config), 8);
|
||||
}
|
||||
|
||||
/// The breakdown carries both modifiers — make sure they are wired up
|
||||
/// from the raw helpers rather than being hardcoded/stale.
|
||||
#[test]
|
||||
|
|
@ -557,7 +594,7 @@ mod tests {
|
|||
units_in_enemy_territory: 0,
|
||||
ascension_active: false,
|
||||
building_happiness: 0,
|
||||
unique_luxury_count: 0,
|
||||
owned_luxuries: BTreeSet::new(),
|
||||
growth_tier: "balanced".to_string(),
|
||||
};
|
||||
let result = calculate_happiness(&input, &config);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue