persona-community-1/pkg/persona/humanoid_validation.go
jordan 4004f88f4a
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/manual/woodpecker Pipeline was successful
Initialize project from skeleton template
2026-02-23 10:20:59 +00:00

185 lines
4.8 KiB
Go

package persona
import "fmt"
// ValidateHumanoidMorphology validates morphology features for humanoid characters.
// Returns errors if morphology features are present without sufficient MorphLevel.
func ValidateHumanoidMorphology(c *Character) ValidationErrors {
var errs ValidationErrors
if c == nil || c.Species != SpeciesHumanoid {
return errs
}
morphology := c.Morphology
if morphology == nil || !morphology.HasFeatures() {
return errs // No morphology features, nothing to validate
}
// Check if morph level allows features
if c.MorphLevel < 25 {
errs.Add("morph_level",
fmt.Sprintf("morph level %d is too low for morphology features (requires >= 25)", c.MorphLevel),
ErrMorphLevelRequired)
return errs
}
// Validate individual feature types
if morphology.EarType != "" && !IsValidEarType(morphology.EarType) {
errs.AddValue("morphology.ear_type", morphology.EarType,
fmt.Sprintf("invalid ear type: %s", morphology.EarType), ErrInvalidFeatureType)
}
if morphology.TailType != "" && !IsValidTailType(morphology.TailType) {
errs.AddValue("morphology.tail_type", morphology.TailType,
fmt.Sprintf("invalid tail type: %s", morphology.TailType), ErrInvalidFeatureType)
}
if morphology.FangType != "" && !IsValidFangType(morphology.FangType) {
errs.AddValue("morphology.fang_type", morphology.FangType,
fmt.Sprintf("invalid fang type: %s", morphology.FangType), ErrInvalidFeatureType)
}
if morphology.WingType != "" && !IsValidWingType(morphology.WingType) {
errs.AddValue("morphology.wing_type", morphology.WingType,
fmt.Sprintf("invalid wing type: %s", morphology.WingType), ErrInvalidFeatureType)
}
if morphology.HornType != "" && !IsValidHornType(morphology.HornType) {
errs.AddValue("morphology.horn_type", morphology.HornType,
fmt.Sprintf("invalid horn type: %s", morphology.HornType), ErrInvalidFeatureType)
}
if morphology.ClawType != "" && !IsValidClawType(morphology.ClawType) {
errs.AddValue("morphology.claw_type", morphology.ClawType,
fmt.Sprintf("invalid claw type: %s", morphology.ClawType), ErrInvalidFeatureType)
}
// Validate morph level vs feature intensity
if err := validateMorphLevelFeatureConsistency(c.MorphLevel, morphology); err != nil {
errs.Add("morphology", err.Error(), ErrInconsistentAttributes)
}
return errs
}
// validateMorphLevelFeatureConsistency ensures features match the morph level band.
func validateMorphLevelFeatureConsistency(morphLevel int, m *MorphologyHints) error {
if m == nil {
return nil
}
band := MorphLevelBand(morphLevel)
// Count features
featureCount := 0
hasExtremeFeatures := false
if m.EarType != "" {
featureCount++
}
if m.TailType != "" {
featureCount++
}
if m.FangType != "" {
featureCount++
}
if m.WingType != "" {
featureCount++
hasExtremeFeatures = true // Wings are extreme
}
if m.HornType != "" {
featureCount++
if m.HornType == "demon" || m.HornType == "antlers" {
hasExtremeFeatures = true
}
}
if m.ClawType != "" {
featureCount++
if m.ClawType == "talons" || m.ClawType == "prominent" {
hasExtremeFeatures = true
}
}
if len(m.FurPatterns) > 0 {
featureCount++
if len(m.FurPatterns) > 2 {
hasExtremeFeatures = true
}
}
if m.ScalePattern != "" {
featureCount++
hasExtremeFeatures = true // Scales are extreme
}
// Validate based on band
switch band {
case "subtle":
// At subtle level (25-49), only minor features allowed
if hasExtremeFeatures {
return fmt.Errorf("extreme features (wings, scales, heavy fur) require morph level >= 75")
}
if featureCount > 3 {
return fmt.Errorf("too many features (%d) for subtle morph level (max 3)", featureCount)
}
case "demi_human":
// At demi-human level (50-74), moderate features allowed
if hasExtremeFeatures {
return fmt.Errorf("extreme features (wings, scales, heavy fur) require morph level >= 75")
}
case "hybrid", "creature":
// At hybrid (75-99) and creature (100), all features allowed
// No restrictions
}
return nil
}
// RecommendMorphLevel recommends a minimum morph level for given morphology.
func RecommendMorphLevel(m *MorphologyHints) int {
if m == nil || !m.HasFeatures() {
return 0
}
// Check for extreme features
hasExtreme := m.WingType != "" ||
m.ScalePattern != "" ||
m.ClawType == "talons" ||
m.ClawType == "prominent" ||
m.HornType == "demon" ||
m.HornType == "antlers" ||
len(m.FurPatterns) > 2
if hasExtreme {
return 75 // Hybrid level
}
// Check for moderate features
featureCount := 0
if m.EarType != "" {
featureCount++
}
if m.TailType != "" {
featureCount++
}
if m.FangType != "" {
featureCount++
}
if m.HornType != "" {
featureCount++
}
if m.ClawType != "" {
featureCount++
}
if len(m.FurPatterns) > 0 {
featureCount++
}
if featureCount > 3 {
return 50 // Demi-human level
}
return 25 // Subtle level
}