Skip to content

Commit

Permalink
Implemented rings of protection.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodiologist committed Feb 11, 2024
1 parent c46cdae commit 7612908
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 9 deletions.
14 changes: 13 additions & 1 deletion simalq/tile/item.hy
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
: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
:color 'purple
:iq-ix 151
:acquirement-points 150
Expand Down Expand Up @@ -293,6 +293,18 @@
f"Makes you invisible for {@duration} more turns. Most monsters can't track or shoot you while you're invisible, unless you're adjacent to them.")
:flavor "A cape enchanted with the power of the night sky. Try not to get it snagged on any loose flagstones (especially when it's invisible).")
(deftile "! " "a ring of protection" StatusEffectItem
:color 'dark-orange
:iq-ix 158
:acquirement-points 150
:effect StatusEffect.Prot
:duration 25
:help (meth []
f"Protects you (for {@duration} more turns) from harmful status effects and disenchantment.")
:flavor "Also known as a ring of anti-anti-magic. Fortunately, anti-anti-anti-magic traps are still in dungeon R&D.")
(defclass Usable [Item]
"An item that's added to your inventory and can thereafter be
Expand Down
2 changes: 1 addition & 1 deletion simalq/tile/monster.hy
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@
:sees-invisible T
:act (meth []
(doc (.format "Disenchant — If it's not adjacent but has line of effect to you, the monster removes the first beneficial status effect that you have from the following list: {}. Otherwise, it behaves per `Approach`."
(doc (.format "Disenchant — If it's not adjacent but has line of effect to you, the monster disenchants you, removing the first beneficial status effect that you have from the following list: {}. Otherwise, it behaves per `Approach`."
(.join ", " (gfor e (StatusEffect.disenchantable) e.name))))
(if (and
(not (adjacent? @pos G.player.pos))
Expand Down
2 changes: 1 addition & 1 deletion simalq/tile/scenery.hy
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@
:iq-ix 169

:hook-player-walked-into (meth []
(doc (.format "Removes the first beneficial status effect that you have from the following list: {}."
(doc (.format "Disenchants you, removing the first beneficial status effect that you have from the following list: {}."
(.join ", " (gfor e (StatusEffect.disenchantable) e.name))))
(StatusEffect.disenchant-player))

Expand Down
1 change: 0 additions & 1 deletion simalq/tile/unimplemented.hy
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
[132 "golem"]
[134 "siren"]
[152 "random_gate"]
[158 "ring_of_protection"]
[159 "amulet_of_poisonous_touch"]
[164 "cyclops"]
[165 "dark_prince"]
Expand Down
12 changes: 7 additions & 5 deletions simalq/util.hy
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@
(bool (get G.player.status-effects @)))

(defmeth add [duration]
(when (and (@bad?) (.player-has? StatusEffect.Prot))
; Protection prevents harmful effects.
(return))
(+= (get G.player.status-effects @) duration))

(defn [classmethod] disenchantable [cls]
Expand All @@ -157,13 +160,12 @@

(defn [classmethod] disenchant-player [cls]
"Try to remove a beneficial status effect from the player. Return
`True` on success."
(when (.player-has? StatusEffect.Prot)
; Protection prevents disenchantment.
(return F))
`True` if there was a removable beneficial effect; under
protection, it still won't actually be removed."
; Remove the first eligible effect that the player actually has.
(for [effect (.disenchantable cls) :if (.player-has? effect)]
(setv (get G.player.status-effects effect) 0)
(unless (.player-has? StatusEffect.Prot)
(setv (get G.player.status-effects effect) 0))
(return T))
F)

Expand Down
36 changes: 36 additions & 0 deletions tests/test_item.hy
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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.util [StatusEffect]
simalq.quest-definition [mk-tile])
(setv T True F False)

Expand Down Expand Up @@ -317,6 +318,41 @@
(assert-at [1 4] "devil"))


(defn test-ring-of-protection []
(init [
:height 1
:tiles [
"passwall amulet" "ring of protection"
"anti-magic trap" "weakness trap"
"pile of gold" "hole" "archmage"]])
(defn check [player-hp pass prot]
(assert (= G.player.hp player-hp))
(assert (= (.player-has? StatusEffect.Pass) pass))
(assert (= (.player-has? StatusEffect.Prot) prot)))

; A ring of protection makes an anti-magic trap ineffective.
(wk 'E 3)
(check 100 T T)
; Likewise a weakness trap.
(wk 'E)
(assert (not (.player-has? StatusEffect.Weak)))
; The archmage's shots have no effect, since we have an effect to
; disenchant (`Pass`), but he can't actually remove it due to
; `Prot`.
(wk 'E)
(check 100 T T)
; Just before `turn-n` advances to 20, `Pass` ends. `Prot` is still
; in effect, but doesn't do anything about damaging shots from the
; archmage.
(wait 14)
(assert (= G.turn-n 19))
(check 100 T T)
(wait)
(check 100 F T)
(wait)
(check 88 F T))


(defn test-inventory []
(init [:tiles [
"wand of shielding" "wall-making wand"
Expand Down

0 comments on commit 7612908

Please sign in to comment.