2022-04-26 10:24:16 +03:00
|
|
|
package model
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"html/template"
|
|
|
|
"regexp"
|
2022-05-01 13:29:39 +03:00
|
|
|
"strconv"
|
2022-04-26 10:24:16 +03:00
|
|
|
"strings"
|
2022-05-07 18:08:42 +03:00
|
|
|
|
|
|
|
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
2022-04-26 10:24:16 +03:00
|
|
|
)
|
|
|
|
|
2022-04-26 18:39:24 +03:00
|
|
|
var LinkHf = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).hf(id)) }
|
2022-05-05 23:18:31 +03:00
|
|
|
var LinkHfShort = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).hfShort(id)) }
|
2022-05-05 17:55:57 +03:00
|
|
|
var LinkHfList = func(w *DfWorld, id []int) template.HTML { return template.HTML((&Context{World: w}).hfList(id)) }
|
2022-04-26 18:39:24 +03:00
|
|
|
var LinkEntity = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).entity(id)) }
|
|
|
|
var LinkSite = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).site(id, "")) }
|
2022-04-29 15:21:27 +03:00
|
|
|
var LinkStructure = func(w *DfWorld, siteId, id int) template.HTML {
|
|
|
|
return template.HTML((&Context{World: w}).structure(siteId, id))
|
|
|
|
}
|
2022-04-26 18:39:24 +03:00
|
|
|
var LinkRegion = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).region(id)) }
|
2022-04-28 22:24:55 +03:00
|
|
|
var LinkWorldConstruction = func(w *DfWorld, id int) template.HTML {
|
|
|
|
return template.HTML((&Context{World: w}).worldConstruction(id))
|
|
|
|
}
|
|
|
|
var LinkArtifact = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).artifact(id)) }
|
|
|
|
var LinkDanceForm = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).danceForm(id)) }
|
|
|
|
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)) }
|
2022-05-03 15:59:47 +03:00
|
|
|
var LinkCollection = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).collection(id)) }
|
2022-05-04 12:42:02 +03:00
|
|
|
var LinkMountain = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).mountain(id)) }
|
|
|
|
var LinkLandmass = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).landmass(id)) }
|
|
|
|
var LinkRiver = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).river(id)) }
|
2022-05-07 22:17:05 +03:00
|
|
|
var LinkIdentity = func(w *DfWorld, id int) template.HTML { return template.HTML((&Context{World: w}).identity(id)) }
|
2022-04-26 10:24:16 +03:00
|
|
|
|
2022-05-07 18:08:42 +03:00
|
|
|
var AddMapLandmass = func(w *DfWorld, id int) template.HTML {
|
|
|
|
if x, ok := w.Landmasses[id]; ok {
|
|
|
|
c1 := strings.Split(x.Coord1, ",")
|
|
|
|
x1, _ := strconv.Atoi(c1[0])
|
|
|
|
y1, _ := strconv.Atoi(c1[1])
|
|
|
|
c2 := strings.Split(x.Coord2, ",")
|
|
|
|
x2, _ := strconv.Atoi(c2[0])
|
|
|
|
y2, _ := strconv.Atoi(c2[1])
|
2022-05-07 21:46:37 +03:00
|
|
|
return template.HTML(fmt.Sprintf(`<script>addLandmass(%d, %d, %d, %d, %d, '#FFF')</script>`, x.Id_, x1, y1, x2, y2))
|
2022-05-07 18:08:42 +03:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
var AddMapRegion = func(w *DfWorld, id int) template.HTML {
|
|
|
|
if x, ok := w.Regions[id]; ok {
|
2022-05-07 21:46:37 +03:00
|
|
|
coords := strings.Join(util.Map(x.Outline(), func(c Coord) string { return fmt.Sprintf(`coord(%d,%d)`, c.X, c.Y-1) }), ",")
|
2022-05-08 17:38:38 +03:00
|
|
|
if len(coords) > 0 {
|
|
|
|
fillColor := "transparent"
|
|
|
|
switch x.Evilness {
|
|
|
|
case RegionEvilness_Evil:
|
|
|
|
fillColor = "fuchsia"
|
|
|
|
case RegionEvilness_Good:
|
|
|
|
fillColor = "aqua"
|
|
|
|
}
|
|
|
|
return template.HTML(fmt.Sprintf(`<script>addRegion(%d, [%s], '%s')</script>`, x.Id_, coords, fillColor))
|
2022-05-07 18:08:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-05-08 10:35:57 +03:00
|
|
|
var AddMapSite = func(w *DfWorld, id int, color bool) template.HTML {
|
2022-05-01 13:29:39 +03:00
|
|
|
if site, ok := w.Sites[id]; ok {
|
|
|
|
coords := strings.Split(site.Rectangle, ":")
|
|
|
|
c1 := strings.Split(coords[0], ",")
|
|
|
|
x1, _ := strconv.ParseFloat(c1[0], 32)
|
|
|
|
y1, _ := strconv.ParseFloat(c1[1], 32)
|
|
|
|
c2 := strings.Split(coords[1], ",")
|
|
|
|
x2, _ := strconv.ParseFloat(c2[0], 32)
|
|
|
|
y2, _ := strconv.ParseFloat(c2[1], 32)
|
2022-05-07 18:18:08 +03:00
|
|
|
c := "#ff0"
|
|
|
|
if e, ok := w.Entities[site.Owner]; ok {
|
|
|
|
c = e.Color()
|
|
|
|
}
|
2022-05-07 19:11:24 +03:00
|
|
|
if site.Ruin {
|
|
|
|
c = "#aaa"
|
|
|
|
}
|
2022-05-08 10:35:57 +03:00
|
|
|
if !color {
|
|
|
|
c = "#fff"
|
|
|
|
}
|
2022-05-07 19:11:24 +03:00
|
|
|
return template.HTML(fmt.Sprintf(`<script>addSite(%d, %f, %f, %f, %f, "%s", "")</script>`, site.Id_, x1/16.0, y1/16.0-1, x2/16.0, y2/16.0-1, c))
|
2022-05-01 13:29:39 +03:00
|
|
|
} else {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-08 10:35:57 +03:00
|
|
|
var AddMapMountain = func(w *DfWorld, id int, color bool) template.HTML {
|
2022-05-07 18:08:42 +03:00
|
|
|
if m, ok := w.MountainPeaks[id]; ok {
|
|
|
|
c1 := strings.Split(m.Coords, ",")
|
|
|
|
x, _ := strconv.Atoi(c1[0])
|
|
|
|
y, _ := strconv.Atoi(c1[1])
|
2022-05-08 10:35:57 +03:00
|
|
|
c := "#666"
|
|
|
|
if !color {
|
|
|
|
c = "#fff"
|
|
|
|
}
|
|
|
|
return template.HTML(fmt.Sprintf(`<script>addMountain(%d, %d, %d, '%s')</script>`, m.Id_, x, y, c))
|
2022-05-07 18:08:42 +03:00
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
var AddMapWorldConstruction = func(w *DfWorld, id int) template.HTML {
|
|
|
|
if x, ok := w.WorldConstructions[id]; ok {
|
|
|
|
color := util.If(x.Type_ == WorldConstructionType_Tunnel, "#000", "#fff")
|
|
|
|
line := x.Line()
|
|
|
|
if len(line) == 1 {
|
2022-05-07 21:46:37 +03:00
|
|
|
return template.HTML(fmt.Sprintf(`<script>addWc(%d, %d, %d, '%s')</script>`, x.Id_, line[0].X, line[0].Y, color))
|
2022-05-07 18:08:42 +03:00
|
|
|
} else {
|
|
|
|
r := "<script>"
|
|
|
|
r += "var polyline = L.polyline(["
|
|
|
|
r += strings.Join(util.Map(x.Line(), func(c Coord) string { return fmt.Sprintf(`coord(%d+0.5,%d-0.5)`, c.X, c.Y) }), ",")
|
|
|
|
r += "], {color: '" + color + "', opacity: 1, weight: 3}).addTo(constructionsLayer);\n"
|
2022-05-07 19:11:24 +03:00
|
|
|
r += fmt.Sprintf(`attachTooltip(polyline, urlToolTip('worldconstruction', %d));`, x.Id_)
|
2022-05-07 18:08:42 +03:00
|
|
|
r += "polyline.on('mouseover', function (e) { this.setStyle({weight: 10}); });\n"
|
|
|
|
r += "polyline.on('mouseout', function (e) { this.setStyle({ weight: 3}); });\n"
|
|
|
|
r += "</script>"
|
|
|
|
return template.HTML(r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
var AddMapRiver = func(w *DfWorld, id int) template.HTML {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-05-11 10:45:17 +03:00
|
|
|
func AddMapCollection(w *DfWorld, id int) template.HTML {
|
|
|
|
if x, ok := w.HistoricalEventCollections[id]; ok {
|
|
|
|
r := ""
|
|
|
|
switch d := x.Details.(type) {
|
|
|
|
case *HistoricalEventCollectionBeastAttack:
|
|
|
|
r += string(AddMapSite(w, d.SiteId, false))
|
|
|
|
case *HistoricalEventCollectionDuel:
|
|
|
|
c1 := strings.Split(d.Coords, ",")
|
|
|
|
x, _ := strconv.Atoi(c1[0])
|
|
|
|
y, _ := strconv.Atoi(c1[1])
|
|
|
|
r += fmt.Sprintf(`<script>addBattle(%d, %d, %d)</script>`, id, x, y)
|
|
|
|
case *HistoricalEventCollectionSiteConquered:
|
|
|
|
r += string(AddMapSite(w, d.SiteId, false))
|
|
|
|
case *HistoricalEventCollectionBattle:
|
|
|
|
if d.SiteId != -1 {
|
|
|
|
r += string(AddMapSite(w, d.SiteId, false))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, s := range d.AttackingSquadSite {
|
|
|
|
r += string(AddMapSite(w, s, true))
|
|
|
|
}
|
|
|
|
for _, s := range d.DefendingSquadSite {
|
|
|
|
r += string(AddMapSite(w, s, true))
|
|
|
|
}
|
|
|
|
|
|
|
|
c1 := strings.Split(d.Coords, ",")
|
|
|
|
x, _ := strconv.Atoi(c1[0])
|
|
|
|
y, _ := strconv.Atoi(c1[1])
|
|
|
|
r += fmt.Sprintf(`<script>addBattle(%d, %d, %d)</script>`, id, x, y)
|
|
|
|
case *HistoricalEventCollectionWar:
|
|
|
|
for _, y := range x.Eventcol {
|
|
|
|
r += string(AddMapCollection(w, y))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return template.HTML(r)
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2022-05-06 14:11:12 +03:00
|
|
|
var AndList = func(s []string) template.HTML { return template.HTML(andList(s)) }
|
|
|
|
|
2022-04-26 10:24:16 +03:00
|
|
|
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 ShortTime(year, seconds int) string {
|
|
|
|
if year == -1 {
|
|
|
|
return "a time before time"
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%d", year)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Time(year, seconds int) string {
|
|
|
|
if year == -1 {
|
|
|
|
return "a time before time"
|
|
|
|
}
|
|
|
|
if seconds == -1 {
|
|
|
|
return fmt.Sprintf("%d", year)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%s of %d", Season(seconds), year)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Season(seconds int) string {
|
|
|
|
r := ""
|
|
|
|
month := seconds % 100800
|
|
|
|
if month <= 33600 {
|
|
|
|
r += "early "
|
|
|
|
} else if month <= 67200 {
|
|
|
|
r += "mid"
|
|
|
|
} else if month <= 100800 {
|
|
|
|
r += "late "
|
|
|
|
}
|
|
|
|
|
|
|
|
season := seconds % 403200
|
|
|
|
if season < 100800 {
|
|
|
|
r += "spring"
|
|
|
|
} else if season < 201600 {
|
|
|
|
r += "summer"
|
|
|
|
} else if season < 302400 {
|
|
|
|
r += "autumn"
|
|
|
|
} else if season < 403200 {
|
|
|
|
r += "winter"
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
func equipmentLevel(level int) string {
|
|
|
|
switch level {
|
|
|
|
case 1:
|
|
|
|
return "well-crafted"
|
|
|
|
case 2:
|
|
|
|
return "finely-crafted"
|
|
|
|
case 3:
|
|
|
|
return "superior quality"
|
|
|
|
case 4:
|
|
|
|
return "exceptional"
|
|
|
|
case 5:
|
|
|
|
return "masterwork"
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func containsInt(list []int, id int) bool {
|
|
|
|
for _, v := range list {
|
|
|
|
if v == id {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2022-05-03 22:39:00 +03:00
|
|
|
|
|
|
|
func LinkDescription(w *DfWorld, desc string) template.HTML {
|
|
|
|
c := &Context{World: w}
|
|
|
|
desc = replaceNameDescription(desc, "originating in ", `\.`, w.Entities, c.entity)
|
|
|
|
desc = replaceNameDescription(desc, "grew out of the performances of ", `\.`, w.Entities, c.entity)
|
|
|
|
desc = replaceNameDescription(desc, "accompanied by(?: any composition of)? ", `(?: as |\.)`, w.MusicalForms, c.musicalForm)
|
|
|
|
desc = replaceNameDescription(desc, "(?:recites?|acts? out)(?: any composition of)? ", `(?: while |\.)`, w.PoeticForms, c.poeticForm)
|
|
|
|
desc = replacHfDescription(desc, "devised by ", `\.`, w.HistoricalFigures, c.hf)
|
|
|
|
desc = replacHfDescription(desc, "the story of ", `\.`, w.HistoricalFigures, c.hf)
|
|
|
|
desc = replaceNameDescription(desc, "the words of ", `(?: while |\.)`, w.WrittenContents, c.writtenContent)
|
|
|
|
desc = replacHfDescription(desc, "express pleasure with ", " originally", w.HistoricalFigures, c.hf)
|
|
|
|
s := strings.Split(desc, "[B]")
|
|
|
|
if len(s) > 1 {
|
|
|
|
desc = s[0] + "<ul><li>" + strings.Join(s[1:], "</li><li>") + "</li></ul>"
|
|
|
|
}
|
|
|
|
return template.HTML(desc)
|
|
|
|
}
|
|
|
|
|
|
|
|
type NamedIdentifiable interface {
|
|
|
|
Id() int
|
|
|
|
Name() string
|
|
|
|
}
|
|
|
|
|
|
|
|
func replaceNameDescription[T NamedIdentifiable](s, prefix, suffix string, input map[int]T, mapper func(int) string) string {
|
|
|
|
return replaceDescription(s, prefix, suffix, input, func(t T) string { return t.Name() }, mapper)
|
|
|
|
}
|
|
|
|
|
|
|
|
func replacHfDescription(s, prefix, suffix string, input map[int]*HistoricalFigure, mapper func(int) string) string {
|
|
|
|
return replaceDescription(s, prefix, suffix, input,
|
|
|
|
func(hf *HistoricalFigure) string {
|
|
|
|
if hf.Race != "" && !hf.Deity && !hf.Force {
|
|
|
|
return fmt.Sprintf("the %s %s", hf.Race, hf.Name())
|
|
|
|
} else {
|
|
|
|
return hf.Name()
|
|
|
|
}
|
|
|
|
}, mapper)
|
|
|
|
}
|
|
|
|
|
|
|
|
func replaceDescription[T NamedIdentifiable](s, prefix, suffix string, input map[int]T, namer func(T) string, mapper func(int) string) string {
|
|
|
|
r := "(" + prefix + `)([^.]+?)(` + suffix + ")"
|
|
|
|
reg := regexp.MustCompile(r)
|
|
|
|
res := reg.FindStringSubmatch(s)
|
|
|
|
if res == nil {
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
name := strings.ToLower(res[2])
|
|
|
|
for id, v := range input {
|
|
|
|
if strings.ToLower(namer(v)) == name {
|
2022-05-04 07:46:21 +03:00
|
|
|
return reg.ReplaceAllString(s, res[1]+mapper(id)+res[3])
|
2022-05-03 22:39:00 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|