From 95eff6118a1f195a68468f45fcd5a9ff5b51ecbb Mon Sep 17 00:00:00 2001 From: Robert Janetzko Date: Thu, 21 Apr 2022 20:01:18 +0000 Subject: [PATCH] events --- backend/go.mod | 1 + backend/go.sum | 2 + backend/model/events.go | 189 +++++++++++++++++++++++++++++---- backend/model/extensions.go | 87 +++++++++++++++ backend/same.json | 16 ++- backend/static/css/legends.css | 2 +- backend/util/util.go | 20 ++++ 7 files changed, 288 insertions(+), 29 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index a819c5d..fc2cbb8 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/cheggaaa/pb/v3 v3.0.8 github.com/gorilla/mux v1.8.0 + github.com/iancoleman/strcase v0.2.0 github.com/pkg/profile v1.6.0 ) diff --git a/backend/go.sum b/backend/go.sum index a4df44b..a75b4b4 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -6,6 +6,8 @@ github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= diff --git a/backend/model/events.go b/backend/model/events.go index b96b1b4..a95d949 100644 --- a/backend/model/events.go +++ b/backend/model/events.go @@ -2,15 +2,10 @@ package model import ( "fmt" - "strings" -) -func andList(list []string) string { - if len(list) > 1 { - return strings.Join(list[:len(list)-1], ", ") + " and " + list[len(list)-1] - } - return strings.Join(list, ", ") -} + "github.com/iancoleman/strcase" + "github.com/robertjanetzko/LegendsBrowser2/backend/util" +) func (x *Honor) Requirement() string { var list []string @@ -287,25 +282,183 @@ func (x *HistoricalEventAssumeIdentity) Html() string { } } -func (x *HistoricalEventAttackedSite) Html() string { return "UNKNWON HistoricalEventAttackedSite" } -func (x *HistoricalEventBodyAbused) Html() string { return "UNKNWON HistoricalEventBodyAbused" } +func (x *HistoricalEventAttackedSite) Html() string { + atk := entity(x.AttackerCivId) + def := entity(x.DefenderCivId) + if x.SiteCivId != x.DefenderCivId { + def = entity(x.SiteCivId) + " of " + def + } + generals := "" + if x.AttackerGeneralHfid != -1 { + generals += ". " + util.Capitalize(hf(x.AttackerGeneralHfid)) + " led the attack" + if x.DefenderGeneralHfid != -1 { + generals += ", and the defenders were led by " + hf(x.DefenderGeneralHfid) + } + } + mercs := "" + if x.AttackerMercEnid != -1 { + mercs += fmt.Sprintf(". %s were hired by the attackers", entity(x.AttackerMercEnid)) + } + if x.ASupportMercEnid != -1 { + mercs += fmt.Sprintf(". %s were hired as scouts by the attackers", entity(x.ASupportMercEnid)) + } + if x.DefenderMercEnid != -1 { + mercs += fmt.Sprintf(". The defenders hired %s", entity(x.DefenderMercEnid)) + } + if x.DSupportMercEnid != -1 { + mercs += fmt.Sprintf(". The defenders hired %s as scouts", entity(x.DSupportMercEnid)) + } + return fmt.Sprintf("%s attacked %s at %s%s%s", atk, def, site(x.SiteId, ""), generals, mercs) +} + +func (x *HistoricalEventBodyAbused) Html() string { + s := "the " + util.If(len(x.Bodies) > 1, "bodies", "body") + " of " + hfList(x.Bodies) + " " + util.If(len(x.Bodies) > 1, "were", "was") + + switch x.AbuseType { + case HistoricalEventBodyAbusedAbuseType_Animated: + s += " animated" + util.If(x.Histfig != -1, " by "+hf(x.Histfig), "") + site(x.SiteId, " in ") + case HistoricalEventBodyAbusedAbuseType_Flayed: + s += " flayed and the skin stretched over " + structure(x.SiteId, x.Structure) + " by " + entity(x.Civ) + site(x.SiteId, " in ") + case HistoricalEventBodyAbusedAbuseType_Hung: + s += " hung from a tree by " + entity(x.Civ) + site(x.SiteId, " in ") + case HistoricalEventBodyAbusedAbuseType_Impaled: + s += " impaled on " + articled(x.ItemMat+" "+x.ItemSubtype.String()) + " by " + entity(x.Civ) + site(x.SiteId, " in ") + case HistoricalEventBodyAbusedAbuseType_Mutilated: + s += " horribly mutilated by " + entity(x.Civ) + site(x.SiteId, " in ") + case HistoricalEventBodyAbusedAbuseType_Piled: + s += " added to a " + switch x.PileType { + case HistoricalEventBodyAbusedPileType_Grislymound: + s += "grisly mound" + case HistoricalEventBodyAbusedPileType_Grotesquepillar: + s += "grotesque pillar" + case HistoricalEventBodyAbusedPileType_Gruesomesculpture: + s += "gruesome sculpture" + } + s += " by " + entity(x.Civ) + site(x.SiteId, " in ") + } + + return s +} + func (x *HistoricalEventBuildingProfileAcquired) Html() string { - return "UNKNWON HistoricalEventBuildingProfileAcquired" + return util.If(x.AcquirerEnid != -1, entity(x.AcquirerEnid), hf(x.AcquirerHfid)) + + util.If(x.PurchasedUnowned, " purchased ", " inherited ") + + property(x.SiteId, x.BuildingProfileId) + site(x.SiteId, " in") + + util.If(x.LastOwnerHfid != -1, " formerly owned by "+hf(x.LastOwnerHfid), "") } -func (x *HistoricalEventCeremony) Html() string { return "UNKNWON HistoricalEventCeremony" } + +func (x *HistoricalEventCeremony) Html() string { + r := entity(x.CivId) + " held a ceremony in " + site(x.SiteId, "") + if e, ok := world.Entities[x.CivId]; ok { + o := e.Occasion[x.OccasionId] + r += " as part of " + o.Name() + s := o.Schedule[x.ScheduleId] + if len(s.Feature) > 0 { + r += ". The event featured " + andList(util.Map(s.Feature, feature)) + } + } + return r +} + func (x *HistoricalEventChangeHfBodyState) Html() string { - return "UNKNWON HistoricalEventChangeHfBodyState" + r := hf(x.Hfid) + switch x.BodyState { + case HistoricalEventChangeHfBodyStateBodyState_EntombedAtSite: + r += " was entombed" + } + if x.StructureId != -1 { + r += " within " + structure(x.SiteId, x.StructureId) + } + r += site(x.SiteId, " in ") + return r +} + +func (x *HistoricalEventChangeHfJob) Html() string { + w := "" + if x.SubregionId != -1 { + w = " in " + region(x.SubregionId) + } + if x.SiteId != -1 { + w = " in " + site(x.SiteId, "") + } + old := articled(strcase.ToDelimited(x.OldJob, ' ')) + new := articled(strcase.ToDelimited(x.NewJob, ' ')) + if x.OldJob == "standard" { + return hf(x.Hfid) + " became " + new + w + } else if x.NewJob == "standard" { + return hf(x.Hfid) + " stopped being " + old + w + } else { + return hf(x.Hfid) + " gave up being " + old + " to become a " + new + w + } } -func (x *HistoricalEventChangeHfJob) Html() string { return "UNKNWON HistoricalEventChangeHfJob" } func (x *HistoricalEventChangeHfState) Html() string { + r := "" + switch x.Reason { + case HistoricalEventChangeHfStateReason_BeWithMaster: + r = " in order to be with the master" + case HistoricalEventChangeHfStateReason_ConvictionExile: + r = " after being exiled following a criminal conviction" + case HistoricalEventChangeHfStateReason_ExiledAfterConviction: + r = " after being exiled following a criminal conviction" + case HistoricalEventChangeHfStateReason_FailedMood: + r = " after failing to create an artifact" + case HistoricalEventChangeHfStateReason_Flight: + case HistoricalEventChangeHfStateReason_GatherInformation: + r = " to gather information" + case HistoricalEventChangeHfStateReason_GreatDealOfStress: + r = " after a great deal of stress" // TODO check + case HistoricalEventChangeHfStateReason_LackOfSleep: + r = " after a lack of sleep" // TODO check + case HistoricalEventChangeHfStateReason_OnAPilgrimage: + r = " on a pilgrimage" + case HistoricalEventChangeHfStateReason_Scholarship: + r = " in order to pursue scholarship" + case HistoricalEventChangeHfStateReason_UnableToLeaveLocation: + r = " after being unable to leave the location" // TODO check + } + switch x.State { + case HistoricalEventChangeHfStateState_Refugee: + return hf(x.Hfid) + " fled " + location(x.SiteId, "to", x.SubregionId, "into") case HistoricalEventChangeHfStateState_Settled: switch x.Reason { - case HistoricalEventChangeHfStateReason_BeWithMaster: - return hf(x.Hfid) + " moved to study " + site(x.SiteId, "in") + " in order to be with the master" - default: - return hf(x.Hfid) + " settled " + site(x.SiteId, "in") + case HistoricalEventChangeHfStateReason_BeWithMaster, HistoricalEventChangeHfStateReason_Scholarship: + return hf(x.Hfid) + " moved to study " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateReason_Flight: + return hf(x.Hfid) + " fled " + site(x.SiteId, "to") + case HistoricalEventChangeHfStateReason_ConvictionExile, HistoricalEventChangeHfStateReason_ExiledAfterConviction: + return hf(x.Hfid) + " departed " + site(x.SiteId, "to") + r + case HistoricalEventChangeHfStateReason_None: + return hf(x.Hfid) + " settled " + location(x.SiteId, "in", x.SubregionId, "in") } + case HistoricalEventChangeHfStateState_Visiting: + return hf(x.Hfid) + " visited " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateState_Wandering: + if x.SubregionId != -1 { + return hf(x.Hfid) + " began wandering " + region(x.SubregionId) + } else { + return hf(x.Hfid) + " began wandering the wilds" + } + } + + switch x.Mood { // todo catatonic + case HistoricalEventChangeHfStateMood_Berserk: + return hf(x.Hfid) + " went berserk " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Fell: + return hf(x.Hfid) + " was taken by a fell mood " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Fey: + return hf(x.Hfid) + " was taken by a fey mood " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Insane: + return hf(x.Hfid) + " became crazed " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Macabre: + return hf(x.Hfid) + " began to skulk and brood " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Melancholy: + return hf(x.Hfid) + " was striken by melancholy " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Possessed: + return hf(x.Hfid) + " was posessed " + site(x.SiteId, "in") + r + case HistoricalEventChangeHfStateMood_Secretive: + return hf(x.Hfid) + " withdrew from society " + site(x.SiteId, "in") + r } return "UNKNWON HistoricalEventChangeHfState" } diff --git a/backend/model/extensions.go b/backend/model/extensions.go index 8c63936..709ae46 100644 --- a/backend/model/extensions.go +++ b/backend/model/extensions.go @@ -2,7 +2,10 @@ package model import ( "fmt" + "regexp" + "strings" + "github.com/iancoleman/strcase" "github.com/robertjanetzko/LegendsBrowser2/backend/util" ) @@ -54,6 +57,20 @@ func containsInt(list []int, id int) bool { var world *DfWorld +func andList(list []string) string { + if len(list) > 1 { + return strings.Join(list[:len(list)-1], ", ") + " and " + list[len(list)-1] + } + return strings.Join(list, ", ") +} + +func articled(s string) string { + if ok, _ := regexp.MatchString("^([aeio]|un|ul).*", s); ok { + return "an " + s + } + return "a " + s +} + func artifact(id int) string { if x, ok := world.Artifacts[id]; ok { return fmt.Sprintf(`%s`, x.Id(), util.Title(x.Name())) @@ -75,6 +92,10 @@ func hf(id int) string { return "UNKNOWN HISTORICAL FIGURE" } +func hfList(ids []int) string { + return andList(util.Map(ids, hf)) +} + func pronoun(id int) string { if x, ok := world.HistoricalFigures[id]; ok { if x.Female() { @@ -100,6 +121,18 @@ func structure(siteId, structureId int) string { return "UNKNOWN STRUCTURE" } +func property(siteId, propertyId int) string { + if x, ok := world.Sites[siteId]; ok { + if y, ok := x.SiteProperties[propertyId]; ok { + if y.StructureId != -1 { + return structure(siteId, y.StructureId) + } + return articled(y.Type.String()) + } + } + return "UNKNOWN PROPERTY" +} + func region(id int) string { if x, ok := world.Regions[id]; ok { return fmt.Sprintf(`%s`, x.Id(), util.Title(x.Name())) @@ -107,9 +140,63 @@ func region(id int) string { return "UNKNOWN REGION" } +func location(siteId int, sitePrefix string, regionId int, regionPrefix string) string { + if siteId != -1 { + return site(siteId, sitePrefix) + } + if regionId != -1 { + return regionPrefix + " " + region(regionId) + } + return "" +} + func identity(id int) string { if x, ok := world.Identities[id]; ok { return fmt.Sprintf(`%s`, x.Id(), util.Title(x.Name())) } return "UNKNOWN IDENTITY" } + +func feature(x *Feature) string { + switch x.Type { + case FeatureType_DancePerformance: + return "a perfomance of " + danceForm(x.Reference) + case FeatureType_Images: + if x.Reference != -1 { + return "images of " + hf(x.Reference) + } + return "images" + case FeatureType_MusicalPerformance: + return "a perfomance of " + musicalForm(x.Reference) + case FeatureType_PoetryRecital: + return "a recital of " + poeticForm(x.Reference) + case FeatureType_Storytelling: + if x.Reference != -1 { + return "a telling of the story of " + hf(x.Reference) + } + return "a story recital" + default: + return strcase.ToDelimited(x.Type.String(), ' ') + } +} + +func danceForm(id int) string { + if x, ok := world.DanceForms[id]; ok { + return fmt.Sprintf(`%s`, id, util.Title(x.Name())) + } + return "UNKNOWN DANCE FORM" +} + +func musicalForm(id int) string { + if x, ok := world.MusicalForms[id]; ok { + return fmt.Sprintf(`%s`, id, util.Title(x.Name())) + } + return "UNKNOWN MUSICAL FORM" +} + +func poeticForm(id int) string { + if x, ok := world.PoeticForms[id]; ok { + return fmt.Sprintf(`%s`, id, util.Title(x.Name())) + } + return "UNKNOWN POETIC FORM" +} diff --git a/backend/same.json b/backend/same.json index 18bffaf..667fffd 100644 --- a/backend/same.json +++ b/backend/same.json @@ -5,14 +5,6 @@ "HistoricalEventAddHfSiteLink": { "Site": "SiteId" }, - "HistoricalEventCreatedStructure": { - "Structure": "StructureId" - }, - "HistoricalEventDiplomatLost": { - "Entity": "SiteId", - "Involved": "SiteId", - "Site": "SiteId" - }, "HistoricalEventPeaceAccepted": { "Site": "SiteId" }, @@ -25,7 +17,11 @@ "HistoricalEventRemoveHfSiteLink": { "Site": "SiteId" }, - "HistoricalFigure": { - "Sex": "BreedId" + "HistoricalEventReplacedStructure": { + "Civ": "OldAbId", + "NewStructure": "OldAbId", + "OldStructure": "OldAbId", + "Site": "OldAbId", + "SiteCiv": "OldAbId" } } \ No newline at end of file diff --git a/backend/static/css/legends.css b/backend/static/css/legends.css index a8ae341..7cb0ba2 100644 --- a/backend/static/css/legends.css +++ b/backend/static/css/legends.css @@ -55,7 +55,7 @@ a { } .json { - color: #ddd; + color: #aaa; font-size: 50%; } diff --git a/backend/util/util.go b/backend/util/util.go index 217ead8..ad7e6b0 100644 --- a/backend/util/util.go +++ b/backend/util/util.go @@ -46,6 +46,10 @@ func Title(input string) string { return strings.Join(words, " ") } +func Capitalize(input string) string { + return strings.ToUpper(input[:1]) + input[1:] +} + func Json(obj any) template.HTML { b, err := json.MarshalIndent(obj, "", " ") if err != nil { @@ -54,3 +58,19 @@ func Json(obj any) template.HTML { } return template.HTML(`` + string(b) + ``) } + +func If[T any](cond bool, v1, v2 T) T { + if cond { + return v1 + } else { + return v2 + } +} + +func Map[U, V any](list []U, mapper func(U) V) []V { + var newList = make([]V, 0, len(list)) + for _, i := range list { + newList = append(newList, mapper(i)) + } + return newList +}