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]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 }