eq2go/internal/races/utils.go

351 lines
10 KiB
Go

package races
import (
"fmt"
"math/rand"
"strings"
)
// RaceUtils provides utility functions for race operations
type RaceUtils struct {
races *Races
}
// NewRaceUtils creates a new race utilities instance
func NewRaceUtils() *RaceUtils {
return &RaceUtils{
races: GetGlobalRaces(),
}
}
// ParseRaceName attempts to parse a race name from various input formats
func (ru *RaceUtils) ParseRaceName(input string) int8 {
if input == "" {
return -1
}
// Try direct lookup first
raceID := ru.races.GetRaceID(input)
if raceID != -1 {
return raceID
}
// Try with common variations
variations := []string{
strings.ToUpper(input),
strings.ReplaceAll(strings.ToUpper(input), " ", ""),
strings.ReplaceAll(strings.ToUpper(input), "_", ""),
strings.ReplaceAll(strings.ToUpper(input), "-", ""),
}
for _, variation := range variations {
if raceID := ru.races.GetRaceID(variation); raceID != -1 {
return raceID
}
}
// Try matching against friendly names (case insensitive)
inputLower := strings.ToLower(input)
allRaces := ru.races.GetAllRaces()
for raceID, friendlyName := range allRaces {
if strings.ToLower(friendlyName) == inputLower {
return raceID
}
}
return -1 // Not found
}
// FormatRaceName returns a properly formatted race name
func (ru *RaceUtils) FormatRaceName(raceID int8, format string) string {
switch strings.ToLower(format) {
case "display", "friendly", "proper":
return ru.races.GetRaceNameCase(raceID)
case "upper", "uppercase":
return ru.races.GetRaceName(raceID)
case "lower", "lowercase":
return strings.ToLower(ru.races.GetRaceName(raceID))
default:
return ru.races.GetRaceNameCase(raceID) // Default to friendly name
}
}
// GetRandomRaceByAlignment returns a random race for the specified alignment
func (ru *RaceUtils) GetRandomRaceByAlignment(alignment string) int8 {
switch strings.ToLower(alignment) {
case AlignmentGood:
return ru.races.GetRandomGoodRace()
case AlignmentEvil:
return ru.races.GetRandomEvilRace()
default:
// For neutral or any other alignment, pick from all races
allRaces := ru.races.GetAllRaces()
if len(allRaces) == 0 {
return DefaultRaceID
}
// Convert map to slice for random selection
raceIDs := make([]int8, 0, len(allRaces))
for raceID := range allRaces {
raceIDs = append(raceIDs, raceID)
}
return raceIDs[rand.Intn(len(raceIDs))]
}
}
// ValidateRaceForClass checks if a race is valid for a specific class
// This is a placeholder for future class-race restrictions
func (ru *RaceUtils) ValidateRaceForClass(raceID, classID int8) bool {
// TODO: Implement class-race restrictions when class system is available
// For now, all races can be all classes
return ru.races.IsValidRaceID(raceID)
}
// GetRaceDescription returns a description of the race
func (ru *RaceUtils) GetRaceDescription(raceID int8) string {
// This would typically come from a database or configuration
// For now, provide basic descriptions based on race
switch raceID {
case RaceHuman:
return "Versatile and adaptable, humans are found throughout Norrath."
case RaceBarbarian:
return "Hardy warriors from the frozen lands of Everfrost."
case RaceDarkElf:
return "Cunning and magical, the dark elves hail from Neriak."
case RaceDwarf:
return "Stout and strong, dwarves are master craftsmen and fighters."
case RaceErudite:
return "Intelligent and scholarly, erudites value knowledge above all."
case RaceFroglok:
return "Honorable amphibians who have overcome great adversity."
case RaceGnome:
return "Small but ingenious, gnomes are masters of tinkering and magic."
case RaceHalfElf:
return "Caught between two worlds, half elves combine human adaptability with elven grace."
case RaceHalfling:
return "Small and nimble, halflings are natural rogues and adventurers."
case RaceHighElf:
return "Noble and proud, high elves are paragons of magical prowess."
case RaceIksar:
return "Ancient lizardfolk with a proud warrior tradition."
case RaceKerra:
return "Feline humanoids known for their agility and curiosity."
case RaceOgre:
return "Massive and powerful, ogres are fearsome warriors."
case RaceRatonga:
return "Clever rodent-folk who excel at stealth and cunning."
case RaceTroll:
return "Large and brutish, trolls possess incredible strength and regeneration."
case RaceWoodElf:
return "Forest dwellers with unmatched skill in archery and nature magic."
case RaceFae:
return "Magical fairy-folk with wings and a connection to nature."
case RaceArasai:
return "Dark counterparts to the Fae, corrupted by shadow magic."
case RaceSarnak:
return "Draconic humanoids with scales and ancient wisdom."
case RaceVampire:
return "Undead beings with supernatural powers and bloodthirst."
case RaceAerakyn:
return "Dragon-blooded humanoids with draconic heritage and flight."
default:
return "An unknown race with mysterious origins."
}
}
// GetRaceStatModifiers returns racial stat modifiers for character creation
// This is a placeholder for future stat system integration
func (ru *RaceUtils) GetRaceStatModifiers(raceID int8) map[string]int8 {
// TODO: Implement racial stat modifiers when stat system is available
// This would typically come from database or configuration files
modifiers := make(map[string]int8)
// Example modifiers (these would need to be balanced and come from data)
switch raceID {
case RaceBarbarian:
modifiers["strength"] = 2
modifiers["stamina"] = 1
modifiers["intelligence"] = -1
case RaceDarkElf:
modifiers["intelligence"] = 2
modifiers["agility"] = 1
modifiers["wisdom"] = -1
case RaceDwarf:
modifiers["stamina"] = 2
modifiers["strength"] = 1
modifiers["agility"] = -1
case RaceErudite:
modifiers["intelligence"] = 3
modifiers["wisdom"] = 1
modifiers["strength"] = -2
case RaceGnome:
modifiers["intelligence"] = 2
modifiers["agility"] = 1
modifiers["strength"] = -2
case RaceHighElf:
modifiers["intelligence"] = 2
modifiers["wisdom"] = 1
modifiers["stamina"] = -1
case RaceOgre:
modifiers["strength"] = 3
modifiers["stamina"] = 2
modifiers["intelligence"] = -2
modifiers["agility"] = -1
case RaceTroll:
modifiers["strength"] = 2
modifiers["stamina"] = 3
modifiers["intelligence"] = -2
modifiers["wisdom"] = -1
default:
// Humans and other races have no modifiers (balanced)
break
}
return modifiers
}
// GetRaceStartingLocation returns the starting city/zone for a race
func (ru *RaceUtils) GetRaceStartingLocation(raceID int8) string {
// TODO: This would typically come from database configuration
switch raceID {
case RaceHuman, RaceBarbarian, RaceErudite, RaceKerra:
return "Qeynos"
case RaceDarkElf, RaceOgre, RaceRatonga, RaceTroll:
return "Freeport"
case RaceDwarf, RaceGnome, RaceHalfling:
return "New Halas"
case RaceHighElf, RaceWoodElf, RaceHalfElf:
return "Kelethin"
case RaceIksar, RaceSarnak:
return "Gorowyn"
case RaceFroglok:
return "Temple of Cazic-Thule"
case RaceFae:
return "Greater Faydark"
case RaceArasai:
return "Darklight Wood"
case RaceVampire:
return "Neriak"
case RaceAerakyn:
return "Draconic Starting Area"
default:
return "Qeynos" // Default starting location
}
}
// GetCompatibleRaces returns races that can interact peacefully
func (ru *RaceUtils) GetCompatibleRaces(raceID int8) []int8 {
// This is based on lore and alignment - races of similar alignment are generally compatible
alignment := ru.races.GetRaceAlignment(raceID)
return ru.races.GetRacesByAlignment(alignment)
}
// FormatRaceList returns a formatted string of race names
func (ru *RaceUtils) FormatRaceList(raceIDs []int8, separator string) string {
if len(raceIDs) == 0 {
return ""
}
names := make([]string, len(raceIDs))
for i, raceID := range raceIDs {
names[i] = ru.races.GetRaceNameCase(raceID)
}
return strings.Join(names, separator)
}
// GetRacesByPattern returns races matching a name pattern
func (ru *RaceUtils) GetRacesByPattern(pattern string) []int8 {
pattern = strings.ToLower(pattern)
result := make([]int8, 0)
allRaces := ru.races.GetAllRaces()
for raceID, friendlyName := range allRaces {
if strings.Contains(strings.ToLower(friendlyName), pattern) {
result = append(result, raceID)
}
}
return result
}
// ValidateRaceTransition checks if a race change is allowed
func (ru *RaceUtils) ValidateRaceTransition(fromRaceID, toRaceID int8) (bool, string) {
if !ru.races.IsValidRaceID(fromRaceID) {
return false, "Invalid source race"
}
if !ru.races.IsValidRaceID(toRaceID) {
return false, "Invalid target race"
}
if fromRaceID == toRaceID {
return false, "Cannot change to the same race"
}
// TODO: Implement specific race change restrictions when needed
// For now, allow all transitions
return true, ""
}
// GetRaceAliases returns common aliases for a race
func (ru *RaceUtils) GetRaceAliases(raceID int8) []string {
aliases := make([]string, 0)
switch raceID {
case RaceDarkElf:
aliases = append(aliases, "DE", "Dark Elf", "Teir'Dal")
case RaceHighElf:
aliases = append(aliases, "HE", "High Elf", "Koada'Dal")
case RaceWoodElf:
aliases = append(aliases, "WE", "Wood Elf", "Feir'Dal")
case RaceHalfElf:
aliases = append(aliases, "Half-Elf", "Half Elf", "Ayr'Dal")
case RaceFae:
aliases = append(aliases, "Fairy", "Pixie")
case RaceArasai:
aliases = append(aliases, "Dark Fae", "Shadow Fae")
case RaceVampire:
aliases = append(aliases, "Vamp", "Undead")
case RaceAerakyn:
aliases = append(aliases, "Dragon-kin", "Dragonborn")
}
// Always include the official names
aliases = append(aliases, ru.races.GetRaceName(raceID))
aliases = append(aliases, ru.races.GetRaceNameCase(raceID))
return aliases
}
// GetRaceStatistics returns statistics about the race system
func (ru *RaceUtils) GetRaceStatistics() map[string]interface{} {
stats := make(map[string]interface{})
stats["total_races"] = ru.races.GetRaceCount()
stats["good_races"] = ru.races.GetGoodRaceCount()
stats["evil_races"] = ru.races.GetEvilRaceCount()
// Count neutral races (appear in both lists)
neutralCount := 0
allRaces := ru.races.GetAllRaces()
for raceID := range allRaces {
if ru.races.IsNeutralRace(raceID) {
neutralCount++
}
}
stats["neutral_races"] = neutralCount
// Race distribution by alignment
alignmentDistribution := make(map[string][]string)
for raceID, friendlyName := range allRaces {
alignment := ru.races.GetRaceAlignment(raceID)
alignmentDistribution[alignment] = append(alignmentDistribution[alignment], friendlyName)
}
stats["alignment_distribution"] = alignmentDistribution
return stats
}