diff options
| author | historia <[not public]> | 2026-07-13 15:07:28 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-07-13 15:07:28 -0400 |
| commit | 93a412aed2b11406399504c81d6d19ed1341908a (patch) | |
| tree | d99f0c283e6684d266676438fbec4e550bf9c774 /internal/world/hazard.go | |
| parent | fcc9c0a83df82093efd3a85e8e0dc0768653ea87 (diff) | |
| download | thehouseoficarus-93a412aed2b11406399504c81d6d19ed1341908a.tar.gz | |
feat(admin): hide irrelevant combat stats for task mobs, show relevant combat stats for hazards
Diffstat (limited to 'internal/world/hazard.go')
| -rw-r--r-- | internal/world/hazard.go | 98 |
1 files changed, 76 insertions, 22 deletions
diff --git a/internal/world/hazard.go b/internal/world/hazard.go index ac2a6a6..c08c2bb 100644 --- a/internal/world/hazard.go +++ b/internal/world/hazard.go @@ -7,31 +7,85 @@ import ( "gopkg.in/yaml.v3" "thehouseoficarus/internal/behavior" + "thehouseoficarus/internal/combat" ) -// HazardDef describes an environmental threat attached to a room (a sandstorm, -// solar radiation, falling rocks, etc.). It is a shared, ID-referenced -// definition loaded from data/hazards/<id>.yaml, so one hazard can be reused -// across a whole area and resolved by name for a future `examine` command. -// -// A hazard rolls an attack against everyone in the room every Speed ticks using -// the SAME combat formulas as a mob: accuracy comes from Attack/AttackBonus, max -// hit from MaxHit, and the player defends with their Defense level + equipment -// bonus selected by AttackType (so existing armour and the Defense skill apply). -// Tech protection (Kinetic Barrier / Projectile Screen / Neural Firewall) keys -// off AttackType automatically. +type HazardCombatBonuses struct { + AttackBonus int `yaml:"attack_bonus"` + StrengthBonus int `yaml:"strength_bonus"` + RangedBonus int `yaml:"ranged_bonus"` + RangedStrengthBonus int `yaml:"ranged_strength_bonus"` + ScienceBonus int `yaml:"science_bonus"` + SciencePercentBonus int `yaml:"science_percent_bonus"` +} + +type HazardCombatStats struct { + Attack int `yaml:"attack"` + Strength int `yaml:"strength"` + Ranged int `yaml:"ranged"` + Science int `yaml:"science"` + Speed float64 `yaml:"speed"` + MaxMeleeHit int `yaml:"max_melee_hit"` + MaxRangedHit int `yaml:"max_ranged_hit"` + MaxScienceHit int `yaml:"max_science_hit"` + Bonuses HazardCombatBonuses `yaml:"bonuses"` +} + +type HazardCombat struct { + AttackTypes []string `yaml:"attack_types"` + Stats HazardCombatStats `yaml:"stats"` +} + +// HazardDef describes an environmental threat attached to a room. Its combat +// block mirrors a mob's combat block (attack_types, stats with per-type max hits +// and bonuses) but has NO defense stats — the hazard is never attacked, it only +// attacks the player. Speed is read from combat.stats.speed (default 5). type HazardDef struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - AttackType string `yaml:"attack_type"` // stab/slash/crush/ranged/science - Attack int `yaml:"attack"` - AttackBonus int `yaml:"attack_bonus"` - MaxHit int `yaml:"max_hit"` - Speed float64 `yaml:"speed"` // ticks between hazard rolls - WarnMessage string `yaml:"warn_message"` - HitMessage string `yaml:"hit_message"` // accepts a single %d for damage - MissMessage string `yaml:"miss_message"` - RequiredItem string `yaml:"required_item"` // equipped item that negates the hazard + Name string `yaml:"name"` + Description string `yaml:"description"` + Combat *HazardCombat `yaml:"combat,omitempty"` + WarnMessage string `yaml:"warn_message"` + HitMessage string `yaml:"hit_message"` // accepts a single %d for damage + MissMessage string `yaml:"miss_message"` + RequiredItem string `yaml:"required_item"` // equipped item that negates the hazard +} + +// AttackType returns the hazard's active attack type: the first melee type from +// attack_types, falling back to the first entry, defaulting to crush. +func (d *HazardDef) AttackType() string { + if d.Combat == nil || len(d.Combat.AttackTypes) == 0 { + return combat.DefaultAttackType + } + for _, t := range d.Combat.AttackTypes { + if combat.IsMeleeType(t) { + return t + } + } + return d.Combat.AttackTypes[0] +} + +// SpeedTicks returns the hazard's tick interval (default 5). +func (d *HazardDef) SpeedTicks() float64 { + if d.Combat == nil || d.Combat.Stats.Speed <= 0 { + return 5 + } + return d.Combat.Stats.Speed +} + +// EffectiveMaxScienceHit applies the hazard's science percent bonus to its max +// science hit. +func (d *HazardDef) EffectiveMaxScienceHit() int { + if d.Combat == nil { + return 0 + } + base := d.Combat.Stats.MaxScienceHit + if d.Combat.Stats.Bonuses.SciencePercentBonus > 0 { + base = int(float64(base) * (1.0 + float64(d.Combat.Stats.Bonuses.SciencePercentBonus)/100.0)) + } + if base < 1 { + base = 1 + } + return base } // LoadHazard returns the shared hazard definition for id, caching results. |
