120 lines
2.6 KiB
Go

package actions
import (
"dk/internal/control"
"dk/internal/models/fights"
"dk/internal/models/monsters"
"dk/internal/models/towns"
"dk/internal/models/users"
"fmt"
"math"
"math/rand"
)
type Direction int
const (
North Direction = iota
East
South
West
)
func (d Direction) String() string {
switch d {
case North:
return "North"
case East:
return "East"
case South:
return "South"
case West:
return "West"
default:
return "Unknown"
}
}
func Move(user *users.User, dir Direction) (string, int, int, error) {
control := control.Get()
newX, newY := user.GetPosition()
switch dir {
case North:
newY++
case East:
newX++
case South:
newY--
case West:
newX--
}
if !control.IsWithinWorldBounds(newX, newY) {
return user.Currently, user.X, user.Y, fmt.Errorf("You've hit the edge of the world.")
}
if town, _ := towns.ByCoords(newX, newY); town != nil {
return "In Town", newX, newY, nil
}
// 33% chance to start a fight when moving to non-town location
if rand.Float32() < 0.33 {
monster, err := getRandomMonsterByDistance(newX, newY)
if err != nil {
return "Exploring", newX, newY, nil // Fall back to exploring if monster selection fails
}
// Create new fight record
fight := fights.New(user.ID, monster.ID)
fight.MonsterHP = monster.MaxHP
fight.MonsterMaxHP = monster.MaxHP
fight.MonsterImmune = monster.Immune
err = fight.Insert()
if err != nil {
return "Exploring", newX, newY, nil // Fall back if fight creation fails
}
user.FightID = fight.ID
return "Fighting", newX, newY, nil
}
return "Exploring", newX, newY, nil
}
// getRandomMonsterByDistance selects a random monster based on distance from origin
func getRandomMonsterByDistance(x, y int) (*monsters.Monster, error) {
// Calculate Manhattan distance from origin
distance := int(math.Abs(float64(x)) + math.Abs(float64(y)))
// Determine level range based on distance (every 5 units increases level)
minLevel := 1 + (distance / 5)
maxLevel := minLevel + 2 // 3-level range
// Cap the levels at reasonable bounds
if minLevel > 50 {
minLevel = 50
}
if maxLevel > 50 {
maxLevel = 50
}
if minLevel < 1 {
minLevel = 1
}
// Get monsters in the level range
availableMonsters, err := monsters.ByLevelRange(minLevel, maxLevel)
if err != nil || len(availableMonsters) == 0 {
// Fallback to level 1 monsters if no monsters found
availableMonsters, err = monsters.ByLevel(1)
if err != nil || len(availableMonsters) == 0 {
return nil, fmt.Errorf("no monsters available")
}
}
// Pick a random monster from available ones
randomIndex := rand.Intn(len(availableMonsters))
return availableMonsters[randomIndex], nil
}