1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-06-20 12:20:01 +00:00

orb help now lists the OSM information (required refactoring)

This commit is contained in:
Zeno Rogue 2017-10-10 12:43:41 +02:00
parent 035f1ad8de
commit 206e56942a
6 changed files with 330 additions and 180 deletions

View File

@ -1206,7 +1206,8 @@ itemtype iinf[ittypes] = {
{ 'o', 0x3080D0, "Orb of Morph", NODESCYET},
};
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
enum eItem {
itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
itFeather, itSapphire, itHyperstone, itKey,
itGreenStone, itOrbYendor,
itOrbLightning, itOrbFlash, itOrbWinter, itOrbSpeed, itOrbLife, itOrbShield, itOrbDigging,
@ -1240,7 +1241,7 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo
itInventory,
itLavaLily, itDogPlains, itBlizzard, itTerra,
itOrbSide1, itOrbSide2, itOrbSide3,
itOrbLava, itOrbMorph
itOrbLava, itOrbMorph,
};
// --- wall types ---

View File

@ -281,6 +281,12 @@ string generateHelpForItem(eItem it) {
"\n\nIn the Orb Strategy Mode, each 25 Necromancer's Totems "
"you are given a random offensive Orb."
);
if(inv::remaining[it] || inv::usedup[it]) help += "\n\n" + inv::osminfo(it);
inv::whichorbinfo = it;
inv::compute();
if(inv::orbinfoline != "") help += "\n\n" + inv::orbinfoline;
if(inv::extra != "") help += "\n\nExtras:" + inv::extra;
}
if(itemclass(it) == IC_ORB || it == itGreenStone || it == itOrbYendor) {

View File

@ -20,7 +20,6 @@ namespace inv {
struct lateextraorb {
eItem treasure;
eItem orb;
int at;
};
vector<lateextraorb> lateextraorbs = {
@ -90,10 +89,6 @@ namespace inv {
return int(mirrorqty0(orb) * sqrt(1.000001+items[itPower]/20.));
}
struct nextinfo { int min, real, max; };
nextinfo next[ittypes];
mt19937 invr;
void sirand(int i) {
@ -104,17 +99,37 @@ namespace inv {
return invr() % i;
}
eItem whichorbinfo;
string orbinfoline, extra;
string extraline(eItem it, string s) {
return " "+XLAT1(iinf[it].name) + " ("+s+")";
}
void gainOrbs(eItem it, eItem o) {
auto& nx = next[o == itHyperstone ? o : it];
int qty = items[it];
if(it == itHolyGrail) {
remaining[itOrbIllusion] += qty;
nx = {qty+1, qty+1, qty+1};
if(it == itOrbIllusion) {
orbinfoline += XLAT("Unlocked by: %1 in %2", it, laNone);
orbinfoline += XLAT(" (next at %1)", its(qty+1));
}
}
else {
bool nextfound = false;
if(qty >= 10) remaining[o]++;
else nx = {10,10,10}, nextfound = true;
else {
if(whichorbinfo == o) {
if(it == itHyperstone) {
extra += extraline(it, "10");
}
else {
orbinfoline += XLAT("Unlocked by: %1 in %2", it, laNone);
orbinfoline += XLAT(" (next at %1)", its(10));
}
}
nextfound = true;
}
int last = 10;
for(int k=0; k<30 || !nextfound; k++) {
int maxstep = 15 + 5 * k;
@ -129,8 +144,19 @@ namespace inv {
}
else
xnext = last + 1 + irand(maxstep);
if(xnext > qty && !nextfound)
nx = { last+1, xnext, last + maxstep }, nextfound = true;
if(xnext > qty && !nextfound) {
if(whichorbinfo == o) {
if(it == itHyperstone) {
extra += extraline(it, its(last+maxstep));
}
orbinfoline += XLAT("Unlocked by: %1 in %2", it, laCrossroads);
if(maxstep == 1)
orbinfoline += XLAT(" (next at %1)", its(last+1));
else
orbinfoline += XLAT(" (next at %1 to %2)", its(last+1), its(last + maxstep));
}
nextfound = true;
}
if(xnext <= qty) remaining[o]++;
last = xnext;
}
@ -143,8 +169,11 @@ namespace inv {
return z;
}
void gainMirrors(int qtl) {
void gainMirrors(eItem forwhich) {
int qtl = items[forwhich];
while(qtl > 0) qtl >>= 1, remaining[itOrbMirror]++;
if(whichorbinfo == itOrbMirror)
extra += extraline(forwhich, its(nextp2(items[which])));
}
vector<eItem> offensiveOrbs = {
@ -166,12 +195,62 @@ namespace inv {
const int qoff = size(orblist);
for(int i=1; i<qoff; i++) swap(orblist[i], orblist[irand(1+i)]);
for(int i=0; i<20; i++) {
if((i+1)*each <= items[which] - reduce)
remaining[orblist[i%qoff]]++;
int nextat = (i+1)*each + reduce;
if(items[which] >= nextat) {
remaining[orblist[i%qoff]]++;
}
else {
if(isIn(whichorbinfo, orblist))
extra += extraline(which, its(nextat) + "?");
break;
}
}
}
void gainGuestOrbs() {
for(int k=0; k<ORBLINES; k++) {
auto& oi = orbinfos[k];
if(oi.flags & orbgenflags::OSM_AT10) {
eItem it = treasureType(oi.l);
if(items[it] >= 10) {
remaining[oi.orb]++;
}
if(whichorbinfo == oi.orb) extra += extraline(it, "10");
}
}
}
void gainLove() {
if(princess::reviveAt) {
remaining[itOrbLove]++;
int s = gold(NO_LOVE);
int last = princess::reviveAt;
for(int k=0;; k++) {
int nextstep = 50 + 20 * k;
last += nextstep;
if(last > s) {
if(whichorbinfo == itOrbLove) {
orbinfoline += XLAT("Unlocked by: %1 in %2", itSavedPrincess, laPrincessQuest);
orbinfoline += XLAT(" (next at %1)", its(last));
}
break;
}
else { last += nextstep; remaining[itOrbLove]++; }
}
}
}
void gainLate(eItem tr, eItem orb) {
int at = 10 + irand(41);
int itr = items[tr];
if(itr >= at) remaining[orb]++;
if(whichorbinfo == orb)
extra += extraline(tr, itr >= at ? (its(at)+"!") : "10-50");
}
void compute() {
extra = "";
orbinfoline = "";
for(int i=0; i<ittypes; i++) remaining[i] = -usedup[i];
for(int i=0; i<ittypes; i++) if(usedup[i] >= TESTMIRRORED) {
@ -182,51 +261,66 @@ namespace inv {
sirand(rseed);
vector<pair<eItem, eItem>> itempairs;
for(int k=0; k<ORBLINES; k++) {
auto oi = orbinfos[k];
eLand l = oi.l;
eItem it = treasureType(l);
eItem o = oi.orb;
if(oi.gchance) itempairs.emplace_back(it, o);
else if(items[it] >= 10) remaining[o]++;
}
sort(itempairs.begin(), itempairs.end());
gainGuestOrbs();
gainOrbs(itShard, itOrbMirror);
gainOrbs(itHyperstone, itOrbMirror);
for(auto p: itempairs)
gainOrbs(p.first, p.second);
gainOrbs(itDiamond, itOrbFlash);
gainOrbs(itGold, itOrbLife);
gainOrbs(itSpice, itOrbShield);
gainOrbs(itRuby, itOrbLightning);
gainOrbs(itElixir, itOrbSpeed);
gainOrbs(itBone, itGreenStone);
gainOrbs(itHell, itOrbYendor);
gainOrbs(itStatue, itOrbTeleport);
gainOrbs(itFeather, itOrbSafety);
gainOrbs(itSapphire, itOrbWinter);
gainOrbs(itFernFlower, itOrbThorns);
gainOrbs(itWine, itOrbAether);
gainOrbs(itSilver, itOrbDigging);
gainOrbs(itRoyalJelly, itOrbInvis);
gainOrbs(itEmerald, itOrbPsi);
gainOrbs(itPower, itOrbFire);
gainOrbs(itHolyGrail, itOrbIllusion);
gainOrbs(itGrimoire, itOrbDragon);
gainOrbs(itPirate, itOrbTime);
gainOrbs(itRedGem, itOrbSpace);
gainOrbs(itBombEgg, itOrbFriend);
gainOrbs(itCoast, itOrbEmpathy);
gainOrbs(itWhirlpool, itOrbWater);
gainOrbs(itPalace, itOrbDiscord);
gainOrbs(itFjord, itOrbFish);
gainOrbs(itSavedPrincess, itOrbLove);
gainOrbs(itIvory, itOrbMatter);
gainOrbs(itZebra, itOrbFrog);
gainOrbs(itElemental, itOrbSummon);
gainOrbs(itFulgurite, itOrbStunning);
gainOrbs(itMutant, itOrbLuck);
gainOrbs(itMutant2, itOrbFreedom);
gainOrbs(itLotus, itOrbUndeath);
gainOrbs(itWindstone, itOrbAir);
gainOrbs(itRose, itOrbBeauty);
gainOrbs(itCoral, itOrb37);
gainOrbs(itBabyTortoise, itOrbShell);
gainOrbs(itApple, itOrbEnergy);
gainOrbs(itDragon, itOrbDomination);
gainOrbs(itKraken, itOrbSword);
gainOrbs(itBarrow, itOrbSword2);
gainOrbs(itTrollEgg, itOrbStone);
gainOrbs(itSlime, itOrbRecall);
gainOrbs(itAmethyst, itOrbNature);
gainOrbs(itDodeca, itOrbDash);
gainOrbs(itGreenGrass, itOrbBull);
gainOrbs(itBull, itOrbHorns);
if(items[itOrbYendor]) remaining[itOrbMirror]++;
gainMirrors(items[itOrbYendor]);
gainMirrors(items[itHolyGrail]);
if(princess::reviveAt) {
remaining[itOrbLove]++;
int s = gold(NO_LOVE);
int last = princess::reviveAt;
for(int k=0;; k++) {
int nextstep = 50 + 20 * k;
last += nextstep;
if(last > s) {
next[itSavedPrincess] = {last, last, last};
break;
}
else { last += nextstep; remaining[itOrbLove]++; }
}
}
gainMirrors(itOrbYendor);
gainMirrors(itHolyGrail);
gainLove();
gainRandomOrbs(offensiveOrbs, itBone, 25, 0);
gainRandomOrbs(elementalOrbs, itElemental, 12, 0);
gainRandomOrbs(demonicOrbs, itHell, 20, 100);
for(auto& it: lateextraorbs) {
it.at = 10 + irand(41);
if(items[it.treasure] >= it.at) remaining[it.orb]++;
}
for(auto& it: lateextraorbs) gainLate(it.treasure, it.orb);
if(items[itOrbLove] && !items[itSavedPrincess]) items[itSavedPrincess] = 1;
@ -285,10 +379,6 @@ namespace inv {
"several quests and lands "
"give you extremely powerful Orbs of the Mirror.\n";
string extraline(eItem it, string s) {
return " "+XLAT1(iinf[it].name) + " ("+s+")";
}
void evokeBeautyAt(cell *c) {
forCellEx(c2, c)
if(c2->monst && !isFriendly(c2->monst) && !isIvy(c2->monst)) {
@ -321,6 +411,14 @@ namespace inv {
}
}
}
string osminfo(eItem orb) {
string s = XLAT("Number of uses left: %1", its(remaining[orb]));
int us = usedup[orb];
if(us >= TESTMIRRORED) s += XLAT(" (mirrored)"), us = us - MIRRORED + mirrorqty0(orb);
if(us) s += XLAT(" (used %1 times)", its(us));
return s;
}
void show() {
@ -401,60 +499,29 @@ namespace inv {
else {
int icol = iinf[which].color;
displaystr(vid.xres/2, vid.fsize*2, 2, vid.fsize*2, XLAT1(iinf[which].name), icol, 8);
auto oi = getOrbInfo(which);
if(mirroring)
displaystr(vid.xres/2, vid.fsize*4, 2, vid.fsize, usedup[which] >= TESTMIRRORED ? XLAT("already mirrored") : XLAT("Uses to gain: %1", its(mirrorqty(which))), icol, 8);
else {
eItem t = treasureType(oi.l);
string s = XLAT("Unlocked by: %1 in %2", t, oi.l);
if(next[t].min == next[t].max)
s += XLAT(" (next at %1)", its(next[t].min));
else
s += XLAT(" (next at %1 to %2)", its(next[t].min), its(next[t].max));
displaystr(vid.xres/2, vid.fsize*4, 2, vid.fsize, s, icol, 8);
whichorbinfo = which;
compute();
string extras = "";
for(int k=0; k<ORBLINES; k++) {
auto oi = orbinfos[k];
if(oi.gchance || oi.orb != which) continue;
eItem it = treasureType(oi.l);
extras += extraline(it, "10");
}
if(which == itOrbMirror) {
extras += extraline(itOrbYendor, its(nextp2(items[itOrbYendor])));
extras += extraline(itHolyGrail, its(nextp2(items[itHolyGrail])));
auto& nx = next[itHyperstone];
extras += extraline(itHyperstone, its(nx.min));
}
if(isIn(which, offensiveOrbs)) extras += extraline(itBone, its(items[itBone]/25*25+25) + "?");
if(isIn(which, elementalOrbs)) extras += extraline(itElemental, its(items[itBone]/20*20+20) + "?");
if(isIn(which, demonicOrbs)) extras += extraline(itHell, its(max(125, items[itHell]/25*25+25)) + "?");
for(auto& a: lateextraorbs) if(a.orb == which)
extras += extraline(a.treasure, items[a.treasure] >= a.at ? (its(a.at)+"!") : "10-50");
if(extras != "")
displaystr(vid.xres/2, vid.fsize*5, 2, vid.fsize, XLAT("Extras:")+extras, icol, 8);
displaystr(vid.xres/2, vid.fsize*4, 2, vid.fsize, orbinfoline, icol, 8);
if(extra != "")
displaystr(vid.xres/2, vid.fsize*5, 2, vid.fsize, XLAT("Extras:")+extra, icol, 8);
}
if(remaining[which] != 1 || usedup[which]) {
string s = XLAT("Number of uses left: %1", its(remaining[which]));
int us = usedup[which];
if(us >= TESTMIRRORED) s += XLAT(" (mirrored)"), us = us - MIRRORED + mirrorqty0(which);
if(us) s += XLAT(" (used %1 times)", its(us));
displaystr(vid.xres/2, vid.yres - vid.fsize*6, 2, vid.fsize, s, icol, 8);
displaystr(vid.xres/2, vid.yres - vid.fsize*6, 2, vid.fsize, osminfo(which), icol, 8);
}
#if ISMOBILE==0
string hot = XLAT1("Hotkey: "); hot += getcstat;
displaystr(vid.xres/2, vid.yres - vid.fsize*5, 2, vid.fsize, hot, icol, 8);
#endif
eOrbLandRelation olr = getOLR(oi.orb, getPrizeLand());
eItem tr = treasureType(oi.l);
eOrbLandRelation olr = getOLR(which, getPrizeLand());
int col = 0;
if(olr == olrDangerous) col = 0xC00000;
@ -462,7 +529,7 @@ namespace inv {
if(olr == olrForbidden) col = 0x804000;
if(col)
displaystr(vid.xres/2, vid.yres - vid.fsize*4, 2, vid.fsize, XLAT(olrDescriptions[olr], cwt.c->land, tr, treasureType(cwt.c->land)), col, 8);
displaystr(vid.xres/2, vid.yres - vid.fsize*4, 2, vid.fsize, XLAT(olrDescriptions[olr], cwt.c->land, itNone, treasureType(cwt.c->land)), col, 8);
}
}

View File

@ -20,6 +20,28 @@ const char *dnameof(eLand l) { return linf[l].name; }
const char *dnameof(eWall w) { return winf[w].name; }
const char *dnameof(eItem i) { return iinf[i].name; }
/*
string dnameofEnum(eItem i) {
FILE *f = fopen("classes.cpp", "rt");
while(!feof(f)) {
char buf[256];
fgets(buf, 256, f);
if(strstr(buf, "eItem")) {
string ret;
int qty = i;
while(qty > -1) {
char c = fgetc(f);
if(c == ' ' || c == '\n' || c == '\r') continue;
else if(c == ',') qty--;
else if(!qty) ret += c;
}
return ret;
}
}
return "?";
}
*/
void rep(string& pattern, string what, string to) {
while(true) {
size_t at = pattern.find(what);

View File

@ -50,7 +50,7 @@ void showOverview() {
s += "@";
s += dnameof(treasureType(l));
s += "@";
s += dnameof(orbType(l));
s += dnameof(nativeOrbType(l));
if(mapeditor::hasInfix(s))
filteredLands[nlid++] = l;
}
@ -104,7 +104,7 @@ void showOverview() {
getcstat = 2000+it;
if(displayfrZ(xr*24+c8*5, i0, 1, vf-4, XLAT1(iinf[it].name), col, 0))
getcstat = 2000+it;
eItem io = orbType(l);
eItem io = nativeOrbType(l);
if(io == itShard) {
if(items[it] >= 10) col = winf[waMirror].color; else col = BLACKISH;
if(chaosmode && noChaos(l)) col = REDDISH;

View File

@ -1,86 +1,121 @@
#define ORBLINES 56
// 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);
// typical combinations
static const int S_NATIVE = LOCAL10 | CROSS10 | GLOBAL25 | NATIVE;
static const int S_GUEST = LOCAL10 | OSM_AT10;
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] = {
{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
{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_NATIVE, laIce, 1500, 0, itOrbWinter},
{orbgenflags::S_GUEST, laDragon, 2500, 0, itOrbWinter},
{orbgenflags::S_GUEST, laDryForest, 2500, 0, itOrbWinter},
{orbgenflags::S_NATIVE, laCocytus, 1500, 1500, 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, laWhirlpool, 0, 2000, itOrbWater},
};
eItem orbType(eLand l) {
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<ORBLINES; i++)
if(orbinfos[i].l == l && orbinfos[i].gchance)
if(orbinfos[i].l == l && orbinfos[i].is_native())
return orbinfos[i].orb;
return itNone;
}
const orbinfo& getOrbInfo(eItem orb) {
const orbinfo& getNativityOrbInfo(eItem orb) {
for(int i=0; i<ORBLINES; i++)
if(orbinfos[i].orb == orb && orbinfos[i].gchance)
if(orbinfos[i].orb == orb && orbinfos[i].is_native())
return orbinfos[i];
static orbinfo oi;
oi.l = laMirror;
@ -161,7 +196,7 @@ eOrbLandRelation getOLR(eItem it, eLand l) {
if(it == itOrbIllusion && l == laCamelot) return olrNative1;
if(it == itOrbLove) return olrNoPrizeOrb;
if(orbType(l) == it) return olrNative;
if(nativeOrbType(l) == it) return olrNative;
if(it == itOrbWinter && (l == laIce || l == laDryForest || l == laDragon))
return olrGuest;
if(it == itOrbLuck && l == laIvoryTower)
@ -346,9 +381,11 @@ void placePrizeOrb(cell *c) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
if(!(oi.flags & orbgenflags::GLOBAL25)) continue;
int mintreas = 25;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 100) ;
if(oi.flags & orbgenflags::OSM_GLOBAL100) mintreas = 100;
else continue;
}
@ -357,7 +394,7 @@ void placePrizeOrb(cell *c) {
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;
if(treas < mintreas) continue;
}
else continue;
@ -386,11 +423,8 @@ void placeLocalOrbs(cell *c) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
if(!(oi.flags & orbgenflags::LOCAL10)) continue;
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;
@ -398,7 +432,15 @@ void placeLocalOrbs(cell *c) {
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)) {
int tc = items[treasureType(oi.l)] * landMultiplier(oi.l);
int tcmin = (chaosmode ? 1+hrand(10) : 10);
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;
@ -415,21 +457,27 @@ void placeCrossroadOrbs(cell *c) {
if(peace::on) return;
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
if(!(oi.flags & orbgenflags::CROSS10)) continue;
if(!oi.gchance) continue;
int treas = items[treasureType(oi.l)] * landMultiplier(oi.l);
int mintreas = 10;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 50) ;
else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ;
if(oi.flags & orbgenflags::OSM_CROSS25)
mintreas = 25;
else if(oi.flags & orbgenflags::OSM_CROSS50)
mintreas = 50;
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)
if(tactic::on) {
if(isCrossroads(tactic::lasttactic) && (oi.flags & orbgenflags::NO_TACTIC))
continue;
else mintreas = 0;
}
else {
if(treas < 10) continue;
}
if(treas < mintreas) continue;
if(oi.orb == itOrbSafety && c->land == laCrossroads5) continue;
int mul = c->land == laCrossroads5 ? 10 : 1;
int gch = oi.gchance;
@ -445,14 +493,20 @@ void placeOceanOrbs(cell *c) {
if(peace::on) return;
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
if(!(oi.flags & orbgenflags::CROSS10)) continue;
int treas = items[treasureType(oi.l)] * landMultiplier(oi.l);
int mintreas = 10;
if(inv::on) {
if(oi.orb == itOrbYendor && items[itHell] >= 50) ;
else if(oi.orb == itOrbSafety && items[itFeather] >= 25) ;
if(oi.flags & orbgenflags::OSM_CROSS25)
mintreas = 25;
else if(oi.flags & orbgenflags::OSM_CROSS50)
mintreas = 50;
else continue;
}
if(items[treasureType(oi.l)] * landMultiplier(oi.l) < 10) continue;
if(treas < mintreas) continue;
if(!oi.gchance) continue;
if(oi.orb == itOrbLife) continue; // useless
if(hrand(oi.gchance) >= 20) continue;