From f1bba9de0d2581f66708d047f20f995e21765eef Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sun, 8 Oct 2017 12:10:40 +0200 Subject: [PATCH] landgen refactoring --- barriers.cpp | 772 +++++++++ bigstuff.cpp | 1029 ++++++++++++ complex.cpp | 523 +++++- debug.cpp | 46 + hyper.h | 25 +- init.cpp | 5 + landgen.cpp | 4287 +----------------------------------------------- landlock.cpp | 856 ++++++++++ monstergen.cpp | 605 +++++++ orbgen.cpp | 462 ++++++ 10 files changed, 4322 insertions(+), 4288 deletions(-) create mode 100644 barriers.cpp create mode 100644 bigstuff.cpp create mode 100644 landlock.cpp create mode 100644 monstergen.cpp create mode 100644 orbgen.cpp diff --git a/barriers.cpp b/barriers.cpp new file mode 100644 index 00000000..ce51b77e --- /dev/null +++ b/barriers.cpp @@ -0,0 +1,772 @@ +// This file implements routines related to barriers (Great Walls and similar). + +bool buildBarrierNowall(cell *c, eLand l2, bool force = false); + +bool checkBarriersBack(cellwalker bb, int q=5, bool cross = false); + +bool checkBarriersFront(cellwalker bb, int q=5, bool cross = false) { + + if(bb.c->type == 6) + return false; + + if(bb.c->mpdist < BARLEV) return false; + if(bb.c->mpdist == BUGLEV) return false; + if(bb.c->bardir != NODIR) return false; + if(bb.spin == (purehepta ? 3 : 0)) {q--; if(!q) return true; } + + if(!cross) for(int i=0; i<7; i++) { + cellwalker bb2 = bb; + cwspin(bb2, i); cwstep(bb2); + if(bb2.c->bardir != NODIR) return false; + if(!purehepta) { + cwspin(bb2, 4); cwstep(bb2); + if(bb2.c->bardir != NODIR) return false; + } + } + + cwstep(bb); + if(!purehepta) { cwspin(bb, 3); cwstep(bb); cwspin(bb, 3); cwstep(bb); } + return checkBarriersBack(bb, q); + } + +bool hasbardir(cell *c) { + return c->bardir != NODIR && c->bardir != NOBARRIERS; + } + +void preventbarriers(cell *c) { + if(c && c->bardir == NODIR) c->bardir = NOBARRIERS; + } + +bool checkBarriersBack(cellwalker bb, int q, bool cross) { + // printf("back, %p, s%d\n", bb.c, bb.spin); + + // if(mark) { printf("mpdist = %d [%d] bardir = %d spin=%d q=%d cross=%d\n", bb.c->mpdist, BARLEV, bb.c->bardir, bb.spin, q, cross); } + + if(bb.c->mpdist < BARLEV) return false; + if(bb.c->mpdist == BUGLEV) return false; + if(bb.c->bardir != NODIR) return false; + + // if(bb.spin == 0 && bb.c->mpdist == INFD) return true; + + if(!cross) for(int i=0; i<7; i++) { + cellwalker bb2 = bb; + cwspin(bb2, i); cwstep(bb2); + if(bb2.c->bardir != NODIR) return false; + if(!purehepta) { + cwspin(bb2, 4); cwstep(bb2); + if(bb2.c->bardir != NODIR) return false; + } + } + + cwspin(bb, 3); cwstep(bb); cwspin(bb, purehepta ? 5 : 4); + // bool create = cwstepcreates(bb); + cwstep(bb); cwspin(bb, 3); + // if(create && bb.spin == 0) return true; + return checkBarriersFront(bb, q); + } + +const eLand NOWALLSEP = laNone; +const eLand NOWALLSEP_USED = laWhirlpool; + +bool checkBarriersNowall(cellwalker bb, int q, int dir, eLand l1=laNone, eLand l2=laNone) { + if(bb.c->mpdist < BARLEV && l1 == laNone) return false; + if(bb.c->bardir != NODIR && l1 == laNone) return false; + + if(l1 != laNone) { + bb.c->bardir = bb.spin; bb.c->barright = l2; bb.c->barleft = NOWALLSEP; + setland(bb.c, l1); + } + if(q > 10) return true; + + if(l1 == laNone) for(int i=0; itype; i++) { + cell *c1 = bb.c->mov[i]; + if(!c1) continue; + for(int j=0; jtype; j++) { + cell *c2 = c1->mov[j]; + if(!c2) continue; + if(c2 && c2->bardir == NOBARRIERS) + return false; + if(c2 && c2->bardir != NODIR && c2->barleft != NOWALLSEP) + return false; + // note: "far crashes" between NOWALL lines are allowed + } + } + + if(purehepta) { + cwspin(bb, 3*dir); + cwstep(bb); + cwspin(bb, -3*dir); + } + else { + cwstep(bb); + cwspin(bb, 2*dir); + cwstep(bb); + cwspin(bb, dir); + } + return checkBarriersNowall(bb, q+1, -dir, l2, l1); + } + +eWall getElementalWall(eLand l) { + if(l == laEAir) return waChasm; + if(l == laEEarth) return waStone; + if(l == laEFire) return waEternalFire; + if(l == laEWater) return waSea; + return waNone; + } + +void setbarrier(cell *c) { + if(isSealand(c->barleft) && isSealand(c->barright)) { + bool setbar = c->type == 7; + if(c->barleft == laKraken || c->barright == laKraken) + if(c->barleft != laWarpSea && c->barright != laWarpSea) + setbar = !setbar; + c->wall = setbar ? waBarrier : waSea; + c->land = laOceanWall; + } + else if(isElemental(c->barleft) && isElemental(c->barright)) { + c->land = laElementalWall; + c->wall = getElementalWall(c->barleft); + } + else if(c->barleft == laHaunted || c->barright == laHaunted) { + c->land = laHauntedWall; + } + else if(c->barleft == laMirrored2 || c->barright == laMirrored2) + c->land = laMirrorWall2; + else if(c->barleft == laMirrored || c->barright == laMirrored) + c->land = laMirrorWall; + else if(c->barleft == laTerracotta && c->barright == laTerracotta) { + c->land = laMercuryRiver; + c->wall = waMercury; + } + else { + c->wall = waBarrier; + c->land = laBarrier; + } +/*if(isHive(c->barleft) && isHive(c->barright)) + c->wall = waWaxWall, c->land = c->barleft; */ + } + +void setland(cell *c, eLand l) { + if(c->land != l) { + c->landparam = 0; + } + if(l == laNone) { + printf("setland\n"); // NONEDEBUG + } + c->land = l; + } + +void extendcheck(cell *c) { + return; + if(!purehepta && c->landparam == 0 && c->barleft != NOWALLSEP) { + raiseBuggyGeneration(c, "extend error"); + } + } + +bool mirrorwall(cell *c) { + return c->barleft == laMirrored || c->barright == laMirrored; + } + +void extendBarrierFront(cell *c) { + limitgen("extend front %p\n", c); + if(buggyGeneration) return; + int ht = c->landparam; + extendcheck(c); + + cellwalker bb(c, c->bardir); setbarrier(bb.c); + cwstep(bb); + + if(!purehepta) { + bb.c->barleft = c->barleft; + bb.c->barright = c->barright; + setbarrier(bb.c); + if(!mirrorwall(bb.c)) + bb.c->landparam = (ht-4); + //printf("[A heat %d]\n", ht-4); + + cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barleft); cwstep(bb); + cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barright); cwstep(bb); + cwspin(bb, 2); + + cwspin(bb, 3); cwstep(bb); + bb.c->barleft = c->barright; + bb.c->barright = c->barleft; + setbarrier(bb.c); + if(!mirrorwall(bb.c)) + bb.c->landparam = (ht-4)^2; + //printf("[B heat %d]\n", (ht-4)^2); + cwspin(bb, 3); cwstep(bb); + + bb.c->barleft = c->barleft; + bb.c->barright = c->barright; + if(!mirrorwall(bb.c)) + bb.c->landparam = ht ^ 2; + } + +//printf("[C heat %d]\n", (ht)^2); + bb.c->bardir = bb.spin; + bb.c->barleft = c->barright; + bb.c->barright = c->barleft; + // printf("#1\n"); + extendcheck(bb.c); + extendBarrier(bb.c); + + for(int a=-3; a<=3; a++) if(a) { + bb.c = c; bb.spin = c->bardir; cwspin(bb, purehepta?-a:a); cwstep(bb); + setland(bb.c, a > 0 ? c->barright : c->barleft); + } + } + +void extendBarrierBack(cell *c) { + limitgen("extend back %p\n", c); + if(buggyGeneration) return; + int ht = c->landparam; + extendcheck(c); + + cellwalker bb(c, c->bardir); setbarrier(bb.c); + cwspin(bb, 3); cwstep(bb); cwspin(bb, purehepta?5:4); + setland(bb.c, purehepta ? c->barleft : c->barright); + cwstep(bb); cwspin(bb, 3); + bb.c->bardir = bb.spin; + bb.c->barleft = c->barright; + bb.c->barright = c->barleft; + if(!mirrorwall(bb.c)) + bb.c->landparam = ht ^ 11; + extendcheck(bb.c); +//printf("[D heat %d]\n", (ht^11)); + + // needed for CR2 to work + if(!purehepta) { + cwstep(bb); + bb.c->barleft = c->barright; + bb.c->barright = c->barleft; + if(!mirrorwall(bb.c)) + bb.c->landparam = (ht^11)-4; + cwstep(bb); + } +//printf("[E heat %d]\n", (ht^11)); + + // printf("#2\n"); + extendBarrier(bb.c); + } + +void extendNowall(cell *c) { + + c->barleft = NOWALLSEP_USED; + cellwalker cw(c, c->bardir); + + if(!purehepta) { + cwstep(cw); + setland(cw.c, c->barright); + } + + for(int i=-1; i<2; i+=2) { + if(purehepta) { + cwspin(cw, 3*i); + cwstep(cw); + cwspin(cw, -3*i); + } + else { + cwspin(cw, 2*i); + cwstep(cw); + } + setland(cw.c, c->barright); + if(cw.c->barleft != NOWALLSEP_USED) { + cw.c->barleft = NOWALLSEP; + cw.c->barright = c->land; + if(c->barright == laNone) { + printf("barright\n"); + }// NONEDEBUG + setland(cw.c, c->barright); + if(!purehepta) cwspin(cw, i); + cw.c->bardir = cw.spin; + if(!purehepta) cwspin(cw, -i); + extendcheck(cw.c); + extendBarrier(cw.c); + } + if(purehepta) { + cwspin(cw, 3*i); + cwstep(cw); + cwspin(cw, -3*i); + } + else { + cwstep(cw); + cwspin(cw, -2*i); + } + } + } + +bool gotit = false; + +void extendCR5(cell *c) { + if(purehepta) return; +// if(c->barright == laCrossroads5) extendCR5(c); + eLand forbidden = c->barleft; + eLand forbidden2 = laNone; + cellwalker cw(c, c->bardir); + for(int u=0; u<2; u++) { + // if(gotit) break; + cwspin(cw, 2); + cwstep(cw); + cwspin(cw, 2); + cwstep(cw); + cwspin(cw, 5); + if(cw.c->bardir == NODIR) { + cw.c->landparam = 40; + cw.c->bardir = cw.spin; + cw.c->barright = laCrossroads5; + eLand nland = forbidden; + for(int i=0; i<10 && (nland == forbidden || nland == forbidden2); i++) + nland = getNewLand(laCrossroads5); + cw.c->barleft = forbidden2 = nland; + landcount[nland]++; + extendBarrier(cw.c); + gotit = true; + } + else forbidden2 = cw.c->barleft; + } + } + +bool isbar4(cell *c) { + return + c->wall == waBarrier || c->land == laElementalWall || + c->land == laMirrorWall || c->land == laMirrorWall2 || + c->land == laMercuryRiver; + } + +void extendBarrier(cell *c) { + limitgen("extend barrier %p\n", c); + if(buggyGeneration) return; + + if(c->barleft == NOWALLSEP_USED) return; + + extendcheck(c); + + // printf("build barrier at %p", c); + if(c->land == laBarrier || c->land == laElementalWall || c->land == laHauntedWall || c->land == laOceanWall || + c->land == laMirrorWall || c->land == laMirrorWall2 || c->land == laMercuryRiver) { + // printf("-> ready\n"); + return; + } +// if(c->wall == waWaxWall) return; + if(c->mpdist > BARLEV) { + // printf("-> too far\n"); + return; // == INFD) return; + } + + if(c->barleft == NOWALLSEP) { + extendNowall(c); + return; + } + + bool firstmirror = + (c->barleft == laMirrored || c->barright == laMirrored) && + c->barleft != laMirrored2 && c->barright != laMirrored2; + + if(firstmirror && c->barleft == laMirror && hrand(100) < 60) { + cellwalker cw(c, c->bardir); + if(!purehepta) cwstep(cw); + if(cw.c->land != laMirrorWall) + if(buildBarrier6(cw, 1)) return; + } + + if(firstmirror && (purehepta?c->barleft == laMirror : c->barright == laMirror) && hrand(100) < 60) { + cellwalker cw(c, c->bardir); + if(purehepta) { + cwspin(cw, -3); cwstep(cw); cwspin(cw, -3); +// cwspin(cw, 3); cwstep(cw); cwspin(cw, -2); cwstep(cw); cwspin(cw, 3); + } + else { + cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); // check this + } + if(buildBarrier6(cw, 2)) return; + } + + if(((c->barleft == laCrossroads3 || c->barright == laCrossroads3) && hrand(100) < 66) || + (isElemental(c->barleft) && isElemental(c->barright) && hrand(100) < 75) + || (firstmirror && hrand(100) < 60) + ) { + + cellwalker cw(c, c->bardir); + if(purehepta) { + cwstep(cw); + if(isbar4(cw.c)) { + cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); cwstep(cw); + bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright); + if(b) return; + } + else { + bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright); + if(b) return; + } + } + else { + cwspin(cw, 3); cwstep(cw); + cell *cp = cwpeek(cw, 4); + if(!isbar4(cp)) { + cwspin(cw, 2); cwstep(cw); + bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright); + if(b) return; + } + else { + bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright); + if(b) return; + } + } + } + + extendBarrierFront(c); + extendBarrierBack(c); + + if(c->barright == laCrossroads5) extendCR5(c); + } + +void buildBarrierForce(cell *c, int d, eLand l) { + c->bardir = d; + eLand oldland = c->land; + if(oldland == laNone) { + raiseBuggyGeneration(c, "oldland is NONE"); + return; + } + eLand newland = l ? l : getNewLand(oldland); + landcount[newland]++; + if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland; + else c->barleft = newland, c->barright = oldland; + if(!mirrorwall(c)) c->landparam = 40; + extendcheck(c); + } + +void buildBarrier(cell *c, int d, eLand l) { + d %= 7; + cellwalker bb(c, d); + + if(checkBarriersFront(bb) && checkBarriersBack(bb)) + buildBarrierForce(c, d, l); + } + +bool buildBarrier6(cellwalker cw, int type) { + limitgen("build6 %p/%d (%d)\n", cw.c, cw.spin, type); + + cellwalker b[4]; + for(int i=0; i<4; i++) b[i] = cw; + + if(buggyGeneration) return true; + + if(!purehepta) { + cwstep(b[0]); + cwspin(b[1], 1); cwstep(b[1]); cwspin(b[1], 3); cwstep(b[1]); + cwspin(b[2], 4); cwstep(b[2]); + cwspin(b[3], 3); cwstep(b[3]); cwspin(b[3], 3); cwstep(b[3]); + } + else { + cwspin(b[1], 3); cwstep(b[1]); cwspin(b[1], 3); + cwspin(b[2], -2); cwstep(b[2]); cwspin(b[2], -3); + cwspin(b[3], -3); cwstep(b[3]); cwspin(b[3], 2); cwstep(b[3]); cwspin(b[3],-3); + if(type == 1 && b[3].c->land != laMirrorWall) return false; + if(type == 2 && cwpeek(b[1], 0)->land != laMirrorWall) return false; + // if(type == 2 && b[2].c->land != laMirrorWall) return false; + } + + if(false) { + for(int z=0; z<4; z++) { + printf("%p/%d\n", b[z].c, b[z].spin); + b[z].c->wall = waStrandedBoat; b[z].c->land = laAlchemist; + b[z].c->mondir = b[z].spin; + b[z].c->mpdist = 7; + b[z].c->item = eItem(1+z); + buggyGeneration = true; + } + return true; + } + + if(type == 1) { + if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[1], 6, true)) return false; + if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[2], 6, true)) return false; + } + else { + if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false; + if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false; + } + + for(int d=0; d<4; d++) { + b[d].c->bardir = b[d].spin; + + if(purehepta) { + b[0].c->barleft = laMirrored, b[0].c->barright = laMirrored2; + b[1].c->barleft = laMirror, b[1].c->barright = laMirrored; + b[2].c->barleft = laMirrored2, b[2].c->barright = laMirrored; + b[3].c->barleft = laMirrored, b[3].c->barright = laMirror; + } + else { + b[0].c->barleft = laMirror, b[0].c->barright = laMirrored; + b[1].c->barleft = laMirrored, b[1].c->barright = laMirror; + b[2].c->barleft = laMirrored, b[2].c->barright = laMirrored2; + b[3].c->barleft = laMirrored2, b[3].c->barright = laMirrored; + } + + (purehepta?extendBarrierFront:extendBarrierBack)(b[d].c); + } + + if(purehepta && false) { + for(int z=0; z<4; z++) + b[z].c->item = eItem(1+z+4*type); + for(int a=0; a<4; a++) + extendBarrierBack(cwpeek(b[a],0)); + } + + if(!purehepta) { + setland(cwpeek(cw, 1), laMirrorWall); + setland(cwpeek(cw, 2), laMirrored); + setland(cwpeek(cw, 3), laMirrorWall2); + setland(cwpeek(cw, 4), laMirrorWall2); + setland(cwpeek(cw, 5), laMirrored); + setland(cwpeek(cw, 0), laMirrorWall); + setland(cwpeek(b[0], 2), laMirrored); + setland(cwpeek(b[3], 6), laMirrored2); + setland(cwpeek(b[3], 5), laMirrored2); + setland(cwpeek(b[1], -1), laMirrored); + setland(cwpeek(b[2], -2), laMirrored); + setland(cwpeek(b[1], -2), laMirrored); + setland(cwpeek(b[0], -2), laMirror); + cw.c->land = laMirrorWall; + cw.c->wall = waMirrorWall; + cw.c->landparam = 1; + } + else { + setland(cw.c, laMirrorWall2); + setland(cwpeek(cw, 0), laMirrorWall2); + setland(cwpeek(cw, 1), laMirrored); + setland(cwpeek(cw, 2), laMirrored); + setland(cwpeek(cw, 3), laMirrorWall); + setland(cwpeek(cw, 4), laMirrored); + setland(cwpeek(cw, 5), laMirrorWall2); + setland(cwpeek(cw, 6), laMirrored2); + + setland(cwpeek(b[1], 0), laMirrorWall); + setland(cwpeek(b[1], 1), laMirror); + setland(cwpeek(b[1], 2), laMirrorWall); + setland(cwpeek(b[1], 6), laMirrored); + + cellwalker cf = b[0]; + cwstep(cf); + setland(cwpeek(cf, -2), laMirrored); + + cf = b[3]; + cwstep(cf); + setland(cwpeek(cf, -2), laMirrored); + } + + return true; + } + + + +bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) { + limitgen("build4 %p\n", c); + if(buggyGeneration) return true; + d %= 7; + cellwalker b1(c, d); + + cellwalker b2(c, d); + if(purehepta) cwstep(b2); + else { cwstep(b2); cwspin(b2, 3); cwstep(b2); cwspin(b2, 3); cwstep(b2); } + + cellwalker b3(c, d); + if(purehepta) { + cwspin(b3, -1); cwstep(b3); cwspin(b3, 3); + } + else { + cwstep(b3); cwspin(b3, 4); cwstep(b3); cwspin(b3, 4); + } + + cellwalker b4(c, d); + if(purehepta) { + cwspin(b4, 1); cwstep(b4); cwspin(b4, -3); + } + else { + cwstep(b4); cwspin(b4, -4); cwstep(b4); cwspin(b4, -4); + } + + if(mode == 0) { + if(!((checkBarriersBack(b1) && checkBarriersBack(b2)))) return false; + if(!((checkBarriersFront(b3) && checkBarriersFront(b4)))) return false; + } + + if(mode == 1) { + if(!(checkBarriersFront(b3, 5, true) && checkBarriersFront(b4, 5, true))) + return false; + } + + if(mode == 2) { + if(!((checkBarriersBack(b1, 5, true) && checkBarriersBack(b2, 5, true)))) + return false; + } + + eLand xl = oppositeElement(ll, lr); + eLand xr = oppositeElement(lr, ll); + + c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c); + + c= b2.c; d=b2.spin; + c->bardir = d, c->barleft = xl, c->barright = xr; extendBarrierBack(c); + + c= b3.c; d=b3.spin; + c->bardir = d, c->barleft = xl, c->barright = lr; extendBarrierFront(c); + + c= b4.c; d=b4.spin; + c->bardir = d, c->barleft = ll, c->barright = xr; extendBarrierFront(c); + + if(!purehepta) for(int a=-3; a<=3; a++) if(a) { + setland(cwpeek(b1, a), a > 0 ? lr : ll); + setland(cwpeek(b2, a), a > 0 ? xr : xl); + setland(cwpeek(b3, a), a > 0 ? lr : xl); + setland(cwpeek(b4, a), a > 0 ? xr : ll); + } + + if(purehepta) setbarrier(b1.c), setbarrier(b2.c), setbarrier(b3.c), setbarrier(b4.c); + + if(!purehepta) { + cell *cp; + cp = cwpeek(b1, 0); + cp->barleft = ll; cp->barright = lr; setbarrier(cp); + cp = cwpeek(b2, 0); + cp->barleft = xl; cp->barright = xr; setbarrier(cp); + } + + return true; + } + +void buildBarrierStrong(cell *c, int d, bool oldleft) { + d %= 7; + cellwalker bb(c, d); + + c->bardir = d; + eLand oldland = c->land; + eLand newland = getNewLand(oldland); + landcount[newland]++; + + if(oldleft) c->barleft = oldland, c->barright = newland; + else c->barleft = newland, c->barright = oldland; + extendcheck(bb.c); + } + +void buildCrossroads2(cell *c) { + + if(buggyGeneration) return; + + if(!c) return; + + for(int i=0; itype; i++) + if(c->mov[i] && !c->mov[i]->landparam && c->mov[i]->mpdist < c->mpdist) + buildCrossroads2(c->mov[i]); + + if(hasbardir(c)) + extendBarrier(c); + + if(c->land != laCrossroads2) return; + + if(!c->landparam) { + for(int i=0; itype; i++) { + cell *c2 = createMov(c, i); + if(c2 && c2->landparam && (c2->land == laCrossroads2 || c2->land == laBarrier)) { + for(int j=0; jtype; j++) { + createMov(c2, j); + cell *c3 = c2->mov[j]; + if(c3 && c3->landparam && (c3->land == laCrossroads2 || c3->land == laBarrier)) { + int h2 = c2->landparam; + int h3 = c3->landparam; + + if(h2 > 100) { raiseBuggyGeneration(c2, "bad c2 landparam"); return; } + if(h3 > 100) { raiseBuggyGeneration(c3, "bad c3 landparam"); return; } + + // ambiguous + if(h2/4 == 1 && h3/4 == 3) continue; + if(h2/4 == 3 && h3/4 == 1) continue; + + for(int d=0; dtype; d++) + if(emeraldtable[h2][d] == h3) { + int nh = emeraldtable[h2][(42+d + c->spn(i) - j) % c2->type]; + if(c->landparam>0 && c->landparam != nh) { + printf("CONFLICT\n"); + raiseBuggyGeneration(c, "CONFLICT"); + } + c->landparam = nh; + } + + if(c->landparam == 0) + printf("H2 = %d H3=%d\n", c2->landparam, c3->landparam); + } + } + if(c->landparam == 0) { + printf("H2 = %d\n", c2->landparam); +// halted = true; +// c->heat = -1; + raiseBuggyGeneration(c, "buildCrossroads2x"); + return; + } + } + } + + if(c->landparam) { +// for(int i=0; itype; i++) { +// cell *c2 = c->mov[i]; +// buildCrossroads2(c2); +// } + } + else { + raiseBuggyGeneration(c, "buildCrossroads2"); + return; + } + } + + int h = c->landparam; + + if(h/4 >= 8 && h/4 <= 11) { + for(int i=0; itype; i++) { + createMov(c, i)->land = laCrossroads2; + if(!c->mov[i]->landparam) buildCrossroads2(c->mov[i]); + } + if(h/4 == 8 || h/4 == 10) + for(int i=0; itype; i++) { + if(c->mov[i] && c->mov[i]->landparam == h-4) { + bool oldleft = true; + for(int j=1; j<=3; j++) + if(c->mov[(i+j)%7] && c->mov[(i+j)%7]->mpdist < c->mpdist) + oldleft = false; + + c->landparam = h; + buildBarrierStrong(c, i, oldleft); + c->landparam = h; + extendBarrier(c); + } + } + } + } + +bool buildBarrierNowall(cell *c, eLand l2, bool force) { + + int dtab[3] = {0,1,6}; + + if(c->land == laNone) { + printf("barrier nowall! [%p]\n", c); + raiseBuggyGeneration(c, "barrier nowall!"); + return false; + } + + for(int i=0; i<3; i++) { + int d = dtab[i]; + if(force) d=1; + cellwalker cw(c, d); + + if(force || (checkBarriersNowall(cw, 0, -1) && checkBarriersNowall(cw, 0, 1))) { + eLand l1 = c->land; + checkBarriersNowall(cw, 0, -1, l1, l2); + checkBarriersNowall(cw, 0, 1, l1, l2); + extendBarrier(c); + return true; + } + } + + return false; + } + diff --git a/bigstuff.cpp b/bigstuff.cpp new file mode 100644 index 00000000..ebc3716e --- /dev/null +++ b/bigstuff.cpp @@ -0,0 +1,1029 @@ +// This file implements: +// * routines related to (horo)cycles +// * routines related to equidistants +// * 'setland' routines for other geometries +// * the buildBigStuff function which calls equidistant/(horo)cycle/barrier generators. + +#define UNKNOWN 65535 + +// horocycles + +int newRoundTableRadius() { + return 28 + 2 * items[itHolyGrail]; + } + +int getAnthraxData(cell *c, bool b) { + int d = celldistAlt(c); + int rad = 28 + 3 * anthraxBonus; + while(d < -rad) { + d += rad + 12; + rad += 3; + } + while(d >= 12) { + if(rad > 5) rad -= 3; + else if(rad) rad--; + d -= rad + 12; + } + if(b) return rad; + return d; + } + +int roundTableRadius(cell *c) { + if(euclid) return 28; + if(tactic::on) return getAnthraxData(c, true); + return c->master->alt->alt->emeraldval & GRAIL_RADIUS_MASK; + } + +int celldistAltRelative(cell *c) { + if(tactic::on) return getAnthraxData(c, false); + return celldistAlt(c) - roundTableRadius(c); + } + +int euclidAlt(short x, short y) { + if(specialland == laTemple || specialland == laClearing) { + return max(int(x), x+y); + } + else if(specialland == laCaribbean || specialland == laWhirlpool || specialland == laMountain) { + return + min( + min(max(int(-x), -x-y) + 3, + max(int(x+y), int(y)) + 3), + max(int(x), int(-y)) + 3 + ); + } + else if(specialland == laPrincessQuest) + return eudist(x-EPX, y-EPY); + else return eudist(x-20, y-10); + } + +const int NOCOMPASS = 1000000; + +int compassDist(cell *c) { + if(c->master->alt) return celldistAlt(c); + if(isHaunted(c->land) || c->land == laGraveyard) return getHauntedDepth(c); + return NOCOMPASS; + } + +cell *findcompass(cell *c) { + int d = compassDist(c); + if(d == NOCOMPASS) return NULL; + + while(inscreenrange(c)) { + generateAlts(c->master); + forCellEx(c2, c) if(compassDist(c2) < d) { + c = c2; + d = compassDist(c2); + goto nextk; + } + break; + nextk: ; + } + + return c; + } + +bool grailWasFound(cell *c) { + if(euclid) return items[itHolyGrail]; + return c->master->alt->alt->emeraldval & GRAIL_FOUND; + } + +void generateAlts(heptagon *h) { + if(!h->alt) return; + preventbarriers(h->c7); + for(int i=0; i<7; i++) preventbarriers(h->c7->mov[i]); + for(int i=0; i<7; i++) + createStep(h->alt, i)->alt = h->alt->alt; + int relspin = -4; // for horocycles it must go the other way + if(quotient) relspin = 0; + else { + for(int j=0; j<7; j++) for(int i=0; i<7; i++) { + createStep(h, i); + if(h->move[i]->alt == h->alt->move[j]) { + relspin = (i-j+7) % 7; + break; + } + } + if(relspin == -4 && quotient != 2) { + if(h->alt != h->alt->alt) { + printf("relspin {%p:%p}\n", h->alt, h->alt->alt); + {for(int i=0; i<7; i++) printf("%p ", h->alt->move[i]);} printf(" ALT\n"); + {for(int i=0; i<7; i++) printf("%p ", h->move[i]);} printf(" REAL\n"); + {for(int i=0; i<7; i++) printf("%p ", h->move[i]->alt);} printf(" REAL ALT\n"); + } + relspin = 3; + } } + // h[relspin] matches alt[0] +//printf("{%d~%d}\n", h->distance, h->alt->distance); + for(int i=0; i<7; i++) { + int ir = (7+i-relspin)%7; + heptagon *hm = h->alt->move[ir]; + heptagon *ho = createStep(h, i); +// printf("[%p:%d ~ %p:%d] %p ~ %p\n", +// h, i, h->alt, ir, +// ho, hm); + if(ho->alt && ho->alt != hm) { + if(ho->alt->alt == hm->alt && !quotient) { + printf("ERROR: alt cross! [%d -> %d]\n", ho->alt->distance, hm->distance); + // exit(1); + } + continue; + } + ho->alt = hm; + } + } + +heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special) { + + // check for direction + int gdir = -1; + for(int i=0; itype; i++) { + if(c->mov[i] && c->mov[i]->mpdist < c->mpdist) gdir = i; + } + if(gdir < 0) return NULL; + + // check for non-crossing + int bd = 2; + cellwalker bb(c, bd); + if(!(checkBarriersFront(bb) && checkBarriersBack(bb))) { + return NULL; + } + + // okay, let's go then! + cellwalker bf(c, gdir); + cell *cx[rad+1]; + for(int i=0; itype == 6) + cwspin(bf, 3); + else + cwspin(bf, 3 + hrand(2)); + cwstep(bf); + } + cx[rad] = bf.c; + heptagon *h = bf.c->master; + + if(special == waPalace) { + + // type 7 is ensured + cell *c = bf.c; + + if(cdist50(c) != 0) return NULL; + if(polarb50(c) != 1) return NULL; + } + + heptagon *alt = new heptagon; + allmaps.push_back(new hrmap_alternate(alt)); +//printf("new alt {%p}\n", alt); + alt->s = firststate; + alt->emeraldval = 0; + alt->zebraval = 0; + for(int i=0; i<7; i++) alt->move[i] = NULL; + alt->distance = 0; + alt->c7 = NULL; + alt->alt = alt; + h->alt = alt; + + for(int d=rad; d>=0; d--) { + generateAlts(cx[d]->master); + preventbarriers(cx[d]); + } + + if(special == waPalace) { + + cell *c = bf.c; + + princess::generating = true; + c->land = laPalace; + for(int j=BARLEV; j>=0; j--) + setdist(c, j, NULL); + princess::generating = false; + + princess::newInfo(c); + princess::forceMouse = false; + + if(princess::gotoPrincess && cheater) princess::gotoPrincess=false, cwt.c = c; + } + + return alt; +//for(int d=rad; d>=0; d--) printf("%3d. %p {%d}\n", d, cx[d]->master, cx[d]->master->alt->distance); + } + +void beCIsland(cell *c) { + int i = hrand(3); + if(i == 0) c->wall = waCIsland; + if(i == 1) c->wall = waCIsland2; + if(i == 2) c->wall = waCTree; + return; + } + +void generateTreasureIsland(cell *c) { + if(!euclid) generateAlts(c->master); + if(isOnCIsland(c)) return; + + bool src = hrand(100) < 10; + if(src) { + beCIsland(c); + if(c->wall == waCTree) return; + } + cell* ctab[7]; + int qc = 0, qlo, qhi; + for(int i=0; itype; i++) { + cell *c2 = createMov(c, i); + if(!euclid) generateAlts(c2->master); + if((euclid || (c->master->alt && c2->master->alt)) && celldistAlt(c2) < celldistAlt(c)) { + ctab[qc++] = c2; + qlo = i; qhi = i; + while(true) { + qlo--; + c2 = createMovR(c, qlo); + if(!euclid && !c2->master->alt) break; + if(celldistAlt(c2) >= celldistAlt(c)) break; + ctab[qc++] = c2; + } + while(true) { + qhi++; + c2 = createMovR(c, qhi); + if(!euclid && !c2->master->alt) break; + if(celldistAlt(c2) >= celldistAlt(c)) break; + ctab[qc++] = c2; + } + break; + } + } + if(!qc) { + printf("NO QC\n"); c->wall = waSea; + for(int i=0; itype; i++) printf("%d ", celldistAlt(c->mov[i])); + printf("vs %d\n", celldistAlt(c)); + return; + } + cell* c2 = createMovR(c, (qlo+qhi)/2); + generateTreasureIsland(c2); + if(!src) { + c->wall = c2->wall; + if(c->wall != waCTree && hrand(100) < 15) + c->wall = (c->wall == waCIsland ? waCIsland2 : waCIsland); + } + if(src && c2->wall == waCTree && (euclid||c->master->alt) && celldistAlt(c) <= -10) { + bool end = true; + for(int i=0; iwall != waCTree) + end = false; + } + // printf("%p: end=%d, qc=%d, dist=%d\n", c, end, qc, celldistAlt(c)); + if(end) c->item = itPirate; + else c->item = itCompass; + } + } + +// equidistants + +#define HAUNTED_RADIUS (purehepta?5:7) +extern bool generatingEquidistant; + +bool generatingEquidistant = false; + +cell *buildAnotherEquidistant(cell *c, int radius) { + int gdir = -1; + for(int i=0; itype; i++) { + if(c->mov[i] && c->mov[i]->mpdist < c->mpdist) gdir = i; + } + if(gdir == -1) return NULL; + + cellwalker cw(c, (gdir+3) % c->type); + vector coastpath; + while(size(coastpath) < radius || cw.c->type != 7) { + // this leads to bugs for some reason! + if(cw.c->land == laCrossroads2) { +#ifdef AUTOPLAY + if(doAutoplay) printf("avoiding the Crossroads II\n"); // todo +#endif + return NULL; + } + if(cw.c->bardir != NODIR) return NULL; + + /* forCellEx(c2, cw.c) if(c2->bardir != NODIR) { + generatingEquidistant = false; + return; + } */ + coastpath.push_back(cw.c); + if(cw.c->land == laNone && cw.c->mpdist <= 7) { + raiseBuggyGeneration(cw.c, "landNone 1"); + for(int i=0; iitem = itPirate; + return NULL; + } + cwstep(cw); cwspin(cw, 3); + if(cw.c->type == 7 && hrand(2) == 0) cwspin(cw, 1); + } + coastpath.push_back(cw.c); + // printf("setdists\n"); + for(int i=1; iland == laNone) { + raiseBuggyGeneration(cwt.c, "landNone 3"); + int mpd[10]; + for(int i=0; i<10; i++) mpd[i] = coastpath[i]->mpdist; + {for(int i=0; i<10; i++) printf("%d ", mpd[i]);} printf("\n"); + for(int i=0; iitem = itPirate; + return NULL; + } + setdist(coastpath[i], BARLEV, coastpath[i-1]); + setdist(coastpath[i], BARLEV-1, coastpath[i-1]); + if(i < size(coastpath) - 5) { + coastpath[i]->bardir = NOBARRIERS; +// coastpath[i]->item = itSapphire; +// forCellEx(c2, coastpath[i]) c2->bardir = NOBARRIERS; + } + } + + //printf("building barrier\n"); + cell *c2 = coastpath[coastpath.size() - 1]; + int bd = 2 + (hrand(2)) * 3; + + bool nowall = false; + + if(c2->land == laNone) { + raiseBuggyGeneration(c2, "landNone 2"); + for(int i=0; iitem = itPirate; + return NULL; + } + + // prevent gravity anomalies + if(c2->land != c->land) return NULL; + + // else if(c->type == 7 && hrand(10000) < 20 && !isCrossroads(c->land) && gold() >= 200) + if(c2->type == 7 && gold() >= R200 && hrand(10) < 2 && buildBarrierNowall(c2, laCrossroads4, true)) { + nowall = true; + // raiseBuggyGeneration(c2, "check"); + // return; + } + else buildBarrier(c2, bd); + //printf("building barrier II\n"); + if(hasbardir(c2)) extendBarrier(c2); + + for(int i=size(coastpath)-(nowall?1:2); i>=0; i--) { + for(int j=BARLEV; j>=6; j--) + setdist(coastpath[i], j, NULL); + } + + return c2; + } + +void buildAnotherEquidistant(cell *c) { + //printf("building another coast\n"); + + if(yendor::on) return; + + generatingEquidistant = true; + + int radius = c->land == laOcean ? 30 : HAUNTED_RADIUS + 5; + + buildAnotherEquidistant(c, radius); + + generatingEquidistant = false; + } + +int coastval(cell *c, eLand base) { + if(!c) return UNKNOWN; + if(c->land == laNone) return UNKNOWN; + if(base == laGraveyard) { + if(c->land == laHaunted || c->land == laHauntedWall) + return 0; + if(c->land != laGraveyard && c->land != laHauntedBorder) return 30; + } + else if(base == laMirrored) { + if(!inmirror(c)) return 0; + if(!c->landparam) return UNKNOWN; + return c->landparam & 255; + } + else { + if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool || + c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken) + return 30; + if(c->land != laOcean && !isGravityLand(c->land) && c->land != laHaunted) { + return 0; + } + } + if(!c->landparam) return UNKNOWN; + return c->landparam; + } + +bool checkInTree(cell *c, int maxv) { + if(c->landparam <= 3) return false; + if(!maxv) return false; + if(c->landflags) return true; + for(int t=0; ttype; t++) + if(c->mov[t] && c->mov[t]->landparam < c->landparam && checkInTree(c->mov[t], maxv-1)) + return true; + return false; + } + +void buildEquidistant(cell *c) { + if(!c) return; + if(c->landparam) return; + eLand b = c->land; + if(chaosmode && !inmirror(b)) return; + if(!b) { + printf("land missing at %p\n", c); + describeCell(c); + for(int i=0; itype; i++) if(c->mov[i]) + describeCell(c->mov[i]); + // buggycells.push_back(c); + } + if(b == laHauntedBorder) b = laGraveyard; + if(inmirror(b)) b = laMirrored; + int mcv = UNKNOWN; + + // find the lowest coastval + for(int i=0; itype; i++) { + int cv = coastval(createMov(c,i), b); + if(cv < mcv) mcv = cv; + } + + int mcv2 = 0; + + if(mcv == 0) { + // if(generatingEquidistant) printf("mcv=0\n"); + c->landparam = 1; + } + else { + // if it appears twice, increase it + int qcv = 0; + int sid = 0; + for(int i=0; itype; i++) + if(coastval(c->mov[i], b) == mcv) + qcv++, sid = i; + + // if(generatingEquidistant) printf("qcv=%d mcv=%d\n", qcv, mcv); + if(qcv >= 2) c->landparam = mcv+1; // (mcv == UNKNOWN ? UNKNOWN : mcv+1); + else { + // if(qcv != 1) { printf("qcv = %d\n", qcv); exit(1); } + cell *c2 = c->mov[sid]; + int bsid = c->spn(sid); + for(int j=0; j<7; j++) { + int q = (bsid+j+42) % c2->type; + cell *c3 = c2->mov[q]; + if(coastval(c3, b) < mcv) { + cell *c4 = createMovR(c2, bsid+1); + if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2); + buildEquidistant(c4); + mcv2 = coastval(c4, b); + break; + } + q = (bsid-j+42) % c2->type; + c3 = c2->mov[q]; + if(coastval(c3, b) < mcv) { + cell *c4 = createMovR(c2, bsid-1); + if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2); + buildEquidistant(c4); + mcv2 = coastval(c4, b); + break; + } + } + if(mcv2 > mcv) mcv2 = mcv; + if(mcv2 == 0) mcv2 = mcv; + c->landparam = mcv2+1; + + /* if(c->heat < 3) + raiseBuggyGeneration(c, "low heat"); */ + } + } + + if(!c->landparam) { + // int z = int(c->heat); + if(c->item || c->monst) + printf("building coast over %s/%s, mpdist = %d\n", iinf[c->item].name, minf[c->monst].name, + c->mpdist); + if(c->land == laOcean) c->wall = waSea; + } + + if(c->land == laEndorian) { + if(c->landparam == 1 && c->type == 7) { + for(int i=0; i<7; i++) { + int i1 = (i+1) % 7; + if(c->mov[i] && c->mov[i]->land != laEndorian && c->mov[i]->land != laNone) + if(c->mov[i1] && c->mov[i1]->land != laEndorian && c->mov[i1]->land != laNone) { + c->landflags = 2; + c->wall = waTrunk; + } + } + } + else if(c->landparam == 1 && c->type == 6) { + for(int i=0; i<6; i++) { + int i1 = (i+1) % 6; + int i2 = (i+2) % 6; + int i4 = (i+4) % 6; + int i5 = (i+5) % 6; + if(c->mov[i] && c->mov[i]->land == laBarrier && c->mov[i]->type == 7) + if(c->mov[i1] && c->mov[i1]->land != laBarrier) + if(c->mov[i2] && c->mov[i2]->land != laBarrier) + if(c->mov[i4] && c->mov[i4]->land != laBarrier) + if(c->mov[i5] && c->mov[i5]->land != laBarrier) { + c->landflags = 2; + c->wall = waTrunk; + } + + if(c->mov[i] && c->mov[i]->land != laEndorian && c->mov[i]->land != laNone && c->mov[i]->type == 7) + if(c->mov[i1] && c->mov[i1]->land != laEndorian && c->mov[i1]->land != laNone) + if(c->mov[i5] && c->mov[i5]->land != laEndorian && c->mov[i5]->land != laNone) { + c->landflags = 3; + c->wall = waTrunk; + } + } + } + else if(c->landparam > 1) { + for(int i=0; itype; i++) { + cell *c2 = c->mov[i]; + if(c2 && c2->landparam < c->landparam && c2->landflags) { + bool ok = false; + if(c2->landflags == 3) + ok = true; + else if(c2->landflags == 2) { + ok = c->mov[(i+1)%c->type]->landparam != c->landparam-1 + && c->mov[(i+c->type-1)%c->type]->landparam != c->landparam-1; + } + else for(int j=0; jtype; j++) { + cell *c3 = c2->mov[j]; + if(c3 && c3->landparam < c2->landparam && c3->landflags) + if(c->spn(i) == (j+3)%c2->type || c->spn(i) == (j+c2->type-3)%c2->type) + ok = true; + } + if(ok) { + c->wall = waTrunk; + c->landflags = 1; + } + } + if(c2 && c2->landparam < c->landparam && c2->landflags == 1 && c->type == 7) { + cell *c3 = c->mov[(i+1)%7]; + if(c3 && c3->landparam < c->landparam && c3->landflags == 1) { + c->wall = waTrunk; + c->landflags = 2; + } + } + } + + if(!c->landflags && checkInTree(c, 5)) { + int lev = hrand(100); + if(lev < 10) c->wall = waSolidBranch; + else if(lev < 20) c->wall = waWeakBranch; + else c->wall = waCanopy; + } + } + } + + if(c->landparam > 30 && b == laOcean && !generatingEquidistant && hrand(10) < 5) + buildAnotherEquidistant(c); + + if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && hrand(100) < (purehepta?25:5) && items[itBone] >= 10) + buildAnotherEquidistant(c); + } + +cell *randomDown(cell *c) { + cell *tab[7]; + int q=0; + for(int i=0; itype; i++) + if(c->mov[i] && coastval(c->mov[i], laIvoryTower) < coastval(c, laIvoryTower)) + tab[q++] = c->mov[i]; + if(!q) return NULL; + if(q==1) return tab[0]; + return tab[hrand(q)]; + } + +// which=1 => right, which=-1 => left +// set which=1,bonus=1 to get right neighbor on level + +typedef int cellfunction(cell*); + +cell *chosenDown(cell *c, int which, int bonus, cellfunction* cf) { + int d = (*cf)(c)-1; + for(int i=0; itype; i++) { + if(!c->mov[i]) createMov(c, i); + if(c->mov[i]->mpdist > BARLEV && cf == coastvalEdge) setdist(c->mov[i], BARLEV, c); + + if((*cf)(c->mov[i]) == d) { + int i2 = (i+which+42)%c->type; + createMov(c, i2); + if((*cf)(c->mov[i2]) == d) + return createMovR(c, i2+bonus); + else return createMovR(c, i+bonus); + } + } + // printf("nothing down here\n"); + return NULL; + } + +int edgeDepth(cell *c) { + if(c->land == laIvoryTower || c->land == laEndorian || c->land == laDungeon) + return coastvalEdge(c); + else if(c->land != laBarrier) { + for(int i=0; itype; i++) if(c->mov[i] && c->mov[i]->land == laBarrier) + return -20+c->cpdist; + } + return 0; + } + +int getHauntedDepth(cell *c) { + if((tactic::on || euclid) && c->land == laHaunted) return celldist(c); + if(c->land == laHaunted) return c->landparam; + if(c->land == laHauntedWall) return 0; + if(c->land == laHauntedBorder || c->land == laGraveyard) return -c->landparam; + return -100; + } + +int towerval(cell *c, cellfunction* cf) { + // if(c->land != laEdge) return 0; + cell *cp1 = chosenDown(c, 1, 1, cf); + if(!cp1) return 0; + /* cell *cp2 = chosenDown(cp1, 1, 1); + if(!cp2) return 0; + cell *cm1 = chosenDown(c, -1, -1); + if(!cm1) return 0; + cell *cm2 = chosenDown(cm1, -1, -1); + if(!cm2) return 0; */ + + /* return + (c->type-6) + + 2*(cp1->type-6) + 4*(cp2->type-6) + + 8*(cm1->type-6) +16*(cm2->type-6); */ + + int under = 0; + int cfc = (*cf)(c); + for(int i=0; itype; i++) { + if(c->mov[i] && (*cf)(c->mov[i]) < cfc) + under++; + } + return (c->type-6) + 2*(cp1->type-6) + 4*under; + } + +/* other geometries */ + +void setLandQuotient(cell *c) { + int fv = zebra40(c); + if(fv/4 == 4 || fv/4 == 6 || fv/4 == 5 || fv/4 == 10) fv ^= 2; + if(specialland == laWarpCoast) + if(fv%4==0 || fv%4 == 2) setland(c, laWarpSea); + if(specialland == laElementalWall) + setland(c, eLand(laEFire + (fv%4))); + } + +void setLandSphere(cell *c) { + if(specialland == laWarpCoast) + setland(c, getHemisphere(c, 0) > 0 ? laWarpCoast : laWarpSea); + if(specialland == laElementalWall) { + int x = getHemisphere(c, 1); + int y = getHemisphere(c, 2); + if(x > 0 && y > 0) setland(c, laEFire); + else if(x > 0 && y < 0) setland(c, laEAir); + else if(x < 0 && y < 0) setland(c, laEWater); + else if(x < 0 && y > 0) setland(c, laEEarth); + else if(x > 0) + c->land = laElementalWall, c->barleft = laEAir, c->barright = laEFire; + else if(x < 0) + c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEWater; + else if(y > 0) + c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEFire; + else if(y < 0) + c->land = laElementalWall, c->barleft = laEAir, c->barright = laEWater; + if(c->land == laElementalWall && c->type != 6) + c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright); + } + if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3) { + int x = getHemisphere(c, 1); + if(x == 0 || (specialland == laCrossroads3 && getHemisphere(c, 2) == 0)) + setland(c, laBarrier), c->wall = waBarrier; + else setland(c, specialland); + if(specialland == laCrossroads3 && c->type != 6 && c->master->fiftyval == 1) + c->wall = waBigTree; + } + } + +eLand euland[65536]; + +eLand switchable(eLand nearland, eLand farland, eucoord c) { + if(specialland == laCrossroads4) { + if(hrand(15) == 0) + return getNewLand(nearland); + return nearland; + } + else if(nearland == laCrossroads) { + if(hrand(4) == 0 && (short(c)%3==0)) + return laBarrier; + return laCrossroads; + } + else if(nearland == laBarrier) { + return getNewLand(farland); + } + else { + if(hrand(20) == 0 && (short(c)%3==0)) + return laBarrier; + return nearland; + } + } + +eLand getEuclidLand(eucoord c) { + if(euland[c]) return euland[c]; + if(c == 0 || c == eucoord(-1) || c == 1) + return euland[c] = specialland; + if(euland[eucoord(c-2)] && ! euland[eucoord(c-1)]) getEuclidLand(c-1); + if(euland[eucoord(c+2)] && ! euland[eucoord(c+1)]) getEuclidLand(c+1); + if(euland[eucoord(c-1)]) return + euland[c] = switchable(euland[c-1], euland[eucoord(c-2)], c); + if(euland[eucoord(c+1)]) return + euland[c] = switchable(euland[c+1], euland[eucoord(c+2)], c); + return euland[c] = laCrossroads; + } + +void setLandEuclid(cell *c) { + setland(c, specialland); + if(specialland == laCrossroads) { + eucoord x, y; + decodeMaster(c->master, x, y); + setland(c, getEuclidLand(y+2*x)); + } + if(specialland == laCrossroads4) { + eucoord x, y; + decodeMaster(c->master, x, y); + c->land = getEuclidLand(y); + } + if(specialland == laWhirlpool) { + c->land = laOcean; + c->landparam = 99; + } + if(specialland == laPrincessQuest) setland(c, laPalace); + if(specialland == laOcean) { + eucoord x, y; + decodeMaster(c->master, x, y); + int y0 = y; if(y>50000) y0 -= 65536; y0 += 10; + if(y0 == 0) + { setland(c, laBarrier); if(ishept(c)) c->land = laRlyeh; } + else if(y0<0) setland(c, laRlyeh); + else c->landparam = y0; + } + if(specialland == laIvoryTower || specialland == laDungeon) { + eucoord x, y; + decodeMaster(c->master, x, y); + int y0 = y; if(y>50000) y0 -= 65536; y0 = -y0; y0 -= 5; + if(y0 == 0) + {setland(c, laBarrier); if(ishept(c)) setland(c, laAlchemist); } + else if(y0<0) setland(c, laAlchemist); + else { + c->landparam = y0; + } + } + if(specialland == laElementalWall) { + eucoord x, y; + decodeMaster(c->master, x, y); + int y0 = y; if(y>32768) y0 -= 65536; + int x0 = x +y/2; + + int id = 0; + if(y0&16) id += 2; + if(x0&16) id += 1; + + x0 += 8; y0 += 8; + + y0--; x0++; + int id2 = 0; + if(y0&16) id2 += 2; + if(x0&16) id2 += 1; + + setland(c, eLand(laEFire + id)); + + if(((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) { + if(c->land == laEFire) c->wall = waEternalFire; + if(c->land == laEWater) c->wall = waSea; + if(c->land == laEAir) c->wall = waChasm; + if(c->land == laEEarth) c->wall = waStone; + c->barright = c->land; + c->barleft = eLand(laEFire+id2); + setland(c, laElementalWall); + } + } + if(specialland == laCrossroads3) { + eucoord x, y; + decodeMaster(c->master, x, y); + int y0 = y; if(y>32768) y0 -= 65536; + int x0 = x +y/2; + + x0 += 24; y0 += 8; + + int id = 0; + if(y0&16) id ^= 1; + if(x0&16) id ^= 1; + + setland(c, id ? laCrossroads3 : laDesert); + + if(((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) { + setland(c, laBarrier); + c->wall = waBarrier; + } + } + if(specialland == laWarpCoast) { + eucoord x, y; + decodeMaster(c->master, x, y); + + int zz = 2*short(x)+short(y) + 10; + zz %= 30; if(zz<0) zz += 30; + if(zz >= 15) + setland(c, laWarpSea); + else + setland(c, laWarpCoast); + } + } + +// the main big stuff function + +bool quickfind(eLand l) { + if(l == cheatdest) return true; +#if CAP_TOUR + if(tour::on && tour::quickfind(l)) return true; +#endif + return false; + } + +#define INVLUCK (items[itOrbLuck] && inv::on) +#define I2000 (INVLUCK?600:2000) +#define I10000 (INVLUCK?3000:10000) + +void buildBigStuff(cell *c, cell *from) { + if(sphere || quotient) return; + bool deepOcean = false; + + if(c->land == laOcean) { + if(!from) deepOcean = true; + else for(int i=0; itype; i++) { + cell *c2 = from->mov[i]; + if(c2 && c2->land == laOcean && c2->landparam > 30) { + deepOcean = true; + } + if(c2) forCellEx(c3, c2) if(c3 && c3->land == laOcean && c3->landparam > 30) + deepOcean = true; + } + } + + if(c->land == laGraveyard) { + if(!from) deepOcean = true; + else for(int i=0; itype; i++) { + cell *c2 = from->mov[i]; + if(c2 && c2->landparam > HAUNTED_RADIUS+5) + deepOcean = true; + } + } + + if(generatingEquidistant) deepOcean = false; + + // buildgreatwalls + + if(chaosmode) { + if(c->type == 7 && hrand(10000) < 9000 && c->land && !inmirror(c) && buildBarrierNowall(c, getNewLand(c->land))) + {} + else if(c->type == 7 && c->land == laMirror && hrand(10000) < 2000) { + int bd = 2 + hrand(2) * 3; + buildBarrier(c, bd, laMirrored); + } + } + + else if(c->type == 7 && isWarped(c->land) && hrand(10000) < 3000 && c->land && + buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) ; + + else if(c->type == 7 && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && + buildBarrierNowall(c, getNewLand(laCrossroads4))) ; + + else if(c->type == 7 && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= R200 && + !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) && + (c->land != laRlyeh || rlyehComplete()) && + c->land != laTortoise && c->land != laPrairie && c->land && + !(c->land == laGraveyard && !deepOcean) + && c->land != laCanvas + ) { + buildBarrierNowall(c, laCrossroads4) ; + } + + else if(c->land == laCrossroads2 && !purehepta) + buildCrossroads2(c); + + else if(c->land == laPrairie && c->LHU.fi.walldist == 0) { + for(int bd=0; bd<7; bd++) { + int fval2 = createStep(c->master, bd)->fieldval; + int wd = fp43.gmul(fval2, fp43.inverses[c->fval-1]); + if(fp43.distwall[wd] == 0) { + buildBarrier(c, bd); + break; + } + } + } + + else if(c->type == 7 && c->land && hrand(I10000) < ( + showoff ? (cwt.c->mpdist > 7 ? 0 : 10000) : + inmirror(c) ? 0 : + isGravityLand(c->land) ? 0 : + generatingEquidistant ? 0 : + c->land == laPrairie ? 0 : + (yendor::on && yendor::nexttostart) ? 10000 : + princess::challenge ? 0 : + isElemental(c->land) ? 4000 : + (yendor::on && (yendor::generating || !(yendor::clev().flags & YF_WALLS))) ? 0 : + c->land == laCrossroads3 ? 10000 : + c->land == laCrossroads ? 5000 : + c->land == laCrossroads2 ? 10000 : + c->land == laCrossroads5 ? 10000 : + c->land == laCrossroads4 ? 0 : + (c->land == laMirror && !yendor::generating) ? 6000 : + c->land == laTerracotta ? 250 : + (tactic::on && !tactic::trailer) ? 0 : + c->land == laCaribbean ? 500 : + (c->land == laWarpSea || c->land == laWarpCoast) ? 500 : + c->land == laStorms ? 250 : + c->land == laCanvas ? 0 : + c->land == laHaunted ? 0 : + (c->land == laGraveyard && !deepOcean) ? 0 : + (c->land == laGraveyard && items[itBone] >= 10) ? 120 : + c->land == laOcean ? (deepOcean ? (purehepta ? 250 : 2000) : 0) : + c->land == laDragon ? 120 : + 50)) + { + + int bd = 2 + hrand(2) * 3; + + buildBarrier(c, bd); + + /* int bd = 2; + buildBarrier4(c, bd, 0, getNewLand(c->land), c->land); */ + } + + if((!chaosmode) && bearsCamelot(c->land) && c->type == 7 && + (quickfind(laCamelot) || peace::on || (hrand(I2000) < 200 && + items[itEmerald] >= U5 && !tactic::on))) { + int rtr = newRoundTableRadius(); + heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin); + if(alt) { + alt->emeraldval = rtr; + alt->fiftyval = c->land; + } + } + + if(!chaosmode) { + + // buildbigstuff + + if(c->land == laRlyeh && c->type == 7 && + (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && + items[itStatue] >= U5 && !randomPatternsMode && + !tactic::on && !yendor::on))) + createAlternateMap(c, 2, hsA); + + if(c->land == laJungle && c->type == 7 && + (quickfind(laMountain) || (hrand(I2000) < 100 && + !randomPatternsMode && !tactic::on && !yendor::on && landUnlocked(laMountain)))) + createAlternateMap(c, 2, hsA); + + if(c->land == laOvergrown && c->type == 7 && + (quickfind(laClearing) || (hrand(I2000) < 25 && + !randomPatternsMode && items[itMutant] >= U5 && + !tactic::on && !yendor::on))) { + heptagon *h = createAlternateMap(c, 2, hsA); + if(h) clearing::bpdata[h].root = NULL; + } + + if(c->land == laStorms && c->type == 7 && hrand(2000) < 1000 && !randomPatternsMode) { + heptagon *h = createAlternateMap(c, 2, hsA); + if(h) h->alt->emeraldval = hrand(2); + } + + if(c->land == laOcean && c->type == 7 && deepOcean && !generatingEquidistant && !peace::on && + (quickfind(laWhirlpool) || ( + hrand(2000) < (purehepta ? 500 : 1000) && !tactic::on && !yendor::on))) + createAlternateMap(c, 2, hsA); + + if(c->land == laCaribbean && c->type == 7) + createAlternateMap(c, 2, hsA); + + if(c->land == laPalace && c->type == 7 && !princess::generating && !shmup::on && multi::players == 1 && + (princess::forceMouse ? (from && from->pathdist != INF) : + (hrand(2000) < (peace::on ? 100 : 20))) && + !c->master->alt && + (princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) { + createAlternateMap(c, PRADIUS0, hsOrigin, waPalace); + celllister cl(c, 5, 1000000, NULL); + for(cell *c: cl.lst) if(c->master->alt) generateAlts(c->master); + } + } + + if(hasbardir(c)) extendBarrier(c); + } + +bool openplains(cell *c) { + celllister cl(c, purehepta ? 5 : 7, 1000000, NULL); + for(cell *c: cl.lst) { + while(c->mpdist > 8) setdist(c, c->mpdist-1, NULL); + if(c->land != laDogPlains) return false; + } + return true; + } + +void doOvergenerate() { + int dcs = size(dcal); + for(int i=0; icpdist <= sightrange-6) setdist(c, 1, NULL); + } + } diff --git a/complex.cpp b/complex.cpp index 8aeb04f7..25316081 100644 --- a/complex.cpp +++ b/complex.cpp @@ -1,7 +1,7 @@ // Hyperbolic Rogue // namespaces for complex features (whirlwind, whirlpool, elec, princess, clearing, -// mirror, hive, heat + livecaves) +// mirror, hive, heat + livecaves, etc.) // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details @@ -1411,6 +1411,20 @@ namespace mirror { namespace hive { + int hivehard() { + return items[itRoyalJelly] + hardness_empty(); + // 0, 5, 40, 135 + } + + eMonster randomHyperbug() { + int h = hivehard(); + if(hrand(200) < h) + return moBug2; + return eMonster(moBug0 + hrand(BUGCOLORS)); + // 50: 25/25/50 + // 100: + } + struct buginfo_t { cell *where; short dist[BUGCOLORS]; @@ -3075,5 +3089,510 @@ namespace windmap { return windmap::windcodes[windmap::getId(c)]; } - }; + } +// Halloween namespace + +namespace halloween { + cell *dragoncells[4]; + vector srch; + + cell *farempty(bool lastresort = false) { + int maxdist = 0; + vector validcells; + int firstfar1 = 0; + for(int i=1; iitem == itNone && dcal[i]->monst == moNone && dcal[i]->wall == waNone; + if(lastresort) + okay = dcal[i]->wall != waChasm && !isMultitile(dcal[i]->monst); + if(okay) { + if(dcal[i]->cpdist > maxdist) + firstfar1 = size(validcells), + maxdist = dcal[i]->cpdist; + validcells.push_back(dcal[i]); + } + } + + int qvc = size(validcells); + if(qvc == firstfar1) return farempty(true); + + return validcells[firstfar1 + hrand(qvc - firstfar1)]; + } + + int demoncount; + int swordpower; + int dragoncount; + + void reset() { + demoncount = 0; + swordpower = 0; + dragoncount = 0; + } + + eMonster nextDemon() { + demoncount++; + if(demoncount % 9 == 0) return moGreater; + return moLesser; + } + + void putMonster(eMonster m) { + cell *c = farempty(); + c->hitpoints = 3; + c->monst = m; + playSeenSound(c); + if(!kills[m]) switch(m) { + case moGhost: + addMessage(XLAT("Ghosts can move through chasms!")); + break; + case moSkeleton: + addMessage(XLAT("Push Skeletons into the holes!")); + break; + case moDraugr: + addMessage(XLAT("You'll need your magical sword against the Draugar!")); + break; + case moLesser: + addMessage(XLAT("Demons are slow, but you'll need the experience against stronger ones...")); + break; + case moGreater: + addMessage(XLAT("You will need more experience to defeat the Greater Demon!")); + break; + case moPyroCultist: + addMessage(XLAT("Cultists throw fire at you from distance!")); + break; + case moFlailer: + addMessage(XLAT("Defeat Flail Guards by moving away from them.")); + break; + case moVampire: + addMessage(XLAT("Vampire Bats drain your magical powers!")); + break; + default: break; + } + c->stuntime = 2; + } + + void getTreat(cell *where) { + if(!items[itTreat]) reset(); + gainItem(itTreat); + farempty()->item = itTreat; + int itr = items[itTreat]; + items[itOrbTime] += 30; + int monpower = 19 + itr + hrand(itr); + int mcount = 0; + while(monpower > 0) { + int id = hrand(10000); + +#define CHANCE(x) (id -= x, id < 0) + if(CHANCE(400) && itr >= 5) { + putMonster(moGhost); + monpower -= 30; + mcount++; + } + else if(CHANCE(400)) { + putMonster(pick(moWitch, moZombie)); + monpower -= 20; + mcount++; + } + else if(CHANCE(400) && itr >= 5) { + putMonster(nextDemon()); + monpower -= 10; + mcount++; + } + else if(CHANCE(100) && itr >= 12) { + putMonster(moVampire); + monpower -= 10; + swordpower -= 5; + if(swordpower < 0) swordpower = 0; + mcount++; + } + else if(CHANCE(400) && swordpower > 0 && !mcount && itr >= 15) { + putMonster(moDraugr); + swordpower -= 3; + monpower -= 100; + mcount++; + } + else if(CHANCE(400) && itr >= 10 && !mcount && itr >= 10) { + putMonster(moSkeleton); + monpower -= 60; + mcount++; + } + else if(CHANCE(10) && itr >= 15) { + putMonster(moWitchFire); + monpower -= 35; + mcount++; + } + else if(CHANCE(100) && itr >= 5) { + putMonster(moFlailer); + monpower -= 35; + mcount++; + } + else if(CHANCE(100) && itr >= 5) { + putMonster(moPyroCultist); + monpower -= 35; + mcount++; + } + else if(CHANCE(5) && itr >= 20 && kills[moSkeleton]) { + putMonster(moFatGuard); + monpower -= 35; + mcount++; + } + else if(CHANCE(5) && itr >= 30 && kills[moFlailer]) { + putMonster(moHedge); + monpower -= 35; + mcount++; + } + else if(CHANCE(5) && itr >= 40 && kills[moHedge]) { + putMonster(moLancer); + monpower -= 60; + mcount++; + } + else if(CHANCE(1) && itr >= 50 && kills[moHedge]) { + putMonster(moFireFairy); + monpower -= 40; + mcount++; + } + else if(CHANCE(5) && itr >= 60) { + putMonster(moBomberbird); + monpower -= 25; + mcount++; + } + else if(CHANCE(5) && itr >= 60) { + putMonster(moRatlingAvenger); + monpower -= 30; + mcount++; + } + else if(CHANCE(5) && itr >= 60) { + putMonster(moVineBeast); + monpower -= 30; + mcount++; + } + else if(CHANCE(5) && itr >= 60) { + dragoncount++; + } + else if(dragoncount && !purehepta && !mcount) { + bool fill = false; + for(int i=0; i<4; i++) + if(!dragoncells[i] || dragoncells[i]->monst) + fill = true; + swap(dragoncells[0], dragoncells[3]); + swap(dragoncells[1], dragoncells[2]); + if(fill) continue; + for(int i=0; i<4; i++) { + dragoncells[i]->monst = i ? moDragonTail : moDragonHead; + dragoncells[i]->mondir = i==3 ? NODIR : neighborId(dragoncells[i], dragoncells[i+1]); + dragoncells[i]->hitpoints = 1; + dragoncells[i]->stuntime = 1; + playSeenSound(dragoncells[i]); + } + monpower -= 200; + mcount++; + dragoncount--; + } + } + int id = hrand(100); + if(items[itTreat] == 1) { +#if ISMOBILE==0 + addMessage(XLAT("Hint: use arrow keys to scroll.")); +#endif + } + else if(items[itTreat] == 2) { +#if ISMOBILE==0 + addMessage(XLAT("Hint: press 1 2 3 4 to change the projection.")); +#endif + } + else if(items[itTreat] == 3) { + items[itOrbShell] += 20; + addMessage(XLAT("You gain a protective Shell!")); + } + else if(items[itTreat] == 4) { + items[itOrbShell] += 10; + addMessage(XLAT("Hint: magical powers from Treats expire after a number of uses.")); + } + else if(kills[moSkeleton] && CHANCE(10)) { + addMessage(XLAT("A magical energy sword. Don't waste its power!")); + items[itOrbSword] += 5; // todo facing + swordpower += 5; + } + else if(kills[moDraugr] && items[itOrbSword] && CHANCE(10)) { + addMessage(XLAT("Another energy sword!")); + items[itOrbSword2] += 5; + swordpower += 5; + } + else if(kills[moFlailer] && CHANCE(10)) { + items[itOrbThorns] += 5; + addMessage(XLAT("You got Thorns! Stab monsters by moving around them.")); + } + else if(kills[moGhost] && CHANCE(10)) { + items[itOrbAether] += 5; + addMessage(XLAT("Aethereal powers let you go through the holes.")); + } + else { + if(items[itOrbShell] > ORBBASE) + addMessage(XLAT("The tasty treat increases your protection.")); + else + addMessage(XLAT("You gain your protective Shell back!")); + items[itOrbShell] += 5; + } + } + } + +// ... also includes the Ivory Tower + +namespace dungeon { + + void buildIvoryTower(cell *c) { + /* if(int(c->landparam) % 5 == 0) + c->wall = waCamelot; + */ + + if(euclid) { + eucoord x, y; + decodeMaster(c->master, x, y); + string tab[] = { + ".####...", + "L...L...", + ".L..L...", + "L...L...", + "........", + "........" + }; + int y0 = y; if(y>32768) y0 -= 65536; + + y0 += 5; y0 %= 12; if(y0<0) y0+=12; + + if(y0 >= 6) { y0 -= 6; x += 4; } + + char ch = tab[y0][(x+(y+1)/2)&7]; + + if(ch == '#') + c->wall = waPlatform; + else if(ch == 'L') + c->wall = waLadder; + } + + else if(true) { + + cell *c2 = c; + cell *c3 = c; + + bool rdepths[5]; + for(int i=0; i<5; i++) { + if(coastvalEdge(c2) == 0) { + rdepths[i] = false; + } + else { + cell *c4 = c2; + if(c2 != c3 && !isNeighbor(c2, c3)) { + for(int i=0; itype; i++) if(c2->mov[i] && isNeighbor(c2->mov[i], c3)) + c4 = c2->mov[i]; + } + rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3); + c2 = chosenDown(c2, 1, 0); // if(!c2) break; + c3 = chosenDown(c3, -1, 0); + if(!c2) { raiseBuggyGeneration(c, "ivory c2"); return; } + if(!c3) { raiseBuggyGeneration(c, "ivory c3"); return; } + } + } + + if(rdepths[3]) { + c->wall = waPlatform; + // if(!c4->item) c4->item = itPalace; + } + else if(!rdepths[2] && !rdepths[4] && !rdepths[1]) { + c2 = c; + c3 = c; + cell *c4 = chosenDown(c, 1, 1); + cell *c5 = chosenDown(c, -1, -1); + for(int i=0; i<3; i++) { + if(coastvalEdge(c2) == 0) break; + if(c2 && c4 && c4->landflags == 3 && c2->landflags != 3 && c4 == chosenDown(c2, 1, 1)) + c->wall = waLadder; + if(c3 && c5 && c5->landflags == 3 && c3->landflags != 3 && c5 == chosenDown(c3, -1, -1)) + c->wall = waLadder; + buildEquidistant(c4); buildEquidistant(c5); + if(c2) c2 = chosenDown(c2, 1, 0); + if(c3) c3 = chosenDown(c3, -1, 0); + if(c4) c4 = chosenDown(c4, 1, 0); + if(c5) c5 = chosenDown(c5, -1, 0); + } + } + } + else c->wall = waCIsland; + } + + int dungeonFlags(cell *c) { + if(!c) return 0; + buildEquidistant(c); + bool rdepths[5]; + + cell *c2 = c; + cell *c3 = c; + + int switchcount = 0; + for(int i=0; i<5; i++) { + if(coastvalEdge(c2) == 0) { + rdepths[i] = false; + } + else { + cell *c4 = c2; + if(c2 != c3 && !isNeighbor(c2, c3)) { + for(int i=0; itype; i++) if(c2->mov[i] && isNeighbor(c2->mov[i], c3)) + c4 = c2->mov[i]; + } + rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3); + if((c2&&c2->landflags == 1) || (c3&&c3->landflags == 1) || (c4&&c4->landflags == 1)) + switchcount++; + c2 = chosenDown(c2, 1, 0); // if(!c2) break; + c3 = chosenDown(c3, -1, 0); + if(!c2) { raiseBuggyGeneration(c, "ivory c2"); return 0; } + if(!c3) { raiseBuggyGeneration(c, "ivory c3"); return 0; } + } + } + + int res = 0; + + if(rdepths[3]) res |= 1; + if(rdepths[2]) res |= 2; + if(switchcount&1) res |= 4; + + return res; + } + + void placeGate(cell *c, eWall w) { + if(w == waOpenGate) { + c->wall = waClosedGate; + toggleGates(c, waOpenPlate, 0); + } + if(w == waClosedGate) { + c->wall = waOpenGate; + toggleGates(c, waClosePlate, 0); + } + } + + bool isGate(eWall w) { + return w == waOpenGate || w == waClosedGate; + } + + void placeRandomGate(cell *c) { + placeGate(c, hrand(2) ? waOpenGate : waClosedGate); + } + + void build(cell *c) { + /* if(int(c->landparam) % 5 == 0) + c->wall = waCamelot; + */ + + if(true) { + + if(coastvalEdge(c) == 1) forCellEx(c2, c) + if(c2->land != laBarrier && c2->land != laDungeon) { + c->wall = waLadder; + c->wparam = 3; + } + + int df = dungeonFlags(c); + + if(df&1) { + int df1 = dungeonFlags(chosenDown(c,1,1)); + int df2 = dungeonFlags(chosenDown(c,-1,-1)); + + c->wparam = 0; + if(hrand(100) < (c->landparam % 5 == 0 ? 80 : 20)) { + if(!(df1&1)) c->wparam = 1; + if(!(df2&1)) c->wparam = 2; + } + + if(df&4) + placeRandomGate(c); + else if(c->wparam == 0 && c->landparam % 5 == 0 && hrand(100) < 10) { + c->wall = waLadder; + c->wparam = 3 + hrand(2); + } + else + c->wall = waPlatform; + } + + if(c->wparam) { + /* int q = 0; + cell* downs[7]; + forCellEx(c2, c) { + buildEquidistant(c2); + if(coastvalEdge(c2) > coastvalEdge(c)) downs[q++] = c2; + } + if(q) downs[hrand(q)]->wall = waLadder; + */ + cell *c2 = + c->wparam == 1 ? chosenDown(c, 1, 2) : + c->wparam == 2 ? chosenDown(c, -1, -2) : + c->wparam == 3 ? chosenDown(c, 1, 3) : + c->wparam == 4 ? chosenDown(c, -1, -3) : + NULL; + + if(c2) { + c2->wall = c->wall, c2->wparam = c->wparam; + if(c2->wall == waPlatform && hrand(10) < 2) + placeRandomGate(c2); + if(isGate(c2->wall) && hrand(10) < 2) + c2->wall = waPlatform; + } + } + } + else c->wall = waCIsland; + } + + void buildPlates(cell *c) { + if(c->wall) return; + int neargate = 0; + int neargateDown = 0; + int neargateEq = 0; + int qup = 0; + forCellEx(c2, c) { + int d = coastvalEdge(c2) - coastvalEdge(c); + if(isGate(c2->wall)) { + neargate++; + if(d>0) neargateDown++; + if(d==0) neargateEq = 0; + } + if(d<0) qup++; + } + + if(!neargate) return; + + int hr = 99; + + if(neargate == neargateDown && qup == 1) + hr = hrand(12); + else if((zebra40(c) >= 40) && !(neargateEq && neargateDown)) + hr = hrand(36); + else if(zebra40(c) >= 40) + hr = hrand(5000); + + if(hr < 5) c->wall = waClosePlate; + else if(hr < 10) c->wall = waOpenPlate; + } + + bool is02(int i) { return i == 0 || i == 2; } + + void all(cell *c, int d) { + if(d == 8 && (c->land == laIvoryTower || c->land == laDungeon) && !euclid) { + + if(hrand(1000) < 75 && (c->landparam & 1) ) { + c->landflags = 3; + } + else c->landflags = 0; + } + + if(d == 8 && c->land == laDungeon && !euclid) { + if(hrand(1000) < 240 && is02(c->landparam%5) ) { + c->landflags = 3; + } + else if(hrand(1000) < 90) + c->landflags = 1; + else c->landflags = 0; + } + + if(d == 7 && c->land == laIvoryTower) buildIvoryTower(c); + if(d == 8 && c->land == laDungeon) build(c); + if(d == 7 && c->land == laDungeon) buildPlates(c); + } + } diff --git a/debug.cpp b/debug.cpp index 590d9fa2..8e8f0512 100644 --- a/debug.cpp +++ b/debug.cpp @@ -1,3 +1,49 @@ +int steplimit = 0; +int cstep; + +template +void limitgen(T... args) { + if(steplimit) { + cstep++; + printf("%6d ", cstep); + printf(args...); + if(cstep == steplimit) buggyGeneration = true; + } + } + +vector buggycells; + +cell *pathTowards(cell *pf, cell *pt) { + + while(celldist(pt) > celldist(pf)) { + if(isNeighbor(pf, pt)) return pt; + cell *pn = NULL; + forCellEx(pn2, pt) if(celldist(pn2) < celldist(pt)) pn = pn2; + pt = pn; + } + + if(isNeighbor(pf, pt)) return pt; + forCellEx(pn2, pt) if(celldist(pn2) < celldist(pt)) return pn2; + return NULL; + } + +bool buggyGeneration = false; + +bool errorReported = false; + +void describeCell(cell *c) { + if(!c) { printf("NULL\n"); return; } + printf("describe %p: ", c); + printf("%-15s", linf[c->land].name); + printf("%-15s", winf[c->wall].name); + printf("%-15s", iinf[c->item].name); + printf("%-15s", minf[c->monst].name); + printf("LP%08x", c->landparam); + printf("D%3d", c->mpdist); + printf("MON%3d", c->mondir); + printf("\n"); + } + static int orbid = 0; void debugScreen(); diff --git a/hyper.h b/hyper.h index f61b19b2..1dffeddd 100644 --- a/hyper.h +++ b/hyper.h @@ -505,8 +505,6 @@ eLand randomElementalLand(); extern eLand euland[65536]; bool notDippingForExtra(eItem i, eItem x); void placePrizeOrb(cell *c); -int hivehard(); -eMonster randomHyperbug(); void wandering(); bool isSealand(eLand l); int newRoundTableRadius(); @@ -1554,3 +1552,26 @@ void sideAttack(cell *mf, int dir, eMonster who, int bonuskill); void warpfloor(cell *c, const transmatrix& V, int col, int prio, bool warp); void orboflava(int i); + +void setland(cell *c, eLand l); + +eLand getNewLand(eLand old); + +extern bool randomPatternsMode; + +extern int isRandland(eLand l); + +extern vector buggycells; + +extern bool landUnlocked(eLand l); + +extern void describeCell(cell*); +extern bool rlyehComplete(); + +template void limitgen(T... args); +eLand oppositeElement(eLand l, eLand l2); + +extern int hardness_empty(); +extern eWall getElementalWall(eLand l); + +void gainItem(eItem it); diff --git a/init.cpp b/init.cpp index a62e68cf..ccbf1652 100644 --- a/init.cpp +++ b/init.cpp @@ -344,6 +344,11 @@ const char *loadlevel = NULL; #include "yendor.cpp" #include "complex.cpp" #include "game.cpp" +#include "orbgen.cpp" +#include "monstergen.cpp" +#include "barriers.cpp" +#include "bigstuff.cpp" +#include "landlock.cpp" #include "landgen.cpp" #include "orbs.cpp" #if CAP_INV diff --git a/landgen.cpp b/landgen.cpp index 23c23c9c..dd35dba4 100644 --- a/landgen.cpp +++ b/landgen.cpp @@ -4,42 +4,8 @@ // land generation routines -int steplimit = 0; -int cstep; - -template -void limitgen(T... args) { - if(steplimit) { - cstep++; - printf("%6d ", cstep); - printf(args...); - if(cstep == steplimit) buggyGeneration = true; - } - } - -vector buggycells; - -cell *pathTowards(cell *pf, cell *pt) { - - while(celldist(pt) > celldist(pf)) { - if(isNeighbor(pf, pt)) return pt; - cell *pn = NULL; - forCellEx(pn2, pt) if(celldist(pn2) < celldist(pt)) pn = pn2; - pt = pn; - } - - if(isNeighbor(pf, pt)) return pt; - forCellEx(pn2, pt) if(celldist(pn2) < celldist(pt)) return pn2; - return NULL; - } - -bool buildBarrierNowall(cell *c, eLand l2, bool force = false); - bool safety = false; -eLand firstland = laIce, specialland = laIce; - -bool timerghost = true; eLand lastland; int lastexplore; @@ -47,1904 +13,9 @@ int lastexplore; bool randomPatternsMode = false; int randompattern[landtypes]; -bool chaosmode = false; bool chaosUnlocked = false; bool chaosAchieved = false; -// returns: 2 = treasure increaser, 1 = just appears, 0 = does not appear -int isNative(eLand l, eMonster m) { - switch(l) { - case laIce: - return (m == moWolf || m == moWolfMoved || m == moYeti) ? 2 : 0; - - case laJungle: - return (m == moIvyRoot || m == moMonkey) ? 2 : - (isIvy(m) || m == moEagle || m == moMonkey) ? 1 : 0; - - case laCaves: - return (m == moGoblin || m == moTroll) ? 2 : m == moSeep ? 1 : 0; - - case laDesert: - return (m == moDesertman || m == moWorm) ? 2 : 0; - - case laAlchemist: - return (m == moSlime) ? 2 : 0; - - case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2: - return (m == moMirrorSpirit || m == moNarciss || m == moMimic) ? 1 : 0; - - case laMirrorOld: - return (m == moEagle || m == moRanger || m == moMimic) ? 1 : 0; - - case laMotion: - return (m == moRunDog) ? 2 : 0; - - case laGraveyard: - return (m == moZombie || m == moNecromancer) ? 2 : - m == moGhost ? 1 : 0; - - case laRlyeh: - return - (m == moCultist || m == moTentacle || m == moPyroCultist) ? 2 : - (m == moCultistLeader || isIvy(m)) ? 1 : 0; - - case laDryForest: - return (m == moHedge || m == moFireFairy) ? 2 : 0; - - case laHell: - return (m == moLesser) ? 2 : 0; - - case laCocytus: - return (m == moShark || m == moGreaterShark || m == moCrystalSage) ? 2 : - m == moYeti ? 1 : 0; - - case laCrossroads: case laCrossroads2: case laCrossroads3: case laCrossroads4: - case laCrossroads5: - case laNone: case laBarrier: case laOceanWall: case laCanvas: return 0; - - case laEmerald: - return (m == moFlailer || m == moLancer || m == moMiner) ? 2 : - m == moHedge ? 1 : 0; - - case laWineyard: - return (m == moVineSpirit || m == moVineBeast) ? 2 : 0; - - case laHive: - return isBug(m) ? 1 : 0; - - case laDeadCaves: - return (m == moEarthElemental || m == moDarkTroll) ? 2 : - (m == moGoblin || m == moSeep) ? 1 : 0; - - case laPower: - return (isWitch(m) || m == moEvilGolem) ? 1 : 0; - - case laCamelot: - return (m == moKnight || m == moHedge || m == moFlailer || m == moLancer) ? 1 : 0; - - case laTemple: - return (m == moTentacle || m == moCultist || m == moPyroCultist || m == moCultistLeader) ? 1 : 0; - - case laCaribbean: - return (m == moPirate || m == moParrot || m == moCShark) ? 1 : 0; - - case laRedRock: return (m == moRedTroll || m == moHexSnake) ? 2 : 0; - - case laMinefield: - return (m == moBomberbird || m == moTameBomberbird) ? 1 : 0; - - case laOcean: - return (m == moAlbatross) ? 2 : (m == moPirate || m == moCShark) ? 1 : 0; - - case laWhirlpool: - return (m == moPirate || m == moCShark) ? 1 : 0; - - case laPalace: case laPrincessQuest: - return (m == moPalace || m == moFatGuard || m == moSkeleton || m == moVizier) ? 2 : - m == moSkeleton ? 1 : 0; - - case laLivefjord: - return m == moViking ? 2 : (m == moFjordTroll || m == moWaterElemental) ? 1 : 0; - - case laIvoryTower: - return (m == moFamiliar || m == moGargoyle) ? 2 : 0; - - case laZebra: return (m == moOrangeDog) ? 2 : 0; - - case laEAir: case laEEarth: case laEWater: case laEFire: - case laElementalWall: - if(m == elementalOf(l)) return 2; - return (m == moAirElemental || m == moEarthElemental || m == moWaterElemental || m == moFireElemental) ? 1 : 0; - - case laStorms: - return (m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0; - - case laOvergrown: - return (m == moMutant || m == moForestTroll) ? 1 : 0; - - case laWildWest: - return (m == moOutlaw) ? 2 : 0; - - case laHalloween: - return 1; - - case laClearing: - return (m == moMutant || m == moRedFox) ? 1 : 0; - - case laHaunted: case laHauntedWall: case laHauntedBorder: - return (m == moGhost || m == moFriendlyGhost) ? 1 : 0; - - case laWhirlwind: - return (m == moAirElemental || m == moWindCrow) ? 2 : 0; - - case laRose: - return (m == moFalsePrincess || m == moRoseBeauty || m == moRoseLady) ? 2 : 0; - - case laWarpCoast: case laWarpSea: - return m == moRatling ? 2 : m == moRatlingAvenger ? 1 : 0; - - case laDragon: - return (isDragon(m) || m == moFireElemental) ? 1 : 0; - - case laEndorian: - return (m == moResearcher || m == moSparrowhawk) ? 2 : 0; - - case laTortoise: - return m == moTortoise ? 1 : 0; - - case laTrollheim: - return isTroll(m) ? 1 : 0; - - case laKraken: - return m == moKrakenH ? 2 : (m == moViking || m == moKrakenT) ? 1 : 0; - - case laBurial: - return m == moDraugr ? 1 : 0; - - case laDungeon: - return - m == moBat ? 2 : - m == moSkeleton || m == moGhost ? 1 : - 0; - - case laMountain: - return - m == moEagle || m == moMonkey || isIvy(m) || m == moFriendlyIvy ? 1 : 0; - - case laReptile: - return m == moReptile ? 1 : 0; - - case laBull: - return (m == moSleepBull || m == moRagingBull || m == moButterfly || m == moGadfly) ? 1 : 0; - - case laPrairie: - return (m == moRagingBull || m == moHerdBull || m == moGadfly) ? 1 : 0; - - case laVolcano: - return (m == moLavaWolf || m == moSalamander) ? 2 : 0; - - case laTerracotta: case laMercuryRiver: - return m == moJiangshi ? 2 : m == moTerraWarrior ? 1 : 0; - - case laBlizzard: - return (m == moVoidBeast || m == moIceGolem) ? 2 : 0; - - case laDogPlains: - return m == moHunterDog ? 1 : 0; - - case laCA: return false; - } - return false; - } - -eItem treasureType(eLand l) { - switch(l) { - case laIce: return itDiamond; - case laJungle: return itRuby; - case laCaves: return itGold; - case laDesert: return itSpice; - - case laAlchemist: return itElixir; - - case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2: - case laMirrorOld: - return itShard; - - case laMotion: return itFeather; - - case laGraveyard: return itBone; - case laRlyeh: return itStatue; - case laDryForest: return itFernFlower; - - case laHell: return itHell; - case laCocytus: return itSapphire; - case laCrossroads: return itHyperstone; - case laCrossroads2: return itHyperstone; - case laCrossroads3: return itHyperstone; - case laCrossroads4: return itHyperstone; - case laCrossroads5: return itHyperstone; - - case laNone: return itNone; - case laBarrier: return itNone; - case laOceanWall: return itNone; - case laCanvas: return itNone; - - case laEmerald: return itEmerald; - case laWineyard: return itWine; - case laHive: return itRoyalJelly; - case laDeadCaves: return itSilver; - case laPower: return itPower; - case laCamelot: return itHolyGrail; - case laTemple: return itGrimoire; - - case laCaribbean: return itPirate; - case laRedRock: return itRedGem; - - case laMinefield: return itBombEgg; - case laOcean: return itCoast; - case laWhirlpool: return itWhirlpool; - case laPalace: return itPalace; - case laLivefjord: return itFjord; - - case laIvoryTower: return itIvory; - case laZebra: return itZebra; - - case laEAir: case laEEarth: case laEWater: case laEFire: - case laElementalWall: return itElemental; - - case laPrincessQuest: return itSavedPrincess; - - case laStorms: return itFulgurite; - case laOvergrown: return itMutant; - case laWildWest: return itBounty; - case laHalloween: return itTreat; - case laClearing: return itMutant2; - case laHaunted: case laHauntedWall: case laHauntedBorder: return itLotus; - case laWhirlwind: return itWindstone; - - case laRose: return itRose; - case laWarpCoast: case laWarpSea: return itCoral; - - case laDragon: return itDragon; - case laEndorian: return itApple; - case laTortoise: return itBabyTortoise; - - case laTrollheim: return itTrollEgg; - case laKraken: return itKraken; - case laBurial: return itBarrow; - - case laDungeon: return itSlime; - case laMountain: return itAmethyst; - case laReptile: return itDodeca; - - case laBull: return itBull; - case laPrairie: return itGreenGrass; - - case laVolcano: return itLavaLily; - case laTerracotta: case laMercuryRiver: return itTerra; - case laBlizzard: return itBlizzard; - case laDogPlains: return itDogPlains; - - case laCA: return itNone; - } - return itNone; - } - -eItem wanderingTreasure(cell *c) { - eLand l = c->land; - if(l == laEFire) return itFireShard; - if(l == laEWater) return itWaterShard; - if(l == laEAir) return itAirShard; - if(l == laEEarth) return itEarthShard; - if(l == laElementalWall) return itNone; - if(l == laMirror && c->type != 6) return itNone; - if(l == laMirrorOld && c->type != 6) return itNone; - if(l == laEmerald) { - forCellEx(c2, c) if(c2->wall == waCavewall) return itNone; - } - if(l == laMinefield && c->wall == waMineMine) return itNone; - if(l == laBurial && hrand(2)) return itOrbSword; - if(l == laKraken) return itOrbFish; - return treasureType(l); - } - -#define ORBLINES 56 - -struct orbinfo { - eLand l; - int lchance; - int gchance; - eItem orb; - }; - -const orbinfo orbinfos[ORBLINES] = { - {laGraveyard, 200, 200,itGreenStone}, // must be first so that it does not reduce - // chance of other orbs - {laJungle, 1200, 1500,itOrbLightning}, - {laIce, 2000, 1500,itOrbFlash}, - {laCaves, 1800, 2000,itOrbLife}, - {laAlchemist, 800, 800,itOrbSpeed}, - {laDesert, 2500, 1500,itOrbShield}, - {laHell, 2000, 1000,itOrbYendor}, - {laRlyeh, 1500, 1500,itOrbTeleport}, - {laMotion, 2000, 700, itOrbSafety}, - {laIce, 1500, 0, itOrbWinter}, - {laDragon, 2500, 0, itOrbWinter}, - {laDryForest, 2500, 0, itOrbWinter}, - {laCocytus, 1500, 1500, itOrbWinter}, - {laCaves, 1200, 0, itOrbDigging}, - {laDryForest, 500, 4500, itOrbThorns}, - {laDeadCaves, 1800, 0, itGreenStone}, - {laDeadCaves, 1800, 1500, itOrbDigging}, - {laEmerald, 1500, 3500, itOrbPsi}, - {laWineyard, 900, 1200, itOrbAether}, - {laHive, 800, 1200, itOrbInvis}, - {laPower, 0, 3000, itOrbFire}, - {laMinefield, 0, 3500, itOrbFriend}, - {laTemple, 0, 3000, itOrbDragon}, - {laCaribbean, 0, 3500, itOrbTime}, - {laRedRock, 0, 2500, itOrbSpace}, - {laCamelot, 1000, 1500, itOrbIllusion}, - {laOcean, 0, 3000, itOrbEmpathy}, - {laOcean, 0, 0, itOrbAir}, - {laPalace, 0, 4000, itOrbDiscord}, - {laPalace, 0, 0, itOrbFrog}, - {laZebra, 500, 2100, itOrbFrog}, - {laLivefjord, 0, 1800, itOrbFish}, - {laPrincessQuest, 0, 200, itOrbLove}, - {laIvoryTower, 500, 4000, itOrbMatter}, - {laElementalWall, 1500, 4000, itOrbSummon}, - {laStorms, 1000, 2500, itOrbStunning}, - {laOvergrown, 1000, 800, itOrbLuck}, - {laWhirlwind, 1250, 3000, itOrbAir}, - {laHaunted, 1000, 5000, itOrbUndeath}, - {laClearing, 5000, 5000, itOrbFreedom}, - {laRose, 2000, 8000, itOrbBeauty}, - {laWarpCoast, 2000, 8000, itOrb37}, - {laDragon, 500, 5000, itOrbDomination}, - {laTortoise, 2500, 1500, itOrbShell}, - {laEndorian, 150, 2500, itOrbEnergy}, - {laEndorian, 450, 0, itOrbTeleport}, - {laKraken, 500, 2500, itOrbSword}, - {laBurial, 500, 2500, itOrbSword2}, - {laTrollheim, 750, 1800, itOrbStone}, - {laMountain, 400, 3500, itOrbNature}, - {laDungeon, 120, 2500, itOrbRecall}, - {laReptile, 500, 2100, itOrbDash}, - {laBull, 720, 3000, itOrbHorns}, - {laPrairie, 0, 3500, itOrbBull}, - {laWhirlpool, 0, 0, itOrbSafety}, - {laWhirlpool, 0, 2000, itOrbWater}, // must be last because it generates a boat - }; - -bool isElemental(eLand l); - -eItem orbType(eLand l) { - if(isElemental(l)) l = laElementalWall; - if(inv::on && (l == laMirror || l == laMirrorOld || isCrossroads(l))) - return itOrbMirror; - if(l == laMirror || l == laMirrorOld) return itShard; - for(int i=0; i= 10; - return false; - } - - switch(l) { - case laOvergrown: - return gold() >= R60 && items[itRuby] >= U10; - - case laStorms: case laWhirlwind: - return gold() >= R60; - - case laWildWest: case laHalloween: - return false; - - case laIce: case laJungle: case laCaves: case laDesert: - case laMotion: case laCrossroads: case laAlchemist: - return true; - - case laMirror: case laMinefield: case laPalace: - case laOcean: case laLivefjord: case laMirrored: case laMirrorWall: case laMirrorWall2: - case laMirrored2: - return gold() >= R30; - - case laCaribbean: case laWhirlpool: - return exploreland[0][laOcean] || items[itCoast] || items[itStatue]; - - case laRlyeh: case laDryForest: case laWineyard: case laCrossroads2: - return gold() >= R60; - - case laDeadCaves: - return gold() >= R60 && items[itGold] >= U10; - - case laGraveyard: - return tkills() >= R100; - - case laHive: - return tkills() >= R100 && gold() >= R60; - - case laRedRock: - return gold() >= R60 && items[itSpice] >= U10; - - case laEmerald: - return (items[itFernFlower] >= U5 && items[itGold] >= U5) || kills[moVizier]; - - case laCamelot: - return items[itEmerald] >= U5; - - case laHell: case laCrossroads3: - return hellUnlocked(); - - case laPower: - return items[itHell] >= U10; - - case laCocytus: - return items[itHell] >= U10 && items[itDiamond] >= U10; - - case laTemple: - return items[itStatue] >= U5; - - case laClearing: - return items[itMutant] >= U5; - - case laIvoryTower: return gold() >= R30; - case laZebra: return gold() >= R30 && items[itFeather] >= U10; - - case laEAir: case laEEarth: case laEWater: case laEFire: case laElementalWall: - return elementalUnlocked(); - - case laBarrier: case laNone: case laOceanWall: case laCanvas: case laCA: - return false; - - case laMirrorOld: - return false; - - case laHaunted: case laHauntedWall: case laHauntedBorder: - return items[itBone] >= U10; - - case laPrincessQuest: return kills[moVizier] && !shmup::on && multi::players == 1; - - case laRose: - return gold() >= R60; - - case laWarpCoast: case laWarpSea: - return gold() >= R30; - - case laCrossroads4: - return gold() >= R200; - - case laEndorian: - return items[itIvory] >= U10; - - case laTortoise: - return tortoise::seek(); - - case laDragon: - return killtypes() >= R20; - - case laKraken: - return items[itFjord] >= U10; - - case laBurial: - return items[itKraken] >= U10; - - case laTrollheim: - return trollUnlocked(); - - case laDungeon: - return items[itPalace] >= U5 && items[itIvory] >= U5; - - case laMountain: - return items[itRuby] >= U5 && items[itIvory] >= U5; - - case laReptile: - return gold() >= R30 && items[itElixir] >= U10; - - case laPrairie: - case laBull: - return gold() >= R90; - - case laVolcano: - return gold() >= R30 && items[itElixir] >= U10; - - case laDogPlains: - return true; - - case laTerracotta: case laMercuryRiver: - return gold() >= 60; - - case laBlizzard: - return items[itDiamond] >= 5 && items[itWindstone] >= 5; - - case laCrossroads5: - return gold() >= R300; - } - return false; - } - -int orbsUnlocked() { - int i = 0; - for(int t=0; t= R10) - i++; - return i; - } - -bool hellUnlocked() { - return orbsUnlocked() >= 9; - } - -void countHyperstoneQuest(int& i1, int& i2) { - i1 = 0; i2 = 0; - for(int t=1; t= R10) i1++; - } - } - -bool hyperstonesUnlocked() { - int i1, i2; - if(tactic::on && isCrossroads(tactic::lasttactic) && !tactic::trailer) return true; - countHyperstoneQuest(i1, i2); - return i1 == i2; - } - -// reduce c->mpdist to d; also generate the landscape - -bool buggyGeneration = false; - -bool checkBarriersBack(cellwalker bb, int q=5, bool cross = false); - -bool checkBarriersFront(cellwalker bb, int q=5, bool cross = false) { - - if(bb.c->type == 6) - return false; - - if(bb.c->mpdist < BARLEV) return false; - if(bb.c->mpdist == BUGLEV) return false; - if(bb.c->bardir != NODIR) return false; - if(bb.spin == (purehepta ? 3 : 0)) {q--; if(!q) return true; } - - if(!cross) for(int i=0; i<7; i++) { - cellwalker bb2 = bb; - cwspin(bb2, i); cwstep(bb2); - if(bb2.c->bardir != NODIR) return false; - if(!purehepta) { - cwspin(bb2, 4); cwstep(bb2); - if(bb2.c->bardir != NODIR) return false; - } - } - - cwstep(bb); - if(!purehepta) { cwspin(bb, 3); cwstep(bb); cwspin(bb, 3); cwstep(bb); } - return checkBarriersBack(bb, q); - } - -bool hasbardir(cell *c) { - return c->bardir != NODIR && c->bardir != NOBARRIERS; - } - -void preventbarriers(cell *c) { - if(c && c->bardir == NODIR) c->bardir = NOBARRIERS; - } - -bool checkBarriersBack(cellwalker bb, int q, bool cross) { - // printf("back, %p, s%d\n", bb.c, bb.spin); - - // if(mark) { printf("mpdist = %d [%d] bardir = %d spin=%d q=%d cross=%d\n", bb.c->mpdist, BARLEV, bb.c->bardir, bb.spin, q, cross); } - - if(bb.c->mpdist < BARLEV) return false; - if(bb.c->mpdist == BUGLEV) return false; - if(bb.c->bardir != NODIR) return false; - - // if(bb.spin == 0 && bb.c->mpdist == INFD) return true; - - if(!cross) for(int i=0; i<7; i++) { - cellwalker bb2 = bb; - cwspin(bb2, i); cwstep(bb2); - if(bb2.c->bardir != NODIR) return false; - if(!purehepta) { - cwspin(bb2, 4); cwstep(bb2); - if(bb2.c->bardir != NODIR) return false; - } - } - - cwspin(bb, 3); cwstep(bb); cwspin(bb, purehepta ? 5 : 4); - // bool create = cwstepcreates(bb); - cwstep(bb); cwspin(bb, 3); - // if(create && bb.spin == 0) return true; - return checkBarriersFront(bb, q); - } - -const eLand NOWALLSEP = laNone; -const eLand NOWALLSEP_USED = laWhirlpool; - -void setland(cell *c, eLand l); - -bool checkBarriersNowall(cellwalker bb, int q, int dir, eLand l1=laNone, eLand l2=laNone) { - if(bb.c->mpdist < BARLEV && l1 == laNone) return false; - if(bb.c->bardir != NODIR && l1 == laNone) return false; - - if(l1 != laNone) { - bb.c->bardir = bb.spin; bb.c->barright = l2; bb.c->barleft = NOWALLSEP; - setland(bb.c, l1); - } - if(q > 10) return true; - - if(l1 == laNone) for(int i=0; itype; i++) { - cell *c1 = bb.c->mov[i]; - if(!c1) continue; - for(int j=0; jtype; j++) { - cell *c2 = c1->mov[j]; - if(!c2) continue; - if(c2 && c2->bardir == NOBARRIERS) - return false; - if(c2 && c2->bardir != NODIR && c2->barleft != NOWALLSEP) - return false; - // note: "far crashes" between NOWALL lines are allowed - } - } - - if(purehepta) { - cwspin(bb, 3*dir); - cwstep(bb); - cwspin(bb, -3*dir); - } - else { - cwstep(bb); - cwspin(bb, 2*dir); - cwstep(bb); - cwspin(bb, dir); - } - return checkBarriersNowall(bb, q+1, -dir, l2, l1); - } - -bool isSealand(eLand l) { - return l == laOcean || l == laCaribbean || l == laWhirlpool || l == laLivefjord || - l == laOceanWall || l == laWarpSea || l == laKraken; - } - -bool isCoastal(eLand l) { - return l == laWarpSea || l == laWarpCoast || l == laLivefjord || l == laOcean; - } - -bool isPureSealand(eLand l) { - return l == laCaribbean || l == laKraken; - } - -bool isElemental(eLand l) { - return l == laEAir || l == laEWater || l == laEEarth || l == laEFire || - l == laElementalWall; - } - -bool isHaunted(eLand l) { - return l == laHaunted || l == laHauntedBorder || l == laHauntedWall; - } - -eWall getElementalWall(eLand l) { - if(l == laEAir) return waChasm; - if(l == laEEarth) return waStone; - if(l == laEFire) return waEternalFire; - if(l == laEWater) return waSea; - return waNone; - } - -bool isTrollLand(eLand l) { - return l == laCaves || l == laStorms || l == laOvergrown || - l == laDeadCaves || l == laLivefjord || l == laRedRock; - } - -void setbarrier(cell *c) { - if(isSealand(c->barleft) && isSealand(c->barright)) { - bool setbar = c->type == 7; - if(c->barleft == laKraken || c->barright == laKraken) - if(c->barleft != laWarpSea && c->barright != laWarpSea) - setbar = !setbar; - c->wall = setbar ? waBarrier : waSea; - c->land = laOceanWall; - } - else if(isElemental(c->barleft) && isElemental(c->barright)) { - c->land = laElementalWall; - c->wall = getElementalWall(c->barleft); - } - else if(c->barleft == laHaunted || c->barright == laHaunted) { - c->land = laHauntedWall; - } - else if(c->barleft == laMirrored2 || c->barright == laMirrored2) - c->land = laMirrorWall2; - else if(c->barleft == laMirrored || c->barright == laMirrored) - c->land = laMirrorWall; - else if(c->barleft == laTerracotta && c->barright == laTerracotta) { - c->land = laMercuryRiver; - c->wall = waMercury; - } - else { - c->wall = waBarrier; - c->land = laBarrier; - } -/*if(isHive(c->barleft) && isHive(c->barright)) - c->wall = waWaxWall, c->land = c->barleft; */ - } - -int buildIvy(cell *c, int children, int minleaf) { - if(c->monst) return 0; - c->mondir = NODIR; - c->monst = moIvyRoot; - - cell *child = NULL; - - int leaf = 0; - int leafchild = 0; - for(int i=0; itype; i++) { - createMov(c, i); - if(passable(c->mov[i], c, 0) && c->mov[i]->land == c->land) { - if(children && !child) - child = c->mov[i], leafchild = buildIvy(c->mov[i], children-1, 5); - else - c->mov[i]->monst = (leaf++ || peace::on) ? moIvyWait : moIvyHead, - c->mov[i]->mondir = c->spn(i); - } - } - - leaf += leafchild; - if(leaf < minleaf) { - if(child) killIvy(child, moNone); - killIvy(c, moNone); - return 0; - } - else return leaf; - } - -bool grailWasFound(cell *c) { - if(euclid) return items[itHolyGrail]; - return c->master->alt->alt->emeraldval & GRAIL_FOUND; - } - -int euclidAlt(short x, short y) { - if(specialland == laTemple || specialland == laClearing) { - return max(int(x), x+y); - } - else if(specialland == laCaribbean || specialland == laWhirlpool || specialland == laMountain) { - return - min( - min(max(int(-x), -x-y) + 3, - max(int(x+y), int(y)) + 3), - max(int(x), int(-y)) + 3 - ); - } - else if(specialland == laPrincessQuest) - return eudist(x-EPX, y-EPY); - else return eudist(x-20, y-10); - } - -bool isCrossroads(eLand l) { - return l == laCrossroads || l == laCrossroads2 || l == laCrossroads3 || - l == laCrossroads4 || l == laCrossroads5; - } - -bool bearsCamelot(eLand l) { - return isCrossroads(l) && l != laCrossroads2 && l != laCrossroads5; - } - -ld orbprizefun(int tr) { - if(tr < 10) return 0; - return .6 + .4 * log(tr/25.) / log(2); - } - -ld orbcrossfun(int tr) { - if(tr < 10) return 0; - if(tr > 25) return 1; - return (tr*2 + 50) / 100.; - } - -bool buildPrizeMirror(cell *c, int freq) { - if(inv::on) return false; - if(c->type == 7 && !purehepta) return false; - if(items[itShard] < 25) return false; - if(freq && hrand(freq * 100 / orbprizefun(items[itShard])) >= 100) - return false; - c->wall = hrand(2) ? waCloud : waMirror; - return true; - } - -eLand getPrizeLand(cell *c = cwt.c) { - eLand l = c->land; - if(isElemental(l)) l = laElementalWall; - if(l == laPalace && princess::dist(c) < OUT_OF_PRISON) - l = laPrincessQuest; - return l; - } - -void placePrizeOrb(cell *c) { - if(peace::on) return; - - eLand l = getPrizeLand(c); - - // these two lands would have too much orbs according to normal rules - if(l == laPalace && hrand(100) >= 20) return; - if(l == laPrincessQuest && hrand(100) >= 20) return; - if(l == laGraveyard && hrand(100) >= 15) return; - if(l == laBurial && hrand(100) >= 10) return; - if(l == laLivefjord && hrand(100) >= 35) return; - if(l == laMinefield && hrand(100) >= 25) return; - if(l == laElementalWall && hrand(100) >= 25) return; - - for(int i=0; i= 100) ; - else continue; - } - - eOrbLandRelation olr = getOLR(oi.orb, l); - if(olr != olrPrize25 && olr != olrPrize3) continue; - int treas = items[treasureType(oi.l)]; - if(olr == olrPrize3) treas *= 10; - if(olr == olrPrize25 || olr == olrPrize3 || olr == olrGuest || olr == olrMonster || olr == olrAlways) { - if(treas < 25) continue; - } - else continue; - - int gch = oi.gchance; - if(!gch) continue; - gch = int(gch / orbprizefun(treas)); - if(hrand(gch) >= 60) continue; - if(oi.orb == itOrbWater && c->land != laOcean && c->land != laKraken) { - if(cellHalfvine(c)) continue; - c->item = oi.orb; - c->wall = waStrandedBoat; - return; - } - c->item = oi.orb; - } - - // printf("land: %s orb: %s\n", dnameof(l), dnameof(c->item)); - } - -void placeLocalOrbs(cell *c) { - eLand l = c->land; - if(l == laZebra && c->wall == waTrapdoor) return; - if(isGravityLand(l) && cellEdgeUnstable(c)) return; - if(isElemental(l)) l = laElementalWall; - if(peace::on) return; - - for(int i=0; i= (11+hrand(15))) - ch = 0; - if(tactic::trailer && ch < 5) ch = 0; - if(ch == 0 && items[treasureType(oi.l)] * landMultiplier(oi.l) >= (chaosmode ? 1+hrand(10) : 10)) { - // printf("local orb\n"); - c->item = oi.orb; - if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat; - return; - } - else if(oi.gchance && (ch >= 1 && ch < 11) && getOLR(itShard, l) == olrPrize25 && l != laRedRock && l != laWhirlwind) - buildPrizeMirror(c, 10); - else if(oi.gchance && (ch >= 11 && ch < 11+PRIZEMUL)) - placePrizeOrb(c); - } - } - -void placeCrossroadOrbs(cell *c) { - if(peace::on) return; - for(int i=0; i= 50) ; - else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ; - else continue; - } - int treas = items[treasureType(oi.l)] * landMultiplier(oi.l); - if(tactic::on && isCrossroads(tactic::lasttactic)) { - if(oi.orb == itOrbYendor || oi.orb == itOrbSummon || oi.orb == itOrbFish || oi.orb == itOrbDigging || oi.orb == itOrbLove || oi.orb == itOrbLuck) - continue; - } - else { - if(treas < 10) continue; - } - if(oi.orb == itOrbSafety && c->land == laCrossroads5) continue; - int mul = c->land == laCrossroads5 ? 10 : 1; - int gch = oi.gchance; - if(!inv::on) gch /= orbcrossfun(treas); else gch /= 2; - if(hrand(gch) >= mul) continue; - if(hrand(50+items[itHyperstone]) >= 50) continue; - c->item = oi.orb; - if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat; - } - } - -void placeOceanOrbs(cell *c) { - if(peace::on) return; - for(int i=0; i= 50) ; - else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ; - else continue; - } - - if(items[treasureType(oi.l)] * landMultiplier(oi.l) < 10) continue; - if(!oi.gchance) continue; - if(oi.orb == itOrbLife) continue; // useless - if(hrand(oi.gchance) >= 20) continue; - c->item = oi.orb; - } - } - -bool errorReported = false; - -void describeCell(cell *c) { - if(!c) { printf("NULL\n"); return; } - printf("describe %p: ", c); - printf("%-15s", linf[c->land].name); - printf("%-15s", winf[c->wall].name); - printf("%-15s", iinf[c->item].name); - printf("%-15s", minf[c->monst].name); - printf("LP%08x", c->landparam); - printf("D%3d", c->mpdist); - printf("MON%3d", c->mondir); - printf("\n"); - } - -void setland(cell *c, eLand l) { - if(c->land != l) { - c->landparam = 0; - } - if(l == laNone) { - printf("setland\n"); // NONEDEBUG - } - c->land = l; - } - -void extendcheck(cell *c) { - return; - if(!purehepta && c->landparam == 0 && c->barleft != NOWALLSEP) { - raiseBuggyGeneration(c, "extend error"); - } - } - -bool oldmirror; - -bool inmirror(eLand l) { - return l == laMirrored || l == laMirrorWall2 || l == laMirrored2; - } - -bool inmirror(cell *c) { - return inmirror(c->land); - } - -bool inmirror(const cellwalker& cw) { - return inmirror(cw.c->land); - } - -bool mirrorwall(cell *c) { - return c->barleft == laMirrored || c->barright == laMirrored; - } - -void extendBarrierFront(cell *c) { - limitgen("extend front %p\n", c); - if(buggyGeneration) return; - int ht = c->landparam; - extendcheck(c); - - cellwalker bb(c, c->bardir); setbarrier(bb.c); - cwstep(bb); - - if(!purehepta) { - bb.c->barleft = c->barleft; - bb.c->barright = c->barright; - setbarrier(bb.c); - if(!mirrorwall(bb.c)) - bb.c->landparam = (ht-4); - //printf("[A heat %d]\n", ht-4); - - cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barleft); cwstep(bb); - cwspin(bb, 2); cwstep(bb); setland(bb.c, c->barright); cwstep(bb); - cwspin(bb, 2); - - cwspin(bb, 3); cwstep(bb); - bb.c->barleft = c->barright; - bb.c->barright = c->barleft; - setbarrier(bb.c); - if(!mirrorwall(bb.c)) - bb.c->landparam = (ht-4)^2; - //printf("[B heat %d]\n", (ht-4)^2); - cwspin(bb, 3); cwstep(bb); - - bb.c->barleft = c->barleft; - bb.c->barright = c->barright; - if(!mirrorwall(bb.c)) - bb.c->landparam = ht ^ 2; - } - -//printf("[C heat %d]\n", (ht)^2); - bb.c->bardir = bb.spin; - bb.c->barleft = c->barright; - bb.c->barright = c->barleft; - // printf("#1\n"); - extendcheck(bb.c); - extendBarrier(bb.c); - - for(int a=-3; a<=3; a++) if(a) { - bb.c = c; bb.spin = c->bardir; cwspin(bb, purehepta?-a:a); cwstep(bb); - setland(bb.c, a > 0 ? c->barright : c->barleft); - } - } - -void extendBarrierBack(cell *c) { - limitgen("extend back %p\n", c); - if(buggyGeneration) return; - int ht = c->landparam; - extendcheck(c); - - cellwalker bb(c, c->bardir); setbarrier(bb.c); - cwspin(bb, 3); cwstep(bb); cwspin(bb, purehepta?5:4); - setland(bb.c, purehepta ? c->barleft : c->barright); - cwstep(bb); cwspin(bb, 3); - bb.c->bardir = bb.spin; - bb.c->barleft = c->barright; - bb.c->barright = c->barleft; - if(!mirrorwall(bb.c)) - bb.c->landparam = ht ^ 11; - extendcheck(bb.c); -//printf("[D heat %d]\n", (ht^11)); - - // needed for CR2 to work - if(!purehepta) { - cwstep(bb); - bb.c->barleft = c->barright; - bb.c->barright = c->barleft; - if(!mirrorwall(bb.c)) - bb.c->landparam = (ht^11)-4; - cwstep(bb); - } -//printf("[E heat %d]\n", (ht^11)); - - // printf("#2\n"); - extendBarrier(bb.c); - } - -eLand oppositeElement(eLand l, eLand l2) { - if(l == laEFire) return laEWater; - if(l == laEWater) return laEFire; - if(l == laEAir) return laEEarth; - if(l == laEEarth) return laEAir; - if(l == laMirror && l2 == laMirrored) return laMirrored2; - if(l == laMirrored2 && l2 == laMirrored) return laMirror; - return l; - } - -void extendNowall(cell *c) { - - c->barleft = NOWALLSEP_USED; - cellwalker cw(c, c->bardir); - - if(!purehepta) { - cwstep(cw); - setland(cw.c, c->barright); - } - - for(int i=-1; i<2; i+=2) { - if(purehepta) { - cwspin(cw, 3*i); - cwstep(cw); - cwspin(cw, -3*i); - } - else { - cwspin(cw, 2*i); - cwstep(cw); - } - setland(cw.c, c->barright); - if(cw.c->barleft != NOWALLSEP_USED) { - cw.c->barleft = NOWALLSEP; - cw.c->barright = c->land; - if(c->barright == laNone) { - printf("barright\n"); - }// NONEDEBUG - setland(cw.c, c->barright); - if(!purehepta) cwspin(cw, i); - cw.c->bardir = cw.spin; - if(!purehepta) cwspin(cw, -i); - extendcheck(cw.c); - extendBarrier(cw.c); - } - if(purehepta) { - cwspin(cw, 3*i); - cwstep(cw); - cwspin(cw, -3*i); - } - else { - cwstep(cw); - cwspin(cw, -2*i); - } - } - } - -eLand getNewLand(eLand old); - -bool gotit = false; - -void extendCR5(cell *c) { - if(purehepta) return; -// if(c->barright == laCrossroads5) extendCR5(c); - eLand forbidden = c->barleft; - eLand forbidden2 = laNone; - cellwalker cw(c, c->bardir); - for(int u=0; u<2; u++) { - // if(gotit) break; - cwspin(cw, 2); - cwstep(cw); - cwspin(cw, 2); - cwstep(cw); - cwspin(cw, 5); - if(cw.c->bardir == NODIR) { - cw.c->landparam = 40; - cw.c->bardir = cw.spin; - cw.c->barright = laCrossroads5; - eLand nland = forbidden; - for(int i=0; i<10 && (nland == forbidden || nland == forbidden2); i++) - nland = getNewLand(laCrossroads5); - cw.c->barleft = forbidden2 = nland; - landcount[nland]++; - extendBarrier(cw.c); - gotit = true; - } - else forbidden2 = cw.c->barleft; - } - } - -bool isbar4(cell *c) { - return - c->wall == waBarrier || c->land == laElementalWall || - c->land == laMirrorWall || c->land == laMirrorWall2 || - c->land == laMercuryRiver; - } - -void extendBarrier(cell *c) { - limitgen("extend barrier %p\n", c); - if(buggyGeneration) return; - - if(c->barleft == NOWALLSEP_USED) return; - - extendcheck(c); - - // printf("build barrier at %p", c); - if(c->land == laBarrier || c->land == laElementalWall || c->land == laHauntedWall || c->land == laOceanWall || - c->land == laMirrorWall || c->land == laMirrorWall2 || c->land == laMercuryRiver) { - // printf("-> ready\n"); - return; - } -// if(c->wall == waWaxWall) return; - if(c->mpdist > BARLEV) { - // printf("-> too far\n"); - return; // == INFD) return; - } - - if(c->barleft == NOWALLSEP) { - extendNowall(c); - return; - } - - bool firstmirror = - (c->barleft == laMirrored || c->barright == laMirrored) && - c->barleft != laMirrored2 && c->barright != laMirrored2; - - if(firstmirror && c->barleft == laMirror && hrand(100) < 60) { - cellwalker cw(c, c->bardir); - if(!purehepta) cwstep(cw); - if(cw.c->land != laMirrorWall) - if(buildBarrier6(cw, 1)) return; - } - - if(firstmirror && (purehepta?c->barleft == laMirror : c->barright == laMirror) && hrand(100) < 60) { - cellwalker cw(c, c->bardir); - if(purehepta) { - cwspin(cw, -3); cwstep(cw); cwspin(cw, -3); -// cwspin(cw, 3); cwstep(cw); cwspin(cw, -2); cwstep(cw); cwspin(cw, 3); - } - else { - cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); // check this - } - if(buildBarrier6(cw, 2)) return; - } - - if(((c->barleft == laCrossroads3 || c->barright == laCrossroads3) && hrand(100) < 66) || - (isElemental(c->barleft) && isElemental(c->barright) && hrand(100) < 75) - || (firstmirror && hrand(100) < 60) - ) { - - cellwalker cw(c, c->bardir); - if(purehepta) { - cwstep(cw); - if(isbar4(cw.c)) { - cwstep(cw); cwspin(cw, 3); cwstep(cw); cwspin(cw, -1); cwstep(cw); - bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright); - if(b) return; - } - else { - bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright); - if(b) return; - } - } - else { - cwspin(cw, 3); cwstep(cw); - cell *cp = cwpeek(cw, 4); - if(!isbar4(cp)) { - cwspin(cw, 2); cwstep(cw); - bool b = buildBarrier4(cw.c, cw.spin, 2, oppositeElement(c->barleft, c->barright), c->barright); - if(b) return; - } - else { - bool b = buildBarrier4(c, c->bardir, 1, c->barleft, c->barright); - if(b) return; - } - } - } - - extendBarrierFront(c); - extendBarrierBack(c); - - if(c->barright == laCrossroads5) extendCR5(c); - } - -void chasmify(cell *c) { - c->wall = waChasm; c->item = itNone; - int q = 0; - cell *c2[10]; - for(int i=0; itype; i++) if(c->mov[i] && c->mov[i]->mpdist > c->mpdist && cellUnstable(c->mov[i])) - c2[q++] = c->mov[i]; - if(q) { - cell *c3 = c2[hrand(q)]; - c3->wall = waChasmD; - } - } - -void chasmifyEarth(cell *c) { - int q = 0; - int d2[10]; - for(int i=2; i<=c->type-2; i++) { - int j = (i+c->mondir)%c->type; - cell *c2 = c->mov[j]; - if(c2 && c2->mpdist > c->mpdist && ( - c2->wall == waDeadfloor || c2->wall == waDeadwall || - c2->wall == waDeadfloor2)) - d2[q++] = j; - } - if(!q) printf("no further move!\n"); - if(q) { - int d = d2[hrand(q)]; - cell *c3 = c->mov[d]; - c3->wall = waEarthD; - for(int i=0; itype; i++) { - cell *c4 = createMov(c3, i); - earthFloor(c4); - } - c3->mondir = c->spn(d); - } - earthWall(c); c->item = itNone; - } - -void chasmifyElemental(cell *c) { - int q = 0; - int d2[10]; - for(int i=2; i<=c->type-2; i++) { - int j = (i+c->mondir)%c->type; - cell *c2 = c->mov[j]; - if(c2 && c2->mpdist > c->mpdist && c2->land == c->land) - d2[q++] = j; - } - if(q) { - int d = d2[hrand(q)]; - cell *c3 = c->mov[d]; - if(!c3->monst) { - c3->wall = waElementalD; - for(int i=0; itype; i++) { - cell *c4 = createMov(c3, i); - if(c4->wall != waBarrier) c4->wall = waNone; - } - c3->mondir = c->spn(d); - } - } - c->wall = getElementalWall(c->land); - c->wparam = 100; c->item = itNone; - } - -bool incompatible1(eLand l1, eLand l2) { - if(isCrossroads(l1) && isCrossroads(l2)) return true; - if(l1 == laJungle && l2 == laMotion) return true; - if(l1 == laMirrorOld && l2 == laMotion) return true; - if(l1 == laPower && l2 == laWineyard) return true; - if(l1 == laPower && l2 == laDryForest) return true; - if(l1 == laDragon && l2 == laDryForest) return true; - if(l1 == laEFire && l2 == laWineyard) return true; - if(l1 == laEFire && l2 == laDryForest) return true; - if(l1 == laGraveyard && l2 == laDryForest) return true; - if(l1 == laGraveyard && l2 == laRedRock) return true; - if(l1 == laGraveyard && l2 == laEmerald) return true; - if(l1 == laDeadCaves && l2 == laEmerald) return true; - if(l1 == laDeadCaves && l2 == laCaves) return true; - if(l1 == laWarpSea && l2 == laKraken) return true; - if(isElemental(l1) && isElemental(l2)) return true; - return false; - } - -eLand randomElementalLand() { - int i = hrand(4); - eLand t[4] = { laEFire, laEWater, laEAir, laEEarth }; - return t[i]; - } - -int elementalKills() { - return - kills[moAirElemental] + kills[moWaterElemental] + kills[moEarthElemental] + kills[moFireElemental]; - } - -bool elementalUnlocked() { - return - kills[moAirElemental] && kills[moWaterElemental] && kills[moEarthElemental] && kills[moFireElemental]; - } - -bool trollUnlocked() { - return - kills[moTroll] && kills[moDarkTroll] && kills[moRedTroll] && - kills[moStormTroll] && kills[moForestTroll] && kills[moFjordTroll]; - } - -eLand randomElementalLandWeighted() { - int i = hrand(elementalKills()); - i -= kills[moAirElemental]; if(i<0) return laEAir; - i -= kills[moWaterElemental]; if(i<0) return laEWater; - i -= kills[moEarthElemental]; if(i<0) return laEEarth; - i -= kills[moFireElemental]; if(i<0) return laEFire; - printf("elemental bug\n"); - return laElementalWall; - } - -bool incompatible(eLand nw, eLand old) { - return (nw == old) || incompatible1(nw, old) || incompatible1(old, nw); - } - -#define HAUNTED_RADIUS (purehepta?5:7) -extern bool generatingEquidistant; - -bool rlyehComplete() { - if(chaosmode) return items[itStatue] >= 1; - return items[itStatue] >= 10 || items[itGrimoire] >= 10; - } - -bool lchance(eLand l) { - if(tactic::on || yendor::on) return true; - if(chaosmode) return hrand(100) < 25; - return hrand(100) >= 40 * kills[elementalOf(l)] / (elementalKills()+1); - } - -eLand pickLandRPM(eLand old) { - while(true) { - eLand n = randlands[hrand(RANDLANDS)]; - if(incompatible(n, old)) continue; - if(isRandland(n) == 2) return n; - if(hiitemsMax(treasureType(n)) < 10) - continue; - return n; - } - } - -eLand pickluck(eLand l1, eLand l2) { - int t1 = items[treasureType(l1)]; - int t2 = items[treasureType(l2)]; - if(t1 < t2) return l1; - if(t2 < t1) return l2; - if(isCrossroads(l1)) return l1; - return l2; - } - -#define LIKELY for(int u=0; u<5; u++) - -bool noChaos(eLand l) { - if(l == laOcean || l == laTemple) return false; - return - isCrossroads(l) || isCyclic(l) || isHaunted(l) || - l == laCaribbean || isGravityLand(l) || l == laPrincessQuest || - l == laPrairie || l == laHalloween; - } - -eLand getNewSealand(eLand old) { - while(true) { - eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken)); - if(p == laKraken && !landUnlocked(p)) continue; - if(p == laKraken && peace::on) continue; - if(incompatible(old, p)) continue; - if(p == old) continue; - if(chaosmode && noChaos(p)) continue; - return p; - } - } - -bool doEndorian = false; - -int whichnow=0; - -bool createOnSea(eLand old) { - return - old == laWarpSea || old == laCaribbean || old == laKraken || - (old == laLivefjord && hrand(2)) || - (old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant)); - } - -hookset *hooks_nextland; - -eLand getNewLand(eLand old) { - - if(old == laMirror && !chaosmode && hrand(10) >= (tactic::on ? 0 : markOrb(itOrbLuck) ? 5 : 2)) return laMirrored; - if(old == laTerracotta && !chaosmode && hrand(5) >= (tactic::on ? 0 : markOrb(itOrbLuck) ? 2 : 1)) return laTerracotta; - - eLand l = callhandlers(laNone, hooks_nextland, old); - if(l) return l; - - if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest; - - if(old == laTortoise) return laDragon; - - if(yendor::on && chaosmode) { - while(true) { - eLand n = eLand(hrand(landtypes)); - if(n == old) continue; - if(incompatible(n,old)) continue; - if(noChaos(n)) continue; - if(n == laElementalWall || isTechnicalLand(n)) continue; - if(n == laWildWest) continue; - if(isElemental(n) && hrand(100) >= 25) continue; - return n; - } - } - - if(markOrb(itOrbLuck)) { - int i = items[itOrbLuck]; - items[itOrbLuck] = 0; - eLand l1 = getNewLand(old); - for(int i=1; i<3; i++) - l1 = pickluck(l1, getNewLand(old)); - items[itOrbLuck] = i; - return l1; - } - - if(randomPatternsMode) return pickLandRPM(old); - - if(old == laEEarth && lchance(old)) return hrand(2) ? laEWater : laEFire; - if(old == laEAir && lchance(old)) return hrand(2) ? laEWater : laEFire; - if(old == laEWater && lchance(old)) return hrand(2) ? laEEarth : laEAir; - if(old == laEFire && lchance(old)) return hrand(2) ? laEEarth : laEAir; - - if(tactic::on && !(tactic::trailer && old == firstland)) return firstland; - - if(yendor::on && (yendor::clev().flags & YF_WALLS)) { - if(old != yendor::clev().l) return yendor::clev().l; - else if(old == laOcean) return pick(laLivefjord, laCaribbean); - } - - if(yendor::on && yendor::nexttostart) { - eLand l = yendor::nexttostart; - if(!(yendor::clev().flags & YF_REPEAT)) - yendor::nexttostart = laNone; - return l; - } - - if(old == laDragon && tortoise::seek() && hrand(100) < 50) - return laTortoise; - - if(isWarped(old) && (hrand(100) < 25) && chaosmode) return eLand(old ^ laWarpCoast ^ laWarpSea); - - if(createOnSea(old)) - return getNewSealand(old); - - if(old == laGraveyard && generatingEquidistant) - return laHaunted; - - if(old == laOcean && gold() >= R60 && hrand(100) < 75 && !rlyehComplete()) - return laRlyeh; - - if(old == laRlyeh && !rlyehComplete()) - return laOcean; - - eLand tab[256]; - int cnt = 0; - -/* if(isHive(old) && hrand(100) < 90) { - eLand n = old; - while(n == old) n = eLand(laHive0 + hrand(3)); - return n; - } */ - - // return (hrand(2)) ? laMotion : laJungle; - - // the basic lands, always available - tab[cnt++] = laCrossroads; - tab[cnt++] = laIce; - tab[cnt++] = laDesert; - tab[cnt++] = laJungle; - tab[cnt++] = laMotion; - tab[cnt++] = laAlchemist; - if(old != laDeadCaves) tab[cnt++] = laCaves; - - // the intermediate lands - if(gold() >= R30) { - tab[cnt++] = laCrossroads; - tab[cnt++] = laMirror; - tab[cnt++] = laOcean; - tab[cnt++] = laLivefjord; - tab[cnt++] = laMinefield; - tab[cnt++] = laPalace; - if(old == laDragon && items[itElixir] >= U10) LIKELY tab[cnt++] = laReptile; - if(kills[moVizier]) tab[cnt++] = laEmerald; - if(items[itFeather] >= U10) tab[cnt++] = laZebra; - tab[cnt++] = laWarpCoast; - if(euclid) tab[cnt++] = laWarpSea; - // Ivory Tower tends to crash while generating equidistant - if(!generatingEquidistant) tab[cnt++] = laIvoryTower; - if(items[itElixir] >= U10) tab[cnt++] = laReptile; - if(items[itIvory] >= U10 && !generatingEquidistant) tab[cnt++] = laEndorian; - - if(items[itKraken] >= U10) tab[cnt++] = laBurial; - } - - if(landUnlocked(laDungeon)) { - tab[cnt++] = laDungeon; - if(old == laPalace) LIKELY tab[cnt++] = laDungeon; - } - - // the advanced lands - if(gold() >= R60) { - tab[cnt++] = laStorms; - tab[cnt++] = laWhirlwind; - tab[cnt++] = laCrossroads; - if(!generatingEquidistant) tab[cnt++] = laCrossroads2; - if(items[itRuby] >= U10) { - tab[cnt++] = laOvergrown; - if(old == laJungle) LIKELY tab[cnt++] = laOvergrown; - } - if(rlyehComplete()) tab[cnt++] = laRlyeh; - else if(chaosmode && (old == laWarpCoast || old == laLivefjord || old == laOcean)) - tab[cnt++] = laRlyeh; - if(items[itStatue] >= U5 && chaosmode) - tab[cnt++] = laTemple; - if(old == laCrossroads || old == laCrossroads2) tab[cnt++] = laOcean; - if(old == laOcean) tab[cnt++] = laCrossroads; - if(items[itGold] >= U5 && items[itFernFlower] >= U5 && !kills[moVizier]) - tab[cnt++] = laEmerald; - tab[cnt++] = laDryForest; - tab[cnt++] = laWineyard; - if(items[itGold] >= U10) tab[cnt++] = laDeadCaves; - // tab[cnt++] = laCaribbean; - if(items[itSpice] >= U10) { - tab[cnt++] = laRedRock; - if(old == laDesert) LIKELY tab[cnt++] = laRedRock; - } - if(old == laRedRock) LIKELY tab[cnt++] = laDesert; - if(old == laOvergrown) LIKELY tab[cnt++] = laJungle; - tab[cnt++] = laRose; - } - - if(gold() >= R90) { - if(!chaosmode) tab[cnt++] = laPrairie; - if(old == laPrairie) LIKELY tab[cnt++] = laBull; - tab[cnt++] = laBull; - if(old == laBull && !chaosmode) LIKELY tab[cnt++] = laPrairie; - } - - if(gold() >= R300) - tab[cnt++] = laCrossroads5; - - if(tkills() >= R100) { - tab[cnt++] = laGraveyard; - if(gold() >= R60) tab[cnt++] = laHive; - } - - if(killtypes() >= R20) { - tab[cnt++] = laDragon; - if(old == laReptile) LIKELY tab[cnt++] = laDragon; - } - - if(trollUnlocked()) { - tab[cnt++] = laTrollheim; - if(isTrollLand(old)) LIKELY tab[cnt++] = laTrollheim; - if(old == laTrollheim) for(int i=0; i= U10) { - if(items[itDiamond] >= U10) { - tab[cnt++] = laCocytus; - if(old == laHell || old == laIce) LIKELY tab[cnt++] = laCocytus; - } - if(old == laCocytus) LIKELY { tab[cnt++] = laIce; tab[cnt++] = laHell; } - tab[cnt++] = laPower; - if(old == laCrossroads || old == laCrossroads2) tab[cnt++] = laOcean; - if(old == laOcean) tab[cnt++] = laCrossroads2; - } - - // for(int i=0; i<20; i++) tab[cnt++] = laRedRock; - // for(int i=0; i<20; i++) tab[cnt++] = laCaribbean; - // for(int i=0; i<20; i++) tab[cnt++] = laCocytus; - - // for(int i=0; i<20; i++) tab[cnt++] = laCrossroads; - - eLand n = old; - while(incompatible(n, old) || (chaosmode && noChaos(n))) n = tab[hrand(cnt)]; - - return n; - } - bool notDippingFor(eItem i) { if(peace::on) return false; int v = items[i] - currentLocalTreasure; @@ -1961,73 +32,6 @@ bool notDippingForExtra(eItem i, eItem x) { return v >= hrand(10) + 10; } -eLand euland[65536]; - -eLand switchable(eLand nearland, eLand farland, eucoord c) { - if(specialland == laCrossroads4) { - if(hrand(15) == 0) - return getNewLand(nearland); - return nearland; - } - else if(nearland == laCrossroads) { - if(hrand(4) == 0 && (short(c)%3==0)) - return laBarrier; - return laCrossroads; - } - else if(nearland == laBarrier) { - return getNewLand(farland); - } - else { - if(hrand(20) == 0 && (short(c)%3==0)) - return laBarrier; - return nearland; - } - } - -eLand getEuclidLand(eucoord c) { - if(euland[c]) return euland[c]; - if(c == 0 || c == eucoord(-1) || c == 1) - return euland[c] = specialland; - if(euland[eucoord(c-2)] && ! euland[eucoord(c-1)]) getEuclidLand(c-1); - if(euland[eucoord(c+2)] && ! euland[eucoord(c+1)]) getEuclidLand(c+1); - if(euland[eucoord(c-1)]) return - euland[c] = switchable(euland[c-1], euland[eucoord(c-2)], c); - if(euland[eucoord(c+1)]) return - euland[c] = switchable(euland[c+1], euland[eucoord(c+2)], c); - return euland[c] = laCrossroads; - } - -int newRoundTableRadius() { - return 28 + 2 * items[itHolyGrail]; - } - -int getAnthraxData(cell *c, bool b) { - int d = celldistAlt(c); - int rad = 28 + 3 * anthraxBonus; - while(d < -rad) { - d += rad + 12; - rad += 3; - } - while(d >= 12) { - if(rad > 5) rad -= 3; - else if(rad) rad--; - d -= rad + 12; - } - if(b) return rad; - return d; - } - -int roundTableRadius(cell *c) { - if(euclid) return 28; - if(tactic::on) return getAnthraxData(c, true); - return c->master->alt->alt->emeraldval & GRAIL_RADIUS_MASK; - } - -int celldistAltRelative(cell *c) { - if(tactic::on) return getAnthraxData(c, false); - return celldistAlt(c) - roundTableRadius(c); - } - void buildCamelotWall(cell *c) { c->wall = waCamelot; for(int i=0; itype; i++) { @@ -2037,740 +41,6 @@ void buildCamelotWall(cell *c) { } } -eLand showlist[10] = { - laHell, laRlyeh, laAlchemist, laGraveyard, laCaves, laDesert, laIce, laJungle, laMotion, laMirror - }; - -void buildBarrierForce(cell *c, int d, eLand l) { - c->bardir = d; - eLand oldland = c->land; - if(oldland == laNone) { - raiseBuggyGeneration(c, "oldland is NONE"); - return; - } - eLand newland = l ? l : getNewLand(oldland); - if(showoff) newland = showlist[(showid++) % 10]; - landcount[newland]++; - if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland; - else c->barleft = newland, c->barright = oldland; - if(!mirrorwall(c)) c->landparam = 40; - extendcheck(c); - } - -void buildBarrier(cell *c, int d, eLand l) { - d %= 7; - cellwalker bb(c, d); - - if(checkBarriersFront(bb) && checkBarriersBack(bb)) - buildBarrierForce(c, d, l); - } - -bool buildBarrier6(cellwalker cw, int type) { - limitgen("build6 %p/%d (%d)\n", cw.c, cw.spin, type); - - cellwalker b[4]; - for(int i=0; i<4; i++) b[i] = cw; - - if(buggyGeneration) return true; - - if(!purehepta) { - cwstep(b[0]); - cwspin(b[1], 1); cwstep(b[1]); cwspin(b[1], 3); cwstep(b[1]); - cwspin(b[2], 4); cwstep(b[2]); - cwspin(b[3], 3); cwstep(b[3]); cwspin(b[3], 3); cwstep(b[3]); - } - else { - cwspin(b[1], 3); cwstep(b[1]); cwspin(b[1], 3); - cwspin(b[2], -2); cwstep(b[2]); cwspin(b[2], -3); - cwspin(b[3], -3); cwstep(b[3]); cwspin(b[3], 2); cwstep(b[3]); cwspin(b[3],-3); - if(type == 1 && b[3].c->land != laMirrorWall) return false; - if(type == 2 && cwpeek(b[1], 0)->land != laMirrorWall) return false; - // if(type == 2 && b[2].c->land != laMirrorWall) return false; - } - - if(false) { - for(int z=0; z<4; z++) { - printf("%p/%d\n", b[z].c, b[z].spin); - b[z].c->wall = waStrandedBoat; b[z].c->land = laAlchemist; - b[z].c->mondir = b[z].spin; - b[z].c->mpdist = 7; - b[z].c->item = eItem(1+z); - buggyGeneration = true; - } - return true; - } - - if(type == 1) { - if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[1], 6, true)) return false; - if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[2], 6, true)) return false; - } - else { - if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[0], 6, true)) return false; - if(!(purehepta?checkBarriersFront:checkBarriersBack)(b[3], 6, true)) return false; - } - - for(int d=0; d<4; d++) { - b[d].c->bardir = b[d].spin; - - if(purehepta) { - b[0].c->barleft = laMirrored, b[0].c->barright = laMirrored2; - b[1].c->barleft = laMirror, b[1].c->barright = laMirrored; - b[2].c->barleft = laMirrored2, b[2].c->barright = laMirrored; - b[3].c->barleft = laMirrored, b[3].c->barright = laMirror; - } - else { - b[0].c->barleft = laMirror, b[0].c->barright = laMirrored; - b[1].c->barleft = laMirrored, b[1].c->barright = laMirror; - b[2].c->barleft = laMirrored, b[2].c->barright = laMirrored2; - b[3].c->barleft = laMirrored2, b[3].c->barright = laMirrored; - } - - (purehepta?extendBarrierFront:extendBarrierBack)(b[d].c); - } - - if(purehepta && false) { - for(int z=0; z<4; z++) - b[z].c->item = eItem(1+z+4*type); - for(int a=0; a<4; a++) - extendBarrierBack(cwpeek(b[a],0)); - } - - if(!purehepta) { - setland(cwpeek(cw, 1), laMirrorWall); - setland(cwpeek(cw, 2), laMirrored); - setland(cwpeek(cw, 3), laMirrorWall2); - setland(cwpeek(cw, 4), laMirrorWall2); - setland(cwpeek(cw, 5), laMirrored); - setland(cwpeek(cw, 0), laMirrorWall); - setland(cwpeek(b[0], 2), laMirrored); - setland(cwpeek(b[3], 6), laMirrored2); - setland(cwpeek(b[3], 5), laMirrored2); - setland(cwpeek(b[1], -1), laMirrored); - setland(cwpeek(b[2], -2), laMirrored); - setland(cwpeek(b[1], -2), laMirrored); - setland(cwpeek(b[0], -2), laMirror); - cw.c->land = laMirrorWall; - cw.c->wall = waMirrorWall; - cw.c->landparam = 1; - } - else { - setland(cw.c, laMirrorWall2); - setland(cwpeek(cw, 0), laMirrorWall2); - setland(cwpeek(cw, 1), laMirrored); - setland(cwpeek(cw, 2), laMirrored); - setland(cwpeek(cw, 3), laMirrorWall); - setland(cwpeek(cw, 4), laMirrored); - setland(cwpeek(cw, 5), laMirrorWall2); - setland(cwpeek(cw, 6), laMirrored2); - - setland(cwpeek(b[1], 0), laMirrorWall); - setland(cwpeek(b[1], 1), laMirror); - setland(cwpeek(b[1], 2), laMirrorWall); - setland(cwpeek(b[1], 6), laMirrored); - - cellwalker cf = b[0]; - cwstep(cf); - setland(cwpeek(cf, -2), laMirrored); - - cf = b[3]; - cwstep(cf); - setland(cwpeek(cf, -2), laMirrored); - } - - return true; - } - - - -bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) { - limitgen("build4 %p\n", c); - if(buggyGeneration) return true; - d %= 7; - cellwalker b1(c, d); - - cellwalker b2(c, d); - if(purehepta) cwstep(b2); - else { cwstep(b2); cwspin(b2, 3); cwstep(b2); cwspin(b2, 3); cwstep(b2); } - - cellwalker b3(c, d); - if(purehepta) { - cwspin(b3, -1); cwstep(b3); cwspin(b3, 3); - } - else { - cwstep(b3); cwspin(b3, 4); cwstep(b3); cwspin(b3, 4); - } - - cellwalker b4(c, d); - if(purehepta) { - cwspin(b4, 1); cwstep(b4); cwspin(b4, -3); - } - else { - cwstep(b4); cwspin(b4, -4); cwstep(b4); cwspin(b4, -4); - } - - if(mode == 0) { - if(!((checkBarriersBack(b1) && checkBarriersBack(b2)))) return false; - if(!((checkBarriersFront(b3) && checkBarriersFront(b4)))) return false; - } - - if(mode == 1) { - if(!(checkBarriersFront(b3, 5, true) && checkBarriersFront(b4, 5, true))) - return false; - } - - if(mode == 2) { - if(!((checkBarriersBack(b1, 5, true) && checkBarriersBack(b2, 5, true)))) - return false; - } - - eLand xl = oppositeElement(ll, lr); - eLand xr = oppositeElement(lr, ll); - - c->bardir = d, c->barleft = ll, c->barright = lr; extendBarrierBack(c); - - c= b2.c; d=b2.spin; - c->bardir = d, c->barleft = xl, c->barright = xr; extendBarrierBack(c); - - c= b3.c; d=b3.spin; - c->bardir = d, c->barleft = xl, c->barright = lr; extendBarrierFront(c); - - c= b4.c; d=b4.spin; - c->bardir = d, c->barleft = ll, c->barright = xr; extendBarrierFront(c); - - if(!purehepta) for(int a=-3; a<=3; a++) if(a) { - setland(cwpeek(b1, a), a > 0 ? lr : ll); - setland(cwpeek(b2, a), a > 0 ? xr : xl); - setland(cwpeek(b3, a), a > 0 ? lr : xl); - setland(cwpeek(b4, a), a > 0 ? xr : ll); - } - - if(purehepta) setbarrier(b1.c), setbarrier(b2.c), setbarrier(b3.c), setbarrier(b4.c); - - if(!purehepta) { - cell *cp; - cp = cwpeek(b1, 0); - cp->barleft = ll; cp->barright = lr; setbarrier(cp); - cp = cwpeek(b2, 0); - cp->barleft = xl; cp->barright = xr; setbarrier(cp); - } - - return true; - } - -void buildBarrierStrong(cell *c, int d, bool oldleft) { - d %= 7; - cellwalker bb(c, d); - - c->bardir = d; - eLand oldland = c->land; - eLand newland = getNewLand(oldland); - if(showoff) newland = showlist[(showid++) % 10]; - landcount[newland]++; - - if(oldleft) c->barleft = oldland, c->barright = newland; - else c->barleft = newland, c->barright = oldland; - extendcheck(bb.c); - } - -void buildCrossroads2(cell *c) { - - if(buggyGeneration) return; - - if(!c) return; - - for(int i=0; itype; i++) - if(c->mov[i] && !c->mov[i]->landparam && c->mov[i]->mpdist < c->mpdist) - buildCrossroads2(c->mov[i]); - - if(hasbardir(c)) - extendBarrier(c); - - if(c->land != laCrossroads2) return; - - if(!c->landparam) { - for(int i=0; itype; i++) { - cell *c2 = createMov(c, i); - if(c2 && c2->landparam && (c2->land == laCrossroads2 || c2->land == laBarrier)) { - for(int j=0; jtype; j++) { - createMov(c2, j); - cell *c3 = c2->mov[j]; - if(c3 && c3->landparam && (c3->land == laCrossroads2 || c3->land == laBarrier)) { - int h2 = c2->landparam; - int h3 = c3->landparam; - - if(h2 > 100) { raiseBuggyGeneration(c2, "bad c2 landparam"); return; } - if(h3 > 100) { raiseBuggyGeneration(c3, "bad c3 landparam"); return; } - - // ambiguous - if(h2/4 == 1 && h3/4 == 3) continue; - if(h2/4 == 3 && h3/4 == 1) continue; - - for(int d=0; dtype; d++) - if(emeraldtable[h2][d] == h3) { - int nh = emeraldtable[h2][(42+d + c->spn(i) - j) % c2->type]; - if(c->landparam>0 && c->landparam != nh) { - printf("CONFLICT\n"); - raiseBuggyGeneration(c, "CONFLICT"); - } - c->landparam = nh; - } - - if(c->landparam == 0) - printf("H2 = %d H3=%d\n", c2->landparam, c3->landparam); - } - } - if(c->landparam == 0) { - printf("H2 = %d\n", c2->landparam); -// halted = true; -// c->heat = -1; - raiseBuggyGeneration(c, "buildCrossroads2x"); - return; - } - } - } - - if(c->landparam) { -// for(int i=0; itype; i++) { -// cell *c2 = c->mov[i]; -// buildCrossroads2(c2); -// } - } - else { - raiseBuggyGeneration(c, "buildCrossroads2"); - return; - } - } - - int h = c->landparam; - - if(h/4 >= 8 && h/4 <= 11) { - for(int i=0; itype; i++) { - createMov(c, i)->land = laCrossroads2; - if(!c->mov[i]->landparam) buildCrossroads2(c->mov[i]); - } - if(h/4 == 8 || h/4 == 10) - for(int i=0; itype; i++) { - if(c->mov[i] && c->mov[i]->landparam == h-4) { - bool oldleft = true; - for(int j=1; j<=3; j++) - if(c->mov[(i+j)%7] && c->mov[(i+j)%7]->mpdist < c->mpdist) - oldleft = false; - - c->landparam = h; - buildBarrierStrong(c, i, oldleft); - c->landparam = h; - extendBarrier(c); - } - } - } - } - -extern bool bugtrack; - -bool generatingEquidistant = false; - -cell *buildAnotherEquidistant(cell *c, int radius) { - int gdir = -1; - for(int i=0; itype; i++) { - if(c->mov[i] && c->mov[i]->mpdist < c->mpdist) gdir = i; - } - if(gdir == -1) return NULL; - - cellwalker cw(c, (gdir+3) % c->type); - vector coastpath; - while(size(coastpath) < radius || cw.c->type != 7) { - // this leads to bugs for some reason! - if(cw.c->land == laCrossroads2) { -#ifdef AUTOPLAY - if(doAutoplay) printf("avoiding the Crossroads II\n"); // todo -#endif - return NULL; - } - if(cw.c->bardir != NODIR) return NULL; - - /* forCellEx(c2, cw.c) if(c2->bardir != NODIR) { - generatingEquidistant = false; - return; - } */ - coastpath.push_back(cw.c); - if(cw.c->land == laNone && cw.c->mpdist <= 7) { - raiseBuggyGeneration(cw.c, "landNone 1"); - for(int i=0; iitem = itPirate; - return NULL; - } - cwstep(cw); cwspin(cw, 3); - if(cw.c->type == 7 && hrand(2) == 0) cwspin(cw, 1); - } - coastpath.push_back(cw.c); - // printf("setdists\n"); - for(int i=1; iland == laNone) { - raiseBuggyGeneration(cwt.c, "landNone 3"); - int mpd[10]; - for(int i=0; i<10; i++) mpd[i] = coastpath[i]->mpdist; - {for(int i=0; i<10; i++) printf("%d ", mpd[i]);} printf("\n"); - for(int i=0; iitem = itPirate; - return NULL; - } - setdist(coastpath[i], BARLEV, coastpath[i-1]); - setdist(coastpath[i], BARLEV-1, coastpath[i-1]); - if(i < size(coastpath) - 5) { - coastpath[i]->bardir = NOBARRIERS; -// coastpath[i]->item = itSapphire; -// forCellEx(c2, coastpath[i]) c2->bardir = NOBARRIERS; - } - } - - //printf("building barrier\n"); - cell *c2 = coastpath[coastpath.size() - 1]; - int bd = 2 + (hrand(2)) * 3; - - bool nowall = false; - - if(c2->land == laNone) { - raiseBuggyGeneration(c2, "landNone 2"); - for(int i=0; iitem = itPirate; - return NULL; - } - - // prevent gravity anomalies - if(c2->land != c->land) return NULL; - - // else if(c->type == 7 && hrand(10000) < 20 && !isCrossroads(c->land) && gold() >= 200) - if(c2->type == 7 && gold() >= R200 && hrand(10) < 2 && buildBarrierNowall(c2, laCrossroads4, true)) { - nowall = true; - // raiseBuggyGeneration(c2, "check"); - // return; - } - else buildBarrier(c2, bd); - //printf("building barrier II\n"); - if(hasbardir(c2)) extendBarrier(c2); - - for(int i=size(coastpath)-(nowall?1:2); i>=0; i--) { - for(int j=BARLEV; j>=6; j--) - setdist(coastpath[i], j, NULL); - } - - return c2; - } - -void buildAnotherEquidistant(cell *c) { - //printf("building another coast\n"); - - if(yendor::on) return; - - generatingEquidistant = true; - - int radius = c->land == laOcean ? 30 : HAUNTED_RADIUS + 5; - - buildAnotherEquidistant(c, radius); - - generatingEquidistant = false; - } - -bool bugtrack = false, bugfound = false; - -#define UNKNOWN 65535 - -int coastval(cell *c, eLand base) { - if(!c) return UNKNOWN; - if(c->land == laNone) return UNKNOWN; - if(base == laGraveyard) { - if(c->land == laHaunted || c->land == laHauntedWall) - return 0; - if(c->land != laGraveyard && c->land != laHauntedBorder) return 30; - } - else if(base == laMirrored) { - if(!inmirror(c)) return 0; - if(!c->landparam) return UNKNOWN; - return c->landparam & 255; - } - else { - if(c->land == laOceanWall || c->land == laCaribbean || c->land == laWhirlpool || - c->land == laLivefjord || c->land == laWarpSea || c->land == laKraken) - return 30; - if(c->land != laOcean && !isGravityLand(c->land) && c->land != laHaunted) { - return 0; - } - } - if(!c->landparam) return UNKNOWN; - return c->landparam; - } - -eMonster crossroadsMonster() { - - static eMonster weak[9] = { - moYeti, moGoblin, moRanger, moOrangeDog, moRunDog, moMonkey, moZombie, - moDesertman, moCultist - }; - - if(hrand(10) == 0) return weak[hrand(9)]; - - static eMonster m[24] = { - moWorm, moTentacle, - moTroll, moEagle, - moLesser, moGreater, moPyroCultist, moGhost, - moFireFairy, moIvyRoot, moHedge, - moLancer, moFlailer, moVineBeast, - moBomberbird, moAlbatross, moRedTroll, - moWaterElemental, moAirElemental, moFireElemental, - moFatGuard, moMiner, moPalace, moVizier - }; - eMonster mo = m[hrand(24)]; - if(peace::on && mo == moWaterElemental) return crossroadsMonster(); - if(peace::on && mo == moFireFairy) return crossroadsMonster(); - if(peace::on && isMultitile(mo)) return crossroadsMonster(); - return mo; - } - -eMonster wanderingCrossroadsMonster() { - while(true) { - eMonster m = crossroadsMonster(); - if(!isIvy(m) && m != moTentacle) return m; - } - } - -bool checkInTree(cell *c, int maxv) { - if(c->landparam <= 3) return false; - if(!maxv) return false; - if(c->landflags) return true; - for(int t=0; ttype; t++) - if(c->mov[t] && c->mov[t]->landparam < c->landparam && checkInTree(c->mov[t], maxv-1)) - return true; - return false; - } - -void buildEquidistant(cell *c) { - if(!c) return; - if(c->landparam) return; - eLand b = c->land; - if(chaosmode && !inmirror(b)) return; - if(!b) { - printf("land missing at %p\n", c); - describeCell(c); - for(int i=0; itype; i++) if(c->mov[i]) - describeCell(c->mov[i]); - // buggycells.push_back(c); - } - if(b == laHauntedBorder) b = laGraveyard; - if(inmirror(b)) b = laMirrored; - int mcv = UNKNOWN; - - // find the lowest coastval - for(int i=0; itype; i++) { - int cv = coastval(createMov(c,i), b); - if(cv < mcv) mcv = cv; - } - - int mcv2 = 0; - - if(bugfound) { mcv = 1; c->landparam = 10; } - - else if(mcv == 0) { - // if(generatingEquidistant) printf("mcv=0\n"); - c->landparam = 1; - } - else { - // if it appears twice, increase it - int qcv = 0; - int sid = 0; - for(int i=0; itype; i++) - if(coastval(c->mov[i], b) == mcv) - qcv++, sid = i; - - // if(generatingEquidistant) printf("qcv=%d mcv=%d\n", qcv, mcv); - if(qcv >= 2) c->landparam = mcv+1; // (mcv == UNKNOWN ? UNKNOWN : mcv+1); - else { - // if(qcv != 1) { printf("qcv = %d\n", qcv); exit(1); } - cell *c2 = c->mov[sid]; - int bsid = c->spn(sid); - for(int j=0; j<7; j++) { - int q = (bsid+j+42) % c2->type; - cell *c3 = c2->mov[q]; - if(coastval(c3, b) < mcv) { - cell *c4 = createMovR(c2, bsid+1); - if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2); - buildEquidistant(c4); - mcv2 = coastval(c4, b); - break; - } - q = (bsid-j+42) % c2->type; - c3 = c2->mov[q]; - if(coastval(c3, b) < mcv) { - cell *c4 = createMovR(c2, bsid-1); - if(c4->land == laNone && c2->mpdist <= BARLEV) setdist(c4, BARLEV, c2); - buildEquidistant(c4); - mcv2 = coastval(c4, b); - break; - } - } - if(bugfound) c->item = itSapphire; - if(mcv2 > mcv) mcv2 = mcv; - if(mcv2 == 0) mcv2 = mcv; - c->landparam = mcv2+1; - - /* if(c->heat < 3) - raiseBuggyGeneration(c, "low heat"); */ - } - } - - if(!c->landparam) { - // int z = int(c->heat); - if(c->item || c->monst) - printf("building coast over %s/%s, mpdist = %d\n", iinf[c->item].name, minf[c->monst].name, - c->mpdist); - if(c->land == laOcean) c->wall = waSea; - } - - if(c->land == laEndorian) { - if(c->landparam == 1 && c->type == 7) { - for(int i=0; i<7; i++) { - int i1 = (i+1) % 7; - if(c->mov[i] && c->mov[i]->land != laEndorian && c->mov[i]->land != laNone) - if(c->mov[i1] && c->mov[i1]->land != laEndorian && c->mov[i1]->land != laNone) { - c->landflags = 2; - c->wall = waTrunk; - } - } - } - else if(c->landparam == 1 && c->type == 6) { - for(int i=0; i<6; i++) { - int i1 = (i+1) % 6; - int i2 = (i+2) % 6; - int i4 = (i+4) % 6; - int i5 = (i+5) % 6; - if(c->mov[i] && c->mov[i]->land == laBarrier && c->mov[i]->type == 7) - if(c->mov[i1] && c->mov[i1]->land != laBarrier) - if(c->mov[i2] && c->mov[i2]->land != laBarrier) - if(c->mov[i4] && c->mov[i4]->land != laBarrier) - if(c->mov[i5] && c->mov[i5]->land != laBarrier) { - c->landflags = 2; - c->wall = waTrunk; - } - - if(c->mov[i] && c->mov[i]->land != laEndorian && c->mov[i]->land != laNone && c->mov[i]->type == 7) - if(c->mov[i1] && c->mov[i1]->land != laEndorian && c->mov[i1]->land != laNone) - if(c->mov[i5] && c->mov[i5]->land != laEndorian && c->mov[i5]->land != laNone) { - c->landflags = 3; - c->wall = waTrunk; - } - } - } - else if(c->landparam > 1) { - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(c2 && c2->landparam < c->landparam && c2->landflags) { - bool ok = false; - if(c2->landflags == 3) - ok = true; - else if(c2->landflags == 2) { - ok = c->mov[(i+1)%c->type]->landparam != c->landparam-1 - && c->mov[(i+c->type-1)%c->type]->landparam != c->landparam-1; - } - else for(int j=0; jtype; j++) { - cell *c3 = c2->mov[j]; - if(c3 && c3->landparam < c2->landparam && c3->landflags) - if(c->spn(i) == (j+3)%c2->type || c->spn(i) == (j+c2->type-3)%c2->type) - ok = true; - } - if(ok) { - c->wall = waTrunk; - c->landflags = 1; - } - } - if(c2 && c2->landparam < c->landparam && c2->landflags == 1 && c->type == 7) { - cell *c3 = c->mov[(i+1)%7]; - if(c3 && c3->landparam < c->landparam && c3->landflags == 1) { - c->wall = waTrunk; - c->landflags = 2; - } - } - } - - if(!c->landflags && checkInTree(c, 5)) { - int lev = hrand(100); - if(lev < 10) c->wall = waSolidBranch; - else if(lev < 20) c->wall = waWeakBranch; - else c->wall = waCanopy; - } - } - } - - if(c->landparam > 30 && b == laOcean && !generatingEquidistant && hrand(10) < 5) - buildAnotherEquidistant(c); - - if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && hrand(100) < (purehepta?25:5) && items[itBone] >= 10) - buildAnotherEquidistant(c); - } - -void beCIsland(cell *c) { - int i = hrand(3); - if(i == 0) c->wall = waCIsland; - if(i == 1) c->wall = waCIsland2; - if(i == 2) c->wall = waCTree; - return; - } - -void generateTreasureIsland(cell *c) { - if(!euclid) generateAlts(c->master); - if(isOnCIsland(c)) return; - - bool src = hrand(100) < 10; - if(src) { - beCIsland(c); - if(c->wall == waCTree) return; - } - cell* ctab[7]; - int qc = 0, qlo, qhi; - for(int i=0; itype; i++) { - cell *c2 = createMov(c, i); - if(!euclid) generateAlts(c2->master); - if((euclid || (c->master->alt && c2->master->alt)) && celldistAlt(c2) < celldistAlt(c)) { - ctab[qc++] = c2; - qlo = i; qhi = i; - while(true) { - qlo--; - c2 = createMovR(c, qlo); - if(!euclid && !c2->master->alt) break; - if(celldistAlt(c2) >= celldistAlt(c)) break; - ctab[qc++] = c2; - } - while(true) { - qhi++; - c2 = createMovR(c, qhi); - if(!euclid && !c2->master->alt) break; - if(celldistAlt(c2) >= celldistAlt(c)) break; - ctab[qc++] = c2; - } - break; - } - } - if(!qc) { - printf("NO QC\n"); c->wall = waSea; - for(int i=0; itype; i++) printf("%d ", celldistAlt(c->mov[i])); - printf("vs %d\n", celldistAlt(c)); - return; - } - cell* c2 = createMovR(c, (qlo+qhi)/2); - generateTreasureIsland(c2); - if(!src) { - c->wall = c2->wall; - if(c->wall != waCTree && hrand(100) < 15) - c->wall = (c->wall == waCIsland ? waCIsland2 : waCIsland); - } - if(src && c2->wall == waCTree && (euclid||c->master->alt) && celldistAlt(c) <= -10) { - bool end = true; - for(int i=0; iwall != waCTree) - end = false; - } - // printf("%p: end=%d, qc=%d, dist=%d\n", c, end, qc, celldistAlt(c)); - if(end) c->item = itPirate; - else c->item = itCompass; - } - } - void buildRedWall(cell *c, int gemchance) { if(c->monst) return; int ki = PT(kills[moHexSnake] + kills[moRedTroll], 50); @@ -2783,772 +53,13 @@ void buildRedWall(cell *c, int gemchance) { placePrizeOrb(c); } -int palaceHP() { - if(tactic::on && isCrossroads(firstland)) - return 4; - if(items[itPalace] < 3) // 1+2 - return 2; - else if(items[itPalace] < 10) // 1+2+3+4 - return 3; - else if(items[itPalace] < 21) // 1+2+3+4+5+6 - return 4; - else if(items[itPalace] < 35) - return 5; - else if(items[itPalace] < 50) - return 6; - else return 7; - } - -cell *randomDown(cell *c) { - cell *tab[7]; - int q=0; - for(int i=0; itype; i++) - if(c->mov[i] && coastval(c->mov[i], laIvoryTower) < coastval(c, laIvoryTower)) - tab[q++] = c->mov[i]; - if(!q) return NULL; - if(q==1) return tab[0]; - return tab[hrand(q)]; - } - -// which=1 => right, which=-1 => left -// set which=1,bonus=1 to get right neighbor on level - -typedef int cellfunction(cell*); - -cell *chosenDown(cell *c, int which, int bonus, cellfunction* cf) { - int d = (*cf)(c)-1; - for(int i=0; itype; i++) { - if(!c->mov[i]) createMov(c, i); - if(c->mov[i]->mpdist > BARLEV && cf == coastvalEdge) setdist(c->mov[i], BARLEV, c); - - if((*cf)(c->mov[i]) == d) { - int i2 = (i+which+42)%c->type; - createMov(c, i2); - if((*cf)(c->mov[i2]) == d) - return createMovR(c, i2+bonus); - else return createMovR(c, i+bonus); - } - } - // printf("nothing down here\n"); - return NULL; - } - -int edgeDepth(cell *c) { - if(c->land == laIvoryTower || c->land == laEndorian || c->land == laDungeon) - return coastvalEdge(c); - else if(c->land != laBarrier) { - for(int i=0; itype; i++) if(c->mov[i] && c->mov[i]->land == laBarrier) - return -20+c->cpdist; - } - return 0; - } - -int getHauntedDepth(cell *c) { - if((tactic::on || euclid) && c->land == laHaunted) return celldist(c); - if(c->land == laHaunted) return c->landparam; - if(c->land == laHauntedWall) return 0; - if(c->land == laHauntedBorder || c->land == laGraveyard) return -c->landparam; - return -100; - } - -const int NOCOMPASS = 1000000; - -int compassDist(cell *c) { - if(c->master->alt) return celldistAlt(c); - if(isHaunted(c->land) || c->land == laGraveyard) return getHauntedDepth(c); - return NOCOMPASS; - } - -cell *findcompass(cell *c) { - int d = compassDist(c); - if(d == NOCOMPASS) return NULL; - - while(inscreenrange(c)) { - generateAlts(c->master); - forCellEx(c2, c) if(compassDist(c2) < d) { - c = c2; - d = compassDist(c2); - goto nextk; - } - break; - nextk: ; - } - - return c; - } - -int towerval(cell *c, cellfunction* cf) { - // if(c->land != laEdge) return 0; - cell *cp1 = chosenDown(c, 1, 1, cf); - if(!cp1) return 0; - /* cell *cp2 = chosenDown(cp1, 1, 1); - if(!cp2) return 0; - cell *cm1 = chosenDown(c, -1, -1); - if(!cm1) return 0; - cell *cm2 = chosenDown(cm1, -1, -1); - if(!cm2) return 0; */ - - /* return - (c->type-6) - + 2*(cp1->type-6) + 4*(cp2->type-6) - + 8*(cm1->type-6) +16*(cm2->type-6); */ - - int under = 0; - int cfc = (*cf)(c); - for(int i=0; itype; i++) { - if(c->mov[i] && (*cf)(c->mov[i]) < cfc) - under++; - } - return (c->type-6) + 2*(cp1->type-6) + 4*under; - } - -int hardness_empty() { - return yendor::hardness() * (yendor::hardness() * 3/5 - 2); - } - -int hivehard() { - return items[itRoyalJelly] + hardness_empty(); - // 0, 5, 40, 135 - } - -eMonster randomHyperbug() { - int h = hivehard(); - if(hrand(200) < h) - return moBug2; - return eMonster(moBug0 + hrand(BUGCOLORS)); - // 50: 25/25/50 - // 100: - } - #define RANDPATC(c) (randpattern(c,randompattern[c->land])) #define RANDPATCL(c, l) (randpattern(c,l)) #define RANDPAT (randpattern(c,randompattern[c->land])) #define RANDPAT3(i) (randpatternMajority(c,i,RANDITER)) #define RANDPATV(x) (randpattern(c,randompattern[x])) -bool buildBarrierNowall(cell *c, eLand l2, bool force) { - - int dtab[3] = {0,1,6}; - - if(c->land == laNone) { - printf("barrier nowall! [%p]\n", c); - raiseBuggyGeneration(c, "barrier nowall!"); - return false; - } - - for(int i=0; i<3; i++) { - int d = dtab[i]; - if(force) d=1; - cellwalker cw(c, d); - - if(force || (checkBarriersNowall(cw, 0, -1) && checkBarriersNowall(cw, 0, 1))) { - eLand l1 = c->land; - checkBarriersNowall(cw, 0, -1, l1, l2); - checkBarriersNowall(cw, 0, 1, l1, l2); - extendBarrier(c); - return true; - } - } - - return false; - } - -void setLandQuotient(cell *c) { - int fv = zebra40(c); - if(fv/4 == 4 || fv/4 == 6 || fv/4 == 5 || fv/4 == 10) fv ^= 2; - if(specialland == laWarpCoast) - if(fv%4==0 || fv%4 == 2) setland(c, laWarpSea); - if(specialland == laElementalWall) - setland(c, eLand(laEFire + (fv%4))); - } - -bool quickfind(eLand l) { - if(l == cheatdest) return true; -#if CAP_TOUR - if(tour::on && tour::quickfind(l)) return true; -#endif - return false; - } - -void setLandSphere(cell *c) { - if(specialland == laWarpCoast) - setland(c, getHemisphere(c, 0) > 0 ? laWarpCoast : laWarpSea); - if(specialland == laElementalWall) { - int x = getHemisphere(c, 1); - int y = getHemisphere(c, 2); - if(x > 0 && y > 0) setland(c, laEFire); - else if(x > 0 && y < 0) setland(c, laEAir); - else if(x < 0 && y < 0) setland(c, laEWater); - else if(x < 0 && y > 0) setland(c, laEEarth); - else if(x > 0) - c->land = laElementalWall, c->barleft = laEAir, c->barright = laEFire; - else if(x < 0) - c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEWater; - else if(y > 0) - c->land = laElementalWall, c->barleft = laEEarth, c->barright = laEFire; - else if(y < 0) - c->land = laElementalWall, c->barleft = laEAir, c->barright = laEWater; - if(c->land == laElementalWall && c->type != 6) - c->wall = getElementalWall(hrand(2) ? c->barleft : c->barright); - } - if(specialland == laCrossroads || specialland == laCrossroads2 || specialland == laCrossroads3) { - int x = getHemisphere(c, 1); - if(x == 0 || (specialland == laCrossroads3 && getHemisphere(c, 2) == 0)) - setland(c, laBarrier), c->wall = waBarrier; - else setland(c, specialland); - if(specialland == laCrossroads3 && c->type != 6 && c->master->fiftyval == 1) - c->wall = waBigTree; - } - } - -void setLandEuclid(cell *c) { - setland(c, specialland); - if(specialland == laCrossroads) { - eucoord x, y; - decodeMaster(c->master, x, y); - setland(c, getEuclidLand(y+2*x)); - } - if(specialland == laCrossroads4) { - eucoord x, y; - decodeMaster(c->master, x, y); - c->land = getEuclidLand(y); - } - if(specialland == laWhirlpool) { - c->land = laOcean; - c->landparam = 99; - } - if(specialland == laPrincessQuest) setland(c, laPalace); - if(specialland == laOcean) { - eucoord x, y; - decodeMaster(c->master, x, y); - int y0 = y; if(y>50000) y0 -= 65536; y0 += 10; - if(y0 == 0) - { setland(c, laBarrier); if(ishept(c)) c->land = laRlyeh; } - else if(y0<0) setland(c, laRlyeh); - else c->landparam = y0; - } - if(specialland == laIvoryTower || specialland == laDungeon) { - eucoord x, y; - decodeMaster(c->master, x, y); - int y0 = y; if(y>50000) y0 -= 65536; y0 = -y0; y0 -= 5; - if(y0 == 0) - {setland(c, laBarrier); if(ishept(c)) setland(c, laAlchemist); } - else if(y0<0) setland(c, laAlchemist); - else { - c->landparam = y0; - } - } - if(specialland == laElementalWall) { - eucoord x, y; - decodeMaster(c->master, x, y); - int y0 = y; if(y>32768) y0 -= 65536; - int x0 = x +y/2; - - int id = 0; - if(y0&16) id += 2; - if(x0&16) id += 1; - - x0 += 8; y0 += 8; - - y0--; x0++; - int id2 = 0; - if(y0&16) id2 += 2; - if(x0&16) id2 += 1; - - setland(c, eLand(laEFire + id)); - - if(((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) { - if(c->land == laEFire) c->wall = waEternalFire; - if(c->land == laEWater) c->wall = waSea; - if(c->land == laEAir) c->wall = waChasm; - if(c->land == laEEarth) c->wall = waStone; - c->barright = c->land; - c->barleft = eLand(laEFire+id2); - setland(c, laElementalWall); - } - } - if(specialland == laCrossroads3) { - eucoord x, y; - decodeMaster(c->master, x, y); - int y0 = y; if(y>32768) y0 -= 65536; - int x0 = x +y/2; - - x0 += 24; y0 += 8; - - int id = 0; - if(y0&16) id ^= 1; - if(x0&16) id ^= 1; - - setland(c, id ? laCrossroads3 : laDesert); - - if(((y0&15) == 15 && (x0&1)) || ((x0&15) == 0 && ((y0+1)&1))) { - setland(c, laBarrier); - c->wall = waBarrier; - } - } - if(specialland == laWarpCoast) { - eucoord x, y; - decodeMaster(c->master, x, y); - - int zz = 2*short(x)+short(y) + 10; - zz %= 30; if(zz<0) zz += 30; - if(zz >= 15) - setland(c, laWarpSea); - else - setland(c, laWarpCoast); - } - } - -#define INVLUCK (items[itOrbLuck] && inv::on) -#define I2000 (INVLUCK?600:2000) -#define I10000 (INVLUCK?3000:10000) - -void buildBigStuff(cell *c, cell *from) { - if(sphere || quotient) return; - bool deepOcean = false; - - if(c->land == laOcean) { - if(!from) deepOcean = true; - else for(int i=0; itype; i++) { - cell *c2 = from->mov[i]; - if(c2 && c2->land == laOcean && c2->landparam > 30) { - deepOcean = true; - } - if(c2) forCellEx(c3, c2) if(c3 && c3->land == laOcean && c3->landparam > 30) - deepOcean = true; - } - } - - if(c->land == laGraveyard) { - if(!from) deepOcean = true; - else for(int i=0; itype; i++) { - cell *c2 = from->mov[i]; - if(c2 && c2->landparam > HAUNTED_RADIUS+5) - deepOcean = true; - } - } - - if(generatingEquidistant) deepOcean = false; - - // buildgreatwalls - - if(chaosmode) { - if(c->type == 7 && hrand(10000) < 9000 && c->land && !inmirror(c) && buildBarrierNowall(c, getNewLand(c->land))) - {} - else if(c->type == 7 && c->land == laMirror && hrand(10000) < 2000) { - int bd = 2 + hrand(2) * 3; - buildBarrier(c, bd, laMirrored); - } - } - - else if(c->type == 7 && isWarped(c->land) && hrand(10000) < 3000 && c->land && - buildBarrierNowall(c, eLand(c->land ^ laWarpSea ^ laWarpCoast))) ; - - else if(c->type == 7 && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && - buildBarrierNowall(c, getNewLand(laCrossroads4))) ; - - else if(c->type == 7 && hrand(I10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= R200 && - !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) && - (c->land != laRlyeh || rlyehComplete()) && - c->land != laTortoise && c->land != laPrairie && c->land && - !(c->land == laGraveyard && !deepOcean) - && c->land != laCanvas - ) { - buildBarrierNowall(c, laCrossroads4) ; - } - - else if(c->land == laCrossroads2 && !purehepta) - buildCrossroads2(c); - - else if(c->land == laPrairie && c->LHU.fi.walldist == 0) { - for(int bd=0; bd<7; bd++) { - int fval2 = createStep(c->master, bd)->fieldval; - int wd = fp43.gmul(fval2, fp43.inverses[c->fval-1]); - if(fp43.distwall[wd] == 0) { - buildBarrier(c, bd); - break; - } - } - } - - else if(c->type == 7 && c->land && hrand(I10000) < ( - showoff ? (cwt.c->mpdist > 7 ? 0 : 10000) : - inmirror(c) ? 0 : - isGravityLand(c->land) ? 0 : - generatingEquidistant ? 0 : - c->land == laPrairie ? 0 : - (yendor::on && yendor::nexttostart) ? 10000 : - princess::challenge ? 0 : - isElemental(c->land) ? 4000 : - (yendor::on && (yendor::generating || !(yendor::clev().flags & YF_WALLS))) ? 0 : - c->land == laCrossroads3 ? 10000 : - c->land == laCrossroads ? 5000 : - c->land == laCrossroads2 ? 10000 : - c->land == laCrossroads5 ? 10000 : - c->land == laCrossroads4 ? 0 : - (c->land == laMirror && !yendor::generating) ? 6000 : - c->land == laTerracotta ? 250 : - (tactic::on && !tactic::trailer) ? 0 : - c->land == laCaribbean ? 500 : - (c->land == laWarpSea || c->land == laWarpCoast) ? 500 : - c->land == laStorms ? 250 : - c->land == laCanvas ? 0 : - c->land == laHaunted ? 0 : - (c->land == laGraveyard && !deepOcean) ? 0 : - (c->land == laGraveyard && items[itBone] >= 10) ? 120 : - c->land == laOcean ? (deepOcean ? (purehepta ? 250 : 2000) : 0) : - c->land == laDragon ? 120 : - 50)) - { - - int bd = 2 + hrand(2) * 3; - - buildBarrier(c, bd); - - /* int bd = 2; - buildBarrier4(c, bd, 0, getNewLand(c->land), c->land); */ - } - - if((!chaosmode) && bearsCamelot(c->land) && c->type == 7 && - (quickfind(laCamelot) || peace::on || (hrand(I2000) < 200 && - items[itEmerald] >= U5 && !tactic::on))) { - int rtr = newRoundTableRadius(); - heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin); - if(alt) { - alt->emeraldval = rtr; - alt->fiftyval = c->land; - } - } - - if(!chaosmode) { - - // buildbigstuff - - if(c->land == laRlyeh && c->type == 7 && - (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && - items[itStatue] >= U5 && !randomPatternsMode && - !tactic::on && !yendor::on))) - createAlternateMap(c, 2, hsA); - - if(c->land == laJungle && c->type == 7 && - (quickfind(laMountain) || (hrand(I2000) < 100 && - !randomPatternsMode && !tactic::on && !yendor::on && landUnlocked(laMountain)))) - createAlternateMap(c, 2, hsA); - - if(c->land == laOvergrown && c->type == 7 && - (quickfind(laClearing) || (hrand(I2000) < 25 && - !randomPatternsMode && items[itMutant] >= U5 && - !tactic::on && !yendor::on))) { - heptagon *h = createAlternateMap(c, 2, hsA); - if(h) clearing::bpdata[h].root = NULL; - } - - if(c->land == laStorms && c->type == 7 && hrand(2000) < 1000 && !randomPatternsMode) { - heptagon *h = createAlternateMap(c, 2, hsA); - if(h) h->alt->emeraldval = hrand(2); - } - - if(c->land == laOcean && c->type == 7 && deepOcean && !generatingEquidistant && !peace::on && - (quickfind(laWhirlpool) || ( - hrand(2000) < (purehepta ? 500 : 1000) && !tactic::on && !yendor::on))) - createAlternateMap(c, 2, hsA); - - if(c->land == laCaribbean && c->type == 7) - createAlternateMap(c, 2, hsA); - - if(c->land == laPalace && c->type == 7 && !princess::generating && !shmup::on && multi::players == 1 && - (princess::forceMouse ? (from && from->pathdist != INF) : - (hrand(2000) < (peace::on ? 100 : 20))) && - !c->master->alt && - (princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) { - createAlternateMap(c, PRADIUS0, hsOrigin, waPalace); - celllister cl(c, 5, 1000000, NULL); - for(cell *c: cl.lst) if(c->master->alt) generateAlts(c->master); - } - } - - if(hasbardir(c)) extendBarrier(c); - } - -void buildIvoryTower(cell *c) { - /* if(int(c->landparam) % 5 == 0) - c->wall = waCamelot; - */ - - if(euclid) { - eucoord x, y; - decodeMaster(c->master, x, y); - string tab[] = { - ".####...", - "L...L...", - ".L..L...", - "L...L...", - "........", - "........" - }; - int y0 = y; if(y>32768) y0 -= 65536; - - y0 += 5; y0 %= 12; if(y0<0) y0+=12; - - if(y0 >= 6) { y0 -= 6; x += 4; } - - char ch = tab[y0][(x+(y+1)/2)&7]; - - if(ch == '#') - c->wall = waPlatform; - else if(ch == 'L') - c->wall = waLadder; - } - - else if(true) { - - cell *c2 = c; - cell *c3 = c; - - bool rdepths[5]; - for(int i=0; i<5; i++) { - if(coastvalEdge(c2) == 0) { - rdepths[i] = false; - } - else { - cell *c4 = c2; - if(c2 != c3 && !isNeighbor(c2, c3)) { - for(int i=0; itype; i++) if(c2->mov[i] && isNeighbor(c2->mov[i], c3)) - c4 = c2->mov[i]; - } - rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3); - c2 = chosenDown(c2, 1, 0); // if(!c2) break; - c3 = chosenDown(c3, -1, 0); - if(!c2) { raiseBuggyGeneration(c, "ivory c2"); return; } - if(!c3) { raiseBuggyGeneration(c, "ivory c3"); return; } - } - } - - if(rdepths[3]) { - c->wall = waPlatform; -// if(!c4->item) c4->item = itPalace; - } - else if(!rdepths[2] && !rdepths[4] && !rdepths[1]) { - c2 = c; - c3 = c; - cell *c4 = chosenDown(c, 1, 1); - cell *c5 = chosenDown(c, -1, -1); - for(int i=0; i<3; i++) { - if(coastvalEdge(c2) == 0) break; - if(c2 && c4 && c4->landflags == 3 && c2->landflags != 3 && c4 == chosenDown(c2, 1, 1)) - c->wall = waLadder; - if(c3 && c5 && c5->landflags == 3 && c3->landflags != 3 && c5 == chosenDown(c3, -1, -1)) - c->wall = waLadder; - buildEquidistant(c4); buildEquidistant(c5); - if(c2) c2 = chosenDown(c2, 1, 0); - if(c3) c3 = chosenDown(c3, -1, 0); - if(c4) c4 = chosenDown(c4, 1, 0); - if(c5) c5 = chosenDown(c5, -1, 0); - } - } - } - else c->wall = waCIsland; - } - -int dungeonFlags(cell *c) { - if(!c) return 0; - buildEquidistant(c); - bool rdepths[5]; - - cell *c2 = c; - cell *c3 = c; - - int switchcount = 0; - for(int i=0; i<5; i++) { - if(coastvalEdge(c2) == 0) { - rdepths[i] = false; - } - else { - cell *c4 = c2; - if(c2 != c3 && !isNeighbor(c2, c3)) { - for(int i=0; itype; i++) if(c2->mov[i] && isNeighbor(c2->mov[i], c3)) - c4 = c2->mov[i]; - } - rdepths[i] = c2 && c3 && c4 && (c2->landflags == 3 || c3->landflags == 3 || c4->landflags == 3); - if((c2&&c2->landflags == 1) || (c3&&c3->landflags == 1) || (c4&&c4->landflags == 1)) - switchcount++; - c2 = chosenDown(c2, 1, 0); // if(!c2) break; - c3 = chosenDown(c3, -1, 0); - if(!c2) { raiseBuggyGeneration(c, "ivory c2"); return 0; } - if(!c3) { raiseBuggyGeneration(c, "ivory c3"); return 0; } - } - } - - int res = 0; - - if(rdepths[3]) res |= 1; - if(rdepths[2]) res |= 2; - if(switchcount&1) res |= 4; - - return res; - } - -void placeGate(cell *c, eWall w) { - if(w == waOpenGate) { - c->wall = waClosedGate; - toggleGates(c, waOpenPlate, 0); - } - if(w == waClosedGate) { - c->wall = waOpenGate; - toggleGates(c, waClosePlate, 0); - } - } - -bool isGate(eWall w) { - return w == waOpenGate || w == waClosedGate; - } - -void placeRandomGate(cell *c) { - placeGate(c, hrand(2) ? waOpenGate : waClosedGate); - } - -void buildDungeon(cell *c) { - /* if(int(c->landparam) % 5 == 0) - c->wall = waCamelot; - */ - - if(true) { - - if(coastvalEdge(c) == 1) forCellEx(c2, c) - if(c2->land != laBarrier && c2->land != laDungeon) { - c->wall = waLadder; - c->wparam = 3; - } - - int df = dungeonFlags(c); - - if(df&1) { - int df1 = dungeonFlags(chosenDown(c,1,1)); - int df2 = dungeonFlags(chosenDown(c,-1,-1)); - - c->wparam = 0; - if(hrand(100) < (c->landparam % 5 == 0 ? 80 : 20)) { - if(!(df1&1)) c->wparam = 1; - if(!(df2&1)) c->wparam = 2; - } - - if(df&4) - placeRandomGate(c); - else if(c->wparam == 0 && c->landparam % 5 == 0 && hrand(100) < 10) { - c->wall = waLadder; - c->wparam = 3 + hrand(2); - } - else - c->wall = waPlatform; - } - - if(c->wparam) { - /* int q = 0; - cell* downs[7]; - forCellEx(c2, c) { - buildEquidistant(c2); - if(coastvalEdge(c2) > coastvalEdge(c)) downs[q++] = c2; - } - if(q) downs[hrand(q)]->wall = waLadder; - */ - cell *c2 = - c->wparam == 1 ? chosenDown(c, 1, 2) : - c->wparam == 2 ? chosenDown(c, -1, -2) : - c->wparam == 3 ? chosenDown(c, 1, 3) : - c->wparam == 4 ? chosenDown(c, -1, -3) : - NULL; - - if(c2) { - c2->wall = c->wall, c2->wparam = c->wparam; - if(c2->wall == waPlatform && hrand(10) < 2) - placeRandomGate(c2); - if(isGate(c2->wall) && hrand(10) < 2) - c2->wall = waPlatform; - } - } - } - else c->wall = waCIsland; - } - -bool is46(int i) { return i == 4 || i == 6; } - -void buildDungeonPlates(cell *c) { - if(c->wall) return; - int neargate = 0; - int neargateDown = 0; - int neargateEq = 0; - int qup = 0; - forCellEx(c2, c) { - int d = coastvalEdge(c2) - coastvalEdge(c); - if(isGate(c2->wall)) { - neargate++; - if(d>0) neargateDown++; - if(d==0) neargateEq = 0; - } - if(d<0) qup++; - } - - if(!neargate) return; - - int hr = 99; - - if(neargate == neargateDown && qup == 1) - hr = hrand(12); - else if((zebra40(c) >= 40) && !(neargateEq && neargateDown)) - hr = hrand(36); - else if(zebra40(c) >= 40) - hr = hrand(5000); - - if(hr < 5) c->wall = waClosePlate; - else if(hr < 10) c->wall = waOpenPlate; - } - -bool redtrolls(cell *c) { - return false; /* - int cd = getCdata(c, 2); - cd &= 63; - return cd < 32; */ - } - bool reptilecheat = false; -bool weaponless = false; - -eMonster pickTroll(cell *c) { - if(redtrolls(c)) - return pick(moTroll,moDarkTroll,moRedTroll); - else - return pick(moForestTroll, moStormTroll, moFjordTroll); - } - -void dieTroll(cell *c, eMonster m) { - if(m == moTroll) c->wall = waDeadTroll; - else if(m == moDarkTroll) c->wall = waDeadfloor2; - else if(m == moRedTroll) c->wall = waRed1; - else c->wall = waDeadTroll2, c->wparam = m; - } - -namespace halloween { - cell *dragoncells[4]; - } - -int reptilemax() { - int i = items[itDodeca] + yendor::hardness(); - if(i >= 245) return 5; - int r = (250 - i); - if(shmup::on) r = (r+2) / 3; - return r; - } - -bool is02(int i) { return i == 0 || i == 2; } - -bool openplains(cell *c) { - celllister cl(c, purehepta ? 5 : 7, 1000000, NULL); - for(cell *c: cl.lst) { - while(c->mpdist > 8) setdist(c, c->mpdist-1, NULL); - if(c->land != laDogPlains) return false; - } - return true; - } // This function generates all lands. Warning: it's very long! void setdist(cell *c, int d, cell *from) { @@ -3661,28 +172,8 @@ void setdist(cell *c, int d, cell *from) { buildEquidistant(c); } - if(d == 8 && (c->land == laIvoryTower || c->land == laDungeon) && !euclid) { + dungeon::all(c, d); - if(hrand(1000) < 75 && (c->landparam & 1) ) { - c->landflags = 3; - } - else c->landflags = 0; - } - - if(d == 8 && c->land == laDungeon && !euclid) { - - if(hrand(1000) < 240 && is02(c->landparam%5) ) { - c->landflags = 3; - } - else if(hrand(1000) < 90) - c->landflags = 1; - else c->landflags = 0; - } - - if(d == 7 && c->land == laIvoryTower) buildIvoryTower(c); - if(d == 8 && c->land == laDungeon) buildDungeon(c); - if(d == 7 && c->land == laDungeon) buildDungeonPlates(c); - if(d == 9 && c->land == laPalace) { if(cdist50(c) == 3 && polarb50(c) == 1) c->wall = waPalace; @@ -5579,8 +2070,8 @@ void setdist(cell *c, int d, cell *from) { } } if(c->land == laHive) { - if(isHive(c->land) && hrand(6000) < (hivehard() - 15)) - c->monst = randomHyperbug(); + if(isHive(c->land) && hrand(6000) < (hive::hivehard() - 15)) + c->monst = hive::randomHyperbug(); /* if(hrand(1500) < 30 + (kills[moBug0] + kills[moBug1] + kills[moBug2]) && notDippingFor(itRoyalJelly)) c->item = itRoyalJelly; */ @@ -5612,775 +2103,3 @@ void setdist(cell *c, int d, cell *from) { mapeditor::applyModelcell(c); #endif } - -bool wchance(int a, int of, int reduction = 0) { - of *= 10; - a += yendor::hardness() + 1; - if(isCrossroads(cwt.c->land)) - a+= items[itHyperstone] * 10; - -//if(cwt.c->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3; - - for(int i=0; icpdist == getDistLimit()) { - c->monst = moOrangeDog; - c->stuntime = 0; - return; - } - int q = 0; - cell *ctab[8]; - for(int i=0; itype; i++) { - cell *c3 = c->mov[i]; - if(c3 && c3 != c2 && c3->land == laZebra && c3->wall == waNone) - ctab[q++] = c3; - } - if(!q) break; - c2 = c; c = ctab[hrand(q)]; - } - } - -int getGhostTimer() { - return shmup::on ? (shmup::curtime - lastexplore) / 350 : turncount - lastexplore; - } - -int getGhostcount() { - if(peace::on) return 0; - int t = getGhostTimer(); - int ghostcount = 0; - if(t > 80) ghostcount = (t-80 + hrand(20)) / 20; - return ghostcount; - } - -int getSeepcount() { - int t = getGhostTimer(); - int seepcount = 0; - if(t > 40) seepcount = (t-40 + hrand(20)) / 20; - return seepcount; - } - -bool canReachPlayer(cell *cf, eMonster m) { - vector v; - sval++; - v.push_back(cf); cf->aitmp = sval; - for(int i=0; itype; j++) { - cell *c2 = c->mov[j]; - if(!c2) continue; - if(eq(c2->aitmp, sval)) continue; - if(!passable_for(m, c2, c, P_MONSTER | P_ONPLAYER | P_CHAIN)) continue; - if(isPlayerOn(c2)) return true; - c2->aitmp = sval; v.push_back(c2); - } - } - return false; - } - -bool haveOrbPower() { - for(int i=0; iitem) == IC_ORB) return true; - } - else if(sphere) for(int i=0; ic7; - if(itemclass(c->item) == IC_ORB) return true; - forCellEx(c2, c) if(itemclass(c2->item) == IC_ORB) return true; - } - return false; - } - -bool haveKraken() { - for(int i=0; ic7; - if(c->monst == moKrakenH || c->monst == moKrakenT) return true; - } - return false; - } - -void wandering() { - if(!canmove) return; - int seepcount = getSeepcount(); - int ghostcount = getGhostcount(); - if(cwt.c->land == laCA) ghostcount = 0; - - if(cwt.c->land == laZebra && cwt.c->wall == waNone && wchance(items[itZebra], 20)) - wanderingZebra(cwt.c); - - if(smallbounded) { - int maxdist = 0; - for(int i=0; icpdist > maxdist) maxdist = dcal[i]->cpdist; - for(int i=0; icpdist >= maxdist-1) { first7 = i; break; } - - if(hrand(5) == 0) { - // spawn treasure - } - } - - while(first7 < size(dcal)) { - int i = first7 + hrand(size(dcal) - first7); - cell *c = dcal[i]; - if(inmirror(c)) continue; - - if(smallbounded && !c->item && hrand(5) == 0 && c->land != laHalloween) { - if(passable(c, NULL, 0) || specialland == laKraken) { - if(!haveOrbPower() && specialland != laHell) for(int it=0; it<1000 && !c->item; it++) - placeLocalOrbs(c); - if(!c->item) c->item = wanderingTreasure(c); - if(c->item == itShard) { - c->item = itNone, c->wall = hrand(2) ? waMirror : waCloud; - } - if(c->item == itFulgurite) { - c->item = itNone, c->wall = waSandstone; - } - if(c->item == itBarrow) - c->landparam = 2 + hrand(2), - c->wall = waBarrowDig; - } - } - - if(!c->monst) c->stuntime = 0; - - if(timerghost && !smallbounded) { - // wandering seeps & ghosts - if(seepcount && c->wall == waCavewall && !c->monst && canReachPlayer(c, moSlime)) { - c->monst = moSeep; - playSeenSound(c); - seepcount--; - continue; - } - - if(ghostcount && !c->monst && !inmirror(c)) { - c->monst = moGhost; - playSeenSound(c); - ghostcount--; - continue; - } - } - - if((c->wall == waCavewall || c->wall == waDeadwall) && !c->monst && - wchance(items[treasureType(c->land)], 10) && canReachPlayer(c, moSlime)) { - c->monst = moSeep; - playSeenSound(c); - continue; - } - - else if(c->wall == waCTree && !c->monst && wchance(items[itPirate], 15) && canReachPlayer(c, moSlime)) { - c->monst = moParrot; - playSeenSound(c); - continue; - } - - else if(c->land == laEndorian && c->wall == waNone && wchance(items[itApple], 50)) { - c->monst = moSparrowhawk; - playSeenSound(c); - continue; - } - - else if(c->wall == waSea && !c->monst) { - if(c->land == laCaribbean && wchance(items[itPirate], 15) && canReachPlayer(c, moPirate)) { - c->monst = moCShark; - playSeenSound(c); - continue; - } - if(c->land == laWarpSea && avengers && canReachPlayer(c, moPirate)) { - c->monst = moRatlingAvenger; - c->wall = waBoat; - avengers--; - if(cheater) printf("avenger comes\n"); - playSeenSound(c); - continue; - } - if(c->land == laWarpSea && wchance(items[itCoral], 25) && canReachPlayer(c, moPirate)) { - c->monst = moRatling; - c->wall = waBoat; - playSeenSound(c); - continue; - } - if(c->land == laOcean && (items[itCoast] > 50 || (cwt.c->landparam < 25 && c->landparam < 25)) && wchance(items[itCoast], 25) && canReachPlayer(c, moEagle)) { - c->monst = moAlbatross; - playSeenSound(c); - continue; - } - if(!peace::on && c->land == laLivefjord && wchance(items[itFjord], 80) && items[itFjord] >= 10 && canReachPlayer(c, moWaterElemental)) { - c->monst = moWaterElemental; - playSeenSound(c); - continue; - } - if(!peace::on && c->land == laKraken && ((sphere && !hrand(15)) || wchance(items[itKraken], 240)) && !pseudohept(c)) { - bool b = canReachPlayer(c, moKrakenH); - if(sphere && (haveKraken() || !items[itOrbFish])) { - c->monst = moViking; c->wall = waBoat; c->item = itOrbFish; - playSeenSound(c); - continue; - } - if(b) forCellEx(c2, c) if((sphere || c2->cpdist > 7) && !pseudohept(c2)) { - forCellCM(c3, c2) if(c3->monst || c3->wall != waSea) - goto notfound; - c2->monst = moKrakenH; - playSeenSound(c2); - for(int i=0; itype; i++) { - c2->mov[i]->monst = moKrakenT; - c2->mov[i]->hitpoints = 1; - c2->mov[i]->mondir = c2->spn(i); - } - goto found; - } - goto notfound; - found: - continue; - } - notfound: - break; - } - - else if(c->monst || c->pathdist == PINFD) break; - - else if(c->land == laClearing && wchance(items[itMutant2], 150) && items[itMutant2] >= 15 && !c->monst && c->type == 7) - c->monst = moRedFox; - - else if(hrand(50) < statuecount * statuecount) - c->monst = moCultistLeader; - - else if(c->land == laIce && wchance(items[itDiamond], 10)) - c->monst = hrand(2) ? moWolf : moYeti; - - else if(c->land == laDogPlains && wchance(items[itDogPlains], 50, 26)) - c->monst = moHunterDog; - - else if(c->land == laDesert && wchance(items[itSpice], 10)) - c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm; - - else if(c->land == laDragon && (items[itDragon] >= 8 || items[itOrbYendor]) && wchance(items[itDragon], 20)) - c->monst = moFireElemental; - - else if(c->land == laRedRock && wchance(items[itRedGem], 10)) - c->monst = (hrand(10) || peace::on) ? moRedTroll : moHexSnake; - - else if(c->land == laCaves && wchance(items[itGold], 5)) - c->monst = hrand(3) ? moTroll : moGoblin; - - else if(c->land == laBull && wchance(items[itBull], 40)) - c->monst = moGadfly; - - else if(items[itBull] >= 50 && size(butterflies) && wchance(items[itBull]-49, 25)) - c->monst = moGadfly; - - else if(c->land == laPrairie && cwt.c->LHU.fi.flowerdist > 3 && wchance(items[itGreenGrass], prairie::isriver(cwt.c) ? 150 : 40)) - c->monst = moGadfly; - - else if(c->land == laHive && wchance(hivehard(), 25)) - c->monst = randomHyperbug(); - - else if(c->land == laDeadCaves && wchance(items[itSilver], 5)) - c->monst = hrand(20) ? (hrand(3) ? moDarkTroll : moGoblin) : moEarthElemental; - - else if(c->land == laJungle && wchance(items[itRuby], 40)) - c->monst = hrand(10) ? moMonkey : moEagle; - - else if(c->land == laMirrorOld && wchance(items[itShard], 15)) - c->monst = hrand(10) ? moRanger : moEagle; - - else if(c->land == laMirror && mirrorspirits) { - mirrorspirits--; - c->monst = moMirrorSpirit; - } - - else if(c->land == laMirror && wchance(items[itShard], 120)) - c->monst = moNarciss; - - else if(c->land == laWarpCoast && wchance(items[itCoral], 40)) - c->monst = moRatling; - - else if(c->land == laBurial && wchance(items[itBarrow], 250)) - c->monst = moDraugr; - - else if(c->land == laTrollheim && wchance(items[itTrollEgg], 150)) - c->monst = pickTroll(c); - - else if(c->land == laRose && wchance(items[itRose], 25)) - c->monst = moFalsePrincess; - - else if(c->land == laHell && wchance(items[itHell], 20)) - c->monst = hrand(3) ? moLesser : moGreater; - - else if(c->land == laStorms && wchance(items[itFulgurite], 30)) { - c->monst = hrand(3) ? moMetalBeast : moStormTroll; - c->hitpoints = 3; - } - - else if(c->land == laWhirlwind && wchance(items[itWindstone], 30)) - c->monst = hrand(5) ? moWindCrow : moAirElemental; - - else if(c->land == laWildWest && wchance(items[itBounty], 30)) - c->monst = moOutlaw; - - else if(c->land == laEndorian && c->wall == waTrunk && wchance(items[itApple], 30)) - c->monst = moResearcher; - - else if(c->land == laOvergrown && wchance(items[itMutant], 50)) - c->monst = moForestTroll; - - else if(c->land == laCaribbean && wchance(items[itPirate], 30)) - c->monst = moPirate; - - else if(c->land == laRlyeh && wchance(items[itStatue], 15)) - c->monst = hrand(3) ? moPyroCultist : - (hrand(40) < items[itStatue]-25) ? moCultistLeader : moCultist; - - else if(c->land == laGraveyard && wchance(items[itBone], 15)) - c->monst = hrand(5) ? moGhost : moNecromancer; - - else if(isHaunted(c->land) && wchance(items[itLotus], 15)) - c->monst = moGhost; - - else if(c->land == laDryForest && wchance(items[itFernFlower], 5)) - c->monst = hrand(5) ? moHedge : moFireFairy; - - else if(c->land == laCocytus && wchance(items[itSapphire], 45)) - c->monst = moCrystalSage; - - else if(c->land == laAlchemist && wchance(items[itElixir], 3) && canReachPlayer(c, moSlime) && c->item == itNone) - c->monst = moSlime; // ? - - else if(isElemental(c->land) && wchance(items[itElemental], 20) && !peace::on) - c->monst = elementalOf(c->land); - - else if(c->land == laIvoryTower && wchance(items[itIvory], 20)) - c->monst = cellEdgeUnstable(c) ? moGargoyle : moFamiliar; - - else if(c->land == laMinefield && wchance(items[itBombEgg]-20, 400)) - c->monst = moBomberbird; - - else if(c->land == laEmerald && wchance(items[itEmerald], 5)) { - static eMonster m[4] = {moHedge, moLancer, moMiner, moFlailer}; - c->monst = m[hrand(4)]; - } - - else if(c->land == laWineyard && wchance(items[itWine], 10)) { - c->monst = moVineBeast; - } - - else if(c->land == laPalace && wchance(items[itPalace], 50)) { - if(princess::dist(c) < OUT_OF_PRISON && !princess::challenge) break; - - if(items[itPalace] >= 15 && hrand(100) < 10) - c->monst = moVizier; - else if(items[itPalace] >= 5 && hrand(100) < 50) - c->monst = hrand(2) ? moFatGuard : moSkeleton; - else c->monst = moPalace; - c->hitpoints = palaceHP(); - } - - else if(c->land == laLivefjord && wchance(items[itFjord], 10)) { - c->monst = sphere ? pick(moViking, moWaterElemental, moFjordTroll) : moViking; - } - - else if(c->land == laOcean && wchance(items[itCoast], 100)) { - c->monst = moAlbatross; - } - - else if(c->land == laPower && wchance(items[itPower], 10)) { - c->monst = eMonster(moWitch + hrand(NUMWITCH)); - } - - else if(c->land == laCamelot && hrand(30) == 0 && (euclid || c->master->alt) && celldistAltRelative(c) < 0) { - eMonster m[3] = { moHedge, moLancer, moFlailer }; - c->monst = m[hrand(3)]; - } - - else if(isCrossroads(c->land) && items[itHyperstone] && wchance(items[itHyperstone], 20)) { - c->monst = wanderingCrossroadsMonster(); - c->hitpoints = palaceHP(); - } - - else break; - - playSeenSound(c); - if(c->monst == moWorm || c->monst == moHexSnake) c->mondir = NODIR; - - // laMotion -> no respawn! - } - } - -void generateAlts(heptagon *h) { - if(!h->alt) return; - preventbarriers(h->c7); - for(int i=0; i<7; i++) preventbarriers(h->c7->mov[i]); - for(int i=0; i<7; i++) - createStep(h->alt, i)->alt = h->alt->alt; - int relspin = -4; // for horocycles it must go the other way - if(quotient) relspin = 0; - else { - for(int j=0; j<7; j++) for(int i=0; i<7; i++) { - createStep(h, i); - if(h->move[i]->alt == h->alt->move[j]) { - relspin = (i-j+7) % 7; - break; - } - } - if(relspin == -4 && quotient != 2) { - if(h->alt != h->alt->alt) { - printf("relspin {%p:%p}\n", h->alt, h->alt->alt); - {for(int i=0; i<7; i++) printf("%p ", h->alt->move[i]);} printf(" ALT\n"); - {for(int i=0; i<7; i++) printf("%p ", h->move[i]);} printf(" REAL\n"); - {for(int i=0; i<7; i++) printf("%p ", h->move[i]->alt);} printf(" REAL ALT\n"); - } - relspin = 3; - } } - // h[relspin] matches alt[0] -//printf("{%d~%d}\n", h->distance, h->alt->distance); - for(int i=0; i<7; i++) { - int ir = (7+i-relspin)%7; - heptagon *hm = h->alt->move[ir]; - heptagon *ho = createStep(h, i); -// printf("[%p:%d ~ %p:%d] %p ~ %p\n", -// h, i, h->alt, ir, -// ho, hm); - if(ho->alt && ho->alt != hm) { - if(ho->alt->alt == hm->alt && !quotient) { - printf("ERROR: alt cross! [%d -> %d]\n", ho->alt->distance, hm->distance); - // exit(1); - } - continue; - } - ho->alt = hm; - } - } - -heptagon *createAlternateMap(cell *c, int rad, hstate firststate, int special) { - - // check for direction - int gdir = -1; - for(int i=0; itype; i++) { - if(c->mov[i] && c->mov[i]->mpdist < c->mpdist) gdir = i; - } - if(gdir < 0) return NULL; - - // check for non-crossing - int bd = 2; - cellwalker bb(c, bd); - if(!(checkBarriersFront(bb) && checkBarriersBack(bb))) { - return NULL; - } - - // okay, let's go then! - cellwalker bf(c, gdir); - cell *cx[rad+1]; - for(int i=0; itype == 6) - cwspin(bf, 3); - else - cwspin(bf, 3 + hrand(2)); - cwstep(bf); - } - cx[rad] = bf.c; - heptagon *h = bf.c->master; - - if(special == waPalace) { - - // type 7 is ensured - cell *c = bf.c; - - if(cdist50(c) != 0) return NULL; - if(polarb50(c) != 1) return NULL; - } - - heptagon *alt = new heptagon; - allmaps.push_back(new hrmap_alternate(alt)); -//printf("new alt {%p}\n", alt); - alt->s = firststate; - alt->emeraldval = 0; - alt->zebraval = 0; - for(int i=0; i<7; i++) alt->move[i] = NULL; - alt->distance = 0; - alt->c7 = NULL; - alt->alt = alt; - h->alt = alt; - - for(int d=rad; d>=0; d--) { - generateAlts(cx[d]->master); - preventbarriers(cx[d]); - } - - if(special == waPalace) { - - cell *c = bf.c; - - princess::generating = true; - c->land = laPalace; - for(int j=BARLEV; j>=0; j--) - setdist(c, j, NULL); - princess::generating = false; - - princess::newInfo(c); - princess::forceMouse = false; - - if(princess::gotoPrincess && cheater) princess::gotoPrincess=false, cwt.c = c; - } - - return alt; -//for(int d=rad; d>=0; d--) printf("%3d. %p {%d}\n", d, cx[d]->master, cx[d]->master->alt->distance); - } - -namespace halloween { - vector srch; - - cell *farempty(bool lastresort = false) { - int maxdist = 0; - vector validcells; - int firstfar1 = 0; - for(int i=1; iitem == itNone && dcal[i]->monst == moNone && dcal[i]->wall == waNone; - if(lastresort) - okay = dcal[i]->wall != waChasm && !isMultitile(dcal[i]->monst); - if(okay) { - if(dcal[i]->cpdist > maxdist) - firstfar1 = size(validcells), - maxdist = dcal[i]->cpdist; - validcells.push_back(dcal[i]); - } - } - - int qvc = size(validcells); - if(qvc == firstfar1) return farempty(true); - - return validcells[firstfar1 + hrand(qvc - firstfar1)]; - } - - int demoncount; - int swordpower; - int dragoncount; - - void reset() { - demoncount = 0; - swordpower = 0; - dragoncount = 0; - } - - eMonster nextDemon() { - demoncount++; - if(demoncount % 9 == 0) return moGreater; - return moLesser; - } - - void putMonster(eMonster m) { - cell *c = farempty(); - c->hitpoints = 3; - c->monst = m; - playSeenSound(c); - if(!kills[m]) switch(m) { - case moGhost: - addMessage(XLAT("Ghosts can move through chasms!")); - break; - case moSkeleton: - addMessage(XLAT("Push Skeletons into the holes!")); - break; - case moDraugr: - addMessage(XLAT("You'll need your magical sword against the Draugar!")); - break; - case moLesser: - addMessage(XLAT("Demons are slow, but you'll need the experience against stronger ones...")); - break; - case moGreater: - addMessage(XLAT("You will need more experience to defeat the Greater Demon!")); - break; - case moPyroCultist: - addMessage(XLAT("Cultists throw fire at you from distance!")); - break; - case moFlailer: - addMessage(XLAT("Defeat Flail Guards by moving away from them.")); - break; - case moVampire: - addMessage(XLAT("Vampire Bats drain your magical powers!")); - break; - default: break; - } - c->stuntime = 2; - } - - void getTreat(cell *where) { - if(!items[itTreat]) reset(); - gainItem(itTreat); - farempty()->item = itTreat; - int itr = items[itTreat]; - items[itOrbTime] += 30; - int monpower = 19 + itr + hrand(itr); - int mcount = 0; - while(monpower > 0) { - int id = hrand(10000); - -#define CHANCE(x) (id -= x, id < 0) - if(CHANCE(400) && itr >= 5) { - putMonster(moGhost); - monpower -= 30; - mcount++; - } - else if(CHANCE(400)) { - putMonster(pick(moWitch, moZombie)); - monpower -= 20; - mcount++; - } - else if(CHANCE(400) && itr >= 5) { - putMonster(nextDemon()); - monpower -= 10; - mcount++; - } - else if(CHANCE(100) && itr >= 12) { - putMonster(moVampire); - monpower -= 10; - swordpower -= 5; - if(swordpower < 0) swordpower = 0; - mcount++; - } - else if(CHANCE(400) && swordpower > 0 && !mcount && itr >= 15) { - putMonster(moDraugr); - swordpower -= 3; - monpower -= 100; - mcount++; - } - else if(CHANCE(400) && itr >= 10 && !mcount && itr >= 10) { - putMonster(moSkeleton); - monpower -= 60; - mcount++; - } - else if(CHANCE(10) && itr >= 15) { - putMonster(moWitchFire); - monpower -= 35; - mcount++; - } - else if(CHANCE(100) && itr >= 5) { - putMonster(moFlailer); - monpower -= 35; - mcount++; - } - else if(CHANCE(100) && itr >= 5) { - putMonster(moPyroCultist); - monpower -= 35; - mcount++; - } - else if(CHANCE(5) && itr >= 20 && kills[moSkeleton]) { - putMonster(moFatGuard); - monpower -= 35; - mcount++; - } - else if(CHANCE(5) && itr >= 30 && kills[moFlailer]) { - putMonster(moHedge); - monpower -= 35; - mcount++; - } - else if(CHANCE(5) && itr >= 40 && kills[moHedge]) { - putMonster(moLancer); - monpower -= 60; - mcount++; - } - else if(CHANCE(1) && itr >= 50 && kills[moHedge]) { - putMonster(moFireFairy); - monpower -= 40; - mcount++; - } - else if(CHANCE(5) && itr >= 60) { - putMonster(moBomberbird); - monpower -= 25; - mcount++; - } - else if(CHANCE(5) && itr >= 60) { - putMonster(moRatlingAvenger); - monpower -= 30; - mcount++; - } - else if(CHANCE(5) && itr >= 60) { - putMonster(moVineBeast); - monpower -= 30; - mcount++; - } - else if(CHANCE(5) && itr >= 60) { - dragoncount++; - } - else if(dragoncount && !purehepta && !mcount) { - bool fill = false; - for(int i=0; i<4; i++) - if(!dragoncells[i] || dragoncells[i]->monst) - fill = true; - swap(dragoncells[0], dragoncells[3]); - swap(dragoncells[1], dragoncells[2]); - if(fill) continue; - for(int i=0; i<4; i++) { - dragoncells[i]->monst = i ? moDragonTail : moDragonHead; - dragoncells[i]->mondir = i==3 ? NODIR : neighborId(dragoncells[i], dragoncells[i+1]); - dragoncells[i]->hitpoints = 1; - dragoncells[i]->stuntime = 1; - playSeenSound(dragoncells[i]); - } - monpower -= 200; - mcount++; - dragoncount--; - } - } - int id = hrand(100); - if(items[itTreat] == 1) { -#if ISMOBILE==0 - addMessage(XLAT("Hint: use arrow keys to scroll.")); -#endif - } - else if(items[itTreat] == 2) { -#if ISMOBILE==0 - addMessage(XLAT("Hint: press 1 2 3 4 to change the projection.")); -#endif - } - else if(items[itTreat] == 3) { - items[itOrbShell] += 20; - addMessage(XLAT("You gain a protective Shell!")); - } - else if(items[itTreat] == 4) { - items[itOrbShell] += 10; - addMessage(XLAT("Hint: magical powers from Treats expire after a number of uses.")); - } - else if(kills[moSkeleton] && CHANCE(10)) { - addMessage(XLAT("A magical energy sword. Don't waste its power!")); - items[itOrbSword] += 5; // todo facing - swordpower += 5; - } - else if(kills[moDraugr] && items[itOrbSword] && CHANCE(10)) { - addMessage(XLAT("Another energy sword!")); - items[itOrbSword2] += 5; - swordpower += 5; - } - else if(kills[moFlailer] && CHANCE(10)) { - items[itOrbThorns] += 5; - addMessage(XLAT("You got Thorns! Stab monsters by moving around them.")); - } - else if(kills[moGhost] && CHANCE(10)) { - items[itOrbAether] += 5; - addMessage(XLAT("Aethereal powers let you go through the holes.")); - } - else { - if(items[itOrbShell] > ORBBASE) - addMessage(XLAT("The tasty treat increases your protection.")); - else - addMessage(XLAT("You gain your protective Shell back!")); - items[itOrbShell] += 5; - } - } - } - -void doOvergenerate() { - int dcs = size(dcal); - for(int i=0; icpdist <= sightrange-6) setdist(c, 1, NULL); - } - } diff --git a/landlock.cpp b/landlock.cpp new file mode 100644 index 00000000..fa2fdf99 --- /dev/null +++ b/landlock.cpp @@ -0,0 +1,856 @@ +// land statistics and flags + +// returns: 2 = treasure increaser, 1 = just appears, 0 = does not appear +int isNative(eLand l, eMonster m) { + switch(l) { + case laIce: + return (m == moWolf || m == moWolfMoved || m == moYeti) ? 2 : 0; + + case laJungle: + return (m == moIvyRoot || m == moMonkey) ? 2 : + (isIvy(m) || m == moEagle || m == moMonkey) ? 1 : 0; + + case laCaves: + return (m == moGoblin || m == moTroll) ? 2 : m == moSeep ? 1 : 0; + + case laDesert: + return (m == moDesertman || m == moWorm) ? 2 : 0; + + case laAlchemist: + return (m == moSlime) ? 2 : 0; + + case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2: + return (m == moMirrorSpirit || m == moNarciss || m == moMimic) ? 1 : 0; + + case laMirrorOld: + return (m == moEagle || m == moRanger || m == moMimic) ? 1 : 0; + + case laMotion: + return (m == moRunDog) ? 2 : 0; + + case laGraveyard: + return (m == moZombie || m == moNecromancer) ? 2 : + m == moGhost ? 1 : 0; + + case laRlyeh: + return + (m == moCultist || m == moTentacle || m == moPyroCultist) ? 2 : + (m == moCultistLeader || isIvy(m)) ? 1 : 0; + + case laDryForest: + return (m == moHedge || m == moFireFairy) ? 2 : 0; + + case laHell: + return (m == moLesser) ? 2 : 0; + + case laCocytus: + return (m == moShark || m == moGreaterShark || m == moCrystalSage) ? 2 : + m == moYeti ? 1 : 0; + + case laCrossroads: case laCrossroads2: case laCrossroads3: case laCrossroads4: + case laCrossroads5: + case laNone: case laBarrier: case laOceanWall: case laCanvas: return 0; + + case laEmerald: + return (m == moFlailer || m == moLancer || m == moMiner) ? 2 : + m == moHedge ? 1 : 0; + + case laWineyard: + return (m == moVineSpirit || m == moVineBeast) ? 2 : 0; + + case laHive: + return isBug(m) ? 1 : 0; + + case laDeadCaves: + return (m == moEarthElemental || m == moDarkTroll) ? 2 : + (m == moGoblin || m == moSeep) ? 1 : 0; + + case laPower: + return (isWitch(m) || m == moEvilGolem) ? 1 : 0; + + case laCamelot: + return (m == moKnight || m == moHedge || m == moFlailer || m == moLancer) ? 1 : 0; + + case laTemple: + return (m == moTentacle || m == moCultist || m == moPyroCultist || m == moCultistLeader) ? 1 : 0; + + case laCaribbean: + return (m == moPirate || m == moParrot || m == moCShark) ? 1 : 0; + + case laRedRock: return (m == moRedTroll || m == moHexSnake) ? 2 : 0; + + case laMinefield: + return (m == moBomberbird || m == moTameBomberbird) ? 1 : 0; + + case laOcean: + return (m == moAlbatross) ? 2 : (m == moPirate || m == moCShark) ? 1 : 0; + + case laWhirlpool: + return (m == moPirate || m == moCShark) ? 1 : 0; + + case laPalace: case laPrincessQuest: + return (m == moPalace || m == moFatGuard || m == moSkeleton || m == moVizier) ? 2 : + m == moSkeleton ? 1 : 0; + + case laLivefjord: + return m == moViking ? 2 : (m == moFjordTroll || m == moWaterElemental) ? 1 : 0; + + case laIvoryTower: + return (m == moFamiliar || m == moGargoyle) ? 2 : 0; + + case laZebra: return (m == moOrangeDog) ? 2 : 0; + + case laEAir: case laEEarth: case laEWater: case laEFire: + case laElementalWall: + if(m == elementalOf(l)) return 2; + return (m == moAirElemental || m == moEarthElemental || m == moWaterElemental || m == moFireElemental) ? 1 : 0; + + case laStorms: + return (m == moMetalBeast || m == moMetalBeast2 || m == moStormTroll) ? 1 : 0; + + case laOvergrown: + return (m == moMutant || m == moForestTroll) ? 1 : 0; + + case laWildWest: + return (m == moOutlaw) ? 2 : 0; + + case laHalloween: + return 1; + + case laClearing: + return (m == moMutant || m == moRedFox) ? 1 : 0; + + case laHaunted: case laHauntedWall: case laHauntedBorder: + return (m == moGhost || m == moFriendlyGhost) ? 1 : 0; + + case laWhirlwind: + return (m == moAirElemental || m == moWindCrow) ? 2 : 0; + + case laRose: + return (m == moFalsePrincess || m == moRoseBeauty || m == moRoseLady) ? 2 : 0; + + case laWarpCoast: case laWarpSea: + return m == moRatling ? 2 : m == moRatlingAvenger ? 1 : 0; + + case laDragon: + return (isDragon(m) || m == moFireElemental) ? 1 : 0; + + case laEndorian: + return (m == moResearcher || m == moSparrowhawk) ? 2 : 0; + + case laTortoise: + return m == moTortoise ? 1 : 0; + + case laTrollheim: + return isTroll(m) ? 1 : 0; + + case laKraken: + return m == moKrakenH ? 2 : (m == moViking || m == moKrakenT) ? 1 : 0; + + case laBurial: + return m == moDraugr ? 1 : 0; + + case laDungeon: + return + m == moBat ? 2 : + m == moSkeleton || m == moGhost ? 1 : + 0; + + case laMountain: + return + m == moEagle || m == moMonkey || isIvy(m) || m == moFriendlyIvy ? 1 : 0; + + case laReptile: + return m == moReptile ? 1 : 0; + + case laBull: + return (m == moSleepBull || m == moRagingBull || m == moButterfly || m == moGadfly) ? 1 : 0; + + case laPrairie: + return (m == moRagingBull || m == moHerdBull || m == moGadfly) ? 1 : 0; + + case laVolcano: + return (m == moLavaWolf || m == moSalamander) ? 2 : 0; + + case laTerracotta: case laMercuryRiver: + return m == moJiangshi ? 2 : m == moTerraWarrior ? 1 : 0; + + case laBlizzard: + return (m == moVoidBeast || m == moIceGolem) ? 2 : 0; + + case laDogPlains: + return m == moHunterDog ? 1 : 0; + + case laCA: return false; + } + return false; + } + +eItem treasureType(eLand l) { + switch(l) { + case laIce: return itDiamond; + case laJungle: return itRuby; + case laCaves: return itGold; + case laDesert: return itSpice; + + case laAlchemist: return itElixir; + + case laMirror: case laMirrored: case laMirrorWall: case laMirrorWall2: case laMirrored2: + case laMirrorOld: + return itShard; + + case laMotion: return itFeather; + + case laGraveyard: return itBone; + case laRlyeh: return itStatue; + case laDryForest: return itFernFlower; + + case laHell: return itHell; + case laCocytus: return itSapphire; + case laCrossroads: return itHyperstone; + case laCrossroads2: return itHyperstone; + case laCrossroads3: return itHyperstone; + case laCrossroads4: return itHyperstone; + case laCrossroads5: return itHyperstone; + + case laNone: return itNone; + case laBarrier: return itNone; + case laOceanWall: return itNone; + case laCanvas: return itNone; + + case laEmerald: return itEmerald; + case laWineyard: return itWine; + case laHive: return itRoyalJelly; + case laDeadCaves: return itSilver; + case laPower: return itPower; + case laCamelot: return itHolyGrail; + case laTemple: return itGrimoire; + + case laCaribbean: return itPirate; + case laRedRock: return itRedGem; + + case laMinefield: return itBombEgg; + case laOcean: return itCoast; + case laWhirlpool: return itWhirlpool; + case laPalace: return itPalace; + case laLivefjord: return itFjord; + + case laIvoryTower: return itIvory; + case laZebra: return itZebra; + + case laEAir: case laEEarth: case laEWater: case laEFire: + case laElementalWall: return itElemental; + + case laPrincessQuest: return itSavedPrincess; + + case laStorms: return itFulgurite; + case laOvergrown: return itMutant; + case laWildWest: return itBounty; + case laHalloween: return itTreat; + case laClearing: return itMutant2; + case laHaunted: case laHauntedWall: case laHauntedBorder: return itLotus; + case laWhirlwind: return itWindstone; + + case laRose: return itRose; + case laWarpCoast: case laWarpSea: return itCoral; + + case laDragon: return itDragon; + case laEndorian: return itApple; + case laTortoise: return itBabyTortoise; + + case laTrollheim: return itTrollEgg; + case laKraken: return itKraken; + case laBurial: return itBarrow; + + case laDungeon: return itSlime; + case laMountain: return itAmethyst; + case laReptile: return itDodeca; + + case laBull: return itBull; + case laPrairie: return itGreenGrass; + + case laVolcano: return itLavaLily; + case laTerracotta: case laMercuryRiver: return itTerra; + case laBlizzard: return itBlizzard; + case laDogPlains: return itDogPlains; + + case laCA: return itNone; + } + return itNone; + } + +bool isSealand(eLand l) { + return l == laOcean || l == laCaribbean || l == laWhirlpool || l == laLivefjord || + l == laOceanWall || l == laWarpSea || l == laKraken; + } + +bool isCoastal(eLand l) { + return l == laWarpSea || l == laWarpCoast || l == laLivefjord || l == laOcean; + } + +bool isPureSealand(eLand l) { + return l == laCaribbean || l == laKraken; + } + +bool isElemental(eLand l) { + return l == laEAir || l == laEWater || l == laEEarth || l == laEFire || + l == laElementalWall; + } + +bool isHaunted(eLand l) { + return l == laHaunted || l == laHauntedBorder || l == laHauntedWall; + } + +int landMultiplier(eLand l) { + if(l == laCamelot || l == laPrincessQuest) return 10; + return 1; + } + +bool isTrollLand(eLand l) { + return l == laCaves || l == laStorms || l == laOvergrown || + l == laDeadCaves || l == laLivefjord || l == laRedRock; + } + +bool isCrossroads(eLand l) { + return l == laCrossroads || l == laCrossroads2 || l == laCrossroads3 || + l == laCrossroads4 || l == laCrossroads5; + } + +bool bearsCamelot(eLand l) { + return isCrossroads(l) && l != laCrossroads2 && l != laCrossroads5; + } + +bool inmirror(eLand l) { + return l == laMirrored || l == laMirrorWall2 || l == laMirrored2; + } + +bool inmirror(cell *c) { + return inmirror(c->land); + } + +bool inmirror(const cellwalker& cw) { + return inmirror(cw.c->land); + } + +eLand oppositeElement(eLand l, eLand l2) { + if(l == laEFire) return laEWater; + if(l == laEWater) return laEFire; + if(l == laEAir) return laEEarth; + if(l == laEEarth) return laEAir; + if(l == laMirror && l2 == laMirrored) return laMirrored2; + if(l == laMirrored2 && l2 == laMirrored) return laMirror; + return l; + } + +// land unlocking + +eLand firstland = laIce, specialland = laIce; + +bool chaosmode = false; + +bool landUnlocked(eLand l) { + if(randomPatternsMode) { + int i = isRandland(l); + if(i == 2) return true; + if(i == 1) return hiitemsMax(treasureType(l)) >= 10; + return false; + } + + switch(l) { + case laOvergrown: + return gold() >= R60 && items[itRuby] >= U10; + + case laStorms: case laWhirlwind: + return gold() >= R60; + + case laWildWest: case laHalloween: + return false; + + case laIce: case laJungle: case laCaves: case laDesert: + case laMotion: case laCrossroads: case laAlchemist: + return true; + + case laMirror: case laMinefield: case laPalace: + case laOcean: case laLivefjord: case laMirrored: case laMirrorWall: case laMirrorWall2: + case laMirrored2: + return gold() >= R30; + + case laCaribbean: case laWhirlpool: + return exploreland[0][laOcean] || items[itCoast] || items[itStatue]; + + case laRlyeh: case laDryForest: case laWineyard: case laCrossroads2: + return gold() >= R60; + + case laDeadCaves: + return gold() >= R60 && items[itGold] >= U10; + + case laGraveyard: + return tkills() >= R100; + + case laHive: + return tkills() >= R100 && gold() >= R60; + + case laRedRock: + return gold() >= R60 && items[itSpice] >= U10; + + case laEmerald: + return (items[itFernFlower] >= U5 && items[itGold] >= U5) || kills[moVizier]; + + case laCamelot: + return items[itEmerald] >= U5; + + case laHell: case laCrossroads3: + return hellUnlocked(); + + case laPower: + return items[itHell] >= U10; + + case laCocytus: + return items[itHell] >= U10 && items[itDiamond] >= U10; + + case laTemple: + return items[itStatue] >= U5; + + case laClearing: + return items[itMutant] >= U5; + + case laIvoryTower: return gold() >= R30; + case laZebra: return gold() >= R30 && items[itFeather] >= U10; + + case laEAir: case laEEarth: case laEWater: case laEFire: case laElementalWall: + return elementalUnlocked(); + + case laBarrier: case laNone: case laOceanWall: case laCanvas: case laCA: + return false; + + case laMirrorOld: + return false; + + case laHaunted: case laHauntedWall: case laHauntedBorder: + return items[itBone] >= U10; + + case laPrincessQuest: return kills[moVizier] && !shmup::on && multi::players == 1; + + case laRose: + return gold() >= R60; + + case laWarpCoast: case laWarpSea: + return gold() >= R30; + + case laCrossroads4: + return gold() >= R200; + + case laEndorian: + return items[itIvory] >= U10; + + case laTortoise: + return tortoise::seek(); + + case laDragon: + return killtypes() >= R20; + + case laKraken: + return items[itFjord] >= U10; + + case laBurial: + return items[itKraken] >= U10; + + case laTrollheim: + return trollUnlocked(); + + case laDungeon: + return items[itPalace] >= U5 && items[itIvory] >= U5; + + case laMountain: + return items[itRuby] >= U5 && items[itIvory] >= U5; + + case laReptile: + return gold() >= R30 && items[itElixir] >= U10; + + case laPrairie: + case laBull: + return gold() >= R90; + + case laVolcano: + return gold() >= R30 && items[itElixir] >= U10; + + case laDogPlains: + return true; + + case laTerracotta: case laMercuryRiver: + return gold() >= 60; + + case laBlizzard: + return items[itDiamond] >= 5 && items[itWindstone] >= 5; + + case laCrossroads5: + return gold() >= R300; + } + return false; + } + +void countHyperstoneQuest(int& i1, int& i2) { + i1 = 0; i2 = 0; + for(int t=1; t= R10) i1++; + } + } + +bool hyperstonesUnlocked() { + int i1, i2; + if(tactic::on && isCrossroads(tactic::lasttactic) && !tactic::trailer) return true; + countHyperstoneQuest(i1, i2); + return i1 == i2; + } + +// 2 = always available, 1 = highscore required, 0 = never available +int isRandland(eLand l) { + if(l == laIce || l == laDesert || l == laCaves || l == laWildWest) + return 2; + for(int i=0; i= 1; + return items[itStatue] >= 10 || items[itGrimoire] >= 10; + } + +bool lchance(eLand l) { + if(tactic::on || yendor::on) return true; + if(chaosmode) return hrand(100) < 25; + return hrand(100) >= 40 * kills[elementalOf(l)] / (elementalKills()+1); + } + +eLand pickLandRPM(eLand old) { + while(true) { + eLand n = randlands[hrand(RANDLANDS)]; + if(incompatible(n, old)) continue; + if(isRandland(n) == 2) return n; + if(hiitemsMax(treasureType(n)) < 10) + continue; + return n; + } + } + +eLand pickluck(eLand l1, eLand l2) { + int t1 = items[treasureType(l1)]; + int t2 = items[treasureType(l2)]; + if(t1 < t2) return l1; + if(t2 < t1) return l2; + if(isCrossroads(l1)) return l1; + return l2; + } + +#define LIKELY for(int u=0; u<5; u++) + +bool noChaos(eLand l) { + if(l == laOcean || l == laTemple) return false; + return + isCrossroads(l) || isCyclic(l) || isHaunted(l) || + l == laCaribbean || isGravityLand(l) || l == laPrincessQuest || + l == laPrairie || l == laHalloween; + } + +eLand getNewSealand(eLand old) { + while(true) { + eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken)); + if(p == laKraken && !landUnlocked(p)) continue; + if(p == laKraken && peace::on) continue; + if(incompatible(old, p)) continue; + if(p == old) continue; + if(chaosmode && noChaos(p)) continue; + return p; + } + } + +bool createOnSea(eLand old) { + return + old == laWarpSea || old == laCaribbean || old == laKraken || + (old == laLivefjord && hrand(2)) || + (old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant)); + } + +hookset *hooks_nextland; + +eLand getNewLand(eLand old) { + + if(old == laMirror && !chaosmode && hrand(10) >= (tactic::on ? 0 : markOrb(itOrbLuck) ? 5 : 2)) return laMirrored; + if(old == laTerracotta && !chaosmode && hrand(5) >= (tactic::on ? 0 : markOrb(itOrbLuck) ? 2 : 1)) return laTerracotta; + + eLand l = callhandlers(laNone, hooks_nextland, old); + if(l) return l; + + if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest; + + if(old == laTortoise) return laDragon; + + if(yendor::on && chaosmode) { + while(true) { + eLand n = eLand(hrand(landtypes)); + if(n == old) continue; + if(incompatible(n,old)) continue; + if(noChaos(n)) continue; + if(n == laElementalWall || isTechnicalLand(n)) continue; + if(n == laWildWest) continue; + if(isElemental(n) && hrand(100) >= 25) continue; + return n; + } + } + + if(markOrb(itOrbLuck)) { + int i = items[itOrbLuck]; + items[itOrbLuck] = 0; + eLand l1 = getNewLand(old); + for(int i=1; i<3; i++) + l1 = pickluck(l1, getNewLand(old)); + items[itOrbLuck] = i; + return l1; + } + + if(randomPatternsMode) return pickLandRPM(old); + + if(old == laEEarth && lchance(old)) return hrand(2) ? laEWater : laEFire; + if(old == laEAir && lchance(old)) return hrand(2) ? laEWater : laEFire; + if(old == laEWater && lchance(old)) return hrand(2) ? laEEarth : laEAir; + if(old == laEFire && lchance(old)) return hrand(2) ? laEEarth : laEAir; + + if(tactic::on && !(tactic::trailer && old == firstland)) return firstland; + + if(yendor::on && (yendor::clev().flags & YF_WALLS)) { + if(old != yendor::clev().l) return yendor::clev().l; + else if(old == laOcean) return pick(laLivefjord, laCaribbean); + } + + if(yendor::on && yendor::nexttostart) { + eLand l = yendor::nexttostart; + if(!(yendor::clev().flags & YF_REPEAT)) + yendor::nexttostart = laNone; + return l; + } + + if(old == laDragon && tortoise::seek() && hrand(100) < 50) + return laTortoise; + + if(isWarped(old) && (hrand(100) < 25) && chaosmode) return eLand(old ^ laWarpCoast ^ laWarpSea); + + if(createOnSea(old)) + return getNewSealand(old); + + if(old == laGraveyard && generatingEquidistant) + return laHaunted; + + if(old == laOcean && gold() >= R60 && hrand(100) < 75 && !rlyehComplete()) + return laRlyeh; + + if(old == laRlyeh && !rlyehComplete()) + return laOcean; + + eLand tab[256]; + int cnt = 0; + +/* if(isHive(old) && hrand(100) < 90) { + eLand n = old; + while(n == old) n = eLand(laHive0 + hrand(3)); + return n; + } */ + + // return (hrand(2)) ? laMotion : laJungle; + + // the basic lands, always available + tab[cnt++] = laCrossroads; + tab[cnt++] = laIce; + tab[cnt++] = laDesert; + tab[cnt++] = laJungle; + tab[cnt++] = laMotion; + tab[cnt++] = laAlchemist; + if(old != laDeadCaves) tab[cnt++] = laCaves; + + // the intermediate lands + if(gold() >= R30) { + tab[cnt++] = laCrossroads; + tab[cnt++] = laMirror; + tab[cnt++] = laOcean; + tab[cnt++] = laLivefjord; + tab[cnt++] = laMinefield; + tab[cnt++] = laPalace; + if(old == laDragon && items[itElixir] >= U10) LIKELY tab[cnt++] = laReptile; + if(kills[moVizier]) tab[cnt++] = laEmerald; + if(items[itFeather] >= U10) tab[cnt++] = laZebra; + tab[cnt++] = laWarpCoast; + if(euclid) tab[cnt++] = laWarpSea; + // Ivory Tower tends to crash while generating equidistant + if(!generatingEquidistant) tab[cnt++] = laIvoryTower; + if(items[itElixir] >= U10) tab[cnt++] = laReptile; + if(items[itIvory] >= U10 && !generatingEquidistant) tab[cnt++] = laEndorian; + + if(items[itKraken] >= U10) tab[cnt++] = laBurial; + } + + if(landUnlocked(laDungeon)) { + tab[cnt++] = laDungeon; + if(old == laPalace) LIKELY tab[cnt++] = laDungeon; + } + + // the advanced lands + if(gold() >= R60) { + tab[cnt++] = laStorms; + tab[cnt++] = laWhirlwind; + tab[cnt++] = laCrossroads; + if(!generatingEquidistant) tab[cnt++] = laCrossroads2; + if(items[itRuby] >= U10) { + tab[cnt++] = laOvergrown; + if(old == laJungle) LIKELY tab[cnt++] = laOvergrown; + } + if(rlyehComplete()) tab[cnt++] = laRlyeh; + else if(chaosmode && (old == laWarpCoast || old == laLivefjord || old == laOcean)) + tab[cnt++] = laRlyeh; + if(items[itStatue] >= U5 && chaosmode) + tab[cnt++] = laTemple; + if(old == laCrossroads || old == laCrossroads2) tab[cnt++] = laOcean; + if(old == laOcean) tab[cnt++] = laCrossroads; + if(items[itGold] >= U5 && items[itFernFlower] >= U5 && !kills[moVizier]) + tab[cnt++] = laEmerald; + tab[cnt++] = laDryForest; + tab[cnt++] = laWineyard; + if(items[itGold] >= U10) tab[cnt++] = laDeadCaves; + // tab[cnt++] = laCaribbean; + if(items[itSpice] >= U10) { + tab[cnt++] = laRedRock; + if(old == laDesert) LIKELY tab[cnt++] = laRedRock; + } + if(old == laRedRock) LIKELY tab[cnt++] = laDesert; + if(old == laOvergrown) LIKELY tab[cnt++] = laJungle; + tab[cnt++] = laRose; + } + + if(gold() >= R90) { + if(!chaosmode) tab[cnt++] = laPrairie; + if(old == laPrairie) LIKELY tab[cnt++] = laBull; + tab[cnt++] = laBull; + if(old == laBull && !chaosmode) LIKELY tab[cnt++] = laPrairie; + } + + if(gold() >= R300) + tab[cnt++] = laCrossroads5; + + if(tkills() >= R100) { + tab[cnt++] = laGraveyard; + if(gold() >= R60) tab[cnt++] = laHive; + } + + if(killtypes() >= R20) { + tab[cnt++] = laDragon; + if(old == laReptile) LIKELY tab[cnt++] = laDragon; + } + + if(trollUnlocked()) { + tab[cnt++] = laTrollheim; + if(isTrollLand(old)) LIKELY tab[cnt++] = laTrollheim; + if(old == laTrollheim) for(int i=0; i= U10) { + if(items[itDiamond] >= U10) { + tab[cnt++] = laCocytus; + if(old == laHell || old == laIce) LIKELY tab[cnt++] = laCocytus; + } + if(old == laCocytus) LIKELY { tab[cnt++] = laIce; tab[cnt++] = laHell; } + tab[cnt++] = laPower; + if(old == laCrossroads || old == laCrossroads2) tab[cnt++] = laOcean; + if(old == laOcean) tab[cnt++] = laCrossroads2; + } + + // for(int i=0; i<20; i++) tab[cnt++] = laRedRock; + // for(int i=0; i<20; i++) tab[cnt++] = laCaribbean; + // for(int i=0; i<20; i++) tab[cnt++] = laCocytus; + + // for(int i=0; i<20; i++) tab[cnt++] = laCrossroads; + + eLand n = old; + while(incompatible(n, old) || (chaosmode && noChaos(n))) n = tab[hrand(cnt)]; + + return n; + } + diff --git a/monstergen.cpp b/monstergen.cpp new file mode 100644 index 00000000..96ec1a17 --- /dev/null +++ b/monstergen.cpp @@ -0,0 +1,605 @@ +// Hyperbolic Rogue + +// Copyright (C) 2011-2017 Zeno Rogue, see 'hyper.cpp' for details + +// Routines concentrating on monster generation. + +bool timerghost = true; + +int buildIvy(cell *c, int children, int minleaf) { + if(c->monst) return 0; + c->mondir = NODIR; + c->monst = moIvyRoot; + + cell *child = NULL; + + int leaf = 0; + int leafchild = 0; + for(int i=0; itype; i++) { + createMov(c, i); + if(passable(c->mov[i], c, 0) && c->mov[i]->land == c->land) { + if(children && !child) + child = c->mov[i], leafchild = buildIvy(c->mov[i], children-1, 5); + else + c->mov[i]->monst = (leaf++ || peace::on) ? moIvyWait : moIvyHead, + c->mov[i]->mondir = c->spn(i); + } + } + + leaf += leafchild; + if(leaf < minleaf) { + if(child) killIvy(child, moNone); + killIvy(c, moNone); + return 0; + } + else return leaf; + } + +// the 'chasmify' functions create a simulation of the path the monster came by + +void chasmify(cell *c) { + c->wall = waChasm; c->item = itNone; + int q = 0; + cell *c2[10]; + for(int i=0; itype; i++) if(c->mov[i] && c->mov[i]->mpdist > c->mpdist && cellUnstable(c->mov[i])) + c2[q++] = c->mov[i]; + if(q) { + cell *c3 = c2[hrand(q)]; + c3->wall = waChasmD; + } + } + +void chasmifyEarth(cell *c) { + int q = 0; + int d2[10]; + for(int i=2; i<=c->type-2; i++) { + int j = (i+c->mondir)%c->type; + cell *c2 = c->mov[j]; + if(c2 && c2->mpdist > c->mpdist && ( + c2->wall == waDeadfloor || c2->wall == waDeadwall || + c2->wall == waDeadfloor2)) + d2[q++] = j; + } + if(!q) printf("no further move!\n"); + if(q) { + int d = d2[hrand(q)]; + cell *c3 = c->mov[d]; + c3->wall = waEarthD; + for(int i=0; itype; i++) { + cell *c4 = createMov(c3, i); + earthFloor(c4); + } + c3->mondir = c->spn(d); + } + earthWall(c); c->item = itNone; + } + +void chasmifyElemental(cell *c) { + int q = 0; + int d2[10]; + for(int i=2; i<=c->type-2; i++) { + int j = (i+c->mondir)%c->type; + cell *c2 = c->mov[j]; + if(c2 && c2->mpdist > c->mpdist && c2->land == c->land) + d2[q++] = j; + } + if(q) { + int d = d2[hrand(q)]; + cell *c3 = c->mov[d]; + if(!c3->monst) { + c3->wall = waElementalD; + for(int i=0; itype; i++) { + cell *c4 = createMov(c3, i); + if(c4->wall != waBarrier) c4->wall = waNone; + } + c3->mondir = c->spn(d); + } + } + c->wall = getElementalWall(c->land); + c->wparam = 100; c->item = itNone; + } + +// an appropriate monster for the Crossroads + +eMonster crossroadsMonster() { + + static eMonster weak[9] = { + moYeti, moGoblin, moRanger, moOrangeDog, moRunDog, moMonkey, moZombie, + moDesertman, moCultist + }; + + if(hrand(10) == 0) return weak[hrand(9)]; + + static eMonster m[24] = { + moWorm, moTentacle, + moTroll, moEagle, + moLesser, moGreater, moPyroCultist, moGhost, + moFireFairy, moIvyRoot, moHedge, + moLancer, moFlailer, moVineBeast, + moBomberbird, moAlbatross, moRedTroll, + moWaterElemental, moAirElemental, moFireElemental, + moFatGuard, moMiner, moPalace, moVizier + }; + eMonster mo = m[hrand(24)]; + if(peace::on && mo == moWaterElemental) return crossroadsMonster(); + if(peace::on && mo == moFireFairy) return crossroadsMonster(); + if(peace::on && isMultitile(mo)) return crossroadsMonster(); + return mo; + } + +eMonster wanderingCrossroadsMonster() { + while(true) { + eMonster m = crossroadsMonster(); + if(!isIvy(m) && m != moTentacle) return m; + } + } + +int palaceHP() { + if(tactic::on && isCrossroads(firstland)) + return 4; + if(items[itPalace] < 3) // 1+2 + return 2; + else if(items[itPalace] < 10) // 1+2+3+4 + return 3; + else if(items[itPalace] < 21) // 1+2+3+4+5+6 + return 4; + else if(items[itPalace] < 35) + return 5; + else if(items[itPalace] < 50) + return 6; + else return 7; + } + +int hardness_empty() { + return yendor::hardness() * (yendor::hardness() * 3/5 - 2); + } + +bool redtrolls(cell *c) { + return false; /* + int cd = getCdata(c, 2); + cd &= 63; + return cd < 32; */ + } + +eMonster pickTroll(cell *c) { + if(redtrolls(c)) + return pick(moTroll,moDarkTroll,moRedTroll); + else + return pick(moForestTroll, moStormTroll, moFjordTroll); + } + +void dieTroll(cell *c, eMonster m) { + if(m == moTroll) c->wall = waDeadTroll; + else if(m == moDarkTroll) c->wall = waDeadfloor2; + else if(m == moRedTroll) c->wall = waRed1; + else c->wall = waDeadTroll2, c->wparam = m; + } + +int reptilemax() { + int i = items[itDodeca] + yendor::hardness(); + if(i >= 245) return 5; + int r = (250 - i); + if(shmup::on) r = (r+2) / 3; + return r; + } + +bool wchance(int a, int of, int reduction = 0) { + of *= 10; + a += yendor::hardness() + 1; + if(isCrossroads(cwt.c->land)) + a+= items[itHyperstone] * 10; + +//if(cwt.c->land == laWhirlwind && !nowhirl) a += items[itWindstone] * 3; + + for(int i=0; icpdist == getDistLimit()) { + c->monst = moOrangeDog; + c->stuntime = 0; + return; + } + int q = 0; + cell *ctab[8]; + for(int i=0; itype; i++) { + cell *c3 = c->mov[i]; + if(c3 && c3 != c2 && c3->land == laZebra && c3->wall == waNone) + ctab[q++] = c3; + } + if(!q) break; + c2 = c; c = ctab[hrand(q)]; + } + } + +int getGhostTimer() { + return shmup::on ? (shmup::curtime - lastexplore) / 350 : turncount - lastexplore; + } + +int getGhostcount() { + if(peace::on) return 0; + int t = getGhostTimer(); + int ghostcount = 0; + if(t > 80) ghostcount = (t-80 + hrand(20)) / 20; + return ghostcount; + } + +int getSeepcount() { + int t = getGhostTimer(); + int seepcount = 0; + if(t > 40) seepcount = (t-40 + hrand(20)) / 20; + return seepcount; + } + +bool canReachPlayer(cell *cf, eMonster m) { + vector v; + sval++; + v.push_back(cf); cf->aitmp = sval; + for(int i=0; itype; j++) { + cell *c2 = c->mov[j]; + if(!c2) continue; + if(eq(c2->aitmp, sval)) continue; + if(!passable_for(m, c2, c, P_MONSTER | P_ONPLAYER | P_CHAIN)) continue; + if(isPlayerOn(c2)) return true; + c2->aitmp = sval; v.push_back(c2); + } + } + return false; + } + +bool haveOrbPower() { + for(int i=0; iitem) == IC_ORB) return true; + } + else if(sphere) for(int i=0; ic7; + if(itemclass(c->item) == IC_ORB) return true; + forCellEx(c2, c) if(itemclass(c2->item) == IC_ORB) return true; + } + return false; + } + +bool haveKraken() { + for(int i=0; ic7; + if(c->monst == moKrakenH || c->monst == moKrakenT) return true; + } + return false; + } + +eItem wanderingTreasure(cell *c) { + eLand l = c->land; + if(l == laEFire) return itFireShard; + if(l == laEWater) return itWaterShard; + if(l == laEAir) return itAirShard; + if(l == laEEarth) return itEarthShard; + if(l == laElementalWall) return itNone; + if(l == laMirror && c->type != 6) return itNone; + if(l == laMirrorOld && c->type != 6) return itNone; + if(l == laEmerald) { + forCellEx(c2, c) if(c2->wall == waCavewall) return itNone; + } + if(l == laMinefield && c->wall == waMineMine) return itNone; + if(l == laBurial && hrand(2)) return itOrbSword; + if(l == laKraken) return itOrbFish; + return treasureType(l); + } + +void wandering() { + if(!canmove) return; + int seepcount = getSeepcount(); + int ghostcount = getGhostcount(); + if(cwt.c->land == laCA) ghostcount = 0; + + if(cwt.c->land == laZebra && cwt.c->wall == waNone && wchance(items[itZebra], 20)) + wanderingZebra(cwt.c); + + if(smallbounded) { + int maxdist = 0; + for(int i=0; icpdist > maxdist) maxdist = dcal[i]->cpdist; + for(int i=0; icpdist >= maxdist-1) { first7 = i; break; } + + if(hrand(5) == 0) { + // spawn treasure + } + } + + while(first7 < size(dcal)) { + int i = first7 + hrand(size(dcal) - first7); + cell *c = dcal[i]; + if(inmirror(c)) continue; + + if(smallbounded && !c->item && hrand(5) == 0 && c->land != laHalloween) { + if(passable(c, NULL, 0) || specialland == laKraken) { + if(!haveOrbPower() && specialland != laHell) for(int it=0; it<1000 && !c->item; it++) + placeLocalOrbs(c); + if(!c->item) c->item = wanderingTreasure(c); + if(c->item == itShard) { + c->item = itNone, c->wall = hrand(2) ? waMirror : waCloud; + } + if(c->item == itFulgurite) { + c->item = itNone, c->wall = waSandstone; + } + if(c->item == itBarrow) + c->landparam = 2 + hrand(2), + c->wall = waBarrowDig; + } + } + + if(!c->monst) c->stuntime = 0; + + if(timerghost && !smallbounded) { + // wandering seeps & ghosts + if(seepcount && c->wall == waCavewall && !c->monst && canReachPlayer(c, moSlime)) { + c->monst = moSeep; + playSeenSound(c); + seepcount--; + continue; + } + + if(ghostcount && !c->monst && !inmirror(c)) { + c->monst = moGhost; + playSeenSound(c); + ghostcount--; + continue; + } + } + + if((c->wall == waCavewall || c->wall == waDeadwall) && !c->monst && + wchance(items[treasureType(c->land)], 10) && canReachPlayer(c, moSlime)) { + c->monst = moSeep; + playSeenSound(c); + continue; + } + + else if(c->wall == waCTree && !c->monst && wchance(items[itPirate], 15) && canReachPlayer(c, moSlime)) { + c->monst = moParrot; + playSeenSound(c); + continue; + } + + else if(c->land == laEndorian && c->wall == waNone && wchance(items[itApple], 50)) { + c->monst = moSparrowhawk; + playSeenSound(c); + continue; + } + + else if(c->wall == waSea && !c->monst) { + if(c->land == laCaribbean && wchance(items[itPirate], 15) && canReachPlayer(c, moPirate)) { + c->monst = moCShark; + playSeenSound(c); + continue; + } + if(c->land == laWarpSea && avengers && canReachPlayer(c, moPirate)) { + c->monst = moRatlingAvenger; + c->wall = waBoat; + avengers--; + if(cheater) printf("avenger comes\n"); + playSeenSound(c); + continue; + } + if(c->land == laWarpSea && wchance(items[itCoral], 25) && canReachPlayer(c, moPirate)) { + c->monst = moRatling; + c->wall = waBoat; + playSeenSound(c); + continue; + } + if(c->land == laOcean && (items[itCoast] > 50 || (cwt.c->landparam < 25 && c->landparam < 25)) && wchance(items[itCoast], 25) && canReachPlayer(c, moEagle)) { + c->monst = moAlbatross; + playSeenSound(c); + continue; + } + if(!peace::on && c->land == laLivefjord && wchance(items[itFjord], 80) && items[itFjord] >= 10 && canReachPlayer(c, moWaterElemental)) { + c->monst = moWaterElemental; + playSeenSound(c); + continue; + } + if(!peace::on && c->land == laKraken && ((sphere && !hrand(15)) || wchance(items[itKraken], 240)) && !pseudohept(c)) { + bool b = canReachPlayer(c, moKrakenH); + if(sphere && (haveKraken() || !items[itOrbFish])) { + c->monst = moViking; c->wall = waBoat; c->item = itOrbFish; + playSeenSound(c); + continue; + } + if(b) forCellEx(c2, c) if((sphere || c2->cpdist > 7) && !pseudohept(c2)) { + forCellCM(c3, c2) if(c3->monst || c3->wall != waSea) + goto notfound; + c2->monst = moKrakenH; + playSeenSound(c2); + for(int i=0; itype; i++) { + c2->mov[i]->monst = moKrakenT; + c2->mov[i]->hitpoints = 1; + c2->mov[i]->mondir = c2->spn(i); + } + goto found; + } + goto notfound; + found: + continue; + } + notfound: + break; + } + + else if(c->monst || c->pathdist == PINFD) break; + + else if(c->land == laClearing && wchance(items[itMutant2], 150) && items[itMutant2] >= 15 && !c->monst && c->type == 7) + c->monst = moRedFox; + + else if(hrand(50) < statuecount * statuecount) + c->monst = moCultistLeader; + + else if(c->land == laIce && wchance(items[itDiamond], 10)) + c->monst = hrand(2) ? moWolf : moYeti; + + else if(c->land == laDogPlains && wchance(items[itDogPlains], 50, 26)) + c->monst = moHunterDog; + + else if(c->land == laDesert && wchance(items[itSpice], 10)) + c->monst = (hrand(10) || peace::on) ? moDesertman : moWorm; + + else if(c->land == laDragon && (items[itDragon] >= 8 || items[itOrbYendor]) && wchance(items[itDragon], 20)) + c->monst = moFireElemental; + + else if(c->land == laRedRock && wchance(items[itRedGem], 10)) + c->monst = (hrand(10) || peace::on) ? moRedTroll : moHexSnake; + + else if(c->land == laCaves && wchance(items[itGold], 5)) + c->monst = hrand(3) ? moTroll : moGoblin; + + else if(c->land == laBull && wchance(items[itBull], 40)) + c->monst = moGadfly; + + else if(items[itBull] >= 50 && size(butterflies) && wchance(items[itBull]-49, 25)) + c->monst = moGadfly; + + else if(c->land == laPrairie && cwt.c->LHU.fi.flowerdist > 3 && wchance(items[itGreenGrass], prairie::isriver(cwt.c) ? 150 : 40)) + c->monst = moGadfly; + + else if(c->land == laHive && wchance(hive::hivehard(), 25)) + c->monst = hive::randomHyperbug(); + + else if(c->land == laDeadCaves && wchance(items[itSilver], 5)) + c->monst = hrand(20) ? (hrand(3) ? moDarkTroll : moGoblin) : moEarthElemental; + + else if(c->land == laJungle && wchance(items[itRuby], 40)) + c->monst = hrand(10) ? moMonkey : moEagle; + + else if(c->land == laMirrorOld && wchance(items[itShard], 15)) + c->monst = hrand(10) ? moRanger : moEagle; + + else if(c->land == laMirror && mirrorspirits) { + mirrorspirits--; + c->monst = moMirrorSpirit; + } + + else if(c->land == laMirror && wchance(items[itShard], 120)) + c->monst = moNarciss; + + else if(c->land == laWarpCoast && wchance(items[itCoral], 40)) + c->monst = moRatling; + + else if(c->land == laBurial && wchance(items[itBarrow], 250)) + c->monst = moDraugr; + + else if(c->land == laTrollheim && wchance(items[itTrollEgg], 150)) + c->monst = pickTroll(c); + + else if(c->land == laRose && wchance(items[itRose], 25)) + c->monst = moFalsePrincess; + + else if(c->land == laHell && wchance(items[itHell], 20)) + c->monst = hrand(3) ? moLesser : moGreater; + + else if(c->land == laStorms && wchance(items[itFulgurite], 30)) { + c->monst = hrand(3) ? moMetalBeast : moStormTroll; + c->hitpoints = 3; + } + + else if(c->land == laWhirlwind && wchance(items[itWindstone], 30)) + c->monst = hrand(5) ? moWindCrow : moAirElemental; + + else if(c->land == laWildWest && wchance(items[itBounty], 30)) + c->monst = moOutlaw; + + else if(c->land == laEndorian && c->wall == waTrunk && wchance(items[itApple], 30)) + c->monst = moResearcher; + + else if(c->land == laOvergrown && wchance(items[itMutant], 50)) + c->monst = moForestTroll; + + else if(c->land == laCaribbean && wchance(items[itPirate], 30)) + c->monst = moPirate; + + else if(c->land == laRlyeh && wchance(items[itStatue], 15)) + c->monst = hrand(3) ? moPyroCultist : + (hrand(40) < items[itStatue]-25) ? moCultistLeader : moCultist; + + else if(c->land == laGraveyard && wchance(items[itBone], 15)) + c->monst = hrand(5) ? moGhost : moNecromancer; + + else if(isHaunted(c->land) && wchance(items[itLotus], 15)) + c->monst = moGhost; + + else if(c->land == laDryForest && wchance(items[itFernFlower], 5)) + c->monst = hrand(5) ? moHedge : moFireFairy; + + else if(c->land == laCocytus && wchance(items[itSapphire], 45)) + c->monst = moCrystalSage; + + else if(c->land == laAlchemist && wchance(items[itElixir], 3) && canReachPlayer(c, moSlime) && c->item == itNone) + c->monst = moSlime; // ? + + else if(isElemental(c->land) && wchance(items[itElemental], 20) && !peace::on) + c->monst = elementalOf(c->land); + + else if(c->land == laIvoryTower && wchance(items[itIvory], 20)) + c->monst = cellEdgeUnstable(c) ? moGargoyle : moFamiliar; + + else if(c->land == laMinefield && wchance(items[itBombEgg]-20, 400)) + c->monst = moBomberbird; + + else if(c->land == laEmerald && wchance(items[itEmerald], 5)) { + static eMonster m[4] = {moHedge, moLancer, moMiner, moFlailer}; + c->monst = m[hrand(4)]; + } + + else if(c->land == laWineyard && wchance(items[itWine], 10)) { + c->monst = moVineBeast; + } + + else if(c->land == laPalace && wchance(items[itPalace], 50)) { + if(princess::dist(c) < OUT_OF_PRISON && !princess::challenge) break; + + if(items[itPalace] >= 15 && hrand(100) < 10) + c->monst = moVizier; + else if(items[itPalace] >= 5 && hrand(100) < 50) + c->monst = hrand(2) ? moFatGuard : moSkeleton; + else c->monst = moPalace; + c->hitpoints = palaceHP(); + } + + else if(c->land == laLivefjord && wchance(items[itFjord], 10)) { + c->monst = sphere ? pick(moViking, moWaterElemental, moFjordTroll) : moViking; + } + + else if(c->land == laOcean && wchance(items[itCoast], 100)) { + c->monst = moAlbatross; + } + + else if(c->land == laPower && wchance(items[itPower], 10)) { + c->monst = eMonster(moWitch + hrand(NUMWITCH)); + } + + else if(c->land == laCamelot && hrand(30) == 0 && (euclid || c->master->alt) && celldistAltRelative(c) < 0) { + eMonster m[3] = { moHedge, moLancer, moFlailer }; + c->monst = m[hrand(3)]; + } + + else if(isCrossroads(c->land) && items[itHyperstone] && wchance(items[itHyperstone], 20)) { + c->monst = wanderingCrossroadsMonster(); + c->hitpoints = palaceHP(); + } + + + else break; + + playSeenSound(c); + if(c->monst == moWorm || c->monst == moHexSnake) c->mondir = NODIR; + + // laMotion -> no respawn! + } + } + diff --git a/orbgen.cpp b/orbgen.cpp new file mode 100644 index 00000000..66d73fa6 --- /dev/null +++ b/orbgen.cpp @@ -0,0 +1,462 @@ +#define ORBLINES 56 + +struct orbinfo { + eLand l; + int lchance; + int gchance; + eItem orb; + }; + +const orbinfo orbinfos[ORBLINES] = { + {laGraveyard, 200, 200,itGreenStone}, // must be first so that it does not reduce + // chance of other orbs + {laJungle, 1200, 1500,itOrbLightning}, + {laIce, 2000, 1500,itOrbFlash}, + {laCaves, 1800, 2000,itOrbLife}, + {laAlchemist, 800, 800,itOrbSpeed}, + {laDesert, 2500, 1500,itOrbShield}, + {laHell, 2000, 1000,itOrbYendor}, + {laRlyeh, 1500, 1500,itOrbTeleport}, + {laMotion, 2000, 700, itOrbSafety}, + {laIce, 1500, 0, itOrbWinter}, + {laDragon, 2500, 0, itOrbWinter}, + {laDryForest, 2500, 0, itOrbWinter}, + {laCocytus, 1500, 1500, itOrbWinter}, + {laCaves, 1200, 0, itOrbDigging}, + {laDryForest, 500, 4500, itOrbThorns}, + {laDeadCaves, 1800, 0, itGreenStone}, + {laDeadCaves, 1800, 1500, itOrbDigging}, + {laEmerald, 1500, 3500, itOrbPsi}, + {laWineyard, 900, 1200, itOrbAether}, + {laHive, 800, 1200, itOrbInvis}, + {laPower, 0, 3000, itOrbFire}, + {laMinefield, 0, 3500, itOrbFriend}, + {laTemple, 0, 3000, itOrbDragon}, + {laCaribbean, 0, 3500, itOrbTime}, + {laRedRock, 0, 2500, itOrbSpace}, + {laCamelot, 1000, 1500, itOrbIllusion}, + {laOcean, 0, 3000, itOrbEmpathy}, + {laOcean, 0, 0, itOrbAir}, + {laPalace, 0, 4000, itOrbDiscord}, + {laPalace, 0, 0, itOrbFrog}, + {laZebra, 500, 2100, itOrbFrog}, + {laLivefjord, 0, 1800, itOrbFish}, + {laPrincessQuest, 0, 200, itOrbLove}, + {laIvoryTower, 500, 4000, itOrbMatter}, + {laElementalWall, 1500, 4000, itOrbSummon}, + {laStorms, 1000, 2500, itOrbStunning}, + {laOvergrown, 1000, 800, itOrbLuck}, + {laWhirlwind, 1250, 3000, itOrbAir}, + {laHaunted, 1000, 5000, itOrbUndeath}, + {laClearing, 5000, 5000, itOrbFreedom}, + {laRose, 2000, 8000, itOrbBeauty}, + {laWarpCoast, 2000, 8000, itOrb37}, + {laDragon, 500, 5000, itOrbDomination}, + {laTortoise, 2500, 1500, itOrbShell}, + {laEndorian, 150, 2500, itOrbEnergy}, + {laEndorian, 450, 0, itOrbTeleport}, + {laKraken, 500, 2500, itOrbSword}, + {laBurial, 500, 2500, itOrbSword2}, + {laTrollheim, 750, 1800, itOrbStone}, + {laMountain, 400, 3500, itOrbNature}, + {laDungeon, 120, 2500, itOrbRecall}, + {laReptile, 500, 2100, itOrbDash}, + {laBull, 720, 3000, itOrbHorns}, + {laPrairie, 0, 3500, itOrbBull}, + {laWhirlpool, 0, 0, itOrbSafety}, + {laWhirlpool, 0, 2000, itOrbWater}, // must be last because it generates a boat + }; + +eItem orbType(eLand l) { + if(isElemental(l)) l = laElementalWall; + if(inv::on && (l == laMirror || l == laMirrorOld || isCrossroads(l))) + return itOrbMirror; + if(l == laMirror || l == laMirrorOld) return itShard; + for(int i=0; i= R10) + i++; + return i; + } + +bool hellUnlocked() { + return orbsUnlocked() >= 9; + } + +ld orbprizefun(int tr) { + if(tr < 10) return 0; + return .6 + .4 * log(tr/25.) / log(2); + } + +ld orbcrossfun(int tr) { + if(tr < 10) return 0; + if(tr > 25) return 1; + return (tr*2 + 50) / 100.; + } + +bool buildPrizeMirror(cell *c, int freq) { + if(inv::on) return false; + if(c->type == 7 && !purehepta) return false; + if(items[itShard] < 25) return false; + if(freq && hrand(freq * 100 / orbprizefun(items[itShard])) >= 100) + return false; + c->wall = hrand(2) ? waCloud : waMirror; + return true; + } + +eLand getPrizeLand(cell *c = cwt.c) { + eLand l = c->land; + if(isElemental(l)) l = laElementalWall; + if(l == laPalace && princess::dist(c) < OUT_OF_PRISON) + l = laPrincessQuest; + return l; + } + +void placePrizeOrb(cell *c) { + if(peace::on) return; + + eLand l = getPrizeLand(c); + + // these two lands would have too much orbs according to normal rules + if(l == laPalace && hrand(100) >= 20) return; + if(l == laPrincessQuest && hrand(100) >= 20) return; + if(l == laGraveyard && hrand(100) >= 15) return; + if(l == laBurial && hrand(100) >= 10) return; + if(l == laLivefjord && hrand(100) >= 35) return; + if(l == laMinefield && hrand(100) >= 25) return; + if(l == laElementalWall && hrand(100) >= 25) return; + + for(int i=0; i= 100) ; + else continue; + } + + eOrbLandRelation olr = getOLR(oi.orb, l); + if(olr != olrPrize25 && olr != olrPrize3) continue; + int treas = items[treasureType(oi.l)]; + if(olr == olrPrize3) treas *= 10; + if(olr == olrPrize25 || olr == olrPrize3 || olr == olrGuest || olr == olrMonster || olr == olrAlways) { + if(treas < 25) continue; + } + else continue; + + int gch = oi.gchance; + if(!gch) continue; + gch = int(gch / orbprizefun(treas)); + if(hrand(gch) >= 60) continue; + if(oi.orb == itOrbWater && c->land != laOcean && c->land != laKraken) { + if(cellHalfvine(c)) continue; + c->item = oi.orb; + c->wall = waStrandedBoat; + return; + } + c->item = oi.orb; + } + + // printf("land: %s orb: %s\n", dnameof(l), dnameof(c->item)); + } + +void placeLocalOrbs(cell *c) { + eLand l = c->land; + if(l == laZebra && c->wall == waTrapdoor) return; + if(isGravityLand(l) && cellEdgeUnstable(c)) return; + if(isElemental(l)) l = laElementalWall; + if(peace::on) return; + + for(int i=0; i= (11+hrand(15))) + ch = 0; + if(tactic::trailer && ch < 5) ch = 0; + if(ch == 0 && items[treasureType(oi.l)] * landMultiplier(oi.l) >= (chaosmode ? 1+hrand(10) : 10)) { + // printf("local orb\n"); + c->item = oi.orb; + if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat; + return; + } + else if(oi.gchance && (ch >= 1 && ch < 11) && getOLR(itShard, l) == olrPrize25 && l != laRedRock && l != laWhirlwind) + buildPrizeMirror(c, 10); + else if(oi.gchance && (ch >= 11 && ch < 11+PRIZEMUL)) + placePrizeOrb(c); + } + } + +void placeCrossroadOrbs(cell *c) { + if(peace::on) return; + for(int i=0; i= 50) ; + else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ; + else continue; + } + int treas = items[treasureType(oi.l)] * landMultiplier(oi.l); + if(tactic::on && isCrossroads(tactic::lasttactic)) { + if(oi.orb == itOrbYendor || oi.orb == itOrbSummon || oi.orb == itOrbFish || oi.orb == itOrbDigging || oi.orb == itOrbLove || oi.orb == itOrbLuck) + continue; + } + else { + if(treas < 10) continue; + } + if(oi.orb == itOrbSafety && c->land == laCrossroads5) continue; + int mul = c->land == laCrossroads5 ? 10 : 1; + int gch = oi.gchance; + if(!inv::on) gch /= orbcrossfun(treas); else gch /= 2; + if(hrand(gch) >= mul) continue; + if(hrand(50+items[itHyperstone]) >= 50) continue; + c->item = oi.orb; + if(oi.orb == itOrbWater && c->land != laOcean) c->wall = waStrandedBoat; + } + } + +void placeOceanOrbs(cell *c) { + if(peace::on) return; + for(int i=0; i= 50) ; + else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ; + else continue; + } + + if(items[treasureType(oi.l)] * landMultiplier(oi.l) < 10) continue; + if(!oi.gchance) continue; + if(oi.orb == itOrbLife) continue; // useless + if(hrand(oi.gchance) >= 20) continue; + c->item = oi.orb; + } + } +