You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
7.7 KiB
274 lines
7.7 KiB
package tables
|
|
|
|
import (
|
|
"mazeratsgen/internal/data"
|
|
"mazeratsgen/internal/dice"
|
|
"mazeratsgen/internal/helpers"
|
|
"strings"
|
|
)
|
|
|
|
type CityTable struct {
|
|
Roller *dice.Roller
|
|
}
|
|
|
|
type Building struct {
|
|
Type string
|
|
Rooms []string
|
|
TacticalFeature string
|
|
}
|
|
|
|
type Faction struct {
|
|
Type string
|
|
Trait string
|
|
Goal string
|
|
}
|
|
|
|
type City struct {
|
|
Theme string
|
|
Events []string
|
|
DistrictThemes []string
|
|
Activities []string
|
|
TacticalStreetFeatures []string
|
|
UpperClassBuildings []Building
|
|
LowerClassBuildings []Building
|
|
Factions []Faction
|
|
Seed int64
|
|
}
|
|
|
|
func (t *CityTable) Generate() City {
|
|
upperClassBuildings := []Building{}
|
|
|
|
// Future Jerry...the weird `for` loops here are to add noise to the seed.
|
|
// This will break if more than 6 rooms are needed
|
|
|
|
for i := 0; i < 3; i++ {
|
|
tempRoller := dice.NewRoller(t.Roller.Seed + int64(i))
|
|
tempTable := CityTable{Roller: tempRoller}
|
|
upperClassBuildings = append(upperClassBuildings, tempTable.UpperClassBuilding(tempRoller.TableRoll()))
|
|
}
|
|
|
|
lowerClassBuildings := []Building{}
|
|
for i := 4; i < 7; i++ {
|
|
tempRoller := dice.NewRoller(t.Roller.Seed + int64(i))
|
|
tempTable := CityTable{Roller: tempRoller}
|
|
lowerClassBuildings = append(lowerClassBuildings, tempTable.LowerClassBuilding(tempRoller.TableRoll()))
|
|
}
|
|
|
|
return City{
|
|
Theme: t.CityTheme(t.Roller.TableRoll()),
|
|
Events: helpers.GenUniqueItems(3, t.CityEvent, t.Roller.Seed),
|
|
DistrictThemes: helpers.GenUniqueItems(3, t.DistrictTheme, t.Roller.Seed),
|
|
UpperClassBuildings: upperClassBuildings,
|
|
LowerClassBuildings: lowerClassBuildings,
|
|
Activities: helpers.GenUniqueItems(3, t.CityActivity, t.Roller.Seed),
|
|
TacticalStreetFeatures: helpers.GenUniqueItems(3, t.TacticalStreetFeature, t.Roller.Seed),
|
|
Factions: []Faction{
|
|
t.GenFaction(t.Roller.TableRoll()),
|
|
t.GenFaction(t.Roller.TableRoll()),
|
|
},
|
|
Seed: t.Roller.Seed,
|
|
}
|
|
}
|
|
|
|
func (t *CityTable) Template() string {
|
|
return strings.TrimSpace(`
|
|
Theme: {{.Theme}}
|
|
Events:
|
|
{{- range $event := .Events}}
|
|
{{$event}}
|
|
{{- end}}
|
|
District Themes:
|
|
{{- range $theme := .DistrictThemes}}
|
|
{{$theme}}
|
|
{{- end}}
|
|
Upper Class Buildings:
|
|
{{- range $building := .UpperClassBuildings}}
|
|
{{$building.Type}}:
|
|
Tactical Feature: {{$building.TacticalFeature}}
|
|
Rooms:
|
|
{{- range $room := $building.Rooms}}
|
|
{{$room}}
|
|
{{- end}}
|
|
{{- end}}
|
|
Lower Class Buildings:
|
|
{{- range $building := .LowerClassBuildings}}
|
|
{{$building.Type}}:
|
|
Tactical Feature: {{$building.TacticalFeature}}
|
|
Rooms:
|
|
{{- range $room := $building.Rooms}}
|
|
{{$room}}
|
|
{{- end}}
|
|
{{- end}}
|
|
Activities:
|
|
{{- range $activity := .Activities }}
|
|
{{$activity}}
|
|
{{- end}}
|
|
Tactical Street Features:
|
|
{{- range $feature := .TacticalStreetFeatures }}
|
|
{{$feature}}
|
|
{{- end}}
|
|
Factions:
|
|
{{- range $faction := .Factions }}
|
|
{{$faction.Type}}:
|
|
Trait: {{$faction.Trait}}
|
|
Goal: {{$faction.Goal}}
|
|
{{- end}}
|
|
Seed: {{.Seed}}
|
|
`)
|
|
}
|
|
|
|
func (t *CityTable) CityTheme(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{1, 1}:
|
|
roll, _ := t.Roller.Roll("1d6")
|
|
return MonsterTable{Roller: t.Roller}.Base(roll[0])
|
|
case [2]int{2, 1}:
|
|
return t.CityActivity(t.Roller.TableRoll())
|
|
case [2]int{2, 2}:
|
|
return t.CityEvent(t.Roller.TableRoll())
|
|
case [2]int{2, 5}:
|
|
return t.DistrictTheme(t.Roller.TableRoll())
|
|
case [2]int{2, 6}:
|
|
return NPCTable{Roller: t.Roller}.DivineDomain(t.Roller.TableRoll())
|
|
case [2]int{3, 1}:
|
|
return t.GenFaction(t.Roller.TableRoll()).Type
|
|
case [2]int{3, 5}:
|
|
return t.LowerClassBuilding(t.Roller.TableRoll()).Type
|
|
case [2]int{4, 2}:
|
|
return "Pick an existing NPC"
|
|
case [2]int{4, 4}:
|
|
return MagicTable{Roller: t.Roller}.PhysicalElement(t.Roller.TableRoll())
|
|
case [2]int{6, 4}:
|
|
return t.UpperClassBuilding(t.Roller.TableRoll()).Type
|
|
default:
|
|
return data.Tables.City.CityThemes[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t *CityTable) CityEvent(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{2, 4}:
|
|
return t.GenFaction(t.Roller.TableRoll()).Type
|
|
default:
|
|
return data.Tables.City.CityEvents[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t *CityTable) DistrictTheme(roll [2]int) string {
|
|
npcTable := NPCTable{Roller: t.Roller}
|
|
switch roll {
|
|
case [2]int{1, 2}:
|
|
return npcTable.CivilizedNPC(t.Roller.TableRoll())
|
|
case [2]int{4, 1}:
|
|
return t.LowerClassBuilding(t.Roller.TableRoll()).Type
|
|
case [2]int{6, 1}:
|
|
return npcTable.UnderworldNPC(t.Roller.TableRoll())
|
|
case [2]int{6, 2}:
|
|
return t.UpperClassBuilding(t.Roller.TableRoll()).Type
|
|
case [2]int{6, 4}:
|
|
return npcTable.WildernessNPC(t.Roller.TableRoll())
|
|
default:
|
|
return data.Tables.City.DistrictThemes[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) GenBuilding(roll int) Building {
|
|
if roll <= 3 {
|
|
return t.LowerClassBuilding(t.Roller.TableRoll())
|
|
}
|
|
return t.UpperClassBuilding(t.Roller.TableRoll())
|
|
}
|
|
|
|
func (t CityTable) UpperClassBuilding(roll [2]int) Building {
|
|
return Building{
|
|
Type: data.Tables.City.UpperClassBuildings[roll[0]-1][roll[1]-1],
|
|
TacticalFeature: t.TacticalBuildingFeature(t.Roller.TableRoll()),
|
|
Rooms: helpers.GenUniqueItems(3, t.BuildingRoom, t.Roller.Seed),
|
|
}
|
|
}
|
|
|
|
func (t CityTable) LowerClassBuilding(roll [2]int) Building {
|
|
return Building{
|
|
Type: data.Tables.City.LowerClassBuildings[roll[0]-1][roll[1]-1],
|
|
TacticalFeature: t.TacticalBuildingFeature(t.Roller.TableRoll()),
|
|
Rooms: helpers.GenUniqueItems(3, t.BuildingRoom, t.Roller.Seed),
|
|
}
|
|
}
|
|
|
|
func (t CityTable) BuildingRoom(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{3, 1}:
|
|
return MazeTable{Roller: t.Roller}.DungeonRoom(t.Roller.TableRoll())
|
|
default:
|
|
return data.Tables.City.BuildingRooms[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) TacticalStreetFeature(roll [2]int) string {
|
|
mazeTable := MazeTable{Roller: t.Roller}
|
|
switch roll {
|
|
case [2]int{2, 3}:
|
|
return t.CityActivity(t.Roller.TableRoll())
|
|
case [2]int{3, 4}:
|
|
return mazeTable.DungeonActivity(t.Roller.TableRoll())
|
|
case [2]int{6, 6}:
|
|
return WildTable{Roller: t.Roller}.WildernessActivity(t.Roller.TableRoll())
|
|
default:
|
|
return data.Tables.City.TacticalStreetFeatures[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) TacticalBuildingFeature(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{1, 1}:
|
|
roll, _ := t.Roller.Roll("1d6")
|
|
return MonsterTable{Roller: t.Roller}.Base(roll[0]) + "Nests"
|
|
default:
|
|
return data.Tables.City.TacticalBuildingFeatures[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) FactionTrait(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{4, 4}:
|
|
return NPCTable{Roller: t.Roller}.Personality(t.Roller.TableRoll())
|
|
default:
|
|
return data.Tables.City.FactionTraits[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) GenFaction(roll [2]int) Faction {
|
|
return Faction{
|
|
Type: data.Tables.City.Factions[roll[0]-1][roll[1]-1],
|
|
Trait: t.FactionTrait(t.Roller.TableRoll()),
|
|
Goal: t.FactionGoal(t.Roller.TableRoll()),
|
|
}
|
|
}
|
|
|
|
func (t CityTable) FactionGoal(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{1, 6}:
|
|
return "Control " + t.GenFaction(t.Roller.TableRoll()).Type
|
|
case [2]int{2, 3}:
|
|
return "Kill a specific monster"
|
|
case [2]int{2, 4}:
|
|
return "Defeat " + t.GenFaction(t.Roller.TableRoll()).Type
|
|
case [2]int{4, 4}:
|
|
return "Infiltrate " + t.GenFaction(t.Roller.TableRoll()).Type
|
|
default:
|
|
return data.Tables.City.FactionGoals[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|
|
func (t CityTable) CityActivity(roll [2]int) string {
|
|
switch roll {
|
|
case [2]int{2, 5}:
|
|
return MazeTable{Roller: t.Roller}.DungeonActivity(t.Roller.TableRoll())
|
|
case [2]int{4, 2}:
|
|
return NPCTable{Roller: t.Roller}.Mission(t.Roller.TableRoll())
|
|
case [2]int{6, 6}:
|
|
return WildTable{Roller: t.Roller}.WildernessActivity(t.Roller.TableRoll())
|
|
default:
|
|
return data.Tables.City.CityActivities[roll[0]-1][roll[1]-1]
|
|
}
|
|
}
|
|
|