From cfc1256d023204e7a19c557f1da219c6cc0727f2 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Fri, 22 Aug 2025 09:09:15 -0500 Subject: [PATCH] fix lots of little bugs and get last_online working --- data/dk.db | Bin 73728 -> 73728 bytes database.sql | 2 +- go.mod | 2 +- go.sum | 4 +- internal/actions/fight.go | 103 +++++++++++++++++----------------- internal/components/asides.go | 2 +- internal/routes/auth.go | 19 ------- internal/routes/fight.go | 2 +- internal/routes/index.go | 16 ++++-- internal/routes/town.go | 17 ++++-- main.go | 17 +++++- 11 files changed, 95 insertions(+), 89 deletions(-) diff --git a/data/dk.db b/data/dk.db index 09be7ffa9c2bc9c79a80b9d4dccbf46f455cce1f..c3fbe1042c95ec6e70d3a99f3e3c62d7b71b7db9 100644 GIT binary patch delta 1755 zcmZwHPi)&%90zbaeomfaKfh8Z&9X51FNF=#cFAbF3JP>BD~L_48rl)jbxMgFN6r5~ zBtz=FT#!JB0|z9;1*9P&4jbJh&~7~-=#UV9q@55F9DplAzy+l7d#=+uYoGKa+xhtW z`@QGbSGUpCZS*PM7ozWRUb@NA>-2AWoBl?BqTkam={34Z-`Hv_vW55A+ZAztE+VJu-hc0QA;7s}aG zG!l!PibN+O(bJLWWF&Sv5}V`*MDcW-qvKo6j(K#VdfW4D$CS zNgYY~38R&txcM{cGGdCs(LZ5pzoDPekLlagr0etoeVU%6N2sL!q5h)osJGRR)OXdU zT2U{l3+j{Vuo_goKZlpD&2%3I2& zVr(`4lT9t=;dovOB8=lkGF7O zw8$aEB#$xEF14dQ$`B4BkG$8;Dmh^r4{K*tJ8lPg_FG;hk93-c51NZ)$Z0NWVGn0o zYj*^#kU=L}(FP6%t&si>kx&QfK5C%=60Hq@m#8F@piM-mR+77q96|z}qz6t-Uh0TZ{LH{pg;%a5Yd)63 zGvQ*7gH`ep%^BnE?q;SV#Y-OOAb~DMa6dxwnQTq(i)S-A79|pD+7Pj~O$?}37C?L- zByGo5C-x{-U@sEnMLo5b#}nCR0*m8&yjC1A>|`8~_85HaN?ZV2as9~E(O user.Level { + r.UserUpdates["level"] = newLevel + r.UserUpdates["strength"] = newStats.Strength + r.UserUpdates["dexterity"] = newStats.Dexterity + } + + r.Ended = true + r.Victory = true + r.Won = true + r.RewardGold = rewardGold + r.RewardExp = rewardExp } func HandleAttack(fight *fights.Fight, user *users.User) *FightResult { @@ -61,10 +93,7 @@ func HandleAttack(fight *fights.Fight, user *users.User) *FightResult { } finalDamage := int(damage) - newMonsterHP := fight.MonsterHP - finalDamage - if newMonsterHP < 0 { - newMonsterHP = 0 - } + newMonsterHP := max(fight.MonsterHP-finalDamage, 0) result := &FightResult{ FightUpdates: map[string]any{"monster_hp": newMonsterHP}, @@ -73,37 +102,13 @@ func HandleAttack(fight *fights.Fight, user *users.User) *FightResult { // Check if monster defeated if newMonsterHP <= 0 { - rewardGold, rewardExp := calculateRewards(monster, user) - - result.FightUpdates["victory"] = true - result.FightUpdates["won"] = true - result.FightUpdates["reward_gold"] = rewardGold - result.FightUpdates["reward_exp"] = rewardExp - - result.UserUpdates = map[string]any{ - "fight_id": 0, - "currently": "Exploring", - "gold": user.Gold + rewardGold, - "exp": user.Exp + rewardExp, - } - - // Handle level up - newLevel, newStats := calculateLevelUp(user.Level, user.Exp+rewardExp, user.Strength, user.Dexterity) - if newLevel > user.Level { - result.UserUpdates["level"] = newLevel - result.UserUpdates["strength"] = newStats.Strength - result.UserUpdates["dexterity"] = newStats.Dexterity - } - + result.EndFightWithVictory(monster, user) result.LogAction = func() error { if err := fightlogs.AddAttackHit(fight.ID, finalDamage); err != nil { return err } return fightlogs.AddMonsterDeath(fight.ID, monster.Name) } - result.Ended = true - result.Victory = true - result.Won = true } return result @@ -135,31 +140,20 @@ func HandleSpell(fight *fights.Fight, user *users.User, spellID int) *FightResul switch spell.Type { case spells.TypeHealing: - newHP := user.HP + spell.Attribute - if newHP > user.MaxHP { - newHP = user.MaxHP - } + newHP := min(user.HP+spell.Attribute, user.MaxHP) result.UserUpdates["hp"] = newHP result.LogAction = func() error { return fightlogs.AddSpellHeal(fight.ID, spell.Name, spell.Attribute) } case spells.TypeHurt: - newMonsterHP := fight.MonsterHP - spell.Attribute - if newMonsterHP < 0 { - newMonsterHP = 0 - } + newMonsterHP := max(fight.MonsterHP-spell.Attribute, 0) result.FightUpdates = map[string]any{"monster_hp": newMonsterHP} result.LogAction = func() error { return fightlogs.AddSpellHurt(fight.ID, spell.Name, spell.Attribute) } if newMonsterHP <= 0 { - result.FightUpdates["victory"] = true - result.FightUpdates["won"] = true - result.FightUpdates["reward_gold"] = 10 - result.FightUpdates["reward_exp"] = 5 - result.UserUpdates["fight_id"] = 0 - result.UserUpdates["currently"] = "Exploring" - result.Ended = true - result.Victory = true - result.Won = true + monster, err := monsters.Find(fight.MonsterID) + if err == nil { + result.EndFightWithVictory(monster, user) + } } default: @@ -218,10 +212,7 @@ func HandleMonsterAttack(fight *fights.Fight, user *users.User) *FightResult { } finalDamage := int(damage) - newHP := user.HP - finalDamage - if newHP < 0 { - newHP = 0 - } + newHP := max(user.HP-finalDamage, 0) result := &FightResult{ UserUpdates: map[string]any{"hp": newHP}, @@ -301,14 +292,22 @@ func findClosestTown(x, y int) *towns.Town { } func calculateRewards(monster *monsters.Monster, user *users.User) (int, int) { - minExp := (monster.MaxExp * 5) / 6 + // More generous reward range: 90-100% of max instead of 83-100% + minExp := (monster.MaxExp * 9) / 10 maxExp := monster.MaxExp exp := rand.Intn(maxExp-minExp+1) + minExp + if exp < 1 { + exp = 1 // Guaranteed minimum + } - minGold := (monster.MaxGold * 5) / 6 + minGold := (monster.MaxGold * 9) / 10 maxGold := monster.MaxGold gold := rand.Intn(maxGold-minGold+1) + minGold + if gold < 1 { + gold = 1 // Guaranteed minimum + } + // Apply bonuses expBonus := (user.ExpBonus * exp) / 100 exp += expBonus diff --git a/internal/components/asides.go b/internal/components/asides.go index e41905f..7c62a4e 100644 --- a/internal/components/asides.go +++ b/internal/components/asides.go @@ -44,7 +44,7 @@ func RightAside(ctx sushi.Ctx) map[string]any { return data } - user := ctx.UserValue("user").(*users.User) + user := ctx.GetCurrentUser().(*users.User) data["_expprog"] = fmt.Sprintf("%.1f", user.ExpProgress()) diff --git a/internal/routes/auth.go b/internal/routes/auth.go index 53f3560..c30e1ca 100644 --- a/internal/routes/auth.go +++ b/internal/routes/auth.go @@ -95,46 +95,35 @@ func showRegister(ctx sushi.Ctx) { // processRegister handles registration form submission func processRegister(ctx sushi.Ctx) { - fmt.Println("DEBUG: Starting registration process") - username := strings.TrimSpace(ctx.Form("username").String()) email := strings.TrimSpace(ctx.Form("email").String()) userPassword := ctx.Form("password").String() confirmPassword := ctx.Form("confirm_password").String() - fmt.Printf("DEBUG: Form data - username: '%s', email: '%s', password length: %d\n", - username, email, len(userPassword)) - formData := map[string]string{ "username": username, "email": email, } if err := validateRegistration(username, email, userPassword, confirmPassword); err != nil { - fmt.Printf("DEBUG: Validation failed: %v\n", err) setFlashAndFormData(ctx, err.Error(), formData) ctx.Redirect("/register") return } - fmt.Println("DEBUG: Validation passed") // Check if username already exists if _, err := users.ByUsername(username); err == nil { - fmt.Printf("DEBUG: Username '%s' already exists\n", username) setFlashAndFormData(ctx, "Username already exists", formData) ctx.Redirect("/register") return } - fmt.Printf("DEBUG: Username '%s' is available\n", username) // Check if email already exists if _, err := users.ByEmail(email); err == nil { - fmt.Printf("DEBUG: Email '%s' already exists\n", email) setFlashAndFormData(ctx, "Email already registered", formData) ctx.Redirect("/register") return } - fmt.Printf("DEBUG: Email '%s' is available\n", email) // Create new user user := users.New() @@ -144,34 +133,26 @@ func processRegister(ctx sushi.Ctx) { user.ClassID = 1 user.Auth = 1 - fmt.Printf("DEBUG: Created user struct with ID: %d\n", user.ID) - // Validate before inserting if err := user.Validate(); err != nil { - fmt.Printf("DEBUG: User validation failed: %v\n", err) setFlashAndFormData(ctx, fmt.Sprintf("Invalid user data: %s", err.Error()), formData) ctx.Redirect("/register") return } - fmt.Println("DEBUG: User validation passed") if err := user.Insert(); err != nil { - fmt.Printf("DEBUG: User insert failed: %v\n", err) setFlashAndFormData(ctx, "Failed to create account", formData) ctx.Redirect("/register") return } - fmt.Printf("DEBUG: User inserted successfully with ID: %d\n", user.ID) // Auto-login after registration ctx.Login(user.ID, user) - fmt.Printf("DEBUG: User logged in with ID: %d\n", user.ID) // Set success message sess := ctx.GetCurrentSession() sess.SetFlash("success", fmt.Sprintf("Greetings, %s!", user.Username)) - fmt.Println("DEBUG: Registration completed successfully") ctx.Redirect("/") } diff --git a/internal/routes/fight.go b/internal/routes/fight.go index fe898a3..451f41c 100644 --- a/internal/routes/fight.go +++ b/internal/routes/fight.go @@ -154,7 +154,7 @@ func handleFightAction(ctx sushi.Ctx) { // Handle fight end states if result.Ended { if result.Won { - sess.SetFlash("success", fmt.Sprintf("Victory! You gained rewards!")) + sess.SetFlash("success", fmt.Sprintf("Victory! You gained %d gold and %d experience!", result.RewardGold, result.RewardExp)) ctx.Redirect("/explore", 302) } else if result.Victory { sess.SetFlash("error", "You have been defeated! You lost some gold and were sent to the nearest town.") diff --git a/internal/routes/index.go b/internal/routes/index.go index dd21652..5354fb0 100644 --- a/internal/routes/index.go +++ b/internal/routes/index.go @@ -54,12 +54,18 @@ func Move(ctx sushi.Ctx) { return } + updateData := map[string]any{ + "currently": currently, + "x": newX, + "y": newY, + } + + if currently == "Fighting" { + updateData["fight_id"] = user.FightID + } + err = database.Transaction(func() error { - return database.Update("users", map[string]any{ - "currently": currently, - "x": newX, - "y": newY, - }, "id", user.ID) + return database.Update("users", updateData, "id", user.ID) }) if err != nil { diff --git a/internal/routes/town.go b/internal/routes/town.go index 17abeee..d01f9f2 100644 --- a/internal/routes/town.go +++ b/internal/routes/town.go @@ -77,9 +77,17 @@ func showTown(ctx sushi.Ctx) { func showInn(ctx sushi.Ctx) { town := ctx.UserValue("town").(*towns.Town) + sess := ctx.GetCurrentSession() + + value, exists := sess.GetFlash("rested") + rested := false + if exists && value == true { + rested = true + } + components.RenderPage(ctx, town.Name+" Inn", "town/inn.html", map[string]any{ "town": town, - "rested": false, + "rested": rested, }) } @@ -102,17 +110,14 @@ func rest(ctx sushi.Ctx) { "tp": user.MaxTP, }, "id", user.ID) }) - if err != nil { sess.SetFlash("error", "Failed to rest at inn.") ctx.Redirect("/town/inn") return } - components.RenderPage(ctx, town.Name+" Inn", "town/inn.html", map[string]any{ - "town": town, - "rested": true, - }) + sess.SetFlash("rested", true) + ctx.Redirect("/town/inn") } func showShop(ctx sushi.Ctx) { diff --git a/main.go b/main.go index 1987c2a..5f5cce5 100644 --- a/main.go +++ b/main.go @@ -8,6 +8,7 @@ import ( "os/signal" "path/filepath" "syscall" + "time" "dk/internal/control" "dk/internal/database" @@ -68,13 +69,27 @@ func start(port string) error { template.InitializeCache(cwd) + authMW := auth.New(getUserByID) + app := sushi.New() sushi.InitSessions(filepath.Join(cwd, "data/sessions.json")) app.Use(session.Middleware()) - app.Use(auth.Middleware(getUserByID)) + app.Use(authMW.Middleware()) app.Use(csrf.Middleware()) app.Use(timing.Middleware()) + app.Use(func(ctx sushi.Ctx, next func()) { + if ctx.IsAuthenticated() { + user := ctx.GetCurrentUser().(*users.User) + now := time.Now().Unix() + if (now - user.LastOnline) >= 540 { // 540 seconds = 9 minutes + database.Update("users", map[string]any{ + "last_online": now, + }, "id", user.ID) + } + } + next() + }) app.Get("/", routes.Index)