351 lines
10 KiB
Go
351 lines
10 KiB
Go
package races
|
|
|
|
import (
|
|
"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]any {
|
|
stats := make(map[string]any)
|
|
|
|
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
|
|
}
|