aboutsummaryrefslogtreecommitdiff
path: root/internal/game/combat_attack.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/combat_attack.go')
-rw-r--r--internal/game/combat_attack.go79
1 files changed, 37 insertions, 42 deletions
diff --git a/internal/game/combat_attack.go b/internal/game/combat_attack.go
index ddc3b8f..6c314ff 100644
--- a/internal/game/combat_attack.go
+++ b/internal/game/combat_attack.go
@@ -8,7 +8,6 @@ import (
"strings"
"thehouseoficarus/internal/behavior"
- "thehouseoficarus/internal/color"
"thehouseoficarus/internal/combat"
"thehouseoficarus/internal/engine"
"thehouseoficarus/internal/item"
@@ -213,13 +212,13 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn
if mod != nil && g.hasJunkCost(p, mod) {
g.scienceAttack(sess, p, currentMob, mod)
} else if mod != nil {
- sess.WriteLine(g.colorize(sess, "error",
- fmt.Sprintf("You're out of junk for %s!! You flail with your fists in desperation!", mod.Name)))
+ sess.WriteLine(g.colorize(sess, "error",
+ fmt.Sprintf("You're out of junk for %s!! You flail with your fists in desperation!", mod.Name)))
g.playerAttackUnarmed(sess, p, currentMob)
} else {
p.AutotriggerMod = ""
- sess.WriteLine(g.colorize(sess, "error",
- "No autotrigger set! Set a module with the 'autotrigger' command."))
+ sess.WriteLine(g.colorize(sess, "error",
+ "No autotrigger set! Set a module with the 'autotrigger' command."))
g.playerAttackUnarmed(sess, p, currentMob)
}
} else {
@@ -289,20 +288,29 @@ func (g *Game) playerAttack(sess *net.Session, p *player.Player, mob *world.MobI
}
}
-func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.EquipmentType, attRoll int, defRoll int, maxHit int) {
- attackType = "crush"
+// resolvePlayerAttackType determines the player's attack type and main-hand
+// weapon type (and the weapon def, if any) from their equipped weapon,
+// defaulting to crush when unarmed or when the weapon specifies no type.
+func (g *Game) resolvePlayerAttackType(p *player.Player) (attackType string, weaponType item.EquipmentType, def *item.ItemDef) {
+ attackType = combat.DefaultAttackType
if itemID, ok := p.Equipment[item.SlotMainHand]; ok {
- if def, err := g.ItemStore.Load(itemID); err == nil {
- if def.AttackType() != "" {
- attackType = def.AttackType()
- } else if def.EquipmentType() == item.EquipRangedWeapon {
- attackType = "ranged"
- } else if def.EquipmentType() == item.EquipScienceWeapon {
- attackType = "science"
+ if d, err := g.ItemStore.Load(itemID); err == nil {
+ def = d
+ weaponType = d.EquipmentType()
+ if at := d.AttackType(); at != "" {
+ attackType = at
+ } else if weaponType == item.EquipRangedWeapon {
+ attackType = combat.AttackRanged
+ } else if weaponType == item.EquipScienceWeapon {
+ attackType = combat.AttackScience
}
- weaponType = def.EquipmentType()
}
}
+ return
+}
+
+func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType item.EquipmentType, attRoll int, defRoll int, maxHit int) {
+ attackType, weaponType, _ = g.resolvePlayerAttackType(p)
totals := g.playerEquipBonuses(p)
isRanged := weaponType == item.EquipRangedWeapon
@@ -311,26 +319,26 @@ func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstanc
rangedBonus, _ := combat.RangedStyleBonus(string(p.AttackStyle))
equipAttack := totals.RangedAttack
effectiveRanged := p.Level(player.Ranged) + g.techLevelBonus(p, "ranged") + g.buffLevelBonus(p, "ranged")
- attRoll = combat.EffectiveRoll(effectiveRanged, rangedBonus, equipAttack)
+ attRoll = combat.AttackRoll(combat.PlayerEffective(effectiveRanged, rangedBonus), equipAttack)
mobDefBonus := combat.SelectBonus(attackType,
mob.StabDefense, mob.SlashDefense, mob.CrushDefense,
mob.ScienceDefense, mob.RangedDefense)
- defRoll = combat.EffectiveRoll(mob.Defense, 0, mobDefBonus)
- maxHit = combat.MaxHit(effectiveRanged, rangedBonus, totals.RangedStrength)
+ defRoll = combat.AttackRoll(combat.NPCEffective(mob.Defense), mobDefBonus)
+ maxHit = combat.MaxHit(combat.PlayerEffective(effectiveRanged, rangedBonus), totals.RangedStrength)
} else {
attBonus, strBonus, _ := combat.AttackStyleBonus(string(p.AttackStyle))
equipAttack := combat.SelectBonus(attackType,
totals.StabAttack, totals.SlashAttack, totals.CrushAttack,
totals.ScienceAttack, totals.RangedAttack)
effectiveAccuracy := p.Level(player.Accuracy) + g.techLevelBonus(p, "accuracy") + g.buffLevelBonus(p, "accuracy")
- attRoll = combat.EffectiveRoll(effectiveAccuracy, attBonus, equipAttack)
+ attRoll = combat.AttackRoll(combat.PlayerEffective(effectiveAccuracy, attBonus), equipAttack)
mobDefBonus := combat.SelectBonus(attackType,
mob.StabDefense, mob.SlashDefense, mob.CrushDefense,
mob.ScienceDefense, mob.RangedDefense)
- defRoll = combat.EffectiveRoll(mob.Defense, 0, mobDefBonus)
- maxHit = combat.MaxHit(p.Level(player.Strength)+g.techLevelBonus(p, "strength")+g.buffLevelBonus(p, "strength"), strBonus, totals.StrengthBonus)
+ defRoll = combat.AttackRoll(combat.NPCEffective(mob.Defense), mobDefBonus)
+ maxHit = combat.MaxHit(combat.PlayerEffective(p.Level(player.Strength)+g.techLevelBonus(p, "strength")+g.buffLevelBonus(p, "strength"), strBonus), totals.StrengthBonus)
}
return
}
@@ -355,13 +363,13 @@ func (g *Game) calculateUnarmedAttackRoll(p *player.Player, mob *world.MobInstan
attBonus, strBonus, _ := combat.AttackStyleBonus(string(p.AttackStyle))
effectiveAccuracy := p.Level(player.Accuracy) + g.techLevelBonus(p, "accuracy") + g.buffLevelBonus(p, "accuracy")
- attRoll = combat.EffectiveRoll(effectiveAccuracy, attBonus, 0)
+ attRoll = combat.AttackRoll(combat.PlayerEffective(effectiveAccuracy, attBonus), 0)
mobDefBonus := combat.SelectBonus(attackType,
mob.StabDefense, mob.SlashDefense, mob.CrushDefense,
mob.ScienceDefense, mob.RangedDefense)
- defRoll = combat.EffectiveRoll(mob.Defense, 0, mobDefBonus)
- maxHit = combat.MaxHit(p.Level(player.Strength)+g.techLevelBonus(p, "strength")+g.buffLevelBonus(p, "strength"), strBonus, 0)
+ defRoll = combat.AttackRoll(combat.NPCEffective(mob.Defense), mobDefBonus)
+ maxHit = combat.MaxHit(combat.PlayerEffective(p.Level(player.Strength)+g.techLevelBonus(p, "strength")+g.buffLevelBonus(p, "strength"), strBonus), 0)
return
}
@@ -380,14 +388,9 @@ func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.Mo
}
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)))
+ mobDisplayName(mob, false), g.itemDisplayName(mob.FinishingBlow))))
}
isRanged := weaponType == item.EquipRangedWeapon
@@ -401,19 +404,11 @@ func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.Mo
g.writeTaskProgress(sess, p, mob, dmg, gains)
} else {
mobName := mobDisplayName(mob, true)
- attacker := mob.Name
- if !mob.Unique {
- attacker = "The " + mob.Name
- }
- w := len(fmt.Sprintf("You hit %s for %d damage.", mobName, 999))
- if w2 := len(fmt.Sprintf("%s hits you for %d damage.", attacker, 999)); w2 > w {
- w = w2
- }
+ attacker := mobDisplayNameCap(mob, true)
prefix := fmt.Sprintf("You hit %s for %s damage.", g.colorize(sess, "mob", mobName), g.colorize(sess, "damage_dealt", fmt.Sprint(dmg)))
- visLen := color.VisibleLen(prefix)
- if visLen < w {
- prefix += strings.Repeat(" ", w-visLen+1)
- }
+ prefix = padCombatPrefix(prefix,
+ fmt.Sprintf("You hit %s for %d damage.", mobName, 999),
+ fmt.Sprintf("%s hits you for %d damage.", attacker, 999))
hpSuffix := fmt.Sprintf("%s [%2d/%d]", g.hpBar(sess, mob.HP, mob.MaxHP), mob.HP, mob.MaxHP)
line := prefix + hpSuffix + g.formatXpDrop(sess, p, gains)
sess.WriteLine(line)