1 // Hyperbolic Rogue -- Big Stuff
2 // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
3 
4 /** \file bigstuff.cpp
5  *  \brief Large map structures, such as (horo)cycles and equidistants.
6  *
7  *   This file implements:
8  *   * routines related to (horo)cycles
9  *   * routines related to equidistants
10  *   * 'setland' routines for other geometries
11  *   * the buildBigStuff function which calls equidistant/(horo)cycle/barrier generators.
12  *  This routines are general, i.e., not necessarily Steam-specific.
13  */
14 
15 #include "hyper.h"
16 namespace hr {
17 
18 // horocycles
19 
newRoundTableRadius()20 EX int newRoundTableRadius() {
21   return 28 + 2 * items[itHolyGrail];
22   }
23 
24 #if CAP_COMPLEX2
getAnthraxData(cell * c,bool b)25 EX int getAnthraxData(cell *c, bool b) {
26   int d = celldistAlt(c);
27   int rad = 28 + 3 * camelot::anthraxBonus;
28   while(d < -rad) {
29     d += rad + 12;
30     rad += 3;
31     }
32   while(d >= 12) {
33     if(rad > 5) rad -= 3;
34     else if(rad) rad--;
35     d -= rad + 12;
36     }
37   if(b) return rad;
38   return d;
39   }
40 #endif
41 
roundTableRadius(cell * c)42 EX int roundTableRadius(cell *c) {
43   if(eubinary) return 28;
44   #if CAP_COMPLEX2
45   if(ls::single()) return getAnthraxData(c, true);
46   #endif
47   if(!c->master->alt) return 28;
48   return altmap::radius(c->master->alt->alt) & GRAIL_RADIUS_MASK;
49   }
50 
celldistAltRelative(cell * c)51 EX int celldistAltRelative(cell *c) {
52   #if CAP_CRYSTAL
53   if(cryst) return crystal::dist_relative(c);
54   #endif
55   #if MAXMDIM >= 4
56   if(euc::in(3)) return euc::dist_relative(c);
57   #endif
58   if(euclid && quotient) return celldistAlt(c) - roundTableRadius(c);
59   if(sphere || quotient) {
60     return celldist(c) - 3;
61     }
62   #if CAP_COMPLEX2
63   if(ls::single()) return getAnthraxData(c, false);
64   #endif
65   return celldistAlt(c) - roundTableRadius(c);
66   }
67 
camelot_coords()68 EX gp::loc camelot_coords() { return gp::loc(a4 ? 21 : 20, 10); }
69 
euclidAlt(short x,short y)70 EX int euclidAlt(short x, short y) {
71   if(among(specialland, laTemple, laClearing, laCanvas)) {
72     if(euc::in(2,6))
73       return max(int(x), x+y);
74     else if(PURE)
75       return x + abs(y);
76     else
77       return max(x, y);
78     }
79   else if(specialland == laCaribbean || specialland == laWhirlpool || specialland == laMountain) {
80     if(euc::in(2,6))
81       return
82         min(
83           min(max(int(-x), -x-y) + 3,
84           max(int(x+y), int(y)) + 3),
85           max(int(x), int(-y)) + 3
86           );
87     else if(PURE)
88       return 3 - min(abs(x-y), abs(x+y));
89     else
90       return 3 - min(abs(x), abs(y));
91     }
92   else if(specialland == laPrincessQuest)
93     return euc::dist(gp::loc(x,y), princess::coords());
94   else return euc::dist(gp::loc(x,y), camelot_coords());
95   }
96 
cylinder_alt(cell * c)97 EX int cylinder_alt(cell *c) {
98   if(specialland == laPrincessQuest)
99     return celldistance(c, euc::at(princess::coords()));
100   if(specialland == laCamelot)
101     return celldistance(c, euc::at(camelot_coords()));
102 
103   int maxmul = 0;
104   for(int d = 0; d < SG6; d++)
105     maxmul = max(maxmul, euc::dcross(euc::sdxy(), gp::eudir(d)));
106   return 5-abs(gdiv(euc::dcross(euc::sdxy(), euc2_coordinates(c)), maxmul));
107   }
108 
109 const int NOCOMPASS = 1000000;
110 
compassDist(cell * c)111 EX int compassDist(cell *c) {
112   if(sphere || quotient) return 0;
113   if(eubinary || c->master->alt) return celldistAlt(c);
114   if(isHaunted(c->land) || c->land == laGraveyard) return getHauntedDepth(c);
115   return NOCOMPASS;
116   }
117 
findcompass(cell * c)118 EX cell *findcompass(cell *c) {
119   int d = compassDist(c);
120   if(d == NOCOMPASS) return NULL;
121 
122   while(inscreenrange(c)) {
123     if(!eubinary && !sphere && !quotient)
124       currentmap->extend_altmap(c->master);
125     forCellEx(c2, c) if(compassDist(c2) < d) {
126       c = c2;
127       d = compassDist(c2);
128       goto nextk;
129       }
130     break;
131     nextk: ;
132     }
133 
134   return c;
135   }
136 
grailWasFound(cell * c)137 EX bool grailWasFound(cell *c) {
138   if(eubinary || quotient || sphere) return items[itHolyGrail];
139   return altmap::radius(c->master->alt->alt) & GRAIL_FOUND;
140   }
141 
default_levs()142 EX int default_levs() {
143   if(arb::in()) return 2;
144   if(IRREGULAR)
145     return 1;
146   if(S3 >= OINF)
147     return 1;
148   #if MAXMDIM >= 4
149   if(reg3::in_rule()) return 0;
150   #endif
151   return S3-3;
152   }
153 
154 #if HDR
155 namespace altmap {
156   /** h->move(relspin(h->alt)) corresponds to h->alt->move(0) */
relspin(heptagon * alt)157   inline short& relspin(heptagon *alt) { return alt->zebraval; }
158 
159   /** for Camelot, the radius */
radius(heptagon * alt)160   inline short& radius(heptagon *alt) { return alt->emeraldval; }
161 
162   /** type of the horocycle -- currently used in Land of Storms which has two types */
which(heptagon * alt)163   inline short& which(heptagon *alt) { return alt->emeraldval; }
164 
165   /** the original land, for altmaps which may appear in multiple lands (Camelot) */
orig_land(heptagon * alt)166   inline short& orig_land(heptagon *alt) { return alt->fiftyval; }
167 
168   /** NOTE: do not use fieldval, because it would conflict with the map generation for hrmap_h3_rule and hrmap_rulegen */
169   }
170 #endif
171 
extend_altmap(heptagon * h,int levs,bool link_cdata)172 void hrmap::extend_altmap(heptagon *h, int levs, bool link_cdata) {
173   if(hybri) { PIU ( extend_altmap(h, levs, link_cdata) ); }
174   if(!h->alt) return;
175   preventbarriers(h->c7);
176   if(h->c7) forCellEx(c2, h->c7) preventbarriers(c2);
177   if(GOLDBERG)
178     for(int i=0; i<S7; i++) preventbarriers(createStep(h, i)->c7);
179   for(int i=0; i<h->type; i++)
180     createStep(h->alt, i)->alt = h->alt->alt;
181 
182   auto relspin = altmap::relspin(h->alt);
183 
184   // h[relspin] matches alt[0]
185   // int relspin = h->alt->fieldval;
186 
187   if(h->type != h->alt->type) return;
188   for(int i=0; i<h->type; i++) {
189     int ir = gmod(i-relspin, h->type);
190     heptagon *hm = h->alt->move(ir);
191     heptagon *ho = createStep(h, i);
192     if(ho->alt && ho->alt != hm) {
193       if(ho->alt->alt == hm->alt && !quotient) {
194         // printf("ERROR: alt cross! [%d -> %d]\n", ho->alt->distance, hm->distance);
195         println(hlog, "alt error from ", h->c7, " to ", ho->c7);
196         // exit(1);
197         }
198       continue;
199       }
200     ho->alt = hm;
201     altmap::relspin(hm) = gmod(h->c.spin(i) - h->alt->c.spin(ir), hm->type);
202     if(link_cdata) hm->cdata = (cdata*) ho;
203     if(levs) currentmap->extend_altmap(ho, levs-1, link_cdata);
204     if(S3 >= OINF) preventbarriers(ho->c7);
205     }
206   }
207 
208 #if MAXMDIM >= 4
hrandom_adjacent(cellwalker cw)209 EX int hrandom_adjacent(cellwalker cw) {
210   auto& da = currentmap->dirdist(cw);
211   vector<int> choices = {cw.spin};
212   for(int a=0; a<cw.at->type; a++) if(da[a] == 1) choices.push_back(a);
213   return hrand_elt(choices, cw.spin);
214   }
215 #endif
216 
217 EX heptagon *create_altmap(cell *c, int rad, hstate firststate, int special IS(0)) {
218 
219   if(hybri) {
220     if(hybrid::under_class() == gcSphere) return NULL;
221     c = hybrid::get_where(c).first;
222     return PIU ( create_altmap(c, rad, firststate, special) );
223     }
224 
225   // check for direction
226   int gdir = -1;
227   for(int i=0; i<c->type; i++) {
228     #if MAXMDIM >= 4
229     if(!reg3::in_rule()) {
230     #else
231     if(true) {
232     #endif
233       if(c->move(i) && c->move(i)->mpdist < c->mpdist) gdir = i;
234       }
235     else {
236       /* mpdist may be incorrect */
237       if(c->move(i) && c->move(i)->master->distance < c->master->distance) gdir = i;
238       }
239     }
240   #if MAXMDIM >= 4
241   if(reg3::in_rule() && c->master->distance == 0) gdir = 0;
242   #endif
243   if(gdir < 0) return NULL;
244 
245   // non-crossing in weird hyperbolic
246   if(weirdhyperbolic) {
247     if(c->bardir == NOBARRIERS) return NULL;
248     forCellCM(c1, c) if(c1->bardir == NOBARRIERS) return NULL;
249     if(IRREGULAR)
250       for(int i=0; i<S7; i++)
251         if(createStep(c->master, i)->c7->bardir != NODIR)
252           return NULL;
253     }
254 
255   // check for non-crossing
256   int bd = 2;
257   cellwalker bb(c, bd);
258   if(!weirdhyperbolic && !(checkBarriersFront(bb) && checkBarriersBack(bb))) {
259     return NULL;
260     }
261 
262   cellwalker bf(c, gdir); bf += rev;
263   auto p = generate_random_path(bf, rad, false, false);
264 
265   for(auto c: p.path) if(c->bardir != NODIR) return nullptr;
266 
267   heptagon *h = p.last.at->master;
268 
269   if(h->alt) {
270     printf("Error: creatingAlternateMap while one already exists\n");
271     return NULL;
272     }
273 
274   if(special == waPalace) {
275     cell *c = p.last.at;
276     if(!ctof(c) || cdist50(c) != 0 || !polarb50(c)) return nullptr;
277     }
278 
279   heptagon *alt = init_heptagon(h->type);
280   allmaps.push_back(newAltMap(alt));
281   alt->s = firststate;
282   if(!currentmap->link_alt(h, alt, firststate, p.last.spin)) {
283     return nullptr;
284     }
285   if(hybri) hybrid::altmap_heights[alt] = hybrid::get_where(centerover).second;
286   alt->alt = alt;
287   h->alt = alt;
288   alt->cdata = (cdata*) h;
289 
290   for(int d=rad; d>=0; d--) {
291     currentmap->extend_altmap(p.path[d]->master);
292     preventbarriers(p.path[d]);
293     }
294 
295   if(special == waPalace) {
296 
297     cell *c = p.last.at;
298 
299     princess::generating = true;
300     c->land = laPalace;
301     for(int j=BARLEV; j>=0; j--)
302       setdist(c, j, NULL);
303     princess::generating = false;
304 
305     princess::newInfo(c);
306     princess::forceMouse = false;
307 
308     if(princess::gotoPrincess && cheater) princess::gotoPrincess=false, cwt.at = c;
309     }
310 
311   return alt;
312 //for(int d=rad; d>=0; d--) printf("%3d. %p {%d}\n", d, hr::voidp(cx[d]->master), cx[d]->master->alt->distance);
313   }
314 
beCIsland(cell * c)315 EX void beCIsland(cell *c) {
316   int i = hrand(3);
317   if(i == 0) c->wall = waCIsland;
318   if(i == 1) c->wall = waCIsland2;
319   if(i == 2) c->wall = waCTree;
320   return;
321   }
322 
generateTreasureIsland(cell * c)323 EX void generateTreasureIsland(cell *c) {
324   gen_alt(c);
325   if(isOnCIsland(c)) return;
326 
327   bool src = hrand(100) < 10;
328   if(src) {
329     beCIsland(c);
330     if(c->wall == waCTree) return;
331     }
332   vector<cell*> ctab;
333   int qlo, qhi;
334   for(int i=0; i<c->type; i++) {
335     cell *c2 = createMov(c, i);
336     if(!eubinary) currentmap->extend_altmap(c2->master);
337     if(greater_alt(c, c2)) {
338       ctab.push_back(c2);
339       qlo = i; qhi = i;
340       while(true && isize(ctab) < c->type) {
341         qlo--;
342         c2 = c->cmodmove(qlo);
343         if(!have_alt(c2)) break;
344         if(celldistAlt(c2) >= celldistAlt(c)) break;
345         ctab.push_back(c2);
346         }
347       while(true && isize(ctab) < c->type) {
348         qhi++;
349         c2 = c->cmodmove(qhi);
350         if(!have_alt(c2)) break;
351         if(celldistAlt(c2) >= celldistAlt(c)) break;
352         ctab.push_back(c2);
353         }
354       break;
355       }
356     }
357   if(ctab.empty()) {
358     printf("NO QC\n"); c->wall = waSea;
359     for(int i=0; i<c->type; i++) printf("%d ", celldistAlt(c->move(i)));
360     printf("vs %d\n", celldistAlt(c));
361     return;
362     }
363   cell* c2 = c->cmodmove((qlo+qhi)/2);
364   generateTreasureIsland(c2);
365   if(!src) {
366     c->wall = c2->wall;
367     if(c->wall != waCTree && hrand(100) < 15)
368       c->wall = (c->wall == waCIsland ? waCIsland2 : waCIsland);
369     }
370   if(src && c2->wall == waCTree && have_alt(c) && celldistAlt(c) <= -10 && geometry != gRhombic3) {
371     bool end = true;
372     for(cell *cc: ctab) {
373       generateTreasureIsland(cc);
374       if(cc->wall != waCTree)
375         end = false;
376       }
377     // printf("%p: end=%d, qc=%d, dist=%d\n", hr::voidp(c), end, qc, celldistAlt(c));
378     if(end) c->item = itPirate;
379     else c->item = itCompass;
380     }
381   }
382 
383 // equidistants
384 
385 EX bool generatingEquidistant = false;
386 
buildAnotherEquidistant(cell * c,int radius)387 EX cell *buildAnotherEquidistant(cell *c, int radius) {
388   int gdir = -1;
389   for(int i=0; i<c->type; i++) {
390     if(c->move(i) && c->move(i)->mpdist < c->mpdist) gdir = i;
391     }
392   if(gdir == -1) return NULL;
393 
394   cellwalker cw(c, (gdir+3) % c->type);
395   vector<cell*> coastpath;
396 
397   while(isize(coastpath) < radius || (cw.at->type != 7 && !weirdhyperbolic)) {
398     // this leads to bugs for some reason!
399     if(cw.at->land == laCrossroads2) {
400 #ifdef AUTOPLAY
401       if(doAutoplay) printf("avoiding the Crossroads II\n"); // todo
402 #endif
403       return NULL;
404       }
405     if(cw.at->bardir != NODIR) return NULL;
406     if(cw.at->landparam && cw.at->landparam < radius) return NULL;
407 
408     /* forCellEx(c2, cw.at) if(c2->bardir != NODIR) {
409       generatingEquidistant = false;
410       return;
411       } */
412     coastpath.push_back(cw.at);
413     if(cw.at->land == laNone && cw.at->mpdist <= 7) {
414       raiseBuggyGeneration(cw.at, "landNone 1");
415       for(int i=0; i<isize(coastpath); i++) coastpath[i]->item = itPirate;
416       return NULL;
417       }
418     cw = cw + wstep + 3;
419     if(ctof(cw.at) && hrand(2) == 0) cw++;
420     }
421   coastpath.push_back(cw.at);
422   // printf("setdists\n");
423   for(int i=1; i<isize(coastpath) - 1; i++) {
424     if(coastpath[i-1]->land == laNone) {
425       raiseBuggyGeneration(cwt.at, "landNone 3");
426       int mpd[10];
427       for(int i=0; i<10; i++) mpd[i] = coastpath[i]->mpdist;
428       {for(int i=0; i<10; i++) printf("%d ", mpd[i]);} printf("\n");
429       for(int i=0; i<isize(coastpath); i++) coastpath[i]->item = itPirate;
430       return NULL;
431       }
432     setdist(coastpath[i], BARLEV, coastpath[i-1]);
433     setdist(coastpath[i], BARLEV-1, coastpath[i-1]);
434     if(i < isize(coastpath) - 5) {
435       coastpath[i]->bardir = NOBARRIERS;
436 //      forCellEx(c2, coastpath[i]) c2->bardir = NOBARRIERS;
437       }
438     }
439 
440   //printf("building barrier\n");
441   cell *c2 = coastpath[coastpath.size() - 1];
442 
443   bool nowall = false;
444 
445   if(c2->land == laNone) {
446     raiseBuggyGeneration(c2, "landNone 2");
447     for(int i=0; i<isize(coastpath); i++) coastpath[i]->item = itPirate;
448     return NULL;
449     }
450 
451   // prevent gravity anomalies
452   if(c2->land != c->land) return NULL;
453 
454   bool oc = c->land == laOcean;
455 
456   // else if(ctof(c) && hrand(10000) < 20 && !isCrossroads(c->land) && gold() >= 200)
457   if(oc && ls::no_walls() && buildBarrierNowall(c2, getNewLand(laOcean))) {
458     nowall = true;
459     }
460   else if(oc && pseudohept(c2) && gold() >= R200 && hrand(10) < 2 && buildBarrierNowall(c2, laCrossroads4)) {
461     nowall = true;
462     // raiseBuggyGeneration(c2, "check");
463     // return;
464     }
465   else if(ls::nice_walls()) build_barrier_good(c2);
466   //printf("building barrier II\n");
467   if(hasbardir(c2)) extendBarrier(c2);
468 
469   for(int i=isize(coastpath)-(nowall?1:2); i>=0; i--) {
470     for(int j=BARLEV; j>=6; j--)
471       setdist(coastpath[i], j, NULL);
472     }
473 
474   return c2;
475   }
476 
buildAnotherEquidistant(cell * c)477 EX void buildAnotherEquidistant(cell *c) {
478   //printf("building another coast\n");
479 
480   if(yendor::on) return;
481 
482   generatingEquidistant = true;
483 
484   int radius = c->land == laOcean ? 30 : HAUNTED_RADIUS + 5;
485 
486   buildAnotherEquidistant(c, radius);
487 
488   generatingEquidistant = false;
489   }
490 
coastval(cell * c,eLand base)491 EX int coastval(cell *c, eLand base) {
492   if(!c) return UNKNOWN;
493   if(c->land == laNone) return UNKNOWN;
494   if(base == laGraveyard) {
495     if(c->land == laHaunted || c->land == laHauntedWall)
496       return 0;
497     if(c->land != laGraveyard && c->land != laHauntedBorder) return 30;
498     }
499   else if(base == laMirrored) {
500     if(!inmirror(c)) return 0;
501     if(!c->landparam) return UNKNOWN;
502     return c->landparam & 255;
503     }
504   else {
505     if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool ||
506       c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken || c->land == laDocks || c->land == laBrownian)
507       return 30;
508     if(c->land  != laOcean && !isGravityLand(c->land) && c->land != laHaunted) {
509       return 0;
510       }
511     }
512   if(!c->landparam) return UNKNOWN;
513   return c->landparam;
514   }
515 
checkInTree(cell * c,int maxv)516 EX bool checkInTree(cell *c, int maxv) {
517   if(c->landparam <= 3) return false;
518   if(!maxv && WDIM == 3 && bt::in()) {
519     forCellEx(c2, c) if(c2->landflags) return true;
520     }
521   if(!maxv) return false;
522   if(c->landflags) return true;
523   forCellEx(c2, c)
524     if(c2->landparam < c->landparam && checkInTree(c2, maxv-1))
525       return true;
526   return false;
527   }
528 
529 int loopval = 0;
530 
531 struct loopchecker {
loopcheckerhr::loopchecker532   loopchecker() { loopval++; }
~loopcheckerhr::loopchecker533   ~loopchecker() { loopval--; }
534   };
535 
buildEquidistant(cell * c)536 EX void buildEquidistant(cell *c) {
537   loopchecker lc;
538   // sometimes crashes in Archimedean
539   if(loopval > 100) { c->landparam = 0; return; }
540   if(!c) return;
541   if(c->landparam) return;
542   /* if(weirdhyperbolic) {
543     c->landparam = 50;
544     return;
545     } */
546   if(sphere || euclid) return;
547   eLand b = c->land;
548   if(ls::any_chaos() && !inmirror(b)) return;
549   if(!b) {
550     printf("land missing at %p\n", hr::voidp(c));
551     describeCell(c);
552     for(int i=0; i<c->type; i++) if(c->move(i))
553       describeCell(c->move(i));
554     // buggycells.push_back(c);
555     }
556   if(b == laHauntedBorder) b = laGraveyard;
557   if(inmirror(b)) b = laMirrored;
558   int mcv = UNKNOWN;
559 
560   // find the lowest coastval
561   for(int i=0; i<c->type; i++) {
562     int cv = coastval(createMov(c,i), b);
563     if(cv < mcv) mcv = cv;
564     }
565 
566   if(S3 == OINF) {
567     c->landparam = mcv + 1;
568     return;
569     }
570 
571   int mcv2 = 0;
572 
573   if(mcv == 0) {
574     // if(generatingEquidistant) printf("mcv=0\n");
575     c->landparam = 1;
576     }
577   else if(WDIM == 3) {
578     forCellCM(c2, c) if(coastval(c2, b) == mcv)
579       forCellEx(c3, c2) if(coastval(c3, b) < mcv)
580         forCellCM(c4, c3) {
581           if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2);
582           buildEquidistant(c4);
583           }
584     forCellCM(c2, c) {
585       int cv = coastval(c2, b);
586       if(cv < mcv) mcv = cv;
587       }
588     c->landparam = mcv + 1;
589     }
590   else {
591     // if it appears twice, increase it
592     int qcv = 0;
593     int sid = 0;
594     for(int i=0; i<c->type; i++)
595       if(coastval(c->move(i), b) == mcv)
596         qcv++, sid = i;
597 
598     // if(generatingEquidistant) printf("qcv=%d mcv=%d\n", qcv, mcv);
599     if(qcv >= 2) c->landparam = mcv+1; // (mcv == UNKNOWN ? UNKNOWN : mcv+1);
600     else {
601       // if(qcv != 1) { printf("qcv = %d\n", qcv);  exit(1); }
602       cell *c2 = c->move(sid);
603       int bsid = c->c.spin(sid);
604       for(int j=0; j<c2->type; j++) {
605         int q = gmod(bsid+j, c2->type);
606         cell *c3 = c2->move(q);
607         if(coastval(c3, b) < mcv) {
608           cell *c4 = c2->cmodmove(bsid+1);
609           if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2);
610           buildEquidistant(c4);
611           mcv2 = coastval(c4, b);
612           break;
613           }
614         q = gmod(bsid-j, c2->type);
615         c3 = c2->move(q);
616         if(coastval(c3, b) < mcv) {
617           cell *c4 = c2->cmodmove(bsid-1);
618           if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2);
619           buildEquidistant(c4);
620           mcv2 = coastval(c4, b);
621           break;
622           }
623         }
624       if(mcv2 > mcv) mcv2 = mcv;
625       if(mcv2 == 0) mcv2 = mcv;
626       c->landparam = mcv2+1;
627 
628       /* if(c->heat < 3)
629         raiseBuggyGeneration(c, "low heat"); */
630       }
631     }
632 
633   if(!c->landparam) {
634     // int z = int(c->heat);
635     if(c->item || c->monst)
636       printf("building coast over %s/%s, mpdist = %d\n", iinf[c->item].name, minf[c->monst].name,
637         c->mpdist);
638     if(c->land == laOcean) c->wall = waSea;
639     }
640 
641   if(c->land == laEndorian) {
642     int ct = c->type;
643     #if CAP_BT
644     if(bt::in()) {
645       int skip = geometry == gHoroRec ? 3 : 2;
646       int up = bt::updir();
647       if(c->landparam == 1)
648         c->landflags = (hrand(100) < 20);
649       else if(WDIM == 2 && c->type == 6 && (c->landparam % 2) && c->move(bt::bd_down) && c->move(bt::bd_down)->landflags)
650         c->landflags = 1;
651       else if(WDIM == 2 && c->type == 7 && (c->landparam % 2 == 0)) {
652         for(int d: {bt::bd_down_left, bt::bd_down_right})
653           if(c->move(d) && c->move(d)->landflags)
654             c->landflags = 1;
655         }
656       else if(WDIM == 3 && c->landparam % skip != 1 && c->move(up) && c->move(up)->landflags)
657         c->landflags = 1;
658       else if(WDIM == 3 && c->landparam % skip == 1 && c->move(up) && c->move(up)->c.spin(up) == (c->c.spin(up)) && c->move(up)->move(up)->landflags)
659         c->landflags = 1;
660       if(c->landflags) c->wall = (WDIM == 3 ? waTrunk3 : waTrunk);
661       }
662     else
663     #endif
664     #if MAXMDIM >= 4
665     if(WDIM == 3 && hyperbolic) {
666       if(c->landparam == 1)
667         c->landflags = (hrand(100) < 20);
668       else if(S7 == 12) {
669         for(int i=0; i<S7; i++) {
670           cellwalker cw(c, i);
671           if(!cw.peek()) continue;
672           cw += wstep;
673           if(cw.at->landparam != c->landparam-1) continue;
674           if(!cw.at->landflags) continue;
675           if(S7 == 6) c->landflags = 1;
676           else {
677             auto& da = currentmap->dirdist(cw);
678             for(int j=0; j<S7; j++) if(cw.at->move(j) && cw.at->move(j)->landparam == c->landparam - 2 && da[j] != 1)
679               if(c->landparam == 2 ? cw.at->move(j)->land != laEndorian : cw.at->move(j)->landparam)
680                 c->landflags = 1;
681             }
682           }
683         }
684       else if(c->landparam == 2) {
685         for(int i=0; i<c->type; i++) {
686           cellwalker cw(c, i);
687           if(!cw.peek()) continue;
688           cw += wstep;
689           if(cw.at->landparam != 1) continue;
690           if(!cw.at->landflags) continue;
691           cw += rev;
692           if(cw.peek() && cw.peek()->land != laEndorian) c->landflags = 1;
693           }
694         }
695       else if(c->landparam % 2 == 1) {
696         for(int i=0; i<c->type; i++) {
697           cellwalker cw(c, i);
698           if(!cw.peek()) continue;
699           cw += wstep;
700           if(cw.at->landparam != c->landparam-1) continue;
701           if(!cw.at->landflags) continue;
702           if(S7 == 6) c->landflags = 1;
703           else {
704             auto& da = currentmap->dirdist(cw);
705             for(int j=0; j<S7; j++) if(cw.at->move(j) && cw.at->move(j)->landparam == c->landparam - 2 && da[j] != 1 && cw.at->move(j)->landflags)
706               c->landflags = 1;
707             }
708           }
709         }
710       else {
711         for(int i=0; i<c->type; i++) {
712           cellwalker cw(c, i);
713           if(!cw.peek()) continue;
714           cw += wstep;
715           if(cw.at->landparam != c->landparam-1) continue;
716           if(!cw.at->landflags) continue;
717           cw += rev;
718           if(cw.peek() && cw.peek()->landflags) c->landflags = 1;
719           }
720         }
721       if(c->landflags) c->wall = waTrunk3;
722       }
723     else
724     #endif
725     if(c->landparam == 1 && ctof(c)) {
726       for(int i=0; i<ct; i++) {
727         int i1 = (i+1) % c->type;
728         if(c->move(i) && c->move(i)->land != laEndorian && c->move(i)->land != laNone)
729         if(c->move(i1) && c->move(i1)->land != laEndorian && c->move(i1)->land != laNone) {
730           c->landflags = 2;
731           c->wall = waTrunk;
732           }
733         }
734       }
735     else if(c->landparam == 1 && !ctof(c)) {
736       int ct = c->type;
737       for(int i=0; i<ct; i++) {
738         int i1 = (i+1) % ct;
739         int i2 = (i+2) % ct;
740         int i4 = (i+4) % ct;
741         int i5 = (i+5) % ct;
742         if(c->move(i) && c->move(i)->land == laBarrier && c->move(i)->type == 7)
743         if(c->move(i1) && c->move(i1)->land != laBarrier)
744         if(c->move(i2) && c->move(i2)->land != laBarrier)
745         if(c->move(i4) && c->move(i4)->land != laBarrier)
746         if(c->move(i5) && c->move(i5)->land != laBarrier) {
747           c->landflags = 2;
748           c->wall = waTrunk;
749           }
750 
751         if(c->move(i) && c->move(i)->land != laEndorian && c->move(i)->land != laNone && c->move(i)->type == 7)
752         if(c->move(i1) && c->move(i1)->land != laEndorian && c->move(i1)->land != laNone)
753         if(c->move(i5) && c->move(i5)->land != laEndorian && c->move(i5)->land != laNone) {
754           c->landflags = 3;
755           c->wall = waTrunk;
756           }
757         }
758       }
759     else if(c->landparam > 1) {
760       for(int i=0; i<c->type; i++) {
761         cell *c2 = c->move(i);
762         if(c2 && c2->landparam < c->landparam && c2->landflags) {
763           bool ok = false;
764           if(c2->landflags == 3)
765             ok = true;
766           else if(c2->landflags == 2) {
767             ok = c->modmove(i+1)->landparam != c->landparam-1
768              &&  c->modmove(i-1)->landparam != c->landparam-1;
769             }
770           else for(int j=0; j<c2->type; j++) {
771             cell *c3 = c2->move(j);
772             if(c3 && c3->landparam < c2->landparam && c3->landflags)
773               if(c->c.spin(i) == (j+3)%c2->type || c->c.spin(i) == (j+c2->type-3)%c2->type)
774                 ok = true;
775             }
776           if(ok) {
777             c->wall = waTrunk;
778             c->landflags = 1;
779             }
780           }
781         if(c2 && c2->landparam < c->landparam && c2->landflags == 1 && ctof(c)) {
782           cell *c3 = c->modmove(i+1);
783           if(c3 && c3->landparam < c->landparam && c3->landflags == 1) {
784             c->wall = waTrunk;
785             c->landflags = 2;
786             }
787           }
788         }
789       }
790     if(!c->landflags && checkInTree(c, 5)) {
791       int lev = hrand(100);
792       if(lev < 10) c->wall = waSolidBranch;
793       else if(lev < 20) c->wall = waWeakBranch;
794       else c->wall = waCanopy;
795       }
796     }
797 
798   bool chance =
799     ls::no_walls() ? (hrand(100) < 10) :
800     ls::nice_walls() ? true :
801     false;
802 
803   if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !hybri && hrand(10) < 5 && chance)
804     buildAnotherEquidistant(c);
805 
806   if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !hybri && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
807     buildAnotherEquidistant(c);
808   }
809 
randomDown(cell * c)810 EX cell *randomDown(cell *c) {
811   vector<cell*> tab;
812   for(int i=0; i<c->type; i++)
813     if(c->move(i) && coastval(c->move(i), laIvoryTower) < coastval(c, laIvoryTower))
814       tab.push_back(c->move(i));
815   if(isize(tab)==1) return tab[0];
816   return hrand_elt(tab, (cell*)nullptr);
817   }
818 
edgeDepth(cell * c)819 EX int edgeDepth(cell *c) {
820   if(c->land == laIvoryTower || c->land == laEndorian || c->land == laDungeon || c->land == laWestWall)
821     return coastvalEdge(c);
822   else if(c->land != laBarrier) {
823     for(int i=0; i<c->type; i++) if(c->move(i) && c->move(i)->land == laBarrier)
824       return -20+c->cpdist;
825     }
826   return 0;
827   }
828 
getHauntedDepth(cell * c)829 EX int getHauntedDepth(cell *c) {
830   if((ls::single() || euclid) && c->land == laHaunted) return celldist(c);
831   if(c->land == laHaunted) return c->landparam;
832   if(c->land == laHauntedWall) return 0;
833   if(c->land == laHauntedBorder || c->land == laGraveyard) return -c->landparam;
834   return -100;
835   }
836 
towerval(cell * c,const cellfunction & cf)837 EX int towerval(cell *c, const cellfunction& cf) {
838   cell *cp1 = ts::left_of(c, cf);
839   if(!cp1) return 0;
840   int under = 0;
841   int cfc = cf(c);
842   forCellEx(c2, c) if(cf(c2) < cfc) under++;
843   return (c->type-6) + 2*(cp1->type-6) + 4*under;
844   }
845 
846 /* other geometries */
847 
setLandWeird(cell * c)848 EX void setLandWeird(cell *c) {
849   // replaced with standard CR4
850   /* if(specialland == laIvoryTower || specialland == laEndorian || specialland == laDungeon || specialland == laOcean) {
851     int d = celldist(c) - (getDistLimit() - 2);
852     if(d <= 0)
853       c->land = laCrossroads4;
854     else
855       c->land = specialland, c->landparam = d;
856     } */
857   }
858 
setLandQuotient(cell * c)859 EX void setLandQuotient(cell *c) {
860   setland(c, specialland);
861   int fv = zebra40(c);
862   if(fv/4 == 4 || fv/4 == 6 || fv/4 == 5 || fv/4 == 10) fv ^= 2;
863   if(specialland == laWarpCoast)
864     if(fv%4==0 || fv%4 == 2) setland(c, laWarpSea);
865   if(specialland == laElementalWall)
866     setland(c, eLand(laEFire + (fv%4)));
867   if(specialland == laClearing)
868     c->land = laClearing;
869   if(specialland == laIvoryTower || specialland == laEndorian || specialland == laDungeon || specialland == laOcean) {
870     int d = celldist(c) - 1;
871     if(d <= 0)
872       c->land = laCrossroads4;
873     else
874       c->land = specialland, c->landparam = d;
875     }
876   if(specialland == laWestWall) c->land = laCrossroads4;
877   }
878 
elementalXY(cell * c,int x,int y,bool make_wall)879 EX void elementalXY(cell *c, int x, int y, bool make_wall) {
880   if(x > 0 && y > 0) setland(c, laEFire);
881   else if(x > 0 && y < 0) setland(c, laEAir);
882   else if(x < 0 && y < 0) setland(c, laEWater);
883   else if(x < 0 && y > 0) setland(c, laEEarth);
884   else if(x > 0)
885     c->land = laElementalWall, c->barleft = laEAir, c->barright = laEFire;
886   else if(x < 0)
887     c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEWater;
888   else if(y > 0)
889     c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEFire;
890   else if(y < 0)
891     c->land = laElementalWall, c->barleft = laEAir, c->barright = laEWater;
892   if(x == 0 && y == 0)
893     c->land = laElementalWall, c->wall = waBarrier;
894   else if(c->land == laElementalWall && make_wall)
895     c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright);
896   }
897 
setLandSphere(cell * c)898 EX void setLandSphere(cell *c) {
899   setland(c, specialland);
900   if(specialland == laWarpCoast)
901     setland(c, getHemisphere(c, 0) > 0 ? laWarpCoast : laWarpSea);
902   if(specialland == laWestWall) c->land = laCrossroads4;
903   if(specialland == laClearing)
904     c->land = laClearing;
905   if(specialland == laElementalWall) {
906     int x = getHemisphere(c, 1);
907     int y = getHemisphere(c, 2);
908     elementalXY(c, x, y, (c->type != 6 || GOLDBERG));
909     }
910   if(!(euclid && quotient))
911   if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3 || specialland == laTerracotta) {
912     int x = getHemisphere(c, 1);
913     if(x == 0 && specialland == laTerracotta)
914       setland(c, laMercuryRiver), c->wall = waMercury;
915     else if(x == 0 || (specialland == laCrossroads3 && getHemisphere(c, 2) == 0))
916       setland(c, laBarrier), c->wall = waBarrier;
917     else setland(c, specialland);
918     if(specialland == laCrossroads3 && c->type != 6 && c->master->fiftyval == 1 && !GOLDBERG)
919       c->wall = waBigTree;
920     }
921   if(specialland == laIvoryTower || specialland == laEndorian || specialland == laDungeon || specialland == laOcean || specialland == laMountain) {
922     int d = celldist(c);
923     if(d <= 0)
924       c->land = laCrossroads4;
925     else
926       c->land = specialland, c->landparam = d;
927     }
928   }
929 
930 vector<eLand> euland;
931 map<int, eLand> euland3;
932 map<int, eLand> euland3_hash;
933 
get_euland(int c)934 EX eLand& get_euland(int c) {
935   euland.resize(max_vec);
936   return euland[c & (max_vec-1)];
937   }
938 
clear_euland(eLand first)939 EX void clear_euland(eLand first) {
940   euland.resize(max_vec);
941   for(int i=0; i<max_vec; i++) euland[i] = laNone;
942   if(!nonisotropic) euland[0] = euland[1] = euland[max_vec-1] = first;
943   euland3.clear();
944   euland3[0] = first;
945   }
946 
valid_wall_at(int c)947 bool valid_wall_at(int c) {
948   if(nonisotropic || hybri) return true;
949   return short(c) % 3 == 0;
950   }
951 
switchable(eLand nearland,eLand farland,int c)952 EX eLand switchable(eLand nearland, eLand farland, int c) {
953   if(ls::std_chaos()) {
954     if(hrand(6) == 0)
955       return getNewLand(nearland);
956     return nearland;
957     }
958   else if(ls::no_walls()) {
959     if((dual::state && nearland == laCrossroads4) || hrand(15) == 0)
960       return getNewLand(nearland);
961     if(nearland == laCrossroads4 && (nonisotropic || hybri))
962       return getNewLand(nearland);
963     return nearland;
964     }
965   else if(nearland == laCrossroads && nonisotropic) {
966     return laBarrier;
967     }
968   else if(nearland == laCrossroads) {
969     if(hrand(4) == 0 && valid_wall_at(c))
970       return laBarrier;
971     return laCrossroads;
972     }
973   else if(nearland == laBarrier) {
974     return getNewLand(farland);
975     }
976   else {
977     if(hrand(20) == 0 && valid_wall_at(c))
978       return laBarrier;
979     return nearland;
980     }
981   }
982 
getEuclidLand(int c)983 EX eLand getEuclidLand(int c) {
984   if(nonorientable && c < 0) c = -c;
985   auto& la = get_euland(c);
986   if(la) return la;
987   if(get_euland(c-2) && !get_euland(c-1)) getEuclidLand(c-1);
988   if(get_euland(c-1)) return
989     la = switchable(get_euland(c-1), get_euland(c-2), c);
990   if(get_euland(c+2) && !get_euland(c+1)) getEuclidLand(c+1);
991   if(get_euland(c+1)) return
992     la = switchable(get_euland(c+1), get_euland(c+2), c);
993   return la = laCrossroads;
994   }
995 
setLandSol(cell * c)996 EX void setLandSol(cell *c) {
997   setland(c, specialland);
998   if(ls::std_chaos()) {
999     setland(c, getEuclidLand(c->master->distance));
1000     return;
1001     }
1002   else if(ls::nice_walls()) {
1003     setland(c, getEuclidLand(c->master->distance));
1004     if(c->land == laBarrier && c->master->emeraldval % 3) c->wall = waBarrier;
1005     }
1006   switch(c->land) {
1007     case laTerracotta:
1008       if((c->master->distance & 15) == 1) {
1009         setland(c, laMercuryRiver);
1010         if(c->master->emeraldval % 3) c->wall = waMercury;
1011         }
1012       break;
1013     case laOcean: case laIvoryTower: case laEndorian: case laDungeon:
1014       if(c->master->distance <= 0) setland(c, laRlyeh);
1015       else c->landparam = c->master->distance;
1016       break;
1017     default: ;
1018     }
1019   }
1020 
setLandHybrid(cell * c)1021 EX void setLandHybrid(cell *c) {
1022   if(in_s2xe() && !among(specialland, laElementalWall)) {
1023     auto w = hybrid::get_where(c);
1024     auto d = w.second;
1025 
1026     bool ps = PIU(pseudohept(w.first));
1027     setland(c, specialland);
1028     if(ls::any_nowall()) {
1029       setland(c, getEuclidLand(d));
1030       return;
1031       }
1032     else if(ls::any_wall()) {
1033       setland(c, getEuclidLand(d));
1034       if(c->land == laBarrier) c->wall = ps ? waNone : waBarrier;
1035       }
1036     switch(c->land) {
1037       case laTerracotta:
1038         if((d & 15) == 1) {
1039           setland(c, laMercuryRiver);
1040           c->wall = ps ? waNone : waMercury;
1041           }
1042         break;
1043       case laOcean: case laIvoryTower: case laEndorian: case laDungeon:
1044         if(d < 0) setland(c, laCrossroads);
1045         else if(d == 0) {
1046           setland(c, laBarrier); c->wall = ps ? waNone : waBarrier;
1047           }
1048         else c->landparam = d;
1049         break;
1050       default: ;
1051       }
1052     return;
1053     }
1054   auto wc = hybrid::get_where(c).first;
1055   c->barleft = wc->barleft;
1056   c->barright = wc->barright;
1057   c->bardir = wc->bardir;
1058   if(wc->land) setland(c, wc->land);
1059   if(among(wc->wall, waBarrier, waMercury) || wc->land == laElementalWall)
1060     c->wall = wc->wall;
1061   }
1062 
setLandNil(cell * c)1063 EX void setLandNil(cell *c) {
1064   setland(c, specialland);
1065 
1066   if(ls::patched_chaos()) {
1067     int hash = (((c->master->zebraval + 4) >> 3) << 16) + ((c->master->emeraldval + 4) >> 3);
1068     auto& l = euland3_hash[hash];
1069     if(l == laNone) l = getNewLand(laNone);
1070     setland(c, l);
1071     return;
1072     }
1073   else if(ls::nice_walls()) {
1074     setland(c, getEuclidLand(c->master->zebraval));
1075     if(c->land == laBarrier && c->master->emeraldval % 3) c->wall = waBarrier;
1076     }
1077   else if(ls::no_walls()) {
1078     setland(c, getEuclidLand(c->master->emeraldval));
1079     if(c->land == laBarrier && c->master->zebraval % 3) c->wall = waBarrier;
1080     }
1081 
1082   switch(c->land) {
1083     case laCrossroads3: {
1084       int ox = c->master->zebraval - 8;
1085       int oy = c->master->emeraldval - 8;
1086       int hash = (((ox + 16) >> 5) << 16) + ((oy + 16) >> 5);
1087       auto& l = euland3_hash[hash];
1088       if(l == laNone) l = getNewLand(laCrossroads3);
1089       if(ox % 16 == 0) setland(c, laBarrier);
1090       else if(oy % 16 == 0) setland(c, laBarrier);
1091       else setland(c, l);
1092       if(c->land == laBarrier && ((c->master->zebraval & 3) || (c->master->emeraldval & 3))) c->wall = waBarrier;
1093       break;
1094       }
1095     case laElementalWall: {
1096       int ox = c->master->zebraval - 4;
1097       int oy = c->master->emeraldval - 4;
1098       int x = (ox & 7) ? ((ox & 8) ? 1 : -1) : 0;
1099       int y = (oy & 7) ? ((oy & 8) ? 1 : -1) : 0;
1100       elementalXY(c, x, y, (ox & 3) || (oy & 3));
1101       break;
1102       }
1103     case laTerracotta:
1104       if((c->master->zebraval & 7) == 4 && (c->master->emeraldval & 7) == 4) {
1105         setland(c, laMercuryRiver);
1106         c->wall = waMercury;
1107         }
1108       break;
1109     case laOcean: case laIvoryTower: case laEndorian: case laDungeon:
1110       if(c->master->zebraval <= 0) setland(c, laRlyeh);
1111       else c->landparam = c->master->zebraval;
1112       break;
1113     default: ;
1114     }
1115   }
1116 
setLandEuclid(cell * c)1117 EX void setLandEuclid(cell *c) {
1118   #if CAP_RACING
1119   if(racing::track_ready) {
1120     setland(c, laMemory);
1121     return;
1122     }
1123   #endif
1124   setland(c, specialland);
1125   if(ls::any_nowall()) {
1126     auto co = euc2_coordinates(c);
1127     int y = co.second;
1128     c->land = getEuclidLand(y);
1129     }
1130   if(ls::any_wall()) {
1131     auto co = euc2_coordinates(c);
1132     int x = co.first, y = co.second;
1133     setland(c, getEuclidLand(y+2*x));
1134     }
1135   if(c->land == laTerracotta) {
1136     auto co = euc2_coordinates(c);
1137     int x = co.first, y = co.second;
1138     if(((y+2*x) & 15) == 1) {
1139       setland(c, laMercuryRiver);
1140       c->wall = waMercury;
1141       }
1142     }
1143   if(specialland == laWhirlpool) {
1144     c->land = laOcean;
1145     c->landparam = 99;
1146     }
1147   if(specialland == laPrincessQuest) setland(c, laPalace);
1148   if(specialland == laOcean) {
1149     auto co = euc2_coordinates(c);
1150     int y = co.second;
1151     y += 10;
1152     if(euclid && quotient) y = -celldistAlt(c);
1153     if(y == 0)
1154       { setland(c, laBarrier); if(ishept(c)) c->land = laRlyeh; }
1155     else if(y<0) setland(c, laRlyeh);
1156     else c->landparam = y;
1157     }
1158   if(specialland == laWestWall) {
1159     auto co = euc2_coordinates(c);
1160     int x = co.first;
1161     x = -5 - x;
1162     if(x == 0)
1163       {setland(c, laBarrier); if(ishept(c)) setland(c, laMotion); }
1164     else if(x<0) setland(c, laMotion);
1165     else c->landparam = x;
1166     }
1167   if(specialland == laIvoryTower || specialland == laDungeon) {
1168     auto co = euc2_coordinates(c);
1169     int y = co.second;
1170     y = -5 - y;
1171     if(specialland == laDungeon) y = -10 - y;
1172     if(euclid && quotient) y = -celldistAlt(c);
1173     if(y == 0)
1174       {setland(c, laBarrier); if(ishept(c)) setland(c, laAlchemist); }
1175     else if(y<0) setland(c, laAlchemist);
1176     else {
1177       c->landparam = y;
1178       }
1179     }
1180   if(specialland == laElementalWall) {
1181     auto co = euc2_coordinates(c);
1182     int x = co.first, y = co.second;
1183     int x0 = euc::in(2,4) ? x : x + (y>>1);
1184     int y0 = y;
1185 
1186     int id = 0;
1187     if(y0&16) id += 2;
1188     if(x0&16) id += 1;
1189 
1190     x0 += 8; y0 += 8;
1191 
1192     y0--; x0++;
1193     int id2 = 0;
1194     if(y0&16) id2 += 2;
1195     if(x0&16) id2 += 1;
1196 
1197     setland(c, eLand(laEFire + id));
1198 
1199     if(((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) {
1200       if(c->land == laEFire) c->wall = waEternalFire;
1201       if(c->land == laEWater) c->wall = waSea;
1202       if(c->land == laEAir) c->wall = waChasm;
1203       if(c->land == laEEarth) c->wall = waStone;
1204       c->barright = c->land;
1205       c->barleft = eLand(laEFire+id2);
1206       setland(c, laElementalWall);
1207       }
1208     }
1209   if(c->land == laCrossroads3) {
1210     auto co = euc2_coordinates(c);
1211     int x = co.first, y = co.second;
1212     int y0 = euc::in(2,4) ? 2 * y - x : y;
1213     int x0 = euc::in(2,4) ? 2 * x + y : x + y/2;
1214 
1215     x0 += 24; y0 += 8;
1216 
1217     int id = 0;
1218     if(y0&16) id ^= 1;
1219     if(x0&16) id ^= 1;
1220 
1221     setland(c, id ? laCrossroads3 : laDesert);
1222 
1223     if(euc::in(2,4) ? (!(y0&15) || !(x0&15)) : ((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) {
1224       setland(c, laBarrier);
1225       c->wall = waBarrier;
1226       }
1227     }
1228   if(specialland == laWarpCoast) {
1229     auto co = euc2_coordinates(c);
1230     int x = co.first, y = co.second;
1231 
1232     int zz = a4 ? x : 2*x+y + 10;
1233     zz = gmod(zz, 30);
1234     if(zz >= 15)
1235       setland(c, laWarpSea);
1236     else
1237       setland(c, laWarpCoast);
1238     }
1239   }
1240 
get_euland3(int x)1241 EX eLand get_euland3(int x) {
1242   if(euland3.count(x)) return euland3[x];
1243   if(x > 0) return euland3[x] = getNewLand(euland3[x-1]);
1244   if(x < 0) return euland3[x] = getNewLand(euland3[x+1]);
1245   return euland3[x] = laCrossroads;
1246   }
1247 
set_euland3(cell * c,int co10,int co11,int alt,int hash)1248 EX void set_euland3(cell *c, int co10, int co11, int alt, int hash) {
1249 
1250   if(ls::std_chaos()) {
1251     setland(c, get_euland3(gdiv(co10, 60)));
1252     }
1253 
1254   else if(ls::nice_walls()) {
1255     eLand l1 = get_euland3(gdiv(co10, 360));
1256     eLand l2 = get_euland3(gdiv(co10+59, 360));
1257     if(l1 != l2 && hrand(100) < 75) setland(c, laBarrier);
1258     else setland(c, l1);
1259     }
1260 
1261   else if(ls::no_walls()) {
1262     setland(c, get_euland3(alt/4));
1263     }
1264 
1265   else if(ls::patched_chaos()) {
1266     auto& l = euland3_hash[hash];
1267     if(l == laNone) l = getNewLand(laBarrier);
1268     setland(c, l);
1269     }
1270 
1271   if(c->land == laElementalWall) {
1272     setland(c, eLand(laEFire + ((co10 / 240)&1?0:2) + ((co11 / 240)&1?0:1)));
1273     }
1274 
1275   if(c->land == laCamelot) {
1276     setland(c, laCrossroads);
1277     buildCamelot(c);
1278     }
1279 
1280   if(c->land == laTerracotta) {
1281     if(((alt&15) == 8) && hrand(100) < 90)
1282        c->wall = waMercury;
1283     }
1284 
1285   if(among(c->land, laOcean, laIvoryTower, laDungeon, laEndorian)) {
1286     if(alt == 0)
1287       c->land = laCrossroads4;
1288     else if(alt > 0)
1289       c->landparam = alt;
1290     else
1291       c->landparam = -alt;
1292     }
1293 
1294   if(c->land == laWarpCoast) {
1295     if(gmod(co10, 240) >= 120)
1296       c->land = laWarpSea;
1297     }
1298   }
1299 
1300 // the main big stuff function
1301 
1302 EX bool easy_to_find_specialland = false;
1303 
quickfind(eLand l)1304 EX bool quickfind(eLand l) {
1305   if(l == cheatdest) return true;
1306   if(l == specialland && easy_to_find_specialland) return true;
1307 #if CAP_TOUR
1308   if(tour::on && tour::quickfind(l)) return true;
1309 #endif
1310   return false;
1311   }
1312 
1313 #define INVLUCK (items[itOrbLuck] && inv::on)
1314 #define I2000 (INVLUCK?600:2000)
1315 #define I10000 (INVLUCK?3000:10000)
1316 
1317 EX hookset<int(cell*, bool)> hooks_wallchance;
1318 
wallchance(cell * c,bool deepOcean)1319 EX int wallchance(cell *c, bool deepOcean) {
1320   int i = callhandlers(-1, hooks_wallchance, c, deepOcean);
1321   if(i != -1) return i;
1322   eLand l = c->land;
1323   return
1324     inmirror(c) ? 0 :
1325     isGravityLand(l) ? 0 :
1326     generatingEquidistant ? 0 :
1327     l == laPrairie ? 0 :
1328     (yendor::on && yendor::nexttostart) ? 10000 :
1329     princess::challenge ? 0 :
1330     isElemental(l) ? 4000 :
1331     (yendor::on && (yendor::generating || !(yendor::clev().flags & YF_WALLS))) ? 0 :
1332     (S3 >= OINF && l == laCrossroads) ? 2000 :
1333     (S3 >= OINF && l == laCrossroads2) ? 2500 :
1334     (S3 >= OINF && l == laCrossroads3) ? 3333 :
1335     (S3 >= OINF && l == laCrossroads4) ? 5000 :
1336     (S3 >= OINF && l == laCrossroads5) ? 10000 :
1337     l == laCrossroads3 ? 10000 :
1338     l == laCrossroads ? 5000 :
1339     l == laCrossroads2 ? 10000 :
1340     l == laCrossroads5 ? 10000 :
1341     l == laCrossroads4 ? 5000 :
1342     (l == laMirror && !yendor::generating) ? 2500 :
1343     tactic::on ? 0 :
1344     racing::on ? 0 :
1345     l == laCaribbean ? 500 :
1346     (l == laWarpSea || l == laWarpCoast) ? 500 :
1347     l == laStorms ? 250 :
1348     l == laHaunted ? 0 :
1349     (l == laGraveyard && !deepOcean) ? 0 :
1350     // (l == laGraveyard && items[itBone] >= 10) ? 120 :
1351     l == laOcean ? (deepOcean ? (PURE ? 250 : 2000) : 0) :
1352     l == laDragon ? 120 :
1353     50;
1354   }
1355 
1356 /** \brief should we generate the horocycles in the current geometry? */
horo_ok()1357 EX bool horo_ok() {
1358   if(INVERSE) return false;
1359   if(currentmap->strict_tree_rules()) return true;
1360   return hyperbolic && !bt::in() && !arcm::in() && !kite::in() && !experimental && !hybri && !arb::in() && !quotient;
1361   }
1362 
1363 /** \brief should we either generate the horocycles in the current geometry, or have them exist via eubinary? */
horo_or_eubinary()1364 EX bool horo_or_eubinary() {
1365   return horo_ok() || eubinary;
1366   }
1367 
1368 /** \brief is celldistAlt defined for c? */
have_alt(cell * c)1369 EX bool have_alt(cell *c) {
1370   return eubinary || c->master->alt;
1371   }
1372 
1373 /** \brief generate alts around c if necessary */
gen_alt(cell * c)1374 EX void gen_alt(cell *c) {
1375   if(!eubinary) currentmap->extend_altmap(c->master);
1376   }
1377 
1378 /** \brief generate alts around c and further if necessary */
gen_alt_around(cell * c)1379 EX void gen_alt_around(cell *c) {
1380   if(!eubinary) {
1381     currentmap->extend_altmap(c->master);
1382     for(int i=0; i<c->master->type; i++)
1383       currentmap->extend_altmap(c->master->move(i));
1384     }
1385   }
1386 
1387 /** \brief is celldistAlt defined for c and c2, and greater for c? */
greater_alt(cell * c,cell * c2)1388 EX bool greater_alt(cell *c, cell *c2) {
1389   return have_alt(c) && have_alt(c2) && celldistAlt(c) > celldistAlt(c2);
1390   }
1391 
horo_gen_distance()1392 EX int horo_gen_distance() {
1393   return  (WDIM == 3 && hyperbolic) ? 1 : 2;
1394   }
1395 
single_horo(eLand horoland)1396 EX bool single_horo(eLand horoland) {
1397   return specialland == horoland && ls::single();
1398   }
1399 
in_single_horo(cell * c,eLand horoland)1400 EX bool in_single_horo(cell *c, eLand horoland) {
1401   return single_horo(horoland) || celldistAlt(c) <= 0;
1402   }
1403 
inside_starting_horo(cell * c,eLand horoland)1404 EX bool inside_starting_horo(cell *c, eLand horoland) {
1405   return specialland == horoland && celldistAlt(c) <= 0;
1406   }
1407 
extend_alt(cell * c,eLand horoland,eLand overland,bool extend_in_single IS (true),int dist IS (horo_gen_distance ()))1408 EX bool extend_alt(cell *c, eLand horoland, eLand overland, bool extend_in_single IS(true), int dist IS(horo_gen_distance())) {
1409   if(c->land != horoland && c->land != overland && !(c->land == laBrownian && overland == laOcean)) return false;
1410   if(bt::in() && !single_horo(horoland) && !inside_starting_horo(c, horoland)) return false;
1411   if(have_alt(c) && ((ls::single() && extend_in_single) || masterAlt(c) <= dist) && !(euclid && !ls::single())) {
1412     gen_alt(c);
1413     preventbarriers(c);
1414     return true;
1415     }
1416   return false;
1417   }
1418 
can_start_horo(cell * c)1419 EX bool can_start_horo(cell *c) {
1420   if(yendor::on && !among(c->land, laCaribbean, laStorms))
1421     return false;
1422   return ctof(c) && !have_alt(c) && horo_ok() && !randomPatternsMode && !racing::on;
1423   }
1424 
gp_wall_test()1425 EX bool gp_wall_test() {
1426   #if CAP_GP
1427   if(GOLDBERG) return hrand(gp::dist_3()) == 0;
1428   #endif
1429   #if CAP_IRR
1430   if(IRREGULAR) return hrand(irr::cellcount * 3) < isize(irr::cells_of_heptagon);
1431   #endif
1432   return true;
1433   }
1434 
deep_ocean_at(cell * c,cell * from)1435 EX bool deep_ocean_at(cell *c, cell *from) {
1436 
1437   if(generatingEquidistant) return false;
1438 
1439   if(c->land == laOcean) {
1440     if(!from) return true;
1441     else for(int i=0; i<from->type; i++) {
1442       cell *c2 = from->move(i);
1443       if(c2 && c2->land == laOcean && c2->landparam > 30) {
1444         return true;
1445         }
1446       if(c2) forCellEx(c3, c2) if(c3 && c3->land == laOcean && c3->landparam > 30)
1447         return true;
1448       }
1449     }
1450 
1451   if(c->land == laGraveyard) {
1452     if(!from) return true;
1453     else for(int i=0; i<from->type; i++) {
1454       cell *c2 = from->move(i);
1455       if(c2 && c2->landparam > HAUNTED_RADIUS+5)
1456         return true;
1457       if(c2) forCellEx(c3, c2) if(c3 && c3->land == laGraveyard && c3->landparam > HAUNTED_RADIUS+5)
1458         return true;
1459       }
1460     }
1461 
1462   return false;
1463   }
1464 
good_for_wall(cell * c)1465 EX bool good_for_wall(cell *c) {
1466   if(arcm::in()) return true;
1467   if(WDIM == 3) return true;
1468   if(INVERSE) return true;
1469   if(!old_nice_walls()) return true;
1470   return pseudohept(c);
1471   }
1472 
walls_not_implemented()1473 EX bool walls_not_implemented() {
1474   // if(WDIM == 3 && !PURE) return true;
1475   if(sphere || quotient || nonisotropic || (kite::in() && !bt::in()) || experimental) return true;
1476   return WDIM == 3 && (cgflags & qIDEAL);
1477   }
1478 
old_nice_walls()1479 EX bool old_nice_walls() {
1480   return (geometry == gNormal && (PURE || BITRUNCATED)) || (geometry == gEuclid && !(INVERSE | IRREGULAR));
1481   }
1482 
nice_walls_available()1483 EX bool nice_walls_available() {
1484   if(hybri) return PIU(nice_walls_available());
1485   if(fake::in()) return FPIU(nice_walls_available());
1486   return WDIM == 2;
1487   }
1488 
build_barrier_good(cell * c,eLand l IS (laNone))1489 EX void build_barrier_good(cell *c, eLand l IS(laNone)) {
1490 
1491   if(!old_nice_walls()) {
1492     general_barrier_build(NOWALLSEP_WALL, c, l ? l : getNewLand(c->land), NODIR);
1493     }
1494 
1495   else {
1496     int bd = 2 + hrand(2) * 3;
1497     buildBarrier(c, bd, l);
1498     }
1499   }
1500 
build_walls(cell * c,cell * from)1501 EX void build_walls(cell *c, cell *from) {
1502   bool deepOcean = deep_ocean_at(c, from);
1503 
1504   // if(weirdhyperbolic && c->land == laOcean) deepOcean = c->landparam >= 30;
1505 
1506   // buildgreatwalls
1507 
1508   if(hybri) return;  /* Great Walls generated via the underlying geometry */
1509 
1510   if(walls_not_implemented()) return; // walls not implemented here
1511 
1512   if(ls::chaoticity() >= 60) return;
1513 
1514   if(nice_walls_available()) {
1515     if(ctof(c) && c->land == laMirror && !yendor::generating && hrand(I10000) < 6000) {
1516       build_barrier_good(c, laMirrored);
1517       return;
1518       }
1519 
1520     if(ctof(c) && c->land == laTerracotta && hrand(I10000) < 200) {
1521       build_barrier_good(c, laTerracotta);
1522       return;
1523       }
1524 
1525     if(ctof(c) && ls::single()) {
1526       if(specialland == laCrossroads && hrand(I10000) < 5000) {
1527         build_barrier_good(c, laCrossroads);
1528         return;
1529         }
1530 
1531       if(specialland == laCrossroads3) {
1532         build_barrier_good(c, laCrossroads3);
1533         return;
1534         }
1535 
1536       if(specialland == laCrossroads5) {
1537         build_barrier_good(c, laCrossroads5);
1538         return;
1539         }
1540 
1541       if(c->land == laCrossroads && isEquidLand(specialland)) {
1542         build_barrier_good(c, specialland);
1543         return;
1544         }
1545 
1546       if(specialland == laElementalWall && hrand(I10000) < 4000) {
1547         build_barrier_good(c);
1548         return;
1549         }
1550       }
1551     }
1552   else if(good_for_wall(c) && ls::single() && specialland == laElementalWall && hrand(I10000) < 4000) {
1553     buildBarrierNowall(c, getNewLand(c->land));
1554     }
1555 
1556   if(c->land == laCrossroads2 && BITRUNCATED) {
1557     buildCrossroads2(c);
1558     return;
1559     }
1560 
1561   else if(good_for_wall(c) && isWarpedType(c->land) && hrand(10000) < 3000 && c->land &&
1562     buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) { }
1563 
1564   else if(ls::single()) return;
1565 
1566   else if(geometry == gNormal && celldist(c) < 3 && !GOLDBERG) {
1567     if(top_land && c == cwt.at->master->move(3)->c7) {
1568       buildBarrierStrong(c, 6, true, top_land);
1569       }
1570     }
1571 
1572   else if(ls::wall_chaos()) {
1573     if(good_for_wall(c) && hrand(10000) < 9000 && c->land && !inmirror(c) && c->bardir != NOBARRIERS && !c->master->alt) {
1574       build_barrier_good(c);
1575       return;
1576       }
1577     }
1578 
1579   else if(ls::std_chaos()) {
1580     if(good_for_wall(c) && hrand(10000) < 9000 && c->land && !inmirror(c) && c->bardir != NOBARRIERS && !c->master->alt && buildBarrierNowall(c, getNewLand(c->land)))
1581       return;
1582     }
1583 
1584   else if(good_for_wall(c) && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && !c->master->alt && !tactic::on && !racing::on &&
1585     buildBarrierNowall(c, getNewLand(laCrossroads4))) ;
1586 
1587   else if(good_for_wall(c) && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !racing::on && !isCrossroads(c->land) &&
1588     gold() >= R200 && !weirdhyperbolic && !c->master->alt && c->bardir != NOBARRIERS &&
1589     !inmirror(c) && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) &&
1590     (c->land != laRlyeh || rlyehComplete()) &&
1591     c->land != laTortoise && c->land != laPrairie && c->land &&
1592     !(c->land == laGraveyard && !deepOcean)
1593     && c->land != laCanvas
1594     ) {
1595     buildBarrierNowall(c, laCrossroads4) ;
1596     }
1597 
1598   else if(ls::no_walls() && hrand(I10000 /4) < wallchance(c, deepOcean) && gp_wall_test() && c->bardir != NOBARRIERS && !c->master->alt) {
1599     buildBarrierNowall(c, getNewLand(c->land));
1600     }
1601 
1602   else if(weirdhyperbolic && yendor::on && yendor::nexttostart) {
1603     if(buildBarrierNowall(c, yendor::nexttostart))
1604       yendor::nexttostart = laNone;
1605     }
1606 
1607   else if(weirdhyperbolic && specialland == laElementalWall && hrand(I10000) < 1000 && gp_wall_test())
1608     buildBarrierNowall(c, getNewLand(c->land));
1609 
1610   else if(S3 >= OINF && c->land && hrand(I10000) < wallchance(c, deepOcean) && c->bardir != NOBARRIERS)
1611     buildBarrierNowall(c, getNewLand(c->land));
1612 
1613   else if(!nice_walls_available()) ; // non-Nowall barriers not implemented yet in weird hyperbolic
1614 
1615   #if CAP_FIELD
1616   else if(c->land == laPrairie && c->LHU.fi.walldist == 0 && !euclid) {
1617     if(ls::nice_walls())
1618     for(int bd=0; bd<c->master->type; bd++) {
1619       int fval2 = createStep(c->master, bd)->fieldval;
1620       int wd = currfp_gmul(fval2, currfp_inverses(c->fval-1));
1621       if(currfp_distwall(wd) == 0) {
1622         buildBarrier(c, bd);
1623         break;
1624         }
1625       }
1626     if(ls::no_walls()) {
1627       buildBarrierNowall(c, getNewLand(c->land));
1628       }
1629     }
1630   #endif
1631 
1632   else if(good_for_wall(c) && c->land && ls::nice_walls() && c->land != laCrossroads4 && hrand(I10000) < wallchance(c, deepOcean))
1633     build_barrier_good(c);
1634   }
1635 
start_camelot(cell * c)1636 EX void start_camelot(cell *c) {
1637   int rtr = newRoundTableRadius();
1638   heptagon *alt = create_altmap(c, ls::single() ? 2 : rtr+(hyperbolic && WDIM == 3 ? 11 : 14), ls::single() ? hsA : hsOrigin);
1639   if(alt) {
1640     altmap::radius(alt) = rtr;
1641     altmap::orig_land(alt) = c->land;
1642     }
1643   }
1644 
build_horocycles(cell * c,cell * from)1645 EX void build_horocycles(cell *c, cell *from) {
1646 
1647   bool deepOcean = deep_ocean_at(c, from);
1648 
1649   if(!ls::any_order() && !ls::single()) return;
1650 
1651   if(ls::single() && !among(specialland, laTemple, laMountain, laClearing, laStorms, laWhirlpool, laCaribbean, laCanvas, laPalace, laPrincessQuest, laCamelot))
1652     return;
1653 
1654   // buildbigstuff
1655 
1656   if(ls::any_order() && bearsCamelot(c->land) && can_start_horo(c) && !bt::in() &&
1657     #if MAXMDIM >= 4
1658     !(hyperbolic && WDIM == 3 && !reg3::in_rule()) &&
1659     #endif
1660     (quickfind(laCamelot) || peace::on || (hrand(I2000) < (c->land == laCrossroads4 || ls::no_walls() ? 800 : 200) && horo_ok() &&
1661     items[itEmerald] >= U5)))
1662     start_camelot(c);
1663 
1664   if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && items[itStatue] >= U5)))
1665     create_altmap(c, horo_gen_distance(), hsA);
1666 
1667   if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlocked(laMountain))))
1668     create_altmap(c, horo_gen_distance(), hsA);
1669 
1670   if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && items[itMutant] >= U5 && isLandIngame(laClearing)))) {
1671     heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
1672     if(h) clearing::bpdata[h].root = NULL;
1673     }
1674 
1675   if(stdhyperbolic && c->land == laStorms && can_start_horo(c) && hrand(2000) < 1000) {
1676     heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
1677     if(h) altmap::which(h->alt) = hrand(2);
1678     }
1679 
1680   if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) &&
1681     (quickfind(laWhirlpool) || (
1682       hrand(2000) < (PURE ? 500 : 1000))))
1683     create_altmap(c, horo_gen_distance(), hsA);
1684 
1685   #if CAP_COMPLEX2
1686   if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety)
1687     brownian::init_further(c);
1688   #endif
1689 
1690   if(c->land == laCaribbean && can_start_horo(c))
1691     create_altmap(c, horo_gen_distance(), hsA);
1692 
1693   if(c->land == laCanvas && can_start_horo(c) && ls::any_order())
1694     create_altmap(c, horo_gen_distance(), hsA);
1695 
1696   if(c->land == laPalace && can_start_horo(c) && !princess::generating && !shmup::on && multi::players == 1 && !weirdhyperbolic &&
1697     (princess::forceMouse ? canReachPlayer(from, moMouse) :
1698       (hrand(2000) < (peace::on ? 100 : 20))) &&
1699     (princess::challenge || kills[moVizier] || peace::on)) {
1700     create_altmap(c, PRADIUS0, hsOrigin, waPalace);
1701     celllister cl(c, 5, 1000000, NULL);
1702     for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master);
1703     }
1704   }
1705 
buildBigStuff(cell * c,cell * from)1706 EX void buildBigStuff(cell *c, cell *from) {
1707   build_walls(c, from);
1708 
1709   build_horocycles(c, from);
1710 
1711   if(hasbardir(c)) extendBarrier(c);
1712   }
1713 
openplains(cell * c)1714 EX bool openplains(cell *c) {
1715   if(ls::any_chaos()) {
1716     forCellEx(c2, c) if(c2->land != laHunting) return false;
1717     return true;
1718     }
1719   int dlimit = getDistLimit();
1720   if(arcm::in()) dlimit--;
1721   if(dlimit < 7) {
1722     celllister cl(c, dlimit, 1000000, NULL);
1723     int bad = 0;
1724     for(cell *c: cl.lst) {
1725       while(c->mpdist > 8) setdist(c, c->mpdist-1, NULL);
1726       if(c->land != laHunting) {bad++; if(bad>5) return false;}
1727       }
1728     return true;
1729     }
1730   else {
1731     celllister cl(c, dlimit, 1000000, NULL);
1732     for(cell *c: cl.lst) {
1733       while(c->mpdist > 8) setdist(c, c->mpdist-1, NULL);
1734       if(c->land != laHunting) return false;
1735       }
1736     return true;
1737     }
1738   }
1739 
buildCamelotWall(cell * c)1740 EX void buildCamelotWall(cell *c) {
1741   if(S3 >= OINF) { c->wall = waRubble; return; }
1742   if(WDIM == 3 && hyperbolic && c->master->fieldval == 0) return;
1743   c->wall = waCamelot;
1744   if(WDIM == 3 && hyperbolic) return;
1745   for(int i=0; i<c->type; i++) {
1746     cell *c2 = createMov(c, i);
1747     if(c2->wall == waNone && greater_alt(c2, c) && c2->monst == moNone)
1748       c2->wall = waCamelotMoat;
1749     }
1750   }
1751 
no_barriers_in_radius(cell * c,int rad)1752 EX bool no_barriers_in_radius(cell *c, int rad) {
1753   celllister cl(c, 2, 1000000, NULL);
1754   for(cell *c: cl.lst) if(c->bardir != NODIR) return false;
1755   return true;
1756   }
1757 
camelot_monster()1758 EX eMonster camelot_monster() {
1759   eMonster ms[3] = { moHedge, moLancer, moFlailer };
1760   eMonster m = ms[hrand(3)];
1761   if(m == moHedge && valence() > 3)
1762     m = moPyroCultist;
1763   if(getDistLimit() <= 2 && m == moLancer) m = moGoblin;
1764   if(getDistLimit() <= 3 && m == moPyroCultist) m = moCultist;
1765   return m;
1766   }
1767 
buildCamelot(cell * c)1768 EX void buildCamelot(cell *c) {
1769   int d = celldistAltRelative(c);
1770   if(ls::single() || (d <= 14 && roundTableRadius(c) > 20)) {
1771     gen_alt(c);
1772     preventbarriers(c);
1773     if(d == 10) {
1774       if(weirdhyperbolic ? hrand(100) < 50 : pseudohept(c)) buildCamelotWall(c);
1775       else {
1776         if(!eubinary) for(int i=0; i<c->master->type; i++) currentmap->extend_altmap(c->master->move(i));
1777         int q = 0;
1778         if(weirdhyperbolic) {
1779           for(int t=0; t<c->type; t++) createMov(c, t);
1780           q = hrand(100);
1781           if(q < 10) q = 0;
1782           else if(q < 50) q = 1;
1783           }
1784         else {
1785           for(int t=0; t<c->type; t++) {
1786             createMov(c, t);
1787             if(celldistAltRelative(c->move(t)) == 10 && !pseudohept(c->move(t))) q++;
1788             }
1789           }
1790         if(q == 1) buildCamelotWall(c);
1791         // towers of Camelot
1792         if(q == 0 && BITRUNCATED) {
1793           c->monst = moKnight;
1794           c->wall = waTower;
1795           forCellEx(c2, c) {
1796             int cr = celldistAltRelative(c2);
1797             if(cr == 9) ;
1798             else {
1799               buildCamelotWall(c2);
1800               if(!ctof(c2))
1801                 c2->wall = waTower, c2->wparam = 1;
1802               }
1803             }
1804           for(int i=0; i<c->type; i++) if(celldistAltRelative(c->move(i)) < d)
1805             c->mondir = i;
1806           }
1807         }
1808       }
1809     if(d == 0) c->wall = waRoundTable;
1810     if(celldistAlt(c) == 0 && !ls::single()) c->item = itHolyGrail;
1811     if(d < 0 && hrand(7000) <= 10 + items[itHolyGrail] * 5)
1812       c->monst = camelot_monster();
1813     if(d == 1) {
1814       // roughly as many knights as table cells
1815       if(hrand(1000000) < 1000000 / expansion.get_growth() && !reptilecheat)
1816         c->monst = moKnight;
1817       if(!eubinary) for(int i=0; i<c->master->type; i++) currentmap->extend_altmap(c->master->move(i));
1818       for(int i=0; i<c->type; i++)
1819         if(c->move(i) && celldistAltRelative(c->move(i)) < d)
1820           c->mondir = (i+3) % 6;
1821       }
1822     if(ls::single() && d >= 2 && d <= 8 && hrand(1000) < 10)
1823       c->item = itOrbSafety;
1824     if(d == 5 && ls::single())
1825       c->item = itGreenStone;
1826     if(d <= 10) c->land = laCamelot;
1827     if(d > 10 && !eubinary && !ls::single()) {
1828       setland(c, eLand(altmap::orig_land(c->master->alt->alt)));
1829       if(c->land == laNone) printf("Camelot\n"); // NONEDEBUG
1830       }
1831     }
1832   }
1833 
masterAlt(cell * c)1834 EX int masterAlt(cell *c) {
1835   if(eubinary) return celldistAlt(c);
1836   #if MAXMDIM >= 4
1837   if(WDIM == 3 && hyperbolic && !reg3::in_rule()) return reg3::altdist(c->master);
1838   #endif
1839   return c->master->alt->distance;
1840   }
1841 
1842 /** the distance between two layers of Temple of Cthulhu */
temple_layer_size()1843 EX int temple_layer_size() {
1844   if(among(geometry, gHoroRec, gHoroHex, gKiteDart3)) return 3;
1845   if(sol) return 6;
1846   if(WDIM == 3 && bt::in()) return 2;
1847   if(among(geometry, gSpace435, gSpace535)) return 5;
1848   if(WDIM == 3 && hyperbolic) return 3;
1849   if(S3 == OINF) return 4;
1850   return 6;
1851   }
1852 
1853 /** generate the (non-chaotic) Temple of Cthulhu */
gen_temple(cell * c)1854 EX void gen_temple(cell *c) {
1855   int d = celldistAlt(c);
1856   if(d <= 0) {
1857     c->land = laTemple, c->wall = waNone, c->monst = moNone, c->item = itNone;
1858     }
1859   if(d % temple_layer_size()==0) {
1860     c->landparam = 0;
1861     if(geometry == gSpace534) {
1862       int i = 0;
1863       forCellCM(c2, c) if(greater_alt(c, c2)) i++;
1864       if(i > 1) c->wall = waColumn;
1865       }
1866     else if(geometry == gSpace535) {
1867       c->wall = (c->master->fieldval % 5) ? waRubble : waColumn;
1868       }
1869     else if(geometry == gSpace435) {
1870       c->wall = waRubble;
1871       if(c->master->fieldval == 0) c->wall = waColumn;
1872       forCellCM(c1, c) if(c1->master->fieldval == 0) c->wall = waColumn;
1873       }
1874     else if(sol) {
1875       if(c->master->emeraldval % 3 || c->master->zebraval % 3)
1876         c->wall = waColumn;
1877       }
1878     else if(nih) {
1879       if(c->master->emeraldval % 2)
1880         c->wall = waColumn;
1881       }
1882     #if CAP_BT
1883     else if(geometry == gBinary3) {
1884       if(c->master->zebraval % 5 != 1) c->wall = waColumn;
1885       }
1886     else if(geometry == gHoroTris || geometry == gHoroRec) {
1887       if(c->c.spin(bt::updir()) != 0) c->wall = waColumn;
1888       }
1889     else if(geometry == gKiteDart3) {
1890       if(kite::getshape(c->master) == kite::pKite) c->wall = waColumn;
1891       }
1892     #endif
1893     else if(in_s2xe()) {
1894       auto d = hybrid::get_where(c);
1895       if(!PIU(pseudohept(d.first))) c->wall = waColumn;
1896       }
1897     else if(hybri) {
1898       auto d = hybrid::get_where(c);
1899       if(d.first->wall == waColumn || (d.second&1)) c->wall = waColumn;
1900       }
1901     else if(WDIM == 3) {
1902       c->wall = hrand(100) < 10 ? waColumn : waRubble;
1903       }
1904     else if(S3 >= OINF) { }
1905     else if(weirdhyperbolic && !BITRUNCATED) {
1906       if(hrand(100) < 50) c->wall = waColumn;
1907       }
1908     else if(pseudohept(c))
1909       c->wall = waColumn;
1910     else {
1911       gen_alt_around(c);
1912       int q = 0;
1913       for(int t=0; t<c->type; t++) {
1914         createMov(c, t);
1915         if(have_alt(c->move(t)) && celldistAlt(c->move(t)) % temple_layer_size() == 0 && !ishept(c->move(t))) q++;
1916         }
1917       if(q == 2) c->wall = waColumn;
1918       }
1919     c->landparam = 1;
1920     }
1921   else c->landparam = 2;
1922   }
1923 
moreBigStuff(cell * c)1924 EX void moreBigStuff(cell *c) {
1925 
1926   if((bearsCamelot(c->land) && !euclid && !quotient && !nil) || c->land == laCamelot)
1927   if(have_alt(c)) if(!(bt::in() && specialland != laCamelot))
1928     buildCamelot(c);
1929 
1930   if(quotient) return;
1931 
1932   extend_alt(c, laCaribbean, laCaribbean, false);
1933   if(c->land == laCaribbean) {
1934     if(have_alt(c) && celldistAlt(c) <= 0)
1935       generateTreasureIsland(c);
1936     else
1937       c->wall = waSea;
1938     }
1939 
1940   extend_alt(c, laPalace, laPalace, false, PRADIUS1);
1941 
1942   extend_alt(c, laCanvas, laCanvas);
1943 
1944   if(extend_alt(c, laStorms, laStorms, false)) {
1945     int d = celldistAlt(c);
1946     if(d <= -2) {
1947       c->wall = eubinary ? waCharged : (altmap::which(c->master->alt->alt) & 1) ? waCharged : waGrounded;
1948       c->item = itNone;
1949       c->monst = moNone;
1950       }
1951     else if(d <= -1)
1952       c->wall = (hrand(100) < 20) ? waSandstone : waNone;
1953     else if(d <= 0)
1954       c->wall = waNone;
1955     }
1956 
1957   if(ls::any_chaos() && c->land == laTemple) {
1958     for(int i=0; i<c->type; i++)
1959       if(pseudohept(c) && c->move(i) && c->move(i)->land != laTemple)
1960         c->wall = waColumn;
1961     }
1962 
1963   else if(extend_alt(c, laTemple, laRlyeh))
1964     gen_temple(c);
1965 
1966   if(extend_alt(c, laClearing, laOvergrown)) {
1967     if(in_single_horo(c, laClearing)) {
1968       c->land = laClearing, c->wall = waNone;
1969       }
1970     else if(celldistAlt(c) == 1)
1971       c->wall = waSmallTree, c->monst = moNone, c->item = itNone, c->landparam = 1;
1972     }
1973 
1974   if(extend_alt(c, laMountain, laJungle) && in_single_horo(c, laMountain)) {
1975     c->land = laMountain, c->wall = waNone;
1976     }
1977 
1978   if(extend_alt(c, laWhirlpool, laOcean) && in_single_horo(c, laWhirlpool))
1979     c->land = laWhirlpool, c->wall = waSea, c->monst = moNone, c->item = itNone;
1980   }
1981 
generate_mines()1982 EX void generate_mines() {
1983   vector<cell*> candidates;
1984 
1985   if(bounded)
1986     for(cell *c: currentmap->allcells())
1987       setdist(c, 7, nullptr);
1988 
1989   for(cell *c: currentmap->allcells())
1990     if(c->wall == waMineUnknown)
1991       candidates.push_back(c);
1992   hrandom_shuffle(candidates);
1993   bounded_mine_max = isize(candidates);
1994   bounded_mine_quantity = int(bounded_mine_max * bounded_mine_percentage + 0.5);
1995   for(int i=0; i<bounded_mine_quantity; i++) candidates[i]->wall = waMineMine;
1996   }
1997 
1998 EX vector<eLand> currentlands;
1999 
pregen()2000 EX void pregen() {
2001   currentlands.clear();
2002   if(ls::any_chaos() && !ls::std_chaos())
2003     for(eLand l: land_over)
2004       if(landUnlocked(l) && isLandIngame(l))
2005         currentlands.push_back(l);
2006   }
2007 
__anon0fc44f570102(gamedata* gd) 2008 auto ccm_bigstuff = addHook(hooks_gamedata, 0, [] (gamedata* gd) {
2009   gd->store(euland);
2010   gd->store(euland3);
2011   gd->store(euland3_hash);
2012   });
2013 
2014 }
2015