intricacy 0.9.0.0 → 0.9.1.0
raw patch · 11 files changed
+337/−296 lines, 11 files
Files
- Cache.hs +1/−1
- MainState.hs +12/−2
- NEWS +0/−108
- NEWS.md +118/−0
- README +0/−157
- README.md +157/−0
- SDL2RenderCache.hs +3/−3
- SDL2UI.hs +40/−20
- SDL2UIMInstance.hs +2/−1
- intricacy.cabal +3/−3
- tutorial/05-hook.text +1/−1
Cache.hs view
@@ -81,7 +81,7 @@ makeRequest saddr@(ServerAddr host prt) request = handle (return . ServerError . (show::SomeException -> String)) $ do connect host (show prt) makeRequest'- `catchIO` const (return $ ServerError $ "Cannot connect to "++saddrStr saddr++"!")+ `catchIO` (\e -> return $ ServerError $ "Cannot connect to "++saddrStr saddr++"! "++show e) where makeRequest' (sock,_) = do send sock . BL.toStrict $ encode request
MainState.hs view
@@ -76,6 +76,8 @@ ok <- initUI if ok then m >>= (endUI >>).return.Just else return Nothing +type TutorialLevel = Maybe Int+ -- | this could be neatened using GADTs data MainState = PlayState@@ -87,7 +89,7 @@ , psGameStateMoveStack :: [(GameState, PlayerMove)] , psUndoneStack :: [PlayerMove] , psTitle :: Maybe String- , psTutLevel :: Maybe Int+ , psTutLevel :: TutorialLevel , psIsSub :: Bool , psSaved :: Bool , psMarks :: Map Char MainState@@ -152,6 +154,10 @@ InitState {} -> IMInit MetaState {} -> IMMeta +getTutLevel :: MainState -> TutorialLevel+getTutLevel s@(PlayState {}) = psTutLevel s+getTutLevel _ = Nothing+ newPlayState (frame,st) pms title tutLev sub saved = PlayState st frame [] False False [] pms title tutLev sub saved Map.empty newReplayState st soln title = ReplayState st [] soln [] title Map.empty newEditState (frame,st) msoln mpath = EditState st [] [] frame mpath@@ -182,9 +188,13 @@ } deriving (Eq, Ord, Show, Read) initTutProgress = TutProgress False 1 Nothing -wrenchOnlyTutLevel, noUndoTutLevel :: Maybe Int -> Bool+wrenchOnlyTutLevel, noUndoTutLevel, keysTutLevel, conflictsTutLev :: TutorialLevel -> Bool wrenchOnlyTutLevel = (`elem` (Just <$> [1..4])) noUndoTutLevel = (`elem` (Just <$> [1..7]))+keysTutLevel (Just n) = n >= 5+keysTutLevel _ = False+conflictsTutLev (Just n) = n == 11+conflictsTutLev _ = False data InitLock = InitLock { initLockName :: String
− NEWS
@@ -1,108 +0,0 @@-This is an abbreviated summary; see the git log for gory details.--0.9:- Switch from SDL1 to SDL2.- Animate force conflicts.- Rework default keybindings and click-to-move.- Allow adjusting sound volume.- Add tutorial lock and 3 initiation locks.- Replace inefficient Read-based serialisation of user info with Binary.-0.8.2:- Show esteem with symbols as well as colour (thanks Locria Cyber)- Fix relative esteem calculation display-0.8.1:- Revise tutorial and initiation levels REP and GAP- Disallow overextended/compressed springs- Allow editing spring tension by turning- Add compact solution format- Revert scoring change introduced in 0.6- Add --datadir option- Fix loading partial initiation solutions- Fix server locking-0.8:- Add single-player introductory subgame ("initiation").- Improve UI variously.-0.7.2.3:- Hopefully work around curses build failures-0.7.2.1:- Support >=ghc-8.6.5-0.7.2:- Support ghc-8.0- Use Argon2 for server-side password hashing- Tweak graphics and text-0.7.1.1:- Make server compatible with feed-1.0.0 (thanks constatinus)- Avoid DOS-reserved codenames (thanks constatinus)-0.7.1:- Rework tutorial and intro.- Animate movement.- Prevent dragging wrench off-path from generating a move.- Various UI improvements.-0.7.0.1:- Fix compile error on older ghc versions.-0.7:- Encrypt passwords when communicating with server- (in previous versions, they were salted and hashed but not encrypted).- Clean out solutions when a lock becomes public.- Various UI improvements, particularly for curses mode.--0.6.2:- Fix obscure but actual bug in core game physics:- wrenches were being blocked when they shouldn't be.- See TST:C on the main server for an example - it can be solved only in- intricacy versions prior to this one.- Extra help text screen for editing first lock.- Cycle through all possibilities when placing blocks in editor.--0.6.1:- Fix stupid bug preventing registration via keyboard command.--0.6:- New scoring system - you don't get the point for a solution if the lock- owner has read your note.- Server optionally notifies users by email when their locks are solved.- Server produces RSS feeds.- Save solutions-in-progress of locks and tutorial.- Indicate when there's a pending network request, and allow cancellation.- Support ghc-7.10.- Support OS X (thanks Kevin Eaves).- Further tweaks to UI and tutorials.--0.5:- Adjustments to graphics, tutorial, and metagame UI, to increase clarity.- Concurrency on server; no more freezes while it checks a solution.- Misc optimisations.- Fix sound lag on Windows.- -0.4:- Sound effects (thanks linley).- Animate to show the two physics phases (thanks dormir).- Help screens.- Help text for buttons and metagame.- Deneutralised metagame terminology.- Tutorial tweaked.- Various UI improvements (thanks Quicksand-S and dormir)--0.3:- Mouse control.- Improvements to curses UI - handle resizing; show keys; allow rebinding.- Shortened tutorial drastically. Other levels now in 'tutorial-extra/'.- Improve handling inaccessible servers.- Added background.- First version uploaded to hackage.- Scoring tweak: empty slots are accessed iff all non-empty slots are.- Detailed game info in README.- Hover text for UI buttons.- Marks.- Lock testing in edit mode.- Significant bugs fixed:- editor, lockfile reader, and validity checker were not in accordance- on what is allowed as the root of a spring.- SDL UI was redrawing the screen on every mouse movement.- curses UI wasn't refreshing properly on async flag.- stale notes weren't getting refreshed.- retired display got stuck on changing codename.- you couldn't move into the bolthole with keyboard commands.- -0.2:- First public release
+ NEWS.md view
@@ -0,0 +1,118 @@+This is an abbreviated summary; see the git log for gory details.++# 0.9+* Switch from SDL1 to SDL2.+* Animate force conflicts.+* Rework default keybindings and click-to-move.+* Allow adjusting sound volume.+* Add tutorial lock and 3 initiation locks.+* Replace inefficient Read-based serialisation of user info with Binary.++# 0.8.2+* Show esteem with symbols as well as colour (thanks Locria Cyber)+* Fix relative esteem calculation display++# 0.8.1+* Revise tutorial and initiation levels REP and GAP+* Disallow overextended/compressed springs+* Allow editing spring tension by turning+* Add compact solution format+* Revert scoring change introduced in 0.6+* Add --datadir option+* Fix loading partial initiation solutions+* Fix server locking++# 0.8+* Add single-player introductory subgame ("initiation").+* Improve UI variously.++# 0.7.2.3+* Hopefully work around curses build failures++# 0.7.2.1+* Support >=ghc-8.6.5++# 0.7.2+* Support ghc-8.0+* Use Argon2 for server-side password hashing+* Tweak graphics and text++# 0.7.1.1+* Make server compatible with feed-1.0.0 (thanks constatinus)+* Avoid DOS-reserved codenames (thanks constatinus)++# 0.7.1+* Rework tutorial and intro.+* Animate movement.+* Prevent dragging wrench off-path from generating a move.+* Various UI improvements.++# 0.7.0.1+* Fix compile error on older ghc versions.++# 0.7+* Encrypt passwords when communicating with server+ (in previous versions, they were salted and hashed but not encrypted).+* Clean out solutions when a lock becomes public.+* Various UI improvements, particularly for curses mode.++# 0.6.2+* Fix obscure but actual bug in core game physics:+ wrenches were being blocked when they shouldn't be.+ See TST:C on the main server for an example - it can be solved only in+ intricacy versions prior to this one.+* Extra help text screen for editing first lock.+* Cycle through all possibilities when placing blocks in editor.++# 0.6.1+* Fix stupid bug preventing registration via keyboard command.++# 0.6+* New scoring system - you don't get the point for a solution if the lock+owner has read your note.+* Server optionally notifies users by email when their locks are solved.+* Server produces RSS feeds.+* Save solutions-in-progress of locks and tutorial.+* Indicate when there's a pending network request, and allow cancellation.+* Support ghc-7.10.+* Support OS X (thanks Kevin Eaves).+* Further tweaks to UI and tutorials.++# 0.5+* Adjustments to graphics, tutorial, and metagame UI, to increase clarity.+* Concurrency on server; no more freezes while it checks a solution.+* Misc optimisations.+* Fix sound lag on Windows.++# 0.4+* Sound effects (thanks linley).+* Animate to show the two physics phases (thanks dormir).+* Help screens.+* Help text for buttons and metagame.+* Deneutralised metagame terminology.+* Tutorial tweaked.+* Various UI improvements (thanks Quicksand-S and dormir)++# 0.3+* Mouse control.+* Improvements to curses UI - handle resizing; show keys; allow rebinding.+* Shortened tutorial drastically. Other levels now in 'tutorial-extra/'.+* Improve handling inaccessible servers.+* Added background.+* First version uploaded to hackage.+* Scoring tweak: empty slots are accessed iff all non-empty slots are.+* Detailed game info in README.+* Hover text for UI buttons.+* Marks.+* Lock testing in edit mode.+* Significant bugs fixed:+* editor, lockfile reader, and validity checker were not in accordance+ on what is allowed as the root of a spring.+* SDL UI was redrawing the screen on every mouse movement.+* curses UI wasn't refreshing properly on async flag.+* stale notes weren't getting refreshed.+* retired display got stuck on changing codename.+* you couldn't move into the bolthole with keyboard commands.++# 0.2+* First public release
− README
@@ -1,157 +0,0 @@-# Intricacy-A game of competitive puzzle-design.--https://mbays.sdf.org/intricacy/--## Configuration-You can change keybindings in SDL mode by right-clicking on the corresponding-button and pressing a key.--Config files are saved in `~/.intricacy/` on unixoids, or something like-`...\Application Data\intricacy\` on windows. In particular, the locks you-create in the lock editor are saved in there (and you can organise them into-directories by including (back)slashs in the lock name). You can edit them in-a text editor if you want - see AsciiLock.hs for what the characters mean.--If you want to cheat your way past initiation, change "False" to "True" in-`metagame.conf`.---## Rough description of the game mechanics-* Locks consist of blocks, pivots and balls. Blocks can be connected to other- blocks by springs. Pivots have arms. When picking a lock, you control two- tools - a hook, which acts as a mobile one-armed pivot, and a wrench,- which acts as a mobile block with momentum.-* To open a lock, the "bolthole" (the area in the top-right) must be empty.-* Each turn, the tools push and rotate according to the player's commands, and- then each spring which is compressed or extended beyond its natural length- pushes/pulls on the block at its end.-* If two forces try to move a piece in two different directions, or try to- move two pieces into the same hex, one or both is blocked.-* If a pivot/hook is trying to turn and there's a piece in the way of one of- its arms, it will at first try to push the piece away - but if that force- is blocked, it will try instead to pull the piece round with the arm as it- turns.-* If two springs are trying to push two blocks into the same hex, they will- generally both be blocked. However, if one of the forces is also pushing- against a fixed piece such as a tool, it won't block the other force.---## Full details of the metagame mechanics-(Where by the 'game' I mean the lock-picking bit, and by the 'metagame' I mean-the bit with the 3-letter codenames and the three lock slots and notes and so-on. If you haven't seen anything of the kind... keep solving those locks!)--Scoring is always relative - each player has a score relative to each other-player. That score is the number of the second player's lock slots to which-the first player has access, minus the number of the first player's lock slots-to which the second player has access.--A player accesses a lock slot when one of the following holds- * the player has solved the lock in the slot, and declared the solution;- * the player has read three notes on the lock in the slot;- * there's no lock in the slot, and the player has accessed all the slots- which do have locks in them.--A player reads every note in every lock the player accesses. When a lock is-replaced ('retired'), each note secured by the lock becomes 'public', and is-read by every player.--Note this means that once three notes on a lock become public, every player-accesses the lock. The lock is then 'public' (and its owner should replace-it!).--To declare a solution, you must secure a note on it behind a non-public lock-in one of your three lock slots. Once the note is placed, it can't be moved.---## Full details of the game mechanics-Springs are directed; one of the blocks it is connected to is the 'root', the-other the 'end'. A block is stationary if it is not the end of any spring. The-directed graph whose nodes are the blocks and whose edges are the springs is-required to be acyclic. A spring may also be rooted in a pivot.--I will now attempt to describe in full excruciating detail the game physics,-i.e. the algorithm used to determine what happens on a turn. You shouldn't-need to read this to play the game! Experimenting and turning on blockage-annotations should be enough.--The following description corresponds to the code in Physics.hs. The algorithm-is the result of an extended process of experiment and iterated-simplification; see notes/game in the source distribution if you're perverse-enough to want to read a scattered stream-of-consciousness account of the-process.--Each turn is separated into two phases. In the first phase, the forces arising-from the player's move are 'resolved', possibly resulting in some movement. In-the second phase, forces arising from stretched or compressed springs are-resolved, possibly resulting in some movement.--Here we abuse physics terminology, and use the term 'force' to refer to either-a directional force in the usual sense, which we call a 'push', or a-rotational force, which we call a 'torque'. A force is always on a piece, in-some direction. Only the obvious six hex directions and the two obvious-rotational directions occur; the magnitude is always 1. --Player moves result in forces on the tools in the obvious way. A wrench which-is moving gets a push in that direction each turn (sorry, Newton!). A spring-which is not at its relaxed length results in a push on the end piece.--To _resolve_ these initial forces:- * each initial force is 'propagated to a force group'- * if a group is 'inconsistent' with another group: if one of the groups is- 'dominated' by the other, it is 'blocked'; else both are blocked- * each force in each unblocked force group is 'applied'--To _apply_ a push: move the piece in the given direction.-To _apply_ a torque: rotate the piece in the given direction.--To _propagate_ a force:- * If applying the force would result in an overlap with another piece,- push that piece - but if it's an arm, twist the pivot instead when- that makes sense.- * If the force is a torque and an arm is pushing on another piece, we have- a special rule: if the obvious push ends up propagating to a resisted- force (see below), then it is replaced with a 'clawing' push. e.g. in- the following situation:- \ O #- o- if the pivot is twisted clockwise, the ball will first be pushed east,- but when that force propagates to a push on the stationary block to- its east which is resisted, processing will back up and a push on the- ball southeast will be tried instead.- * A spring connecting two blocks transmits a push on one block to the- other unless the direction is such that the push is tending to- compress resp. extend the spring and the spring is currently extended - resp. compressed, or the force is a player force and the spring isn't - already fully compressed resp. extended.--A force is _resisted_ if it is a push on a pivot or on a block which isn't the- end of a spring, or it's a torque on a block, or it's a force on a hook- which isn't already getting that force this phase as the result of a- player move, or it's a force on a wrench which isn't a push in the- direction it's already moving.--To _propagate an initial force to a force group_:- * Propagate the force as above, then recursively propagate the resulting- forces, checking for resistance as we go. The force group consists of- all the resulting propagated forces.- * On resistance: back up to try clawing as described above if appropriate,- else consider the whole force group resisted - so the resulting force- group is empty.--Two forces are _inconsistent_ when- * they act on the same piece in different directions, or- * applying both at once results in overlapping pieces, or- * applying both at once results in an overextended/overcompressed spring.--Two force groups are _inconsistent_ iff there is some force from the first- which is inconsistent with some force from the second.--A force group _dominates_ another iff their initial forces are spring forces,- and the root of the first spring is an ancestor of the root of the second- spring, where an ancestor of a block B is recursively defined to be a block- which is the root of a spring which ends at B, or an ancestor of such a- block.---- mbays@sdf.org 2013
+ README.md view
@@ -0,0 +1,157 @@+# Intricacy+A game of competitive puzzle-design.++https://mbays.sdf.org/intricacy/++## Configuration+You can change keybindings in SDL mode by right-clicking on the corresponding+button and pressing a key.++Config files are saved in `~/.intricacy/` on unixoids, or something like+`...\Application Data\intricacy\` on windows. In particular, the locks you+create in the lock editor are saved in there (and you can organise them into+directories by including (back)slashs in the lock name). You can edit them in+a text editor if you want - see AsciiLock.hs for what the characters mean.++If you want to cheat your way past initiation, change "False" to "True" in+`metagame.conf`.+++## Rough description of the game mechanics+* Locks consist of blocks, pivots and balls. Blocks can be connected to other+ blocks by springs. Pivots have arms. When picking a lock, you control two+ tools - a hook, which acts as a mobile one-armed pivot, and a wrench,+ which acts as a mobile block with momentum.+* To open a lock, the "bolthole" (the area in the top-right) must be empty.+* Each turn, the tools push and rotate according to the player's commands, and+ then each spring which is compressed or extended beyond its natural length+ pushes/pulls on the block at its end.+* If two forces try to move a piece in two different directions, or try to+ move two pieces into the same hex, one or both is blocked.+* If a pivot/hook is trying to turn and there's a piece in the way of one of+ its arms, it will at first try to push the piece away - but if that force+ is blocked, it will try instead to pull the piece round with the arm as it+ turns.+* If two springs are trying to push two blocks into the same hex, they will+ generally both be blocked. However, if one of the forces is also pushing+ against a fixed piece such as a tool, it won't block the other force.+++## Full details of the metagame mechanics+(Where by the 'game' I mean the lock-picking bit, and by the 'metagame' I mean+the bit with the 3-letter codenames and the three lock slots and notes and so+on. If you haven't seen anything of the kind... keep solving those locks!)++Scoring is always relative - each player has a score relative to each other+player. That score is the number of the second player's lock slots to which+the first player has access, minus the number of the first player's lock slots+to which the second player has access.++A player accesses a lock slot when one of the following holds+ * the player has solved the lock in the slot, and declared the solution;+ * the player has read three notes on the lock in the slot;+ * there's no lock in the slot, and the player has accessed all the slots+ which do have locks in them.++A player reads every note in every lock the player accesses. When a lock is+replaced ('retired'), each note secured by the lock becomes 'public', and is+read by every player.++Note this means that once three notes on a lock become public, every player+accesses the lock. The lock is then 'public' (and its owner should replace+it!).++To declare a solution, you must secure a note on it behind a non-public lock+in one of your three lock slots. Once the note is placed, it can't be moved.+++## Full details of the game mechanics+Springs are directed; one of the blocks it is connected to is the 'root', the+other the 'end'. A block is stationary if it is not the end of any spring. The+directed graph whose nodes are the blocks and whose edges are the springs is+required to be acyclic. A spring may also be rooted in a pivot.++I will now attempt to describe in full excruciating detail the game physics,+i.e. the algorithm used to determine what happens on a turn. You shouldn't+need to read this to play the game! Experimenting and turning on blockage+annotations should be enough.++The following description corresponds to the code in Physics.hs. The algorithm+is the result of an extended process of experiment and iterated+simplification; see notes/game in the source distribution if you're perverse+enough to want to read a scattered stream-of-consciousness account of the+process.++Each turn is separated into two phases. In the first phase, the forces arising+from the player's move are 'resolved', possibly resulting in some movement. In+the second phase, forces arising from stretched or compressed springs are+resolved, possibly resulting in some movement.++Here we abuse physics terminology, and use the term 'force' to refer to either+a directional force in the usual sense, which we call a 'push', or a+rotational force, which we call a 'torque'. A force is always on a piece, in+some direction. Only the obvious six hex directions and the two obvious+rotational directions occur; the magnitude is always 1. ++Player moves result in forces on the tools in the obvious way. A wrench which+is moving gets a push in that direction each turn (sorry, Newton!). A spring+which is not at its relaxed length results in a push on the end piece.++To _resolve_ these initial forces:+ * each initial force is 'propagated to a force group'+ * if a group is 'inconsistent' with another group: if one of the groups is+ 'dominated' by the other, it is 'blocked'; else both are blocked+ * each force in each unblocked force group is 'applied'++To _apply_ a push: move the piece in the given direction.+To _apply_ a torque: rotate the piece in the given direction.++To _propagate_ a force:+ * If applying the force would result in an overlap with another piece,+ push that piece - but if it's an arm, twist the pivot instead when+ that makes sense.+ * If the force is a torque and an arm is pushing on another piece, we have+ a special rule: if the obvious push ends up propagating to a resisted+ force (see below), then it is replaced with a 'clawing' push. e.g. in+ the following situation:+ \ O #+ o+ if the pivot is twisted clockwise, the ball will first be pushed east,+ but when that force propagates to a push on the stationary block to+ its east which is resisted, processing will back up and a push on the+ ball southeast will be tried instead.+ * A spring connecting two blocks transmits a push on one block to the+ other unless the direction is such that the push is tending to+ compress resp. extend the spring and the spring is currently extended + resp. compressed, or the force is a player force and the spring isn't + already fully compressed resp. extended.++A force is _resisted_ if it is a push on a pivot or on a block which isn't the+ end of a spring, or it's a torque on a block, or it's a force on a hook+ which isn't already getting that force this phase as the result of a+ player move, or it's a force on a wrench which isn't a push in the+ direction it's already moving.++To _propagate an initial force to a force group_:+ * Propagate the force as above, then recursively propagate the resulting+ forces, checking for resistance as we go. The force group consists of+ all the resulting propagated forces.+ * On resistance: back up to try clawing as described above if appropriate,+ else consider the whole force group resisted - so the resulting force+ group is empty.++Two forces are _inconsistent_ when+ * they act on the same piece in different directions, or+ * applying both at once results in overlapping pieces, or+ * applying both at once results in an overextended/overcompressed spring.++Two force groups are _inconsistent_ iff there is some force from the first+ which is inconsistent with some force from the second.++A force group _dominates_ another iff their initial forces are spring forces,+ and the root of the first spring is an ancestor of the root of the second+ spring, where an ancestor of a block B is recursively defined to be a block+ which is the root of a spring which ends at B, or an ancestor of such a+ block.++-- mbays@sdf.org 2013
SDL2RenderCache.hs view
@@ -298,9 +298,9 @@ sequence_ [ pixelR (FVec (1/3 + i/4) (-1/4)) (bright white) | i <- [-1..1] ] renderGlyph (VolumeButton vol) = do- sequence_ [ arcR (FVec (-2/3) 0) r (-20) 20- (if vol > 0 then bright green else dim red)- | r <- [1/3] <> [2/3 | vol > 16 || vol == 0] <> [1 | vol > 32 || vol == 0 ] ]+ sequence_ [ arcR (FVec (-2/3) 0) ((fi r+1)/3) (-20) 20+ (if vol > 16*r then bright green else dim red)+ | r <- [0..2] ] unless (vol > 0) $ aaLineR (innerCorner hw) (innerCorner $ neg hw) $ dim red
SDL2UI.hs view
@@ -53,6 +53,7 @@ import InputMode import KeyBindings import Lock+import MainState import Maxlocksize import Metagame import Mundanities@@ -403,9 +404,16 @@ helpOfSelectableFiltered _ s = helpOfSelectable s -data UIOptButton a = UIOptButton { getUIOpt :: UIOptions->a, setUIOpt :: a->UIOptions->UIOptions,- uiOptVals :: [a], uiOptPos :: HexVec, uiOptGlyph :: a->Glyph, uiOptDescr :: a->String,- uiOptModes :: [InputMode], onSet :: Maybe (a -> UIM ()) }+data UIOptButton a = UIOptButton+ { getUIOpt :: UIOptions->a+ , setUIOpt :: a->UIOptions->UIOptions+ , uiOptVals :: [a]+ , uiOptPos :: HexVec+ , uiOptGlyph :: a->Glyph+ , uiOptDescr :: a->String+ , uiOptModes :: [InputMode]+ , uiOptSideText :: a -> TutorialLevel -> Maybe (String, HexVec)+ , onSet :: Maybe (a -> UIM ()) } -- non-uniform type, so can't use a list... uiOB1 = UIOptButton useFiveColouring (\v o -> o {useFiveColouring=v}) [True,False]@@ -413,6 +421,7 @@ (\v -> if v then "Adjacent pieces get different colours" else "Pieces are coloured according to type") [] -- disabled+ (const $ const Nothing) Nothing uiOB2 = UIOptButton showBlocks (\v o -> o {showBlocks=v}) [ShowBlocksBlocking,ShowBlocksAll,ShowBlocksNone] (periphery 0 +^ 2 *^ hu +^ 2 *^ neg hv) ShowBlocksButton@@ -420,7 +429,9 @@ ShowBlocksBlocking -> "Showing conflicting forces" ShowBlocksAll -> "Showing conflicting forces and movements they prevent" ShowBlocksNone -> "Not showing conflicts")- [IMPlay, IMReplay] Nothing+ [IMPlay, IMReplay]+ (\a tutLev -> if a == ShowBlocksNone && conflictsTutLev tutLev then Just ("Conflicts -->", 14*^neg hu) else Nothing)+ Nothing uiOB3P = UIOptButton ((!? IMPlay) . whsButtons) (\v o -> o { whsButtons = Map.alter (const v) IMPlay $ whsButtons o }) [Nothing, Just WHSSelected, Just WHSHook, Just WHSWrench] (periphery 3 +^ 3 *^ hv) WhsButtonsButton@@ -430,23 +441,25 @@ WHSSelected -> "selected piece; right-click on buttons to rebind" WHSWrench -> "wrench; right-click on buttons to rebind" WHSHook -> "hook; right-click on buttons to rebind")- [IMPlay] Nothing+ [IMPlay]+ (\a tutLev -> if isNothing a && keysTutLevel tutLev then Just ("<-- KEYS", 3*^hu) else Nothing)+ Nothing uiOB3E = UIOptButton ((!? IMEdit) . whsButtons) (\v o -> o { whsButtons = Map.alter (const v) IMEdit $ whsButtons o }) [Nothing, Just WHSSelected] (periphery 3 +^ 3 *^ hv) WhsEditButtonsButton (\case Nothing -> "Click to show (and rebind) keyboard control buttons." Just _ -> "Showing buttons for controlling cursor / selected piece; right-click on buttons to rebind")- [IMEdit] Nothing+ [IMEdit] (const $ const Nothing) Nothing uiOB4 = UIOptButton showButtonText (\v o -> o {showButtonText=v}) [True,False] (periphery 0 +^ 2 *^ hu +^ 3 *^ hv) ShowButtonTextButton (\v -> if v then "Help text enabled" else "Help text disabled")- [IMPlay, IMEdit, IMReplay, IMMeta, IMInit] Nothing+ [IMPlay, IMEdit, IMReplay, IMMeta, IMInit] (const $ const Nothing) Nothing uiOB5 = UIOptButton fullscreen (\v o -> o {fullscreen=v}) [True,False] (periphery 0 +^ 4 *^ hu +^ 2 *^ hv) FullscreenButton (\v -> if v then "Fullscreen mode active" else "Windowed mode active")- [IMPlay, IMEdit, IMReplay, IMMeta, IMInit] (Just onFullScreenChange)+ [IMPlay, IMEdit, IMReplay, IMMeta, IMInit] (const $ const Nothing) (Just onFullScreenChange) uiOB6 = UIOptButton soundVolume (\v o -> o {soundVolume=v}) [64,0,16,32] (periphery 0 +^ 4 *^ hu +^ hv) VolumeButton (\case@@ -454,29 +467,36 @@ v | v >= 32 -> "Sound effects at medium volume" 0 -> "Sound effects disabled" _ -> "Sound effects at low volume")- [IMPlay, IMEdit, IMReplay] $ Just (`setVolume` AllChannels)+ [IMPlay, IMEdit, IMReplay] (const $ const Nothing) $ Just (`setVolume` AllChannels) -drawUIOptionButtons :: InputMode -> UIM ()-drawUIOptionButtons mode = do- drawUIOptionButton mode uiOB1- drawUIOptionButton mode uiOB2- drawUIOptionButton mode uiOB3P- drawUIOptionButton mode uiOB3E- drawUIOptionButton mode uiOB4- drawUIOptionButton mode uiOB5+drawUIOptionButtons :: InputMode -> TutorialLevel -> UIM ()+drawUIOptionButtons mode tutLev = do+ drawUIOptionButton mode tutLev uiOB1+ drawUIOptionButton mode tutLev uiOB2+ drawUIOptionButton mode tutLev uiOB3P+ drawUIOptionButton mode tutLev uiOB3E+ drawUIOptionButton mode tutLev uiOB4+ drawUIOptionButton mode tutLev uiOB5 #ifdef SOUND- drawUIOptionButton mode uiOB6+ drawUIOptionButton mode tutLev uiOB6 #endif-drawUIOptionButton im b = when (im `elem` uiOptModes b) $ do+drawUIOptionButton im tutLev b = when (im `elem` uiOptModes b) $ do value <- gets $ getUIOpt b . uiOptions renderToMain $ mapM_ (\g -> drawAtRel g (uiOptPos b)) [HollowGlyph $ obscure purple, uiOptGlyph b value]+ maybe (pure ()) drawSideText $ uiOptSideText b value tutLev+ where+ drawSideText (s,dv) = do+ smallFont <- gets dispFontSmall+ renderToMain $ withFont smallFont $ recentreAt (uiOptPos b) $ rescaleRender (1/4) $+ renderStrColAtLeft white s dv+ describeUIOptionButton :: UIOptButton a -> MaybeT UIM String describeUIOptionButton b = do value <- gets $ getUIOpt b . uiOptions return $ uiOptDescr b value -- XXX: hand-hacking lenses...-toggleUIOption (UIOptButton getopt setopt vals _ _ _ _ monSet) = do+toggleUIOption (UIOptButton getopt setopt vals _ _ _ _ _ monSet) = do value <- gets $ getopt . uiOptions let value' = cycle vals !! max 0 (1 + fromMaybe 0 (elemIndex value vals)) modifyUIOptions $ setopt value'
SDL2UIMInstance.hs view
@@ -61,12 +61,13 @@ lift $ clearButtons >> clearSelectables s <- get let mode = ms2im s+ tutLev = getTutLevel s lift waitFrame drawMainState' s lift . drawTitle =<< getTitle lift $ do drawButtons mode- drawUIOptionButtons mode+ drawUIOptionButtons mode tutLev updateHoverStr mode drawMsgLine drawShortMouseHelp mode s
intricacy.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.2 name: intricacy-version: 0.9.0.0+version: 0.9.1.0 license: GPL-3.0-or-later license-file: COPYING maintainer: mbays@sdf.org@@ -33,9 +33,9 @@ extra-source-files: Main_stub.h extra-doc-files:- README+ README.md BUILD- NEWS+ NEWS.md tutorial-extra/*.lock tutorial-extra/README
tutorial/05-hook.text view
@@ -1,1 +1,1 @@-turn hook with mouse wheel (or keys) to pull springs aside+turn hook with mouse wheel or keys to pull springs aside