aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_attack.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-19 21:20:32 -0400
committerhistoria <[not public]>2026-06-19 21:20:32 -0400
commit5ea082ab4e82409aebc889b496f43e52b003d4f7 (patch)
tree942f2c4a18ecbee42ba25726048d09827ea68894 /internal/game/cmd_attack.go
parent8ee8982b8759bcae116647cc993867f4c8b0a6ce (diff)
downloadthehouseoficarus-5ea082ab4e82409aebc889b496f43e52b003d4f7.tar.gz
feat: science combat/triggers overhauled. decks now use autotrigger attacks.
Diffstat (limited to 'internal/game/cmd_attack.go')
-rw-r--r--internal/game/cmd_attack.go85
1 files changed, 69 insertions, 16 deletions
diff --git a/internal/game/cmd_attack.go b/internal/game/cmd_attack.go
index 222e3c3..f9cfba2 100644
--- a/internal/game/cmd_attack.go
+++ b/internal/game/cmd_attack.go
@@ -129,12 +129,9 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn
g.cancelBackgroundAction(p)
combat.EnterCombat(p.Name, mob.InstanceID)
+ p.AttackTimer = 0
autotriggerActive := p.AutotriggerMod != ""
- playerSpeed := g.playerWeaponSpeed(p)
- if autotriggerActive {
- playerSpeed = 5.0
- }
if !autotriggerActive {
attBonus, strBonus, defBonus := combat.AttackStyleBonus(string(p.AttackStyle))
@@ -173,7 +170,7 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn
}
}
- g.Ticks.Subscribe(engine.ToTicks(playerSpeed), func() bool {
+ g.Ticks.Subscribe(1, func() bool {
cs := combat.GetCombat(p.Name)
if cs == nil || !cs.Active {
return false
@@ -183,21 +180,46 @@ func (g *Game) startCombat(sess *net.Session, p *player.Player, mob *world.MobIn
g.endCombat(sess, p, currentMob)
return false
}
- if p.AutotriggerMod != "" {
- mod := GetMod(p.AutotriggerMod)
- if mod != nil {
- if !g.scienceAttack(sess, p, currentMob, mod) {
- p.AutotriggerMod = ""
- sess.WriteLine("You've run out of junk. Switching to melee.")
- g.playerAttack(sess, p, currentMob)
+
+ p.AttackTimer++
+ if float64(p.AttackTimer) >= g.playerWeaponSpeed(p) {
+ p.AttackTimer = 0
+
+ if g.hasDeckEquipped(p) {
+ if p.AutotriggerMod != "" {
+ mod := GetMod(p.AutotriggerMod)
+ 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("\nYou'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",
+ "\nNo autotrigger set! Set a module with the 'autotrigger' command."))
+ g.playerAttackUnarmed(sess, p, currentMob)
+ }
+ } else {
+ sess.WriteLine(g.colorize(sess, "error",
+ "\nNo autotrigger set! Set a module with the 'autotrigger' command."))
+ g.playerAttackUnarmed(sess, p, currentMob)
}
} else {
- p.AutotriggerMod = ""
- g.playerAttack(sess, p, currentMob)
+ if p.QueuedTrigger != "" {
+ mod := GetMod(p.QueuedTrigger)
+ p.QueuedTrigger = ""
+ if mod != nil && g.hasJunkCost(p, mod) {
+ g.scienceAttack(sess, p, currentMob, mod)
+ } else {
+ g.playerAttack(sess, p, currentMob)
+ }
+ } else {
+ g.playerAttack(sess, p, currentMob)
+ }
}
- } else {
- g.playerAttack(sess, p, currentMob)
}
+
if currentMob.HP <= 0 {
g.endCombat(sess, p, currentMob)
return false
@@ -284,6 +306,37 @@ func (g *Game) calculatePlayerAttackRoll(p *player.Player, mob *world.MobInstanc
return
}
+func (g *Game) playerAttackUnarmed(sess *net.Session, p *player.Player, mob *world.MobInstance) {
+ if g.processConsumeQueue(p, sess) {
+ p.ActionState = &ActionState{Type: ActionEating, TargetName: "food"}
+ return
+ }
+
+ attackType, _, attRoll, defRoll, maxHit := g.calculateUnarmedAttackRoll(p, mob)
+
+ if combat.HitCheck(attRoll, defRoll) {
+ g.applyPlayerHit(sess, p, mob, attackType, object.WeaponMelee, maxHit)
+ } else {
+ g.applyPlayerMiss(sess, p, mob, object.WeaponMelee)
+ }
+}
+
+func (g *Game) calculateUnarmedAttackRoll(p *player.Player, mob *world.MobInstance) (attackType string, weaponType object.WeaponType, attRoll int, defRoll int, maxHit int) {
+ attackType = "crush"
+ weaponType = object.WeaponMelee
+
+ attBonus, strBonus, _ := combat.AttackStyleBonus(string(p.AttackStyle))
+ effectiveAttack := p.Level(player.Attack) + g.techLevelBonus(p, "attack") + g.buffLevelBonus(p, "attack")
+ attRoll = combat.AttackRoll(effectiveAttack, attBonus, 0)
+
+ mobDefBonus := combat.SelectDefenseBonus(attackType,
+ mob.StabDefense, mob.SlashDefense, mob.CrushDefense,
+ mob.ScienceDefense, mob.RangedDefense)
+ defRoll = combat.DefenseRoll(mob.Defense, 0, mobDefBonus)
+ maxHit = combat.MaxHit(p.Level(player.Strength)+g.techLevelBonus(p, "strength")+g.buffLevelBonus(p, "strength"), strBonus, 0)
+ return
+}
+
func (g *Game) applyPlayerHit(sess *net.Session, p *player.Player, mob *world.MobInstance, attackType string, weaponType object.WeaponType, maxHit int) {
dmg := combat.RollDamage(maxHit)