120 lines
2.6 KiB
Go
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
|
|
}
|