Skip to content

Commit

Permalink
Implemented passwall amulets.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodiologist committed Jan 25, 2024
1 parent 6d17bdf commit 8a155b3
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 13 deletions.
21 changes: 15 additions & 6 deletions simalq/commands.hy
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
simalq.geometry [Direction Pos at dist]
simalq.game-state [G]
simalq.tile [Damageable]
simalq.tile.scenery [walkability]
simalq.tile.scenery [Scenery walkability]
simalq.save-load [save-game-to-slot get-saves-list load-game])
(setv T True F False)

Expand Down Expand Up @@ -200,27 +200,36 @@
None

[Walk UseControllableTeleporter] (do
(defn pat [pos]
"`at`, but excluding tiles we should ignore due to passwall."
(gfor
tile (at pos)
:if (not (and
(isinstance tile Scenery)
tile.passwallable
(player-status 'Pass)))
tile))
(setv d action.direction)
(setv [target wly] (walkability G.player.pos d :monster? F))
(when (= wly 'out-of-bounds)
(raise (CommandError "The border of the dungeon blocks your movement.")))
(when (= wly 'blocked-diag)
(raise (CommandError "That diagonal is blocked by a neighbor.")))
(for [tile (at target)]
(for [tile (pat target)]
(when (.hook-player-bump tile G.player.pos)
(return)))
(when (= wly 'bump)
(raise (CommandError "Your way is blocked.")))
(for [tile (at G.player.pos)]
(for [tile (pat G.player.pos)]
(.hook-player-walk-from tile target))
(for [tile (at target)]
(for [tile (pat target)]
(.hook-player-walk-to tile G.player.pos))
; No exceptions have stopped us, so go.
(setv pos-was G.player.pos)
(.move G.player target)
(for [tile (at pos-was)]
(for [tile (pat pos-was)]
(.hook-player-walked-from tile))
(for [tile (at target)]
(for [tile (pat target)]
(when (.hook-player-walked-into tile)
(return))))

Expand Down
12 changes: 12 additions & 0 deletions simalq/tile/item.hy
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,18 @@
f"Makes you invulnerable for {@duration} more turns, protecting you from all damage and ambient poison, but not harmful status effects or disenchantment.")
:flavor "A star-shaped pendant with two black spots in the center. Its magic is short-lived but potent indeed.")
(deftile "! " "a passwall amulet" StatusEffectItem
:color 'dark-orange
:iq-ix 151
:acquirement-points 150
:effect 'Pass
:duration 20
:help (meth []
f"Makes you semi-material for {@duration} more turns, allowing you to walk through walls (plus other scenery types noted as affected by a passwall amulet). You ignore most properties of the affected scenery, such as a one-way door's restrictions on movement direction, or a locked door's consumption of a key.")
:flavor "Looks like the ethereal power of one of those many, many evil undead phantasms rubbed off onto this little trinket. Try not to let the magic run out when you're entirely surrounded by walls. Getting buried alive is a bad way to go.")
(deftile "! " "a potion of speed" StatusEffectItem
:color 'dark-green
:iq-ix 34
Expand Down
22 changes: 19 additions & 3 deletions simalq/tile/scenery.hy
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
(import
fractions [Fraction :as f/]
simalq.color :as color
simalq.util [CommandError DamageType next-in-cycle StatusEffect]
simalq.util [CommandError DamageType next-in-cycle StatusEffect player-status]
simalq.geometry [Pos Direction at burst dist dir-to ray]
simalq.tile [Tile PosHooked EachTurner Damageable]
simalq.game-state [G])
Expand All @@ -22,6 +22,7 @@
; Block diagonal movement between orthogonally adjacent squares.
blocks-monster F
; Block monster movement, even if `blocks-move` is false.
passwallable F
wand-destructible F
protects-vs-poison-air F
emits-poison-air F)
Expand Down Expand Up @@ -54,6 +55,8 @@
"Blocks your shots, but not monsters' shots"
@blocks-monster-shots
"Blocks monsters' shots, but not your shots")
(when @passwallable
"Permeable with a passwall amulet")
(when @wand-destructible
"Destructible with a wall-destroying wand")
(when @superblock
Expand Down Expand Up @@ -100,7 +103,8 @@
(and
(isinstance tile Scenery)
tile.blocks-diag
(not-in tile.stem ethereal-to)))))
(not-in tile.stem ethereal-to)
(not (and tile.passwallable (player-status 'Pass)))))))
'blocked-diag
(nogo? target monster? ethereal-to)
'bump
Expand All @@ -115,7 +119,8 @@
(isinstance tile hy.I.simalq/tile.Monster)
(and (isinstance tile Scenery) (or
(and monster? tile.blocks-monster)
tile.blocks-move)))))))
(and tile.blocks-move (or monster?
(not (and tile.passwallable (player-status 'Pass))))))))))))
(deftile "██" "a wall" Scenery
Expand All @@ -126,6 +131,7 @@
; IQ's invisible walls are specifically immune to passwall
; amulets, albeit not wall-destroying wands.
:blocks-move T :blocks-diag T
:passwallable T
:wand-destructible T
:flavor "Among the most numerous and persistent of the obstacles that stand in the way of your inevitable victory.\n\n This man, with lime and rough-cast, doth present\n Wall, that vile Wall which did these lovers sunder;\n And through Wall's chink, poor souls, they are content\n To whisper, at the which let no man wonder.")

Expand All @@ -144,12 +150,14 @@
; cosmetic. For example, IQ's fire fountains aren't affected by
; wall-destroying wands.
:blocks-move T
:passwallable T
:wand-destructible T
:flavor "A structure of vaguely Roman style.")

(deftile "" "a broken pillar" Scenery
:iq-ix 82
:blocks-move T :blocks-player-shots F
:passwallable T
:wand-destructible T
:flavor "It's just a chest-high half of a pillar now. Good thing it wasn't load-bearing, huh? It makes for good cover against enemy shots.")

Expand Down Expand Up @@ -187,19 +195,22 @@
(deftile "++" "a locked door" LockedDoor
:color 'navy
:iq-ix 6
:passwallable T
:result-when-opened "door"
:flavor "Fortunately, Tris knows how to pick locks. Unfortunately, she was wearing her hair down when she got whisked away to the dungeon, so she doesn't have any hairpins. You may have to use a key.")

(deftile "++" "a locked disappearing door" LockedDoor
:color 'steel-blue
:iq-ix 81
:passwallable T
:result-when-opened None
:flavor "This advanced door destroys not only the key used to unlock it, but also itself. A true marvel of engineering.")

(deftile "##" "a closed portcullis" LockedDoor
:color 'navy
:iq-ix 103
:blocks-player-shots F :blocks-monster-shots F
:passwallable T
:result-when-opened "open portcullis"
:flavor "Finally, a kind of door that can be locked more than once. The keys are still really fragile, though.")

Expand Down Expand Up @@ -234,6 +245,7 @@

(setv
blocks-monster T
passwallable T
direction None
color #('brown 'red))

Expand Down Expand Up @@ -312,6 +324,7 @@
{3 4 4 2 15 6}]

:blocks-move T :blocks-diag T :blocks-player-shots F
:passwallable T
:wand-destructible T
:immune #(DamageType.Poison DamageType.Fire DamageType.DeathMagic)

Expand All @@ -323,6 +336,7 @@
(setv
blocks-monster T
blocks-diag T
passwallable T
wand-destructible T
color 'white
color-bg 'black)
Expand Down Expand Up @@ -382,6 +396,7 @@
:color-bg #('black None)
:iq-ix 139
:blocks-move T :blocks-diag T
:passwallable T
:wand-destructible T

:phase-replace "phasing wall (out of phase)"
Expand Down Expand Up @@ -656,6 +671,7 @@
:suffix-dict (meth []
(dict :type @wallnum))
:blocks-move T :blocks-diag T
:passwallable T
:wand-destructible T
:info-bullets (meth [#* extra]
(.info-bullets (super)
Expand Down
1 change: 0 additions & 1 deletion simalq/tile/unimplemented.hy
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
[132 "golem"]
[134 "siren"]
[141 "phasing_wall_trap"]
[151 "passwall_amulet"]
[152 "random_gate"]
[154 "wand_of_flame"]
[158 "ring_of_protection"]
Expand Down
1 change: 1 addition & 0 deletions simalq/util.hy
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@
Ivis "invisibility"
Fast "haste"
Pois "poisonous touch"
Pass "passwall"
MKey "magical key"
Prot "protection")
(defmeth [property] bad []
Expand Down
5 changes: 3 additions & 2 deletions tests/lib.hy
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@
(assert (= G.player.pos (Pos G.map x y))))


(defmacro cant [form msg-check]
(defmacro cant [form [msg-check None]]
(setv e (hy.gensym))
`(do
(with [~e (hy.I.pytest.raises hy.I.simalq/util.CommandError)]
~form)
(assert (= (. ~e value args [0]) ~msg-check))))
~@(when msg-check
[`(assert (= (. ~e value args [0]) ~msg-check))])))


(defn wk [direction-abbr [n-times 1]]
Expand Down
50 changes: 49 additions & 1 deletion tests/test_item.hy
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
tests.lib [cant])
(import
fractions [Fraction :as f/]
tests.lib [init init-boot-camp assert-at assert-hp assert-textmap set-square mv-player wk shoot wait use-item top]
tests.lib [init init-boot-camp assert-at assert-player-at assert-hp assert-textmap set-square mv-player wk shoot wait use-item top]
simalq.geometry [Pos Direction at]
simalq.game-state [G]
simalq.quest-definition [mk-tile])
Expand Down Expand Up @@ -204,6 +204,54 @@
(check 41 97))


(defn test-passwall-amulet []

(defn ok [tile [can-pass-thru? True]]
(init
[:tiles ["passwall amulet" tile]])
(wk 'E)
(if can-pass-thru?
(do
(wk 'E 2)
(assert-player-at 3 0))
(cant (wk 'E))))

(ok "wall")
(ok "trapped wall")
(ok "cracked wall")
(ok "breakable wall (zonal)")
(ok "pillar")
(ok "broken pillar")
(ok "locked door")
(ok "locked disappearing door")
(ok "one-way door (west)")
(ok "closed portcullis")
(ok "phasing wall (in phase)")

(ok "Void" F)
(ok "water fountain" F)
(ok "treasure chest" F))


(defn test-passwall-diag []
"Passwall allows you to ignore diagonal blockers that you would be
able to walk through, but not other diagonal blockers (contra IQ)."

(init [
:map "
. ██.
@ ! ██"
:map-marks
{"! " "passwall amulet"}])

(wk 'E)
(wk 'NE)
(assert-player-at 2 1)
(mv-player 1 0)
(set-square 'N "Void")
(cant (wk 'NE) "That diagonal is blocked by a neighbor."))


(defn test-potion-of-speed []
(init
[:tiles ["potion of speed" "orc"]])
Expand Down

0 comments on commit 8a155b3

Please sign in to comment.