years
This commit is contained in:
parent
e5cd5bd3c2
commit
6380871358
|
@ -85,6 +85,10 @@
|
||||||
{
|
{
|
||||||
"Name": "NecromancerSince",
|
"Name": "NecromancerSince",
|
||||||
"Type": "int"
|
"Type": "int"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Kills",
|
||||||
|
"Type": "[]int"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Entity": [
|
"Entity": [
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (w *DfWorld) AllEventTypes() []string {
|
func (w *DfWorld) AllEventTypes() []string {
|
||||||
|
@ -63,6 +64,16 @@ func (w *DfWorld) SiteHistory(siteId int) []*HistoricalEvent {
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *DfWorld) Races() []string {
|
||||||
|
races := make(map[string]bool)
|
||||||
|
for _, hf := range w.HistoricalFigures {
|
||||||
|
races[hf.Race] = true
|
||||||
|
}
|
||||||
|
list := maps.Keys(races)
|
||||||
|
sort.Strings(list)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
func (c *HistoricalEventCollection) Type() string {
|
func (c *HistoricalEventCollection) Type() string {
|
||||||
if c.Details == nil {
|
if c.Details == nil {
|
||||||
return "unk"
|
return "unk"
|
||||||
|
|
|
@ -19059,6 +19059,7 @@ type HistoricalFigure struct {
|
||||||
Sphere []string `json:"sphere" legend:"base" related:""` // sphere
|
Sphere []string `json:"sphere" legend:"base" related:""` // sphere
|
||||||
UsedIdentityId []int `json:"usedIdentityId" legend:"base" related:""` // used_identity_id
|
UsedIdentityId []int `json:"usedIdentityId" legend:"base" related:""` // used_identity_id
|
||||||
VagueRelationship []*VagueRelationship `json:"vagueRelationship" legend:"base" related:""` // vague_relationship
|
VagueRelationship []*VagueRelationship `json:"vagueRelationship" legend:"base" related:""` // vague_relationship
|
||||||
|
Kills []int `json:"kills" legend:"add" related:""` // Kills
|
||||||
Leader bool `json:"leader" legend:"add" related:""` // Leader
|
Leader bool `json:"leader" legend:"add" related:""` // Leader
|
||||||
Necromancer bool `json:"necromancer" legend:"add" related:""` // Necromancer
|
Necromancer bool `json:"necromancer" legend:"add" related:""` // Necromancer
|
||||||
NecromancerSince int `json:"necromancerSince" legend:"add" related:""` // NecromancerSince
|
NecromancerSince int `json:"necromancerSince" legend:"add" related:""` // NecromancerSince
|
||||||
|
@ -19182,6 +19183,7 @@ func (x *HistoricalFigure) MarshalJSON() ([]byte, error) {
|
||||||
d["sphere"] = x.Sphere
|
d["sphere"] = x.Sphere
|
||||||
d["usedIdentityId"] = x.UsedIdentityId
|
d["usedIdentityId"] = x.UsedIdentityId
|
||||||
d["vagueRelationship"] = x.VagueRelationship
|
d["vagueRelationship"] = x.VagueRelationship
|
||||||
|
d["kills"] = x.Kills
|
||||||
d["leader"] = x.Leader
|
d["leader"] = x.Leader
|
||||||
d["necromancer"] = x.Necromancer
|
d["necromancer"] = x.Necromancer
|
||||||
if x.NecromancerSince != -1 {
|
if x.NecromancerSince != -1 {
|
||||||
|
|
|
@ -150,6 +150,10 @@ func (w *DfWorld) processEvents() {
|
||||||
id.HistfigId = hf.Id_
|
id.HistfigId = hf.Id_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case *HistoricalEventHfDied:
|
||||||
|
if hf, ok := w.HistoricalFigures[d.SlayerHfid]; ok {
|
||||||
|
hf.Kills = append(hf.Kills, d.Hfid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"github.com/robertjanetzko/LegendsBrowser2/backend/model"
|
"github.com/robertjanetzko/LegendsBrowser2/backend/model"
|
||||||
"github.com/robertjanetzko/LegendsBrowser2/backend/templates"
|
"github.com/robertjanetzko/LegendsBrowser2/backend/templates"
|
||||||
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DfServerContext struct {
|
type DfServerContext struct {
|
||||||
|
@ -119,6 +120,19 @@ func StartServer(config *Config, world *model.DfWorld, static embed.FS) error {
|
||||||
srv.RegisterWorldResourcePage("/identity/{id}", "identity.html", func(id int) any { return srv.context.world.Identities[id] })
|
srv.RegisterWorldResourcePage("/identity/{id}", "identity.html", func(id int) any { return srv.context.world.Identities[id] })
|
||||||
srv.RegisterWorldResourcePage("/popover/identity/{id}", "popoverIdentity.html", func(id int) any { return srv.context.world.Identities[id] })
|
srv.RegisterWorldResourcePage("/popover/identity/{id}", "popoverIdentity.html", func(id int) any { return srv.context.world.Identities[id] })
|
||||||
|
|
||||||
|
srv.RegisterWorldPage("/years", "years.html", func(p Parms) any {
|
||||||
|
return groupBy(srv.context.world.HistoricalEvents,
|
||||||
|
func(e *model.HistoricalEvent) int { return e.Year },
|
||||||
|
func(e *model.HistoricalEvent) bool { return true },
|
||||||
|
func(e *model.HistoricalEvent) int { return e.Id_ })
|
||||||
|
})
|
||||||
|
srv.RegisterWorldResourcePage("/year/{id}", "year.html", func(id int) any {
|
||||||
|
return util.FilterMap(srv.context.world.HistoricalEvents,
|
||||||
|
func(v *model.HistoricalEvent) bool { return v.Year == id },
|
||||||
|
func(a, b *model.HistoricalEvent) bool { return a.Id_ < b.Id_ },
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
srv.RegisterWorldPage("/events", "eventTypes.html", func(p Parms) any { return srv.context.world.AllEventTypes() })
|
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("/events/{type}", "eventType.html", func(p Parms) any { return srv.context.world.EventsOfType(p["type"]) })
|
||||||
srv.RegisterWorldResourcePage("/event/{id}", "event.html", func(id int) any { return srv.context.world.HistoricalEvents[id] })
|
srv.RegisterWorldResourcePage("/event/{id}", "event.html", func(id int) any { return srv.context.world.HistoricalEvents[id] })
|
||||||
|
@ -236,7 +250,18 @@ func (srv *DfServer) searchHf(p Parms) any {
|
||||||
list = append(list, hf)
|
list = append(list, hf)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(list, func(i, j int) bool { return list[i].Name_ < list[j].Name_ })
|
switch p["sort"] {
|
||||||
|
case "race":
|
||||||
|
sort.Slice(list, func(i, j int) bool { return list[i].Race < list[j].Race })
|
||||||
|
case "birth":
|
||||||
|
sort.Slice(list, func(i, j int) bool { return list[i].BirthYear < list[j].BirthYear })
|
||||||
|
case "death":
|
||||||
|
sort.Slice(list, func(i, j int) bool { return list[i].DeathYear < list[j].DeathYear })
|
||||||
|
case "kills":
|
||||||
|
sort.Slice(list, func(i, j int) bool { return len(list[i].Kills) > len(list[j].Kills) })
|
||||||
|
default:
|
||||||
|
sort.Slice(list, func(i, j int) bool { return list[i].Name_ < list[j].Name_ })
|
||||||
|
}
|
||||||
|
|
||||||
return map[string]any{
|
return map[string]any{
|
||||||
"Params": p,
|
"Params": p,
|
||||||
|
@ -288,8 +313,8 @@ func groupByType[K comparable, T namedTyped](input map[K]T) map[string][]T {
|
||||||
return groupBy(input, func(t T) string { return t.Type() }, func(t T) bool { return t.Name() != "" }, func(t T) string { return t.Name() })
|
return groupBy(input, func(t T) string { return t.Type() }, func(t T) bool { return t.Name() != "" }, func(t T) string { return t.Name() })
|
||||||
}
|
}
|
||||||
|
|
||||||
func groupBy[K comparable, T any](input map[K]T, mapper func(T) string, filter func(T) bool, sortMapper func(T) string) map[string][]T {
|
func groupBy[K comparable, N comparable, T any, S constraints.Ordered](input map[K]T, mapper func(T) N, filter func(T) bool, sortMapper func(T) S) map[N][]T {
|
||||||
output := make(map[string][]T)
|
output := make(map[N][]T)
|
||||||
|
|
||||||
for _, v := range input {
|
for _, v := range input {
|
||||||
k := mapper(v)
|
k := mapper(v)
|
||||||
|
|
|
@ -90,12 +90,14 @@ func (srv *DfServer) LoadTemplates() {
|
||||||
"html": func(value any) template.HTML {
|
"html": func(value any) template.HTML {
|
||||||
return template.HTML(fmt.Sprint(value))
|
return template.HTML(fmt.Sprint(value))
|
||||||
},
|
},
|
||||||
"bytes": func(s int64) string { return humanize.Bytes(uint64(s)) },
|
"bytes": func(s int64) string { return humanize.Bytes(uint64(s)) },
|
||||||
"first": util.FirstInMap,
|
"first": util.FirstInMap,
|
||||||
"ifFirst": func(m any, k string, r string) string { return util.If(util.FirstInMap(m, k), r, "") },
|
"ifFirst": func(m any, k string, r string) string { return util.If(util.FirstInMap(m, k), r, "") },
|
||||||
"strip": util.Strip,
|
"strip": util.Strip,
|
||||||
"string": util.String,
|
"string": util.String,
|
||||||
"capitalize": util.Capitalize,
|
"capitalize": util.Capitalize,
|
||||||
|
"add": func(a, b int) int { return a + b },
|
||||||
|
"breakYearColumn": func(c, m int) bool { return (c % ((m + 2) / 4)) == 0 },
|
||||||
}
|
}
|
||||||
srv.templates = templates.New(functions)
|
srv.templates = templates.New(functions)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Race</th>
|
<th>Race</th>
|
||||||
<th>Lived</th>
|
<th>Lived</th>
|
||||||
|
<th>Kills</th>
|
||||||
</tr>
|
</tr>
|
||||||
{{- range .Hfs }}{{- if not (eq .Name "") }}
|
{{- range .Hfs }}{{- if not (eq .Name "") }}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
from {{ .BirthYear }} till {{ .DeathYear }}
|
from {{ .BirthYear }} till {{ .DeathYear }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ len .Kills }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{- end}}{{- end}}
|
{{- end}}{{- end}}
|
||||||
</table>
|
</table>
|
||||||
|
@ -51,25 +53,26 @@
|
||||||
}}checked{{end}}> Ghost</label></div>
|
}}checked{{end}}> Ghost</label></div>
|
||||||
<div class="checkbox"><label><input class="filter" type="checkbox" name="adventurer" value="1" {{if eq .Params.adventurer "1"
|
<div class="checkbox"><label><input class="filter" type="checkbox" name="adventurer" value="1" {{if eq .Params.adventurer "1"
|
||||||
}}checked{{end}}> Adventurer</label></div>
|
}}checked{{end}}> Adventurer</label></div>
|
||||||
<div class="select form-group">
|
<div class="select form-group mt-1 mb-3">
|
||||||
<select class="form-control" name="race">
|
<select class="form-control" name="race">
|
||||||
<option class="text-muted" value="">Race</option>
|
<option class="text-muted" value="">Race</option>
|
||||||
<option value="black bear">black bear</option>
|
{{- range world.Races -}}
|
||||||
|
<option value="{{ . }}" {{if eq $.Params.race . }}selected{{end}}>{{ . }}</option>
|
||||||
|
{{- end -}}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<h4>Sorting</h4>
|
<h4>Sorting</h4>
|
||||||
<div class="select form-group">
|
<div class="select form-group">
|
||||||
<select class="form-control" name="sort">
|
<select class="form-control" name="sort">
|
||||||
<option value="">Default</option>
|
<option value="">Default</option>
|
||||||
<option value="name">Name</option>
|
<option value="name" {{if eq .Params.sort "name" }}selected{{end}}>Name</option>
|
||||||
<option value="race">Race</option>
|
<option value="race" {{if eq .Params.sort "race" }}selected{{end}}>Race</option>
|
||||||
<option value="birth">Birth</option>
|
<option value="birth" {{if eq .Params.sort "birth" }}selected{{end}}>Birth</option>
|
||||||
<option value="death">Death</option>
|
<option value="death" {{if eq .Params.sort "death" }}selected{{end}}>Death</option>
|
||||||
<option value="kills">Kills</option>
|
<option value="kills" {{if eq .Params.sort "kills" }}selected{{end}}>Kills</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Refresh</button>
|
<button type="submit" class="btn btn-primary mt-4">Refresh</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{template "layout.html" .}}
|
||||||
|
|
||||||
|
{{define "title"}}Year {{(index . 0).Year}}{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
|
||||||
|
<h3>Year {{(index . 0).Year}}</h3>
|
||||||
|
|
||||||
|
<h5>Events</h5>
|
||||||
|
{{ template "events.html" events . }}
|
||||||
|
|
||||||
|
{{- end }}
|
|
@ -0,0 +1,25 @@
|
||||||
|
{{template "layout.html" .}}
|
||||||
|
|
||||||
|
{{define "title"}}Years{{end}}
|
||||||
|
|
||||||
|
{{define "content"}}
|
||||||
|
<h3>Years</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<ul>
|
||||||
|
{{ $c := 0}}
|
||||||
|
{{ range $y, $e := . }}
|
||||||
|
{{ $c = add $c 1 }}
|
||||||
|
{{ if breakYearColumn $c (len $) }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<ul>
|
||||||
|
{{end}}
|
||||||
|
<li><a href="/year/{{ $y }}">Year {{ $y }}</a> ({{len $e}} events)</li>
|
||||||
|
{{ end }}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{- end }}
|
|
@ -90,6 +90,17 @@ func Map[U, V any](list []U, mapper func(U) V) []V {
|
||||||
return newList
|
return newList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FilterMap[K comparable, V any](input map[K]V, predicate func(V) bool, sorter func(V, V) bool) []V {
|
||||||
|
var list []V
|
||||||
|
for _, v := range input {
|
||||||
|
if predicate(v) {
|
||||||
|
list = append(list, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(list, func(i, j int) bool { return sorter(list[i], list[j]) })
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
type Identifiable interface {
|
type Identifiable interface {
|
||||||
Id() int
|
Id() int
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue