// Hyperbolic Rogue -- orb generation routines // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details #define ORBLINES 70 // orbgen flags namespace orbgenflags { // generates in the given land from 10 treasures, in the classic mode static const int LOCAL10 = 1; // generates in the Crossroads from 10 treasures, in the classic mode static const int CROSS10 = 2; // generates in other places from 25 treasures, in the classic mode static const int GLOBAL25 = 4; // in OSM you get it once at 10 treasures static const int OSM_AT10 = 8; // 'native' functions return this static const int NATIVE = 64; // 'local' orb will be also placed in OSM (at 25 treasures); needs LOCAL10 static const int OSM_LOCAL25 = 128; // 'crossroads' orb will be also placed in OSM (at 50 treasures) static const int OSM_CROSS50 = 256; // 'crossroads' orb will be also placed in OSM (at 25 treasures) static const int OSM_CROSS25 = 512; // 'global' orb will be also placed in OSM (at 100 treasures) static const int OSM_GLOBAL100 = 1024; // do not create in the Crossroads in the tactics mode static const int NO_TACTIC = (1<<11); // guest Orb static const int GUEST = (1<<12); // typical combinations static const int S_NATIVE = LOCAL10 | CROSS10 | GLOBAL25 | NATIVE; static const int S_GUEST = LOCAL10 | OSM_AT10 | GUEST; static const int S_YENDOR = S_NATIVE | OSM_LOCAL25 | OSM_CROSS50 | OSM_GLOBAL100 | NO_TACTIC; static const int S_NAT_NT = S_NATIVE | NO_TACTIC; static const int S_NA_O25 = S_NATIVE | OSM_CROSS25; } struct orbinfo { int flags; eLand l; int lchance; int gchance; eItem orb; bool is_native() const { using namespace orbgenflags; return flags & NATIVE; } }; const orbinfo orbinfos[ORBLINES] = { {orbgenflags::S_NATIVE, laGraveyard, 200, 200,itGreenStone}, // must be first so that it does not reduce {orbgenflags::S_NATIVE, laJungle, 1200, 1500,itOrbLightning}, {orbgenflags::S_NATIVE, laIce, 2000, 1500,itOrbFlash}, {orbgenflags::S_NATIVE, laCaves, 1800, 2000,itOrbLife}, {orbgenflags::S_NATIVE, laAlchemist, 800, 800,itOrbSpeed}, {orbgenflags::S_NATIVE, laDesert, 2500, 1500,itOrbShield}, {orbgenflags::S_YENDOR, laHell, 2000, 1000,itOrbYendor}, {orbgenflags::S_NATIVE, laRlyeh, 1500, 1500,itOrbTeleport}, {orbgenflags::S_NA_O25, laMotion, 2000, 700, itOrbSafety}, {orbgenflags::S_GUEST, laIce, 1500, 0, itOrbWinter}, {orbgenflags::S_GUEST, laDragon, 2500, 0, itOrbWinter}, {orbgenflags::S_GUEST, laDryForest, 2500, 0, itOrbWinter}, {orbgenflags::S_NATIVE, laCocytus, 1500, 1500, itOrbMorph}, {orbgenflags::S_GUEST, laCocytus, 1500, 0, itOrbWinter}, {orbgenflags::S_GUEST, laCaves, 1200, 0, itOrbDigging}, {orbgenflags::S_NATIVE, laDryForest, 500, 4500, itOrbThorns}, {orbgenflags::S_GUEST, laDeadCaves, 1800, 0, itGreenStone}, {orbgenflags::S_NAT_NT, laDeadCaves, 1800, 1500, itOrbDigging}, {orbgenflags::S_NATIVE, laEmerald, 1500, 3500, itOrbPsi}, {orbgenflags::S_NATIVE, laWineyard, 900, 1200, itOrbAether}, {orbgenflags::S_NATIVE, laHive, 800, 1200, itOrbInvis}, {orbgenflags::S_NATIVE, laPower, 0, 3000, itOrbFire}, {orbgenflags::S_NATIVE, laMinefield, 0, 3500, itOrbFriend}, {orbgenflags::S_NATIVE, laTemple, 0, 3000, itOrbDragon}, {orbgenflags::S_NATIVE, laCaribbean, 0, 3500, itOrbTime}, {orbgenflags::S_NATIVE, laRedRock, 0, 2500, itOrbSpace}, {orbgenflags::S_NATIVE, laCamelot, 1000, 1500, itOrbIllusion}, {orbgenflags::S_NATIVE, laOcean, 0, 3000, itOrbEmpathy}, {orbgenflags::S_GUEST, laOcean, 0, 0, itOrbAir}, {orbgenflags::S_NATIVE, laPalace, 0, 4000, itOrbDiscord}, {orbgenflags::S_GUEST, laPalace, 0, 0, itOrbFrog}, {orbgenflags::S_NATIVE, laZebra, 500, 2100, itOrbFrog}, {orbgenflags::S_NAT_NT, laLivefjord, 0, 1800, itOrbFish}, {orbgenflags::S_NAT_NT, laPrincessQuest, 0, 200, itOrbLove}, {orbgenflags::S_NATIVE, laIvoryTower, 500, 4000, itOrbMatter}, {orbgenflags::S_NAT_NT, laElementalWall, 1500, 4000, itOrbSummon}, {orbgenflags::S_NATIVE, laStorms, 1000, 2500, itOrbStunning}, {orbgenflags::S_NAT_NT, laOvergrown, 1000, 800, itOrbLuck}, {orbgenflags::S_NATIVE, laWhirlwind, 1250, 3000, itOrbAir}, {orbgenflags::S_NATIVE, laHaunted, 1000, 5000, itOrbUndeath}, {orbgenflags::S_NATIVE, laClearing, 5000, 5000, itOrbFreedom}, {orbgenflags::S_NATIVE, laRose, 2000, 8000, itOrbBeauty}, {orbgenflags::S_NATIVE, laWarpCoast, 2000, 8000, itOrb37}, {orbgenflags::S_NATIVE, laDragon, 500, 5000, itOrbDomination}, {orbgenflags::S_NATIVE, laTortoise, 2500, 1500, itOrbShell}, {orbgenflags::S_NATIVE, laEndorian, 150, 2500, itOrbEnergy}, {orbgenflags::S_GUEST, laEndorian, 450, 0, itOrbTeleport}, {orbgenflags::S_NATIVE, laKraken, 500, 2500, itOrbSword}, {orbgenflags::S_NATIVE, laBurial, 500, 2500, itOrbSword2}, {orbgenflags::S_NATIVE, laTrollheim, 750, 1800, itOrbStone}, {orbgenflags::S_NATIVE, laMountain, 400, 3500, itOrbNature}, {orbgenflags::S_NATIVE, laDungeon, 120, 2500, itOrbRecall}, {orbgenflags::S_NATIVE, laReptile, 500, 2100, itOrbDash}, {orbgenflags::S_NATIVE, laBull, 720, 3000, itOrbHorns}, {orbgenflags::S_NATIVE, laPrairie, 0, 3500, itOrbBull}, {orbgenflags::S_GUEST, laWhirlpool, 0, 0, itOrbSafety}, {orbgenflags::S_NATIVE, laVolcano, 0, 7000, itOrbLava}, {orbgenflags::S_NATIVE, laHunting, 0, 2500, itOrbSide3}, {orbgenflags::S_NATIVE, laBlizzard, 0, 2000, itOrbWinter}, {orbgenflags::S_NATIVE, laTerracotta, 800, 2500, itOrbSide1}, {orbgenflags::S_NATIVE, laDual, 600, 2500, itOrbSide2}, {orbgenflags::S_GUEST, laSnakeNest, 2000, 0, itOrbDomination}, {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbFish}, {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbDragon}, {orbgenflags::S_GUEST, laDocks, 3000, 0, itOrbDash}, {orbgenflags::S_GUEST, laSwitch, 2000, 0, itOrbSpace}, {orbgenflags::S_NATIVE, laSwitch, 2000, 3000, itOrbPhasing}, {orbgenflags::S_NATIVE, laMagnetic, 2000, 3000, itOrbMagnetism}, {orbgenflags::S_NATIVE, laRuins, 1200, 2500, itOrbSlaying}, {orbgenflags::S_NATIVE, laWhirlpool, 0, 2000, itOrbWater}, // needs to be last }; eItem nativeOrbType(eLand l) { if(isElemental(l)) l = laElementalWall; if(inv::on && (l == laMirror || l == laMirrorOld || isCrossroads(l))) return itOrbMirror; if(l == laMirror || l == laMirrorOld) return itShard; for(int i=0; i= R10) i++; return i; } bool hellUnlocked() { return orbsUnlocked() >= 9; } ld orbprizefun(int tr) { if(tactic::on) return 1; if(tr < 10) return 0; return .6 + .4 * log(tr/25.) / log(2); } ld orbcrossfun(int tr) { if(tactic::on) return 1; 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(gp::on) return false; if(c->type == 7 && !nonbitrunc) 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= 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)); } // 10 not in chaos, less in chaos int treasureForLocal() { return (chaosmode ? 1+hrand(10) : 10); } void placeLocalOrbs(cell *c) { eLand l = c->land; if(l == laZebra && c->wall == waTrapdoor) return; if(isGravityLand(l) && cellEdgeUnstable(c)) return; if(isElemental(l)) l = laElementalWall; if(peace::on) return; for(int i=0; i= (11+hrand(15))) ch = 0; if(tactic::trailer && ch < 5) ch = 0; int tc = items[treasureType(oi.l)] * landMultiplier(oi.l); int tcmin = treasureForLocal(); if(inv::on) { if(!(oi.flags & orbgenflags::OSM_LOCAL25)) tc = 0; else tcmin = 25; } if(ch == 0 && tc >= tcmin) { // 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 placeLocalSpecial(cell *c, int outof, int loc=1, int priz=1) { if(peace::on || safety) return; int i = hrand(outof); if(i < loc && items[treasureType(c->land)] >= treasureForLocal() && !inv::on) c->item = nativeOrbType(c->land); else if(i >= loc && i < loc + PRIZEMUL * priz) placePrizeOrb(c); } void placeCrossroadOrbs(cell *c) { if(peace::on) return; for(int i=0; iland == 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= 20) continue; c->item = oi.orb; } }