From 52a3ce6a4b4a254dc5d3067979a09e93c060fa20 Mon Sep 17 00:00:00 2001 From: workhorse Date: Fri, 19 Jun 2026 03:57:06 -0400 Subject: feat: shops and rough assassin skill --- internal/game/cmd_attack.go | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'internal/game/cmd_attack.go') diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go index 29bff30..a8dc5d3 100644 --- a/internal/game/cmd_attack.go +++ b/internal/game/cmd_attack.go @@ -41,6 +41,11 @@ func (g *Game) doAttack(sess *net.Session, input string) { return } + if mob.AssassinLevel > 0 && p.Level(player.Assassin) < mob.AssassinLevel { + sess.WriteLine(fmt.Sprintf("You need Assassin level %d to attack %s.", mob.AssassinLevel, mobDisplayName(mob, true))) + return + } + if combat.IsMobInCombat(mob.InstanceID) { sess.WriteLine(fmt.Sprintf("%s is already engaged in combat!", mobDisplayName(mob, false))) return @@ -268,9 +273,23 @@ func (g *Game) playerAttack(sess *net.Session, p *player.Player, mob *world.MobI if mob.HP < 0 { mob.HP = 0 } + if mob.FinishingBlow != "" && mob.HP <= 0 { + mob.HP = 1 + } if mob.HP < mob.MaxHP && mob.HP > 0 { mob.StartRegen() } + + if mob.FinishingBlow != "" && mob.HP == 1 { + fbDef, _ := g.ItemStore.Load(mob.FinishingBlow) + fbName := mob.FinishingBlow + if fbDef != nil { + fbName = fbDef.Name + } + sess.WriteLine(g.colorize(sess, "warning", + fmt.Sprintf(" %s resists death! Use %s on it to finish it off.", + mobDisplayName(mob, false), fbName))) + } gains, leveled := g.awardCombatXP(p, dmg, isRanged) if isRanged { @@ -329,6 +348,7 @@ func (g *Game) playerAttack(sess *net.Session, p *player.Player, mob *world.MobI } func (g *Game) mobAttack(sess *net.Session, p *player.Player, mob *world.MobInstance) { + cs := combat.GetCombat(p.Name) _, _, defStyleBonus := combat.AttackStyleBonus(string(p.AttackStyle)) mobAttackType := mob.AttackType @@ -349,6 +369,37 @@ func (g *Game) mobAttack(sess *net.Session, p *player.Player, mob *world.MobInst dmg := combat.RollDamage(maxHit) dmg = g.applyTechProtection(p, mob, dmg) + if mob.DamageWithout != "" { + hasProtection := false + for _, itemID := range p.Equipment { + if itemID == mob.DamageWithout { + hasProtection = true + break + } + } + if !hasProtection { + dmg = dmg * 3 / 2 + if dmg < 1 { + dmg = 1 + } + if cs != nil && !cs.DamageWarningShown { + cs.DamageWarningShown = true + fbDef, _ := g.ItemStore.Load(mob.DamageWithout) + fbName := mob.DamageWithout + if fbDef != nil { + fbName = fbDef.Name + } + attacker := mob.Name + if !mob.Unique { + attacker = "The " + mob.Name + } + sess.WriteLine(g.colorize(sess, "warning", + fmt.Sprintf(" %s's attack is extra effective! Equip %s for protection.", + attacker, fbName))) + } + } + } + p.HP -= dmg if p.HP < 0 { p.HP = 0 @@ -421,6 +472,9 @@ func (g *Game) endCombat(sess *net.Session, p *player.Player, mob *world.MobInst if mob != nil && mob.HP <= 0 { sess.WriteLine(g.colorize(sess, "victory", fmt.Sprintf("\nYou have defeated %s!", mobDisplayName(mob, true)))) + + g.onAssassinKill(sess, p, mob) + if g.Hub != nil { for _, other := range g.Hub.PlayersInRoom(p.RoomID) { if other != sess && other.Player != nil { -- cgit v1.2.3