From c14c2e403c75a913e1a6d962fb6fe64f013adae5 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 1 Jul 2026 22:30:31 -0400 Subject: fix: combat formulas and mob attack types (mobs switch attack styles if safespotting) --- internal/world/mob.go | 268 +++++++++++++++++++++++++++++--------------------- 1 file changed, 157 insertions(+), 111 deletions(-) (limited to 'internal/world/mob.go') diff --git a/internal/world/mob.go b/internal/world/mob.go index 19ec935..05650c0 100644 --- a/internal/world/mob.go +++ b/internal/world/mob.go @@ -40,47 +40,51 @@ type MobCombatBonuses struct { } 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"` + 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"` + WeaknessPercent int `yaml:"weakness_percent"` } 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"` + HP int `yaml:"hp"` + Attack int `yaml:"attack"` + Strength int `yaml:"strength"` + Defense int `yaml:"defense"` + 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 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"` + Kind string `yaml:"kind"` + AttackTypes []string `yaml:"attack_types"` + Aggressive bool `yaml:"aggressive"` + RespawnTicks float64 `yaml:"respawn_ticks"` + 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"` - Protected bool `yaml:"protected"` - Unique bool `yaml:"unique"` - Drops MobDropTable `yaml:"drops"` + 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"` @@ -98,35 +102,39 @@ func (d *MobDef) HasShop() bool { return d.Shop != nil } func (d *MobDef) IsTask() bool { return d.Combat != nil && d.Combat.Kind == "task" } type MobInstance struct { - InstanceID string - DefID string - Name string - Description string - HP int - MaxHP int - Attack int - Strength int - Defense int - Ranged int - Science int - Speed float64 - Aggressive bool - Protected bool - Unique bool - RespawnTicks float64 - RoomID int - HomeRoomID int - Drops MobDropTable - IdleDescription string - CombatDescriptions []string - WanderRooms []int - WanderInterval float64 - WanderTickCounter int - regenerateTick int + InstanceID string + DefID string + Name string + Description string + HP int + MaxHP int + Attack int + Strength int + Defense int + Ranged int + Science int + Speed float64 + Aggressive bool + Protected bool + Unique bool + RespawnTicks float64 + RoomID int + HomeRoomID int + Drops MobDropTable + IdleDescription string + CombatDescriptions []string + WanderRooms []int + WanderInterval float64 + WanderTickCounter int + regenerateTick int AttackBonus int StrengthBonus int - AttackType string + AttackTypes []string + + RangedBonus int + ScienceBonus int + SciencePercentBonus int StabDefense int SlashDefense int @@ -134,11 +142,16 @@ type MobInstance struct { ScienceDefense int RangedDefense int - Weakness string - StealTable string - StealLevel int - StealXP int - StealSpeed float64 + Weakness string + WeaknessPercent int + + MaxMeleeHit int + MaxRangedHit int + MaxScienceHit int + StealTable string + StealLevel int + StealXP int + StealSpeed float64 AssassinLevel int FinishingBlow string @@ -186,13 +199,20 @@ func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []in respawnTicks := 0.0 attackBonus := 0 strengthBonus := 0 - attackType := "" + rangedBonus := 0 + scienceBonus := 0 + sciencePercentBonus := 0 + var attackType []string stabDef := 0 slashDef := 0 crushDef := 0 scienceDef := 0 rangedDef := 0 weakness := "" + weaknessPercent := 0 + maxMeleeHit := 0 + maxRangedHit := 0 + maxScienceHit := 0 assassinLevel := 0 finishingBlow := "" damageWithout := "" @@ -208,6 +228,10 @@ func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []in stealSpeed := 0.0 if def.Combat != nil { + aggressive = def.Combat.Aggressive + respawnTicks = def.Combat.RespawnTicks + attackType = append([]string(nil), def.Combat.AttackTypes...) + cs := def.Combat.Stats hp = cs.HP attack = cs.Attack @@ -216,17 +240,21 @@ func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []in 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 + rangedBonus = cs.Bonuses.RangedBonus + scienceBonus = cs.Bonuses.ScienceBonus + sciencePercentBonus = cs.Bonuses.SciencePercentBonus stabDef = cs.Defenses.StabDefense slashDef = cs.Defenses.SlashDefense crushDef = cs.Defenses.CrushDefense scienceDef = cs.Defenses.ScienceDefense rangedDef = cs.Defenses.RangedDefense weakness = cs.Defenses.Weakness + weaknessPercent = cs.Defenses.WeaknessPercent + maxMeleeHit = cs.MaxMeleeHit + maxRangedHit = cs.MaxRangedHit + maxScienceHit = cs.MaxScienceHit assassinLevel = def.Combat.AssassinLevel finishingBlow = def.Combat.FinishingBlow @@ -253,50 +281,57 @@ func NewMobInstance(def *MobDef, instanceID string, roomID int, wanderRooms []in hp = 1 } inst := &MobInstance{ - InstanceID: instanceID, - DefID: def.ID, - Name: def.Name, - Description: def.Description, - HP: hp, - MaxHP: hp, - Attack: attack, - Strength: strength, - Defense: defense, - Ranged: ranged, - Science: science, - Speed: speed, - Aggressive: aggressive, - Protected: def.Protected, - Unique: def.Unique, - RespawnTicks: respawnTicks, - RoomID: roomID, - HomeRoomID: roomID, - WanderRooms: wanderRooms, - WanderInterval: wanderInterval, - Drops: def.Drops, - 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, + InstanceID: instanceID, + DefID: def.ID, + Name: def.Name, + Description: def.Description, + HP: hp, + MaxHP: hp, + Attack: attack, + Strength: strength, + Defense: defense, + Ranged: ranged, + Science: science, + Speed: speed, + Aggressive: aggressive, + Protected: def.Protected, + Unique: def.Unique, + RespawnTicks: respawnTicks, + RoomID: roomID, + HomeRoomID: roomID, + WanderRooms: wanderRooms, + WanderInterval: wanderInterval, + Drops: def.Drops, + AttackBonus: attackBonus, + StrengthBonus: strengthBonus, + AttackTypes: attackType, + RangedBonus: rangedBonus, + ScienceBonus: scienceBonus, + SciencePercentBonus: sciencePercentBonus, + StabDefense: stabDef, + SlashDefense: slashDef, + CrushDefense: crushDef, + ScienceDefense: scienceDef, + RangedDefense: rangedDef, + Weakness: weakness, + WeaknessPercent: weaknessPercent, + MaxMeleeHit: maxMeleeHit, + MaxRangedHit: maxRangedHit, + MaxScienceHit: maxScienceHit, + 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 { inst.Shop = def.Shop @@ -434,6 +469,17 @@ func (s *MobStore) AllInstances() []*MobInstance { return out } +// SetInstanceRoom updates a mob instance's room under the store lock, so it is +// safe against concurrent readers (MobsInRoom, RemoveMobsInRoom) in other +// goroutines. +func (s *MobStore) SetInstanceRoom(instanceID string, roomID int) { + s.mu.Lock() + defer s.mu.Unlock() + if inst := s.instances[instanceID]; inst != nil { + inst.RoomID = roomID + } +} + func (s *MobStore) MobsInRoom(roomID int) []*MobInstance { s.mu.Lock() defer s.mu.Unlock() -- cgit v1.2.3