diff --git a/analyze/df/generate_backend.go b/analyze/df/generate_backend.go index b5277c3..25537c1 100644 --- a/analyze/df/generate_backend.go +++ b/analyze/df/generate_backend.go @@ -162,6 +162,12 @@ func (x *{{ $obj.Name }}) MarshalJSON() ([]byte, error) { {{- range $fname, $field := $obj.Fields }}{{- if not ($field.SameField $obj) }}{{- if not (and (eq $fname "type") (not (not $obj.SubTypes))) }} {{ $field.JsonMarshal }} {{- end }}{{- end }}{{- end }} + {{- if not (not $obj.SubTypes) }} + d["details"] = x.Details + {{- end }} + {{- range $fname, $field := $obj.Additional }} + {{ $field.JsonMarshal }} + {{- end }} return json.Marshal(d) } @@ -399,6 +405,9 @@ func (f Field) StartAction(obj Object, plus bool) string { return fmt.Sprintf("%sobj.%s = append(obj.%s, num(data))", s, n, n) } else if f.Type == "string" { return fmt.Sprintf("%sobj.%s = append(obj.%s, txt(data))", s, n, n) + } else if f.Type == "bool" { + s := "_, err := p.Value()\nif err != nil { return nil, err }\n" + return fmt.Sprintf("%sobj.%s = append(obj.%s, true)", s, n, n) } else if f.Type == "enum" { return fmt.Sprintf("%sobj.%s = append(obj.%s, parse%s%s(txt(data)))", s, n, n, obj.Name, f.CorrectedName(obj)) } diff --git a/analyze/overwrites.json b/analyze/overwrites.json index 97e4d93..db937fd 100644 --- a/analyze/overwrites.json +++ b/analyze/overwrites.json @@ -62,6 +62,54 @@ "Name": "Ruin", "Type": "bool" } + ], + "HistoricalEvent": [ + { + "Name": "Collection", + "Type": "int" + } + ], + "HistoricalEventCollectionAbduction": [ + { + "Name": "TargetHfids", + "Type": "[]int" + } + ], + "HistoricalEventCollectionBeastAttack": [ + { + "Name": "AttackerHfIds", + "Type": "[]int" + } + ], + "HistoricalEventCollectionJourney": [ + { + "Name": "TravellerHfIds", + "Type": "[]int" + } + ], + "HistoricalEventCollectionCeremony": [ + { + "Name": "OccasionEventcol", + "Type": "int" + } + ], + "HistoricalEventCollectionCompetition": [ + { + "Name": "OccasionEventcol", + "Type": "int" + } + ], + "HistoricalEventCollectionPerformance": [ + { + "Name": "OccasionEventcol", + "Type": "int" + } + ], + "HistoricalEventCollectionProcession": [ + { + "Name": "OccasionEventcol", + "Type": "int" + } ] } } \ No newline at end of file diff --git a/backend/model/collections.go b/backend/model/collections.go new file mode 100644 index 0000000..311244f --- /dev/null +++ b/backend/model/collections.go @@ -0,0 +1,187 @@ +package model + +import ( + "fmt" + + humanize "github.com/dustin/go-humanize" + "github.com/iancoleman/strcase" + "github.com/robertjanetzko/LegendsBrowser2/backend/util" +) + +func (x *HistoricalEventCollection) Link(s string) string { + return fmt.Sprintf(`%s`, strcase.ToKebab(x.Details.Type()), x.Id_, util.Title(s)) +} + +func (x *HistoricalEventCollection) ParentId() int { + switch t := x.Details.(type) { + case *HistoricalEventCollectionAbduction: + return t.ParentEventcol + case *HistoricalEventCollectionBattle: + return t.WarEventcol + case *HistoricalEventCollectionBeastAttack: + return t.ParentEventcol + case *HistoricalEventCollectionDuel: + return t.ParentEventcol + case *HistoricalEventCollectionRaid: + return t.ParentEventcol + case *HistoricalEventCollectionSiteConquered: + return t.WarEventcol + case *HistoricalEventCollectionTheft: + return t.ParentEventcol + } + return -1 +} + +func ord(ordinal int) string { + switch ordinal { + case 1: + return "" + case 2: + return "second" + " " + case 3: + return "third" + " " + } + return humanize.Ordinal(ordinal) + " " +} + +func (x *HistoricalEventCollectionAbduction) Html(e *HistoricalEventCollection, c *Context) string { + loc := c.location(x.SiteId, " at", x.SubregionId, " at") + switch l := len(x.TargetHfids); { + case l == 0: + return "the " + e.Link(ord(x.Ordinal)+"attempted abduction") + loc + case l == 1: + return "the " + e.Link(ord(x.Ordinal)+"abduction") + " of " + c.hf(x.TargetHfids[0]) + loc + } + return "the " + e.Link(ord(x.Ordinal)+"abduction") + loc +} + +func (x *HistoricalEventCollectionBattle) Html(e *HistoricalEventCollection, c *Context) string { + return e.Link(util.Title(x.Name_)) +} + +func (x *HistoricalEventCollectionBeastAttack) Html(e *HistoricalEventCollection, c *Context) string { + r := "the " + switch l := len(x.AttackerHfIds); { + case l == 1: + r += e.Link(ord(x.Ordinal)+"rampage") + " of " + c.hf(x.AttackerHfIds[0]) + case l > 1: + if hf, ok := c.World.HistoricalFigures[x.AttackerHfIds[0]]; ok { + r += e.Link(ord(x.Ordinal) + hf.Race + " " + "rampage") + } + default: + r += e.Link(ord(x.Ordinal) + "rampage") + } + r += c.location(x.SiteId, " in", x.SubregionId, " in") + return r +} + +func (x *HistoricalEventCollectionCeremony) Html(e *HistoricalEventCollection, c *Context) string { + r := "ceremony" + if len(e.Event) > 0 { + if event, ok := c.World.HistoricalEvents[e.Event[0]]; ok { + if d, ok := event.Details.(*HistoricalEventCeremony); ok { + if entity, ok := c.World.Entities[d.CivId]; ok { + occ := entity.Occasion[d.OccasionId] + if len(occ.Schedule) > 1 { + switch d.ScheduleId { + case 0: + r = "opening ceremony" + case len(occ.Schedule) - 1: + r = "closing ceremony" + default: + r = "main ceremony" + } + } + } + } + } + } + return "the " + e.Link(ord(x.Ordinal)+r) + " of " + c.collection(x.OccasionEventcol) +} + +func (x *HistoricalEventCollectionCompetition) Html(e *HistoricalEventCollection, c *Context) string { + r := "competition" + if len(e.Event) > 0 { + if event, ok := c.World.HistoricalEvents[e.Event[0]]; ok { + if d, ok := event.Details.(*HistoricalEventCompetition); ok { + if entity, ok := c.World.Entities[d.CivId]; ok { + occ := entity.Occasion[d.OccasionId] + r = occ.Schedule[d.ScheduleId].Type_.String() + } + } + } + } + return "the " + e.Link(ord(x.Ordinal)+r) + " of " + c.collection(x.OccasionEventcol) +} + +func (x *HistoricalEventCollectionDuel) Html(e *HistoricalEventCollection, c *Context) string { + r := "the " + r += e.Link(ord(x.Ordinal)+"duel") + " of " + c.hf(x.AttackingHfid) + " and " + c.hfRelated(x.DefendingHfid, x.AttackingHfid) + r += c.location(x.SiteId, " in", x.SubregionId, " in") + return r +} + +func (x *HistoricalEventCollectionEntityOverthrown) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"overthrow") + " of " + c.entity(x.TargetEntityId) + c.site(x.SiteId, " in") +} + +func (x *HistoricalEventCollectionInsurrection) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"insurrection") + c.site(x.SiteId, " at") +} + +func (x *HistoricalEventCollectionJourney) Html(e *HistoricalEventCollection, c *Context) string { + r := "the " + r += e.Link(ord(x.Ordinal)+"journey") + " of " + c.hfList(x.TravellerHfIds) + return r +} + +func (x *HistoricalEventCollectionOccasion) Html(e *HistoricalEventCollection, c *Context) string { + if civ, ok := c.World.Entities[x.CivId]; ok { + occ := civ.Occasion[x.OccasionId] + return util.If(x.Ordinal > 1, "the "+ord(x.Ordinal)+"occasion of ", "") + e.Link(occ.Name_) + } + return util.If(x.Ordinal > 1, "the "+ord(x.Ordinal)+"occasion of ", "") + e.Link("UNKNOWN OCCASION") +} + +func (x *HistoricalEventCollectionPerformance) Html(e *HistoricalEventCollection, c *Context) string { + r := "performance" + if len(e.Event) > 0 { + if event, ok := c.World.HistoricalEvents[e.Event[0]]; ok { + if d, ok := event.Details.(*HistoricalEventPerformance); ok { + if entity, ok := c.World.Entities[d.CivId]; ok { + occ := entity.Occasion[d.OccasionId] + r = occ.Schedule[d.ScheduleId].Type_.String() + } + } + } + } + return "the " + e.Link(ord(x.Ordinal)+r) + " of " + c.collection(x.OccasionEventcol) +} + +func (x *HistoricalEventCollectionPersecution) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"persecution") + " of " + c.entity(x.TargetEntityId) + c.site(x.SiteId, " in") +} + +func (x *HistoricalEventCollectionProcession) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"procession") + " of " + c.collection(x.OccasionEventcol) +} + +func (x *HistoricalEventCollectionPurge) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+x.Adjective.String()+" purge") + c.site(x.SiteId, " in") +} + +func (x *HistoricalEventCollectionRaid) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"raid") + c.site(x.SiteId, " at") +} + +func (x *HistoricalEventCollectionSiteConquered) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"pillaging") + c.site(x.SiteId, " of") +} + +func (x *HistoricalEventCollectionTheft) Html(e *HistoricalEventCollection, c *Context) string { + return "the " + e.Link(ord(x.Ordinal)+"theft") + c.site(x.SiteId, " at") +} + +func (x *HistoricalEventCollectionWar) Html(e *HistoricalEventCollection, c *Context) string { + return e.Link(util.Title(x.Name_)) +} diff --git a/backend/model/context.go b/backend/model/context.go index 4397d7c..8bca9c5 100644 --- a/backend/model/context.go +++ b/backend/model/context.go @@ -74,14 +74,14 @@ func (c *Context) hfListRelated(ids []int, to int) string { func (c *Context) artifact(id int) string { if x, ok := c.World.Artifacts[id]; ok { - return fmt.Sprintf(` %s`, x.Id(), x.Icon(), util.Title(x.Name())) + return fmt.Sprintf(` %s`, x.Id(), x.Icon(), util.Title(x.Name())) } return "UNKNOWN ARTIFACT" } func (c *Context) entity(id int) string { if x, ok := c.World.Entities[id]; ok { - return fmt.Sprintf(` %s`, x.Id(), x.Icon(), util.Title(x.Name())) + return fmt.Sprintf(` %s`, x.Id(), x.Icon(), util.Title(x.Name())) } return "UNKNOWN ENTITY" } @@ -115,7 +115,7 @@ func (c *Context) siteStructure(siteId, structureId int, prefix string) string { func (c *Context) site(id int, prefix string) string { if x, ok := c.World.Sites[id]; ok { - return fmt.Sprintf(`%s  %s`, prefix, x.Id(), x.Icon(), util.Title(x.Name())) + return fmt.Sprintf(`%s %s`, prefix, x.Id(), x.Icon(), util.Title(x.Name())) } return "UNKNOWN SITE" } @@ -123,7 +123,7 @@ func (c *Context) site(id int, prefix string) string { func (c *Context) structure(siteId, structureId int) string { if x, ok := c.World.Sites[siteId]; ok { if y, ok := x.Structures[structureId]; ok { - return fmt.Sprintf(` %s`, siteId, structureId, y.Icon(), util.Title(y.Name())) + return fmt.Sprintf(` %s`, siteId, structureId, y.Icon(), util.Title(y.Name())) } } return "UNKNOWN STRUCTURE" @@ -191,28 +191,28 @@ func (c *Context) fullIdentity(id int) string { func (c *Context) danceForm(id int) string { if x, ok := c.World.DanceForms[id]; ok { - return fmt.Sprintf(` %s`, id, util.Title(x.Name())) + return fmt.Sprintf(` %s`, id, util.Title(x.Name())) } return "UNKNOWN DANCE FORM" } func (c *Context) musicalForm(id int) string { if x, ok := c.World.MusicalForms[id]; ok { - return fmt.Sprintf(` %s`, id, util.Title(x.Name())) + return fmt.Sprintf(` %s`, id, util.Title(x.Name())) } return "UNKNOWN MUSICAL FORM" } func (c *Context) poeticForm(id int) string { if x, ok := c.World.PoeticForms[id]; ok { - return fmt.Sprintf(` %s`, id, util.Title(x.Name())) + return fmt.Sprintf(` %s`, id, util.Title(x.Name())) } return "UNKNOWN POETIC FORM" } func (c *Context) worldConstruction(id int) string { if x, ok := c.World.WorldConstructions[id]; ok { - return fmt.Sprintf(` %s`, id, x.Icon(), util.Title(x.Name())) + return fmt.Sprintf(` %s`, id, x.Icon(), util.Title(x.Name())) } return "UNKNOWN WORLD CONSTRUCTION" } @@ -224,6 +224,13 @@ func (c *Context) writtenContent(id int) string { return "UNKNOWN WORLD CONSTRUCTION" } +func (c *Context) collection(id int) string { + if x, ok := c.World.HistoricalEventCollections[id]; ok { + return x.Details.Html(x, c) + } + return "UNKNOWN EVENT COLLECTION" +} + func (c *Context) feature(x *Feature) string { switch x.Type_ { case FeatureType_DancePerformance: diff --git a/backend/model/eventList.go b/backend/model/eventList.go index b5c6003..cab069c 100644 --- a/backend/model/eventList.go +++ b/backend/model/eventList.go @@ -2,6 +2,8 @@ package model import ( "fmt" + + "github.com/robertjanetzko/LegendsBrowser2/backend/util" ) type HistoricalEventDetails interface { @@ -16,6 +18,8 @@ type HistoricalEventDetails interface { } type HistoricalEventCollectionDetails interface { + Type() string + Html(*HistoricalEventCollection, *Context) string } type EventList struct { @@ -48,6 +52,8 @@ func NewEventList(world *DfWorld, obj any) *EventList { el.Events = world.EventsMatching(func(d HistoricalEventDetails) bool { return d.RelatedToRegion(x.Id()) }) case []*HistoricalEvent: el.Events = x + case []int: + el.Events = util.Map(x, func(id int) *HistoricalEvent { return world.HistoricalEvents[id] }) default: fmt.Printf("unknown type %T\n", obj) } diff --git a/backend/model/extensions.go b/backend/model/extensions.go index b8690e5..c02bd52 100644 --- a/backend/model/extensions.go +++ b/backend/model/extensions.go @@ -63,6 +63,20 @@ func (w *DfWorld) SiteHistory(siteId int) []*HistoricalEvent { return list } +func (c *HistoricalEventCollection) Type() string { + if c.Details == nil { + return "unk" + } + return c.Details.Type() +} + +func (e *HistoricalEventCollection) Html(c *Context) string { + if e.Details == nil { + return "unk" + } + return e.Details.Html(e, c) +} + func (e *Artifact) Type() string { switch e.ItemSubtype { case "scroll": diff --git a/backend/model/functions.go b/backend/model/functions.go index 451fe4d..bf28578 100644 --- a/backend/model/functions.go +++ b/backend/model/functions.go @@ -23,6 +23,7 @@ var LinkDanceForm = func(w *DfWorld, id int) template.HTML { return template.HTM var LinkMusicalForm = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).musicalForm(id)) } var LinkPoeticForm = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).poeticForm(id)) } var LinkWrittenContent = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).writtenContent(id)) } +var LinkCollection = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).collection(id)) } var AddMapSite = func(w *DfWorld, id int) template.HTML { if site, ok := w.Sites[id]; ok { diff --git a/backend/model/model.go b/backend/model/model.go index fe00959..4ca92a6 100644 --- a/backend/model/model.go +++ b/backend/model/model.go @@ -1631,6 +1631,19 @@ func (x *DfWorld) MarshalJSON() ([]byte, error) { d["undergroundRegions"] = x.UndergroundRegions d["worldConstructions"] = x.WorldConstructions d["writtenContents"] = x.WrittenContents + if x.EndYear != -1 { + d["endYear"] = x.EndYear + } + d["filePath"] = x.FilePath + if x.Height != -1 { + d["height"] = x.Height + } + d["mapData"] = x.MapData + d["mapReady"] = x.MapReady + d["plusFilePath"] = x.PlusFilePath + if x.Width != -1 { + d["width"] = x.Width + } return json.Marshal(d) } @@ -2045,6 +2058,7 @@ func (x *Entity) MarshalJSON() ([]byte, error) { } d["weapon"] = x.Weapon d["worshipId"] = x.WorshipId + d["sites"] = x.Sites return json.Marshal(d) } @@ -2819,17 +2833,19 @@ func (x *HistoricalEra) MarshalJSON() ([]byte, error) { } type HistoricalEvent struct { - Id_ int `json:"id" legend:"both"` // id - Seconds72 int `json:"seconds72" legend:"base"` // seconds72 - Year int `json:"year" legend:"base"` // year - Details HistoricalEventDetails + Id_ int `json:"id" legend:"both"` // id + Seconds72 int `json:"seconds72" legend:"base"` // seconds72 + Year int `json:"year" legend:"base"` // year + Details HistoricalEventDetails + Collection int `json:"collection" legend:"add"` // Collection } func NewHistoricalEvent() *HistoricalEvent { return &HistoricalEvent{ - Id_: -1, - Seconds72: -1, - Year: -1, + Id_: -1, + Seconds72: -1, + Year: -1, + Collection: -1, } } func (x *HistoricalEvent) Id() int { return x.Id_ } @@ -2855,6 +2871,10 @@ func (x *HistoricalEvent) MarshalJSON() ([]byte, error) { if x.Year != -1 { d["year"] = x.Year } + d["details"] = x.Details + if x.Collection != -1 { + d["collection"] = x.Collection + } return json.Marshal(d) } @@ -5915,6 +5935,7 @@ func (x *HistoricalEventCollection) MarshalJSON() ([]byte, error) { if x.StartYear != -1 { d["startYear"] = x.StartYear } + d["details"] = x.Details return json.Marshal(d) } @@ -5927,6 +5948,7 @@ type HistoricalEventCollectionAbduction struct { ParentEventcol int `json:"parentEventcol" legend:"base"` // parent_eventcol SiteId int `json:"siteId" legend:"base"` // site_id SubregionId int `json:"subregionId" legend:"base"` // subregion_id + TargetHfids []int `json:"targetHfids" legend:"add"` // TargetHfids } func NewHistoricalEventCollectionAbduction() *HistoricalEventCollectionAbduction { @@ -5977,6 +5999,7 @@ func (x *HistoricalEventCollectionAbduction) MarshalJSON() ([]byte, error) { if x.SubregionId != -1 { d["subregionId"] = x.SubregionId } + d["targetHfids"] = x.TargetHfids return json.Marshal(d) } @@ -6136,6 +6159,7 @@ type HistoricalEventCollectionBeastAttack struct { ParentEventcol int `json:"parentEventcol" legend:"base"` // parent_eventcol SiteId int `json:"siteId" legend:"base"` // site_id SubregionId int `json:"subregionId" legend:"base"` // subregion_id + AttackerHfIds []int `json:"attackerHfIds" legend:"add"` // AttackerHfIds } func NewHistoricalEventCollectionBeastAttack() *HistoricalEventCollectionBeastAttack { @@ -6184,16 +6208,19 @@ func (x *HistoricalEventCollectionBeastAttack) MarshalJSON() ([]byte, error) { if x.SubregionId != -1 { d["subregionId"] = x.SubregionId } + d["attackerHfIds"] = x.AttackerHfIds return json.Marshal(d) } type HistoricalEventCollectionCeremony struct { - Ordinal int `json:"ordinal" legend:"base"` // ordinal + Ordinal int `json:"ordinal" legend:"base"` // ordinal + OccasionEventcol int `json:"occasionEventcol" legend:"add"` // OccasionEventcol } func NewHistoricalEventCollectionCeremony() *HistoricalEventCollectionCeremony { return &HistoricalEventCollectionCeremony{ - Ordinal: -1, + Ordinal: -1, + OccasionEventcol: -1, } } func (x *HistoricalEventCollectionCeremony) Type() string { return "ceremony" } @@ -6212,16 +6239,21 @@ func (x *HistoricalEventCollectionCeremony) MarshalJSON() ([]byte, error) { if x.Ordinal != -1 { d["ordinal"] = x.Ordinal } + if x.OccasionEventcol != -1 { + d["occasionEventcol"] = x.OccasionEventcol + } return json.Marshal(d) } type HistoricalEventCollectionCompetition struct { - Ordinal int `json:"ordinal" legend:"base"` // ordinal + Ordinal int `json:"ordinal" legend:"base"` // ordinal + OccasionEventcol int `json:"occasionEventcol" legend:"add"` // OccasionEventcol } func NewHistoricalEventCollectionCompetition() *HistoricalEventCollectionCompetition { return &HistoricalEventCollectionCompetition{ - Ordinal: -1, + Ordinal: -1, + OccasionEventcol: -1, } } func (x *HistoricalEventCollectionCompetition) Type() string { return "competition" } @@ -6240,6 +6272,9 @@ func (x *HistoricalEventCollectionCompetition) MarshalJSON() ([]byte, error) { if x.Ordinal != -1 { d["ordinal"] = x.Ordinal } + if x.OccasionEventcol != -1 { + d["occasionEventcol"] = x.OccasionEventcol + } return json.Marshal(d) } @@ -6388,7 +6423,8 @@ func (x *HistoricalEventCollectionInsurrection) MarshalJSON() ([]byte, error) { } type HistoricalEventCollectionJourney struct { - Ordinal int `json:"ordinal" legend:"base"` // ordinal + Ordinal int `json:"ordinal" legend:"base"` // ordinal + TravellerHfIds []int `json:"travellerHfIds" legend:"add"` // TravellerHfIds } func NewHistoricalEventCollectionJourney() *HistoricalEventCollectionJourney { @@ -6412,6 +6448,7 @@ func (x *HistoricalEventCollectionJourney) MarshalJSON() ([]byte, error) { if x.Ordinal != -1 { d["ordinal"] = x.Ordinal } + d["travellerHfIds"] = x.TravellerHfIds return json.Marshal(d) } @@ -6454,12 +6491,14 @@ func (x *HistoricalEventCollectionOccasion) MarshalJSON() ([]byte, error) { } type HistoricalEventCollectionPerformance struct { - Ordinal int `json:"ordinal" legend:"base"` // ordinal + Ordinal int `json:"ordinal" legend:"base"` // ordinal + OccasionEventcol int `json:"occasionEventcol" legend:"add"` // OccasionEventcol } func NewHistoricalEventCollectionPerformance() *HistoricalEventCollectionPerformance { return &HistoricalEventCollectionPerformance{ - Ordinal: -1, + Ordinal: -1, + OccasionEventcol: -1, } } func (x *HistoricalEventCollectionPerformance) Type() string { return "performance" } @@ -6478,6 +6517,9 @@ func (x *HistoricalEventCollectionPerformance) MarshalJSON() ([]byte, error) { if x.Ordinal != -1 { d["ordinal"] = x.Ordinal } + if x.OccasionEventcol != -1 { + d["occasionEventcol"] = x.OccasionEventcol + } return json.Marshal(d) } @@ -6522,12 +6564,14 @@ func (x *HistoricalEventCollectionPersecution) MarshalJSON() ([]byte, error) { } type HistoricalEventCollectionProcession struct { - Ordinal int `json:"ordinal" legend:"base"` // ordinal + Ordinal int `json:"ordinal" legend:"base"` // ordinal + OccasionEventcol int `json:"occasionEventcol" legend:"add"` // OccasionEventcol } func NewHistoricalEventCollectionProcession() *HistoricalEventCollectionProcession { return &HistoricalEventCollectionProcession{ - Ordinal: -1, + Ordinal: -1, + OccasionEventcol: -1, } } func (x *HistoricalEventCollectionProcession) Type() string { return "procession" } @@ -6546,6 +6590,9 @@ func (x *HistoricalEventCollectionProcession) MarshalJSON() ([]byte, error) { if x.Ordinal != -1 { d["ordinal"] = x.Ordinal } + if x.OccasionEventcol != -1 { + d["occasionEventcol"] = x.OccasionEventcol + } return json.Marshal(d) } @@ -18172,6 +18219,8 @@ func (x *HistoricalFigure) MarshalJSON() ([]byte, error) { d["sphere"] = x.Sphere d["usedIdentityId"] = x.UsedIdentityId d["vagueRelationship"] = x.VagueRelationship + d["vampire"] = x.Vampire + d["werebeast"] = x.Werebeast return json.Marshal(d) } @@ -20434,6 +20483,7 @@ func (x *Site) MarshalJSON() ([]byte, error) { if x.Type_ != 0 { d["type"] = x.Type_ } + d["ruin"] = x.Ruin return json.Marshal(d) } @@ -20855,6 +20905,9 @@ func (x *Structure) MarshalJSON() ([]byte, error) { if x.WorshipHfid != -1 { d["worshipHfid"] = x.WorshipHfid } + if x.SiteId != -1 { + d["siteId"] = x.SiteId + } return json.Marshal(d) } @@ -27040,7 +27093,11 @@ func parseHistoricalEventCollectionBattle(p *util.XMLParser) (*HistoricalEventCo } obj.AttackingMercEnid = num(data) case "attacking_squad_animated": - + _, err := p.Value() + if err != nil { + return nil, err + } + obj.AttackingSquadAnimated = append(obj.AttackingSquadAnimated, true) case "attacking_squad_deaths": data, err := p.Value() if err != nil { @@ -27072,7 +27129,11 @@ func parseHistoricalEventCollectionBattle(p *util.XMLParser) (*HistoricalEventCo } obj.AttackingSquadSite = append(obj.AttackingSquadSite, num(data)) case "company_merc": - + _, err := p.Value() + if err != nil { + return nil, err + } + obj.CompanyMerc = append(obj.CompanyMerc, true) case "coords": data, err := p.Value() if err != nil { @@ -27104,7 +27165,11 @@ func parseHistoricalEventCollectionBattle(p *util.XMLParser) (*HistoricalEventCo } obj.DefendingMercEnid = num(data) case "defending_squad_animated": - + _, err := p.Value() + if err != nil { + return nil, err + } + obj.DefendingSquadAnimated = append(obj.DefendingSquadAnimated, true) case "defending_squad_deaths": data, err := p.Value() if err != nil { @@ -27142,7 +27207,11 @@ func parseHistoricalEventCollectionBattle(p *util.XMLParser) (*HistoricalEventCo } obj.FeatureLayerId = num(data) case "individual_merc": - + _, err := p.Value() + if err != nil { + return nil, err + } + obj.IndividualMerc = append(obj.IndividualMerc, true) case "name": data, err := p.Value() if err != nil { diff --git a/backend/model/parse.go b/backend/model/parse.go index d4fdf15..193d48e 100644 --- a/backend/model/parse.go +++ b/backend/model/parse.go @@ -13,8 +13,7 @@ import ( "github.com/robertjanetzko/LegendsBrowser2/backend/util" ) -func (e *HistoricalEvent) Name() string { return "" } -func (e *HistoricalEventCollection) Name() string { return "" } +func (e *HistoricalEvent) Name() string { return "" } func NewLegendsDecoder(file string) (*xml.Decoder, *os.File, *pb.ProgressBar, error) { fi, err := os.Stat(file) diff --git a/backend/model/process.go b/backend/model/process.go index 8a143b1..92bd556 100644 --- a/backend/model/process.go +++ b/backend/model/process.go @@ -3,6 +3,7 @@ package model import ( "strings" + "github.com/robertjanetzko/LegendsBrowser2/backend/util" "golang.org/x/exp/slices" ) @@ -16,6 +17,7 @@ func (w *DfWorld) process() { } w.processEvents() + w.processCollections() // check events texts for _, e := range w.HistoricalEvents { @@ -57,6 +59,79 @@ func (w *DfWorld) processEvents() { } } +func (w *DfWorld) processCollections() { + for _, col := range w.HistoricalEventCollections { + for _, eventId := range col.Event { + if e, ok := w.HistoricalEvents[eventId]; ok { + e.Collection = col.Id_ + } + } + + switch cd := col.Details.(type) { + case *HistoricalEventCollectionAbduction: + targets := make(map[int]bool) + for _, eventId := range col.Event { + if e, ok := w.HistoricalEvents[eventId]; ok { + switch d := e.Details.(type) { + case *HistoricalEventHfAbducted: + targets[d.TargetHfid] = true + } + } + } + delete(targets, -1) + cd.TargetHfids = util.Keys(targets) + case *HistoricalEventCollectionBeastAttack: + attackers := make(map[int]bool) + for _, eventId := range col.Event { + if e, ok := w.HistoricalEvents[eventId]; ok { + switch d := e.Details.(type) { + case *HistoricalEventHfSimpleBattleEvent: + attackers[d.Group1Hfid] = true + case *HistoricalEventHfAttackedSite: + attackers[d.AttackerHfid] = true + case *HistoricalEventHfDestroyedSite: + attackers[d.AttackerHfid] = true + case *HistoricalEventAddHfEntityLink: + attackers[d.Hfid] = true + case *HistoricalEventCreatureDevoured: + attackers[d.Eater] = true + case *HistoricalEventItemStolen: + attackers[d.Histfig] = true + } + } + } + delete(attackers, -1) + cd.AttackerHfIds = util.Keys(attackers) + case *HistoricalEventCollectionJourney: + HistoricalEventCollectionJourneyLoop: + for _, eventId := range col.Event { + if e, ok := w.HistoricalEvents[eventId]; ok { + switch d := e.Details.(type) { + case *HistoricalEventHfTravel: + cd.TravellerHfIds = d.GroupHfid + break HistoricalEventCollectionJourneyLoop + } + } + } + case *HistoricalEventCollectionOccasion: + for _, eventcolId := range col.Eventcol { + if e, ok := w.HistoricalEventCollections[eventcolId]; ok { + switch d := e.Details.(type) { + case *HistoricalEventCollectionCeremony: + d.OccasionEventcol = col.Id_ + case *HistoricalEventCollectionCompetition: + d.OccasionEventcol = col.Id_ + case *HistoricalEventCollectionPerformance: + d.OccasionEventcol = col.Id_ + case *HistoricalEventCollectionProcession: + d.OccasionEventcol = col.Id_ + } + } + } + } + } +} + func (w *DfWorld) addEntitySite(entityId, siteId int) { if e, ok := w.Entities[entityId]; ok { if !slices.Contains(e.Sites, siteId) { diff --git a/backend/server/resource.go b/backend/server/resource.go index 67a7a04..62caa58 100644 --- a/backend/server/resource.go +++ b/backend/server/resource.go @@ -26,7 +26,7 @@ func (srv *DfServer) RegisterWorldPage(path string, template string, accessor fu err := srv.templates.Render(w, template, data) if err != nil { - fmt.Fprintln(w, err) + fmt.Fprint(w, err) fmt.Println(err) } } diff --git a/backend/server/server.go b/backend/server/server.go index 8cc382a..7aa56f6 100644 --- a/backend/server/server.go +++ b/backend/server/server.go @@ -4,6 +4,7 @@ import ( "embed" "fmt" "net/http" + "os" "sort" "strconv" @@ -93,6 +94,16 @@ func StartServer(world *model.DfWorld, static embed.FS) error { srv.RegisterWorldPage("/events", "eventTypes.html", func(p Parms) any { return srv.context.world.AllEventTypes() }) srv.RegisterWorldPage("/events/{type}", "eventType.html", func(p Parms) any { return srv.context.world.EventsOfType(p["type"]) }) + srv.RegisterWorldPage("/collections", "collections.html", func(p Parms) any { + return groupBy(srv.context.world.HistoricalEventCollections, + func(e *model.HistoricalEventCollection) string { return e.Type() }, + func(e *model.HistoricalEventCollection) bool { return true }, + func(e *model.HistoricalEventCollection) string { return model.Time(e.StartYear, e.StartSeconds72) }, + ) + }) + srv.RegisterWorldResourcePage("/collection/{id}", "collection.html", func(id int) any { return srv.context.world.HistoricalEventCollections[id] }) + srv.RegisterWorldResourcePage("/popover/collection/{id}", "popoverCollection.html", func(id int) any { return srv.context.world.HistoricalEventCollections[id] }) + srv.RegisterWorldPage("/", "index.html", func(p Parms) any { return &struct { Civilizations map[string][]*model.Entity @@ -115,6 +126,9 @@ func StartServer(world *model.DfWorld, static embed.FS) error { srv.router.PathPrefix("/load").Handler(srv.loader) spa := spaHandler{server: srv, staticFS: static, staticPath: "static", indexPath: "index.html"} + if templates.DebugTemplates { + spa.staticFS = os.DirFS(".") + } srv.router.PathPrefix("/").Handler(spa) OpenBrowser("http://localhost:8080") diff --git a/backend/server/static.go b/backend/server/static.go index f3c672d..15fb699 100644 --- a/backend/server/static.go +++ b/backend/server/static.go @@ -1,16 +1,16 @@ package server import ( - "embed" "fmt" "io/fs" + "io/ioutil" "net/http" "os" ) type spaHandler struct { server *DfServer - staticFS embed.FS + staticFS fs.FS staticPath string indexPath string } @@ -30,7 +30,12 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if os.IsNotExist(err) { // file does not exist, serve index.html fmt.Println(path) - index, err := h.staticFS.ReadFile(h.staticPath + "/" + h.indexPath) + file, err := h.staticFS.Open(h.staticPath + "/" + h.indexPath) + if err != nil { + h.server.notFound(w) + return + } + index, err := ioutil.ReadAll(file) if err != nil { h.server.notFound(w) return diff --git a/backend/server/templates.go b/backend/server/templates.go index 8755150..9334774 100644 --- a/backend/server/templates.go +++ b/backend/server/templates.go @@ -55,6 +55,20 @@ func (srv *DfServer) LoadTemplates() { "history": func(siteId int) []*model.HistoricalEvent { return srv.context.world.SiteHistory(siteId) }, + "collection": func(id int) template.HTML { return model.LinkCollection(srv.context.world, id) }, + "getCollection": func(id int) *model.HistoricalEventCollection { return srv.context.world.HistoricalEventCollections[id] }, + "getOccasion": func(civId, occasionId int) *model.Occasion { + if civ, ok := srv.context.world.Entities[civId]; ok { + return civ.Occasion[occasionId] + } + return nil + }, + "story": func(id int) template.HTML { + if e, ok := srv.context.world.HistoricalEvents[id]; ok { + return template.HTML(e.Details.Html(&model.Context{World: srv.context.world, Story: true}) + " in " + model.Time(e.Year, e.Seconds72)) + } + return template.HTML("") + }, "season": model.Season, "time": model.Time, "url": url.PathEscape, @@ -63,9 +77,12 @@ func (srv *DfServer) LoadTemplates() { "html": func(value any) template.HTML { return template.HTML(fmt.Sprint(value)) }, - "bytes": func(s int64) string { return humanize.Bytes(uint64(s)) }, - "first": util.FirstInMap, - "ifFirst": func(m any, k string, r string) string { return util.If(util.FirstInMap(m, k), r, "") }, + "bytes": func(s int64) string { return humanize.Bytes(uint64(s)) }, + "first": util.FirstInMap, + "ifFirst": func(m any, k string, r string) string { return util.If(util.FirstInMap(m, k), r, "") }, + "strip": util.Strip, + "string": util.String, + "capitalize": util.Capitalize, } srv.templates = templates.New(functions) } diff --git a/backend/static/css/legends.css b/backend/static/css/legends.css index 6b21502..c04af5e 100644 --- a/backend/static/css/legends.css +++ b/backend/static/css/legends.css @@ -71,17 +71,22 @@ td.object { font-size: 80%; } -/* + @media (prefers-color-scheme: dark) { a { color: #337ab7; } + .collection { + color: #718dc9; + } + + .artifact { color: #ea4e00; } - .historical-figure { + .hf { color: #5c93ff; } @@ -93,7 +98,20 @@ td.object { color: #c70303; } - .art-form { + .occasion { + color: #ff91ff; + } + + + .artform { color: #cc45cc; } -} */ \ No newline at end of file + + .worldconstruction { + color: #aaa; + } + + .json { + color: #666; + } +} \ No newline at end of file diff --git a/backend/templates/collection.html b/backend/templates/collection.html new file mode 100644 index 0000000..d374419 --- /dev/null +++ b/backend/templates/collection.html @@ -0,0 +1,16 @@ +{{template "layout.html" .}} + +{{define "title"}}{{ title (strip (collection .Id)) }}{{end}} + +{{define "content"}} + +

{{ html (capitalize (string (collection .Id))) }}

+ +{{- if eq .Type "occasion" }}{{- with getOccasion .Details.CivId .Details.OccasionId }}{{- if ne .Event -1 }} +

A festival commemorating {{ story .Event }}

+{{- end }}{{- end}}{{- end}} + +{{ template "collectionDetail.html" . }} + +

{{ json . }}

+{{- end }} \ No newline at end of file diff --git a/backend/templates/collectionDetail.html b/backend/templates/collectionDetail.html new file mode 100644 index 0000000..2db816d --- /dev/null +++ b/backend/templates/collectionDetail.html @@ -0,0 +1,11 @@ +{{- if gt (len .Eventcol) 0 }} + +{{- end }} +{{ template "events.html" events .Event }} \ No newline at end of file diff --git a/backend/templates/collections.html b/backend/templates/collections.html new file mode 100644 index 0000000..924ae71 --- /dev/null +++ b/backend/templates/collections.html @@ -0,0 +1,37 @@ +{{template "layout.html" .}} + +{{define "title"}}Event Collections{{end}} + +{{define "content"}} +

Event Collections

+ + + + +{{- end }} \ No newline at end of file diff --git a/backend/templates/events.html b/backend/templates/events.html index 02f3ebd..79852e3 100644 --- a/backend/templates/events.html +++ b/backend/templates/events.html @@ -1,8 +1,11 @@ \ No newline at end of file diff --git a/backend/templates/layout.html b/backend/templates/layout.html index a27a261..d6efaa5 100644 --- a/backend/templates/layout.html +++ b/backend/templates/layout.html @@ -107,7 +107,7 @@ }).responseText; } - $('a.entity,a.hf,a.region,a.site,a.structure,a.worldconstruction,a.artifact,a.writtencontent').each(function () { + $('a.entity,a.hf,a.region,a.site,a.structure,a.worldconstruction,a.artifact,a.writtencontent,a.collection').each(function () { var popover = new bootstrap.Popover($(this), { content: loadLinkPopoverData, trigger: "hover", placement: "top", html: true }) }) diff --git a/backend/templates/popoverCollection.html b/backend/templates/popoverCollection.html new file mode 100644 index 0000000..0b5f2fb --- /dev/null +++ b/backend/templates/popoverCollection.html @@ -0,0 +1,3 @@ +{{ collection .Id }} +{{if ne .ParentId -1 }} +
as part of {{ collection .ParentId }}{{ end }} \ No newline at end of file diff --git a/backend/util/util.go b/backend/util/util.go index eebedcc..3723040 100644 --- a/backend/util/util.go +++ b/backend/util/util.go @@ -117,3 +117,12 @@ func FirstInMap(a any, b string) bool { sort.Slice(ks, func(i, j int) bool { return ks[i].String() < ks[j].String() }) return ks[0].String() == b } + +func Strip(html template.HTML) string { + r := regexp.MustCompile(`<.*?>`) + return r.ReplaceAllString(string(html), "") +} + +func String(html template.HTML) string { + return string(html) +}