// Hyperbolic Rogue // Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // routines for: initializing/closing, loading/saving, and cheating bool cblind; bool autocheat; int truelotus; time_t timerstart, savetime; bool timerstopped; int savecount; bool showoff = false; // initialize the game void initgame() { DEBB(DF_INIT, (debugfile,"initGame\n")); yendor::init(1); if(safety && safetyseed) { shrand(safetyseed); firstland = safetyland; } if(tactic::on && euclid) euclidland = firstland; if(firstland == laNone || firstland == laBarrier) firstland = laCrossroads; if(firstland == laOceanWall) firstland = laOcean; if(firstland == laHauntedWall) firstland = laGraveyard; if(isGravityLand(firstland) && !tactic::on) firstland = laCrossroads; cwt.c = origin.c7; cwt.spin = 0; cwt.c->land = euclid ? euclidland : firstland; chaosAchieved = false; if(firstland == laElementalWall) cwt.c->land = randomElementalLand(); if(tactic::on && (isGravityLand(firstland) || firstland == laOcean)) cwt.c->land = purehepta ? laCrossroads : laCrossroads2; createMov(cwt.c, 0); setdist(cwt.c, BARLEV, NULL); if((tactic::on || yendor::on) && isCyclic(firstland)) { anthraxBonus = items[itHolyGrail]; cwt.c->mov[0]->land = firstland; if(firstland == laWhirlpool) cwt.c->mov[0]->wall = waSea; setdist(cwt.c->mov[0], BARLEV-1, cwt.c); heptagon *h = createAlternateMap(cwt.c, 2, hsA); if(!h) printf("FAIL\n"); } if(tactic::on && firstland == laPower) { items[itOrbSpeed] = 30; items[itOrbWinter] = 30; items[itOrbFlash] = 30; } if(tactic::on && firstland == laCaribbean) { if(hiitemsMax(itRedGem) >= 25) items[itRedGem] = 25; if(hiitemsMax(itFernFlower) >= 25) items[itFernFlower] = 25; if(hiitemsMax(itWine) >= 25) items[itWine] = 25; } if(tactic::on && tactic::trailer) items[treasureType(firstland)] = 5; tactic::lasttactic = firstland; yendor::lastchallenge = yendor::challenge; yendor::init(2); for(int i=0; i<65536; i++) euland[i] = laNone; if(euclid && euclidland == laPrincessQuest) { cell *c = euclideanAtCreate(EPX, EPY); princess::generating = true; c->land = laPalace; for(int j=BARLEV; j>=0; j--) setdist(c, j, NULL); princess::generating = false; } if(cwt.c->land == laCrossroads2) { cwt.c->landparam = 12; createMov(cwt.c, 0)->landparam = 44; } // extern int sightrange; sightrange = 9; // cwt.c->land = laHell; items[itHell] = 10; for(int i=BARLEV; i>=0; i--) { if(tactic::trailer) safety = true; setdist(cwt.c, i, NULL); if(tactic::trailer) safety = false; verifycells(&origin); } if(tactic::on && tactic::trailer) items[treasureType(firstland)] = 15; yendor::init(3); makeEmpty(cwt.c); if(shmup::on) shmup::init(); if(!safety) { usedSafety = false; timerstart = time(NULL); turncount = 0; rosewave = 0; rosephase = 0; mapeditor::whichPattern = 0; mapeditor::whichShape = 0; noiseuntil = 0; sagephase = 0; hardcoreAt = 0; timerstopped = false; savecount = 0; savetime = 0; cheater = 0; if(autocheat) cheater = 1; hauntedWarning = false; timerghost = true; truelotus = 0; survivalist = true; if(!randomPatternsMode && !tactic::on && !yendor::on) { if(firstland != (princess::challenge ? laPalace : laIce)) cheater++; } if(princess::challenge) { kills[moVizier] = 1; princess::forceMouse = true; if(yendor::everwon) items[itGreenStone] = 99; addMessage(XLAT("Welcome to %the1 Challenge!", moPrincess)); addMessage(XLAT("The more Hypersian Rugs you collect, the harder it is.", moPrincess)); } /* if(tactic::on && isCrossroads(firstland)) { for(int i=0; iland, "current land"); else if(loading) firstland = safetyland = eLand(applyBoxLoad()); else lostin = eLand(savebox[boxid++]); for(int i=itOrbLightning; i<25; i++) applyBoxI(eItem(i), true); applyBoxI(itRoyalJelly); applyBoxI(itWine); applyBoxI(itSilver); applyBoxI(itEmerald); applyBoxI(itPower); applyBoxI(itOrbFire, true); applyBoxI(itOrbInvis, true); applyBoxI(itOrbGhost, true); applyBoxI(itOrbPsi, true); applyBoxM(moBug0); applyBoxM(moBug1); applyBoxM(moBug2); applyBoxM(moVineBeast); applyBoxM(moVineSpirit); applyBoxM(moLancer); applyBoxM(moFlailer); applyBoxM(moEarthElemental); applyBoxM(moDarkTroll); applyBoxM(moWitch); applyBoxM(moWitchFire); applyBoxM(moWitchFlash); applyBoxM(moWitchGhost); applyBoxM(moWitchSpeed); applyBoxM(moEvilGolem); applyBoxM(moWitchWinter); applyBoxI(itHolyGrail); applyBoxI(itGrimoire); applyBoxM(moKnight); applyBoxM(moCultistLeader); applyBoxM(moPirate); applyBoxM(moCShark); applyBoxM(moParrot); applyBoxI(itPirate); applyBoxI(itOrbPreserve, true); applyBoxM(moHexSnake); applyBoxM(moRedTroll); applyBoxI(itRedGem); applyBoxI(itOrbTelekinesis, true); applyBoxBool(euclid, "Euclidean"); applyBoxBool(hardcore, "hardcore"); applyBoxNum(hardcoreAt, "hardcoreAt"); applyBoxBool(shmup::on, "shmup"); if(saving) applyBoxSave(euclidland, "euclid land"); else if(loading) euclidland = eLand(applyBoxLoad("euclid land")); else boxid++; applyBoxI(itCoast); applyBoxI(itWhirlpool); applyBoxI(itBombEgg); applyBoxM(moBomberbird); applyBoxM(moTameBomberbird); applyBoxM(moAlbatross); applyBoxI(itOrbFriend, true); applyBoxI(itOrbAir, true); applyBoxI(itOrbWater, true); applyBoxI(itPalace); applyBoxI(itFjord); applyBoxI(itOrbFrog); applyBoxI(itOrbDiscord); applyBoxM(moPalace); applyBoxM(moFatGuard); applyBoxM(moSkeleton); applyBoxM(moVizier); applyBoxM(moViking); applyBoxM(moFjordTroll); applyBoxM(moWaterElemental); applyBoxI(itSavedPrincess); applyBoxI(itOrbLove); applyBoxM(moPrincess); applyBoxM(moPrincessMoved); // live Princess for Safety applyBoxM(moPrincessArmedMoved); // live Princess for Safety applyBoxM(moMouse); applyBoxNum(princess::saveArmedHP, "save armed HP"); applyBoxNum(princess::saveHP, "save HP"); applyBoxI(itEdge); applyBoxI(itElemental); applyBoxI(itZebra); applyBoxI(itFireShard); applyBoxI(itWaterShard); applyBoxI(itAirShard); applyBoxI(itEarthShard); applyBoxM(moAirElemental); applyBoxM(moFireElemental); applyBoxM(moEdgeMonkey); applyBoxM(moGargoyle); applyBoxM(moOrangeDog); applyBoxI(itOrbSummon); applyBoxI(itOrbMatter); applyBoxM(moForestTroll); applyBoxM(moStormTroll); applyBoxM(moOutlaw); applyBoxM(moMutant); applyBoxM(moMetalBeast); applyBoxM(moMetalBeast2); applyBoxI(itMutant); applyBoxI(itFulgurite); applyBoxI(itBounty); applyBoxI(itOrbLuck); applyBoxI(itOrbStunning, true); applyBoxBool(tactic::on, "tactic ON"); applyBoxNum(elec::lightningfast, "lightningfast"); // if(savebox[boxid]) printf("lotus = %d (lost = %d)\n", savebox[boxid], isHaunted(lostin)); if(loadingHi && isHaunted(lostin)) boxid++; else applyBoxI(itLotus); applyBoxI(itOrbUndeath, true); applyBoxI(itWindstone); applyBoxI(itOrbEmpathy, true); applyBoxM(moWindCrow); applyBoxI(itMutant2); applyBoxI(itOrbFreedom, true); applyBoxM(moRedFox); applyBoxBool(survivalist); if(loadingHi) applyBoxI(itLotus); else applyBoxNum(truelotus, "lotus/escape"); applyBoxBool(purehepta, "heptagons only"); applyBoxI(itRose); applyBoxI(itOrbSkunk, true); applyBoxI(itCoral); applyBoxI(itOrb37, true); applyBoxI(itOrbEnergy, true); applyBoxM(moRatling); applyBoxM(moFalsePrincess); applyBoxM(moRoseLady); applyBoxM(moRoseBeauty); applyBoxBool(chaosmode, "Chaos mode"); applyBoxNum(shmup::players, "shmup players"); applyBoxM(moRatlingAvenger); // printf("applybox %d\n", shmup::players); applyBoxI(itApple); applyBoxM(moKestrel); applyBoxM(moLemur); applyBoxI(itDragon); applyBoxM(moDragonHead); applyBoxI(itOrbDomination, true); applyBoxI(itBabyTortoise); applyBoxNum(tortoise::seekbits, "tortoise bits"); applyBoxM(moTortoise); applyBoxI(itOrbShell, true); applyBoxNum(safetyseed); } void saveBox() { boxid = 0; saving = true; applyBoxes(); saving = false; } void loadBox() { // have boxid boxid = 0; loading = true; applyBoxes(); loading = false; } void loadBoxHigh() { int sp = shmup::players; int son = shmup::on; bool euc = euclid; bool cha = chaosmode; bool ph = purehepta; euclid = savebox[116]; shmup::on = savebox[119]; purehepta = savebox[186]; chaosmode = savebox[196]; shmup::players = savebox[197]; if(shmup::on && !shmup::players) ; else { // have boxid boxid = 0; loadingHi = true; applyBoxes(); loadingHi = false; } purehepta = ph; chaosmode = cha; euclid = euc; shmup::on = son; shmup::players = sp; } // certify that saves and achievements were received // in an official version of HyperRogue #ifdef CERTIFY #include "certify.cpp" #else namespace anticheat { bool tampered; void save(FILE *f) {} bool load(FILE *f, score& sc, const string& ver) {return true; } int certify(const string& s, int a, int b, int c, int d=0) { return d; } int check(int cv, const string& ver, const string& s, int a, int b, int c, int d=0) { return cv==d; } void nextid(int& tid, const string& ver, int cert) { tid++; } }; #endif long long saveposition = -1; void saveStats(bool emergency = false) { DEBB(DF_INIT, (debugfile,"saveStats [%s]\n", scorefile)); #ifndef ANDROID if(randomPatternsMode) return; FILE *f = fopen(scorefile, "at"); if(!f) { // printf("Could not open the score file '%s'!\n", scorefile); addMessage(XLAT("Could not open the score file: ") + scorefile); return; } if(saveposition >= 0) { // addMessage(XLAT("Emergency seek to ") + its(saveposition)); fseek(f, saveposition, SEEK_SET); saveposition = -1; } if(emergency) { saveposition = ftell(f); // addMessage(XLAT("Emergency save at ") + its(saveposition)); } if(showoff) return; time_t timer; timer = time(NULL); char sbuf[128]; strftime(sbuf, 128, "%c", localtime(&timerstart)); char buf[128]; strftime(buf, 128, "%c", localtime(&timer)); if((tactic::on || yendor::on) && !items[itOrbSafety] && !cheater) { int t = (int) (timer - timerstart); int xcode = modecode(); if(tactic::on) { int score = items[treasureType(tactic::lasttactic)]; if(score) { int c = anticheat::certify(dnameof(tactic::lasttactic), turncount, t, (int) timerstart, xcode*999 + tactic::id + 256 * score); fprintf(f, "TACTICS %s %d %d %d %d %d %d %d date: %s\n", VER, tactic::id, tactic::lasttactic, score, turncount, t, int(timerstart), c, buf); tactic::record(tactic::lasttactic, score); anticheat::nextid(tactic::id, VER, c); } } if(yendor::on) fprintf(f, "YENDOR %s %d %d %d %d %d %d %d date: %s\n", VER, yendor::lastchallenge, items[itOrbYendor], yendor::won, turncount, t, int(timerstart), anticheat::certify(yendor::won ? "WON" : "LOST", turncount, t, (int) timerstart, xcode*999 + yendor::lastchallenge + 256 * items[itOrbYendor]), buf); fclose(f); return; } fprintf(f, "HyperRogue: game statistics (version " VER ")\n"); if(cheater) fprintf(f, "CHEATER! (cheated %d times)\n", cheater); if(true) { fprintf(f, VER); if(!shmup::on) items[itOrbLife] = countMyGolems(moGolem); if(!shmup::on) items[itOrbFriend] = countMyGolems(moTameBomberbird); if(!shmup::on) kills[moPrincessMoved] = countMyGolems(moPrincess); if(!shmup::on) kills[moPrincessArmedMoved] = countMyGolems(moPrincessArmed); if(!shmup::on) princess::saveHP = countMyGolemsHP(moPrincess); if(!shmup::on) princess::saveArmedHP = countMyGolemsHP(moPrincessArmed); saveBox(); for(int i=0; i 0 && cid < YENDORLEVELS) if(!(ver < string("8.0f") && oy > 1 && cid == 15)) { yendor::bestscore[xc][cid] = max(yendor::bestscore[xc][cid], oy); } } } } fclose(f); if(ok && sc.box[65 + 4 + itOrbSafety - itOrbLightning]) { anticheat::tampered = tamper; // printf("box = %d (%d)\n", sc.box[65 + 4 + itOrbSafety - itOrbLightning], boxid); // printf("boxid = %d\n", boxid); for(int i=0; iland)) q -= 5; if(q < bq) bq = q, cq = 0; if(q == bq) { cq++; if(hrand(cq) == 0) best = i; } } return best; } bool isTechnicalLand(eLand l) { return l == laNone || l == laOceanWall || l == laBarrier || l == laCanvas || l == laHauntedWall || l == laHauntedBorder; } bool applyCheat(char u, cell *c = NULL) { if(u == 'M' && cwt.c->type == 6) { addMessage(XLAT("You summon some Mirages!")); cheater++; mirror::createMirrors(cwt.c, cwt.spin, moMirage), mirror::createMirages(cwt.c, cwt.spin, moMirage); return true; } if(u == 'G') { addMessage(XLAT("You summon a golem!")); cheater++; int i = cwt.spin; if(passable(cwt.c->mov[i], NULL, 0)) cwt.c->mov[i]->monst = hrand(2) ? moGolem : moTameBomberbird; return true; } if(u == 'L') { do { if(firstland == eLand(landtypes-1)) firstland = eLand(2); else firstland = eLand(firstland+1); } while(isTechnicalLand(firstland) || isCyclic(firstland)); euclidland = firstland; cheater++; addMessage(XLAT("You will now start your games in %1", firstland)); return true; } if(u == 'C') { cheater++; activateSafety(laCrossroads); addMessage(XLAT("Activated the Hyperstone Quest!")); for(int t=1; ttype; i++) if(passable(cwt.c->mov[i], NULL, 0)) { eItem it = nextOrb(); cwt.c->mov[i]->item = it; } return true; } if(u == 'F') { if(hardcore && !canmove) { canmove = true; addMessage(XLAT("Revived!")); } else { items[itOrbFlash] += 1; items[itOrbTeleport] += 1; items[itOrbLightning] += 1; items[itOrbSpeed] += 1; items[itOrbShield] += 1; cheater++; addMessage(XLAT("Orb power gained!")); canmove = true; if(cmode == emQuit) cmode = emNormal; } return true; } if(u == 'D') { items[itGreenStone] += 10; cheater++; addMessage(XLAT("Dead orbs gained!")); return true; } if(u == 'R'-64) buildRosemap(); if(u == 'D'-64) { mapeditor::drawplayer = !mapeditor::drawplayer; return true; } #ifndef MOBILE if(u == 'A') { lastexplore = turncount; cmode = emMapEditor; return true; } if(u == 'A'-64) { mapeditor::drawcell = mouseover ? mouseover : cwt.c; cmode = emDraw; return true; } #endif if(u == 'Y') { items[itOrbYendor] ++; cheater++; addMessage(XLAT("Orb of Yendor gained!")); return true; } if(u == 'T') { items[randomTreasure2(10)] += 10; cheater++; addMessage(XLAT("Treasure gained!")); return true; } if(u == 'T'-64) { items[randomTreasure2(100)] += 100; cheater++; addMessage(XLAT("Lots of treasure gained!")); return true; } if(u == 'I'-64) { items[randomTreasure2(10)] += 25; cheater++; addMessage(XLAT("Treasure gained!")); return true; } if(u == 'U'-64) { items[randomTreasure2(10)] += 50; cheater++; addMessage(XLAT("Treasure gained!")); return true; } if(u == 'W') { addMessage(XLAT("You summon a sandworm!")); cheater++; int i = cwt.spin; if(passable(cwt.c->mov[i], NULL, 0)) cwt.c->mov[i]->monst = moWorm, cwt.c->mov[i]->mondir = NODIR; return true; } if(u == 'I') { addMessage(XLAT("You summon an Ivy!")); cheater++; int i = cwt.spin; int j = cwt.c->spn[i]; cell* c = cwt.c->mov[i]->mov[(j+3)%cwt.c->mov[i]->type]; if(passable(c, NULL, 0)) buildIvy(c, 0, 1); return true; } if(u == 'E') { addMessage(XLAT("You summon a monster!")); cheater++; int i = cwt.spin; if(cwt.c->mov[i]->wall == waChasm) cwt.c->mov[i]->wall = waNone; if(passable(cwt.c->mov[i], NULL, P_MONSTER)) { eMonster mo[9] = { moEagle, moPyroCultist, moGhost, moTroll, moMiner, moVineBeast, moBug0, moBomberbird, moSkeleton }; cwt.c->mov[i]->monst = mo[hrand(9)]; cwt.c->mov[i]->stuntime = 3; cwt.c->mov[i]->hitpoints = 3; } return true; } if(u == 'E'-64) { addMessage(XLAT("You summon many monsters!")); cheater++; for(int i=0; itype; i++) { cell *c2 = cwt.c->mov[i]; if(passable(c2, NULL, P_MONSTER)) { eMonster mo[2] = { moRedTroll, moDarkTroll }; c2->monst = mo[hrand(2)]; } } return true; } if(u == 'H') { addMessage(XLAT("You summon some Thumpers!")); cheater++; for(int i=0; itype; i++) if(passable(cwt.c->mov[i], NULL, 0)) { eWall ws[3] = { waThumperOff, waBigStatue, waBoat }; cwt.c->mov[i]->wall = ws[hrand(3)]; } return true; } if(u == 'B') { addMessage(XLAT("You summon a bonfire!")); cheater++; int i = cwt.spin; if(passable(cwt.c->mov[i], NULL, 0)) cwt.c->mov[i]->wall = waBonfireOff; return true; } if(u == 'Z') { cwt.spin++; flipplayer = false; cwt.spin %= cwt.c->type; return true; } if(u == 'J') { if(items[localTreasureType()] > 0) items[localTreasureType()] = 0; else for(int i=1; iland); items[itOrbSafety] += 3; cheater++; addMessage(XLAT("Activated Orb of Safety!")); return true; } if(u == 'U') { canmove = true; activateSafety(firstland); cheater++; addMessage(XLAT("Teleported to %1!", firstland)); return true; } if(u == 'W'-64) { webdisplay++; cheater++; addMessage(XLAT("Cheat-changed the display.", firstland)); return true; } if(u == 'G'-64) { timerghost = !timerghost; cheater++; addMessage(XLAT("turn count = %1 last exploration = %2 ghost timer = %3", its(turncount), its(lastexplore), ONOFF(timerghost))); return true; } if(u == 'F'-64) { items[itOrbShield] += 30; return true; } if(u == 'Y'-64) { int i = cwt.spin; cwt.c->mov[i]->item = itOrbYendor; return true; } if(u == 'X'-64) { items[itEdge] = 12345; cheater++; return true; } if(u == 'C'-64) { cblind = !cblind; return true; } return false; }