From 8eec7b75ff9c8c368b252373db45fb891732d2ca Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 1 Jul 2026 19:41:34 -0400 Subject: mob combat stats overhauled and standardized --- internal/world/mob.go | 263 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 179 insertions(+), 84 deletions(-) (limited to 'internal/world') diff --git a/internal/world/mob.go b/internal/world/mob.go index 58bf769..19ec935 100644 --- a/internal/world/mob.go +++ b/internal/world/mob.go @@ -17,55 +17,75 @@ type MobDropTable struct { Loot []behavior.DropEntry `yaml:"loot"` } +type MobSteal struct { + Table string `yaml:"table"` + Level int `yaml:"level"` + XP int `yaml:"xp"` + Speed float64 `yaml:"speed"` +} + +type MobTask struct { + Verb string `yaml:"verb"` + ProgressNoun string `yaml:"progress_noun"` + CompleteMessage string `yaml:"complete_message"` +} + +type MobCombatBonuses struct { + AttackBonus int `yaml:"attack_bonus"` + StrengthBonus int `yaml:"strength_bonus"` + ScienceBonus int `yaml:"science_bonus"` + SciencePercentBonus int `yaml:"science_percent_bonus"` + RangedBonus int `yaml:"ranged_bonus"` + RangedStrengthBonus int `yaml:"ranged_strength_bonus"` +} + +type MobCombatDefenses struct { + StabDefense int `yaml:"stab_defense"` + SlashDefense int `yaml:"slash_defense"` + CrushDefense int `yaml:"crush_defense"` + ScienceDefense int `yaml:"science_defense"` + RangedDefense int `yaml:"ranged_defense"` + Weakness string `yaml:"weakness"` +} + +type MobCombatStats struct { + HP int `yaml:"hp"` + Attack int `yaml:"attack"` + Strength int `yaml:"strength"` + Defense int `yaml:"defense"` + Ranged int `yaml:"ranged"` + Science int `yaml:"science"` + AttackType string `yaml:"attack_type"` + Speed float64 `yaml:"speed"` + Aggressive bool `yaml:"aggressive"` + RespawnTicks float64 `yaml:"respawn_ticks"` + Bonuses MobCombatBonuses `yaml:"bonuses"` + Defenses MobCombatDefenses `yaml:"defenses"` +} + +type MobCombat struct { + Kind string `yaml:"kind"` + Stats MobCombatStats `yaml:"stats"` + AssassinLevel int `yaml:"assassin_level"` + FinishingBlow string `yaml:"finishing_blow"` + DamageWithout string `yaml:"damage_without"` + Size string `yaml:"size"` + CombatDescriptions []string `yaml:"combat_descriptions"` +} + type MobDef struct { - ID string `yaml:"id"` - Name string `yaml:"name"` - Description string `yaml:"description"` - IdleDescriptions []string `yaml:"idle_descriptions"` - CombatDescriptions []string `yaml:"combat_descriptions"` - Attack int `yaml:"attack"` - Strength int `yaml:"strength"` - Defense int `yaml:"defense"` - HP int `yaml:"hp"` - Ranged int `yaml:"ranged"` - Science int `yaml:"science"` - Speed float64 `yaml:"speed"` - Aggressive bool `yaml:"aggressive"` - Protected bool `yaml:"protected"` - Unique bool `yaml:"unique"` - RespawnTicks float64 `yaml:"respawn_ticks"` - Drops MobDropTable `yaml:"drops"` - - AttackBonus int `yaml:"attack_bonus"` - StrengthBonus int `yaml:"strength_bonus"` - AttackType string `yaml:"attack_type"` - - StabDefense int `yaml:"stab_defense"` - SlashDefense int `yaml:"slash_defense"` - CrushDefense int `yaml:"crush_defense"` - ScienceDefense int `yaml:"science_defense"` - RangedDefense int `yaml:"ranged_defense"` - - Weakness string `yaml:"weakness"` - StealTable string `yaml:"steal_table"` - StealLevel int `yaml:"steal_level"` - StealXP int `yaml:"steal_xp"` - StealSpeed float64 `yaml:"steal_speed"` - - AssassinLevel int `yaml:"assassin_level"` - FinishingBlow string `yaml:"finishing_blow"` - DamageWithout string `yaml:"damage_without"` - Size string `yaml:"size"` - - // Kind discriminates a normal combat mob ("" or "combat") from a "task" - // worksite (build a solar panel, survey a rock, etc.). A task mob reuses the - // entire combat engine but its HP drains to 0 to COMPLETE the work; it never - // attacks back (the room hazard, if any, supplies the danger). The progress - // bar is displayed inverted (filling toward 100%). - Kind string `yaml:"kind"` - Verb string `yaml:"verb"` // flavor verb for messages (default "work") - ProgressNoun string `yaml:"progress_noun"` // flavor noun, e.g. "construction" - CompleteMessage string `yaml:"complete_message"` // shown on completion + ID string `yaml:"id"` + Name string `yaml:"name"` + Description string `yaml:"description"` + IdleDescriptions []string `yaml:"idle_descriptions"` + Protected bool `yaml:"protected"` + Unique bool `yaml:"unique"` + Drops MobDropTable `yaml:"drops"` + + Steal *MobSteal `yaml:"steal,omitempty"` + Task *MobTask `yaml:"task,omitempty"` + + Combat *MobCombat `yaml:"combat,omitempty"` Talk *behavior.TalkConfig `yaml:"talk,omitempty"` Shop *behavior.ShopConfig `yaml:"shop,omitempty"` @@ -75,7 +95,7 @@ func (d *MobDef) IsTalkable() bool { return d.Talk != nil } func (d *MobDef) HasShop() bool { return d.Shop != nil } -func (d *MobDef) IsTask() bool { return d.Kind == "task" } +func (d *MobDef) IsTask() bool { return d.Combat != nil && d.Combat.Kind == "task" } type MobInstance struct { InstanceID string @@ -97,11 +117,12 @@ type MobInstance struct { RoomID int HomeRoomID int Drops MobDropTable - IdleDescription string - WanderRooms []int - WanderInterval float64 - WanderTickCounter int - regenerateTick int + IdleDescription string + CombatDescriptions []string + WanderRooms []int + WanderInterval float64 + WanderTickCounter int + regenerateTick int AttackBonus int StrengthBonus int @@ -154,7 +175,80 @@ func (m *MobInstance) HasShop() bool { return m.Shop != nil } func (m *MobInstance) IsTask() bool { return m.Kind == "task" } func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []int, wanderInterval float64) *MobInstance { - hp := def.HP + hp := 0 + attack := 0 + strength := 0 + defense := 0 + ranged := 0 + science := 0 + speed := 0.0 + aggressive := false + respawnTicks := 0.0 + attackBonus := 0 + strengthBonus := 0 + attackType := "" + stabDef := 0 + slashDef := 0 + crushDef := 0 + scienceDef := 0 + rangedDef := 0 + weakness := "" + assassinLevel := 0 + finishingBlow := "" + damageWithout := "" + size := "" + kind := "" + verb := "" + progressNoun := "" + completeMessage := "" + var combatDescriptions []string + stealTable := "" + stealLevel := 0 + stealXP := 0 + stealSpeed := 0.0 + + if def.Combat != nil { + cs := def.Combat.Stats + hp = cs.HP + attack = cs.Attack + strength = cs.Strength + defense = cs.Defense + ranged = cs.Ranged + science = cs.Science + speed = cs.Speed + aggressive = cs.Aggressive + respawnTicks = cs.RespawnTicks + attackBonus = cs.Bonuses.AttackBonus + strengthBonus = cs.Bonuses.StrengthBonus + attackType = cs.AttackType + stabDef = cs.Defenses.StabDefense + slashDef = cs.Defenses.SlashDefense + crushDef = cs.Defenses.CrushDefense + scienceDef = cs.Defenses.ScienceDefense + rangedDef = cs.Defenses.RangedDefense + weakness = cs.Defenses.Weakness + + assassinLevel = def.Combat.AssassinLevel + finishingBlow = def.Combat.FinishingBlow + damageWithout = def.Combat.DamageWithout + size = def.Combat.Size + kind = def.Combat.Kind + combatDescriptions = def.Combat.CombatDescriptions + } + + if def.Steal != nil { + stealTable = def.Steal.Table + stealLevel = def.Steal.Level + stealXP = def.Steal.XP + stealSpeed = def.Steal.Speed + } + + if def.Task != nil { + verb = def.Task.Verb + progressNoun = def.Task.ProgressNoun + completeMessage = def.Task.CompleteMessage + } + if def.Protected && hp <= 0 { hp = 1 } @@ -165,42 +259,43 @@ func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []in Description: def.Description, HP: hp, MaxHP: hp, - Attack: def.Attack, - Strength: def.Strength, - Defense: def.Defense, - Ranged: def.Ranged, - Science: def.Science, - Speed: def.Speed, - Aggressive: def.Aggressive, + Attack: attack, + Strength: strength, + Defense: defense, + Ranged: ranged, + Science: science, + Speed: speed, + Aggressive: aggressive, Protected: def.Protected, Unique: def.Unique, - RespawnTicks: def.RespawnTicks, + RespawnTicks: respawnTicks, RoomID: roomID, HomeRoomID: roomID, WanderRooms: wanderRooms, WanderInterval: wanderInterval, Drops: def.Drops, - AttackBonus: def.AttackBonus, - StrengthBonus: def.StrengthBonus, - AttackType: def.AttackType, - StabDefense: def.StabDefense, - SlashDefense: def.SlashDefense, - CrushDefense: def.CrushDefense, - ScienceDefense: def.ScienceDefense, - RangedDefense: def.RangedDefense, - Weakness: def.Weakness, - StealTable: def.StealTable, - StealLevel: def.StealLevel, - StealXP: def.StealXP, - StealSpeed: def.StealSpeed, - AssassinLevel: def.AssassinLevel, - FinishingBlow: def.FinishingBlow, - DamageWithout: def.DamageWithout, - Size: def.Size, - Kind: def.Kind, - Verb: def.Verb, - ProgressNoun: def.ProgressNoun, - CompleteMessage: def.CompleteMessage, + AttackBonus: attackBonus, + StrengthBonus: strengthBonus, + AttackType: attackType, + StabDefense: stabDef, + SlashDefense: slashDef, + CrushDefense: crushDef, + ScienceDefense: scienceDef, + RangedDefense: rangedDef, + Weakness: weakness, + StealTable: stealTable, + StealLevel: stealLevel, + StealXP: stealXP, + StealSpeed: stealSpeed, + AssassinLevel: assassinLevel, + FinishingBlow: finishingBlow, + DamageWithout: damageWithout, + Size: size, + Kind: kind, + Verb: verb, + ProgressNoun: progressNoun, + CompleteMessage: completeMessage, + CombatDescriptions: combatDescriptions, TalkConfig: def.Talk, } if def.Shop != nil { -- cgit v1.2.3