package routes import ( "dk/internal/actions" "dk/internal/auth" "dk/internal/components" "dk/internal/helpers" "dk/internal/middleware" "dk/internal/models/fights" "dk/internal/models/monsters" "dk/internal/models/spells" "dk/internal/models/users" "dk/internal/router" "dk/internal/session" "fmt" "math/rand" "strconv" ) func RegisterFightRoutes(r *router.Router) { group := r.Group("/fight") group.Use(auth.RequireAuth()) group.Use(middleware.RequireFighting()) group.Get("/", showFight) group.Post("/", handleFightAction) } func showFight(ctx router.Ctx, _ []string) { sess := ctx.UserValue("session").(*session.Session) user := ctx.UserValue("user").(*users.User) fight, err := fights.Find(user.FightID) if err != nil { ctx.SetContentType("text/plain") ctx.SetBodyString("Fight not found") return } monster, err := monsters.Find(fight.MonsterID) if err != nil { ctx.SetContentType("text/plain") ctx.SetBodyString("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 router.Ctx, _ []string) { user := ctx.UserValue("user").(*users.User) sess := ctx.UserValue("session").(*session.Session) 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) }