package spells import ( "sort" "gitea.maximumdirect.net/eric/notarius/internal/core/source" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd" "gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared" ) func canonicalizeResponse(response *extractionResponse) { if response == nil { return } for index := range response.SpellCasts { canonicalizeSpellCast(&response.SpellCasts[index]) } sort.SliceStable(response.SpellCasts, func(i, j int) bool { left, leftOK := earliestSourceUnit(response.SpellCasts[i]) right, rightOK := earliestSourceUnit(response.SpellCasts[j]) if leftOK != rightOK { return leftOK } if !leftOK { return false } return left < right }) } func canonicalizeSpellCast(spell *spellCastResponse) { for index := range spell.SourceRefs { spell.SourceRefs[index].StartUnitID = canonicalUnitRef(spell.SourceRefs[index].StartUnitID) spell.SourceRefs[index].EndUnitID = canonicalUnitRef(spell.SourceRefs[index].EndUnitID) } sort.SliceStable(spell.SourceRefs, func(i, j int) bool { left := spell.SourceRefs[i] right := spell.SourceRefs[j] if left.StartUnitID.Int() != right.StartUnitID.Int() { return unitSortValue(left.StartUnitID) < unitSortValue(right.StartUnitID) } return unitSortValue(left.EndUnitID) < unitSortValue(right.EndUnitID) }) spell.SourceRefs = dedupeSourceRefs(spell.SourceRefs) } func canonicalUnitRef(ref shared.UnitRef) shared.UnitRef { value := ref.Int() if value <= 0 { return ref } return shared.UnitRefFromInt(value) } func dedupeSourceRefs(refs []spellSourceRefResponse) []spellSourceRefResponse { if len(refs) < 2 { return refs } out := refs[:0] var previous spellSourceRefResponse for index, ref := range refs { if index > 0 && sameSourceRef(previous, ref) { continue } out = append(out, ref) previous = ref } return out } func sameSourceRef(left spellSourceRefResponse, right spellSourceRefResponse) bool { return left.StartUnitID.Int() == right.StartUnitID.Int() && left.EndUnitID.Int() == right.EndUnitID.Int() } func earliestSourceUnit(spell spellCastResponse) (int, bool) { for _, ref := range spell.SourceRefs { start := ref.StartUnitID.Int() if start > 0 { return start, true } } return 0, false } func unitSortValue(ref shared.UnitRef) int { value := ref.Int() if value <= 0 { return int(^uint(0) >> 1) } return value } func canonicalSpellList(response extractionResponse, sourceID string) dnd.SpellList { spellCasts := make([]dnd.SpellCast, len(response.SpellCasts)) for index, spell := range response.SpellCasts { refs := make([]source.SourceRef, len(spell.SourceRefs)) for refIndex, ref := range spell.SourceRefs { refs[refIndex] = source.SourceRef{ SourceID: sourceID, StartUnitID: ref.StartUnitID.Int(), EndUnitID: ref.EndUnitID.Int(), } } spellCasts[index] = dnd.SpellCast{ Caster: spell.Caster, Spell: spell.Spell, Effect: spell.Effect, NarrativeDescription: spell.NarrativeDescription, SourceRefs: refs, } } if response.SpellCasts == nil { spellCasts = nil } return dnd.SpellList{SpellCasts: spellCasts} }