mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-24 09:00:34 +00:00
landgen refactoring
This commit is contained in:
parent
362abea781
commit
f1bba9de0d
772
barriers.cpp
Normal file
772
barriers.cpp
Normal file
@ -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; i<bb.c->type; i++) {
|
||||
cell *c1 = bb.c->mov[i];
|
||||
if(!c1) continue;
|
||||
for(int j=0; j<c1->type; 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; i<c->type; 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; i<c->type; i++) {
|
||||
cell *c2 = createMov(c, i);
|
||||
if(c2 && c2->landparam && (c2->land == laCrossroads2 || c2->land == laBarrier)) {
|
||||
for(int j=0; j<c2->type; 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; d<c2->type; 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; i<c->type; 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; i<c->type; 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; i<c->type; 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;
|
||||
}
|
||||
|
1029
bigstuff.cpp
Normal file
1029
bigstuff.cpp
Normal file
File diff suppressed because it is too large
Load Diff
523
complex.cpp
523
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<cell*> srch;
|
||||
|
||||
cell *farempty(bool lastresort = false) {
|
||||
int maxdist = 0;
|
||||
vector<cell*> validcells;
|
||||
int firstfar1 = 0;
|
||||
for(int i=1; i<size(dcal); i++) {
|
||||
bool okay =
|
||||
dcal[i]->item == 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; i<c2->type; 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; i<c2->type; 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);
|
||||
}
|
||||
}
|
||||
|
46
debug.cpp
46
debug.cpp
@ -1,3 +1,49 @@
|
||||
int steplimit = 0;
|
||||
int cstep;
|
||||
|
||||
template<class... T>
|
||||
void limitgen(T... args) {
|
||||
if(steplimit) {
|
||||
cstep++;
|
||||
printf("%6d ", cstep);
|
||||
printf(args...);
|
||||
if(cstep == steplimit) buggyGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
vector<cell*> 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();
|
||||
|
25
hyper.h
25
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<cell*> buggycells;
|
||||
|
||||
extern bool landUnlocked(eLand l);
|
||||
|
||||
extern void describeCell(cell*);
|
||||
extern bool rlyehComplete();
|
||||
|
||||
template<class... T> void limitgen(T... args);
|
||||
eLand oppositeElement(eLand l, eLand l2);
|
||||
|
||||
extern int hardness_empty();
|
||||
extern eWall getElementalWall(eLand l);
|
||||
|
||||
void gainItem(eItem it);
|
||||
|
5
init.cpp
5
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
|
||||
|
4287
landgen.cpp
4287
landgen.cpp
File diff suppressed because it is too large
Load Diff
856
landlock.cpp
Normal file
856
landlock.cpp
Normal file
@ -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<ittypes; t++)
|
||||
if(t != itHyperstone && t != itBounty && t != itTreat &&
|
||||
itemclass(eItem(t)) == IC_TREASURE) {
|
||||
i2++; if(items[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<RANDLANDS; i++) if(randlands[i] == l) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 createOnSea(eLand old) {
|
||||
return
|
||||
old == laWarpSea || old == laCaribbean || old == laKraken ||
|
||||
(old == laLivefjord && hrand(2)) ||
|
||||
(old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant));
|
||||
}
|
||||
|
||||
hookset<eLand(eLand)> *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<landtypes; i++) {
|
||||
eLand l2 = eLand(i);
|
||||
if(isTrollLand(l2)) LIKELY tab[cnt++] = l2;
|
||||
}
|
||||
}
|
||||
|
||||
if(elementalUnlocked()) {
|
||||
tab[cnt++] = randomElementalLandWeighted();
|
||||
|
||||
if(old == laDragon) LIKELY tab[cnt++] = laEFire;
|
||||
if(old == laEFire) LIKELY tab[cnt++] = laDragon;
|
||||
|
||||
if(old == laLivefjord) LIKELY tab[cnt++] = laEWater;
|
||||
if(old == laEWater) LIKELY tab[cnt++] = laLivefjord;
|
||||
|
||||
if(old == laDeadCaves) LIKELY tab[cnt++] = laEEarth;
|
||||
if(old == laEEarth) LIKELY tab[cnt++] = laDeadCaves;
|
||||
|
||||
if(old == laWhirlwind) LIKELY tab[cnt++] = laEAir;
|
||||
if(old == laEAir) LIKELY tab[cnt++] = laWhirlwind;
|
||||
}
|
||||
|
||||
if(hellUnlocked()) {
|
||||
if(!generatingEquidistant && old != laPrairie) tab[cnt++] = laCrossroads3;
|
||||
tab[cnt++] = laHell;
|
||||
}
|
||||
|
||||
if(items[itHell] >= 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;
|
||||
}
|
||||
|
605
monstergen.cpp
Normal file
605
monstergen.cpp
Normal file
@ -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; i<c->type; 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; i<c->type; 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; i<c3->type; 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; i<c3->type; 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; i<ittypes; i++) if(itemclass(eItem(i)) == IC_TREASURE)
|
||||
a = max(a, (items[i]-R10) / 10);
|
||||
|
||||
a -= reduction;
|
||||
if(a < 0) return false;
|
||||
|
||||
return hrand(a+of) < a;
|
||||
}
|
||||
|
||||
void wanderingZebra(cell *start) {
|
||||
cell *c = start, *c2 = start;
|
||||
for(int it=0; it<100; it++) {
|
||||
if(c->cpdist == getDistLimit()) {
|
||||
c->monst = moOrangeDog;
|
||||
c->stuntime = 0;
|
||||
return;
|
||||
}
|
||||
int q = 0;
|
||||
cell *ctab[8];
|
||||
for(int i=0; i<c->type; 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<cell*> v;
|
||||
sval++;
|
||||
v.push_back(cf); cf->aitmp = sval;
|
||||
for(int i=0; i<size(v); i++) {
|
||||
cell *c = v[i];
|
||||
for(int j=0; j<c->type; 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; i<ittypes; i++) if(itemclass(eItem(i)) == IC_ORB && items[i]) return true;
|
||||
if(quotient) for(int i=0; i<size(dcal); i++) {
|
||||
cell *c = dcal[i];
|
||||
if(itemclass(c->item) == IC_ORB) return true;
|
||||
}
|
||||
else if(sphere) for(int i=0; i<spherecells(); i++) {
|
||||
cell *c = getDodecahedron(i)->c7;
|
||||
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; i<spherecells(); i++) {
|
||||
cell *c = getDodecahedron(i)->c7;
|
||||
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; i<size(dcal); i++) if(dcal[i]->cpdist > maxdist) maxdist = dcal[i]->cpdist;
|
||||
for(int i=0; i<size(dcal); i++) if(dcal[i]->cpdist >= 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; i<c2->type; 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!
|
||||
}
|
||||
}
|
||||
|
462
orbgen.cpp
Normal file
462
orbgen.cpp
Normal file
@ -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<ORBLINES; i++)
|
||||
if(orbinfos[i].l == l && orbinfos[i].gchance)
|
||||
return orbinfos[i].orb;
|
||||
return itNone;
|
||||
}
|
||||
|
||||
const orbinfo& getOrbInfo(eItem orb) {
|
||||
for(int i=0; i<ORBLINES; i++)
|
||||
if(orbinfos[i].orb == orb && orbinfos[i].gchance)
|
||||
return orbinfos[i];
|
||||
static orbinfo oi;
|
||||
oi.l = laMirror;
|
||||
return oi;
|
||||
}
|
||||
|
||||
enum eOrbLandRelation {
|
||||
olrForbidden, // never appears: forbidden
|
||||
olrDangerous, // never appears: would be dangerous
|
||||
olrUseless, // never appears: useless here
|
||||
olrNoPrizes, // no prizes in this land
|
||||
olrNoPrizeOrb,// orb not allowed as a prize
|
||||
olrPrize25, // prize for collecting 25
|
||||
olrPrize3, // prize for collecting 3
|
||||
olrNative, // native orb in this land
|
||||
olrNative1, // native orb in this land (1)
|
||||
olrGuest, // extra orb in this land
|
||||
olrPNative, // Land of Power: native
|
||||
olrPBasic, // Land of Power: basic orbs
|
||||
olrPPrized, // Land of Power: prized orbs
|
||||
olrPNever, // Land of Power: foreign orbs
|
||||
olrHub, // hub lands
|
||||
olrMonster, // available from a monster
|
||||
olrAlways // always available
|
||||
};
|
||||
|
||||
string olrDescriptions[] = {
|
||||
"forbidden to find in %the1",
|
||||
"too dangerous to use in %the1",
|
||||
"useless in %the1",
|
||||
"only native Orbs allowed in %the1",
|
||||
"this Orb is never unlocked globally (only hubs)",
|
||||
"collect 25 %2 to unlock it in %the1",
|
||||
"collect 3 %2 to unlock it in %the1",
|
||||
"native to %the1 (collect 10 %2)",
|
||||
"native to %the1 (collect 1 %2)",
|
||||
"secondary in %the1 (collect 10 %3, or 25 %2)",
|
||||
"the native Orb of %the1",
|
||||
"this Orb appears on floors and is used by witches",
|
||||
"a prized Orb, it appears only in cabinets",
|
||||
"this Orb never appears in %the1",
|
||||
"Hub Land: orbs appear here if unlocked in their native land",
|
||||
"kill a monster, or collect 25 %2",
|
||||
"always available"
|
||||
};
|
||||
|
||||
eOrbLandRelation getOLR(eItem it, eLand l) {
|
||||
|
||||
if(l == laPower) {
|
||||
if(it == itOrbFire) return olrPNative;
|
||||
|
||||
if(
|
||||
it == itOrbFlash || it == itOrbSpeed || it == itOrbWinter || it == itOrbAether ||
|
||||
it == itOrbLife) return olrPBasic;
|
||||
|
||||
if(
|
||||
it == itOrbLightning || it == itOrbThorns || it == itOrbInvis ||
|
||||
it == itOrbShield || it == itOrbTeleport || it == itOrbPsi ||
|
||||
it == itOrbDragon || it == itOrbIllusion || it == itOrbTime)
|
||||
return olrPPrized;
|
||||
|
||||
return olrPNever;
|
||||
}
|
||||
|
||||
if(it == itOrbSafety && l == laCrossroads5) return olrDangerous;
|
||||
if(it == itOrbFire && l == laKraken) return olrUseless;
|
||||
if(it == itOrbDragon && l == laKraken) return olrUseless;
|
||||
if(it == itOrbDigging && l == laKraken) return olrUseless;
|
||||
if(it == itOrbIllusion && l == laKraken) return olrUseless;
|
||||
|
||||
// if(it == itOrbYendor && l == laWhirlpool) return olrUseless;
|
||||
if(it == itOrbYendor && l == laWhirlwind) return olrUseless;
|
||||
|
||||
if(it == itOrbLife && (l == laKraken)) return olrUseless;
|
||||
|
||||
if(it == itOrbAir && l == laAlchemist) return olrUseless;
|
||||
// if(it == itOrbShield && l == laMotion) return olrUseless;
|
||||
|
||||
if(it == itOrbIllusion && l == laCamelot) return olrNative1;
|
||||
if(it == itOrbLove) return olrNoPrizeOrb;
|
||||
if(orbType(l) == it) return olrNative;
|
||||
if(it == itOrbWinter && (l == laIce || l == laDryForest || l == laDragon))
|
||||
return olrGuest;
|
||||
if(it == itOrbLuck && l == laIvoryTower)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laEndorian)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laDungeon)
|
||||
return olrUseless;
|
||||
if(it == itOrbWater && l == laRedRock)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laTortoise)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laMountain)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laCamelot)
|
||||
return olrUseless;
|
||||
if(it == itOrbLuck && l == laHaunted)
|
||||
return olrUseless;
|
||||
if(it == itOrbNature && l == laWineyard)
|
||||
return olrDangerous;
|
||||
if(it == itOrbDigging && l == laCaves)
|
||||
return olrGuest;
|
||||
if(it == itOrbFrog && (l == laPalace || l == laPrincessQuest))
|
||||
return olrGuest;
|
||||
if(it == itOrbDragon && l == laRlyeh)
|
||||
return olrMonster;
|
||||
|
||||
if(it == itOrbSafety && l == laWhirlpool)
|
||||
return olrAlways;
|
||||
if(it == itOrbSafety && l == laPrairie)
|
||||
return olrAlways;
|
||||
if(it == itGreenStone && isHaunted(l))
|
||||
return olrAlways;
|
||||
if(it == itOrbWater && l == laLivefjord)
|
||||
return olrMonster;
|
||||
if(isCrossroads(l) || l == laOcean)
|
||||
return olrHub;
|
||||
|
||||
if(l == laCocytus)
|
||||
if(it == itOrbDragon || it == itOrbFire || it == itOrbFlash || it == itOrbLightning)
|
||||
return olrDangerous;
|
||||
|
||||
if(it == itOrbSafety)
|
||||
if(l == laCaves || l == laLivefjord || l == laRedRock || l == laCocytus || l == laHell ||
|
||||
l == laDesert || l == laAlchemist || l == laDeadCaves || l == laMinefield || isHaunted(l) ||
|
||||
l == laDragon)
|
||||
return olrDangerous;
|
||||
|
||||
if(it == itOrbMatter)
|
||||
if(l == laCaves || l == laEmerald || l == laAlchemist || l == laCaribbean ||
|
||||
l == laMinefield || l == laCocytus) return olrUseless;
|
||||
|
||||
if(l == laPrincessQuest)
|
||||
if(it == itOrbAether || it == itOrbFlash || it == itOrbTeleport || it == itOrbSummon || it == itOrbFreedom)
|
||||
return olrForbidden;
|
||||
|
||||
if(l == laTemple)
|
||||
return olrNoPrizes;
|
||||
|
||||
if(it == itOrbDigging) {
|
||||
if(l == laCaves || l == laOcean || l == laLivefjord || l == laEmerald ||
|
||||
l == laDesert || l == laDeadCaves || l == laRedRock || l == laCaribbean || l == laGraveyard ||
|
||||
l == laMountain)
|
||||
return olrPrize25;
|
||||
return olrUseless;
|
||||
}
|
||||
|
||||
if(it == itShard) {
|
||||
if(l == laDesert || l == laIce || l == laJungle || l == laGraveyard ||
|
||||
l == laRlyeh || l == laHell || l == laDryForest || l == laWineyard ||
|
||||
l == laHive || l == laCamelot || l == laRedRock || l == laPalace ||
|
||||
l == laLivefjord || l == laZebra || isElemental(l) || l == laPrincessQuest ||
|
||||
l == laDragon || l == laTortoise || l == laBurial || l == laTrollheim ||
|
||||
l == laOcean || l == laHaunted || l == laWarpCoast || l == laRose)
|
||||
return olrPrize25;
|
||||
return olrForbidden;
|
||||
}
|
||||
|
||||
if(it == itOrbWater)
|
||||
if(l == laMotion || l == laZebra || l == laIvoryTower || l == laEndorian ||
|
||||
l == laMountain || l == laReptile || l == laDungeon)
|
||||
return olrUseless;
|
||||
|
||||
if(it == itOrbWinter && l == laMinefield)
|
||||
return olrForbidden;
|
||||
|
||||
if(it == itOrbWinter && l != laRlyeh && l != laTemple)
|
||||
return olrUseless;
|
||||
|
||||
if(it == itOrbLife && l == laMotion)
|
||||
return olrUseless;
|
||||
|
||||
if(it == itOrbFish && l == laKraken)
|
||||
return olrAlways;
|
||||
|
||||
if(it == itOrbSword && l == laBurial)
|
||||
return olrAlways;
|
||||
|
||||
if(it == itOrbFish && l != laOcean && l != laLivefjord && l != laWhirlpool && l != laCamelot &&
|
||||
l != laTortoise)
|
||||
return olrUseless;
|
||||
|
||||
if(it == itOrbDomination && l != laOcean && l != laRedRock && l != laDesert &&
|
||||
l != laRlyeh && l != laDragon)
|
||||
return olrUseless;
|
||||
|
||||
if(it == itOrbIllusion) return olrPrize3;
|
||||
|
||||
if(l == laTortoise)
|
||||
if(it == itOrbFlash || it == itOrbLightning || it == itOrbFreedom ||
|
||||
it == itOrbPsi || it == itOrbFriend || it == itOrbDragon)
|
||||
return olrForbidden;
|
||||
|
||||
if(l == laEndorian)
|
||||
if(it == itOrbDragon || it == itOrbFire || it == itOrbLightning)
|
||||
return olrDangerous;
|
||||
|
||||
if(l == laDungeon) {
|
||||
if(it == itOrbSafety || it == itOrbFrog ||
|
||||
it == itOrbTeleport || it == itOrbMatter || it == itOrbNature ||
|
||||
it == itOrbAether || it == itOrbSummon || it == itOrbStone)
|
||||
return olrForbidden;
|
||||
}
|
||||
|
||||
return olrPrize25;
|
||||
}
|
||||
|
||||
int orbsUnlocked() {
|
||||
int i = 0;
|
||||
for(int t=0; t<ittypes; t++)
|
||||
if(itemclass(eItem(t)) == IC_TREASURE && items[t] >= 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<ORBLINES; i++) {
|
||||
const orbinfo& oi(orbinfos[i]);
|
||||
|
||||
if(inv::on) {
|
||||
if(oi.orb == itOrbYendor && items[itHell] >= 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<ORBLINES; i++) {
|
||||
const orbinfo& oi(orbinfos[i]);
|
||||
if(oi.l != l) continue;
|
||||
if(inv::on) {
|
||||
if(oi.orb != itOrbYendor) continue;
|
||||
if(items[itHell] < 25) continue;
|
||||
}
|
||||
if(yendor::on && (oi.orb == itOrbSafety || oi.orb == itOrbYendor))
|
||||
continue;
|
||||
if(!oi.lchance) continue;
|
||||
int ch = hrand(oi.lchance);
|
||||
if(ch == 1 && chaosmode && hrand(2) == 0 && items[treasureType(oi.l)] * landMultiplier(oi.l) >= (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<ORBLINES; i++) {
|
||||
const orbinfo& oi(orbinfos[i]);
|
||||
if(!oi.gchance) continue;
|
||||
|
||||
if(inv::on) {
|
||||
if(oi.orb == itOrbYendor && items[itHell] >= 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<ORBLINES; i++) {
|
||||
const orbinfo& oi(orbinfos[i]);
|
||||
|
||||
if(inv::on) {
|
||||
if(oi.orb == itOrbYendor && items[itHell] >= 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user