Compare commits
No commits in common. "archive" and "main" have entirely different histories.
129
src/Decoder.elm
129
src/Decoder.elm
|
|
@ -1,129 +0,0 @@
|
||||||
module Decoder exposing (..)
|
|
||||||
|
|
||||||
import Dict
|
|
||||||
import FastDict
|
|
||||||
import Json.Decode as D
|
|
||||||
import Json.Encode as E
|
|
||||||
|
|
||||||
|
|
||||||
type Information a
|
|
||||||
= Information
|
|
||||||
{ decoder : D.Decoder a
|
|
||||||
, encoder : a -> E.Value
|
|
||||||
, keys : List String
|
|
||||||
, default : a
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool : List String -> Bool -> Information Bool
|
|
||||||
bool keys default =
|
|
||||||
Information
|
|
||||||
{ decoder = D.bool
|
|
||||||
, encoder = E.bool
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
dict : List String -> Dict.Dict comparable value -> (comparable -> String) -> (String -> comparable) -> (value -> E.Value) -> D.Decoder value -> Information (Dict.Dict comparable value)
|
|
||||||
dict keys default fromKey toKey fromValue valueDecoder =
|
|
||||||
Information
|
|
||||||
{ decoder =
|
|
||||||
D.keyValuePairs valueDecoder
|
|
||||||
|> D.map (List.map (Tuple.mapFirst toKey))
|
|
||||||
|> D.map Dict.fromList
|
|
||||||
, encoder = E.dict fromKey fromValue
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fastdict : List String -> FastDict.Dict comparable value -> (comparable -> String) -> (String -> comparable) -> (value -> E.Value) -> D.Decoder value -> Information (FastDict.Dict comparable value)
|
|
||||||
fastdict keys default fromKey toKey fromValue valueDecoder =
|
|
||||||
Information
|
|
||||||
{ decoder =
|
|
||||||
D.keyValuePairs valueDecoder
|
|
||||||
|> D.map (List.map (Tuple.mapFirst toKey))
|
|
||||||
|> D.map FastDict.fromList
|
|
||||||
, encoder =
|
|
||||||
FastDict.toList
|
|
||||||
>> List.map (Tuple.mapBoth fromKey fromValue)
|
|
||||||
>> E.object
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int : List String -> Int -> Information Int
|
|
||||||
int keys default =
|
|
||||||
Information
|
|
||||||
{ decoder = D.int
|
|
||||||
, encoder = E.int
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
list : List String -> List a -> (a -> E.Value) -> D.Decoder a -> Information (List a)
|
|
||||||
list keys default fromValue valueDecoder =
|
|
||||||
Information
|
|
||||||
{ decoder = D.list valueDecoder
|
|
||||||
, encoder = E.list fromValue
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{-| The website allows users to overwrite the pre-generated values.
|
|
||||||
Hence, if a value already exists, it is returned. If it does not, it will be
|
|
||||||
generated.
|
|
||||||
-}
|
|
||||||
lookUp : E.Value -> Information a -> a
|
|
||||||
lookUp value (Information { decoder, keys, default }) =
|
|
||||||
case D.decodeValue (D.at keys decoder) value of
|
|
||||||
Ok v ->
|
|
||||||
v
|
|
||||||
|
|
||||||
Err _ ->
|
|
||||||
default
|
|
||||||
|
|
||||||
|
|
||||||
overwrite : a -> Information a -> E.Value -> E.Value
|
|
||||||
overwrite newValue (Information info) obj =
|
|
||||||
case info.keys of
|
|
||||||
[] ->
|
|
||||||
info.encoder newValue
|
|
||||||
|
|
||||||
head :: tail ->
|
|
||||||
case D.decodeValue (D.keyValuePairs D.value) obj of
|
|
||||||
Ok o ->
|
|
||||||
o
|
|
||||||
|> FastDict.fromList
|
|
||||||
|> FastDict.update head
|
|
||||||
(\mv ->
|
|
||||||
overwrite newValue
|
|
||||||
(Information
|
|
||||||
{ encoder = info.encoder
|
|
||||||
, decoder = info.decoder
|
|
||||||
, keys = tail
|
|
||||||
, default = info.default
|
|
||||||
}
|
|
||||||
)
|
|
||||||
(mv |> Maybe.withDefault (E.dict identity identity Dict.empty))
|
|
||||||
|> Just
|
|
||||||
)
|
|
||||||
|> FastDict.toCoreDict
|
|
||||||
|> E.dict identity identity
|
|
||||||
|
|
||||||
Err _ ->
|
|
||||||
obj
|
|
||||||
|
|
||||||
|
|
||||||
string : List String -> String -> Information String
|
|
||||||
string keys default =
|
|
||||||
Information
|
|
||||||
{ encoder = E.string
|
|
||||||
, decoder = D.string
|
|
||||||
, keys = keys
|
|
||||||
, default = default
|
|
||||||
}
|
|
||||||
341
src/Defaults.elm
341
src/Defaults.elm
|
|
@ -1,341 +0,0 @@
|
||||||
module Defaults exposing (..)
|
|
||||||
|
|
||||||
{-| The Defaults module exposes config values. These values can be overwritten
|
|
||||||
but they are usually set by default.
|
|
||||||
-}
|
|
||||||
|
|
||||||
import FastDict as Dict
|
|
||||||
|
|
||||||
|
|
||||||
commonerOccupations : Dict.Dict String Int
|
|
||||||
commonerOccupations =
|
|
||||||
Dict.fromList
|
|
||||||
[ ( "Baker", 25 )
|
|
||||||
, ( "Shoemaker", 37 )
|
|
||||||
, ( "Furrier", 62 )
|
|
||||||
, ( "Household helper", 62 )
|
|
||||||
, ( "Tailor", 62 )
|
|
||||||
, ( "Barber", 87 )
|
|
||||||
, ( "Unlicensed Doctor", 87 )
|
|
||||||
, ( "Jeweler", 100 )
|
|
||||||
, ( "Old cloth seller", 100 )
|
|
||||||
, ( "Pastry baker", 125 )
|
|
||||||
, ( "Mason", 125 )
|
|
||||||
, ( "Carpenter", 137 )
|
|
||||||
, ( "Ostler", 150 )
|
|
||||||
, ( "Porter", 150 )
|
|
||||||
, ( "Weaver", 150 )
|
|
||||||
, ( "Chandler", 175 )
|
|
||||||
, ( "Mercer", 175 )
|
|
||||||
, ( "Cooper", 175 )
|
|
||||||
, ( "Cobbler", 180 )
|
|
||||||
, ( "Watercarrier", 212 )
|
|
||||||
, ( "Scabbardmaker", 212 )
|
|
||||||
, ( "Wine-seller", 225 )
|
|
||||||
, ( "Hatmaker", 237 )
|
|
||||||
, ( "Saddler", 250 )
|
|
||||||
, ( "Chicken butcher", 250 )
|
|
||||||
, ( "Pursemaker", 275 )
|
|
||||||
, ( "Soapmaker", 275 )
|
|
||||||
, ( "Goldsmith", 300 )
|
|
||||||
, ( "Butcher", 300 )
|
|
||||||
, ( "Farrier", 300 )
|
|
||||||
, ( "Fishmonger", 300 )
|
|
||||||
, ( "Beer seller", 350 )
|
|
||||||
, ( "Buckle Maker", 350 )
|
|
||||||
, ( "Plasterer", 350 )
|
|
||||||
, ( "Spice Merchant", 350 )
|
|
||||||
, ( "Hedge-Mage", 350 )
|
|
||||||
, ( "Painter", 375 )
|
|
||||||
, ( "Hunter", 400 )
|
|
||||||
, ( "Licensed doctor", 425 )
|
|
||||||
, ( "Roofer", 450 )
|
|
||||||
, ( "Locksmith", 475 )
|
|
||||||
, ( "Bather", 475 )
|
|
||||||
, ( "Ropemaker", 475 )
|
|
||||||
, ( "Inn", 500 )
|
|
||||||
, ( "Tanner", 500 )
|
|
||||||
, ( "Copyist", 500 )
|
|
||||||
, ( "Sculptor", 500 )
|
|
||||||
, ( "Rugmaker", 500 )
|
|
||||||
, ( "Dyer", 500 )
|
|
||||||
, ( "Harness-Maker", 500 )
|
|
||||||
, ( "Bleacher", 525 )
|
|
||||||
, ( "Hay Merchant", 575 )
|
|
||||||
, ( "Cutler", 575 )
|
|
||||||
, ( "Glovemaker", 600 )
|
|
||||||
, ( "Woodcarver", 600 )
|
|
||||||
, ( "Woodseller", 600 )
|
|
||||||
, ( "Herald", 600 )
|
|
||||||
, ( "Lorimer", 600 )
|
|
||||||
, ( "Penmaker", 650 )
|
|
||||||
, ( "Horse Trainer", 700 )
|
|
||||||
, ( "Bookbinder", 750 )
|
|
||||||
, ( "Stationer (Ink/Pen Maker)", 700 )
|
|
||||||
, ( "Spurrer", 800 )
|
|
||||||
, ( "Dung Carter", 800 )
|
|
||||||
, ( "Costermonger", 800 )
|
|
||||||
, ( "Fortune Teller", 900 )
|
|
||||||
, ( "Chirurgeon", 900 )
|
|
||||||
, ( "Silversmith", 920 )
|
|
||||||
, ( "Illuminator", 975 )
|
|
||||||
, ( "Coppersmith", 1100 )
|
|
||||||
, ( "Master of Hounds", 1200 )
|
|
||||||
, ( "Leech Collector", 1300 )
|
|
||||||
, ( "Tinsmith", 1400 )
|
|
||||||
, ( "Castellan", 1500 )
|
|
||||||
, ( "Bookseller", 1575 )
|
|
||||||
, ( "Composer", 1600 )
|
|
||||||
, ( "Limeburner", 1600 )
|
|
||||||
, ( "Ale-conner", 1700 )
|
|
||||||
, ( "Amanuensis", 1800 )
|
|
||||||
, ( "Gong Farmer", 1800 )
|
|
||||||
, ( "Coiner", 1900 )
|
|
||||||
, ( "Philosopher", 2000 )
|
|
||||||
, ( "Noble", 3000 )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
type alias RaceData =
|
|
||||||
{ density : Int
|
|
||||||
, maturesAt : Int
|
|
||||||
, livesUntil : Int
|
|
||||||
, becomesParentUntil : Int
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
races : Dict.Dict String RaceData
|
|
||||||
races =
|
|
||||||
Dict.fromList
|
|
||||||
[ ( "Human"
|
|
||||||
, { density = 800000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Half-elf"
|
|
||||||
, { density = 100000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 200
|
|
||||||
, becomesParentUntil = 160
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Dwarf"
|
|
||||||
, { density = 60000
|
|
||||||
, maturesAt = 50
|
|
||||||
, livesUntil = 350
|
|
||||||
, becomesParentUntil = 150
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Elf"
|
|
||||||
, { density = 35000
|
|
||||||
, maturesAt = 100
|
|
||||||
, livesUntil = 750
|
|
||||||
, becomesParentUntil = 500
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Half-orc"
|
|
||||||
, { density = 25000
|
|
||||||
, maturesAt = 14
|
|
||||||
, livesUntil = 75
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Halfling"
|
|
||||||
, { density = 20000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 65
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Dragonborn"
|
|
||||||
, { density = 10000
|
|
||||||
, maturesAt = 15
|
|
||||||
, livesUntil = 80
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Tiefling"
|
|
||||||
, { density = 10000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 110
|
|
||||||
, becomesParentUntil = 45
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Gnome"
|
|
||||||
, { density = 10000
|
|
||||||
, maturesAt = 40
|
|
||||||
, livesUntil = 500
|
|
||||||
, becomesParentUntil = 200
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Aasimar"
|
|
||||||
, { density = 9000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 160
|
|
||||||
, becomesParentUntil = 60
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Orc"
|
|
||||||
, { density = 8000
|
|
||||||
, maturesAt = 12
|
|
||||||
, livesUntil = 50
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Goliath"
|
|
||||||
, { density = 7500
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Tabaxi"
|
|
||||||
, { density = 5000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Hobgoblin"
|
|
||||||
, { density = 2500
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Lizardfolk"
|
|
||||||
, { density = 1500
|
|
||||||
, maturesAt = 14
|
|
||||||
, livesUntil = 60
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Goblin"
|
|
||||||
, { density = 1000
|
|
||||||
, maturesAt = 8
|
|
||||||
, livesUntil = 60
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Yuan-Ti Pureblood"
|
|
||||||
, { density = 1000
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Bugbear"
|
|
||||||
, { density = 1000
|
|
||||||
, maturesAt = 16
|
|
||||||
, livesUntil = 80
|
|
||||||
, becomesParentUntil = 35
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Tortle"
|
|
||||||
, { density = 1000
|
|
||||||
, maturesAt = 15
|
|
||||||
, livesUntil = 50
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Warforged"
|
|
||||||
, { density = 1000
|
|
||||||
, maturesAt = 0
|
|
||||||
, livesUntil = 5000
|
|
||||||
, becomesParentUntil = 5000
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Kobold"
|
|
||||||
, { density = 800
|
|
||||||
, maturesAt = 6
|
|
||||||
, livesUntil = 120
|
|
||||||
, becomesParentUntil = 25
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Shifter"
|
|
||||||
, { density = 750
|
|
||||||
, maturesAt = 10
|
|
||||||
, livesUntil = 70
|
|
||||||
, becomesParentUntil = 30
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Triton"
|
|
||||||
, { density = 400
|
|
||||||
, maturesAt = 15
|
|
||||||
, livesUntil = 200
|
|
||||||
, becomesParentUntil = 110
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Firbolg"
|
|
||||||
, { density = 300
|
|
||||||
, maturesAt = 30
|
|
||||||
, livesUntil = 500
|
|
||||||
, becomesParentUntil = 300
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Kalashtar"
|
|
||||||
, { density = 250
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Aarakocra"
|
|
||||||
, { density = 250
|
|
||||||
, maturesAt = 3
|
|
||||||
, livesUntil = 30
|
|
||||||
, becomesParentUntil = 20
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Kenku"
|
|
||||||
, { density = 200
|
|
||||||
, maturesAt = 12
|
|
||||||
, livesUntil = 60
|
|
||||||
, becomesParentUntil = 36
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Changeling"
|
|
||||||
, { density = 50
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Gith"
|
|
||||||
, { density = 75
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 90
|
|
||||||
, becomesParentUntil = 40
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Air Genasi"
|
|
||||||
, { density = 10
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 120
|
|
||||||
, becomesParentUntil = 50
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Earth Genasi"
|
|
||||||
, { density = 10
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 120
|
|
||||||
, becomesParentUntil = 50
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Fire Genasi"
|
|
||||||
, { density = 10
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 120
|
|
||||||
, becomesParentUntil = 50
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, ( "Water Genasi"
|
|
||||||
, { density = 10
|
|
||||||
, maturesAt = 20
|
|
||||||
, livesUntil = 120
|
|
||||||
, becomesParentUntil = 50
|
|
||||||
}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
module Generatable exposing (Generatable, content, fromGenerator, generateAndReturnFromSeed, generateFromSeed, generate, map, regenerate, setContent, removeContent, updateGenerator)
|
module Generatable exposing (..)
|
||||||
{-| The Generatable type contains information that can be stored, modified,
|
{-| The Generatable type contains information that can be stored, modified,
|
||||||
generated or regenerated.
|
generated or regenerated.
|
||||||
-}
|
-}
|
||||||
|
|
@ -26,25 +26,6 @@ fromGenerator : Random.Generator a -> Generatable a
|
||||||
fromGenerator gr =
|
fromGenerator gr =
|
||||||
ToBeGenerated gr
|
ToBeGenerated gr
|
||||||
|
|
||||||
{-| Get the generator with which new values can be generated.
|
|
||||||
-}
|
|
||||||
generator : Generatable a -> Random.Generator a
|
|
||||||
generator gen =
|
|
||||||
case gen of
|
|
||||||
ToBeGenerated gr ->
|
|
||||||
gr
|
|
||||||
|
|
||||||
Generated _ gr ->
|
|
||||||
gr
|
|
||||||
|
|
||||||
{-| Create a new Generatable from a given seed, and return the value.
|
|
||||||
-}
|
|
||||||
generateAndReturnFromSeed : Random.Seed -> Generatable a -> ( Generatable a, a )
|
|
||||||
generateAndReturnFromSeed seed gen =
|
|
||||||
case Random.step (generator gen) seed of
|
|
||||||
( new, _ ) ->
|
|
||||||
( Generated new (generator gen), new )
|
|
||||||
|
|
||||||
{-| Create a new generatable from a given seed.
|
{-| Create a new generatable from a given seed.
|
||||||
-}
|
-}
|
||||||
generateFromSeed : Random.Seed -> Generatable a -> Generatable a
|
generateFromSeed : Random.Seed -> Generatable a -> Generatable a
|
||||||
|
|
@ -84,13 +65,23 @@ already generated.
|
||||||
-}
|
-}
|
||||||
regenerate : (a -> msg) -> Generatable a -> Cmd msg
|
regenerate : (a -> msg) -> Generatable a -> Cmd msg
|
||||||
regenerate toMsg gen =
|
regenerate toMsg gen =
|
||||||
Random.generate toMsg (generator gen)
|
case gen of
|
||||||
|
ToBeGenerated gr ->
|
||||||
|
Random.generate toMsg gr
|
||||||
|
|
||||||
|
Generated _ gr ->
|
||||||
|
Random.generate toMsg gr
|
||||||
|
|
||||||
{-| Override the content with freshly generated content.
|
{-| Override the content with freshly generated content.
|
||||||
-}
|
-}
|
||||||
setContent : a -> Generatable a -> Generatable a
|
setContent : a -> Generatable a -> Generatable a
|
||||||
setContent x gen =
|
setContent x gen =
|
||||||
Generated x (generator gen)
|
case gen of
|
||||||
|
ToBeGenerated gr ->
|
||||||
|
Generated x gr
|
||||||
|
|
||||||
|
Generated _ gr ->
|
||||||
|
Generated x gr
|
||||||
|
|
||||||
{-| Remove any previously generated content from the generatable.
|
{-| Remove any previously generated content from the generatable.
|
||||||
-}
|
-}
|
||||||
|
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
module Generator exposing (..)
|
|
||||||
|
|
||||||
{-| The Generator module helps generate values based on a given hash.
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Pick exposing (Generator)
|
|
||||||
|
|
||||||
|
|
||||||
commonerOccupation : Generator (Maybe String)
|
|
||||||
commonerOccupation =
|
|
||||||
Pick.inverseWeighted
|
|
||||||
[ ( "Baker", 25 )
|
|
||||||
, ( "Shoemaker", 37 )
|
|
||||||
, ( "Furrier", 62 )
|
|
||||||
, ( "Household helper", 62 )
|
|
||||||
, ( "Tailor", 62 )
|
|
||||||
, ( "Barber", 87 )
|
|
||||||
, ( "Unlicensed Doctor", 87 )
|
|
||||||
, ( "Jeweler", 100 )
|
|
||||||
, ( "Old cloth seller", 100 )
|
|
||||||
, ( "Pastry baker", 125 )
|
|
||||||
, ( "Mason", 125 )
|
|
||||||
, ( "Carpenter", 137 )
|
|
||||||
, ( "Ostler", 150 )
|
|
||||||
, ( "Porter", 150 )
|
|
||||||
, ( "Weaver", 150 )
|
|
||||||
, ( "Chandler", 175 )
|
|
||||||
, ( "Mercer", 175 )
|
|
||||||
, ( "Cooper", 175 )
|
|
||||||
, ( "Cobbler", 180 )
|
|
||||||
, ( "Watercarrier", 212 )
|
|
||||||
, ( "Scabbardmaker", 212 )
|
|
||||||
, ( "Wine-seller", 225 )
|
|
||||||
, ( "Hatmaker", 237 )
|
|
||||||
, ( "Saddler", 250 )
|
|
||||||
, ( "Chicken butcher", 250 )
|
|
||||||
, ( "Pursemaker", 275 )
|
|
||||||
, ( "Soapmaker", 275 )
|
|
||||||
, ( "Goldsmith", 300 )
|
|
||||||
, ( "Butcher", 300 )
|
|
||||||
, ( "Farrier", 300 )
|
|
||||||
, ( "Fishmonger", 300 )
|
|
||||||
, ( "Beer seller", 350 )
|
|
||||||
, ( "Buckle Maker", 350 )
|
|
||||||
, ( "Plasterer", 350 )
|
|
||||||
, ( "Spice Merchant", 350 )
|
|
||||||
, ( "Hedge-Mage", 350 )
|
|
||||||
, ( "Painter", 375 )
|
|
||||||
, ( "Hunter", 400 )
|
|
||||||
, ( "Licensed doctor", 425 )
|
|
||||||
, ( "Roofer", 450 )
|
|
||||||
, ( "Locksmith", 475 )
|
|
||||||
, ( "Bather", 475 )
|
|
||||||
, ( "Ropemaker", 475 )
|
|
||||||
, ( "Inn", 500 )
|
|
||||||
, ( "Tanner", 500 )
|
|
||||||
, ( "Copyist", 500 )
|
|
||||||
, ( "Sculptor", 500 )
|
|
||||||
, ( "Rugmaker", 500 )
|
|
||||||
, ( "Dyer", 500 )
|
|
||||||
, ( "Harness-Maker", 500 )
|
|
||||||
, ( "Bleacher", 525 )
|
|
||||||
, ( "Hay Merchant", 575 )
|
|
||||||
, ( "Cutler", 575 )
|
|
||||||
, ( "Glovemaker", 600 )
|
|
||||||
, ( "Woodcarver", 600 )
|
|
||||||
, ( "Woodseller", 600 )
|
|
||||||
, ( "Herald", 600 )
|
|
||||||
, ( "Lorimer", 600 )
|
|
||||||
, ( "Penmaker", 650 )
|
|
||||||
, ( "Horse Trainer", 700 )
|
|
||||||
, ( "Bookbinder", 750 )
|
|
||||||
, ( "Stationer (Ink/Pen Maker)", 700 )
|
|
||||||
, ( "Spurrer", 800 )
|
|
||||||
, ( "Dung Carter", 800 )
|
|
||||||
, ( "Costermonger", 800 )
|
|
||||||
, ( "Fortune Teller", 900 )
|
|
||||||
, ( "Chirurgeon", 900 )
|
|
||||||
, ( "Silversmith", 920 )
|
|
||||||
, ( "Illuminator", 975 )
|
|
||||||
, ( "Coppersmith", 1100 )
|
|
||||||
, ( "Master of Hounds", 1200 )
|
|
||||||
, ( "Leech Collector", 1300 )
|
|
||||||
, ( "Tinsmith", 1400 )
|
|
||||||
, ( "Castellan", 1500 )
|
|
||||||
, ( "Bookseller", 1575 )
|
|
||||||
, ( "Composer", 1600 )
|
|
||||||
, ( "Limeburner", 1600 )
|
|
||||||
, ( "Ale-conner", 1700 )
|
|
||||||
, ( "Amanuensis", 1800 )
|
|
||||||
, ( "Gong Farmer", 1800 )
|
|
||||||
, ( "Coiner", 1900 )
|
|
||||||
, ( "Philosopher", 2000 )
|
|
||||||
, ( "Noble", 3000 )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
townName : Generator String
|
|
||||||
townName =
|
|
||||||
Pick.map2 (++)
|
|
||||||
(Pick.fromList
|
|
||||||
"Auden"
|
|
||||||
[ "Caia"
|
|
||||||
, "Ex Caia"
|
|
||||||
, "Gold"
|
|
||||||
, "Hirey"
|
|
||||||
, "Ideato"
|
|
||||||
, "Jairo"
|
|
||||||
, "Kalares"
|
|
||||||
, "Oosterdorp"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
(Pick.fromList
|
|
||||||
""
|
|
||||||
[ ""
|
|
||||||
, ""
|
|
||||||
, " City"
|
|
||||||
, " Town"
|
|
||||||
, "'s Creek"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
module Objects exposing (..)
|
|
||||||
|
|
||||||
{-| This module exposes all types that can be generated.
|
|
||||||
-}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
module Objects.District exposing (..)
|
|
||||||
{-| Districts are sections of a town. These are mostly segregated to keep the
|
|
||||||
design of the procedurally generated town simple.
|
|
||||||
-}
|
|
||||||
|
|
||||||
{-| A district is a part of town. Usually, it is a neighbourhood.
|
|
||||||
-}
|
|
||||||
type District
|
|
||||||
= District {}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
module Objects.NPC exposing (..)
|
|
||||||
|
|
||||||
{-| The NPC is the character that is most ordinary.
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Hash exposing (Hash)
|
|
||||||
import Objects.TownName as Town
|
|
||||||
|
|
||||||
|
|
||||||
type NPC
|
|
||||||
= NPC { town : Town.TownName, id : Int }
|
|
||||||
|
|
||||||
|
|
||||||
fromTown : { town : Town.TownName, id : Int } -> NPC
|
|
||||||
fromTown =
|
|
||||||
NPC
|
|
||||||
|
|
||||||
|
|
||||||
toTown : NPC -> Town.TownName
|
|
||||||
toTown (NPC { town }) =
|
|
||||||
town
|
|
||||||
|
|
||||||
|
|
||||||
toId : NPC -> Int
|
|
||||||
toId (NPC { id }) =
|
|
||||||
id
|
|
||||||
|
|
||||||
|
|
||||||
toHash : NPC -> Hash
|
|
||||||
toHash (NPC { town, id }) =
|
|
||||||
Hash.fromString "NPC"
|
|
||||||
|> Hash.dependent (Town.toHash town)
|
|
||||||
|> Hash.dependent (Hash.fromInt id)
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
module Objects.Town exposing (..)
|
|
||||||
|
|
||||||
import Array exposing (Array)
|
|
||||||
import Hash
|
|
||||||
import Random
|
|
||||||
import Generatable exposing (Generatable)
|
|
||||||
import Objects.District as District exposing (District)
|
|
||||||
|
|
||||||
{-| The Msg is the update telling what adjustments are made to the model.
|
|
||||||
-}
|
|
||||||
type Msg
|
|
||||||
= GenerateSize
|
|
||||||
|
|
||||||
{-| The Town is the comprehensive model that contains all the information about
|
|
||||||
a town.
|
|
||||||
-}
|
|
||||||
type Town
|
|
||||||
= Town
|
|
||||||
{ districts : Generatable (Array (Generatable District))
|
|
||||||
, name : String
|
|
||||||
, size : TownSize
|
|
||||||
}
|
|
||||||
|
|
||||||
type TownSize
|
|
||||||
= Tiny
|
|
||||||
| Small
|
|
||||||
| Medium
|
|
||||||
| Average
|
|
||||||
| Big
|
|
||||||
| Huge
|
|
||||||
-- | Humongous
|
|
||||||
-- | Massive
|
|
||||||
-- | Colossal
|
|
||||||
|
|
||||||
{-| Determine the number of districts in the town based on its size.
|
|
||||||
-}
|
|
||||||
districtNumberGenerator : TownSize -> Random.Generator Int
|
|
||||||
districtNumberGenerator ts =
|
|
||||||
case ts of
|
|
||||||
Tiny ->
|
|
||||||
Random.int 1 2
|
|
||||||
|
|
||||||
Small ->
|
|
||||||
Random.int 5 8
|
|
||||||
|
|
||||||
Medium ->
|
|
||||||
Random.int 15 20
|
|
||||||
|
|
||||||
Average ->
|
|
||||||
Random.int 35 45
|
|
||||||
|
|
||||||
Big ->
|
|
||||||
Random.int 90 140
|
|
||||||
|
|
||||||
Huge ->
|
|
||||||
Random.int 250 470
|
|
||||||
|
|
||||||
{-| Init a new town.
|
|
||||||
-}
|
|
||||||
init : { name : String, size : TownSize } -> Town
|
|
||||||
init data =
|
|
||||||
Town
|
|
||||||
{ districts =
|
|
||||||
data.size
|
|
||||||
|> districtNumberGenerator
|
|
||||||
|> Random.map (always never)
|
|
||||||
|> Generatable.fromGenerator
|
|
||||||
, name = data.name
|
|
||||||
, size = data.size
|
|
||||||
}
|
|
||||||
|
|
||||||
{-| Get a town's name.
|
|
||||||
-}
|
|
||||||
name : Town -> String
|
|
||||||
name (Town town) = town.name
|
|
||||||
|
|
||||||
{-| Get a town's size.
|
|
||||||
-}
|
|
||||||
size : Town -> Maybe Int
|
|
||||||
size (Town town) =
|
|
||||||
Generatable.content town.size
|
|
||||||
|
|
||||||
{-| Get a town's size. If it isn't generated yet, generate it.
|
|
||||||
-}
|
|
||||||
sizeGenerate : Town -> ( Town, Int )
|
|
||||||
sizeGenerate ((Town t) as town) =
|
|
||||||
case Generatable.content t.size of
|
|
||||||
Just s ->
|
|
||||||
( town, s )
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
case Generatable.generateAndReturnFromSeed (sizeSeed town) t.size of
|
|
||||||
( newSize, s ) ->
|
|
||||||
( Town { t | size = newSize }, s )
|
|
||||||
|
|
||||||
{-| Generate a seed for the town's size.
|
|
||||||
-}
|
|
||||||
sizeSeed : Town -> Random.Seed
|
|
||||||
sizeSeed (Town town) =
|
|
||||||
Hash.fromString town.name
|
|
||||||
|> Hash.dependent (Hash.fromString "size")
|
|
||||||
|> Hash.toString
|
|
||||||
|> String.toInt
|
|
||||||
|> Maybe.withDefault 0
|
|
||||||
|> Random.initialSeed
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
module Objects.TownName exposing (TownName, fromString, toHash, toString)
|
|
||||||
|
|
||||||
import Hash exposing (Hash)
|
|
||||||
|
|
||||||
|
|
||||||
type TownName
|
|
||||||
= TownName String
|
|
||||||
|
|
||||||
|
|
||||||
{-| Decode a town name from a string.
|
|
||||||
-}
|
|
||||||
fromString : String -> TownName
|
|
||||||
fromString =
|
|
||||||
TownName
|
|
||||||
|
|
||||||
|
|
||||||
{-| Encode a town name into a string.
|
|
||||||
-}
|
|
||||||
toString : TownName -> String
|
|
||||||
toString (TownName name) =
|
|
||||||
name
|
|
||||||
|
|
||||||
|
|
||||||
{-| Hash a town name.
|
|
||||||
-}
|
|
||||||
toHash : TownName -> Hash
|
|
||||||
toHash (TownName name) =
|
|
||||||
Hash.dependent (Hash.fromString "town-name") (Hash.fromString name)
|
|
||||||
68
src/Pick.elm
68
src/Pick.elm
|
|
@ -1,68 +0,0 @@
|
||||||
module Pick exposing (..)
|
|
||||||
|
|
||||||
{-| The pick module helps pick random values based on a given hash.
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Hash exposing (Hash)
|
|
||||||
import Random
|
|
||||||
|
|
||||||
|
|
||||||
type alias Generator a =
|
|
||||||
Random.Generator a
|
|
||||||
|
|
||||||
|
|
||||||
generate : Hash -> Generator a -> a
|
|
||||||
generate hash picker =
|
|
||||||
let
|
|
||||||
seed : Random.Seed
|
|
||||||
seed =
|
|
||||||
hash
|
|
||||||
|> Hash.toString
|
|
||||||
|> String.toInt
|
|
||||||
|> Maybe.withDefault 0
|
|
||||||
|> Random.initialSeed
|
|
||||||
in
|
|
||||||
Random.step
|
|
||||||
|
|
||||||
|
|
||||||
fromList : a -> List a -> Generator a
|
|
||||||
fromList head tail =
|
|
||||||
Random.uniform head tail
|
|
||||||
|
|
||||||
|
|
||||||
inverseWeighted : List ( a, Int ) -> Generator (Maybe a)
|
|
||||||
inverseWeighted items =
|
|
||||||
let
|
|
||||||
chanceSum : Float
|
|
||||||
chanceSum =
|
|
||||||
items
|
|
||||||
|> List.map Tuple.second
|
|
||||||
|> List.map toFloat
|
|
||||||
|> List.map ((/) 1)
|
|
||||||
|> List.sum
|
|
||||||
in
|
|
||||||
items
|
|
||||||
|> List.map (Tuple.mapSecond (\i -> 1 / toFloat i))
|
|
||||||
|> List.map (\( a, b ) -> ( b, a ))
|
|
||||||
|> List.map (Tuple.mapSecond Just)
|
|
||||||
|> weighted ( max 0 (1 - chanceSum), Nothing )
|
|
||||||
|
|
||||||
|
|
||||||
map : (a -> b) -> Generator a -> Generator b
|
|
||||||
map =
|
|
||||||
Random.map
|
|
||||||
|
|
||||||
|
|
||||||
map2 : (a -> b -> c) -> Generator a -> Generator b -> Generator c
|
|
||||||
map2 =
|
|
||||||
Random.map2
|
|
||||||
|
|
||||||
|
|
||||||
value : a -> Generator a
|
|
||||||
value =
|
|
||||||
Random.constant
|
|
||||||
|
|
||||||
|
|
||||||
weighted : ( Float, a ) -> List ( Float, a ) -> Generator a
|
|
||||||
weighted =
|
|
||||||
Random.weighted
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
module Seed.Town exposing (TownSeed, fromName, toHash, toSeed)
|
|
||||||
{-| The Town Seed helps generate different towns.
|
|
||||||
-}
|
|
||||||
|
|
||||||
import Hash
|
|
||||||
import Random
|
|
||||||
|
|
||||||
type TownSeed = TownSeed String
|
|
||||||
|
|
||||||
fromName : String -> TownSeed
|
|
||||||
fromName name = TownSeed name
|
|
||||||
|
|
||||||
toHash : TownSeed -> Hash.Hash
|
|
||||||
toHash (TownSeed name) =
|
|
||||||
Hash.fromString name
|
|
||||||
|
|
||||||
toSeed : TownSeed -> Random.Seed
|
|
||||||
toSeed seed =
|
|
||||||
seed
|
|
||||||
|> toHash
|
|
||||||
|> Hash.toString
|
|
||||||
|> String.toInt
|
|
||||||
|> Maybe.withDefault 0
|
|
||||||
|> Random.initialSeed
|
|
||||||
Loading…
Reference in New Issue