1 // Hyperbolic Rogue -- Barriers
2 // Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
3
4 /** \file barriers.cpp
5 * \brief This file implements routines related to barriers (Great Walls and similar).
6 */
7
8 #include "hyper.h"
9 namespace hr {
10
11 EX bool checkBarriersFront(cellwalker bb, int q IS(5), bool cross IS(false)) {
12
13 if(!ctof(bb.at))
14 return false;
15
16 if(bb.at->mpdist < BARLEV) return false;
17 if(bb.at->mpdist == BUGLEV) return false;
18 if(bb.at->bardir != NODIR) return false;
19 if(bb.spin == (PURE ? 3 : 0)) {q--; if(!q) return true; }
20
21 if(!cross) for(int i=0; i<7; i++) {
22 cellwalker bb2 = bb + i + wstep;
23 if(bb2.at->bardir != NODIR) return false;
24 if(!PURE) {
25 bb2 = bb2 + 4 + wstep;
26 if(bb2.at->bardir != NODIR) return false;
27 }
28 }
29
30 bb += wstep;
31 if(!PURE) { bb = bb + 3 + wstep + 3 + wstep; }
32 return checkBarriersBack(bb, q);
33 }
34
35 /** return true if the cell c is not allowed to generate barriers because of other large things already existing nearby. */
hasbardir(cell * c)36 EX bool hasbardir(cell *c) {
37 return c->bardir != NODIR && c->bardir != NOBARRIERS;
38 }
39
preventbarriers(cell * c)40 EX void preventbarriers(cell *c) {
41 if(hybri) c = hybrid::get_where(c).first;
42 if(c && c->bardir == NODIR) c->bardir = NOBARRIERS;
43 }
44
45 EX bool checkBarriersBack(cellwalker bb, int q IS(5), bool cross IS(false)) {
46 // printf("back, %p, s%d\n", hr::voidp(bb.at), bb.spin);
47
48 // if(mark) { printf("mpdist = %d [%d] bardir = %d spin=%d q=%d cross=%d\n", bb.at->mpdist, BARLEV, bb.at->bardir, bb.spin, q, cross); }
49
50 if(bb.at->mpdist < BARLEV) return false;
51 if(bb.at->mpdist == BUGLEV) return false;
52 if(bb.at->bardir != NODIR) return false;
53
54 // if(bb.spin == 0 && bb.at->mpdist == INFD) return true;
55
56 if(!cross) for(int i=0; i<7; i++) {
57 cellwalker bb2 = bb + i + wstep;
58 if(bb2.at->bardir != NODIR) return false;
59 if(!PURE) {
60 bb2 = bb2 + 4 + wstep;
61 if(bb2.at->bardir != NODIR) return false;
62 }
63 }
64
65 bb = bb + 3 + wstep + (PURE ? 5 : 4) + wstep + 3;
66 return checkBarriersFront(bb, q);
67 }
68
69 /** warp coasts use a different algorithm for nowall barriers when has_nice_dual() is on. Check whether we should use this different algorithm when the lands are l1 and l2 */
warped_version(eLand l1,eLand l2)70 EX bool warped_version(eLand l1, eLand l2) {
71 return (has_nice_dual() && (l1 == laWarpCoast || l1 == laWarpSea || l2 == laWarpSea || l2 == laWarpCoast));
72 }
73
get_valence(cellwalker bb,int dir,bool & ok)74 EX int get_valence(cellwalker bb, int dir, bool& ok) {
75 int steps = 0;
76 cellwalker bb1 = bb;
77 while(bb1 != bb || !steps) {
78 bb1 += dir;
79 bb1 += wstep;
80 steps++;
81 }
82 return steps;
83 }
84
set_and_wall(cell * c,eLand l)85 EX void set_and_wall(cell *c, eLand l) {
86 setland(c, l);
87 if(c->bardir == NODIR) {
88 c->barleft = NOWALLSEP_USED;
89 c->bardir = NOBARRIERS;
90 }
91 }
92
surround_by(bool setit,cellwalker bb,int dir,int a,int b,eLand which,bool swapped,bool & ok)93 EX void surround_by(bool setit, cellwalker bb, int dir, int a, int b, eLand which, bool swapped, bool& ok) {
94 for(int i=0; i<a; i++) {
95 bb += dir;
96 bb += wstep;
97 }
98 for(int i=a; i<b; i++) {
99 if(setit) set_and_wall(bb.at, which);
100 else {
101 if(bb.at->bardir != NODIR) ok = false;
102 if(swapped && bb.at->mpdist < BARLEV) ok = false;
103 }
104 bb += dir;
105 bb += wstep;
106 }
107 }
108
spin_around_by(cellwalker & bb,int dir,int q)109 EX void spin_around_by(cellwalker& bb, int dir, int q) {
110 for(int i=0; i<q; i++) {
111 bb += dir;
112 bb += wstep;
113 }
114 }
115
on_wall(eLand ws)116 EX bool on_wall(eLand ws) {
117 return among(ws, NOWALLSEP_WALL_CPOS, NOWALLSEP_WALL_CNEG, NOWALLSEP_WALL_EPOS, NOWALLSEP_WALL_ENEG);
118 }
119
wsname(eLand ws)120 string wsname(eLand ws) {
121 if(ws == NOWALLSEP) return "NO";
122 if(ws == NOWALLSEP_SWAP) return "SWAP";
123 if(ws == NOWALLSEP_USED) return "USED";
124 if(ws == NOWALLSEP_WALL) return "WALL";
125 if(ws == NOWALLSEP_WALL_CPOS) return "CPOS";
126 if(ws == NOWALLSEP_WALL_CNEG) return "CNEG";
127 if(ws == NOWALLSEP_WALL_EPOS) return "EPOS";
128 if(ws == NOWALLSEP_WALL_ENEG) return "ENEG";
129 return dnameof(ws);
130 }
131
general_barrier_advance(cellwalker & bb,int & dir,eLand & l1,eLand & l2,eLand & ws,bool setit)132 EX bool general_barrier_advance(cellwalker& bb, int& dir, eLand& l1, eLand& l2, eLand& ws, bool setit) {
133 bool ok = true;
134 if(ws == NOWALLSEP_WALL) {
135
136
137 /*
138 if(setit) bb.at->monst = moBug0;
139 if(setit) bb.cpeek()->monst = moBug2;
140 */
141
142 int steps = get_valence(bb, dir, ok);
143 if(steps % 2 == 0) goto again;
144
145 int s = (steps - 1) / 2;
146 surround_by(setit, bb, dir, 1, s, l1, false, ok);
147 surround_by(setit, bb, dir, s+1, steps-1, l2, true, ok);
148 spin_around_by(bb, dir, s);
149
150 ws = dir > 0 ? NOWALLSEP_WALL_CPOS : NOWALLSEP_WALL_CNEG;
151 // goto tile;
152 return ok;
153 }
154
155 if(on_wall(ws)) {
156
157 bool at_corner = among(ws, NOWALLSEP_WALL_CPOS, NOWALLSEP_WALL_CNEG);
158
159 cell *current = bb.at;
160
161 // if at_corner: bb is facing the tile 1 before the first inside
162 int t = bb.at->type;
163
164 int q = at_corner ? t/2 : (t-1) / 2;
165
166 if(1) {
167 auto bb1 = bb;
168 if(at_corner) bb1 += dir;
169 bb1 -= dir;
170 for(int i=1; i<q; i++) {
171 int d = get_valence(bb1, -dir, ok);
172 surround_by(setit, bb1, -dir, 1, d, l1, false, ok);
173 bb1-=dir;
174 }
175 }
176
177 bb += dir;
178 for(int i=1; i<q; i++) {
179 int d = get_valence(bb, dir, ok);
180 surround_by(setit, bb, dir, 1, d, l2, true, ok);
181 bb+=dir;
182 }
183
184 // bb is now facing the last neighbor inside
185
186 if(t % 2 == (at_corner ? 1 : 0)) {
187 if(setit) setbarrier(current, l1, l2, at_corner);
188 int d = get_valence(bb, dir, ok);
189 surround_by(setit, bb, dir, 2, d, l2, true, ok);
190
191 bb += dir;
192 bb += wstep;
193
194 d = get_valence(bb, -dir, ok);
195 surround_by(setit, bb, -dir, 2, d-1, l1, false, ok);
196
197 ws = dir > 0 ? NOWALLSEP_WALL_EPOS : NOWALLSEP_WALL_ENEG;
198 return ok;
199 }
200
201 int steps1 = get_valence(bb, dir, ok);
202 if(setit) setbarrier(current, l1, l2, true);
203
204 if(steps1 % 2 == 0) {
205 int s1 = steps1 / 2;
206 surround_by(setit, bb, dir, 1, s1, l1, false, ok);
207 surround_by(setit, bb, dir, s1+1, steps1-1, l2, true, ok);
208 spin_around_by(bb, dir, s1);
209 ws = dir > 0 ? NOWALLSEP_WALL_CPOS : NOWALLSEP_WALL_CNEG;
210 return ok;
211 }
212
213 int s1 = (steps1 - 1) / 2;
214 surround_by(setit, bb, dir, 1, s1, l1, false, ok);
215 surround_by(setit, bb, dir, s1+2, steps1-1, l2, true, ok);
216 spin_around_by(bb, dir, s1);
217 bb += dir;
218 ws = NOWALLSEP_WALL;
219 }
220 else if(warped_version(l1, l2)) {
221 bb = bb + wstep + (2*dir) + wstep + dir;
222 dir = -dir;
223 swap(l1, l2);
224 }
225 else {
226 again:
227 cellwalker bb1 = bb;
228 int steps = get_valence(bb, dir, ok);
229 int s = 2;
230 if(ws == NOWALLSEP_SWAP) s = 5 - s;
231 if(dir == -1) s = 5 - s;
232 s = (1 + steps - s) / 2;
233 surround_by(setit, bb, dir, 1, s, l1, false, ok);
234 surround_by(setit, bb, dir, s+2, steps-1, l2, true, ok);
235 spin_around_by(bb, dir, s);
236 bb += dir;
237 if(steps & 1) ws = (ws == NOWALLSEP ? NOWALLSEP_SWAP : NOWALLSEP);
238 if(bb.at == bb1.at) goto again;
239 }
240 return ok;
241 }
242
general_barrier_check(cellwalker bb,int q,int dir,eLand ws,eLand l1 IS (laNone),eLand l2 IS (laNone))243 EX bool general_barrier_check(cellwalker bb, int q, int dir, eLand ws, eLand l1 IS(laNone), eLand l2 IS(laNone)) {
244
245 if(l1 == l2) {
246 if(bb.at->mpdist < BARLEV || bb.cpeek()->mpdist < BARLEV || bb.cpeek()->bardir != NODIR || bb.at->bardir != NODIR)
247 return false;
248 for(int i=0; i<bb.at->type; i++) {
249 cell *c1 = bb.at->move(i);
250 if(!c1) continue;
251 if(c1->bardir != NODIR) return false;
252 }
253 }
254
255 if(l1 != l2 && bb.at->barleft != NOWALLSEP_USED) {
256 bb.at->bardir = bb.spin; bb.at->barright = l2; bb.at->barleft = ws;
257 setland(bb.at, l1);
258 }
259 if(q <= 0) return true;
260
261 bool b = general_barrier_advance(bb, dir, l1, l2, ws, l1 != l2);
262 if(l1 == l2 && !b) return false;
263 return general_barrier_check(bb, q-1, dir, ws, l1, l2);
264 }
265
general_barrier_check_after(cellwalker bb,int steps,int q,int dir,eLand ws,eLand l1 IS (laNone),eLand l2 IS (laNone))266 EX bool general_barrier_check_after(cellwalker bb, int steps, int q, int dir, eLand ws, eLand l1 IS(laNone), eLand l2 IS(laNone)) {
267 for(int i=0; i<steps; i++) general_barrier_advance(bb, dir, l1, l2, ws, l1 != l2);
268 return general_barrier_check(bb, q, dir, ws, l1, l2);
269 }
270
getElementalWall(eLand l)271 EX eWall getElementalWall(eLand l) {
272 if(l == laEAir) return waChasm;
273 if(l == laEEarth) return waStone;
274 if(l == laEFire) return waEternalFire;
275 if(l == laEWater) return waSea;
276 return waNone;
277 }
278
setbarrier(cell * c,eLand l1,eLand l2,bool setbar)279 EX void setbarrier(cell *c, eLand l1, eLand l2, bool setbar) {
280 if(isSealand(l1) && isSealand(l2)) {
281 if(l1 == laKraken || l2 == laKraken)
282 if(l1 != laWarpSea && l2 != laWarpSea)
283 setbar = !setbar;
284 c->wall = setbar ? waBarrier : waSea;
285 c->land = laOceanWall;
286 }
287 else if(isElemental(l1) && isElemental(l2)) {
288 c->land = laElementalWall;
289 c->wall = getElementalWall(l1);
290 }
291 else if(l1 == laHaunted || l2 == laHaunted) {
292 c->land = laHauntedWall;
293 }
294 else if(l1 == laMirrored2 || l2 == laMirrored2)
295 c->land = laMirrorWall2;
296 else if(l1 == laMirrored || l2 == laMirrored)
297 c->land = laMirrorWall;
298 else if(l1 == laTerracotta && l2 == laTerracotta) {
299 c->land = laMercuryRiver;
300 c->wall = waMercury;
301 }
302 else {
303 c->wall = waBarrier;
304 c->land = laBarrier;
305 }
306 }
307
setbarrier(cell * c)308 EX void setbarrier(cell *c) {
309 setbarrier(c, c->barleft, c->barright, ctof(c));
310 }
311
setland(cell * c,eLand l)312 EX void setland(cell *c, eLand l) {
313 if(c->land != l) {
314 c->landparam = 0;
315 }
316 if(l == laNone) {
317 printf("setland\n"); // NONEDEBUG
318 }
319 c->land = l;
320 }
321
extendcheck(cell * c)322 EX void extendcheck(cell *c) {
323 return;
324 if(BITRUNCATED && c->landparam == 0 && c->barleft != NOWALLSEP) {
325 raiseBuggyGeneration(c, "extend error");
326 }
327 }
328
mirrorwall(cell * c)329 EX bool mirrorwall(cell *c) {
330 return c->barleft == laMirrored || c->barright == laMirrored;
331 }
332
extendBarrierFront(cell * c)333 EX void extendBarrierFront(cell *c) {
334 limitgen("extend front %p\n", hr::voidp(c));
335 if(buggyGeneration) return;
336 int ht = c->landparam;
337 extendcheck(c);
338
339 cellwalker bb(c, c->bardir); setbarrier(bb.at);
340 bb += wstep;
341
342 if(BITRUNCATED) {
343 bb.at->barleft = c->barleft;
344 bb.at->barright = c->barright;
345 setbarrier(bb.at);
346 if(!mirrorwall(bb.at))
347 bb.at->landparam = (ht-4);
348 //printf("[A heat %d]\n", ht-4);
349
350 setland((bb + 2).cpeek(), c->barleft);
351 setland((bb + 4).cpeek(), c->barright);
352
353 bb = bb + 3 + wstep;
354 bb.at->barleft = c->barright;
355 bb.at->barright = c->barleft;
356 setbarrier(bb.at);
357 if(!mirrorwall(bb.at))
358 bb.at->landparam = (ht-4)^2;
359 //printf("[B heat %d]\n", (ht-4)^2);
360
361 bb = bb + 3 + wstep;
362
363 bb.at->barleft = c->barleft;
364 bb.at->barright = c->barright;
365 if(!mirrorwall(bb.at))
366 bb.at->landparam = ht ^ 2;
367 }
368
369 //printf("[C heat %d]\n", (ht)^2);
370 bb.at->bardir = bb.spin;
371 bb.at->barleft = c->barright;
372 bb.at->barright = c->barleft;
373 // printf("#1\n");
374 extendcheck(bb.at);
375 extendBarrier(bb.at);
376
377 for(int a=-3; a<=3; a++) if(a) {
378 bb.at = c; bb.spin = c->bardir; bb += (PURE?-a:a); bb += wstep;
379 setland(bb.at, a > 0 ? c->barright : c->barleft);
380 }
381 }
382
extendBarrierBack(cell * c)383 EX void extendBarrierBack(cell *c) {
384 limitgen("extend back %p\n", hr::voidp(c));
385 if(buggyGeneration) return;
386 int ht = c->landparam;
387 extendcheck(c);
388
389 cellwalker bb(c, c->bardir); setbarrier(bb.at);
390 bb = bb + 3 + wstep + (PURE?5:4);
391 setland(bb.at, PURE ? c->barleft : c->barright);
392 bb = bb + wstep + 3;
393 bb.at->bardir = bb.spin;
394 bb.at->barleft = c->barright;
395 bb.at->barright = c->barleft;
396 if(!mirrorwall(bb.at))
397 bb.at->landparam = ht ^ 11;
398 extendcheck(bb.at);
399 //printf("[D heat %d]\n", (ht^11));
400
401 // needed for CR2 to work
402 if(BITRUNCATED) {
403 auto bb2 = bb + wstep;
404 bb2.at->barleft = c->barright;
405 bb2.at->barright = c->barleft;
406 if(!mirrorwall(bb2.at))
407 bb2.at->landparam = (ht^11)-4;
408 }
409 //printf("[E heat %d]\n", (ht^11));
410
411 // printf("#2\n");
412 extendBarrier(bb.at);
413 }
414
general_barrier_extend(cell * c)415 EX void general_barrier_extend(cell *c) {
416
417 eLand ws = c->barleft;
418 cellwalker cw(c, c->bardir);
419
420 c->barleft = NOWALLSEP_USED;
421 eLand l1 = c->land;
422 eLand l2 = c->barright;
423
424 if(!on_wall(ws)) {
425 if(c->bardir == NODIR) {
426 println(hlog, "error: NODIR barrier at ", c);
427 return;
428 }
429 setland(cw.cpeek(), l2);
430 cw.cpeek()->barleft = NOWALLSEP_USED;
431 }
432
433 if(ws == NOWALLSEP_WALL && barrier_cross(l1, l2)) {
434
435 cellwalker p_cw = cw;
436 eLand p_l1 = l1, p_l2 = l2;
437 eLand p_ws = ws;
438 int i = 1;
439 general_barrier_advance(p_cw, i, p_l1, p_l2, p_ws, false);
440
441 cellwalker n_cw = cw;
442 eLand n_l1 = l1, n_l2 = l2;
443 eLand n_ws = ws;
444 i = -1;
445 general_barrier_advance(n_cw, i, n_l1, n_l2, n_ws, false);
446
447 int dir = 0;
448
449 println(hlog, "left ", n_cw, " = ", n_cw.at->barleft, " right ", p_cw, " = ", p_cw.at->barleft, " USED = ", NOWALLSEP_USED);
450
451 if(n_cw.at->barleft == NOWALLSEP_USED && p_cw.at->barleft != NOWALLSEP_USED) dir = 1;
452 if(p_cw.at->barleft == NOWALLSEP_USED && n_cw.at->barleft != NOWALLSEP_USED) dir = -1;
453
454 if(dir) {
455 if(!general_barrier_check_after(cw, 2, 10, 1, NOWALLSEP_WALL_EPOS, l1, l1)) {
456 println(hlog, "failed to check 1");
457 dir = 0;
458 }
459 if(!general_barrier_check_after(cw+wstep, 2, 10, 1, NOWALLSEP_WALL_EPOS, l1, l1)) {
460 println(hlog, "failed to check 2");
461 dir = 0;
462 }
463 }
464
465 if(dir) {
466 eLand xl1 = oppositeElement(l1, l2);
467 eLand xl2 = oppositeElement(l2, l1);
468
469 if(dir == 1) {
470 general_barrier_check_after(cw, 0, 10, 1, NOWALLSEP_WALL_EPOS, l1, xl2);
471 general_barrier_check_after(cw+wstep, 0, 10, 1, NOWALLSEP_WALL_EPOS, xl1, l2);
472 }
473 else {
474 general_barrier_check_after(cw, 0, 10, 1, NOWALLSEP_WALL_EPOS, xl2, l1);
475 general_barrier_check_after(cw+wstep, 0, 10, 1, NOWALLSEP_WALL_EPOS, l2, xl1);
476 }
477
478 general_barrier_check(cw, 10, dir, ws, xl2, xl1);
479 return;
480 }
481 }
482
483 for(int i: {-1, 1}) {
484
485 if(i == -1 && among(ws, NOWALLSEP_WALL_CPOS, NOWALLSEP_WALL_EPOS)) continue;
486 if(i == +1 && among(ws, NOWALLSEP_WALL_CNEG, NOWALLSEP_WALL_ENEG)) continue;
487
488 // general_barrier_check((cw, 10, i, ws, l1, l2);
489
490 cellwalker cw0 = cw;
491 eLand xl1 = l1, xl2 = l2;
492 eLand ws1 = ws;
493 int i1 = i;
494 general_barrier_advance(cw0, i1, xl1, xl2, ws1, true);
495
496 if(cw0.at->barleft != NOWALLSEP_USED) {
497 setland(cw0.at, xl1);
498 cw0.at->barleft = ws1;
499 cw0.at->barright = xl2;
500 cw0.at->bardir = cw0.spin;
501 extendcheck(cw0.at);
502 extendBarrier(cw0.at);
503 }
504 }
505 }
506
507 bool gotit = false;
508
extendCR5(cell * c)509 EX void extendCR5(cell *c) {
510 if(!BITRUNCATED) return;
511 // if(c->barright == laCrossroads5) extendCR5(c);
512 eLand forbidden = c->barleft;
513 eLand forbidden2 = laNone;
514 cellwalker cw(c, c->bardir);
515 for(int u=0; u<2; u++) {
516 // if(gotit) break;
517 cw = cw + 2 + wstep + 2 + wstep + 5;
518 if(cw.at->bardir == NODIR) {
519 cw.at->landparam = 40;
520 cw.at->bardir = cw.spin;
521 cw.at->barright = laCrossroads5;
522 eLand nland = forbidden;
523 for(int i=0; i<10 && (nland == forbidden || nland == forbidden2); i++)
524 nland = getNewLand(laCrossroads5);
525 if(ls::single() && specialland == laCrossroads5)
526 nland = laCrossroads5;
527 cw.at->barleft = forbidden2 = nland;
528 landcount[nland]++;
529 extendBarrier(cw.at);
530 gotit = true;
531 }
532 else forbidden2 = cw.at->barleft;
533 }
534 }
535
isbar4(cell * c)536 EX bool isbar4(cell *c) {
537 return
538 c->wall == waBarrier || c->land == laElementalWall ||
539 c->land == laMirrorWall || c->land == laMirrorWall2 ||
540 c->land == laMercuryRiver;
541 }
542
barrier_cross(eLand l,eLand r)543 EX bool barrier_cross(eLand l, eLand r) {
544 if(l == laCrossroads3 || r == laCrossroads3) return hrand(100) < 66;
545 if(isElemental(l) && isElemental(r)) return hrand(100) < 75;
546 return false;
547 }
548
extendBarrier(cell * c)549 EX void extendBarrier(cell *c) {
550 limitgen("extend barrier %p\n", hr::voidp(c));
551 if(buggyGeneration) return;
552
553 if(c->barleft == NOWALLSEP_USED) return;
554
555 extendcheck(c);
556
557 // printf("build barrier at %p", hr::voidp(c));
558 if(c->land == laBarrier || c->land == laElementalWall || c->land == laHauntedWall || c->land == laOceanWall ||
559 c->land == laMirrorWall || c->land == laMirrorWall2 || c->land == laMercuryRiver) {
560 // printf("-> ready\n");
561 return;
562 }
563 // if(c->wall == waWaxWall) return;
564 if(c->mpdist > BARLEV) {
565 // printf("-> too far\n");
566 return; // == INFD) return;
567 }
568
569 if(c->barleft == NOWALLSEP || c->barleft == NOWALLSEP_SWAP || c->barleft == NOWALLSEP_WALL || on_wall(c->barleft)) {
570 #if MAXMDIM >= 4
571 if(WDIM == 3) extend3D(c);
572 else
573 #endif
574 general_barrier_extend(c);
575 return;
576 }
577
578 bool firstmirror =
579 (c->barleft == laMirrored || c->barright == laMirrored) &&
580 c->barleft != laMirrored2 && c->barright != laMirrored2;
581
582 if(firstmirror && c->barleft == laMirror && hrand(100) < 60) {
583 cellwalker cw(c, c->bardir);
584 if(BITRUNCATED) cw += wstep;
585 if(cw.at->land != laMirrorWall)
586 if(buildBarrier6(cw, 1)) return;
587 }
588
589 if(firstmirror && (PURE?c->barleft == laMirror : c->barright == laMirror) && hrand(100) < 60) {
590 cellwalker cw(c, c->bardir);
591 if(PURE) {
592 cw = cw - 3 + wstep - 3;
593 }
594 else {
595 cw = cw + wstep + 3 + wstep - 1; // check this
596 }
597 if(buildBarrier6(cw, 2)) return;
598 }
599
600 if(barrier_cross(c->barleft, c->barright) || (firstmirror && hrand(100) < 60)) {
601
602 cellwalker cw(c, c->bardir);
603 if(PURE) {
604 cw += wstep;
605 if(isbar4(cw.at)) {
606 cw = cw + wstep + 3 + wstep - 1 + wstep;
607 bool b = buildBarrier4(cw.at, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright);
608 if(b) return;
609 }
610 else {
611 bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright);
612 if(b) return;
613 }
614 }
615 else {
616 cw = cw + 3 + wstep;
617 cell *cp = (cw + 4 + wstep).at;
618 if(!isbar4(cp)) {
619 cw = cw + 2 + wstep;
620 bool b = buildBarrier4(cw.at, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright);
621 if(b) return;
622 }
623 else {
624 bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright);
625 if(b) return;
626 }
627 }
628 }
629
630 extendBarrierFront(c);
631 extendBarrierBack(c);
632
633 if(c->barright == laCrossroads5) extendCR5(c);
634 }
635
buildBarrierForce(cell * c,int d,eLand l)636 EX void buildBarrierForce(cell *c, int d, eLand l) {
637 c->bardir = d;
638 eLand oldland = c->land;
639 if(oldland == laNone) {
640 raiseBuggyGeneration(c, "oldland is NONE");
641 return;
642 }
643 eLand newland = l ? l : getNewLand(oldland);
644 landcount[newland]++;
645 if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland;
646 else c->barleft = newland, c->barright = oldland;
647 if(!mirrorwall(c)) c->landparam = 40;
648 extendcheck(c);
649 }
650
buildBarrier(cell * c,int d,eLand l IS (laNone))651 EX void buildBarrier(cell *c, int d, eLand l IS(laNone)) {
652
653 if(!old_nice_walls()) {
654 general_barrier_build(NOWALLSEP_WALL, c, l ? l : getNewLand(c->land), NODIR);
655 return;
656 }
657
658 d %= 7;
659 cellwalker bb(c, d);
660
661 if(checkBarriersFront(bb) && checkBarriersBack(bb))
662 buildBarrierForce(c, d, l);
663 }
664
buildBarrier6(cellwalker cw,int type)665 EX bool buildBarrier6(cellwalker cw, int type) {
666 limitgen("build6 %p/%d (%d)\n", hr::voidp(cw.at), cw.spin, type);
667
668 cellwalker b[4];
669
670 if(buggyGeneration) return true;
671
672 if(BITRUNCATED) {
673 b[0] = cw + wstep;
674 b[1] = cw + 1 + wstep + 3 + wstep;
675 b[2] = cw + 4 + wstep;
676 b[3] = cw + 3 + wstep + 3 + wstep;
677 }
678 else {
679 b[0] = cw;
680 b[1] = cw + 3 + wstep + 3;
681 b[2] = cw - 2 + wstep - 3;
682 b[3] = cw - 3 + wstep + 2 + wstep - 3;
683
684 if(type == 1 && b[3].at->land != laMirrorWall) return false;
685 if(type == 2 && (b[1] + wstep).at->land != laMirrorWall) return false;
686 // if(type == 2 && b[2].at->land != laMirrorWall) return false;
687 }
688
689 if(false) {
690 for(int z=0; z<4; z++) {
691 printf("%p/%d\n", hr::voidp(b[z].at), b[z].spin);
692 b[z].at->wall = waStrandedBoat; b[z].at->land = laAlchemist;
693 b[z].at->mondir = b[z].spin;
694 b[z].at->mpdist = 7;
695 b[z].at->item = eItem(1+z);
696 buggyGeneration = true;
697 }
698 return true;
699 }
700
701 if(type == 1) {
702 if(!(PURE?checkBarriersFront:checkBarriersBack)(b[1], 6, true)) return false;
703 if(!(PURE?checkBarriersFront:checkBarriersBack)(b[2], 6, true)) return false;
704 }
705 else {
706 if(!(PURE?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false;
707 if(!(PURE?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false;
708 }
709
710 for(int d=0; d<4; d++) {
711 b[d].at->bardir = b[d].spin;
712
713 if(PURE) {
714 b[0].at->barleft = laMirrored, b[0].at->barright = laMirrored2;
715 b[1].at->barleft = laMirror, b[1].at->barright = laMirrored;
716 b[2].at->barleft = laMirrored2, b[2].at->barright = laMirrored;
717 b[3].at->barleft = laMirrored, b[3].at->barright = laMirror;
718 }
719 else {
720 b[0].at->barleft = laMirror, b[0].at->barright = laMirrored;
721 b[1].at->barleft = laMirrored, b[1].at->barright = laMirror;
722 b[2].at->barleft = laMirrored, b[2].at->barright = laMirrored2;
723 b[3].at->barleft = laMirrored2, b[3].at->barright = laMirrored;
724 }
725
726 (PURE?extendBarrierFront:extendBarrierBack)(b[d].at);
727 }
728
729 if(PURE && false) {
730 for(int z=0; z<4; z++)
731 b[z].at->item = eItem(1+z+4*type);
732 for(int a=0; a<4; a++)
733 extendBarrierBack((b[a]+wstep).at);
734 }
735
736 if(BITRUNCATED) {
737 setland((cw+1).cpeek(), laMirrorWall);
738 setland((cw+2).cpeek(), laMirrored);
739 setland((cw+3).cpeek(), laMirrorWall2);
740 setland((cw+4).cpeek(), laMirrorWall2);
741 setland((cw+5).cpeek(), laMirrored);
742 setland((cw+0).cpeek(), laMirrorWall);
743 setland((b[0]+2).cpeek(), laMirrored);
744 setland((b[3]+6).cpeek(), laMirrored2);
745 setland((b[3]+5).cpeek(), laMirrored2);
746 setland((b[1]-1).cpeek(), laMirrored);
747 setland((b[2]-2).cpeek(), laMirrored);
748 setland((b[1]-2).cpeek(), laMirrored);
749 setland((b[0]-2).cpeek(), laMirror);
750 cw.at->land = laMirrorWall;
751 cw.at->wall = waMirrorWall;
752 cw.at->landparam = 1;
753 }
754 else {
755 setland(cw.at, laMirrorWall2);
756 setland((cw+0).cpeek(), laMirrorWall2);
757 setland((cw+1).cpeek(), laMirrored);
758 setland((cw+2).cpeek(), laMirrored);
759 setland((cw+3).cpeek(), laMirrorWall);
760 setland((cw+4).cpeek(), laMirrored);
761 setland((cw+5).cpeek(), laMirrorWall2);
762 setland((cw+6).cpeek(), laMirrored2);
763
764 setland((b[1]).cpeek(), laMirrorWall);
765 setland((b[1]+1).cpeek(), laMirror);
766 setland((b[1]+2).cpeek(), laMirrorWall);
767 setland((b[1]+6).cpeek(), laMirrored);
768
769 setland((b[0] + wstep - 2).cpeek(), laMirrored);
770 setland((b[3] + wstep - 2).cpeek(), laMirrored);
771 }
772
773 return true;
774 }
775
buildBarrier4(cell * c,int d,int mode,eLand ll,eLand lr)776 EX bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) {
777 limitgen("build4 %p\n", hr::voidp(c));
778 if(buggyGeneration) return true;
779 d %= 7;
780
781 cellwalker cd(c, d);
782
783 cellwalker b1 = cd;
784 cellwalker b2 = PURE ? cd + wstep : cd + wstep + 3 + wstep + 3 + wstep;
785 cellwalker b3 = PURE ? cd - 1 + wstep + 3 : cd + wstep + 4 + wstep + 4;
786 cellwalker b4 = PURE ? cd + 1 + wstep - 3 : cd + wstep - 4 + wstep - 4;
787
788 if(mode == 0) {
789 if(!((checkBarriersBack(b1) && checkBarriersBack(b2)))) return false;
790 if(!((checkBarriersFront(b3) && checkBarriersFront(b4)))) return false;
791 }
792
793 if(mode == 1) {
794 if(!(checkBarriersFront(b3, 5, true) && checkBarriersFront(b4, 5, true)))
795 return false;
796 }
797
798 if(mode == 2) {
799 if(!((checkBarriersBack(b1, 5, true) && checkBarriersBack(b2, 5, true))))
800 return false;
801 }
802
803 eLand xl = oppositeElement(ll, lr);
804 eLand xr = oppositeElement(lr, ll);
805
806 c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c);
807
808 c= b2.at; d=b2.spin;
809 c->bardir = d, c->barleft = xl, c->barright = xr; extendBarrierBack(c);
810
811 c= b3.at; d=b3.spin;
812 c->bardir = d, c->barleft = xl, c->barright = lr; extendBarrierFront(c);
813
814 c= b4.at; d=b4.spin;
815 c->bardir = d, c->barleft = ll, c->barright = xr; extendBarrierFront(c);
816
817 if(BITRUNCATED) for(int a=-3; a<=3; a++) if(a) {
818 setland((b1+a).cpeek(), a > 0 ? lr : ll);
819 setland((b2+a).cpeek(), a > 0 ? xr : xl);
820 setland((b3+a).cpeek(), a > 0 ? lr : xl);
821 setland((b4+a).cpeek(), a > 0 ? xr : ll);
822 }
823
824 if(PURE) setbarrier(b1.at), setbarrier(b2.at), setbarrier(b3.at), setbarrier(b4.at);
825
826 if(BITRUNCATED) {
827 cell *cp;
828 cp = (b1+wstep).at;
829 cp->barleft = ll; cp->barright = lr; setbarrier(cp);
830 cp = (b2+wstep).at;
831 cp->barleft = xl; cp->barright = xr; setbarrier(cp);
832 }
833
834 return true;
835 }
836
buildBarrierStrong(cell * c,int d,bool oldleft,eLand newland)837 EX void buildBarrierStrong(cell *c, int d, bool oldleft, eLand newland) {
838 d %= 7;
839 cellwalker bb(c, d);
840
841 c->bardir = d;
842 eLand oldland = c->land;
843 landcount[newland]++;
844
845 if(oldleft) c->barleft = oldland, c->barright = newland;
846 else c->barleft = newland, c->barright = oldland;
847 extendcheck(bb.at);
848 }
849
buildBarrierStrong(cell * c,int d,bool oldleft)850 EX void buildBarrierStrong(cell *c, int d, bool oldleft) {
851 buildBarrierStrong(c, d, oldleft, getNewLand(c->land));
852 }
853
buildCrossroads2(cell * c)854 EX void buildCrossroads2(cell *c) {
855
856 if(buggyGeneration) return;
857
858 if(!c) return;
859
860 for(int i=0; i<c->type; i++)
861 if(c->move(i) && !c->move(i)->landparam && c->move(i)->mpdist < c->mpdist)
862 buildCrossroads2(c->move(i));
863
864 if(hasbardir(c))
865 extendBarrier(c);
866
867 if(c->land != laCrossroads2) return;
868
869 if(!c->landparam) {
870 for(int i=0; i<c->type; i++) {
871 cell *c2 = createMov(c, i);
872 if(c2 && c2->landparam && (c2->land == laCrossroads2 || c2->land == laBarrier)) {
873 for(int j=0; j<c2->type; j++) {
874 createMov(c2, j);
875 cell *c3 = c2->move(j);
876 if(c3 && c3->landparam && (c3->land == laCrossroads2 || c3->land == laBarrier)) {
877 int h2 = c2->landparam;
878 int h3 = c3->landparam;
879
880 if(h2 > 100) { raiseBuggyGeneration(c2, "bad c2 landparam"); return; }
881 if(h3 > 100) { raiseBuggyGeneration(c3, "bad c3 landparam"); return; }
882
883 // ambiguous
884 if(h2/4 == 1 && h3/4 == 3) continue;
885 if(h2/4 == 3 && h3/4 == 1) continue;
886
887 for(int d=0; d<c2->type; d++)
888 if(emeraldtable[h2][d] == h3) {
889 int nh = emeraldtable[h2][(42+d + c->c.spin(i) - j) % c2->type];
890 if(c->landparam>0 && c->landparam != nh) {
891 printf("CONFLICT\n");
892 raiseBuggyGeneration(c, "CONFLICT");
893 }
894 c->landparam = nh;
895 }
896
897 if(c->landparam == 0)
898 printf("H2 = %d H3=%d\n", c2->landparam, c3->landparam);
899 }
900 }
901 if(c->landparam == 0) {
902 printf("H2 = %d\n", c2->landparam);
903 // halted = true;
904 // c->heat = -1;
905 raiseBuggyGeneration(c, "buildCrossroads2x");
906 return;
907 }
908 }
909 }
910
911 if(c->landparam) {
912 // for(int i=0; i<c->type; i++) {
913 // cell *c2 = c->move(i);
914 // buildCrossroads2(c2);
915 // }
916 }
917 else {
918 raiseBuggyGeneration(c, "buildCrossroads2");
919 return;
920 }
921 }
922
923 int h = c->landparam;
924
925 if(h/4 >= 8 && h/4 <= 11) {
926 for(int i=0; i<c->type; i++) if(c->land != laBarrier) {
927 cell *c2 = createMov(c, i);
928 if(c2->land == laBarrier) continue;
929 c2->land = laCrossroads2;
930 if(!c2->landparam) buildCrossroads2(c2);
931 }
932 if(h/4 == 8 || h/4 == 10)
933 for(int i=0; i<c->type; i++) {
934 if(c->move(i) && c->move(i)->landparam == h-4) {
935 bool oldleft = true;
936 for(int j=1; j<=3; j++)
937 if(c->modmove(i+j) && c->modmove(i+j)->mpdist < c->mpdist)
938 oldleft = false;
939
940 c->landparam = h;
941 if(ls::single())
942 buildBarrierStrong(c, i, oldleft, specialland);
943 else
944 buildBarrierStrong(c, i, oldleft);
945 c->landparam = h;
946 extendBarrier(c);
947 }
948 }
949 }
950 }
951
952 #if MAXMDIM >= 4
bufferzone()953 EX bool bufferzone() { return PURE && S7 == 6; }
basic_tests()954 EX int basic_tests() { return 50; }
955
valid_dir(const vector<char> & ad,int j,cell * c)956 EX bool valid_dir(const vector<char>& ad, int j, cell *c) {
957 bool bch = variation == eVariation::bch;
958 if(!bch) return ad[j] == 1;
959
960 if(ad[j] != 2) return false;
961 auto ad1 = currentmap->get_cellshape(c).dirdist[j];
962 int a = 0;
963 for(auto& dd: ad1) if(dd == 1) a++;
964
965 int a0 = 0;
966 for(auto& dd: ad) if(dd == 1) a0++;
967 return a < 6;
968 }
969
extend3D(cell * c)970 EX void extend3D(cell *c) {
971 eLand l1 = c->land;
972 c->barleft = NOWALLSEP_USED;
973
974 cellwalker cw(c, c->bardir);
975
976 if(bufferzone()) {
977 cw += wstep; cw += rev;
978 cw.at->bardir = NOBARRIERS;
979 setland(cw.at, laBarrier);
980 }
981
982 auto cw1 = cw + wstep;
983 setland(cw1.at, c->barright);
984 if(cw1.at->bardir == NODIR) {
985 cw1.at->barleft = NOWALLSEP_USED;
986 cw1.at->barright = l1;
987 cw1.at->bardir = cw1.spin;
988 }
989
990 bool bch = variation == eVariation::bch;
991
992 auto& ad = currentmap->dirdist(cw);
993 for(int j=0; j<cw.at->type; j++) {
994
995 if(!valid_dir(ad, j, cw.at)) {
996 if(bch && ad[j] == 1) {
997 cell *c1 = cw.at->cmove(j);
998 c1->bardir = NOBARRIERS;
999 setland(c1, c->barright);
1000 }
1001
1002 if(bch && ad[j] == 2) {
1003 cell *c1 = cw.at->cmove(j);
1004 c1->bardir = NOBARRIERS;
1005 setland(c1, l1);
1006 }
1007
1008 continue;
1009 }
1010
1011 cellwalker bb2 = currentmap->strafe(cw, j);
1012 if(bufferzone()) { bb2 += rev; bb2 += wstep; }
1013
1014 if(bb2.at->bardir == NODIR) {
1015 bb2.at->bardir = bb2.spin;
1016 bb2.at->barleft = NOWALLSEP;
1017 bb2.at->barright = c->barright;
1018 bb2.at->land = l1;
1019 // bb2.at->item = itGold;
1020 extendBarrier(bb2.at);
1021 }
1022 }
1023 }
1024
1025 bool built = false;
1026
buildBarrier3D(cell * c,eLand l2,int forced_dir)1027 EX bool buildBarrier3D(cell *c, eLand l2, int forced_dir) {
1028 if(forced_dir == NODIR) {
1029 for(int t=0; t<c->type; t++) if((!c->move(t) || c->move(t)->mpdist > c->mpdist) && buildBarrier3D(c, l2, t)) return true;
1030 return false;
1031 }
1032 bool bch = variation == eVariation::bch;
1033
1034 cellwalker cw(c, forced_dir);
1035
1036 if(bch) {
1037 auto& ad = currentmap->dirdist(cw);
1038 int a = 0;
1039 for(auto& dd: ad) if(dd == 1) a++;
1040 if(a == 6) return false;
1041 }
1042
1043 if(bufferzone()) { cw += wstep; cw += rev; }
1044 set<cell*> listed_cells = { cw.at };
1045 vector<cellwalker> to_test { cw };
1046 int tc = basic_tests();
1047 for(int i=0; i<isize(to_test); i++) {
1048 auto bb = to_test[i];
1049 if(bb.at->mpdist < BARLEV) return false;
1050 if(bb.cpeek()->mpdist < BARLEV) return false;
1051 if(bb.cpeek()->bardir != NODIR) return false;
1052 if(bufferzone() && (bb+rev).cpeek()->mpdist < BARLEV) return false;
1053 if(bufferzone() && (bb+rev).cpeek()->bardir != NODIR) return false;
1054 if(bb.at->bardir != NODIR) return false;
1055 auto& ad = currentmap->dirdist(bb);
1056 for(int j=0; j<bb.at->type; j++) {
1057 if(i < tc) bb.at->cmove(j);
1058 if(!bb.at->move(j)) continue;
1059 if(!valid_dir(ad, j, bb.at)) continue;
1060 cellwalker bb2 = currentmap->strafe(bb, j);
1061 if(listed_cells.count(bb2.at)) continue;
1062 listed_cells.insert(bb2.at);
1063 to_test.push_back(bb2);
1064 }
1065 }
1066
1067 for(int i=0; i<isize(to_test); i++) {
1068 auto bb = to_test[i];
1069 if(bufferzone()) { bb.at->bardir = NOBARRIERS; setland(bb.at, laBarrier); bb += rev; bb += wstep; }
1070 bb.at->land = c->land;
1071 bb.at->bardir = bb.spin;
1072 bb.at->barleft = NOWALLSEP;
1073 bb.at->barright = l2;
1074 extendBarrier(bb.at);
1075 }
1076
1077 built = true;
1078 return true;
1079 }
1080 #endif
1081
buildBarrierNowall(cell * c,eLand l2,int forced_dir IS (NODIR))1082 EX bool buildBarrierNowall(cell *c, eLand l2, int forced_dir IS(NODIR)) {
1083 return general_barrier_build(NOWALLSEP, c, l2, forced_dir);
1084 }
1085
general_barrier_build(eLand ws,cell * c,eLand l2,int forced_dir IS (NODIR))1086 EX bool general_barrier_build(eLand ws, cell *c, eLand l2, int forced_dir IS(NODIR)) {
1087
1088 if(S3 >= OINF) { c->land = l2; return true; }
1089
1090 #if MAXMDIM >= 4
1091 // 3D binary tilings create walls using their own methods
1092 if(WDIM == 3 && bt::in()) return false;
1093
1094 if(WDIM == 3 && hyperbolic) return buildBarrier3D(c, l2, forced_dir);
1095 #endif
1096
1097 if(c->land == laNone) {
1098 printf("barrier nowall! [%p]\n", hr::voidp(c));
1099 raiseBuggyGeneration(c, "barrier nowall!");
1100 return false;
1101 }
1102
1103 bool warpv = warped_version(c->land, l2);
1104 if(warpv && !arcm::in() && !pseudohept(c)) return false;
1105
1106 vector<int> ds = hrandom_permutation(c->type);
1107
1108 eLand wsx = warpv ? laWarpCoast : laNone;
1109 eLand l1 = c->land;
1110
1111 if(forced_dir != NODIR) {
1112 cellwalker cw(c, forced_dir);
1113 general_barrier_check(cw, 20, -1, ws, l1, l2);
1114 general_barrier_check(cw, 20, 1, ws, l1, l2);
1115 extendBarrier(c);
1116 return true;
1117 }
1118
1119 for(int d: ds) {
1120 if(c->move(d) && c->move(d)->mpdist <= c->mpdist) continue;
1121 cellwalker cw(c, d);
1122 if(general_barrier_check(cw, 20, -1, ws, wsx, wsx) && general_barrier_check(cw, 20, 1, ws, wsx, wsx)) {
1123 general_barrier_check(cw, 20, -1, ws, l1, l2);
1124 general_barrier_check(cw, 20, 1, ws, l1, l2);
1125 extendBarrier(c);
1126 return true;
1127 }
1128 }
1129
1130 return false;
1131 }
1132
1133 }
1134