Skip to content

Commit

Permalink
(green) Don't let user exceed the number of available levels
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxWilson committed Jan 11, 2024
1 parent 173389b commit f31a319
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/Core/Common.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ let thunk v _ = v
let thunk1 f arg _ = f arg
let thunk2 f arg1 arg2 _ = f arg1 arg2
let thunk3 f arg1 arg2 arg3 _ = f arg1 arg2 arg3
let thunk4 f arg1 arg2 arg3 arg4 _ = f arg1 arg2 arg3 arg4
let tuple2 x y = x,y
let matchfail v = sprintf "No match found for %A. This is a bug." v |> invalidOp
let ignoreM (_, monad) = (), monad
Expand Down
10 changes: 5 additions & 5 deletions src/Core/Menus.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Key = KeySegment ReversedList
type MenuOutput =
| Either of label: string option * options: MenuSelection list
| And of label: string option * grants: MenuOutput list
| Leveled of label: string * Key * level: int
| Leveled of label: string * Key * currentLevel: int * levelCount: int
| Leaf of label: string
with
member this.DisplayText =
Expand All @@ -18,7 +18,7 @@ type MenuOutput =
| Either(Some label, children) -> $"Either({label}, {show children})"
| And(None, grants) -> $"And({show grants})"
| And(Some label, grants) -> $"And({label}, {show grants})"
| Leveled(label, key, level) -> $"Leveled({label}, {key}, {level})"
| Leveled(label, key, currentLevel, levelCount) -> $"Leveled({label}, {key}, {currentLevel}, {levelCount})"
| Leaf(label) -> $"Leaf({label})"
and MenuSelection = bool * Key * MenuOutput

Expand Down Expand Up @@ -67,7 +67,7 @@ type 'reactElement RenderApi = {
checked': string * Key * ('reactElement list) -> 'reactElement
unchecked: string * Key -> 'reactElement
unconditional: string * ('reactElement list) -> 'reactElement
leveledLeaf: string * Key * int -> 'reactElement
leveledLeaf: string * Key * int * int -> 'reactElement // label, key, currentValue, levelCount
combine: 'reactElement list -> 'reactElement
}

Expand All @@ -94,7 +94,7 @@ let render (render: 'reactElement RenderApi) (menus: MenuOutput list) =
| And(label, grants) ->
let childReacts = grants |> List.map (recur true render.unconditional)
renderMe(defaultArg label "And:", childReacts)
| Leveled(name, key, lvl) -> render.leveledLeaf(name, key, lvl)
| Leveled(name, key, lvl, levelCount) -> render.leveledLeaf(name, key, lvl, levelCount)
| Leaf(name) -> renderMe(name, [])
menus |> List.map (recur true render.unconditional) |> render.combine

Expand Down Expand Up @@ -157,7 +157,7 @@ type Op =
let level ix =
let level = levels[ix] // e.g. if this is skill("Rapier", [+5..+8]) then ix 0 means level = +5 and value = Rapier +5
let value = spec.ctor level
Some value, Leveled(defaultArg config.label $"{spec.toString value}", fullKey, ix)
Some value, Leveled(defaultArg config.label $"{spec.toString value}", fullKey, ix, levels.Length)
match input.lookup fullKey with
| Some (Level lvl) when lvl < levels.Length -> level lvl
| _ when levels.Length >= 1 -> // we are permissive in the input we accept, partly to make testing easier. Flag means "default to the lowest value", e.g. Rapier +5-+7 defaults to Rapier +5.
Expand Down
7 changes: 4 additions & 3 deletions src/UI/DFRPG/ChargenView.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ module private Impl =
let toggle dispatch (key: Key) (newValue: bool) =
if newValue then dispatch (SetKey(key, Some Flag))
else dispatch (SetKey(key, None))
let changeLevel dispatch key (newLevel: int) =
()
let changeLevel dispatch key (newLevel: int) (levelCount: int) =
if newLevel < 0 then dispatch (SetKey(key, None))
elif newLevel < levelCount then dispatch (SetKey(key, Some (Level newLevel)))
let checkbox (txt: string) checked' (onChange: bool -> unit) children =
let id = System.Guid.NewGuid().ToString()
Html.li [
Expand All @@ -27,7 +28,7 @@ module private Impl =
{
checked' = fun (label, key, children) -> checkbox label true (toggle key) children
unchecked = fun (label, key) -> checkbox label false (toggle key) []
leveledLeaf = fun (label, key, level) -> class' "" Html.li [ button "-" (thunk3 changeLevel dispatch key (level-1)); button "+" (thunk3 changeLevel dispatch key (level+1)); Html.text label ]
leveledLeaf = fun (label, key, level, levelCount) -> class' "" Html.li [ button "-" (thunk4 changeLevel dispatch key (level-1) levelCount); button "+" (thunk4 changeLevel dispatch key (level+1) levelCount); Html.text label ]
unconditional = fun (label, children) -> class' "" Html.li [ Html.text label; combine children ]
combine = combine
}
Expand Down
10 changes: 5 additions & 5 deletions test/Chargen.Accept.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ type Pseudoreact =
| Checked of string * Key * Pseudoreact list
| Unchecked of string * Key
| Unconditional of string * Pseudoreact list
| NumberInput of string * Key * int
| NumberInput of string * Key * int * int
| Fragment of Pseudoreact list

let pseudoReactApi = {
Expand Down Expand Up @@ -128,7 +128,7 @@ let units = testList "Unit.Chargen" [
nestedEither |> testFor ["Sword!"; "Sword!-Rapier"] (
Either(None, [
true, key "Sword!", Either(Some "Sword!", [
true, key "Sword!-Rapier", Leveled("Rapier +5", key "Sword!-Rapier", 0) // it's a Levelled, not a Leaf, because it's currently selected. Note that the level is 0, not +5, because it's the lowest level out of +5 to +5.
true, key "Sword!-Rapier", Leveled("Rapier +5", key "Sword!-Rapier", 0, 2) // it's a Levelled, not a Leaf, because it's currently selected. Note that the level is 0, not +5, because it's the lowest level out of +5 to +5.
])
])
)
Expand Down Expand Up @@ -176,7 +176,7 @@ let tests =
let offers = swash()
let expectedMenus = [
Leaf "Climbing +1" // Leaf not Level because swash() template is only using trait', not level
Leveled("Stealth +1", key "Stealth", 0) // Leveled because it can go up to +3
Leveled("Stealth +1", key "Stealth", 0, 3) // Leveled because it can go up to +3
Either(None, [
false, key "Combat Reflexes", Leaf "Combat Reflexes"
false, key "Acrobatics", Leaf "Acrobatics +1"
Expand All @@ -196,13 +196,13 @@ let tests =
let (|Checked|) = function Checked(label, key, children) -> Checked(label, key, children) | v -> fail "Checked" v
let (|Unchecked|) = function Unchecked(label, key) -> Unchecked(label, key) | v -> fail "Unchecked" v
let (|Unconditional|) = function Unconditional(label, children) -> Unconditional(label, children) | v -> fail "Unconditional" v
let (|NumberInput|) = function NumberInput(label, key, value) -> NumberInput(label, key, value) | v -> fail "NumberInput" v
let (|NumberInput|) = function NumberInput(label, key, value, levelCount) -> NumberInput(label, key, value, levelCount) | v -> fail "NumberInput" v
let (|Fragment|) = function Fragment(children) -> Fragment(children) | v -> fail "Fragment" v
let (|Expect|_|) expect actual = if expect = actual then Some () else fail expect actual
match pseudoActual with
| Fragment([
Unconditional(Expect "Climbing +1", [])
NumberInput(Expect "Stealth +1", Expect ["Stealth"], Expect 0)
NumberInput(Expect "Stealth +1", Expect ["Stealth"], Expect 0, Expect 3)
Unconditional(Expect "Choose one:", [
Unchecked(Expect "Combat Reflexes", Expect ["Combat Reflexes"])
Unchecked(Expect "Acrobatics +1", Expect ["Acrobatics"]) // note: Acrobatics is the key here, not Acrobatics +1, because it's leveled.
Expand Down

0 comments on commit f31a319

Please sign in to comment.