194 lines
4.7 KiB
Go

package routes
import (
"dk/internal/actions"
"dk/internal/components"
"dk/internal/helpers"
"dk/internal/models/fights"
"dk/internal/models/monsters"
"dk/internal/models/spells"
"dk/internal/models/users"
"fmt"
"math/rand"
"strconv"
sushi "git.sharkk.net/Sharkk/Sushi"
"git.sharkk.net/Sharkk/Sushi/auth"
)
func RegisterFightRoutes(app *sushi.App) {
group := app.Group("/fight")
group.Use(auth.RequireAuth("/login"))
group.Use(requireFighting())
group.Get("/", showFight)
group.Post("/", handleFightAction)
}
// requireFighting middleware ensures the user is in a fight
func requireFighting() sushi.Middleware {
return func(ctx sushi.Ctx, next func()) {
user := ctx.GetCurrentUser()
if user == nil {
ctx.SendError(401, "Not authenticated")
return
}
userModel := user.(*users.User)
if !userModel.IsFighting() {
ctx.Redirect("/")
return
}
next()
}
}
func showFight(ctx sushi.Ctx) {
sess := ctx.GetCurrentSession()
user := ctx.GetCurrentUser().(*users.User)
fight, err := fights.Find(user.FightID)
if err != nil {
ctx.SendError(404, "Fight not found")
return
}
monster, err := monsters.Find(fight.MonsterID)
if err != nil {
ctx.SendError(404, "Monster not found for fight")
return
}
// If turn 0, determine first strike and advance to turn 1
if fight.Turn == 0 {
// 50% chance user goes first
fight.FirstStrike = rand.Float32() < 0.5
fight.Turn = 1
fight.Save()
}
monHpPct := helpers.ClampPct(float64(fight.MonsterHP), float64(fight.MonsterMaxHP), 0, 100)
monHpColor := ""
if monHpPct < 35 {
monHpColor = "danger"
} else if monHpPct < 75 {
monHpColor = "warning"
}
spellMap := helpers.NewOrderedMap[int, *spells.Spell]()
if user.Spells != "" {
for _, id := range user.GetSpellIDs() {
if spell, err := spells.Find(id); err == nil {
spellMap.Set(id, spell)
}
}
}
components.RenderPage(ctx, "Fighting", "fight/fight.html", map[string]any{
"fight": fight,
"user": user,
"monster": monster,
"mon_hppct": monHpPct,
"mon_hpcol": monHpColor,
"spells": spellMap.ToSlice(),
"action": sess.GetFlashMessage("action"),
"mon_action": sess.GetFlashMessage("mon_action"),
})
}
func handleFightAction(ctx sushi.Ctx) {
sess := ctx.GetCurrentSession()
user := ctx.GetCurrentUser().(*users.User)
fight, err := fights.Find(user.FightID)
if err != nil {
ctx.SetContentType("text/plain")
ctx.SetBodyString("Fight not found")
return
}
action := string(ctx.FormValue("action"))
var userAction string
switch action {
case "attack":
actions.HandleAttack(fight, user)
userAction = fight.GetLastAction()
case "spell":
spellIDStr := string(ctx.FormValue("spell_id"))
if spellID, err := strconv.Atoi(spellIDStr); err == nil {
actions.HandleSpell(fight, user, spellID)
userAction = fight.GetLastAction()
}
case "run":
actions.HandleRun(fight, user)
userAction = fight.GetLastAction()
// If successfully ran away, redirect to explore
if fight.RanAway {
user.Currently = "Exploring"
user.Save()
sess.SetFlash("success", "You successfully escaped!")
ctx.Redirect("/explore", 302)
return
}
default:
fight.AddAction("Invalid action!")
userAction = "Invalid action!"
}
// Flash user action
sess.SetFlash("action", userAction)
// Check if fight ended due to user action
if fight.Victory {
if fight.Won {
// Player won
sess.SetFlash("success", fmt.Sprintf("Victory! You gained %d gold and %d experience!", fight.RewardGold, fight.RewardExp))
sess.DeleteFlash("action")
sess.DeleteFlash("mon_action")
ctx.Redirect("/explore", 302)
} else {
// Player lost
sess.SetFlash("error", "You have been defeated! You lost some gold and were sent to the nearest town.")
sess.DeleteFlash("action")
sess.DeleteFlash("mon_action")
ctx.Redirect("/town", 302)
}
return
}
// Monster attacks back if fight is still active
if fight.IsActive() && user.HP > 0 {
actions.HandleMonsterAttack(fight, user)
// Check if fight ended due to monster attack
if fight.Victory {
if fight.Won {
sess.SetFlash("success", fmt.Sprintf("Victory! You gained %d gold and %d experience!", fight.RewardGold, fight.RewardExp))
sess.DeleteFlash("action")
sess.DeleteFlash("mon_action")
ctx.Redirect("/explore", 302)
} else {
sess.SetFlash("error", "You have been defeated! You lost some gold and were sent to the nearest town.")
sess.DeleteFlash("action")
sess.DeleteFlash("mon_action")
ctx.Redirect("/town", 302)
}
return
}
monsterAction := fight.GetLastAction()
sess.SetFlash("mon_action", monsterAction)
}
fight.IncrementTurn()
fight.Save()
user.Save()
// Redirect back to fight page
ctx.Redirect("/fight", 302)
}