Add 'game-sml/' from commit '113c3e67abe635f714f972a1e2ab0e4b24ff10f4'

git-subtree-dir: game-sml
git-subtree-mainline: aa5357714d
git-subtree-split: 113c3e67ab
This commit is contained in:
2026-04-24 00:38:14 +01:00
174 changed files with 337598 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
signature OPTIONS_TYPE =
sig
datatype focus =
LEFT_KEY
| RIGHT_KEY
| UP_KEY
| DOWN_KEY
| JUMP_KEY
| ATTACK_KEY
| SAVE_BUTTON
| CANCEL_BUTTON
type options_type =
{ focus: focus
, isSelected: bool
, lastUpPress: Time.time
, lastDownPress: Time.time
, tempKeys: CoreKey.user_key
}
val init: CoreKey.user_key -> options_type
end
structure OptionsType : OPTIONS_TYPE =
struct
datatype focus =
LEFT_KEY
| RIGHT_KEY
| UP_KEY
| DOWN_KEY
| JUMP_KEY
| ATTACK_KEY
| SAVE_BUTTON
| CANCEL_BUTTON
type options_type =
{ focus: focus
, isSelected: bool
, lastUpPress: Time.time
, lastDownPress: Time.time
, tempKeys: CoreKey.user_key
}
fun init userKeys =
{ focus = LEFT_KEY
, isSelected = false
, lastUpPress = Time.zeroTime
, lastDownPress = Time.zeroTime
, tempKeys = userKeys
}
end

View File

@@ -0,0 +1,377 @@
signature MAKE_UPDATE_SELECTED_KEY =
sig
val updateKeys: CoreKey.key_code * CoreKey.user_key -> CoreKey.user_key
val default: OptionsType.options_type * CoreKey.user_key -> GameType.game_type
val deselect: OptionsType.options_type * CoreKey.user_key
-> GameType.game_type
end
functor MakeUpdateSelectedKey(Fn: MAKE_UPDATE_SELECTED_KEY) =
struct
fun setNewKeys (options, tempKeys, userKeys, time) =
let
val {focus, lastUpPress, lastDownPress, ...} = options
val options =
{ focus = focus
, lastUpPress = time
, lastDownPress = time
, isSelected = false
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun onSelected (options, input: FrameInputType.t, userKeys, time) =
case #newKeys input of
key :: tl =>
(* change key *)
if key = CoreKey.KEY_ESCAPE orelse CoreKey.containsEscape (userKeys, tl) then
(* deslect as that is the function of the escape key *)
Fn.deselect (options, userKeys)
(* what if new key collides with existing key? todo *)
else
let val tempKeys = Fn.updateKeys (key, #tempKeys options)
in setNewKeys (options, tempKeys, userKeys, time)
end
| [] => Fn.default (options, userKeys)
end
structure OptionsUpdate =
struct
open OptionsType
fun default (options: OptionsType.options_type, userKeys) =
let
val {focus, isSelected, tempKeys, ...} = options
(* `default` function is called when no keys are pressed
* so set up pressed/down pressed both to 0
* as neither is being pressed. *)
val options =
{ focus = focus
, lastUpPress = Time.zeroTime
, lastDownPress = Time.zeroTime
, isSelected = isSelected
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun moveFocusUp (options: OptionsType.options_type, newFocus, userKeys, time) =
let
(* only opening Time for time comparison and adding; no impurities here *)
open Time
val {focus, isSelected, lastUpPress, tempKeys, ...} = options
(* only switch to newFocus if it is time for key delay to be triggered.
* We set lastDownPress to 0 because up is currently being pressed instead
* so we don't want to a key delay for down. *)
val options =
if lastUpPress + Constants.keyDelay <= time then
{ focus = newFocus
, lastUpPress = time
, lastDownPress = Time.zeroTime
, isSelected = isSelected
, tempKeys = tempKeys
}
else
{ focus = focus
, lastUpPress = lastUpPress
, lastDownPress = Time.zeroTime
, isSelected = isSelected
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun moveFocusDown
(options: OptionsType.options_type, newFocus, userKeys, time) =
let
(* only opening Time for time comparison and adding; no impurities here *)
open Time
val {focus, isSelected, lastDownPress, tempKeys, ...} = options
val options =
if lastDownPress + Constants.keyDelay <= time then
{ focus = newFocus
, lastUpPress = Time.zeroTime
, lastDownPress = time
, isSelected = isSelected
, tempKeys = tempKeys
}
else
{ focus = focus
, lastUpPress = Time.zeroTime
, lastDownPress = lastDownPress
, isSelected = isSelected
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun select (options: OptionsType.options_type, userKeys) =
let
val {focus, lastUpPress, lastDownPress, tempKeys, ...} = options
val options =
{ focus = focus
, lastUpPress = lastUpPress
, lastDownPress = lastDownPress
, isSelected = true
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun deselect (options: OptionsType.options_type, userKeys) =
let
val {focus, lastUpPress, lastDownPress, tempKeys, ...} = options
val options =
{ focus = focus
, lastUpPress = lastUpPress
, lastDownPress = lastDownPress
, isSelected = false
, tempKeys = tempKeys
}
in
{mode = GameType.OPTIONS options, userKeys = userKeys, saveKeys = false}
end
fun withLeftKeys (newLeft, userKeys: CoreKey.user_key) =
let
val {right, up, down, jump, attack, escape, ...} = userKeys
in
{ left = newLeft
, right = right
, up = up
, down = down
, jump = jump
, attack = attack
, escape = escape
}
end
fun withRightKeys (newRight, userKeys: CoreKey.user_key) =
let
val {left, up, down, jump, attack, escape, ...} = userKeys
in
{ left = left
, right = newRight
, up = up
, down = down
, jump = jump
, attack = attack
, escape = escape
}
end
fun withUpKeys (newUp, userKeys: CoreKey.user_key) =
let
val {left, right, down, jump, attack, escape, ...} = userKeys
in
{ left = left
, right = right
, up = newUp
, down = down
, jump = jump
, attack = attack
, escape = escape
}
end
fun withDownKeys (newDown, userKeys: CoreKey.user_key) =
let
val {left, right, up, jump, attack, escape, ...} = userKeys
in
{ left = left
, right = right
, up = up
, down = newDown
, jump = jump
, attack = attack
, escape = escape
}
end
fun withJumpKeys (newJump, userKeys: CoreKey.user_key) =
let
val {left, right, up, down, attack, escape, ...} = userKeys
in
{ left = left
, right = right
, up = up
, down = down
, jump = newJump
, attack = attack
, escape = escape
}
end
fun withAttackKeys (newAttack, userKeys: CoreKey.user_key) =
let
val {left, right, up, down, jump, escape, ...} = userKeys
in
{ left = left
, right = right
, up = up
, down = down
, jump = jump
, attack = newAttack
, escape = escape
}
end
structure UpdateLeftKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withLeftKeys
val default = default
val deselect = deselect
end)
structure UpdateRightKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withRightKeys
val default = default
val deselect = deselect
end)
structure UpdateUpKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withUpKeys
val default = default
val deselect = deselect
end)
structure UpdateDownKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withDownKeys
val default = default
val deselect = deselect
end)
structure UpdateJumpKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withJumpKeys
val default = default
val deselect = deselect
end)
structure UpdateAttackKey =
MakeUpdateSelectedKey
(struct
val updateKeys = withAttackKeys
val default = default
val deselect = deselect
end)
fun saveAndGoToTitle options =
let
val userKeys = #tempKeys options
in
{ mode = GameType.TITLE TitleType.initial
, userKeys = userKeys
, saveKeys = true
}
end
fun cancelAndGoToTitle userKeys =
{ mode = GameType.TITLE TitleType.initial
, userKeys = userKeys
, saveKeys = false
}
fun update (options, input: FrameInputType.t, userKeys, time) =
case #focus options of
LEFT_KEY =>
if #isSelected options then
UpdateLeftKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, CANCEL_BUTTON, userKeys, time)
else if #downHeld input then
moveFocusDown (options, RIGHT_KEY, userKeys, time)
else
default (options, userKeys)
| RIGHT_KEY =>
if #isSelected options then
UpdateRightKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, LEFT_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, UP_KEY, userKeys, time)
else
default (options, userKeys)
| UP_KEY =>
if #isSelected options then
UpdateUpKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, RIGHT_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, DOWN_KEY, userKeys, time)
else
default (options, userKeys)
| DOWN_KEY =>
if #isSelected options then
UpdateDownKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, UP_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, JUMP_KEY, userKeys, time)
else
default (options, userKeys)
| JUMP_KEY =>
if #isSelected options then
UpdateJumpKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, DOWN_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, ATTACK_KEY, userKeys, time)
else
default (options, userKeys)
| ATTACK_KEY =>
if #isSelected options then
UpdateAttackKey.onSelected (options, input, userKeys, time)
else if CoreKey.containsAttack (userKeys, #newKeys input) then
select (options, userKeys)
else if #upHeld input then
moveFocusUp (options, JUMP_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, SAVE_BUTTON, userKeys, time)
else
default (options, userKeys)
| SAVE_BUTTON =>
if CoreKey.containsAttack (userKeys, #newKeys input) then
saveAndGoToTitle options
else if #upHeld input then
moveFocusUp (options, ATTACK_KEY, userKeys, time)
else if #downHeld input then
moveFocusDown (options, CANCEL_BUTTON, userKeys, time)
else
default (options, userKeys)
| CANCEL_BUTTON =>
if CoreKey.containsAttack (userKeys, #newKeys input) then
cancelAndGoToTitle userKeys
else if #upHeld input then
moveFocusUp (options, SAVE_BUTTON, userKeys, time)
else if #downHeld input then
moveFocusDown (options, LEFT_KEY, userKeys, time)
else
default (options, userKeys)
end

View File

@@ -0,0 +1,290 @@
structure OptionsVec =
struct
open OptionsType
(* There's code duplication here because we want to avoid
* branhing if/case expressions per draw-call because of
* the branch prediction cost *)
fun drawLeftKey (options, width, height) =
let
val acc =
if #isSelected options then
MakeTextVec.make
(155, 35, width, height, "Left key", 0.7, 0.7, 0.3, [])
else
MakeTextVec.make
(155, 35, width, height, "Left key", 0.3, 0.3, 0.7, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawRightKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc =
if #isSelected options then
MakeTextVec.make
(155, 95, width, height, "Right key", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 95, width, height, "Right key", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawUpKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 155, width, height, "Up key", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 155, width, height, "Up key", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawDownKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 215, width, height, "Down key", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 215, width, height, "Down key", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawJumpKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 275, width, height, "Jump key", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 275, width, height, "Jump key", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawAttackKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 335, width, height, "Attack key", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 335, width, height, "Attack key", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawSaveKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 395, width, height, "Save changes", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 395, width, height, "Save changes", 0.3, 0.3, 0.7, acc)
val acc = MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.0, 0.0, 0.0, acc)
in
Vector.concat acc
end
fun drawCancelKey (options, width, height) =
let
val acc = MakeTextVec.make
(155, 35, width, height, "Left key", 0.0, 0.0, 0.0, [])
val acc = MakeTextVec.make
(155, 95, width, height, "Right key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 155, width, height, "Up key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 215, width, height, "Down key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 275, width, height, "Jump key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 335, width, height, "Attack key", 0.0, 0.0, 0.0, acc)
val acc = MakeTextVec.make
(155, 395, width, height, "Save changes", 0.0, 0.0, 0.0, acc)
val acc =
if #isSelected options then
MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.7, 0.7, 0.3, acc)
else
MakeTextVec.make
(155, 455, width, height, "Cancel changes", 0.3, 0.3, 0.7, acc)
in
Vector.concat acc
end
fun getDrawVec (options: OptionsType.options_type, width, height) =
case #focus options of
LEFT_KEY => drawLeftKey (options, width, height)
| RIGHT_KEY => drawRightKey (options, width, height)
| UP_KEY => drawUpKey (options, width, height)
| DOWN_KEY => drawDownKey (options, width, height)
| JUMP_KEY => drawJumpKey (options, width, height)
| ATTACK_KEY => drawAttackKey (options, width, height)
| SAVE_BUTTON => drawSaveKey (options, width, height)
| CANCEL_BUTTON => drawCancelKey (options, width, height)
end