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