1 // Hyperbolic Rogue -- monster generation
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3
4 /** \file monstergen.cpp
5 * \brief monster generation
6 */
7
8 #include "hyper.h"
9 namespace hr {
10
11 EX int avengers, mirrorspirits, wandering_jiangshi, jiangshi_on_screen;
12
13 EX bool timerghost = true;
14 EX bool gen_wandering = true;
15
buildIvy(cell * c,int children,int minleaf)16 EX int buildIvy(cell *c, int children, int minleaf) {
17 if(c->monst) return 0;
18 c->mondir = NODIR;
19 c->monst = moIvyRoot;
20 c->monmirror = nonorientable && hrand(2);
21
22 cell *child = NULL;
23
24 int leaf = 0;
25 int leafchild = 0;
26 for(int i=0; i<c->type; i++) {
27 createMov(c, i);
28 if(passable(c->move(i), c, 0) && c->move(i)->land == c->land) {
29 if(children && !child)
30 child = c->move(i), leafchild = buildIvy(c->move(i), children-1, 5);
31 else
32 c->move(i)->monst = (leaf++ || peace::on) ? moIvyWait : moIvyHead,
33 c->move(i)->mondir = c->c.spin(i),
34 c->move(i)->monmirror = c->monmirror;
35 }
36 }
37
38 leaf += leafchild;
39 if(leaf < minleaf) {
40 if(child) killIvy(child, moNone);
41 dynamicval<int> k(kills[moIvyDead]);
42 killIvy(c, moNone);
43 return 0;
44 }
45 else return leaf;
46 }
47
48 /** the 'chasmify' functions create a simulation of the path the monster came by */
chasmify(cell * c)49 EX void chasmify(cell *c) {
50 c->wall = waChasm; c->item = itNone;
51 int q = 0;
52 cell *c2[10];
53 for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i)->mpdist > c->mpdist && cellUnstable(c->move(i)))
54 c2[q++] = c->move(i);
55 if(q) {
56 cell *c3 = c2[hrand(q)];
57 c3->wall = waChasmD;
58 }
59 }
60
chasmifyEarth(cell * c)61 EX void chasmifyEarth(cell *c) {
62 int q = 0;
63 int d2[10];
64 for(int i=2; i<=c->type-2; i++) {
65 int j = (i+c->mondir)%c->type;
66 cell *c2 = c->move(j);
67 if(c2 && c2->mpdist > c->mpdist && (
68 c2->wall == waDeadfloor || c2->wall == waDeadwall ||
69 c2->wall == waDeadfloor2))
70 d2[q++] = j;
71 }
72 if(!q) printf("no further move!\n");
73 if(q) {
74 int d = d2[hrand(q)];
75 cell *c3 = c->move(d);
76 c3->wall = waEarthD;
77 for(int i=0; i<c3->type; i++) {
78 cell *c4 = createMov(c3, i);
79 earthFloor(c4);
80 }
81 c3->mondir = c->c.spin(d);
82 }
83 earthWall(c); c->item = itNone;
84 }
85
chasmifyElemental(cell * c)86 EX void chasmifyElemental(cell *c) {
87 int q = 0;
88 int d2[10];
89 for(int i=2; i<=c->type-2; i++) {
90 int j = (i+c->mondir)%c->type;
91 cell *c2 = c->move(j);
92 if(c2 && c2->mpdist > c->mpdist && c2->land == c->land)
93 d2[q++] = j;
94 }
95 if(q) {
96 int d = d2[hrand(q)];
97 cell *c3 = c->move(d);
98 if(!c3->monst) {
99 c3->wall = waElementalD;
100 for(int i=0; i<c3->type; i++) {
101 cell *c4 = createMov(c3, i);
102 if(c4->wall != waBarrier) c4->wall = waNone;
103 }
104 c3->mondir = c->c.spin(d);
105 }
106 }
107 c->wall = getElementalWall(c->land);
108 c->wparam = 100; c->item = itNone;
109 }
110
111 /** generate a monster appropriate for the Crossroads */
112
crossroadsMonster()113 EX eMonster crossroadsMonster() {
114
115 static eMonster weak[9] = {
116 moYeti, moGoblin, moRanger, moOrangeDog, moRunDog, moMonkey, moZombie,
117 moDesertman, moCultist
118 };
119
120 if(hrand(10) == 0) return weak[hrand(9)];
121
122 static eMonster m[24] = {
123 moWorm, moTentacle,
124 moTroll, moEagle,
125 moLesser, moGreater, moPyroCultist, moGhost,
126 moFireFairy, moIvyRoot, moHedge,
127 moLancer, moFlailer, moVineBeast,
128 moBomberbird, moAlbatross, moRedTroll,
129 moWaterElemental, moAirElemental, moFireElemental,
130 moFatGuard, moMiner, moPalace, moVizier
131 };
132 eMonster mo = m[hrand(24)];
133 if(peace::on && mo == moWaterElemental) return crossroadsMonster();
134 if(peace::on && mo == moFireFairy) return crossroadsMonster();
135 if(peace::on && isMultitile(mo)) return crossroadsMonster();
136 return mo;
137 }
138
wanderingCrossroadsMonster()139 EX eMonster wanderingCrossroadsMonster() {
140 while(true) {
141 eMonster m = crossroadsMonster();
142 if(!isIvy(m) && m != moTentacle) return m;
143 }
144 }
145
palaceHP()146 EX int palaceHP() {
147 if(tactic::on && isCrossroads(firstland))
148 return 4;
149 if(items[itPalace] < 3) // 1+2
150 return 2;
151 else if(items[itPalace] < 10) // 1+2+3+4
152 return 3;
153 else if(items[itPalace] < 21) // 1+2+3+4+5+6
154 return 4;
155 else if(items[itPalace] < 35)
156 return 5;
157 else if(items[itPalace] < 50)
158 return 6;
159 else return 7;
160 }
161
hardness_empty()162 EX int hardness_empty() {
163 return yendor::hardness() * (yendor::hardness() * 3/5 - 2);
164 }
165
redtrolls(cell * c)166 EX bool redtrolls(cell *c) {
167 return false; /*
168 int cd = getCdata(c, 2);
169 cd &= 63;
170 return cd < 32; */
171 }
172
pickTroll(cell * c)173 EX eMonster pickTroll(cell *c) {
174 if(redtrolls(c))
175 return pick(moTroll,moDarkTroll,moRedTroll);
176 else
177 return pick(moForestTroll, moStormTroll, moFjordTroll);
178 }
179
dieTroll(cell * c,eMonster m)180 EX void dieTroll(cell *c, eMonster m) {
181 if(m == moTroll) c->wall = waDeadTroll;
182 else if(m == moDarkTroll) c->wall = waDeadfloor2;
183 else if(m == moRedTroll) c->wall = waRed1;
184 else c->wall = waDeadTroll2, c->wparam = m;
185 }
186
reptilemax()187 EX int reptilemax() {
188 int i = items[itDodeca] + yendor::hardness();
189 if(i >= 245) return 5;
190 int r = (250 - i);
191 if(shmup::on) r = (r+2) / 3;
192 return r;
193 }
194
wchance(int a,int of,int reduction=0)195 bool wchance(int a, int of, int reduction = 0) {
196 of *= 10;
197 a += yendor::hardness() + 1;
198 if(isCrossroads(cwt.at->land))
199 a+= items[itHyperstone] * 10;
200
201 //if(cwt.at->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3;
202
203 for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE)
204 a = max(a, (items[i]-R10) / 10);
205
206 a -= reduction;
207 if(a < 0) return false;
208
209 return hrand(a+of) < a;
210 }
211
wanderingZebra(cell * start)212 void wanderingZebra(cell *start) {
213 cell *c = start, *c2 = start;
214 for(int it=0; it<100; it++) {
215 if(c->cpdist == getDistLimit()) {
216 c->monst = moOrangeDog;
217 c->stuntime = 0;
218 return;
219 }
220 int q = 0;
221 cell *ctab[8];
222 for(int i=0; i<c->type; i++) {
223 cell *c3 = c->move(i);
224 if(c3 && c3 != c2 && c3->land == laZebra && c3->wall == waNone)
225 ctab[q++] = c3;
226 }
227 if(!q) break;
228 c2 = c; c = ctab[hrand(q)];
229 }
230 }
231
getGhostTimer()232 EX int getGhostTimer() {
233 return shmup::on ? (shmup::curtime - lastexplore) / 350 : turncount - lastexplore;
234 }
235
getGhostcount()236 EX int getGhostcount() {
237 if(peace::on) return 0;
238 int t = getGhostTimer();
239 int ghostcount = 0;
240 if(t > 80) ghostcount = (t-80 + hrand(20)) / 20;
241 return ghostcount;
242 }
243
getSeepcount()244 int getSeepcount() {
245 int t = getGhostTimer();
246 int seepcount = 0;
247 if(t > 40) seepcount = (t-40 + hrand(20)) / 20;
248 return seepcount;
249 }
250
canReachPlayer(cell * cf,eMonster m)251 EX bool canReachPlayer(cell *cf, eMonster m) {
252 manual_celllister cl;
253 cl.add(cf);
254 for(int i=0; i<isize(cl.lst) && i < 10000; i++) {
255 cell *c = cl.lst[i];
256 bool found = false;
257
258 auto test = [&] (cell *c2) {
259 if(cl.listed(c2)) return;
260 if(!passable_for(m, c2, c, P_MONSTER | P_ONPLAYER | P_CHAIN)) return;
261 if(isPlayerOn(c2)) found = true;
262 cl.add(c2);
263 };
264
265 forCellEx(c2, c) {
266 if(frog_power(m)) forCellEx(c3, c2) test(c3);
267 test(c2);
268 }
269
270 if(found) return true;
271 }
272 return false;
273 }
274
haveOrbPower()275 EX bool haveOrbPower() {
276 for(int i=0; i<ittypes; i++) if(itemclass(eItem(i)) == IC_ORB && items[i]) return true;
277 if(quotient) for(int i=0; i<isize(dcal); i++) {
278 cell *c = dcal[i];
279 if(itemclass(c->item) == IC_ORB) return true;
280 }
281 else if(sphere_narcm && WDIM == 2 && !INVERSE) for(int i=0; i<spherecells(); i++) {
282 cell *c = getDodecahedron(i)->c7;
283 if(itemclass(c->item) == IC_ORB) return true;
284 forCellEx(c2, c) if(itemclass(c2->item) == IC_ORB) return true;
285 }
286 return false;
287 }
288
haveKraken()289 EX bool haveKraken() {
290 for(int i=0; i<spherecells(); i++) {
291 cell *c = getDodecahedron(i)->c7;
292 if(c->monst == moKrakenH || c->monst == moKrakenT) return true;
293 }
294 return false;
295 }
296
wanderingTreasure(cell * c)297 EX eItem wanderingTreasure(cell *c) {
298 eLand l = c->land;
299 #if CAP_DAILY
300 if(daily::on && daily::prevent_spawn_treasure_on(c)) return itNone;
301 #endif
302 if(l == laEFire) return itFireShard;
303 if(l == laEWater) return itWaterShard;
304 if(l == laEAir) return itAirShard;
305 if(l == laEEarth) return itEarthShard;
306 if(l == laElementalWall) return itNone;
307 if(l == laAsteroids) return itNone;
308 if(l == laMirror && c->type != 6) return itNone;
309 if(l == laMirrorOld && c->type != 6) return itNone;
310 if(l == laEmerald) {
311 forCellEx(c2, c) if(c2->wall == waCavewall) return itNone;
312 }
313 if(l == laMinefield && c->wall == waMineMine) return itNone;
314 if(l == laBurial && hrand(2)) return itOrbSword;
315 if(l == laKraken) return itOrbFish;
316 return treasureType(l);
317 }
318
319 /** generate the wandering monsters */
wandering()320 EX void wandering() {
321 #if CAP_COMPLEX2
322 if(mine::in_minesweeper()) {
323 mine::count_status();
324 return;
325 }
326 #endif
327 if(!canmove) return;
328 if(!gen_wandering) return;
329 if(racing::on) return;
330 if(dpgen::in) return;
331 if(items[itOrbSafety]) return;
332 pathdata pd(moYeti);
333 int seepcount = getSeepcount();
334 int ghostcount = getGhostcount();
335 if(cwt.at->land == laCA) ghostcount = 0;
336 bool genturn = hrand(100) < 30;
337
338 if(bounded && specialland == laClearing)
339 clearing::new_root();
340
341 if(cwt.at->land == laZebra && cwt.at->wall == waNone && wchance(items[itZebra], 20))
342 wanderingZebra(cwt.at);
343
344 bool smallbounded_generation = smallbounded || (bounded && specialland == laClearing);
345
346 if(smallbounded_generation) {
347 int maxdist = 0;
348 for(int i=0; i<isize(dcal); i++) if(dcal[i]->cpdist > maxdist) maxdist = dcal[i]->cpdist;
349 for(int i=0; i<isize(dcal); i++) if(dcal[i]->cpdist >= maxdist-1) { first7 = i; break; }
350
351 if(hrand(5) == 0) {
352 // spawn treasure
353 }
354
355 if(smallbounded && hrand(100) < 2) {
356 auto& ac = currentmap->allcells();
357 cell *c1 = ac[hrand(isize(ac))];
358 if(c1->wall == waVinePlant && !c1->monst) {
359 c1->monst = moVineSpirit;
360 c1->stuntime = 3;
361 }
362 }
363 }
364
365 while(first7 < isize(dcal)) {
366 int i = first7 + hrand(isize(dcal) - first7);
367 cell *c = dcal[i];
368 if(inmirror(c)) continue;
369 if(isPlayerOn(c)) break;
370
371 if(specialland == laStorms) {
372 // place the sandstone wall completely randomly (but not on the player)
373 vector<cell*>& ac = currentmap->allcells();
374 c = ac[hrand(isize(ac))];
375 if(isPlayerOn(c)) continue;
376 }
377
378 if(smallbounded_generation && !c->item && hrand(5) == 0 && c->land != laHalloween) {
379 if(passable(c, NULL, 0) || specialland == laKraken) {
380 if(c->land != laGraveyard && !in_lovasz() && !haveOrbPower() && specialland != laHell) for(int it=0; it<1000 && !c->item; it++)
381 placeLocalOrbs(c);
382 if(!c->item) c->item = wanderingTreasure(c);
383 if(c->item == itShard) {
384 c->item = itNone;
385 mirror::build(c);
386 }
387 if(c->item == itFulgurite) {
388 c->item = itNone, c->wall = waSandstone;
389 }
390 if(c->item == itBarrow)
391 c->landparam = 2 + hrand(2),
392 c->wall = waBarrowDig;
393 }
394 }
395
396 if(!c->monst) c->stuntime = 0;
397
398 if(timerghost && !smallbounded) {
399 // wandering seeps & ghosts
400 if(seepcount && c->wall == waCavewall && !c->monst && canReachPlayer(c, moSlime)) {
401 c->monst = moSeep;
402 playSeenSound(c);
403 seepcount--;
404 continue;
405 }
406
407 if(ghostcount && !c->monst && !inmirror(c)) {
408 c->monst = moGhost;
409 playSeenSound(c);
410 ghostcount--;
411 continue;
412 }
413 }
414
415 if(c->land == laWet && !smallbounded && wetslime >= 25 && !c->monst && hrand(100) <= wetslime-25) {
416 static bool angry = false;
417 if(!angry) { angry = true; addMessage("You seem to have really pissed off the water spirits!"); }
418 c->monst = moGhost;
419 playSeenSound(c);
420 continue;
421 }
422
423 else if((c->wall == waCavewall || c->wall == waDeadwall) && !c->monst &&
424 wchance(items[treasureType(c->land)], 10) && canReachPlayer(c, moSlime)) {
425 c->monst = moSeep;
426 playSeenSound(c);
427 continue;
428 }
429
430 else if(smallbounded && c->wall == waVinePlant && !c->monst && wchance(items[treasureType(c->land)], 10) && canReachPlayer(c, moSlime)) {
431 c->monst = moVineSpirit;
432 playSeenSound(c);
433 continue;
434 }
435
436 else if(c->land == laOcean && cwt.at->land == laOcean && cwt.at->landparam > 25 && c->landparam > 25 && !tactic::on && !yendor::on && hrand(100) < 2) {
437 c->monst = moPirate; c->wall = waBoat; c->item = itOrbSafety;
438 continue;
439 }
440
441 else if(c->wall == waCTree && !c->monst && wchance(items[itPirate], 15) && canReachPlayer(c, moSlime)) {
442 c->monst = moParrot;
443 playSeenSound(c);
444 continue;
445 }
446
447 else if(c->land == laEndorian && c->wall == waNone && wchance(items[itApple], 50)) {
448 c->monst = moSparrowhawk;
449 playSeenSound(c);
450 continue;
451 }
452
453 #if CAP_COMPLEX2
454 else if(c->land == laBrownian && wchance(items[itBrownian], 75)) {
455 c->monst = moAcidBird;
456 continue;
457 }
458
459 else if(c->land == laVariant && wchance(items[itVarTreasure], 50)) {
460 int i = hrand(21);
461 if(getBits(c) & (1>>i)) {
462 eMonster m = variant::features[i].wanderer;
463 if(m) c->monst = m, c->hitpoints = 3;
464 }
465 continue;
466 }
467 #endif
468
469 else if(c->land == laFrog && !c->monst && wchance(items[itFrog], 25)) {
470 eMonster m = pick(moFrog, moPhaser, moVaulter);
471 if(canReachPlayer(c, m)) {
472 c->monst = m;
473 playSeenSound(c);
474 continue;
475 }
476 }
477
478 else if(c->land == laWet && among(c->wall, waDeepWater, waShallow) && !c->monst && wchance(items[itWet], 15) && canReachPlayer(c, moShark)) {
479 c->monst = hrand(100) < 10 ? moRusalka : moPike;
480 playSeenSound(c);
481 continue;
482 }
483
484 else if(c->wall == waSea && !c->monst) {
485 if(c->land == laCaribbean && wchance(items[itPirate], 15) && canReachPlayer(c, moPirate)) {
486 c->monst = moCShark;
487 playSeenSound(c);
488 continue;
489 }
490 if(c->land == laWarpSea && avengers && canReachPlayer(c, moPirate)) {
491 c->monst = moRatlingAvenger;
492 c->wall = waBoat;
493 avengers--;
494 if(cheater) printf("avenger comes\n");
495 playSeenSound(c);
496 continue;
497 }
498 if(c->land == laWarpSea && wchance(items[itCoral], 25) && canReachPlayer(c, moPirate)) {
499 c->monst = moRatling;
500 c->wall = waBoat;
501 playSeenSound(c);
502 continue;
503 }
504 if(c->land == laOcean && (items[itCoast] > 50 || ((cwt.at->land != laOcean || cwt.at->landparam < 25) && c->landparam < 25)) && wchance(items[itCoast], 25) && canReachPlayer(c, moEagle)) {
505 c->monst = moAlbatross;
506 playSeenSound(c);
507 continue;
508 }
509 if(c->land == laDocks && wchance(items[itDock], 25) && canReachPlayer(c, moEagle)) {
510 c->monst = moAlbatross;
511 playSeenSound(c);
512 continue;
513 }
514 if(!peace::on && c->land == laLivefjord && wchance(items[itFjord], 80) && items[itFjord] >= 10 && canReachPlayer(c, moWaterElemental)) {
515 c->monst = moWaterElemental;
516 playSeenSound(c);
517 continue;
518 }
519 if(!peace::on && c->land == laKraken && ((sphere && !hrand(15)) || wchance(items[itKraken], 240)) && !kraken_pseudohept(c)) {
520 bool b = sphere || canReachPlayer(c, moKrakenH);
521 if(sphere_narcm && WDIM == 2 && (haveKraken() || !items[itOrbFish])) {
522 c->monst = moViking; c->wall = waBoat; c->item = itOrbFish;
523 playSeenSound(c);
524 continue;
525 }
526 if(b) forCellEx(c2, c) if((sphere || c2->cpdist > gamerange()) && !kraken_pseudohept(c2)) {
527 forCellCM(c3, c2) if(c3->monst || c3->wall != waSea)
528 goto notfound;
529 c2->monst = moKrakenH;
530 c2->stuntime = 0;
531 playSeenSound(c2);
532 for(int i=0; i<c2->type; i++) {
533 c2->move(i)->monst = moKrakenT;
534 c2->move(i)->hitpoints = 1;
535 c2->move(i)->stuntime = 0;
536 c2->move(i)->mondir = c2->c.spin(i);
537 }
538 goto found;
539 }
540 goto notfound;
541 found:
542 continue;
543 }
544 notfound:
545 break;
546 }
547
548 else if(smallbounded && c->land == laPower && !c->monst) {
549 if(wchance(items[itPower], 10))
550 c->monst = eMonster(moWitch + hrand(NUMWITCH));
551 }
552
553 else if(c->monst || c->pathdist == PINFD) break;
554
555 else if(c->land == laAsteroids) {
556 int gen = 0;
557 if(asteroids_generated * 12 <= items[itAsteroid]) gen = 2;
558 if(gen == 0) {
559 int qty = 0;
560 for(cell *c: currentmap->allcells()) if(c->monst == moAsteroid) qty++;
561 if(!qty) gen = 1;
562 }
563 if(gen) c->monst = moAsteroid, c->hitpoints = 4;
564 if(gen == 2)
565 asteroids_generated++;
566
567 if(items[itAsteroid] > (asteroid_orbs_generated+2) * (asteroid_orbs_generated+3) && !c->item) {
568 c->item = pick(itOrbThorns, itOrbSide1, itOrbSide2, itOrbSide3, itOrbShield, itOrbLife);
569 asteroid_orbs_generated++;
570 }
571
572 break;
573 }
574
575 else if(c->land == laClearing && wchance(items[itMutant2], 150) && items[itMutant2] >= 15 && !c->monst && c->type == 7)
576 c->monst = moRedFox;
577
578 else if(c->land == laDual && wchance(items[itGlowCrystal], 40)) {
579 c->monst = moRatling;
580 playSeenSound(c);
581 }
582
583 else if(hrand(50) < statuecount * statuecount)
584 c->monst = moCultistLeader;
585
586 else if(c->land == laIce && wchance(items[itDiamond], 10))
587 c->monst = hrand(2) ? moWolf : moYeti;
588
589 else if(c->land == laHunting && wchance(items[itHunting], 50, 26))
590 c->monst = moHunterDog;
591
592 else if(c->land == laDesert && wchance(items[itSpice], 10))
593 c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm;
594
595 else if(c->land == laDragon && (items[itDragon] >= 8 || items[itOrbYendor]) && wchance(items[itDragon], 20))
596 c->monst = moFireElemental;
597
598 else if(c->land == laRedRock && wchance(items[itRedGem], 10)) {
599 if (hrand(10) || peace::on)
600 c->monst = moRedTroll;
601 else if (!pseudohept(c))
602 c->monst = moHexSnake, c->hitpoints = 1;
603 }
604
605 else if(c->land == laCaves && wchance(items[itGold], 5))
606 c->monst = hrand(3) ? moTroll : moGoblin;
607
608 else if(c->land == laBull && wchance(items[itBull], 40))
609 c->monst = moGadfly;
610
611 else if(items[itBull] >= 50 && isize(butterflies) && wchance(items[itBull]-49, 25))
612 c->monst = moGadfly;
613
614 else if(c->land == laPrairie && cwt.at->LHU.fi.flowerdist > 3 && wchance(items[itGreenGrass], prairie::isriver(cwt.at) ? 150 : 40))
615 c->monst = moGadfly;
616
617 else if(c->land == laHive && wchance(hive::hivehard(), 25))
618 c->monst = hive::randomHyperbug();
619
620 else if(c->land == laDeadCaves && wchance(items[itSilver], 5))
621 c->monst = hrand(20) ? (hrand(3) ? moDarkTroll : moGoblin) : moEarthElemental;
622
623 else if(c->land == laJungle && wchance(items[itRuby], 40))
624 c->monst = hrand(10) ? moMonkey : moEagle;
625
626 else if(c->land == laCursed && wchance(items[itCursed], 40))
627 c->monst = moHexer;
628
629 else if(c->land == laMirrorOld && wchance(items[itShard], 15))
630 c->monst = hrand(10) ? moRanger : moEagle;
631
632 else if(c->land == laMirror && mirrorspirits) {
633 mirrorspirits--;
634 c->monst = moMirrorSpirit;
635 }
636
637 else if(c->land == laMirror && wchance(items[itShard], 120))
638 c->monst = moNarciss;
639
640 else if(c->land == laWarpCoast && wchance(items[itCoral], 40))
641 c->monst = moRatling;
642
643 else if(c->land == laBurial && wchance(items[itBarrow], 250))
644 c->monst = moDraugr;
645
646 else if(c->land == laBlizzard && wchance(items[itBlizzard], 120))
647 c->monst = hrand(5) ? moVoidBeast : moIceGolem;
648
649 else if(c->land == laVolcano && wchance(items[itLavaLily], 120)) {
650 c->monst = hrand(5) ? moLavaWolf : moSalamander;
651 c->hitpoints = 3;
652 }
653
654 else if(c->land == laTrollheim && wchance(items[itTrollEgg], 150))
655 c->monst = pickTroll(c);
656
657 else if(c->land == laRose && wchance(items[itRose], 25))
658 c->monst = moFalsePrincess;
659
660 else if(c->land == laHell && wchance(items[itHell], 20))
661 c->monst = hrand(3) ? moLesser : moGreater;
662
663 else if(c->land == laStorms && wchance(items[itFulgurite], 30)) {
664 c->monst = hrand(3) ? moMetalBeast : moStormTroll;
665 c->hitpoints = 3;
666 }
667
668 else if(c->land == laWhirlwind && wchance(items[itWindstone], 30))
669 c->monst = hrand(5) ? moWindCrow : moAirElemental;
670
671 else if(c->land == laWildWest && wchance(items[itBounty], 30))
672 c->monst = moOutlaw;
673
674 else if(c->land == laEndorian && c->wall == waTrunk && wchance(items[itApple], 30))
675 c->monst = moResearcher;
676
677 else if(c->land == laOvergrown && wchance(items[itMutant], 50))
678 c->monst = moForestTroll;
679
680 else if(c->land == laTerracotta && wchance(items[itTerra], 40))
681 c->monst = moJiangshi;
682
683 else if(c->land == laTerracotta && wandering_jiangshi && genturn)
684 wandering_jiangshi--, c->monst = moJiangshi;
685
686 else if(c->land == laSwitch && wchance(items[itSwitch], 80))
687 c->monst = active_switch();
688
689 else if(c->land == laRuins && wchance(items[itRuins], 80)) {
690 c->monst = genRuinMonster(c);
691 c->hitpoints = 3;
692 }
693
694 else if(c->land == laEclectic && wchance(items[itEclectic], 20)) {
695 gen_eclectic_monster(c);
696 }
697
698 else if(c->land == laCaribbean && wchance(items[itPirate], 30))
699 c->monst = moPirate;
700
701 else if(c->land == laRlyeh && wchance(items[itStatue], 15))
702 c->monst = hrand(3) ? moPyroCultist :
703 (hrand(40) < items[itStatue]-25) ? moCultistLeader : moCultist;
704
705 else if(c->land == laGraveyard && wchance(items[itBone], 15))
706 c->monst = hrand(5) ? moGhost : moNecromancer;
707
708 else if(isHaunted(c->land) && wchance(items[itLotus], 15))
709 c->monst = moGhost;
710
711 else if(c->land == laDryForest && wchance(items[itFernFlower], 5))
712 c->monst = hrand(5) ? moHedge : moFireFairy;
713
714 else if(c->land == laCocytus && wchance(items[itSapphire], 45))
715 c->monst = moCrystalSage;
716
717 else if(c->land == laAlchemist && wchance(items[itElixir], 3) && canReachPlayer(c, moSlime) && c->item == itNone)
718 c->monst = moSlime; // ?
719
720 else if(isElemental(c->land) && wchance(items[itElemental], 20) && !peace::on)
721 c->monst = elementalOf(c->land);
722
723 else if(c->land == laIvoryTower && wchance(items[itIvory], 20))
724 c->monst = cellEdgeUnstable(c) ? moGargoyle : moFamiliar;
725
726 else if(c->land == laMinefield && wchance(items[itBombEgg]-20, 400))
727 c->monst = moBomberbird;
728
729 else if(c->land == laEmerald && wchance(items[itEmerald], 5))
730 c->monst = emerald_monster();
731
732 else if(c->land == laWineyard && wchance(items[itWine], 10)) {
733 c->monst = moVineBeast;
734 }
735
736 else if(c->land == laPalace && wchance(items[itPalace], 50)) {
737 if(princess::dist(c) < OUT_OF_PRISON && !princess::challenge) break;
738
739 if(items[itPalace] >= 15 && hrand(100) < 10)
740 c->monst = moVizier;
741 else if(items[itPalace] >= 5 && hrand(100) < 50)
742 c->monst = hrand(2) ? moFatGuard : moSkeleton;
743 else c->monst = moPalace;
744 c->hitpoints = palaceHP();
745 }
746
747 else if(c->land == laLivefjord && wchance(items[itFjord], 10)) {
748 c->monst = sphere ? pick(moViking, moWaterElemental, moFjordTroll) : moViking;
749 }
750
751 else if(c->land == laOcean && wchance(items[itCoast], 100)) {
752 c->monst = moAlbatross;
753 }
754
755 else if(c->land == laPower && wchance(items[itPower], 10)) {
756 c->monst = eMonster(moWitch + hrand(NUMWITCH));
757 }
758
759 else if(c->land == laCamelot && hrand(30) == 0 && (euclid || c->master->alt) && celldistAltRelative(c) < 0)
760 c->monst = camelot_monster();
761
762 else if(isCrossroads(c->land) && items[itHyperstone] && wchance(items[itHyperstone], 20)) {
763 c->monst = wanderingCrossroadsMonster();
764 c->hitpoints = palaceHP();
765 }
766
767
768 else break;
769
770 playSeenSound(c);
771 if(c->monst == moWorm || c->monst == moHexSnake) c->mondir = NODIR;
772
773 // laMotion -> no respawn!
774 }
775 }
776
generateSnake(cell * c,int i,int snakecolor)777 EX void generateSnake(cell *c, int i, int snakecolor) {
778 c->monst = moHexSnake;
779 c->hitpoints = snakecolor;
780 int cpair = (1<<pattern_threecolor(c)) | (1<<pattern_threecolor(c->move(i)));
781 preventbarriers(c);
782 int len = BITRUNCATED ? ROCKSNAKELENGTH : 2;
783 cell *c2 = c;
784 vector<cell*> rocksnake;
785 while(--len) {
786 rocksnake.push_back(c2);
787 preventbarriers(c2);
788 c2->mondir = i;
789 createMov(c2, i);
790 int j = c2->c.spin(i);
791 cell *c3 = c2->move(i);
792 if(c3->monst || c3->bardir != NODIR || c3->wall) break;
793 c2 = c3;
794 c2->monst = moHexSnakeTail; c2->hitpoints = snakecolor;
795 int t = c2->type;
796 if(hybri) t -= 2;
797 i = (j + (t%4 == 0 ? t/2 : (len%2 ? 2 : t - 2))) % t;
798 createMov(c2, i);
799 if(!inpair(c2->move(i), cpair)) {
800 vector<int> goodsteps;
801 {for(int i=0; i<t; i++)
802 if(inpair(c2->cmove(i), cpair))
803 goodsteps.push_back(i);}
804 if(!isize(goodsteps)) break;
805 i = goodsteps[hrand(isize(goodsteps))];
806 }
807 }
808 if(isize(rocksnake) < ROCKSNAKELENGTH/2 && BITRUNCATED) {
809 for(int i=0; i<isize(rocksnake); i++)
810 rocksnake[i]->monst = moNone;
811 }
812 else c2->mondir = NODIR;
813 }
814 }
815