Skip to content

Commit 589c1c6

Browse files
committed
Implemented vampires.
1 parent 0ff2f84 commit 589c1c6

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-3
lines changed

simalq/tile/monster.hy

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
;; --------------------------------------------------------------
44

55
(require
6-
hyrule [unless do-n list-n defmacro-kwargs case pun]
6+
hyrule [unless do-n list-n defmacro-kwargs case ecase pun block]
77
simalq.macros [field-defaults pop-integer-part defmeth]
88
simalq.tile [deftile])
99
(import
@@ -13,7 +13,7 @@
1313
hyrule [thru xor]
1414
toolz [unique]
1515
simalq.util [DamageType StatusEffect next-in-cycle mixed-number]
16-
simalq.geometry [Direction at dist adjacent? adj-or-eq? dir-to turn-and-pos-seed ray]
16+
simalq.geometry [Direction at dist adjacent? adj-or-eq? dir-to turn-and-pos-seed ray burst]
1717
simalq.game-state [G]
1818
simalq.tile [Tile Actor Damageable]
1919
simalq.tile.scenery [Scenery walkability can-occupy?])
@@ -53,6 +53,8 @@
5353
; If true, the monster kills itself upon attacking.
5454
sees-invisible F
5555
; If true, the monster is unaffected by the player being invisible.
56+
vampirizable F
57+
; If true, a vampire can turn this monster into another vampire.
5658
flavor-for-generator "In defiance of thermodynamics, this device pumps out monsters endlessly.")
5759
; Flavor text for generators of this monster type.
5860

@@ -175,6 +177,8 @@
175177
#("Kamikaze" "When the monster attacks, it dies. You get no points for this."))
176178
(when @sees-invisible
177179
#("Invisibility detection" "The monster is unaffected by you being invisible."))
180+
(when @vampirizable
181+
#("Vampirizable" "This monster can be turned by a vampire."))
178182
(@dod "Effect when damaged" 'hook-damaged Damageable)
179183
(@dod "Effect on death" 'hook-normal-destruction Damageable)
180184
#* extra
@@ -471,6 +475,7 @@
471475
:points-mon 3 :points-gen 12
472476
473477
:damage-melee #(3 6 9)
478+
:vampirizable T
474479
475480
:flavor-mon "A green-skinned, muscle-bound, porcine humanoid with a pointy spear and a bad attitude."
476481
:flavor-gen "A sort of orcish clown car, facetiously called a village.")
@@ -480,6 +485,7 @@
480485
:points-mon 2 :points-gen 8
481486
482487
:damage-melee #(2 4 6)
488+
:vampirizable T
483489
484490
:flavor-mon "Goblins are a smaller, uglier, smellier, and worse-equipped cousin of orcs that try to make up for it with even more sadistic malice. It almost works."
485491
:flavor-gen "Oops, somebody gave the goblins a bath. Now there's a lot more of them, and they still stink.")
@@ -529,6 +535,7 @@
529535
530536
:damage-melee 4
531537
:damage-shot #(4 8 12)
538+
:vampirizable T
532539
533540
:flavor-mon "This fresh-faced would-be scholar has finished sewing the stars onto his robe and is starting to grow a beard. Idok has told the whole class that whoever kills you gets tenure. Considering what the rest of the academic job market is like, the offer has proven irresistible to many."
534541
:flavor-gen "The Pigpimples Institute of Thaumaturgy and Dweomercraft: a shameless diploma mill that happily takes students' money to teach them one spell, then sends them on a suicide mission against a much smarter and tougher opponent.")
@@ -1057,6 +1064,75 @@
10571064
:flavor #[[A feudal lord of Dark Knights. Her armor is covered with long spikes, and her massive halberd means business. When she sees you, she cries out "Fight me!". But first, she'd like to soften you up with some of her subordinates.]])
10581065
10591066
1067+
(deftile "V " "a vampire" [Wanderer Summoner]
1068+
:iq-ix 204
1069+
:destruction-points 100
1070+
1071+
:field-defaults (dict
1072+
:action-i 0)
1073+
:mutable-fields #("action_i")
1074+
1075+
:immune undead-immunities
1076+
:damage-melee 10
1077+
1078+
:$summon-frequency 2
1079+
:$summon-hp 3
1080+
:$action-list #(
1081+
; For simplicity, vampires don't also sometimes apporach as in IQ.
1082+
'wander
1083+
'wander
1084+
'vampirize
1085+
'wander
1086+
'bats
1087+
'vampirize
1088+
'wander
1089+
'wander
1090+
'vampirize
1091+
'bats)
1092+
1093+
:info-bullets (meth []
1094+
(.info-bullets (super)
1095+
#("Action list" (.join ", " (map str @action-list)))
1096+
#("Action index" @action-i)))
1097+
1098+
:suffix-dict (meth []
1099+
{
1100+
#** (Monster.suffix-dict @)
1101+
"wd" (:wd (Wanderer.suffix-dict @))
1102+
; Summoner.suffix-dict is skipped on purpose, because the
1103+
; displayed summon power will always be 0, because the summon
1104+
; frequency is an integer.
1105+
"act" (hy.repr (str (get @action-list @action-i)))})
1106+
1107+
:act (meth []
1108+
(doc f"Idiosyncratic — If the monster can attack, it does. Otherwise, it rotates among its list of actions. `wander` works per `Wander`. `bats` summons {@summon-frequency} bats, each with {@summon-hp} HP. `vampirize` attempts to turn an adjacent monster into a vampire, and works per `Wander` if no eligible monster is present.")
1109+
(when (@try-to-attack-player)
1110+
(return))
1111+
(ecase (get @action-list @action-i)
1112+
'wander
1113+
(@wander)
1114+
'bats
1115+
(@summon "bat" @summon-frequency @summon-hp)
1116+
'vampirize
1117+
(block (for [p (burst @pos 1 :exclude-center T) tile (at p)]
1118+
(when (and
1119+
(isinstance tile Monster)
1120+
tile.vampirizable
1121+
(in (get (walkability @pos (dir-to @pos p) :monster? T) 1)
1122+
['bump 'walk]))
1123+
(.replace tile "vampire" :hp tile.hp)
1124+
(block-ret))
1125+
(else
1126+
(@wander)))))
1127+
(setv @action-i (% (+ 1 @action-i) (len @action-list))))
1128+
1129+
:hook-normal-destruction (meth []
1130+
(doc f"A bat with {@summon-hp} HP is created in its square.")
1131+
(@replace "bat" :hp @summon-hp))
1132+
1133+
:flavor "An aristocratic gentleman in a long black cloak with an infectious personality. A steady diet of the blood of the living makes him appear much more vivacious than other undead. Though he looks young, he is in fact somewhat long in the tooth.")
1134+
1135+
10601136
(deftile "@ " "a doppelganger" Approacher
10611137
:iq-ix 177
10621138
:destruction-points 100

simalq/tile/unimplemented.hy

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
[152 "random_gate"]
2222
[187 "magical_mirror"]
2323
[202 "rotation_trap"]
24-
[204 "vampire"]
2524
[205 "moving_wall"]
2625
[209 "snitch"]
2726
[210 "dark_king"]]

tests/test_monster.hy

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
(require
22
hyrule [do-n])
33
(import
4+
collections [Counter]
45
fractions [Fraction :as f/]
56
hyrule [thru]
67
tests.lib [init assert-at assert-full-name assert-hp assert-textmap wait set-square wk shoot mv-player use-item top]
@@ -1024,6 +1025,41 @@
10241025
(assert-at [2 0] 'floor))
10251026

10261027

1028+
(defn test-vampire []
1029+
1030+
(init [
1031+
:map "
1032+
d o w
1033+
. V g
1034+
. . .
1035+
██████
1036+
@ . ."
1037+
:map-marks {
1038+
"w " ["wizard" :hp 10]}])
1039+
(assert-full-name [1 3] #[[a vampire (HP 1, wd ....., act "wander")]])
1040+
; Given enough time, all the non-vampires (except the devil, which
1041+
; isn't vampirizable) are vampirized, and the remaining empty space
1042+
; is filled with 3-HP bats.
1043+
(wait 20)
1044+
(assert (=
1045+
(Counter (lfor
1046+
p (burst (Pos G.map 1 3) 1)
1047+
tile (at p)
1048+
#(tile.stem tile.hp)))
1049+
(Counter {
1050+
#("vampire" 1) 3
1051+
#("vampire" 10) 1
1052+
#("bat" 3) 4
1053+
#("devil" 1) 1})))
1054+
1055+
; A slain vampire becomes a 3-HP bat.
1056+
(init
1057+
[:tiles ["vampire"]])
1058+
(wk 'E)
1059+
(assert-at 'E "bat")
1060+
(assert-hp 'E 3))
1061+
1062+
10271063
(defn test-doppelganger []
10281064

10291065
; Tris takes 5 damage for each point of damage received by a

0 commit comments

Comments
 (0)