Skip to content

Commit 8a155b3

Browse files
committed
Implemented passwall amulets.
1 parent 6d17bdf commit 8a155b3

File tree

7 files changed

+99
-13
lines changed

7 files changed

+99
-13
lines changed

simalq/commands.hy

+15-6
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
simalq.geometry [Direction Pos at dist]
1212
simalq.game-state [G]
1313
simalq.tile [Damageable]
14-
simalq.tile.scenery [walkability]
14+
simalq.tile.scenery [Scenery walkability]
1515
simalq.save-load [save-game-to-slot get-saves-list load-game])
1616
(setv T True F False)
1717

@@ -200,27 +200,36 @@
200200
None
201201

202202
[Walk UseControllableTeleporter] (do
203+
(defn pat [pos]
204+
"`at`, but excluding tiles we should ignore due to passwall."
205+
(gfor
206+
tile (at pos)
207+
:if (not (and
208+
(isinstance tile Scenery)
209+
tile.passwallable
210+
(player-status 'Pass)))
211+
tile))
203212
(setv d action.direction)
204213
(setv [target wly] (walkability G.player.pos d :monster? F))
205214
(when (= wly 'out-of-bounds)
206215
(raise (CommandError "The border of the dungeon blocks your movement.")))
207216
(when (= wly 'blocked-diag)
208217
(raise (CommandError "That diagonal is blocked by a neighbor.")))
209-
(for [tile (at target)]
218+
(for [tile (pat target)]
210219
(when (.hook-player-bump tile G.player.pos)
211220
(return)))
212221
(when (= wly 'bump)
213222
(raise (CommandError "Your way is blocked.")))
214-
(for [tile (at G.player.pos)]
223+
(for [tile (pat G.player.pos)]
215224
(.hook-player-walk-from tile target))
216-
(for [tile (at target)]
225+
(for [tile (pat target)]
217226
(.hook-player-walk-to tile G.player.pos))
218227
; No exceptions have stopped us, so go.
219228
(setv pos-was G.player.pos)
220229
(.move G.player target)
221-
(for [tile (at pos-was)]
230+
(for [tile (pat pos-was)]
222231
(.hook-player-walked-from tile))
223-
(for [tile (at target)]
232+
(for [tile (pat target)]
224233
(when (.hook-player-walked-into tile)
225234
(return))))
226235

simalq/tile/item.hy

+12
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,18 @@
266266
f"Makes you invulnerable for {@duration} more turns, protecting you from all damage and ambient poison, but not harmful status effects or disenchantment.")
267267
:flavor "A star-shaped pendant with two black spots in the center. Its magic is short-lived but potent indeed.")
268268
269+
(deftile "! " "a passwall amulet" StatusEffectItem
270+
:color 'dark-orange
271+
:iq-ix 151
272+
:acquirement-points 150
273+
274+
:effect 'Pass
275+
:duration 20
276+
277+
:help (meth []
278+
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.")
279+
: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.")
280+
269281
(deftile "! " "a potion of speed" StatusEffectItem
270282
:color 'dark-green
271283
:iq-ix 34

simalq/tile/scenery.hy

+19-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
(import
66
fractions [Fraction :as f/]
77
simalq.color :as color
8-
simalq.util [CommandError DamageType next-in-cycle StatusEffect]
8+
simalq.util [CommandError DamageType next-in-cycle StatusEffect player-status]
99
simalq.geometry [Pos Direction at burst dist dir-to ray]
1010
simalq.tile [Tile PosHooked EachTurner Damageable]
1111
simalq.game-state [G])
@@ -22,6 +22,7 @@
2222
; Block diagonal movement between orthogonally adjacent squares.
2323
blocks-monster F
2424
; Block monster movement, even if `blocks-move` is false.
25+
passwallable F
2526
wand-destructible F
2627
protects-vs-poison-air F
2728
emits-poison-air F)
@@ -54,6 +55,8 @@
5455
"Blocks your shots, but not monsters' shots"
5556
@blocks-monster-shots
5657
"Blocks monsters' shots, but not your shots")
58+
(when @passwallable
59+
"Permeable with a passwall amulet")
5760
(when @wand-destructible
5861
"Destructible with a wall-destroying wand")
5962
(when @superblock
@@ -100,7 +103,8 @@
100103
(and
101104
(isinstance tile Scenery)
102105
tile.blocks-diag
103-
(not-in tile.stem ethereal-to)))))
106+
(not-in tile.stem ethereal-to)
107+
(not (and tile.passwallable (player-status 'Pass)))))))
104108
'blocked-diag
105109
(nogo? target monster? ethereal-to)
106110
'bump
@@ -115,7 +119,8 @@
115119
(isinstance tile hy.I.simalq/tile.Monster)
116120
(and (isinstance tile Scenery) (or
117121
(and monster? tile.blocks-monster)
118-
tile.blocks-move)))))))
122+
(and tile.blocks-move (or monster?
123+
(not (and tile.passwallable (player-status 'Pass))))))))))))
119124
120125
121126
(deftile "██" "a wall" Scenery
@@ -126,6 +131,7 @@
126131
; IQ's invisible walls are specifically immune to passwall
127132
; amulets, albeit not wall-destroying wands.
128133
:blocks-move T :blocks-diag T
134+
:passwallable T
129135
:wand-destructible T
130136
: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.")
131137

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

150157
(deftile "" "a broken pillar" Scenery
151158
:iq-ix 82
152159
:blocks-move T :blocks-player-shots F
160+
:passwallable T
153161
:wand-destructible T
154162
: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.")
155163

@@ -187,19 +195,22 @@
187195
(deftile "++" "a locked door" LockedDoor
188196
:color 'navy
189197
:iq-ix 6
198+
:passwallable T
190199
:result-when-opened "door"
191200
: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.")
192201

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

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

@@ -234,6 +245,7 @@
234245

235246
(setv
236247
blocks-monster T
248+
passwallable T
237249
direction None
238250
color #('brown 'red))
239251

@@ -312,6 +324,7 @@
312324
{3 4 4 2 15 6}]
313325

314326
:blocks-move T :blocks-diag T :blocks-player-shots F
327+
:passwallable T
315328
:wand-destructible T
316329
:immune #(DamageType.Poison DamageType.Fire DamageType.DeathMagic)
317330

@@ -323,6 +336,7 @@
323336
(setv
324337
blocks-monster T
325338
blocks-diag T
339+
passwallable T
326340
wand-destructible T
327341
color 'white
328342
color-bg 'black)
@@ -382,6 +396,7 @@
382396
:color-bg #('black None)
383397
:iq-ix 139
384398
:blocks-move T :blocks-diag T
399+
:passwallable T
385400
:wand-destructible T
386401

387402
:phase-replace "phasing wall (out of phase)"
@@ -656,6 +671,7 @@
656671
:suffix-dict (meth []
657672
(dict :type @wallnum))
658673
:blocks-move T :blocks-diag T
674+
:passwallable T
659675
:wand-destructible T
660676
:info-bullets (meth [#* extra]
661677
(.info-bullets (super)

simalq/tile/unimplemented.hy

-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
[132 "golem"]
3333
[134 "siren"]
3434
[141 "phasing_wall_trap"]
35-
[151 "passwall_amulet"]
3635
[152 "random_gate"]
3736
[154 "wand_of_flame"]
3837
[158 "ring_of_protection"]

simalq/util.hy

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
Ivis "invisibility"
132132
Fast "haste"
133133
Pois "poisonous touch"
134+
Pass "passwall"
134135
MKey "magical key"
135136
Prot "protection")
136137
(defmeth [property] bad []

tests/lib.hy

+3-2
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,13 @@
7979
(assert (= G.player.pos (Pos G.map x y))))
8080

8181

82-
(defmacro cant [form msg-check]
82+
(defmacro cant [form [msg-check None]]
8383
(setv e (hy.gensym))
8484
`(do
8585
(with [~e (hy.I.pytest.raises hy.I.simalq/util.CommandError)]
8686
~form)
87-
(assert (= (. ~e value args [0]) ~msg-check))))
87+
~@(when msg-check
88+
[`(assert (= (. ~e value args [0]) ~msg-check))])))
8889

8990

9091
(defn wk [direction-abbr [n-times 1]]

tests/test_item.hy

+49-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
tests.lib [cant])
44
(import
55
fractions [Fraction :as f/]
6-
tests.lib [init init-boot-camp assert-at assert-hp assert-textmap set-square mv-player wk shoot wait use-item top]
6+
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]
77
simalq.geometry [Pos Direction at]
88
simalq.game-state [G]
99
simalq.quest-definition [mk-tile])
@@ -204,6 +204,54 @@
204204
(check 41 97))
205205

206206

207+
(defn test-passwall-amulet []
208+
209+
(defn ok [tile [can-pass-thru? True]]
210+
(init
211+
[:tiles ["passwall amulet" tile]])
212+
(wk 'E)
213+
(if can-pass-thru?
214+
(do
215+
(wk 'E 2)
216+
(assert-player-at 3 0))
217+
(cant (wk 'E))))
218+
219+
(ok "wall")
220+
(ok "trapped wall")
221+
(ok "cracked wall")
222+
(ok "breakable wall (zonal)")
223+
(ok "pillar")
224+
(ok "broken pillar")
225+
(ok "locked door")
226+
(ok "locked disappearing door")
227+
(ok "one-way door (west)")
228+
(ok "closed portcullis")
229+
(ok "phasing wall (in phase)")
230+
231+
(ok "Void" F)
232+
(ok "water fountain" F)
233+
(ok "treasure chest" F))
234+
235+
236+
(defn test-passwall-diag []
237+
"Passwall allows you to ignore diagonal blockers that you would be
238+
able to walk through, but not other diagonal blockers (contra IQ)."
239+
240+
(init [
241+
:map "
242+
. ██.
243+
@ ! ██"
244+
:map-marks
245+
{"! " "passwall amulet"}])
246+
247+
(wk 'E)
248+
(wk 'NE)
249+
(assert-player-at 2 1)
250+
(mv-player 1 0)
251+
(set-square 'N "Void")
252+
(cant (wk 'NE) "That diagonal is blocked by a neighbor."))
253+
254+
207255
(defn test-potion-of-speed []
208256
(init
209257
[:tiles ["potion of speed" "orc"]])

0 commit comments

Comments
 (0)