diff --git a/achievement.cpp b/achievement.cpp index 9e4f4caf..b616b5fc 100644 --- a/achievement.cpp +++ b/achievement.cpp @@ -83,6 +83,7 @@ bool wrongMode(char flags) { if(shmup::on != (flags == 's')) return true; if(randomPatternsMode) return true; if(yendor::on) return true; + if(peace::on) return true; if(tactic::on) return true; #ifdef TOUR if(tour::on) return true; @@ -94,7 +95,7 @@ bool wrongMode(char flags) { void achievement_log(const char* s, char flags) { -#ifdef LOCAL +#ifdef PRINT_ACHIEVEMENTS printf("achievement = %s [%d]\n", s, wrongMode(flags)); #endif @@ -124,7 +125,7 @@ void achievement_log(const char* s, char flags) { #ifdef STEAM void improveItemScores(); -#include "hypersteam.cpp" +#include "private/hypersteam.cpp" #else #ifndef ANDROID #ifndef IOS @@ -525,6 +526,17 @@ void achievement_final(bool really_final) { if(tour::on) return; #endif + if(randomPatternsMode) return; + if(peace::on) return; + if(yendor::on) return; + + if(tactic::on) { + tactic::record(); + tactic::unrecord(); + tactic::uploadScore(); + return; + } + if(sphere && euclidland == laHalloween) { if(shmup::on || chaosmode || purehepta || numplayers() > 1 || tactic::on || randomPatternsMode) return; @@ -534,16 +546,7 @@ void achievement_final(bool really_final) { if(euclid) return; if(sphere) return; if(elliptic) return; - if(randomPatternsMode) return; - - if(tactic::on) { - tactic::record(); - tactic::unrecord(); - tactic::uploadScore(); - return; - } - if(yendor::on) return; // no leaderboards for two special modes at once int specials = 0; @@ -610,6 +613,7 @@ void achievement_victory(bool hyper) { if(randomPatternsMode) return; if(hyper && shmup::on) return; if(yendor::on) return; + if(peace::on) return; if(tactic::on) return; if(chaosmode) return; DEBB(DF_STEAM, (debugfile,"after checks\n")) diff --git a/cell.cpp b/cell.cpp index 3032e195..4e3a5872 100644 --- a/cell.cpp +++ b/cell.cpp @@ -72,20 +72,14 @@ struct celllister { vector tmps; vector dists; - bool listed(cell *c) { - return c->aitmp >= 0 && c->aitmp < size(lst) && lst[c->aitmp] == c; - } - void add(cell *c, int d) { - if(listed(c)) return; - c->aitmp = size(lst); + if(eq(c->aitmp, sval)) return; + c->aitmp = sval; tmps.push_back(c->aitmp); lst.push_back(c); dists.push_back(d); } - int getdist(cell *c) { return dists[c->aitmp]; } - ~celllister() { for(int i=0; iaitmp = tmps[i]; } @@ -94,6 +88,7 @@ struct celllister { lst.clear(); tmps.clear(); dists.clear(); + sval++; add(orig, 0); cell *last = orig; for(int i=0; iaitmp = i; + } + + int getdist(cell *c) { return dists[c->aitmp]; } + + bool listed(cell *c) { + return c->aitmp >= 0 && c->aitmp < size(lst) && lst[c->aitmp] == c; + } + }; // -- hrmap --- diff --git a/classes.cpp b/classes.cpp index c5bf6df4..b865e9bc 100644 --- a/classes.cpp +++ b/classes.cpp @@ -767,7 +767,7 @@ genderswitch_t genderswitch[NUM_GS] = { // --- items --- -const int ittypes = 110; +const int ittypes = 111; struct itemtype { char glyph; @@ -1152,6 +1152,7 @@ itemtype iinf[ittypes] = { "You get the powers of Shield, Horns, and Thorns after you move two moves in a straight line " "with this Orb." }, { '$', 0xC060C0, "Spinel", bulldashdesc }, + { 'o', 0xC0C0FF, "Orb of the Mirror", NODESCYET }, }; enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue, @@ -1181,22 +1182,15 @@ enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBo itWindstone, itOrbEmpathy, itStrongWind, itBuggy, itBuggy2, itRose, itCoral, itOrbBeauty, itOrb37, itOrbEnergy, itBabyTortoise, itOrbShell, itApple, itDragon, itOrbDomination, - itOrbSword, - itKraken, itOrbSword2, itBarrow, - itTrollEgg, itWarning, - itOrbStone, itOrbNature, itTreat, - itSlime, itAmethyst, - itOrbRecall, itDodeca, - itOrbDash, - itGreenGrass, - itOrbHorns, - itOrbBull, - itBull + itOrbSword, itKraken, itOrbSword2, itBarrow, + itTrollEgg, itWarning, itOrbStone, itOrbNature, itTreat, + itSlime, itAmethyst, itOrbRecall, itDodeca, itOrbDash, itGreenGrass, itOrbHorns, + itOrbBull, itBull, itOrbMirror }; // --- wall types --- -const int walltypes = 96; +const int walltypes = 97; struct walltype { char glyph; @@ -1375,6 +1369,7 @@ walltype winf[walltypes] = { "Bushes block the movement of birds."}, { '.', 0xFFFF00, "Reptile floor", reptiledesc}, { '.', 0xFFFF00, "Reptile bridge", reptiledesc}, + { '.', 0xFFFF00, "invisible floor", NODESCYET}, }; enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune, @@ -1402,7 +1397,8 @@ enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCav waBarrowWall, waBarrowDig, waPetrified, waTower, waBigBush, waSmallBush, - waReptile, waReptileBridge + waReptile, waReptileBridge, + waInvisibleFloor }; // --- land types --- @@ -1782,3 +1778,24 @@ eLand randlands[RANDLANDS] = { laOvergrown, laWildWest, laWarpCoast }; +// land completion for shared unlocking +#define U5 (inv::on ? 10 : 5) +// land completion for advanced unlocking +#define U10 (inv::on ? 25 : 10) + +// land completion +#define R10 (inv::on ? 50 : 10) +// intermediate lands +#define R30 (inv::on ? 100 : 30) +// advanced lands +#define R60 (inv::on ? 200 : 60) +// advanced lands II +#define R90 (inv::on ? 300 : 90) +// Crossroads IV +#define R200 (inv::on ? 800 : 200) +// Crossroads V +#define R300 (inv::on ? 1200 : 300) +// kill types for Dragon Chasms +#define R20 (inv::on ? 30 : 20) +// kill count for Graveyard/Hive +#define R100 (inv::on ? 500 : 100) diff --git a/complex.cpp b/complex.cpp index ef45df5f..60f5143b 100644 --- a/complex.cpp +++ b/complex.cpp @@ -1853,7 +1853,7 @@ void livecaves() { if(c->mov[j]->wall == waThumperOn) c->aitmp+=100; if(c->mov[j]->wall == waFire) c->aitmp+=100; if(c->mov[j]->wall == waBigStatue) c->aitmp-=100; - if(c->mov[j]->item) c->aitmp+=2; + if(c->mov[j]->item && !peace::on) c->aitmp+=2; if(c->mov[j]->monst == moZombie) c->aitmp += 10; if(c->mov[j]->monst == moGhost) c->aitmp += 10; if(c->mov[j]->monst == moTentacleGhost) c->aitmp += 10; @@ -2024,7 +2024,7 @@ namespace tortoise { void updateVals(int delta) { int currbits = getBits(cwt.c); for(int i=0; i geom3::middetail) geom3::highdetail = geom3::middetail; - if(lastmode == em3D) buildpolys(), resetGL(); + if(lastmode == em3D) buildpolys(); +#ifdef GL + if(lastmode == em3D) resetGL(); +#endif } void drawNumberDialog() { @@ -663,6 +667,9 @@ namespace dialog { if(ne.editwhat == &ne.intbuf && ne.intval == &sightrange && cheater) addBoolItem("overgenerate", overgenerate, 'o'); + if(ne.editwhat == &vid.linewidth) + addBoolItem("finer lines at the boundary", vid.antialias & AA_LINEWIDTH, 'o'); + display(); } @@ -710,6 +717,8 @@ namespace dialog { } else if(uni == 'o' && ne.editwhat == &ne.intbuf && ne.intval == &sightrange && cheater) overgenerate = !overgenerate; + else if(uni == 'o' && ne.editwhat == &vid.linewidth) + vid.antialias ^= AA_LINEWIDTH; else if(uni == 'p' && ne.editwhat == &vid.alpha) { *ne.editwhat = 1; vid.scale = 1; ne.s = "1"; } diff --git a/fake-mobile.cpp b/fake-mobile.cpp index e0b9a9e3..ae685ec2 100644 --- a/fake-mobile.cpp +++ b/fake-mobile.cpp @@ -213,7 +213,7 @@ int main(int argc, char **argv) { items[itGreenStone] = 100; } action = sym; */ - extra ex; + eventtype ex; mousing = false; handlekey(sym, sym, ex); } diff --git a/flags.cpp b/flags.cpp index 7513aa67..5a6a2f72 100644 --- a/flags.cpp +++ b/flags.cpp @@ -314,7 +314,7 @@ bool isWall(cell *w) { w->wall == waLadder || w->wall == waTrunk || w->wall == waSolidBranch || w->wall == waWeakBranch || w->wall == waCanopy || w->wall == waTower || w->wall == waSmallBush || w->wall == waBigBush || - w->wall == waReptile || w->wall == waReptileBridge) + w->wall == waReptile || w->wall == waReptileBridge || w->wall == waInvisibleFloor) return false; if(isWatery(w) || isChasmy(w) || isFire(w)) return false; return true; @@ -641,7 +641,7 @@ bool highwall(cell *c) { } int chasmgraph(cell *c) { - if(c->wall == waChasm) return 2; + if(c->wall == waChasm || c->wall == waInvisibleFloor) return 2; if(isChasmy(c)) return 1; if(isWateryOrBoat(c)) return 1; if(wmescher && c->wall == waBarrier && c->land == laOceanWall) return 1; diff --git a/game.cpp b/game.cpp index 833397ec..afdffc5a 100644 --- a/game.cpp +++ b/game.cpp @@ -687,7 +687,7 @@ bool sharkpassable(cell *w, cell *c) { bool canPushStatueOn(cell *c) { return passable(c, NULL, P_MONSTER) && c->wall != waBoat && !snakelevel(c) && - !isWorm(c->monst) && !isReptile(c->wall); + !isWorm(c->monst) && !isReptile(c->wall) && !peace::on; } void moveBoat(cell *to, cell *from) { @@ -844,6 +844,8 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) { if(!m2) return false; + if(m2 == moPlayer && peace::on) return false; + if((flags & AF_ONLY_FRIEND) && m2 != moPlayer && !isFriendly(c2)) return false; if((flags & AF_ONLY_FBUG) && m2 != moPlayer && !isFriendlyOrBug(c2)) return false; if((flags & AF_ONLY_ENEMY) && (m2 == moPlayer || isFriendlyOrBug(c2))) return false; @@ -1214,7 +1216,9 @@ int monstersnear2() { } int monstersnear(cell *c, cell *nocount, eMonster who, cell *pushto, cell *comefrom) { - + + if(peace::on) return 0; // you are safe + stalemate1 sm(who, c, nocount, pushto, comefrom); if(who == moPlayer) for(int b=0; b<2; b++) sm.swordlast[b] = sword::pos(multi::cpid, b); @@ -2055,7 +2059,7 @@ void fightmessage(eMonster victim, eMonster attacker, bool stun, int flags) { else addMessage(XLAT("You pierce %the1.", victim)); // normal } - else { + else if(!peace::on) { playSound(NULL, "hit-sword"+pick123()); addMessage(XLAT("You kill %the1.", victim)); // normal } @@ -2133,6 +2137,8 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) { else killMonster(c, killer, flags); + if(peace::on) return false; + int ntk = tkills(); int ntkt = killtypes(); @@ -2318,6 +2324,8 @@ void calcTidalPhase() { tidalphase = tide[ (shmup::on ? shmup::curtime/600 : turncount) % tidalsize]; + if(peace::on) + tidalphase = 5 + tidalphase / 6; } int tidespeed() { @@ -2587,7 +2595,7 @@ void bfs() { c2->cpdist = d+1; // remove treasures - if(c2->item && c2->cpdist == distlimit && itemclass(c2->item) == IC_TREASURE && + if(!peace::on && c2->item && c2->cpdist == distlimit && itemclass(c2->item) == IC_TREASURE && c2->item != itBabyTortoise && (items[c2->item] >= (chaosmode?10:20) + currentLocalTreasure || getGhostcount() >= 2)) { c2->item = itNone; @@ -2914,7 +2922,9 @@ void gainShard(cell *c2, const char *msg) { invismove = false; } -void playerMoveEffects(cell *c1, cell *c2) { +void playerMoveEffects(cell *c1, cell *c2) { + + if(peace::on) items[itOrbSword] = c2->land == laBurial ? 100 : 0; sword::angle[multi::cpid] = sword::shift(c1, c2, sword::angle[multi::cpid]); @@ -3276,7 +3286,7 @@ int moveval(cell *c1, cell *c2, int d, int mf) { else if(isFriendlyOrBug(c2)) return 500; else return 2000; } - if(isPlayerOn(c2)) return 2500; + if(isPlayerOn(c2)) return peace::on ? -1700 : 2500; else if(isFriendlyOrBug(c2)) return 2000; else return 500; } @@ -3338,7 +3348,7 @@ int moveval(cell *c1, cell *c2, int d, int mf) { if(m == moRagingBull && c1->mondir != NODIR) return 1500 - bulldist(c2); - if((mf & MF_PATHDIST) && c2->pathdist < c1->pathdist) return 1500; // good move + if((mf & MF_PATHDIST) && c2->pathdist < c1->pathdist && !peace::on) return 1500; // good move // prefer straight direction when wandering int dd = angledist(c1, c1->mondir, d); @@ -3369,6 +3379,8 @@ int stayval(cell *c, flagtype mf) { // Vikings move in a roughly straight line even if they cannot detect you if(c->monst == moViking && c->wall == waBoat) return 750; + // in peaceful, all monsters are wandering + if(peace::on && c->monst != moTortoise) return 750; if(isWorm(c->monst)) return 550; if(c->monst == moRagingBull) return -1690; // worse than to stay in place if(c->monst == moBat && batsAfraid(c)) return 575; @@ -3871,7 +3883,7 @@ void moveivy() { raiseBuggyGeneration(c, "wrong mondir!"); for(int j=0; jtype; j++) { if(c->mov[j] && canAttack(c, c->monst, c->mov[j], c->mov[j]->monst, AF_ONLY_FRIEND | AF_GETPLAYER)) { - if(isPlayerOn(c->mov[j])) + if(isPlayerOn(c->mov[j])) killThePlayerAt(c->monst, c->mov[j], 0); else { if(attackJustStuns(c->mov[j])) @@ -4033,7 +4045,7 @@ void groupmove(eMonster movtype, flagtype mf) { } } else { - for(int i=0; imonst; - if(m == moSleepBull) { + if(m == moSleepBull && !peace::on) { bool wakeup = false; forCellEx(c2, c) if(c2->monst == moGadfly) { addMessage(XLAT("%The1 wakes up %the2.", c2->monst, m)); @@ -4957,6 +4970,17 @@ void moverefresh(bool turn = true) { c->monst = moReptile; c->hitpoints = 3; c->stuntime = 0; + int gooddirs[7], qdirs = 0; + // in the peace mode, a reptile will + // prefer to walk on the ground, rather than the chasm + for(int i=0; itype; i++) { + int i0 = (i+3) % c->type; + int i1 = (i+c->type-3) % c->type; + if(c->mov[i0] && passable(c->mov[i0], c, 0)) + if(c->mov[i1] && passable(c->mov[i1], c, 0)) + gooddirs[qdirs++] = i; + } + if(qdirs) c->mondir = gooddirs[hrand(qdirs)]; playSound(c, "click"); } } @@ -5521,7 +5545,8 @@ void gainLife() { void collectMessage(cell *c2, eItem which) { bool specialmode = yendor::on || tactic::on || princess::challenge || euclid || sphere; - + + if(which == itDodeca && peace::on) return; if(which == itTreat) ; else if(isElementalShard(which)) { int tsh = @@ -5536,8 +5561,9 @@ void collectMessage(cell *c2, eItem which) { addMessage(t); } } - else if(which == itKey) + else if(which == itKey) { addMessage(XLAT("You have found the Key! Now unlock this Orb of Yendor!")); + } else if(which == itGreenStone && !items[itGreenStone]) addMessage(XLAT("This orb is dead...")); else if(which == itGreenStone) @@ -5632,6 +5658,7 @@ bool collectItem(cell *c2, bool telekinesis) { princess::forceVizier = true; if(!cantGetGrimoire(c2, false)) collectMessage(c2, c2->item); + if(c2->item == itDodeca) peace::simon::extend(); } if(isRevivalOrb(c2->item) && multi::revive_queue.size()) { @@ -5861,47 +5888,21 @@ bool collectItem(cell *c2, bool telekinesis) { playSound(c2, "pickup-orb"); items[c2->item] += 78; } + else if(c2->item == itOrbYendor && peace::on) { + if(!items[itDodeca]) { + addMessage(XLAT("Collect as many Dodecahedra as you can, then return here!")); + } + else { + addMessage(XLAT("Your score: %1", its(items[itDodeca]))); + peace::simon::restore(); + } + dopickup = false; + } else if(c2->item == itOrbYendor && yendor::state(c2) != yendor::ysUnlocked) { dopickup = false; } - else if(c2->item == itOrbYendor) { - playSound(c2, "tada"); - items[itOrbShield] += 31; - for(int i=0; i c(chaosmode, false); - yendor::bestscore[modecode()][yendor::challenge] = - max(yendor::bestscore[modecode()][yendor::challenge], items[itOrbYendor]); - yendor::uploadScore(); - } - } - addMessage(XLAT("CONGRATULATIONS!")); - achievement_collection(itOrbYendor, pg, gold()); - achievement_victory(false); - } + else if(c2->item == itOrbYendor) + yendor::collected(c2); else if(c2->item == itHolyGrail) { playSound(c2, "tada"); int v = newRoundTableRadius() + 12; @@ -5993,7 +5994,7 @@ bool collectItem(cell *c2, bool telekinesis) { if(pg < 75 && g2 >= 75) addMessage(XLAT("Kill monsters and collect treasures, and you may get access to Hell...")); if(pg < 90 && g2 >= 90) - addMessage(XLAT("To access Hell, collect 10 treasures each of 9 kinds...")); + addMessage(XLAT("To access Hell, collect %1 treasures each of 9 kinds...", its(R10))); if(hellUnlocked() && !lhu) { addMessage(XLAT("Abandon all hope, the gates of Hell are opened!")); addMessage(XLAT("And the Orbs of Yendor await!")); @@ -6467,6 +6468,7 @@ bool movepcto(int d, int subdir, bool checkonly) { if(d >= 0) { cell *c2 = cwt.c->mov[d]; + bool goodTortoise = c2->monst == moTortoise && tortoise::seek() && !tortoise::diff(tortoise::getb(c2)) && !c2->item; if(againstRose(cwt.c, c2) && !scentResistant()) { if(checkonly) return false; @@ -6652,7 +6654,8 @@ bool movepcto(int d, int subdir, bool checkonly) { knightFlavorMessage(c2); return false; } - else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst))) { + else if(c2->monst && (!isFriendly(c2) || c2->monst == moTameBomberbird || isMountable(c2->monst)) + && !(peace::on && !isMultitile(c2->monst) && !goodTortoise)) { bool fast = !((!items[itOrbSpeed]) || (items[itOrbSpeed]&1)); @@ -6731,7 +6734,7 @@ bool movepcto(int d, int subdir, bool checkonly) { !c2->item); } */ - if(c2->monst == moTortoise && tortoise::seek() && !tortoise::diff(tortoise::getb(c2)) && !c2->item) { + if(goodTortoise) { items[itBabyTortoise] += 4; updateHi(itBabyTortoise, items[itBabyTortoise]); c2->item = itBabyTortoise; @@ -6792,7 +6795,7 @@ bool movepcto(int d, int subdir, bool checkonly) { addMessage("Are you sure you want to step there?"); return false; } - if(c2->item == itOrbYendor && !boatmove && !checkonly && yendor::check(c2)) { + if(c2->item == itOrbYendor && !boatmove && !checkonly && !peace::on && yendor::check(c2)) { return false; } if(monstersnear(c2, NULL, moPlayer, NULL, cwt.c)) { @@ -6888,8 +6891,20 @@ bool movepcto(int d, int subdir, bool checkonly) { movecost(cwt.c, c2); - if(c2->monst == moGolem || c2->monst == moIllusion || isPrincess(c2->monst) || c2->monst == moMouse || - c2->monst == moFriendlyGhost) { + { + bool pushpast = false; + pushpast = + c2->monst == moGolem || c2->monst == moIllusion || isPrincess(c2->monst) || c2->monst == moMouse || + c2->monst == moFriendlyGhost; + + if(peace::on) pushpast |= c2->monst && !isMultitile(c2->monst); + + if(isMimic(c2->monst)) { + addMessage(XLAT("You rejoin %the1.", c2->monst)); + playSound(c2, "click"); + killMonster(c2, moNone); + } + else if(pushpast) { bool pswitch = false; if(c2->monst == moMouse) princess::mouseSqueak(c2); @@ -6907,11 +6922,7 @@ bool movepcto(int d, int subdir, bool checkonly) { c2->monst = moNone; switchplaces = true; } - else if(isMimic(c2->monst)) { - addMessage(XLAT("You rejoin %the1.", c2->monst)); - playSound(c2, "click"); - killMonster(c2, moNone); - } + } mountjump: lastmovetype = lmMove; lastmove = cwt.c; diff --git a/graph.cpp b/graph.cpp index c7ec8c50..5a4c6931 100644 --- a/graph.cpp +++ b/graph.cpp @@ -13,6 +13,8 @@ int maxreclevel, reclevel; int lastt; int backcolor = 0; +int bordcolor = 0; +int forecolor = 0xFFFFFF; int detaillevel = 0; @@ -174,7 +176,7 @@ void loadfont(int siz) { #ifdef WEB font[siz] = TTF_OpenFont("sans-serif", siz); #else - font[siz] = TTF_OpenFont("DejaVuSans-Bold.ttf", siz); + font[siz] = TTF_OpenFont(HYPERPATH "DejaVuSans-Bold.ttf", siz); #endif // Destination set by ./configure (in the GitHub repository) #ifdef FONTDESTDIR @@ -196,7 +198,11 @@ int textwidth(int siz, const string &str) { if(size(str) == 0) return 0; #ifdef NOTTF +#ifdef GL return gl_width(siz, str.c_str()); +#else + return 0; +#endif #else @@ -222,30 +228,29 @@ int textwidth(int siz, const string &str) { int gradient(int c0, int c1, ld v0, ld v, ld v1); -#ifdef LOCAL -double fadeout = 1; -#endif - -int darkened(int c) { -#ifdef LOCAL - c = gradient(0, c, 0, fadeout, 1); -#endif - // c = ((c & 0xFFFF) << 8) | ((c & 0xFF0000) >> 16); - // c = ((c & 0xFFFF) << 8) | ((c & 0xFF0000) >> 16); - for(int i=0; i>= 1; +int darkenedby(int c, int lev) { + for(int i=0; i> 1); return c; } -int darkenedby(int c, int lev) { - for(int i=0; i>= 1; +int darkened(int c) { +#ifdef EXTRA_FADEOUT + c = gradient(backcolor, c, 0, extra::fadeout, 1); +#endif + for(int i=0; i> 1) + ((backcolor & 0xFEFEFE) >> 1); return c; } int darkena(int c, int lev, int a) { - for(int i=0; i>= 1; - return (c << 8) + a; + return (darkenedby(c, lev) << 8) + a; } +#ifndef GL +void setcameraangle(bool b) { } +#endif + #ifdef GL bool cameraangle_on; @@ -349,6 +354,20 @@ void setGLProjection() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_BLEND); + if(vid.antialias & AA_LINES) { + glEnable(GL_LINE_SMOOTH); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + } + else glDisable(GL_LINE_SMOOTH); + glLineWidth(vid.linewidth); + + if(vid.antialias & AA_POLY) { + glEnable(GL_POLYGON_SMOOTH); + glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + } + else glDisable(GL_POLYGON_SMOOTH); + + //glLineWidth(1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if(pmodel == mdBall || pmodel == mdHyperboloid) { @@ -413,6 +432,54 @@ void glError(const char* GLcall, const char* file, const int line) { #include "nofont.cpp" #endif +void sdltogl(SDL_Surface *txt, glfont_t& f, int ch) { +#ifdef NOTTF + int otwidth, otheight, tpix[3000], tpixindex = 0; + loadCompressedChar(otwidth, otheight, tpix); +#else + int otwidth = txt->w; + int otheight = txt->h; +#endif + + int twidth = next_p2( otwidth ); + int theight = next_p2( otheight ); + +#ifdef NOTTF + int expanded_data[twidth * theight]; +#else + Uint16 expanded_data[twidth * theight]; +#endif + + for(int j=0; j =otwidth || j>=otheight) ? 0 : tpix[tpixindex++]; +#else + expanded_data[(i+j*twidth)] = + ((i>=txt->w || j>=txt->h) ? 0 : ((qpixel(txt, i, j)>>24)&0xFF) * 0x100) | 0x00FF; +#endif + } + + f.widths[ch] = otwidth; + f.heights[ch] = otheight; + + glBindTexture( GL_TEXTURE_2D, f.textures[ch]); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, twidth, theight, 0, +#ifdef NOTTF + GL_RGBA, GL_UNSIGNED_BYTE, +#else + GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, +#endif + expanded_data ); + + float x=(float)otwidth / (float)twidth; + float y=(float)otheight / (float)theight; + f.tx[ch] = x; + f.ty[ch] = y; + } + void init_glfont(int size) { if(glfont[size]) return; DEBB(DF_INIT, (debugfile,"init GL font: %d\n", size)); @@ -442,11 +509,9 @@ void init_glfont(int size) { if(ch<32) continue; #ifdef NOTTF - int otwidth, otheight, tpix[3000], tpixindex = 0; - loadCompressedChar(otwidth, otheight, tpix); + sdltogl(NULL, f, ch); #else - SDL_Surface *txt; if(ch < 128) { str[0] = ch; @@ -459,79 +524,9 @@ void init_glfont(int size) { #ifdef CREATEFONT generateFont(ch, txt); #endif - - int otwidth = txt->w; - int otheight = txt->h; + sdltogl(txt, f, ch); #endif - int twidth = next_p2( otwidth ); - int theight = next_p2( otheight ); - -#ifdef NOTTF - int expanded_data[twidth * theight]; -#else - Uint16 expanded_data[twidth * theight]; -#endif - - for(int j=0; j =otwidth || j>=otheight) ? 0 : tpix[tpixindex++]; -#else - expanded_data[(i+j*twidth)] = - (i>=txt->w || j>=txt->h) ? 0 : ((qpixel(txt, i, j)>>24)&0xFF) * 0x101; -#endif - } - -/* if(ch == '@') { - for(int j=0; j left,0,0); - // glTranslatef(0,bitmap_glyph->top-bitmap.rows,0); - -// printf("d\n"); - - glBegin(GL_QUADS); - float eps=0; - glTexCoord2d(eps,eps); glVertex2f(0, txt->h); - glTexCoord2d(eps,y-0); glVertex2f(0, 0); - glTexCoord2d(x-eps,y-0); glVertex2f(txt->w, 0); - glTexCoord2d(x-eps,0); glVertex2f(txt->w, txt->h); - glEnd(); - glEndList(); */ - //glPopMatrix(); - #ifndef NOTTF SDL_FreeSurface(txt); #endif @@ -541,16 +536,27 @@ void init_glfont(int size) { GLERR("initfont"); } +int utfsize(char c) { + unsigned char cu = c; + if(cu < 128) return 1; + if(cu < 224) return 2; + if(cu < 0xE0) return 3; + return 4; + } + +bool eqs(const char* x, const char* y) { + return *y? *x==*y?eqs(x+1,y+1):false:true; + } + int getnext(const char* s, int& i) { + int siz = utfsize(s[i]); + if(siz == 1) return s[i++]; for(int k=0; k= 2) { + int b1 = b-1; + displaystr(x-b1, y-b1, 0, size, s, p, align); + displaystr(x-b1, y+b1, 0, size, s, p, align); + displaystr(x+b1, y-b1, 0, size, s, p, align); + displaystr(x+b1, y+b1, 0, size, s, p, align); + } return displaystr(x, y, 0, size, s, color, align); } +bool displayfr(int x, int y, int b, int size, const string &s, int color, int align) { + return displayfrSP(x, y, 0, b, size, s, color, align, poly_outline>>8); + } + bool displaychr(int x, int y, int shift, int size, char chr, int col) { char buf[2]; @@ -903,6 +922,12 @@ void addMessage(string s, char spamtype) { addMessageToLog(m, msgs); } +int colormix(int a, int b, int c) { + for(int p=0; p<3; p++) + part(a, p) = part(a,p) + (part(b,p) - part(a,p)) * part(c,p) / 255; + return a; + } + void drawmessages() { DEBB(DF_GRAPH, (debugfile,"draw messages\n")); int i = 0; @@ -918,7 +943,8 @@ void drawmessages() { int y = vid.yres - vid.fsize * (size(msgs) - j) - (ISIOS ? 4 : 0); string s = msgs[j].msg; if(msgs[j].quantity > 1) s += " (x" + its(msgs[j].quantity) + ")"; - displayfr(x, y, 1, vid.fsize, s, 0x10101 * (255 - age/vid.flashtime), 8); + poly_outline = gradient(bordcolor, backcolor, 0, age, 256*vid.flashtime) << 8; + displayfr(x, y, 1, vid.fsize, s, gradient(forecolor, backcolor, 0, age, 256*vid.flashtime), 8); msgs[i++] = msgs[j]; } } @@ -1180,7 +1206,7 @@ int gradient(int c0, int c1, ld v0, ld v, ld v1) { int p0 = (c0 >> (8*a)) & 255; int p1 = (c1 >> (8*a)) & 255; int p = (p0*(256-vv) + p1*vv + 127) >> 8; - c += p << (8*a); + c |= p << (8*a); } return c; } @@ -1511,9 +1537,7 @@ namespace tortoise { else if(d < 0) mcol = 0; int dd = 0xFF * (atan(fabs(d)/2) / (M_PI/2)); - /* poly_outline = OUTLINE_TRANS; - queuepoly(V, shHeptaMarker, darkena(mcol, 0, dd)); - poly_outline = OUTLINE_NONE; */ + return gradient(0x487830, mcol, 0, dd, 0xFF); } }; @@ -1885,7 +1909,8 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou queuepoly(VBODY, shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); queuepoly(VBODY * Mirror, shBullHorn, items[itOrbDiscord] ? watercolor(0) : 0xFF000040); } - if(items[itOrbThorns]) + if(peace::on) ; + else if(items[itOrbThorns]) queuepoly(VBODY, shHedgehogBladePlayer, items[itOrbDiscord] ? watercolor(0) : 0x00FF00FF); else if(!shmup::on && items[itOrbDiscord]) queuepoly(VBODY, cs.charid >= 2 ? shSabre : shPSword, watercolor(0)); @@ -2217,7 +2242,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou otherbodyparts(V, darkena(col, 0, 0xC0), m, footphase); ShadowV(V, shPBody); queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0)); - queuepoly(VBODY, shPSword, 0xFFFF00FF); + if(!peace::on) queuepoly(VBODY, shPSword, 0xFFFF00FF); queuepoly(VHEAD, shHood, 0xD0D000C0); } else if(m == moPalace || m == moFatGuard || m == moVizier || m == moSkeleton) { @@ -2310,7 +2335,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou ShadowV(V, shPBody); otherbodyparts(V, darkena(col, 0, 0xFF), m, footphase); queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0)); - queuepoly(VBODY, shPSword, darkena(col, 0, 0xFF)); + if(!peace::on) queuepoly(VBODY, shPSword, darkena(col, 0, 0xFF)); queuepoly(VHEAD, shArmor, darkena(col, 1, 0xFF)); } else if(m == moGhost || m == moSeep || m == moFriendlyGhost) { @@ -2348,7 +2373,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou otherbodyparts(V, darkena(col, 1, 0xFF), m, footphase); ShadowV(V, shPBody); queuepoly(VBODY, shPBody, darkena(col, 0, 0xC0)); - queuepoly(VBODY, shPSword, darkena(col, 2, 0xFF)); + if(!peace::on) queuepoly(VBODY, shPSword, darkena(col, 2, 0xFF)); queuepoly(VHEAD, shHood, darkena(col, 1, 0xFF)); } else if(m == moPirate) { @@ -2383,7 +2408,7 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou otherbodyparts(V, darkena(col, 1, 0xFF), m, footphase); ShadowV(V, shPBody); queuepoly(VBODY, shPBody, darkena(0xE00000, 0, 0xFF)); - queuepoly(VBODY, shPSword, darkena(0xD0D0D0, 0, 0xFF)); + if(!peace::on) queuepoly(VBODY, shPSword, darkena(0xD0D0D0, 0, 0xFF)); queuepoly(VBODY, shKnightCloak, darkena(0x404040, 0, 0xFF)); queuepoly(VHEAD, shVikingHelmet, darkena(0xC0C0C0, 0, 0XFF)); queuepoly(VHEAD, shPFace, darkena(0xFFFF80, 0, 0xFF)); @@ -2574,13 +2599,13 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou } bool drawMonsterTypeDH(eMonster m, cell *where, const transmatrix& V, int col, bool dh, ld footphase) { + dynamicval p(poly_outline, poly_outline); if(dh) { poly_outline = OUTLINE_DEAD; darken++; } bool b = drawMonsterType(m,where,V,col, footphase); if(dh) { - poly_outline = OUTLINE_NONE; darken--; } return b; @@ -2931,10 +2956,10 @@ int keycelldist; int aurac[AURA+1][4]; bool haveaura() { - return pmodel == mdDisk && !sphere && !euclid && vid.aurastr>0 && !svg::in && (auraNOGL || vid.usingGL); + return pmodel == mdDisk && (!sphere || vid.alpha > 10) && !euclid && vid.aurastr>0 && !svg::in && (auraNOGL || vid.usingGL); } -void clearaura() { +void clearaura() { if(!haveaura()) return; for(int a=0; a>16)&255; aurac[r][1] += (col>>8)&255; aurac[r][2] += (col>>0)&255; @@ -2968,17 +2994,24 @@ void sumaura(int v) { void drawaura() { if(!haveaura()) return; + double rad = vid.radius; + if(sphere) rad /= sqrt(vid.alphax*vid.alphax - 1); for(int v=0; v<4; v++) sumaura(v); + double bak[3]; + bak[0] = ((backcolor>>16)&255)/255.; + bak[1] = ((backcolor>>8)&255)/255.; + bak[2] = ((backcolor>>0)&255)/255.; + #ifndef NOSDL if(!vid.usingGL) { SDL_LockSurface(s); for(int y=0; y p(poly_outline, - doHighlight() && ecol != -1 && ecol != 0 ? OUTLINE_ENEMY : OUTLINE_NONE); + doHighlight() && ecol != -1 && ecol != 0 ? OUTLINE_ENEMY : OUTLINE_DEFAULT); if(!chasmg) { if(wmescher) @@ -3324,7 +3356,7 @@ void drawMovementArrows(cell *c, transmatrix V) { // make it more transparent int col = getcs().uicolor; col -= (col & 0xFF) >> 1; - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; queuepoly(fixrot * spin(-d * M_PI/4 + (sphere && vid.alpha>1?M_PI:0))/* * eupush(1,0)*/, shArrow, col); if(c->type != 6 && (isStunnable(c->monst) || c->wall == waThumperOn)) { @@ -3363,7 +3395,7 @@ void drawMobileArrow(cell *c, transmatrix V) { if(invalid) col -= (col & 0xFF) >> 1; if(invalid) col -= (col & 0xFF) >> 1; - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; transmatrix m2 = Id; ld scale = vid.mobilecompasssize / 15.; m2[0][0] = scale; m2[1][1] = scale; m2[2][2] = 1; @@ -3923,7 +3955,7 @@ bool openorsafe(cell *c) { #define Dark(x) darkena(x,0,0xFF) int gridcolor(cell *c1, cell *c2) { - if(cmode == emDraw) return Dark(0xFFFFFF); + if(cmode == emDraw) return Dark(forecolor); if(!c2) return 0x202020 >> darken; int rd1 = rosedist(c1), rd2 = rosedist(c2); @@ -4028,20 +4060,24 @@ bool allemptynear(cell *c) { return true; } -bool behindsphere(const transmatrix& V) { +bool behindsphere(const hyperpoint& h) { if(!sphere) return false; if(vid.alpha > 1) { - if(V[2][2] > -1/vid.alpha) return true; + if(h[2] > -1/vid.alpha) return true; } if(vid.alpha <= 1) { - if(V[2][2] < -.8) return true; + if(h[2] < -.8) return true; } return false; } +bool behindsphere(const transmatrix& V) { + return behindsphere(tC0(V)); + } + void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { qfi.shape = NULL; qfi.special = false; @@ -4058,6 +4094,10 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { if(behindsphere(V)) return; +#ifdef EXTRA_DRAWCELL + extra::drawcell(c, V); +#endif + ld dist0 = hdist0(tC0(V)) - 1e-6; if(dist0 < geom3::highdetail) detaillevel = 2; else if(dist0 < geom3::middetail) detaillevel = 1; @@ -4160,6 +4200,17 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { // addaura(tC0(V), wcol); int zcol = fcol; + if(peace::on && peace::hint && c->land != laTortoise) { + int d = + (c->land == laCamelot || (c->land == laCaribbean && celldistAlt(c) <= 0) || (c->land == laPalace && celldistAlt(c))) ? celldistAlt(c): + celldist(c); + + int dc = + 0x10101 * (127 + int(127 * sin(ticks / 200. + d*1.5))); + wcol = gradient(wcol, dc, 0, .3, 1); + fcol = gradient(fcol, dc, 0, .3, 1); + } + if(viewdists) { int cd = celldistance(c, cwt.c); string label = its(cd); @@ -4181,7 +4232,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { int ds = ticks; for(int u=0; u<5; u++) { ld rad = hexf * (.3 * u + (ds%1000) * .0003); - int tcol = darkena(gradient(0xFFFFFF, 0, 0, rad, 1.5 * hexf), 0, 0xFF); + int tcol = darkena(gradient(forecolor, backcolor, 0, rad, 1.5 * hexf), 0, 0xFF); for(int a=0; aland == laReptile ? 0 : 2; - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; int sl = snakelevel(c); @@ -4307,7 +4358,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { shmup::drawMonster(V, c, Vboat, Vboat0, zlev); } - poly_outline = (backcolor << 8) + 0xFF; + poly_outline = OUTLINE_DEFAULT; if(!wmascii) { @@ -4631,10 +4682,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { int labeli = mapeditor::displaycodes == 1 ? mapeditor::realpattern(c) : mapeditor::subpattern(c); string label = its(labeli); - if(svg::in) - queuestr(V, .5, label, 0xFF000000); - else - queuestr(V, .2, label, 0xFFFFFFFF); + queuestr(V, .5, label, 0xFF000000 + forecolor); /* transmatrix V2 = V * applyPatterndir(c); qfloor(c, V2, shNecro, 0x80808080); @@ -4938,7 +4986,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { else { queuepoly(V, shMirror, darkena(wcol, 0, 0xC0)); } - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; } else if(isFire(c) || isThumper(c) || c->wall == waBonfireOff) { @@ -5113,36 +5161,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { poly_outline = OUTLINE_TRANS; queuepoly((*Vdp)*V0*xpush(hexf*-cos(ph0)), shDisk, aircol); - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; } } - -// queuepoly(V*ddi(rand() % S84, hexf*(rand()%100)/100), shDisk, aircolor(airdir)); } - /* int rd = rosedist(c); - if(rd > 0 && ((rd&7) == (turncount&7))) { - - for(int i=0; itype; i++) { - cell *c2 = c->mov[i]; - if(rosedist(c2) == rosedist(c)-1) { - int hdir = displaydir(c, i); - transmatrix V0 = spin((S42+hdir) * M_PI / S42); - - double ph = ticks / 75.0; // + airdir * M_PI / (S21+.0); - - int rosecol = 0x764e7c00 | int(32 + 32 * -cos(ph)); - - double ph0 = ph/2; - ph0 -= floor(ph0/M_PI)*M_PI; - - poly_outline = OUTLINE_TRANS; - queuepoly(V*V0*ddi(0, hexf*-cos(ph0)), shDisk, rosecol); - poly_outline = OUTLINE_NONE; - } - } - } */ - if(c->land == laWhirlwind) { whirlwind::calcdirs(c); @@ -5167,13 +5190,13 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { poly_outline = OUTLINE_TRANS; queuepoly((*Vdp)*V0*xpush(ldist*(2*ph1-1)), shDisk, aircol); - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; } } if(error) { - queuechr(V, 1, ch, asciicol, 2); + queuechr(V, 1, ch, darkenedby(asciicol, darken), 2); } if(vid.grid) { @@ -5287,11 +5310,6 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { #ifndef NOMODEL netgen::buildVertexInfo(c, V); #endif - -#ifdef LOCAL - extern void localdraw (const transmatrix& V, cell *c); - localdraw(V, c); -#endif } } @@ -5504,7 +5522,7 @@ void drawFlashes() { if(f.spd) { kill = tim > 300; int partcol = darkena(f.color, 0, max(255 - kill/2, 0)); - poly_outline = OUTLINE_NONE; + poly_outline = OUTLINE_DEFAULT; queuepoly(V * spin(f.angle) * xpush(f.spd * tim / 50000.), shParticle[f.size], partcol); } @@ -5908,13 +5926,13 @@ string generateHelpForLand(eLand l) { #define ACCONLY(z) s += XLAT("Accessible only from %the1.\n", z); #define ACCONLY2(z,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, x); #define ACCONLYF(z) s += XLAT("Accessible only from %the1 (until finished).\n", z); - #define TREQ(z) { s += XLAT("Treasure required: %1 $$$.\n", #z); buteol(s, gold(), z); } - #define TREQ2(z,x) { s += XLAT("Treasure required: %1 x %2.\n", #z, x); buteol(s, items[x], z); } + #define TREQ(z) { s += XLAT("Treasure required: %1 $$$.\n", its(z)); buteol(s, gold(), z); } + #define TREQ2(z,x) { s += XLAT("Treasure required: %1 x %2.\n", its(z), x); buteol(s, items[x], z); } if(l == laMirror || l == laMinefield || l == laPalace || l == laOcean || l == laLivefjord || l == laZebra || l == laWarpCoast || l == laWarpSea || l == laReptile || l == laIvoryTower) - TREQ(30) + TREQ(R30) if(isCoastal(l)) @@ -5935,50 +5953,50 @@ string generateHelpForLand(eLand l) { if(l == laDryForest || l == laWineyard || l == laDeadCaves || l == laHive || l == laRedRock || l == laOvergrown || l == laStorms || l == laWhirlwind || l == laRose || l == laCrossroads2 || l == laRlyeh) - TREQ(60) + TREQ(R60) - if(l == laReptile) TREQ2(10, itElixir) - if(l == laEndorian) TREQ2(10, itIvory) - if(l == laKraken) TREQ2(10, itFjord) - if(l == laBurial) TREQ2(10, itKraken) + if(l == laReptile) TREQ2(U10, itElixir) + if(l == laEndorian) TREQ2(U10, itIvory) + if(l == laKraken) TREQ2(U10, itFjord) + if(l == laBurial) TREQ2(U10, itKraken) - if(l == laDungeon) TREQ2(5, itIvory) - if(l == laDungeon) TREQ2(5, itPalace) - if(l == laMountain) TREQ2(5, itIvory) - if(l == laMountain) TREQ2(5, itRuby) + if(l == laDungeon) TREQ2(U5, itIvory) + if(l == laDungeon) TREQ2(U5, itPalace) + if(l == laMountain) TREQ2(U5, itIvory) + if(l == laMountain) TREQ2(U5, itRuby) - if(l == laPrairie) TREQ(90) - if(l == laBull) TREQ(90) - if(l == laCrossroads4) TREQ(200) - if(l == laCrossroads5) TREQ(300) + if(l == laPrairie) TREQ(R90) + if(l == laBull) TREQ(R90) + if(l == laCrossroads4) TREQ(R200) + if(l == laCrossroads5) TREQ(R300) if(l == laGraveyard || l == laHive) { s += XLAT("Kills required: %1.\n", "100"); - buteol(s, tkills(), 100); + buteol(s, tkills(), R100); } if(l == laDragon) { s += XLAT("Different kills required: %1.\n", "20"); - buteol(s, killtypes(), 20); + buteol(s, killtypes(), R20); } if(l == laTortoise) ACCONLY(laDragon) if(l == laTortoise) s += XLAT("Find a %1 in %the2.", itBabyTortoise, laDragon); if(l == laHell || l == laCrossroads3) { - s += XLAT("Finished lands required: %1 (collect 10 treasure)\n", "9"); + s += XLAT("Finished lands required: %1 (collect %2 treasure)\n", "9", its(R10)); buteol(s, orbsUnlocked(), 9); } - if(l == laCocytus || l == laPower) TREQ2(10, itHell) - if(l == laRedRock) TREQ2(10, itSpice) - if(l == laOvergrown) TREQ2(10, itRuby) - if(l == laClearing) TREQ2(5, itMutant) - if(l == laCocytus) TREQ2(10, itDiamond) - if(l == laDeadCaves) TREQ2(10, itGold) - if(l == laTemple) TREQ2(5, itStatue) - if(l == laHaunted) TREQ2(10, itBone) - if(l == laCamelot) TREQ2(5, itEmerald) + if(l == laCocytus || l == laPower) TREQ2(U10, itHell) + if(l == laRedRock) TREQ2(U10, itSpice) + if(l == laOvergrown) TREQ2(U10, itRuby) + if(l == laClearing) TREQ2(U5, itMutant) + if(l == laCocytus) TREQ2(U10, itDiamond) + if(l == laDeadCaves) TREQ2(U10, itGold) + if(l == laTemple) TREQ2(U5, itStatue) + if(l == laHaunted) TREQ2(U10, itBone) + if(l == laCamelot) TREQ2(U5, itEmerald) if(l == laEmerald) { TREQ2(5, itFernFlower) TREQ2(5, itGold) s += XLAT("Alternatively: kill a %1 in %the2.\n", moVizier, laPalace); @@ -6006,7 +6024,7 @@ string generateHelpForLand(eLand l) { KILLREQ(moRedTroll, laRedRock); } - if(l == laZebra) TREQ2(10, itFeather) + if(l == laZebra) TREQ2(U10, itFeather) if(l == laCamelot || l == laPrincessQuest) s += XLAT("Completing the quest in this land is not necessary for the Hyperstone Quest."); @@ -6280,29 +6298,21 @@ void describeMouseover() { if(isWarped(c)) help += s0 + "\n\n" + warpdesc; } - else if(cmode == emVisual1) { - if(getcstat == 'p') { - out = XLAT("0 = Klein model, 1 = Poincaré model"); - if(vid.alpha < -0.5) - out = XLAT("you are looking through it!"); - if(vid.alpha > 5) - out = XLAT("(press 'i' to approach infinity (Gans model)"); - } - else if(getcstat == 'r') { - out = XLAT("simply resize the window to change resolution"); - } - /* else if(getcstat == 'f') { - out = XLAT("[+] keep the window size, [-] use the screen resolution"); - } */ - else if(getcstat == 'a' && vid.sspeed > -4.99) + else if(cmode == emGraphConfig) { + if(getcstat == 'a' && vid.sspeed > -4.99) out = XLAT("+5 = center instantly, -5 = do not center the map"); else if(getcstat == 'a') out = XLAT("press Space or Home to center on the PC"); else if(getcstat == 'w') out = XLAT("also hold Alt during the game to toggle high contrast"); - else if(getcstat == 'w' || getcstat == 'm') - out = XLAT("You can choose one of the several modes"); - else if(getcstat == 'c') + else if(getcstat == 'f') + out = XLAT("Reduce the framerate limit to conserve CPU energy"); + } + else if(cmode == emBasicConfig) { + /* else if(getcstat == 'f') { + out = XLAT("[+] keep the window size, [-] use the screen resolution"); + } */ + if(getcstat == 'c') out = XLAT("The axes help with keyboard movement"); else if(getcstat == 'g') out = XLAT("Affects looks and grammar"); @@ -6312,17 +6322,13 @@ void describeMouseover() { #endif else out = ""; } - else if(cmode == emVisual2) { + else if(cmode == emDisplayMode) { if(getcstat == 'p') { if(autojoy) out = XLAT("joystick mode: automatic (release the joystick to move)"); if(!autojoy) out = XLAT("joystick mode: manual (press a button to move)"); } - else if(getcstat == 'e') - out = XLAT("You need special glasses to view the game in 3D"); - else if(getcstat == 'f') - out = XLAT("Reduce the framerate limit to conserve CPU energy"); } else if(cmode == emChangeMode) { if(getcstat == 'h') @@ -6584,6 +6590,10 @@ void drawthemap() { rogueviz::drawExtra(); #endif +#ifdef EXTRA_FRAME + extra::frame(); +#endif + #ifdef TOUR if(tour::on) tour::presentation(tour::pmFrame); #endif @@ -6921,6 +6931,11 @@ void calcparam() { if(vid.xres >= vid.yres * 5/4-16 && dialog::sidedialog && cmode == emNumber) sidescreen = true; if(viewdists && cmode == emNormal && vid.xres > vid.yres) sidescreen = true; +#ifdef TOUR + if(tour::on && (tour::slides[tour::currentslide].flags & tour::SIDESCREEN)) + sidescreen = true; +#endif + if(sidescreen) vid.xcenter = vid.yres/2; } @@ -7031,14 +7046,14 @@ void showGameover() { else { if(princess::challenge) dialog::addInfo(XLAT("Follow the Mouse and escape with %the1!", moPrincess)); - else if(gold() < 30) - dialog::addInfo(XLAT("Collect 30 $$$ to access more worlds")); - else if(gold() < 60) - dialog::addInfo(XLAT("Collect 60 $$$ to access even more lands")); + else if(gold() < R30) + dialog::addInfo(XLAT("Collect %1 $$$ to access more worlds", its(R30))); + else if(gold() < R60) + dialog::addInfo(XLAT("Collect %1 $$$ to access even more lands", its(R60))); else if(!hellUnlocked()) - dialog::addInfo(XLAT("Collect at least 10 treasures in each of 9 types to access Hell")); - else if(items[itHell] < 10) - dialog::addInfo(XLAT("Collect at least 10 Demon Daisies to find the Orbs of Yendor")); + dialog::addInfo(XLAT("Collect at least %1 treasures in each of 9 types to access Hell", its(R10))); + else if(items[itHell] < R10) + dialog::addInfo(XLAT("Collect at least %1 Demon Daisies to find the Orbs of Yendor", its(R10))); else if(size(yendor::yi) == 0) dialog::addInfo(XLAT("Look for the Orbs of Yendor in Hell or in the Crossroads!")); else @@ -7056,21 +7071,21 @@ void showGameover() { #ifdef TOUR else if(tour::on) ; #endif - else if(tkills() < 100) - dialog::addInfo(XLAT("Defeat 100 enemies to access the Graveyard")); - else if(kills[moVizier] == 0 && (items[itFernFlower] < 5 || items[itGold] < 5)) + else if(tkills() < R100) + dialog::addInfo(XLAT("Defeat %1 enemies to access the Graveyard", its(R100))); + else if(kills[moVizier] == 0 && (items[itFernFlower] < U5 || items[itGold] < U5)) dialog::addInfo(XLAT("Kill a Vizier in the Palace to access Emerald Mine")); - else if(items[itEmerald] < 5) + else if(items[itEmerald] < U5) dialog::addInfo(XLAT("Collect 5 Emeralds to access Camelot")); else if(hellUnlocked() && !chaosmode) { bool b = true; for(int i=0; i= ittypes) { eMonster m = eMonster(id - ittypes); int bsize = buttonsize; @@ -7561,11 +7582,14 @@ void displayglyph2(int cx, int cy, int buttonsize, int i) { } } +bool nohud, nomenukey; + void drawStats() { #ifdef ROGUEVIZ - if(rogueviz::on) return; + if(rogueviz::on || nohud) return; #endif if(viewdists && sidescreen) { + distcolors[0] = forecolor; dialog::init(""); int qty[64]; vector& ac = currentmap->allcells(); @@ -7587,16 +7611,16 @@ void drawStats() { if(geometry == gNormal && !purehepta) { dialog::addBreak(200); dialog::addHelp("a(d+4) = a(d+3) + a(d+2) + a(d+1) - a(d)"); - dialog::addInfo("a(d) ~ 1.72208^d", 0xFFFFFF); + dialog::addInfo("a(d) ~ 1.72208ᵈ", forecolor); } if(geometry == gNormal && purehepta) { dialog::addBreak(200); dialog::addHelp("a(d+2) = 3a(d+1) - a(d+2)"); - dialog::addInfo("a(d) ~ 2.61803^d", 0xFFFFFF); + dialog::addInfo("a(d) ~ 2.61803ᵈ", forecolor); } if(geometry == gEuclid) { dialog::addBreak(300); - dialog::addInfo("a(n) = 6n", 0xFFFFFF); + dialog::addInfo("a(d) = 6d", forecolor); } dialog::display(); } @@ -7707,7 +7731,7 @@ void drawStats() { } string s0; - if(displayButtonS(vid.xres - 8, vid.fsize, "score: " + its(gold()), 0xFFFFFFF, 16, vid.fsize)) { + if(displayButtonS(vid.xres - 8, vid.fsize, "score: " + its(gold()), forecolor, 16, vid.fsize)) { mouseovers = XLAT("Your total wealth"), instat = true, getcstat = SDLK_F1, @@ -7720,7 +7744,7 @@ void drawStats() { "Orbs of Yendor are worth 50 $$$ each.\n\n" ); } - if(displayButtonS(8, vid.fsize, "kills: " + its(tkills()), 0xFFFFFFF, 0, vid.fsize)) { + if(displayButtonS(8, vid.fsize, "kills: " + its(tkills()), forecolor, 0, vid.fsize)) { instat = true, getcstat = SDLK_F1, mouseovers = XLAT("Your total kills")+": " + its(tkills()), @@ -7754,11 +7778,14 @@ XLAT( } achievement_display(); -#ifdef LOCAL - process_local_stats(); +#ifdef EXTRA_STATS + extra::stats(); #endif } +int pngres = 2000; +int pngformat = 0; + #ifndef NOSDL #ifndef NOPNG @@ -7769,9 +7796,6 @@ void IMAGESAVE(SDL_Surface *s, const char *fname) { } #endif -int pngres = 2000; -int pngformat = 0; - void saveHighQualityShot(const char *fname, const char *caption, int fade) { #ifndef SDLGFX @@ -7829,7 +7853,7 @@ void saveHighQualityShot(const char *fname, const char *caption, int fade) { } if(caption) - displayfr(vid.xres/2, vid.fsize+vid.fsize/4, 3, vid.fsize*2, caption, 0xFFFFFF, 8); + displayfr(vid.xres/2, vid.fsize+vid.fsize/4, 3, vid.fsize*2, caption, forecolor, 8); char buf[128]; strftime(buf, 128, "bigshota-%y%m%d-%H%M%S" IMAGEEXT, localtime(&timer)); buf[7] += i; @@ -7867,6 +7891,8 @@ void ballgeometry() { queuereset(pmodel, PPR_CIRCLE); } +int ringcolor = darkena(0xFF, 0, 0xFF); + void drawfullmap() { DEBB(DF_GRAPH, (debugfile,"draw full map\n")); @@ -7885,8 +7911,7 @@ void drawfullmap() { else if(vid.grid) // mark the edge rad /= sqrt(vid.alphax*vid.alphax - 1); } - if(!haveaura()) queuecircle(vid.xcenter, vid.ycenter, rad, - svg::in ? 0x808080FF : darkena(0xFF, 0, 0xFF), + if(!haveaura()) queuecircle(vid.xcenter, vid.ycenter, rad, ringcolor, vid.usingGL ? PPR_CIRCLE : PPR_OUTCIRCLE); if(pmodel == mdBall) ballgeometry(); } @@ -7966,6 +7991,7 @@ void drawscreen() { if(cmode != emNormal && cmode != emDraw && cmode != emCustomizeChar) darken = 2; if(cmode == emQuit && !canmove) darken = 0; if(cmode == emOverview) darken = 16; + if(cmode == emOverview && !vid.monmode && !hiliteclick) darken = 4; if(sidescreen) darken = 0; @@ -7987,6 +8013,8 @@ void drawscreen() { else drawfullmap(); if(conformal::includeHistory && cmode != emProgress) conformal::restoreBack(); + + poly_outline = OUTLINE_DEFAULT; lgetcstat = getcstat; getcstat = 0; inslider = false; @@ -8001,8 +8029,8 @@ void drawscreen() { if(andmode == 0 && shmup::on) { using namespace shmupballs; calc(); - drawCircle(xmove, yb, rad, 0xFFFFFFFF); - drawCircle(xmove, yb, rad/2, 0xFFFFFFFF); + drawCircle(xmove, yb, rad, OUTLINE_FORE); + drawCircle(xmove, yb, rad/2, OUTLINE_FORE); drawCircle(xfire, yb, rad, 0xFF0000FF); drawCircle(xfire, yb, rad/2, 0xFF0000FF); } @@ -8073,9 +8101,11 @@ void drawscreen() { } #ifndef MOBILE - if(cmode == emNormal || cmode == emVisual1 || cmode == emVisual2 || cmode == emChangeMode ) { + if(cmode == emNormal || cmode == emBasicConfig || cmode == emGraphConfig || cmode == emDisplayMode || cmode == emChangeMode ) { + if(nomenukey) + ; #ifdef TOUR - if(tour::on) + else if(tour::on) displayButton(vid.xres-8, vid.yres-vid.fsize, XLAT("(ESC) tour menu"), SDLK_ESCAPE, 16); else #endif @@ -8224,7 +8254,7 @@ void saveConfig() { } fprintf(f, "%d %d %d %d\n", vid.xres, vid.yres, vid.full, vid.fsize); fprintf(f, "%f %f %f %f\n", float(vid.scale), float(vid.eye), float(vid.alpha), float(vid.sspeed)); - fprintf(f, "%d %d %d %d %d %d %d\n", vid.wallmode, vid.monmode, vid.axes, musicvolume, vid.framelimit, vid.usingGL, vid.usingAA); + fprintf(f, "%d %d %d %d %d %d %d\n", vid.wallmode, vid.monmode, vid.axes, musicvolume, vid.framelimit, vid.usingGL, vid.antialias); fprintf(f, "%d %d %d %f %d %d\n", vid.joyvalue, vid.joyvalue2, vid.joypanthreshold, float(vid.joypanspeed), autojoy, vid.flashtime); savecs(f, vid.cs, 0); @@ -8278,15 +8308,14 @@ void saveConfig() { float(vid.ballangle), float(vid.ballproj) ); - fprintf(f, "%d %d %d %d\n", vid.mobilecompasssize, vid.aurastr, vid.aurasmoothen, vid.graphglyph); - + fprintf(f, "%d %d %d %d %f\n", vid.mobilecompasssize, vid.aurastr, vid.aurasmoothen, vid.graphglyph, float(vid.linewidth)); } fprintf(f, "\n\nThis is a configuration file for HyperRogue (version " VER ")\n"); fprintf(f, "\n\nThe numbers are:\n"); fprintf(f, "screen width & height, fullscreen mode (0=windowed, 1=fullscreen), font size\n"); fprintf(f, "scale, eye distance, parameter, scrolling speed\n"); - fprintf(f, "wallmode, monster mode, cross mode, music volume, framerate limit, usingGL, usingAA\n"); + fprintf(f, "wallmode, monster mode, cross mode, music volume, framerate limit, usingGL, antialiasing flags\n"); fprintf(f, "calibrate first joystick (threshold A, threshold B), calibrate second joystick (pan threshold, pan speed), joy mode\n"); fprintf(f, "gender (1=female, 16=same gender prince), language, skin color, hair color, sword color, dress color\n"); fprintf(f, "darken hepta, shift target\n"); @@ -8331,8 +8360,10 @@ void loadConfig() { if(err == 4) { vid.scale = a; vid.eye = b; vid.alpha = c; vid.sspeed = d; } - err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &aa); - vid.usingGL = gl; vid.usingAA = aa; + err=fscanf(f, "%d%d%d%d%d%d%d", &vid.wallmode, &vid.monmode, &vid.axes, &musicvolume, &vid.framelimit, &gl, &vid.antialias); + vid.usingGL = gl; + if(vid.antialias == 0) vid.antialias = AA_VERSION | AA_LINES | AA_LINEWIDTH; + if(vid.antialias == 1) vid.antialias = AA_NOGL | AA_VERSION | AA_LINES | AA_LINEWIDTH | AA_FONT; double jps = vid.joypanspeed; err=fscanf(f, "%d%d%d%lf%d%d", &vid.joyvalue, &vid.joyvalue2, &vid.joypanthreshold, &jps, &aa, &vid.flashtime); vid.joypanspeed = jps; @@ -8407,7 +8438,9 @@ void loadConfig() { readf(f, vid.yshift); readf(f, vid.camera_angle); readf(f, vid.ballangle); readf(f, vid.ballproj); - err=fscanf(f, "%d%d%d%d\n", &vid.mobilecompasssize, &vid.aurastr, &vid.aurasmoothen, &vid.graphglyph); + jps = vid.linewidth; + err=fscanf(f, "%d%d%d%d%lf\n", &vid.mobilecompasssize, &vid.aurastr, &vid.aurasmoothen, &vid.graphglyph, &jps); + vid.linewidth = jps; fclose(f); DEBB(DF_INIT, (debugfile,"Loaded configuration: %s\n", conffile)); @@ -8452,7 +8485,8 @@ void initgraph() { DEBB(DF_INIT, (debugfile,"initgraph\n")); vid.usingGL = true; - vid.usingAA = true; + vid.antialias = AA_NOGL | AA_FONT | AA_LINES | AA_LINEWIDTH | AA_VERSION; + vid.linewidth = 1; vid.flashtime = 8; vid.scale = 1; vid.alpha = 1; @@ -8594,10 +8628,6 @@ void panning(hyperpoint hf, hyperpoint ht) { playermoved = false; } -#ifdef LOCAL -#include "local.cpp" -#endif - bool needConfirmation() { return canmove && (gold() >= 30 || tkills() >= 50) && !cheater && !quitsaves(); } @@ -8647,6 +8677,7 @@ void handleKeyQuit(int sym, int uni) { else if(sym == SDLK_F3 || (sym == ' ' || sym == SDLK_HOME)) fullcenter(); else if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview(); + else if(uni == 'i' && DEFAULTNOR(sym) && inv::on) cmode = emInventory; #ifndef NOSAVE else if(uni == 't') { if(!canmove) restartGame(); @@ -8663,12 +8694,12 @@ void handleKeyQuit(int sym, int uni) { } #ifdef MOBILE -#define extra int +typedef int eventtype; #else -#define extra SDL_Event +typedef SDL_Event eventtype; #endif -void handleKeyNormal(int sym, int uni, extra& ev) { +void handleKeyNormal(int sym, int uni, eventtype& ev) { if(cheater) { if(applyCheat(uni, mouseover)) @@ -8696,30 +8727,11 @@ void handleKeyNormal(int sym, int uni, extra& ev) { #endif if(uni == sym && DEFAULTNOR(sym)) { - if(sym == '1') { - vid.alpha = 999; vid.scale = 998; - } - if(sym == '2') { - vid.alpha = 1; vid.scale = 0.4; - } - if(sym == '3') { - vid.alpha = 1; vid.scale = 1; - } - if(sym == '4') { - vid.alpha = 0; vid.scale = 1; - } - if(sym == '5') { - vid.wallmode++; - if(vid.wallmode == 6) vid.wallmode = 0; - } - if(sym == '6') { - vid.grid = !vid.grid; - } - if(sym == '7') { - vid.darkhepta = !vid.darkhepta; - } + gmodekeys(sym, uni); if(sym == '8') { backcolor = backcolor ^ 0xFFFFFF; + bordcolor = bordcolor ^ 0xFFFFFF; + forecolor = forecolor ^ 0xFFFFFF; printf("back = %x\n", backcolor); } if(sym == '9') { @@ -8733,10 +8745,6 @@ void handleKeyNormal(int sym, int uni, extra& ev) { if(DEFAULTCONTROL) { if(sym == '.' || sym == 's') movepcto(-1, 1); - if(uni == '%' && sym == '5') { - if(vid.wallmode == 0) vid.wallmode = 6; - vid.wallmode--; - } if((sym == SDLK_DELETE || sym == SDLK_KP_PERIOD || sym == 'g') && uni != 'G' && uni != 'G'-64) movepcto(MD_DROP, 1); if(sym == 't' && uni != 'T' && uni != 'T'-64 && canmove && cmode == emNormal) { @@ -8791,6 +8799,7 @@ void handleKeyNormal(int sym, int uni, extra& ev) { } if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview(); + if(uni == 'i' && DEFAULTNOR(sym) && inv::on) cmode = emInventory; if((sym == SDLK_HOME || sym == SDLK_F3 || sym == ' ') && DEFAULTNOR(sym)) fullcenter(); @@ -8805,10 +8814,6 @@ void handleKeyNormal(int sym, int uni, extra& ev) { cmode = emMenu; } - if(sym == SDLK_F2) { - cmode = emVisual1; - } - #ifndef NOSDL #ifdef PANDORA if(ev.type == SDL_MOUSEBUTTONUP && sym == 0 && !rightclick) @@ -8841,13 +8846,13 @@ void handleKeyNormal(int sym, int uni, extra& ev) { #ifdef ROGUEVIZ rogueviz::processKey(sym, uni); #endif - -#ifdef LOCAL - process_local0(sym); -#endif } -void handlekey(int sym, int uni, extra& ev) { +void handlekey(int sym, int uni, eventtype& ev) { + +#ifdef EXTRA_HANDLEKEY + if(extra::handleKey(sym, uni)) return; +#endif #ifdef TOUR if(tour::on && tour::handleKeyTour(sym, uni)) return; @@ -8916,10 +8921,11 @@ void handlekey(int sym, int uni, extra& ev) { if(cmode == emNormal) handleKeyNormal(sym, uni, ev); else if(cmode == emMenu) handleMenuKey(sym, uni); else if(cmode == emCheatMenu) handleCheatMenu(sym, uni); - else if(cmode == emVisual1) handleVisual1(sym, uni); + else if(cmode == emBasicConfig) handleBasicConfig(sym, uni); + else if(cmode == emGraphConfig) handleGraphConfig(sym, uni); else if(cmode == emJoyConfig) handleJoystickConfig(sym, uni); else if(cmode == emCustomizeChar) handleCustomizeChar(sym, uni); - else if(cmode == emVisual2) handleVisual2(sym, uni); + else if(cmode == emDisplayMode) handleDisplayMode(sym, uni); else if(cmode == emChangeMode) handleChangeMode(sym, uni); else if(cmode == emShmupConfig) shmup::handleConfig(sym, uni); #ifndef NOMODEL @@ -8940,6 +8946,11 @@ void handlekey(int sym, int uni, extra& ev) { #endif else if(cmode == emConformal) conformal::handleKey(sym, uni); else if(cmode == emYendor) yendor::handleKey(sym, uni); + else if(cmode == emPeace) peace::handleKey(sym, uni); +#ifdef INV + else if(cmode == emInventory) inv::handleKey(sym, uni); +#endif + else if(cmode == emSlideshows) tour::ss::handleKey(sym, uni); else if(cmode == emTactic) tactic::handleKey(sym, uni); else if(cmode == emOverview) handleOverview(sym, uni); else if(cmode == emPickEuclidean) handleEuclidean(sym, uni); @@ -8977,10 +8988,6 @@ void mainloopiter() { #endif #endif -#ifdef LOCAL - process_local_extra(); -#endif - optimizeview(); if(conformal::on) conformal::apply(); @@ -8988,7 +8995,7 @@ void mainloopiter() { ticks = SDL_GetTicks(); int cframelimit = vid.framelimit; - if((cmode == emVisual1 || cmode == emVisual2 || cmode == emHelp || cmode == emQuit || + if((cmode == emBasicConfig || cmode == emGraphConfig || cmode == emDisplayMode || cmode == emHelp || cmode == emQuit || cmode == emCustomizeChar || cmode == emMenu || cmode == emPickEuclidean || cmode == emScores || cmode == emPickScores) && cframelimit > 15) cframelimit = 15; @@ -9294,8 +9301,10 @@ void cleargraph() { for(int i=0; i<256; i++) if(font[i]) TTF_CloseFont(font[i]); #endif #ifndef EXTERNALFONT +#ifdef GL for(int i=0; i<128; i++) if(glfont[i]) delete glfont[i]; #endif +#endif #ifndef NOSDL #ifndef SIMULATE_JOYSTICK closeJoysticks(); @@ -9327,8 +9336,10 @@ void showMissionScreen() { void resetGeometry() { precalc(); - fp43.analyze(); + fp43.analyze(); +#ifdef GL resetGL(); +#endif } diff --git a/heptagon.cpp b/heptagon.cpp index 205f9379..bee9bf16 100644 --- a/heptagon.cpp +++ b/heptagon.cpp @@ -34,7 +34,8 @@ void tsetspin(uint32_t& t, int d, int spin) { struct heptagon { // automaton state - hstate s : 8; + hstate s : 6; + int dm4: 2; // we are spin[i]-th neighbor of move[i] uint32_t spintable; int spin(int d) { return tspin(spintable, d); } @@ -126,6 +127,7 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) { //generateEmeraldval(parent); //generateEmeraldval(h); if(pard == 0) { + h->dm4 = parent->dm4+1; if(purehepta) h->distance = parent->distance + 1; else if(parent->s == hsOrigin) h->distance = 2; else if(h->spin(0) == 5) @@ -134,7 +136,10 @@ heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) { h->distance = createStep(h->move[0], (h->spin(0)+2)%7)->distance + 3; else h->distance = parent->distance + 2; } - else h->distance = parent->distance - (purehepta?1:2); + else { + h->distance = parent->distance - (purehepta?1:2); + h->dm4 = parent->dm4-1; + } return h; } diff --git a/hyper.cpp b/hyper.cpp index 58f3103a..efb7727e 100644 --- a/hyper.cpp +++ b/hyper.cpp @@ -119,6 +119,12 @@ int arg::readCommon() { else if(argis("-back")) { shift(); backcolor = strtol(args(), NULL, 16); } + else if(argis("-borders")) { + shift(); bordcolor = strtol(args(), NULL, 16); + } + else if(argis("-fore")) { + shift(); forecolor = strtol(args(), NULL, 16); + } else if(argis("-W2")) { shift(); cheatdest = readland(args()); autocheat = true; } @@ -168,6 +174,8 @@ int arg::readCommon() { exit(0); } + else if(argis("-aa")) { PHASEFROM(2); shift(); vid.antialias = argi(); } + else if(argis("-lw")) { PHASEFROM(2); shift(); vid.linewidth = argf(); } else if(argis("-wm")) { PHASEFROM(2); vid.wallmode = argi(); } else if(argis("-mm")) { PHASEFROM(2); vid.monmode = argi(); } @@ -379,7 +387,11 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { if(curphase == return 0; } +#ifndef NOMAIN int main(int argc, char **argv) { +#ifdef EXTRA_MAIN + if(extra::main(argc, argv)) return 0; +#endif #ifndef WEB #ifdef LINUX moreStack(); @@ -394,6 +406,7 @@ int main(int argc, char **argv) { profile_info(); return 0; } +#endif #ifdef USE_COMMANDLINE namespace arg { @@ -401,11 +414,14 @@ namespace arg { void read(int phase) { curphase = phase; +#ifdef EXTRA_CONFIG + extra::config(); +#endif while(argc) { int r; r = readCommon(); if(r == 2) return; if(r == 0) { lshift(); continue; } -#ifdef LOCAL - r = readLocal(); if(r == 2) return; if(r == 0) { lshift(); continue; } +#ifdef EXTRA_ARG + r = extra::arg(); if(r == 2) return; if(r == 0) { lshift(); continue; } #endif #ifdef ROGUEVIZ r = rogueviz::readArgs(); if(r == 2) return; if(r == 0) { lshift(); continue; } diff --git a/hyper.h b/hyper.h index 14fed305..19c6162f 100644 --- a/hyper.h +++ b/hyper.h @@ -251,6 +251,7 @@ int darkened(int c); extern int getcstat; bool displaychr(int x, int y, int shift, int size, char chr, int col); bool displayfr(int x, int y, int b, int size, const string &s, int color, int align); +bool displayfrSP(int x, int y, int sh, int b, int size, const string &s, int color, int align, int p); bool outofmap(hyperpoint h); void applymodel(hyperpoint H, hyperpoint& Hscr); @@ -262,6 +263,7 @@ void resetview(); extern heptspin viewctr; extern cell *centerover; void drawthemap(); void drawfullmap(); bool displaystr(int x, int y, int shift, int size, const char *str, int color, int align); +bool displaystr(int x, int y, int shift, int size, const string& str, int color, int align); extern int darken; void calcparam(); @@ -322,7 +324,14 @@ struct videopar { float scrdist; bool usingGL; - bool usingAA; + int antialias; + #define AA_NOGL 1 + #define AA_VERSION 2 + #define AA_LINES 4 + #define AA_POLY 8 + #define AA_LINEWIDTH 16 + #define AA_FONT 32 + ld linewidth; int joyvalue, joyvalue2, joypanthreshold; ld joypanspeed; @@ -344,7 +353,7 @@ extern videopar vid; enum emtype {emNormal, emHelp, emMenu, - emVisual1, emVisual2, + emBasicConfig, emGraphConfig, emDisplayMode, emChangeMode, emCustomizeChar, emQuit, emDraw, emScores, emPickEuclidean, emPickScores, @@ -360,7 +369,9 @@ enum emtype {emNormal, emHelp, emJoyConfig, emColor, emNumber, em3D, emRogueviz, - emLinepattern + emLinepattern, + emPeace, emInventory, + emSlideshows }; extern emtype cmode, lastmode; @@ -704,6 +715,7 @@ template struct dynamicval { T& where; T backup; dynamicval(T& wh, T val) : where(wh) { backup = wh; wh = val; } + dynamicval(T& wh) : where(wh) { backup = wh; } ~dynamicval() { where = backup; } }; @@ -790,6 +802,7 @@ namespace dialog { int color, colorv, colork, colors, colorc; int scale; double param; + int position; }; item& lastItem(); @@ -801,7 +814,7 @@ namespace dialog { void addHelp(string body); void addInfo(string body, int color = 0xC0C0C0); void addItem(string body, int key); - void addBreak(int val); + int addBreak(int val); void addTitle(string body, int color, int scale); void init(); @@ -947,6 +960,9 @@ void ShadowV(const transmatrix& V, const struct hpcshape& bp, int prio = PPR_MON #define OUTLINE_OTHER 0xFFFFFFFF #define OUTLINE_DEAD 0x800000FF #define OUTLINE_TRANS 0 +#define OUTLINE_DEFAULT ((bordcolor << 8) + 0xFF) +#define OUTLINE_FORE ((forecolor << 8) + 0xFF) +#define OUTLINE_BACK ((backcolor << 8) + 0xFF) extern bool audio; extern string musiclicense; @@ -1023,7 +1039,7 @@ extern cell *recallCell; extern eLand cheatdest; void cheatMoveTo(eLand l); -extern int backcolor; +extern int backcolor, bordcolor, forecolor; extern bool overgenerate; void doOvergenerate(); @@ -1131,6 +1147,7 @@ namespace tour { extern bool on; extern string tourhelp; extern string slidecommand; + extern int currentslide; bool handleKeyTour(int sym, int uni); @@ -1167,9 +1184,18 @@ namespace tour { static const int LEGAL_NONEUC=4; static const int QUICKSKIP=8; static const int FINALSLIDE=16; + static const int QUICKGEO=32; + static const int SIDESCREEN = 64; extern slide slideHypersian; extern slide slideExpansion; + + namespace ss { + void showMenu(); + void handleKey(int sym, int uni); + void list(slide*); + } + }; #endif @@ -1184,10 +1210,8 @@ namespace rogueviz { extern bool doCross; void optimizeview(); -#ifndef NOPNG extern int pngres; extern int pngformat; -#endif extern bool noGUI; extern bool dronemode; @@ -1211,7 +1235,8 @@ namespace linepatterns { patPower, patNormal, patTrihepta, - patBigTriangles + patBigTriangles, + patBigRings }; void clearAll(); @@ -1242,3 +1267,26 @@ void displaymm(char c, int x, int y, int rad, int size, const string& title, int bool canPushThumperOn(cell *tgt, cell *thumper, cell *player); void pushThumper(cell *th, cell *cto); + +template T pick(T x, T y) { return hrand(2) ? x : y; } +template T pick(T x, T y, T z) { switch(hrand(3)) { case 0: return x; case 1: return y; case 2: return z; } return x; } +template T pick(T x, T y, T z, T v) { switch(hrand(4)) { case 0: return x; case 1: return y; case 2: return z; case 3: return v; } return x; } + +eLand getNewSealand(eLand old); +bool createOnSea(eLand old); + +namespace inv { + bool on; + } + +bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks, bool hidden); + +void initquickqueue(); +void quickqueue(); +int darkenedby(int c, int lev); +extern int mousex, mousey; +string generateHelpForItem(eItem it); +bool graphglyph(); +extern bool hiliteclick; +extern int antialiaslines; +extern int ringcolor; diff --git a/hyper.rc b/hyper.rc index a477bc8e..acdac4a4 100644 --- a/hyper.rc +++ b/hyper.rc @@ -1,8 +1,8 @@ id ICON "hr-icon.ico" 1 VERSIONINFO -FILEVERSION 9,4,0,14 -PRODUCTVERSION 9,4,0,14 +FILEVERSION 9,4,0,15 +PRODUCTVERSION 9,4,0,15 BEGIN BLOCK "StringFileInfo" BEGIN @@ -10,12 +10,12 @@ BEGIN BEGIN VALUE "CompanyName", "Zeno Rogue" VALUE "FileDescription", "A roguelike in non-euclidean space" - VALUE "FileVersion", "94n" + VALUE "FileVersion", "94n1" VALUE "InternalName", "hyper" VALUE "LegalCopyright", "Zeno Rogue" VALUE "OriginalFilename", "hyper.exe" VALUE "ProductName", "HyperRogue" - VALUE "ProductVersion", "9.4n" + VALUE "ProductVersion", "9.4n1" END END diff --git a/init.cpp b/init.cpp index 3c71260c..60040dfd 100644 --- a/init.cpp +++ b/init.cpp @@ -1,6 +1,6 @@ -#define VER "9.4n" -#define VERNUM 9414 -#define VERNUM_HEX 0x9414 +#define VER "9.4n1" +#define VERNUM 9415 +#define VERNUM_HEX 0x9415 #define GEN_M 0 #define GEN_F 1 @@ -40,7 +40,9 @@ #define GFX #endif +#ifndef NOGL #define GL +#endif #define PSEUDOKEY_WHEELDOWN 2501 #define PSEUDOKEY_WHEELUP 2502 @@ -53,6 +55,8 @@ #define NOPNG #endif +// #define INV + #ifndef MOBILE #ifndef NOAUDIO #define SDLAUDIO @@ -72,6 +76,10 @@ bool buttonclicked; void gdpush(int t); #endif +#ifndef HYPERPATH +#define HYPERPATH "" +#endif + #include #ifdef NOSDL @@ -151,7 +159,11 @@ typedef int SDL_Event; #ifdef GL -#ifdef WINDOWS +#ifdef MAC +#define AVOID_GLEW +#endif + +#ifndef AVOID_GLEW #include #else #define GL_GLEXT_PROTOTYPES 1 @@ -251,6 +263,9 @@ const char *loadlevel = NULL; #include "game.cpp" #include "landgen.cpp" #include "orbs.cpp" +#ifdef INV +#include "inventory.cpp" +#endif #include "system.cpp" #include "geometry.cpp" #include "polygons.cpp" @@ -258,6 +273,9 @@ const char *loadlevel = NULL; #ifndef MOBILE #include "netgen.cpp" #endif +#ifdef EXTRA +#include "extra/extra.cpp" +#endif #include "graph.cpp" #include "sound.cpp" #include "achievement.cpp" @@ -592,7 +610,7 @@ void mobile_draw(MOBPAR_FORMAL) { displayTexts(); #endif - if((cmode != emVisual1 && cmode != emScores)) { + if((cmode != emBasicConfig && cmode != emScores)) { if(clicked && lclicked && andmode == 1 && !inmenu) { if(!mouseout2() && mouseoh[2] < 50 && mouseh[2] < 50) { @@ -646,3 +664,35 @@ void mobile_draw(MOBPAR_FORMAL) { #ifdef NOAUDIO void playSound(cell*, const string &s, int vol) { printf("play sound: %s vol %d\n", s.c_str(), vol); } #endif + +// optional hooks +// you may include hyper.cpp from another file and define EXTRA_... to change some things +namespace extra { + + // on drawing cells + void drawcell(cell *c, const transmatrix& V); + + // on each frame + void frame(); + + // on stats drawing + void stats(); + + // return true if key is handled + bool handleKey(int sym, int uni); + + // return true to exit immediately + bool main(int argc, char **argv); + + // extra configuration, called together with reading arguments + void config(); + + // read command line arguments + int arg(); + + // change land distribution + eLand getNext(eLand old); + + // change musics + bool changeMusic(eLand id); + } diff --git a/kohonen.cpp b/kohonen.cpp index e5561603..6b8d8694 100644 --- a/kohonen.cpp +++ b/kohonen.cpp @@ -379,7 +379,9 @@ void ksave(const char *fname) { FILE *f = fopen(fname, "wt"); fprintf(f, "%d %d\n", cells, t); for(neuron& n: net) { - for(int k=0; k= 60 && items[itRuby] >= 10; + return gold() >= R60 && items[itRuby] >= U10; case laStorms: case laWhirlwind: - return gold() >= 60; + return gold() >= R60; case laWildWest: case laHalloween: return false; @@ -627,49 +636,49 @@ bool landUnlocked(eLand l) { case laMirror: case laMinefield: case laPalace: case laOcean: case laLivefjord: - return gold() >= 30; + 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() >= 60; + return gold() >= R60; case laDeadCaves: - return gold() >= 60 && items[itGold] >= 10; + return gold() >= R60 && items[itGold] >= U10; case laGraveyard: - return tkills() >= 100; + return tkills() >= R100; case laHive: - return tkills() >= 100 && gold() >= 60; + return tkills() >= R100 && gold() >= R60; case laRedRock: - return gold() >= 60 && items[itSpice] >= 10; + return gold() >= R60 && items[itSpice] >= U10; case laEmerald: - return (items[itFernFlower] >= 5 && items[itGold] >= 5) || kills[moVizier]; + return (items[itFernFlower] >= U5 && items[itGold] >= U5) || kills[moVizier]; case laCamelot: - return items[itEmerald] >= 5; + return items[itEmerald] >= U5; case laHell: case laCrossroads3: return hellUnlocked(); case laPower: - return items[itHell] >= 10; + return items[itHell] >= U10; case laCocytus: - return items[itHell] >= 10 && items[itDiamond] >= 10; + return items[itHell] >= U10 && items[itDiamond] >= U10; case laTemple: - return items[itStatue] >= 5; + return items[itStatue] >= U5; case laClearing: - return items[itMutant] >= 5; + return items[itMutant] >= U5; - case laIvoryTower: return gold() >= 30; - case laZebra: return gold() >= 30 && items[itFeather] >= 10; + 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(); @@ -678,52 +687,52 @@ bool landUnlocked(eLand l) { return false; case laHaunted: case laHauntedWall: case laHauntedBorder: - return items[itBone] >= 10; + return items[itBone] >= U10; case laPrincessQuest: return kills[moVizier] && !shmup::on && multi::players == 1; case laRose: - return gold() >= 60; + return gold() >= R60; case laWarpCoast: case laWarpSea: - return gold() >= 30; + return gold() >= R30; case laCrossroads4: - return gold() >= 200; + return gold() >= R200; case laEndorian: - return items[itIvory] >= 10; + return items[itIvory] >= U10; case laTortoise: return tortoise::seek(); case laDragon: - return killtypes() >= 20; + return killtypes() >= R20; case laKraken: - return items[itFjord] >= 10; + return items[itFjord] >= U10; case laBurial: - return items[itKraken] >= 10; + return items[itKraken] >= U10; case laTrollheim: return trollUnlocked(); case laDungeon: - return items[itPalace] >= 5 && items[itIvory] >= 5; + return items[itPalace] >= U5 && items[itIvory] >= U5; case laMountain: - return items[itRuby] >= 5 && items[itIvory] >= 5; + return items[itRuby] >= U5 && items[itIvory] >= U5; case laReptile: - return gold() >= 30 && items[itElixir] >= 10; + return gold() >= R30 && items[itElixir] >= U10; case laPrairie: case laBull: - return gold() >= 90; + return gold() >= R90; case laCrossroads5: - return gold() >= 300; + return gold() >= R300; } return false; } @@ -731,7 +740,7 @@ bool landUnlocked(eLand l) { int orbsUnlocked() { int i = 0; for(int t=0; t= 10) + if(itemclass(eItem(t)) == IC_TREASURE && items[t] >= R10) i++; return i; } @@ -745,7 +754,7 @@ void countHyperstoneQuest(int& i1, int& i2) { for(int t=1; t= 10) i1++; + i2++; if(items[t] >= R10) i1++; } } @@ -991,12 +1000,14 @@ ld orbprizefun(int tr) { } ld orbcrossfun(int tr) { + if(inv::on) return tr >= 50 ? 1 : 0; 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) @@ -1008,6 +1019,7 @@ bool buildPrizeMirror(cell *c, int freq) { void placePrizeOrb(cell *c) { eLand l = c->land; if(isElemental(l)) l = laElementalWall; + if(peace::on) return; // these two lands would have too much orbs according to normal rules if(l == laPalace && hrand(100) >= 20) return; @@ -1021,6 +1033,7 @@ void placePrizeOrb(cell *c) { l = laPrincessQuest; for(int i=0; iwall == waTrapdoor) return; if(isGravityLand(l) && cellEdgeUnstable(c)) return; if(isElemental(l)) l = laElementalWall; + if(peace::on) return; for(int i=0; itype; i++) describeCell(c->mov[i]); @@ -1547,10 +1565,6 @@ eLand pickluck(eLand l1, eLand l2) { #define LIKELY for(int u=0; u<5; u++) -template T pick(T x, T y) { return hrand(2) ? x : y; } -template T pick(T x, T y, T z) { switch(hrand(3)) { case 0: return x; case 1: return y; case 2: return z; } return x; } -template T pick(T x, T y, T z, T v) { switch(hrand(4)) { case 0: return x; case 1: return y; case 2: return z; case 3: return v; } return x; } - bool noChaos(eLand l) { if(l == laOcean || l == laTemple) return false; return @@ -1563,6 +1577,7 @@ 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; @@ -1574,52 +1589,34 @@ bool doEndorian = false; int whichnow=0; +bool createOnSea(eLand old) { + return + old == laWarpSea || old == laCaribbean || old == laKraken || + (old == laLivefjord && hrand(2)) || + (old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant)); + } + eLand getNewLand(eLand old) { - /* eLand landtab[10] = { - laWhirlwind, laRose, laEndorian, laRlyeh, - laPalace, laOcean, laEmerald, laStorms, - laGraveyard, laAlchemist - }; */ - - // return landtab[items[itStrongWind]++ % 10]; - // if(old != laPrairie) return laRiver; +#ifdef EXTRA_NEWLAND + if(true) { + eLand l = extra::getNext(old); + if(l) return l; + } +#endif #ifdef TOUR if(tour::on) { eLand l = tour::getNext(old); if(l) return l; } + + if(peace::on) { + eLand l = peace::getNext(old); + if(l) return l; + } #endif -#ifdef LOCAL - extern bool doAutoplay; - if(doAutoplay) - return pick(laOcean, laLivefjord, laWarpSea, laWarpCoast); - extern bool doCross; - if(doCross) { - whichnow++; - eLand tabb[30] = { -/* laIce, laRedRock, laCaribbean, laWarpCoast, laWhirlwind, laPower, - laMirror, laPalace, laLivefjord, laAlchemist, laCocytus, - laHell, laJungle, laCaves, laDesert, laRlyeh, laStorms, - laGraveyard, laMotion, laDryForest, laDragon, laZebra, laIvoryTower, - laTrollheim, laOvergrown, laBurial, laRose, laHive, laEmerald, - laEmerald */ - laIce, laPalace, laDryForest, laRedRock, laWhirlwind, - laAlchemist, laWarpCoast, laOvergrown, - laEmerald, laWhirlwind, - laIce, laRedRock, laWarpCoast, laPalace, laWhirlwind, - laAlchemist, laDryForest, laOvergrown, - laEmerald, laDesert, - laIce, laRedRock, laWarpCoast, laPalace, laWhirlwind, - laAlchemist, laDryForest, laOvergrown, - laEmerald, laDesert, - }; - return tabb[whichnow%30]; - } -#endif - if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest; if(old == laTortoise) return laDragon; @@ -1673,15 +1670,13 @@ eLand getNewLand(eLand old) { if(isWarped(old) && (hrand(100) < 25) && chaosmode) return eLand(old ^ laWarpCoast ^ laWarpSea); - if(old == laWarpSea || old == laCaribbean || old == laKraken || - (old == laLivefjord && hrand(2)) || - (old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant))) + if(createOnSea(old)) return getNewSealand(old); - + if(old == laGraveyard && generatingEquidistant) return laHaunted; - if(old == laOcean && gold() >= 60 && hrand(100) < 75 && !rlyehComplete()) + if(old == laOcean && gold() >= R60 && hrand(100) < 75 && !rlyehComplete()) return laRlyeh; if(old == laRlyeh && !rlyehComplete()) @@ -1708,7 +1703,7 @@ eLand getNewLand(eLand old) { if(old != laDeadCaves) tab[cnt++] = laCaves; // the intermediate lands - if(gold() >= 30) { + if(gold() >= R30) { tab[cnt++] = laCrossroads; tab[cnt++] = laMirror; tab[cnt++] = laOcean; @@ -1717,15 +1712,15 @@ eLand getNewLand(eLand old) { tab[cnt++] = laPalace; if(old == laDragon) LIKELY tab[cnt++] = laReptile; if(kills[moVizier]) tab[cnt++] = laEmerald; - if(items[itFeather] >= 10) tab[cnt++] = laZebra; + 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] >= 10) tab[cnt++] = laReptile; - if(items[itIvory] >= 10 && !generatingEquidistant) tab[cnt++] = laEndorian; + if(items[itElixir] >= U10) tab[cnt++] = laReptile; + if(items[itIvory] >= U10 && !generatingEquidistant) tab[cnt++] = laEndorian; - if(items[itKraken] >= 10) tab[cnt++] = laBurial; + if(items[itKraken] >= U10) tab[cnt++] = laBurial; } if(landUnlocked(laDungeon)) { @@ -1734,29 +1729,29 @@ eLand getNewLand(eLand old) { } // the advanced lands - if(gold() >= 60) { + if(gold() >= R60) { tab[cnt++] = laStorms; tab[cnt++] = laWhirlwind; tab[cnt++] = laCrossroads; if(!generatingEquidistant) tab[cnt++] = laCrossroads2; - if(items[itRuby] >= 10) { + 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] >= 5 && chaosmode) + 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] >= 5 && items[itFernFlower] >= 5 && !kills[moVizier]) + if(items[itGold] >= U5 && items[itFernFlower] >= U5 && !kills[moVizier]) tab[cnt++] = laEmerald; tab[cnt++] = laDryForest; tab[cnt++] = laWineyard; - if(items[itGold] >= 10) tab[cnt++] = laDeadCaves; + if(items[itGold] >= U10) tab[cnt++] = laDeadCaves; // tab[cnt++] = laCaribbean; - if(items[itSpice] >= 10) { + if(items[itSpice] >= U10) { tab[cnt++] = laRedRock; if(old == laDesert) LIKELY tab[cnt++] = laRedRock; } @@ -1765,22 +1760,22 @@ eLand getNewLand(eLand old) { tab[cnt++] = laRose; } - if(gold() >= 90) { + 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() >= 300) + if(gold() >= R300) tab[cnt++] = laCrossroads5; - if(tkills() >= 100) { + if(tkills() >= R100) { tab[cnt++] = laGraveyard; - if(gold() >= 60) tab[cnt++] = laHive; + if(gold() >= R60) tab[cnt++] = laHive; } - if(killtypes() >= 20) { + if(killtypes() >= R20) { tab[cnt++] = laDragon; if(old == laReptile) LIKELY tab[cnt++] = laDragon; } @@ -1815,8 +1810,8 @@ eLand getNewLand(eLand old) { tab[cnt++] = laHell; } - if(items[itHell] >= 10) { - if(items[itDiamond] >= 10) { + if(items[itHell] >= U10) { + if(items[itDiamond] >= U10) { tab[cnt++] = laCocytus; if(old == laHell || old == laIce) LIKELY tab[cnt++] = laCocytus; } @@ -1839,6 +1834,7 @@ eLand getNewLand(eLand old) { } bool notDippingFor(eItem i) { + if(peace::on) return false; int v = items[i] - currentLocalTreasure; if(v <= 10) return true; if(v >= 20) return false; @@ -1846,6 +1842,7 @@ bool notDippingFor(eItem i) { } bool notDippingForExtra(eItem i, eItem x) { + if(peace::on) return false; int v = items[i] - min(items[x], currentLocalTreasure); if(v <= 10) return true; if(v >= 20) return false; @@ -1932,25 +1929,28 @@ eLand showlist[10] = { laHell, laRlyeh, laAlchemist, laGraveyard, laCaves, laDesert, laIce, laJungle, laMotion, laMirror }; +void buildBarrierForce(cell *c, int d, eLand l) { + c->bardir = d; + eLand oldland = c->land; + if(oldland == laNone) { + raiseBuggyGeneration(c, "oldland is NONE"); + return; + } + eLand newland = l ? l : getNewLand(oldland); + if(showoff) newland = showlist[(showid++) % 10]; + landcount[newland]++; + if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland; + else c->barleft = newland, c->barright = oldland; + c->landparam = 40; + extendcheck(c); + } + void buildBarrier(cell *c, int d, eLand l) { d %= 7; cellwalker bb(c, d); - if(checkBarriersFront(bb) && checkBarriersBack(bb)) { - c->bardir = d; - eLand oldland = c->land; - if(oldland == laNone) { - raiseBuggyGeneration(c, "oldland is NONE"); - return; - } - eLand newland = l ? l : getNewLand(oldland); - if(showoff) newland = showlist[(showid++) % 10]; - landcount[newland]++; - if(d == 4 || d == 5 || d == 6) c->barleft = oldland, c->barright = newland; - else c->barleft = newland, c->barright = oldland; - c->landparam = 40; - extendcheck(c); - } + if(checkBarriersFront(bb) && checkBarriersBack(bb)) + buildBarrierForce(c, d, l); } bool buildBarrier4(cell *c, int d, int mode, eLand ll, eLand lr) { @@ -2138,21 +2138,13 @@ extern bool bugtrack; bool generatingEquidistant = false; -void buildAnotherEquidistant(cell *c) { - //printf("building another coast\n"); - - if(yendor::on) return; - +cell *buildAnotherEquidistant(cell *c, int radius) { int gdir = -1; for(int i=0; itype; i++) { if(c->mov[i] && c->mov[i]->mpdist < c->mpdist) gdir = i; } - if(gdir == -1) return; + if(gdir == -1) return NULL; - generatingEquidistant = true; - - int radius = c->land == laOcean ? 30 : HAUNTED_RADIUS + 5; - cellwalker cw(c, (gdir+3) % c->type); vector coastpath; while(size(coastpath) < radius || cw.c->type != 7) { @@ -2161,13 +2153,10 @@ void buildAnotherEquidistant(cell *c) { #ifdef AUTOPLAY if(doAutoplay) printf("avoiding the Crossroads II\n"); // todo #endif - generatingEquidistant = false; - return; - } - if(cw.c->bardir != NODIR) { - generatingEquidistant = false; - return; + return NULL; } + if(cw.c->bardir != NODIR) return NULL; + /* forCellEx(c2, cw.c) if(c2->bardir != NODIR) { generatingEquidistant = false; return; @@ -2176,21 +2165,21 @@ void buildAnotherEquidistant(cell *c) { if(cw.c->land == laNone && cw.c->mpdist <= 7) { raiseBuggyGeneration(cw.c, "landNone 1"); for(int i=0; iitem = itPirate; - return; + return NULL; } cwstep(cw); cwspin(cw, 3); if(cw.c->type == 7 && hrand(2) == 0) cwspin(cw, 1); } - int mpd[10]; - for(int i=0; i<10; i++) mpd[i] = coastpath[i]->mpdist; coastpath.push_back(cw.c); // printf("setdists\n"); for(int i=1; iland == laNone) { raiseBuggyGeneration(cwt.c, "landNone 3"); + int mpd[10]; + for(int i=0; i<10; i++) mpd[i] = coastpath[i]->mpdist; {for(int i=0; i<10; i++) printf("%d ", mpd[i]);} printf("\n"); for(int i=0; iitem = itPirate; - return; + return NULL; } setdist(coastpath[i], BARLEV, coastpath[i-1]); setdist(coastpath[i], BARLEV-1, coastpath[i-1]); @@ -2210,16 +2199,14 @@ void buildAnotherEquidistant(cell *c) { if(c2->land == laNone) { raiseBuggyGeneration(c2, "landNone 2"); for(int i=0; iitem = itPirate; - return; + return NULL; } - if(c2->land != c->land) { - generatingEquidistant = false; - return; // prevent gravity anomalies - } + // prevent gravity anomalies + if(c2->land != c->land) return NULL; // else if(c->type == 7 && hrand(10000) < 20 && !isCrossroads(c->land) && gold() >= 200) - if(c2->type == 7 && gold() >= 200 && hrand(10) < 2 && buildBarrierNowall(c2, laCrossroads4, true)) { + if(c2->type == 7 && gold() >= R200 && hrand(10) < 2 && buildBarrierNowall(c2, laCrossroads4, true)) { nowall = true; // raiseBuggyGeneration(c2, "check"); // return; @@ -2232,7 +2219,21 @@ void buildAnotherEquidistant(cell *c) { for(int j=BARLEV; j>=6; j--) setdist(coastpath[i], j, NULL); } + + return c2; + } +void buildAnotherEquidistant(cell *c) { + //printf("building another coast\n"); + + if(yendor::on) return; + + generatingEquidistant = true; + + int radius = c->land == laOcean ? 30 : HAUNTED_RADIUS + 5; + + buildAnotherEquidistant(c, radius); + generatingEquidistant = false; } @@ -2279,7 +2280,11 @@ eMonster crossroadsMonster() { moWaterElemental, moAirElemental, moFireElemental, moFatGuard, moMiner, moPalace, moVizier }; - return m[hrand(24)]; + 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() { @@ -2535,7 +2540,7 @@ void buildRedWall(cell *c, int gemchance) { c->wall = waRed3; if(hrand(100+ki) < gemchance + ki) c->item = itRedGem; - if(items[itRedGem] >= 10 && hrand(8000) < gemchance) + if(items[itRedGem] >= 10 && hrand(8000) < gemchance && !peace::on && !inv::on) c->item = itOrbSpace; else if(hrand(8000) < gemchance * PRIZEMUL) placePrizeOrb(c); @@ -2876,7 +2881,7 @@ void buildBigStuff(cell *c, cell *from) { else if(c->type == 7 && c->land == laCrossroads4 && hrand(10000) < 7000 && c->land && buildBarrierNowall(c, getNewLand(laCrossroads4))) ; - else if(c->type == 7 && hrand(10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= 200 && + else if(c->type == 7 && hrand(10000) < 20 && !generatingEquidistant && !yendor::on && !tactic::on && !isCrossroads(c->land) && gold() >= R200 && !isSealand(c->land) && !isHaunted(c->land) && !isGravityLand(c->land) && (c->land != laRlyeh || rlyehComplete()) && c->land != laTortoise && c->land != laPrairie && c->land && @@ -2936,8 +2941,8 @@ void buildBigStuff(cell *c, cell *from) { } if((!chaosmode) && bearsCamelot(c->land) && c->type == 7 && - (quickfind(laCamelot) || (hrand(2000) < 200 && - items[itEmerald] >= 5 && !tactic::on))) { + (quickfind(laCamelot) || peace::on || (hrand(2000) < 200 && + items[itEmerald] >= U5 && !tactic::on))) { int rtr = newRoundTableRadius(); heptagon *alt = createAlternateMap(c, rtr+14, hsOrigin); if(alt) { @@ -2951,8 +2956,8 @@ void buildBigStuff(cell *c, cell *from) { // buildbigstuff if(c->land == laRlyeh && c->type == 7 && - (quickfind(laTemple) || (hrand(2000) < 100 && - items[itStatue] >= 5 && !randomPatternsMode && + (quickfind(laTemple) || peace::on || (hrand(2000) < 100 && + items[itStatue] >= U5 && !randomPatternsMode && !tactic::on && !yendor::on))) createAlternateMap(c, 2, hsA); @@ -2963,7 +2968,7 @@ void buildBigStuff(cell *c, cell *from) { if(c->land == laOvergrown && c->type == 7 && (quickfind(laClearing) || (hrand(2000) < 25 && - !randomPatternsMode && items[itMutant] >= 5 && + !randomPatternsMode && items[itMutant] >= U5 && !tactic::on && !yendor::on))) { heptagon *h = createAlternateMap(c, 2, hsA); if(h) clearing::bpdata[h].root = NULL; @@ -2974,7 +2979,7 @@ void buildBigStuff(cell *c, cell *from) { if(h) h->alt->emeraldval = hrand(2); } - if(c->land == laOcean && c->type == 7 && deepOcean && !generatingEquidistant && + if(c->land == laOcean && c->type == 7 && deepOcean && !generatingEquidistant && !peace::on && (quickfind(laWhirlpool) || ( hrand(2000) < (purehepta ? 500 : 1000) && !tactic::on && !yendor::on))) createAlternateMap(c, 2, hsA); @@ -2983,9 +2988,10 @@ void buildBigStuff(cell *c, cell *from) { createAlternateMap(c, 2, hsA); if(c->land == laPalace && c->type == 7 && !princess::generating && !shmup::on && multi::players == 1 && - (princess::forceMouse ? (from && from->pathdist != INF) : (hrand(2000) < 20)) && + (princess::forceMouse ? (from && from->pathdist != INF) : + (hrand(2000) < (peace::on ? 100 : 20))) && !c->master->alt && - (princess::challenge || kills[moVizier]) && !tactic::on && !yendor::on) + (princess::challenge || kills[moVizier] || peace::on) && !tactic::on && !yendor::on) createAlternateMap(c, 141, hsOrigin, waPalace); } @@ -3233,6 +3239,7 @@ bool redtrolls(cell *c) { } bool reptilecheat = false; +bool weaponless = false; eMonster pickTroll(cell *c) { if(redtrolls(c)) @@ -3450,6 +3457,8 @@ void setdist(cell *c, int d, cell *from) { cell *c2 = c->mov[hrand(c->type)]; if(c2->wall == waNone) c2->wall = waTrapdoor; } + + if((c->wall == waClosePlate || c->wall == waTrapdoor) && peace::on) c->wall = waNone; } if(d==8 && c->land == laEmerald) { @@ -3641,7 +3650,7 @@ void setdist(cell *c, int d, cell *from) { } if(c->land == laTrollheim) { - if(hrand(50000) < (chaosmode?1000:5) && c->wall != waBarrier && celldist(c) >= 7 && !safety) { + if(hrand(50000) < (chaosmode?1000:5) && c->wall != waBarrier && celldist(c) >= 7 && !safety && !peace::on) { bool okay = true; forCellCM(c2, c) forCellCM(c3, c2) forCellCM(c4, c3) forCellCM(c5, c4) { cell *cx = chaosmode ? c3 : c5; @@ -4252,7 +4261,7 @@ void setdist(cell *c, int d, cell *from) { c2->hitpoints = 1; c2->mondir = c->spn(i); } - playSound(c, "seen-kraken"); + if(!peace::on) playSound(c, "seen-kraken"); } } @@ -4282,7 +4291,7 @@ void setdist(cell *c, int d, cell *from) { if(d == 8 && c->land == laOvergrown) { if(hrand(doCross ?450:15000) < 20 + (2 * items[itMutant] + hard) && !safety) { - c->item = itMutant; + if(!peace::on) c->item = itMutant; c->landparam = items[itMutant] + 5 + hrand(11); c->wall = waNone; for(int i=0; itype; i++) @@ -4338,7 +4347,7 @@ void setdist(cell *c, int d, cell *from) { int depth = getHauntedDepth(c); - if(hrand(500 + depth) < depth - items[itLotus] && !safety) + if(hrand(500 + depth) < depth - items[itLotus] && !safety && !peace::on) c->item = itLotus; } } @@ -4373,7 +4382,7 @@ void setdist(cell *c, int d, cell *from) { } if(coast && hrand(10) < 5) { c->wall = waBoat; - if(items[itPirate] >= 10 && hrand(100) < 2 && !safety) + if(items[itPirate] >= 10 && hrand(100) < 2 && !safety && !peace::on && !inv::on) c->item = itOrbTime; else if(hrand(100) < 2*PRIZEMUL && !safety) placePrizeOrb(c); @@ -4384,7 +4393,7 @@ void setdist(cell *c, int d, cell *from) { c->monst = moSeep; if(d == 7 && c->land == laLivefjord && c->wall == waSea && hrand(5000) < 15 + items[itFjord] + hard && !safety) { - if(items[itFjord] >= 5 && hrand(100) < 20) + if(items[itFjord] >= 5 && hrand(100) < 20 && !peace::on) c->monst = moWaterElemental; else { c->monst = moViking; @@ -4401,7 +4410,7 @@ void setdist(cell *c, int d, cell *from) { c->item = itFjord; } - if(d == 7 && c->land == laLivefjord && items[itFjord] >= 10 && hrand(2000) < 2) + if(d == 7 && c->land == laLivefjord && items[itFjord] >= 10 && hrand(2000) < 2 && !peace::on && !inv::on) c->item = itOrbFish; if(d == 7 && c->land == laLivefjord && hrand(2000) < 2*PRIZEMUL) @@ -4444,13 +4453,13 @@ void setdist(cell *c, int d, cell *from) { else if((c->landparam >= 1 && c->landparam <= 25) || chaosmode) { if(hrand(1000) < 5) c->wall = waBoat; - if(hrand(1000) < PT(50 + kills[moAlbatross]/2, 150)) + if(hrand(1000) < PT(50 + kills[moAlbatross]/2, 150) && !peace::on) c->item = itCoast; if(hrand(15000) < 10 + 2 * items[itCoast] + 2 * hard) c->monst = moAlbatross; - if(items[itCoast] >= 10 && hrand(10000) < 5) + if(items[itCoast] >= 10 && hrand(10000) < 5 && !peace::on && !inv::on) c->item = itOrbAir; - else if(items[itCoast] >= 10 && hrand(10000) < 6) + else if(items[itCoast] >= 10 && hrand(10000) < 6 && !peace::on && !inv::on) c->item = itOrbEmpathy; if(hrand(10000) < 5*PRIZEMUL) placePrizeOrb(c); @@ -4539,13 +4548,13 @@ void setdist(cell *c, int d, cell *from) { if(hrand(5000) < minefreq) c->wall = waMineMine; - else if(hrand(5000) < tfreq && !safety) { + else if(hrand(5000) < tfreq && !safety && !peace::on) { c->item = itBombEgg; c->landparam = items[itBombEgg] + 5 + hrand(11); } else if(hrand(5000) < treas - 20 + yendor::hardness() && !safety) c->monst = moBomberbird; - else if(treas >= 10 && hrand(5000) < 10 && !safety) + else if(treas >= 10 && hrand(5000) < 10 && !safety && !peace::on && !inv::on) c->item = itOrbFriend; else if(hrand(5000) < 10*PRIZEMUL && !safety) placePrizeOrb(c); @@ -4665,7 +4674,7 @@ void setdist(cell *c, int d, cell *from) { else c->monst = moFamiliar; } - else if(c->landparam >= 14 && hrand(2000) < PT(50+kills[moGargoyle]+kills[moFamiliar], 150) && !cellEdgeUnstable(c) ) { + else if(c->landparam >= 14 && hrand(2000) < PT(50+kills[moGargoyle]+kills[moFamiliar], 150) && !cellEdgeUnstable(c) && !peace::on) { c->item = itIvory; } } @@ -4673,7 +4682,7 @@ void setdist(cell *c, int d, cell *from) { if(c->land == laDungeon) { int lp = c->landparam * c->landparam; if(lp > 100) lp = 100; - if(c->landparam >= 10 && hrand(20000) < 5*lp + items[itSlime] + hard && !cellEdgeUnstable(c)) { + if(c->landparam >= 10 && hrand(20000) < 5*lp + items[itSlime] + hard && !cellEdgeUnstable(c) && !peace::on) { c->monst = moSkeleton, c->hitpoints = 3; } else if(c->landparam >= 10 && hrand(50000) < lp/2 + items[itSlime] + hard) { @@ -4709,14 +4718,14 @@ void setdist(cell *c, int d, cell *from) { } if(c->land == laTortoise) { - if(hrand(4000) < 50 + items[itBabyTortoise]*2 + hard * 6 && !safety) { + if(hrand(4000) < (peace::on ? 750 : 50 + items[itBabyTortoise]*2 + hard * 6) && !safety) { c->monst = moTortoise; c->hitpoints = 3; } int chance = 50 + items[itBabyTortoise]*2; if(quickfind(laTortoise)) chance += 150; - if((tactic::on || euclid) && hrand(4000) < chance && !safety) { + if((tactic::on || euclid || peace::on) && hrand(4000) < chance && !safety) { c->item = itBabyTortoise; tortoise::babymap[c] = getBits(c) ^ tortoise::getRandomBits(); } @@ -4730,7 +4739,7 @@ void setdist(cell *c, int d, cell *from) { if(hrand(5000) < PT(100 + 2 * (kills[moPalace] + kills[moFatGuard] + kills[moVizier] + kills[moSkeleton]), 200) && notDippingFor(itPalace) && c->wall != waOpenGate && !lookingForPrincess0) c->item = itPalace; - if(items[itPalace] >= 10 && hrand(5000) < 16 && c->wall != waOpenGate) + if(items[itPalace] >= 10 && hrand(5000) < 16 && c->wall != waOpenGate && !inv::on && !peace::on) c->item = hrand(100) < 80 ? itOrbFrog : itOrbDiscord; if(hrand(5000) < 20*PRIZEMUL && c->wall != waOpenGate) placePrizeOrb(c); @@ -4806,7 +4815,7 @@ void setdist(cell *c, int d, cell *from) { if(hrand(5000) < PT(100 + 2 * (kills[moWorm] + kills[moDesertman]), 200) && notDippingFor(itSpice)) c->item = itSpice; if(hrand(8000) < 10 + 2 * (items[itSpice] + hard) && !c->monst) - c->monst = hrand(2) ? moWorm : moDesertman, + c->monst = (hrand(2) && !peace::on) ? moWorm : moDesertman, c->mondir = NODIR; } if(c->land == laRedRock) { @@ -4814,7 +4823,7 @@ void setdist(cell *c, int d, cell *from) { int i = -1; for(int t=0; t<6; t++) if(c->mov[t]->mpdist > c->mpdist && !pseudohept(c->mov[t])) i = t; - if(i != -1) { + if(i != -1 && !peace::on) { c->monst = moHexSnake; preventbarriers(c); int len = purehepta ? 2 : ROCKSNAKELENGTH; @@ -4853,7 +4862,7 @@ void setdist(cell *c, int d, cell *from) { else if((havewhat&HF_DRAGON) && items[itDragon] < 10) dchance = 5; - if(hrand(150000) < dchance && !c->monst && (!c->wall || c->wall == waChasm)) { + if(hrand(150000) < dchance && !c->monst && (!c->wall || c->wall == waChasm) && !peace::on) { havewhat |= HF_DRAGON; // printf("dragon generated with dchance = %d\n", dchance); vector possi; @@ -4887,7 +4896,7 @@ void setdist(cell *c, int d, cell *from) { else c2->mondir = NODIR; } } - if(!c->monst && !tactic::on && !yendor::on && !euclid && hrand(4000) < 10 && !safety) { + if(!c->monst && !tactic::on && !yendor::on && !peace::on && !euclid && hrand(4000) < 10 && !safety) { c->item = itBabyTortoise; tortoise::babymap[c] = getBits(c) ^ tortoise::getRandomBits(); } @@ -4918,7 +4927,7 @@ void setdist(cell *c, int d, cell *from) { } else if(hrand(5000) < 100 + elkills*3 && notDippingFor(itElemental)) c->item = localshard; - else if(hrand(5000) < 10 && items[itElemental] >= 10) + else if(hrand(5000) < 10 && items[itElemental] >= 10 && !inv::on && !peace::on) c->item = itOrbSummon; else if(hrand(5000) < 10*PRIZEMUL) placePrizeOrb(c); @@ -4939,7 +4948,7 @@ void setdist(cell *c, int d, cell *from) { c->stuntime = 7; } } - if(c->land == laBurial && !safety) { + if(c->land == laBurial && !safety && !peace::on) { if(hrand(15000) < 5 + 3 * items[itBarrow] + 4 * hard) c->monst = moDraugr; else if(hrand(5000) < 20 + (quickfind(laBurial) ? 40 : 0)) @@ -4956,7 +4965,7 @@ void setdist(cell *c, int d, cell *from) { int hardchance = items[itRuby] + hard; if(hardchance > 25) hardchance = 25; bool hardivy = hrand(100) < hardchance; - if(hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) + if((hardivy ? buildIvy(c, 1, 9) : buildIvy(c, 0, c->type)) && !peace::on) c->item = itRuby; } } @@ -5061,7 +5070,7 @@ void setdist(cell *c, int d, cell *from) { if(c->land == laRlyeh) { if(hrand(5000) < PT(30 + 2 * (kills[moCultist] + kills[moTentacle] + kills[moPyroCultist]), 100) && notDippingFor(itStatue)) c->item = itStatue; - if(hrand(8000) < 5 + items[itStatue] + hard && !c->monst) + if(hrand(8000) < 5 + items[itStatue] + hard && !c->monst && !peace::on) c->monst = moTentacle, c->item = itStatue, c->mondir = NODIR; else if(hrand(12000) < 5 + items[itStatue] + hard) c->monst = hrand(3) ? ((hrand(40) < items[itStatue]-25) ? moCultistLeader : moCultist) : moPyroCultist; @@ -5082,13 +5091,13 @@ void setdist(cell *c, int d, cell *from) { (euclid || c->master->alt) ? celldistAlt(c) : 10; // remember: d is negative if(chaosmode ? hrand(100) < 25 : d % TEMPLE_EACH == 0) { - if(hrand(5000) < 20 - 2*d && !c->monst) + if(hrand(5000) < 20 - 2*d && !c->monst && !peace::on) c->monst = moTentacle, c->mondir = NODIR; } else { // int d0 = d % TEMPLE_EACH; // if(d0<0) d0=-d0; - if(hrand(100) < 30) // && d0 != 1 && d0 != TEMPLE_EACH-1) + if(hrand(100) < (peace::on ? 15 : 30)) // && d0 != 1 && d0 != TEMPLE_EACH-1) c->wall = waBigStatue; else if(hrand(20000) < -d) c->monst = hrand(3) ? moCultist : moPyroCultist; @@ -5096,7 +5105,7 @@ void setdist(cell *c, int d, cell *from) { c->monst = moCultistLeader; else if(hrand(5000) < 250) c->item = itGrimoire; - else if(hrand(5000) < 10 && (chaosmode ? items[itGrimoire] >= 10 : -d > TEMPLE_EACH * 10)) + else if(hrand(5000) < 10 && (chaosmode ? items[itGrimoire] >= 10 : -d > TEMPLE_EACH * 10) && !peace::on && !inv::on) c->item = itOrbDragon; } } @@ -5116,7 +5125,7 @@ void setdist(cell *c, int d, cell *from) { c->item = itFernFlower; if(hrand(4000) < 40 + items[itFernFlower] + hard) c->monst = moHedge; - else if(hrand(8000) < 2 * items[itFernFlower] + hard) + else if(hrand(8000) < 2 * items[itFernFlower] + hard && !peace::on) c->monst = moFireFairy; } if(c->land == laHell) { @@ -5167,8 +5176,8 @@ void setdist(cell *c, int d, cell *from) { c->monst = eMonster(moBug0 + hrand(3)); */ } if(c->land == laCaribbean) { -// if(hrand(1500) < 60 && celldistAlt(c) <= -5) -// c->item = itCompass; + if(hrand(1500) < 4 && celldistAlt(c) <= -5 && peace::on) + c->item = itCompass; if(hrand(16000) < 40 + (items[itPirate] + hard)) c->monst = moPirate; } @@ -5227,6 +5236,7 @@ int getGhostTimer() { } int getGhostcount() { + if(peace::on) return 0; int t = getGhostTimer(); int ghostcount = 0; if(t > 80) ghostcount = (t-80 + hrand(20)) / 20; @@ -5383,12 +5393,12 @@ void wandering() { playSeenSound(c); continue; } - if(c->land == laLivefjord && wchance(items[itFjord], 80) && items[itFjord] >= 10 && canReachPlayer(c, moWaterElemental)) { + if(!peace::on && c->land == laLivefjord && wchance(items[itFjord], 80) && items[itFjord] >= 10 && canReachPlayer(c, moWaterElemental)) { c->monst = moWaterElemental; playSeenSound(c); continue; } - if(c->land == laKraken && ((sphere && !hrand(15)) || wchance(items[itKraken], 240)) && !pseudohept(c)) { + 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; @@ -5427,13 +5437,13 @@ void wandering() { c->monst = hrand(2) ? moWolf : moYeti; else if(c->land == laDesert && wchance(items[itSpice], 10)) - c->monst = hrand(10) ? moDesertman : moWorm; + 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) ? moRedTroll : moHexSnake; + c->monst = (hrand(10) || peace::on) ? moRedTroll : moHexSnake; else if(c->land == laCaves && wchance(items[itGold], 5)) c->monst = hrand(3) ? moTroll : moGoblin; @@ -5513,7 +5523,7 @@ void wandering() { 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)) + 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)) diff --git a/langen.cpp b/langen.cpp index 52e91fcc..6e62e895 100644 --- a/langen.cpp +++ b/langen.cpp @@ -39,21 +39,21 @@ dictionary nouns[NUMLAN]; #include +int utfsize(char c) { + unsigned char cu = c; + if(cu < 128) return 1; + if(cu < 224) return 2; + if(cu < 0xE0) return 3; + return 4; + } + void addutftoset(set& s, string& w) { int i = 0; //printf("%s\n", w.c_str()); while(i < size(w)) { - - if(((signed char)(w[i])) < 0) { - string z = w.substr(i, 2); -// printf("Insert: %s [%02x%02x]\n", z.c_str(), w[i], w[i+1]); - s.insert(w.substr(i, 2)); - i += 2; - } - else { - s.insert(w.substr(i, 1)); - i++; - } + int siz = utfsize(w[i]); + s.insert(w.substr(i, siz)); + i += siz; } } @@ -143,6 +143,8 @@ int main() { plural.insert("Elemental Planes"); plural.insert("Crossroads IV"); plural.insert("Kraken Depths"); + allchars.insert("ᵈ"); + allchars.insert("δ"); #define S(a,b) d[1].add(a,b); #define N(a,b,c,d,e,f) \ @@ -236,7 +238,7 @@ int main() { //printf("ALL:"); for(set::iterator it = allchars.begin(); it != allchars.end(); it++) { // printf(" \"%s\",", it->c_str()); - if(size(*it) == 2) { javastring += (*it); vchars.push_back(*it); c++; } + if(size(*it) >= 2) { javastring += (*it); vchars.push_back(*it); c++; } } printf("// DO NOT EDIT -- this file is generated automatically with langen\n"); printf("\n"); diff --git a/language-cz.cpp b/language-cz.cpp index 37bbe97b..f9fcf04c 100644 --- a/language-cz.cpp +++ b/language-cz.cpp @@ -265,7 +265,7 @@ S("You feel that you have enough treasure to access new lands!", "Cítíš, že S("Collect more treasures, there are still more lands waiting...", "Sbírej další poklady, další kraje stále čekají...") S("You feel that the stars are right, and you can access R'Lyeh!", "Cítíš, že postavení hvězd je správné, a ty můžeš vstoupit do R'Lyeh!") S("Kill monsters and collect treasures, and you may get access to Hell...", "Zabíjej netvory a sbírej poklady a možná najdeš cestu do Pekla...") -S("To access Hell, collect 10 treasures each of 9 kinds...", "Aby ses dostal do Pekla, sesbírej 10 pokladů od každého z 9 různých typů...") +S("To access Hell, collect %1 treasures each of 9 kinds...", "Aby ses dostal do Pekla, sesbírej %1 pokladů od každého z 9 různých typů...") S("Abandon all hope, the gates of Hell are opened!", "Zanech vší naděje, brány Pekla jsou otevřeny!") S("And the Orbs of Yendor await!", "A Yendorské sféry čekají!") S("You switch places with %the1.", "Vyměni%l0 sis místo s %abl1.") @@ -367,11 +367,11 @@ S("GAME OVER", "KONEC HRY") S("Your score: %1", "Tvé skóre: %1") S("Enemies killed: %1", "Zabitých netvorů: %1") S("Orbs of Yendor found: %1", "Nalezených Yendorských sfér: %1") -S("Collect 30 $$$ to access more worlds", "Další kraje zpřístupníš sesbíráním 30 $$$") -// S("Collect 60 $$$ to access R'Lyeh and Dry Forest", "R'Lyeh a Suchý hvozd zpřístupníš sesbíráním 60 $$$") -S("Collect at least 10 treasures in each of 9 types to access Hell", "Peklo zpřístupníš sesbíráním 10 pokladů od každého z 9 typů") +S("Collect %1 $$$ to access more worlds", "Další kraje zpřístupníš sesbíráním %1 $$$") +// S("Collect %1 $$$ to access R'Lyeh and Dry Forest", "R'Lyeh a Suchý hvozd zpřístupníš sesbíráním %1 $$$") +S("Collect at least %1 treasures in each of 9 types to access Hell", "Peklo zpřístupníš sesbíráním %1 pokladů od každého z 9 typů") S("Collect at least 10 Demon Daisies to find the Orbs of Yendor", "Yendorské sféry zpřístupníš sesbíráním nejméně 10 Čertových kvítek") -S("Hyperstone Quest: collect at least 10 %1 in %the2", "Hyperkamový úkol: sesbírej nejméně 10 pokladů %abl2") +S("Hyperstone Quest: collect at least %3 %1 in %the2", "Hyperkamový úkol: sesbírej nejméně %3 pokladů %abl2") S("Hyperstone Quest completed!", "Hyperkamový úkol splněn!") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Hledej Yendorské sféry v Pekle nebo na Křižovatce!") S("Unlock the Orb of Yendor!", "Odemkni Yendorskou sféru!") @@ -1009,7 +1009,7 @@ S("Periodic Editor", "Periodický editor") // also translate this line: // "Stiskem kláves 0-4 můžete různě přepínat zdi\n", -S("Collect 60 $$$ to access even more lands", "Sesbíráním 60 $$$ získáš přístup do dalších krajů") +S("Collect %1 $$$ to access even more lands", "Sesbíráním %1 $$$ získáš přístup do dalších krajů") // Emerald Mine // ------------ @@ -2530,8 +2530,8 @@ S("Accessible only from %the1 (until finished).\n", "Tento kraj je dostupný pou S("Accessible only from %the1 or %the2.\n", "Tento kraj je dostupný pouze skrz %a1 nebo %a2.\n") S("Kills required: %1.\n", "Potřebuješ zabít %1 nepřátel.\n") -S("Finished lands required: %1 (collect 10 treasure)\n", - "Potřebuješ dokončit %1 krajů (získat v nich 10 pokladů)\n") +S("Finished lands required: %1 (collect %2 treasure)\n", + "Potřebuješ dokončit %1 krajů (získat v nich %2 pokladů)\n") S("Treasure required: %1 x %2.\n", "Potřebuješ %1 x %2.\n") @@ -3821,8 +3821,8 @@ S( S("%The1 scares %the2 a bit!", "%1 trochu vyleka%l1 %a2!") S("%The1 attacks your shell!", "%1 zaútoči%l1 na tvůj krunýř!") -S("Hyperstone Quest: collect at least 10 points in %the2", - "Hyperkamový úkol: získej nejméně 10 bodů %abl2") +S("Hyperstone Quest: collect at least %3 points in %the2", + "Hyperkamový úkol: získej nejméně %3 bodů %abl2") S("animals killed: %1", "zabitých zvířat: %1") S("\n\nTortoises are not monsters! They are just annoyed. They do not count for your total kills.", @@ -5011,7 +5011,7 @@ N("Tortoise", GEN_F, "Želva", "Želvy", "Želva", "Želvou") S("line patterns", "vzory čar") S("1 turn", "1 kolo") S("%1 turns", "kola: %1") -S("items/kills mode", "mód předmětů/zabitých netvorů") +S("inventory/kill mode", "mód předmětů/zabitých netvorů") S("images", "obrázky") S("letters", "písmena") S("input", "vstup") diff --git a/language-de.cpp b/language-de.cpp index ce7bed5c..eb24bcd4 100644 --- a/language-de.cpp +++ b/language-de.cpp @@ -243,7 +243,7 @@ S("You feel that you have enough treasure to access new lands!", "Du spürst, da S("Collect more treasures, there are still more lands waiting...", "Sammle mehr Schätze, es warten weitere Länder auf dich...") S("You feel that the stars are right, and you can access R'Lyeh!", "Die Sterne stehen günstig, du kannst R´Lyeh erreichen!") S("Kill monsters and collect treasures, and you may get access to Hell...", "Wenn du Monster tötest und Schätze sammelst erhältst du vielleicht Zutritt zur Hölle...") -S("To access Hell, collect 10 treasures each of 9 kinds...", "Um die Hölle zu erreichen sammle je 10 von 9 verschiedenen Schätzen...") +S("To access Hell, collect %1 treasures each of 9 kinds...", "Um die Hölle zu erreichen sammle je %1 von 9 verschiedenen Schätzen...") S("Abandon all hope, the gates of Hell are opened!", "Gib jegliche Hoffnung auf, die Pforte der Hölle ist geöffnet!") S("And the Orbs of Yendor await!", "Und die Orbs von Yendor erwarten dich!") S("You switch places with %the1.", "Du tauschst den Platz mit %dem1 %a1.") @@ -334,10 +334,10 @@ S("GAME OVER", "GAME OVER") S("Your score: %1", "Punkte: %1") S("Enemies killed: %1", "Getötete Gegner: %1") S("Orbs of Yendor found: %1", "Orbs von Yendor gefunden: %1") -S("Collect 30 $$$ to access more worlds", "Sammle 30 $$$ um mehr Länder betreten zu können") -S("Collect at least 10 treasures in each of 9 types to access Hell", "Sammle 9 verschiedene Schätze mindestens 10x um Zugang zur Hölle zu erhalten") +S("Collect %1 $$$ to access more worlds", "Sammle %1 $$$ um mehr Länder betreten zu können") +S("Collect at least %1 treasures in each of 9 types to access Hell", "Sammle 9 verschiedene Schätze mindestens %1x um Zugang zur Hölle zu erhalten") S("Collect at least 10 Demon Daisies to find the Orbs of Yendor", "Sammle mindestens 10 Dämonenblümchen um die Orbs von Yendor zu finden") -S("Hyperstone Quest: collect at least 10 %1 in %the2", "Hyperstein-Herausforderung: Sammle 10 %P1 %a2") +S("Hyperstone Quest: collect at least %3 %1 in %the2", "Hyperstein-Herausforderung: Sammle %3 %P1 %a2") S("Hyperstone Quest completed!", "Hyperstein-Herausforderung abgeschlossen!") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Such die Orbs von Yendor in der Hölle oder auf den Kreuzungen!") S("Unlock the Orb of Yendor!", "Öffne den Orb von Yendor!") @@ -947,7 +947,7 @@ S("Periodic Editor", "Periodischer Editor") // "In the periodic editor, press 0-4 to switch walls in different ways\n", // "Im periodischen Editor kannst du 0-4 verwenden um die Wände zu verändern\n" -S("Collect 60 $$$ to access even more lands", "Sammle 60 $$$ um noch mehr Länder zu besuchen.") +S("Collect %1 $$$ to access even more lands", "Sammle %1 $$$ um noch mehr Länder zu besuchen.") // Emerald Mine @@ -2337,8 +2337,8 @@ S("Accessible only from %the1 (until finished).\n", "Nur von %der1 %a1 aus errei S("Accessible only from %the1 or %the2.\n", "Nur von %der1 %a1 oder %der %a2 aus erreichbar.\n") S("Kills required: %1.\n", "Benötigte Kills: %1.\n") -S("Finished lands required: %1 (collect 10 treasure)\n", - "Abgeschlossene Länder benötigt: %1 (sammle 10 Schätze)\n") +S("Finished lands required: %1 (collect %2 treasure)\n", + "Abgeschlossene Länder benötigt: %1 (sammle %2 Schätze)\n") S("Treasure required: %1 x %2.\n", "Benötigte Schätze: %1 x %2.\n") @@ -3427,7 +3427,8 @@ S("Dragon Scales are a prized material for armors. " "wie sie einen Drachen getötet haben.\n\n" "Drachenschuppen verschwinden nach 500 Zügen.") -S("Dragons are powerful monsters. They are slow, but evil, " +S( + "Dragons are powerful monsters. They are slow, but evil, " "and love to pick on creatures who are even slower than " "them. They must be stopped!\n\n" @@ -3438,8 +3439,8 @@ S("Dragons are powerful monsters. They are slow, but evil, " "The head will regenerate on the " "turns the Dragon is not moving, so you will usually have to hit it with " "your last attack; otherwise, if the head is healthy, it may breathe " - "fire (at range 3), losing the hitpoint. Killing the Dragon gives you " - "treasure.", + "fire (at range 3), losing the hitpoint. Killing the Dragon " + "while still in the Dragon Chasms gives you treasure.", "Drachen sind mächtige Monster. Sie sind langsam, aber böse, " "und lieben es Wesen zu schikanieren, die noch langsamer sind als sie. " @@ -3525,8 +3526,8 @@ S("Galápagos is the land of Tortoises. " S("%The1 scares %the2 a bit!", "%Der1 %1 ängstigt %den2 %a2 ein wenig!") S("%The1 attacks your shell!", "%Der1 %1 attackiert deinen Panzer!") -S("Hyperstone Quest: collect at least 10 points in %the2", - "Hyperstein-Herausforderung: sammle mindestens 10 Punkte %abl2") +S("Hyperstone Quest: collect at least %3 points in %the2", + "Hyperstein-Herausforderung: sammle mindestens %3 Punkte %abl2") S("animals killed: %1", "getötete Tiere: %1") S("\n\nTortoises are not monsters! They are just annoyed. They do not count for your total kills.", diff --git a/language-pl.cpp b/language-pl.cpp index 40886657..37d3e087 100644 --- a/language-pl.cpp +++ b/language-pl.cpp @@ -248,7 +248,7 @@ S("You feel that you have enough treasure to access new lands!", "Masz wystarcza S("Collect more treasures, there are still more lands waiting...", "Zbieraj skarby, nowe krainy czekają...") S("You feel that the stars are right, and you can access R'Lyeh!", "Gwiazdy są na miejscu, R'Lyeh czeka!") S("Kill monsters and collect treasures, and you may get access to Hell...", "Zabijaj potwory, zdobywaj skarby, może trafisz do Piekła...") -S("To access Hell, collect 10 treasures each of 9 kinds...", "By dostać się do Piekła, znajdź po 10 skarbów każdego z 9 rodzajów...") +S("To access Hell, collect %1 treasures each of 9 kinds...", "By dostać się do Piekła, znajdź po %1 skarbów każdego z 9 rodzajów...") S("Abandon all hope, the gates of Hell are opened!", "Porzuć wszelką nadzieję, bramy Piekła są otwarte!") S("And the Orbs of Yendor await!", "I sfery Yendoru czekają!") S("You switch places with %the1.", "Zamieniasz się miejscami z %abl1.") @@ -339,10 +339,10 @@ S("GAME OVER", "KONIEC GRY") S("Your score: %1", "Twój wynik: %1") S("Enemies killed: %1", "Potwory pokonane: %1") S("Orbs of Yendor found: %1", "Znalezione Sfery Yendoru: %1") -S("Collect 30 $$$ to access more worlds", "Znajdź 30 $$$, by iść do nowych krain") -S("Collect at least 10 treasures in each of 9 types to access Hell", "Znajdź po 10 skarbów w 9 typach, by się dostać do Piekła") +S("Collect %1 $$$ to access more worlds", "Znajdź %1 $$$, by iść do nowych krain") +S("Collect at least %1 treasures in each of 9 types to access Hell", "Znajdź po %1 skarbów w 9 typach, by się dostać do Piekła") S("Collect at least 10 Demon Daisies to find the Orbs of Yendor", "Znajdź 10 Czarciego Ziela, by znaleźć Sfery Yendoru") -S("Hyperstone Quest: collect at least 10 %1 in %the2", "Misja alternatywna: znajdź co najmniej 10 skarbów %abl2") +S("Hyperstone Quest: collect at least %3 %1 in %the2", "Misja alternatywna: znajdź co najmniej %3 skarbów %abl2") S("Hyperstone Quest completed!", "Misja alternatywna zakończona!") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Szukaj Sfer Yendoru w Piekle albo na Skrzyżowaniu!") S("Unlock the Orb of Yendor!", "Otwórz Sferę Yendoru!") @@ -994,7 +994,7 @@ S("Periodic Editor", "Edytor okresowy") // also translate this line: // "In the periodic editor, press 0-4 to switch walls in different ways\n", -S("Collect 60 $$$ to access even more lands", "Znajdź 60 $$$ by iść do kolejnych krain") +S("Collect %1 $$$ to access even more lands", "Znajdź %1 $$$ by iść do kolejnych krain") // Emerald Mine // ------------ @@ -2500,8 +2500,8 @@ S("Accessible only from %the1 (until finished).\n", "Kraina dostępna tylko popr S("Accessible only from %the1 or %the2.\n", "Kraina dostępna tylko poprzez %a1 i %a2.\n") S("Kills required: %1.\n", "Wymagani pokonani przeciwnicy: %1.\n") -S("Finished lands required: %1 (collect 10 treasure)\n", - "Wymagane ukończone krainy: %1 (zdobądź 10 skarbów)\n") +S("Finished lands required: %1 (collect %2 treasure)\n", + "Wymagane ukończone krainy: %1 (zdobądź %2 skarbów)\n") S("Treasure required: %1 x %2.\n", "Wymagane skarby: %1 x %2.\n") @@ -3737,8 +3737,8 @@ S( S("%The1 scares %the2 a bit!", "%1 troszkę przestraszy%ł1 %a2!") S("%The1 attacks your shell!", "%1 zaatakowa%ł1 Twoją skorupę!") -S("Hyperstone Quest: collect at least 10 points in %the2", - "Misja Hiperkamień: zdobądź co najmniej 10 punktów %abl2") +S("Hyperstone Quest: collect at least %3 points in %the2", + "Misja Hiperkamień: zdobądź co najmniej %3 punktów %abl2") S("animals killed: %1", "zabitych zwierząt: %1") S("\n\nTortoises are not monsters! They are just annoyed. They do not count for your total kills.", @@ -4946,7 +4946,7 @@ N("Tortoise", GEN_M, "Żółw", "Żółwie", "Żółwia", "Żółwiem") S("line patterns", "wzory linii") S("1 turn", "1 kolejka") S("%1 turns", "kolejek: %1") -S("items/kills mode", "tryb rzeczy/zabić") +S("inventory/kill mode", "tryb rzeczy/zabić") S("images", "obrazki") S("letters", "literki") S("input", "sterowanie") @@ -5442,4 +5442,22 @@ S( #undef Orb +/* +// for 10.0 +S("configure keys/joysticks", "konfiguracja klawiszy/joysticka") +S("Press F5 or 'o' to try again!", "Naciśnij F5 lub 'o' by spróbować jeszcze raz!") +S("peaceful mode", "tryb pokojowy") +S("inventory mode", "tryb inwentarza") +S("inventory", "sfery") +S("mirror what?", "co odbić?") +S("Which orb to use?", "Której Sfery użyć?") +S("Unlocked by: %1 in %2", "Odblokwane przez: %1 %abl2") +S(" (next at %1)", " (kolejny przy %1)") +S(" (next at %1 to %2)", " (kolejny przy %1 do %2)") +S("Number of uses left: %1", "Pozostało użyć: %1") +S("You mirror %the1.", "Odbijasz %a1.") +S("You need to stand next to a magic mirror or cloud to use %the1.", + "Musisz stać przy magicznym lustrze, by odbić %a1.") +S("Each orb type can be mirrored only once.", "Każdy typ sfery może być odbity tylko raz.") +*/ \ No newline at end of file diff --git a/language-ru.cpp b/language-ru.cpp index 6d7c09f8..08e4292d 100644 --- a/language-ru.cpp +++ b/language-ru.cpp @@ -248,7 +248,7 @@ S("You feel that you have enough treasure to access new lands!", "Вы чувс S("Collect more treasures, there are still more lands waiting...", "Собирайте больше сокровищ, ещё много земель Вас ждут...") S("You feel that the stars are right, and you can access R'Lyeh!", "Вы чувствуете, что звёзды правы, Вы можете открыть Р'Льех!") S("Kill monsters and collect treasures, and you may get access to Hell...", "Убивайте монстров и собирайте сокровища, и Вы сможете открыть Ад...") -S("To access Hell, collect 10 treasures each of 9 kinds...", "Чтобы открыть Ад, соберите по 10 сокровищ из 9 различных мест...") +S("To access Hell, collect %1 treasures each of 9 kinds...", "Чтобы открыть Ад, соберите по %1 сокровищ из 9 различных мест...") S("Abandon all hope, the gates of Hell are opened!", "Оставь надежду, врата Ада открылись!") S("And the Orbs of Yendor await!", "Шары Йендора ждут!") S("You switch places with %the1.", "Вы поменялись местами с %abl1.") @@ -340,10 +340,10 @@ S("GAME OVER", "КОНЕЦ ИГРЫ") S("Your score: %1", "Ваш счёт: %1") S("Enemies killed: %1", "Врагов убито: %1") S("Orbs of Yendor found: %1", "Собрано сфер Йендора: %1") -S("Collect 30 $$$ to access more worlds", "Соберите 30 $$$, чтобы открыть новые земли") -S("Collect at least 10 treasures in each of 9 types to access Hell", "Соберите хотя бы по 10 сокровищ 9 разных типов, чтобы попасть в Ад") +S("Collect %1 $$$ to access more worlds", "Соберите %1 $$$, чтобы открыть новые земли") +S("Collect at least %1 treasures in each of 9 types to access Hell", "Соберите хотя бы по %1 сокровищ 9 разных типов, чтобы попасть в Ад") S("Collect at least 10 Demon Daisies to find the Orbs of Yendor", "Соберите 10 адских ромашек, чтобы найти сферу Йендора") -S("Hyperstone Quest: collect at least 10 %1 in %the2", "Миссия Гиперкамня: соберите 10 драгоценностей в %abl2") +S("Hyperstone Quest: collect at least %3 %1 in %the2", "Миссия Гиперкамня: соберите %3 драгоценностей в %abl2") S("Hyperstone Quest completed!", "Миссия Гиперкамня закончена!") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Ищите сферы Йендора в Аду и на Перекрёстке!") S("Unlock the Orb of Yendor!", "Откройте сферу Йендора!") @@ -978,7 +978,7 @@ S("Periodic Editor", "Периодический редактор") // also translate this line: // "In the periodic editor, press 0-4 to switch walls in different ways\n", -S("Collect 60 $$$ to access even more lands", "Соберите 60 $$$, чтобы открыть новые земли") +S("Collect %1 $$$ to access even more lands", "Соберите %1 $$$, чтобы открыть новые земли") // Emerald Mine // ------------ @@ -2169,6 +2169,18 @@ S("player 4 X", "игрок 4 X") S("player 4 Y", "игрок 4 Y") S("player 4 go", "игрок 4 идёт") S("player 4 spin", "игрок 4 вертит") +S("player 5 X", "игрок 5 X") +S("player 5 Y", "игрок 5 Y") +S("player 5 go", "игрок 5 идёт") +S("player 5 spin", "игрок 5 вертит") +S("player 6 X", "игрок 6 X") +S("player 6 Y", "игрок 6 Y") +S("player 6 go", "игрок 6 идёт") +S("player 6 spin", "игрок 6 вертит") +S("player 7 X", "игрок 7 X") +S("player 7 Y", "игрок 7 Y") +S("player 7 go", "игрок 7 идёт") +S("player 7 spin", "игрок 7 вертит") S("Joystick %1, axis %2", "Джойстик %1, ось %2") S("one player", "один игрок") @@ -2492,8 +2504,8 @@ S("Accessible only from %the1 (until finished).\n", "Доступно тольк S("Accessible only from %the1 or %the2.\n", "Доступно только из %a1 и %a2.\n") S("Kills required: %1.\n", "УБийств нужно: %1 $$$.\n") -S("Finished lands required: %1 (collect 10 treasure)\n", - "Земель окончено: %1 (собрано 10 сокровищ)\n") +S("Finished lands required: %1 (collect %2 treasure)\n", + "Земель окончено: %1 (собрано %2 сокровищ)\n") S("Treasure required: %1 x %2.\n", "Сокровищ собрано: %1 x %2.\n") @@ -3864,8 +3876,8 @@ S( S("%The1 scares %the2 a bit!", "%1 немного пугает %a2!") S("%The1 attacks your shell!", "%1 атакует вашу раковину!") -S("Hyperstone Quest: collect at least 10 points in %the2", - "Миссия Гиперкамней: собери не меньше 10 очков %abl2") +S("Hyperstone Quest: collect at least %3 points in %the2", + "Миссия Гиперкамней: собери не меньше %3 очков %abl2") S("animals killed: %1", "животных убито: %1") S("\n\nTortoises are not monsters! They are just annoyed. They do not count for your total kills.", @@ -5091,7 +5103,7 @@ N("Tortoise", GEN_F, "Черепаха", "Черепахи", "Черепаху", S("line patterns", "шаблоны линий") S("1 turn", "1 ход") S("%1 turns", "ходов: %1") -S("items/kills mode", "режим предметов/убийств") +S("inventory/kill mode", "режим предметов/убийств") S("images", "изображения") S("letters", "буквы") S("input", "ввод") diff --git a/language-tr.cpp b/language-tr.cpp index 3e54a3ca..10c243ad 100644 --- a/language-tr.cpp +++ b/language-tr.cpp @@ -229,7 +229,7 @@ S("You feel that you have enough treasure to access new lands!", "Yeni diyarlara S("Collect more treasures, there are still more lands waiting...", "Daha fazla hazine topla, hâlâ seni bekleyen diyarlar var...") S("You feel that the stars are right, and you can access R'Lyeh!", "Yıldızlar sana, R'Lyeh'e ulaşabileceğini söylüyor!") S("Kill monsters and collect treasures, and you may get access to Hell...", "Canavarlar öldür, hazineler topla ve belki Cehenneme erişebilirsin...") -S("To access Hell, collect 10 treasures each of 9 kinds...", "Cehenneme erişmek için her 9 hazine tipinden 10'ar tane toplamalısın...") +S("To access Hell, collect %1 treasures each of 9 kinds...", "Cehenneme erişmek için her 9 hazine tipinden %1'ar tane toplamalısın...") S("Abandon all hope, the gates of Hell are opened!", "Umutlar tükendi, Cehennemin kapıları açıldı!") S("And the Orbs of Yendor await!", "Yendorun Küresi seni bekliyor!") S("You switch places with %the1.", "%abl1 yer değiştirdin.") @@ -320,11 +320,11 @@ S("GAME OVER", "OYUN BİTTİ") S("Your score: %1", "Puanın: %1") S("Enemies killed: %1", "Öldürülen Düşmanlar: %1") S("Orbs of Yendor found: %1", "Bulunan Yendor Küresi sayısı: %1") -S("Collect 30 $$$ to access more worlds", "30 $$$ toplayarak başka dünyalara eriş") -// S("Collect 60 $$$ to access R'Lyeh and Dry Forest", "60 $$$ toplayarak R'Lyeh ve Kara Ormana eriş.") -S("Collect at least 10 treasures in each of 9 types to access Hell", "9 hazine çeşidinin hepsinden 10'ar tane toplayarak Cehenneme erişebilirsin.") +S("Collect %1 $$$ to access more worlds", "%1 $$$ toplayarak başka dünyalara eriş") +// S("Collect %1 $$$ to access R'Lyeh and Dry Forest", "60 $$$ toplayarak R'Lyeh ve Kara Ormana eriş.") +S("Collect at least %1 treasures in each of 9 types to access Hell", "9 hazine çeşidinin hepsinden %1'ar tane toplayarak Cehenneme erişebilirsin.") S("Collect at least 10 Demon Daisies to find the Orbs of Yendor", "10 Şeytan Papatyası toplayarak Yendorun Kürelerini bulabilirsin.") -S("Hyperstone Quest: collect at least 10 %1 in %the2", "Aşkıntaş Görevi: %2'de en az 10 hazine topla.") +S("Hyperstone Quest: collect at least %3 %1 in %the2", "Aşkıntaş Görevi: %2'de en az %3 hazine topla.") S("Hyperstone Quest completed!", "Aşkıntaş görevi tamamlandı.") S("Look for the Orbs of Yendor in Hell or in the Crossroads!", "Yendorun Küreleri için Cehennemi yahut Arayolları ara!") S("Unlock the Orb of Yendor!", "Yendor'un küresinin kilidini aç!") @@ -921,7 +921,7 @@ S("Periodic Editor", "Periyodik Editör") // "In the periodic editor, press 0-4 to switch walls in different ways\n", // "Periyodik editörde, duvarları farklı şekillerde seçmek için 0-4'e basın.\n" -S("Collect 60 $$$ to access even more lands", "Daha da fazla diyara ulaşmak için 60 $$$ toplayın.") +S("Collect %1 $$$ to access even more lands", "Daha da fazla diyara ulaşmak için %1 $$$ toplayın.") // Emerald Mine // ------------ @@ -2382,8 +2382,8 @@ S("Accessible only from %the1 (until finished).\n", "Sadece %a1 erişilebilir. % S("Accessible only from %the1 or %the2.\n", "Sadece %a1 veya %a2 erişilebilir.\n") S("Kills required: %1.\n", "Gereken leşler: %1 $$$.\n") -S("Finished lands required: %1 (collect 10 treasure)\n", - "Gereken bitirilmiş diyarlar: %1 (10 hazine toplananlar)\n") +S("Finished lands required: %1 (collect %2 treasure)\n", + "Gereken bitirilmiş diyarlar: %1 (%2 hazine toplananlar)\n") S("Treasure required: %1 x %2.\n", "Gereken hazine: %1 tane %2.\n") diff --git a/mapeditor.cpp b/mapeditor.cpp index e4b2ce87..6aa59ac6 100644 --- a/mapeditor.cpp +++ b/mapeditor.cpp @@ -427,6 +427,8 @@ namespace mapeditor { int subscreen; //0=normal, 1=config, 2=patterns, 3=predesigned + cell *drawcell; + #ifndef NOEDIT int paintwhat = 0; int painttype = 0; @@ -436,9 +438,7 @@ namespace mapeditor { bool symRotation, sym01, sym02, sym03; int whichpart; - - cell *drawcell; - + const char *mapeditorhelp = "This mode allows you to edit the map.\n\n" "NOTE: Use at your own risk. Combinations which never " @@ -547,7 +547,7 @@ namespace mapeditor { bool editext = false; #define CDIR 0xC0C0C0 - #define CFILE 0xFFFFFF + #define CFILE forecolor bool filecmp(const pair &f1, const pair &f2) { if(f1.first == "../") return true; @@ -559,7 +559,7 @@ namespace mapeditor { void drawFileDialog() { displayfr(vid.xres/2, 30 + vid.fsize, 2, vid.fsize, - XLAT(cmode == emDraw ? "pics to save/load:" : "level to save/load:"), 0xFFFFFF, 8); + XLAT(cmode == emDraw ? "pics to save/load:" : "level to save/load:"), forecolor, 8); string cfile = cmode == emDraw ? picfile : levelfile; displayfr(vid.xres/2, 34 + vid.fsize * 2, 2, vid.fsize, @@ -748,7 +748,7 @@ namespace mapeditor { getcstat = '-'; - displayfr(8, 8 + fs, 2, vid.fsize, paintwhat_str, 0xFFFFFF, 0); + displayfr(8, 8 + fs, 2, vid.fsize, paintwhat_str, forecolor, 0); displayfr(8, 8+fs*2, 2, vid.fsize, XLAT("use at your own risk!"), 0x800000, 0); displayButton(8, 8+fs*4, XLAT("0-9 = radius (%1)", its(radius)), ('0' + (radius+1)%10), 0); @@ -1931,7 +1931,7 @@ namespace mapeditor { hyperpoint Plast = V * spin(-2*M_PI/ds.rots) * (ds.sym?Mirror*ds.list[0]:ds.list[size(ds.list)-1]); int state = 0; int gstate = 0; - double dist2; + double dist2 = 0; hyperpoint lpsm; for(int a=0; atype; i+=2) { + cell *c2 = createMov(c, i); + int fv1 = zebra40(c); + if(fv1/4 == 4 || fv1/4 == 6 || fv1/4 == 5 || fv1/4 == 10) fv1 ^= 2; + int fv2 = zebra40(c2); + if(fv2/4 == 4 || fv2/4 == 6 || fv2/4 == 5 || fv2/4 == 10) fv2 ^= 2; + if((fv1&1) == (fv2&1)) continue; + + double x = sphere?.3651:euclid?.2611:.2849; + + queueline(V * ddspin(c,i,-S14) * xpush0(x), + V * ddspin(c,i,+S14) * xpush0(x), + col, 1); + } + break; + + case patNormal: { + double x = sphere?.401:euclid?.3 : .328; + if(euclid || !pseudohept(c)) for(int t=0; ttype; t++) + if(euclid ? c->mov[t]mov[t] < c)) + queueline(V * ddspin(c,t,-S7) * xpush0(x), + V * ddspin(c,t,+S7) * xpush0(x), + col1, 1); + break; + } + + case patTrihepta: + if(!pseudohept(c)) for(int i=0; i<6; i++) { + cell *c2 = c->mov[i]; + if(!c2 || !pseudohept(c2)) continue; + double x = sphere?.3651:euclid?.2611:.2849; + queueline(V * ddspin(c,i,-S14) * xpush0(x), + V * ddspin(c,i,+S14) * xpush0(x), + col2, 1); + } + break; + + case patTriNet: + forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2)) if(celldist(c) != celldist(c2)) { + queueline(tC0(V), gmatrix[c2]*C0, + darkena(backcolor ^ 0xFFFFFF, 0, col2), + 2); + } + break; + + case patTriRings: + forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && celldist(c) == celldist(c2)) + queueline(tC0(V), gmatrix[c2]*C0, + darkena(backcolor ^ 0xFFFFFF, 0, col2), + 2); + break; + + case patHepta: + forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && pseudohept(c) == pseudohept(c2)) + queueline(tC0(V), gmatrix[c2]*C0, + darkena(backcolor ^ 0xFFFFFF, 0, col2), + 2); + break; + + case patRhomb: + forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && pseudohept(c) != pseudohept(c2)) + queueline(tC0(V), gmatrix[c2]*C0, + darkena(backcolor ^ 0xFFFFFF, 0, col2), + 2); + break; + + case patPalace: { + int a = polarb50(c); + if(pseudohept(c)) for(int i=0; i<7; i++) { + cell *c1 = createMov(c, (i+3) % 7); + cell *c2 = createMov(c, (i+4) % 7); + if(polarb50(c1) != a && polarb50(c2) != a) + queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), + V * ddspin(c,i,84*9/14) * xpush0(tessf/2), + col, 1); + } + break; + } + + case patPalacelike: + if(pseudohept(c)) for(int i=0; i<7; i++) + queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), + V * ddspin(c,i,84*9/14) * xpush0(tessf/2), + col1, 1); + break; + + case patBigTriangles: { + if(pseudohept(c) && !euclid) for(int i=0; imaster->move[i] < c->master) { + queueline(tC0(V), V*xspinpush0((purehepta?M_PI:0) -2*M_PI*i/S7, tessf), col1, 2); + } + break; + } + + case patBigRings: { + if(pseudohept(c) && !euclid) for(int i=0; imaster->move[i] && c->master->move[i] < c->master && c->master->move[i]->dm4 == c->master->dm4) { + cell *c2 = c->master->move[i]->c7; + queueline(tC0(V), V*xspinpush0((purehepta?M_PI:0) -2*M_PI*i/S7, tessf), col2, 2); + } + break; + } + + case patTree: + if(c->type != 6 && !euclid) + queueline(tC0(V), V*ddi0(purehepta?S42:0, tessf), col1, 2); + break; + + case patAltTree: + if(c->type != 6 && !euclid && c->master->alt) { + for(int i=0; imaster->move[i] && c->master->move[i]->alt == c->master->alt->move[0]) + queueline(tC0(V), V*xspinpush0((purehepta?M_PI:0) -2*M_PI*i/S7, tessf), col, 2); + } + break; + + case patVine: { + int p = emeraldval(c); + double hdist = hdist0(heptmove[0] * heptmove[2] * C0); + if(pseudohept(c) && (p/4 == 10 || p/4 == 8)) + for(int i=0; imov[i] && emeraldval(c->mov[i]) == p-4) { + queueline(tC0(V), V*tC0(heptmove[i]), col, 2); + queueline(tC0(V), V*tC0(spin(-i * ALPHA) * xpush(-hdist/2)), col, 2); + } + break; + } + + case patPower: { + int a = emeraldval(c); + if(pseudohept(c) && a/4 == 8) for(int i=0; i<7; i++) { + heptagon *h1 = c->master->move[(i+1)%7]; + heptagon *h2 = c->master->move[(i+6)%7]; + if(!h1 || !h2) continue; + if(emeraldval(h1->c7)/4 == 8 && emeraldval(h2->c7)/4 == 8) + queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), + V * ddspin(c,i,84*9/14) * xpush0(tessf/2), + col, 1); + } + break; + } + } + } + void drawAll() { if(any()) for(map::iterator it = gmatrix.begin(); it != gmatrix.end(); it++) { @@ -2072,163 +2242,7 @@ namespace linepatterns { if(!(col & 255)) continue; int id = patterns[k].id; - switch(id) { - -#define col1 \ - lessalphaif(col, behindsphere(V)) - -#define col2 \ - lessalphaif(col, behindsphere(V), behindsphere(gmatrix[c2])) - - case patZebraTriangles: - if(zebra40(c) / 4 == 10) { - bool all = true; - hyperpoint tri[3]; - for(int i=0; i<3; i++) { - cell *c2 = createMov(c, i*2); - if(!gmatrix.count(c2)) all = false; - else tri[i] = tC0(gmatrix[c2]); - } - - if(all) for(int i=0; i<3; i++) - queueline(tri[i], tri[(i+1)%3], col, 3); - } - break; - - case patZebraLines: - if(!pseudohept(c)) for(int i=0; itype; i+=2) { - cell *c2 = createMov(c, i); - int fv1 = zebra40(c); - if(fv1/4 == 4 || fv1/4 == 6 || fv1/4 == 5 || fv1/4 == 10) fv1 ^= 2; - int fv2 = zebra40(c2); - if(fv2/4 == 4 || fv2/4 == 6 || fv2/4 == 5 || fv2/4 == 10) fv2 ^= 2; - if((fv1&1) == (fv2&1)) continue; - - double x = sphere?.3651:euclid?.2611:.2849; - - queueline(V * ddspin(c,i,-S14) * xpush0(x), - V * ddspin(c,i,+S14) * xpush0(x), - col, 1); - } - break; - - case patNormal: { - double x = sphere?.401:euclid?.3 : .328; - if(euclid || !pseudohept(c)) for(int t=0; ttype; t++) - if(euclid ? c->mov[t]mov[t] < c)) - queueline(V * ddspin(c,t,-S7) * xpush0(x), - V * ddspin(c,t,+S7) * xpush0(x), - col1, 1); - break; - } - - case patTrihepta: - if(!pseudohept(c)) for(int i=0; i<6; i++) { - cell *c2 = c->mov[i]; - if(!c2 || !pseudohept(c2)) continue; - double x = sphere?.3651:euclid?.2611:.2849; - queueline(V * ddspin(c,i,-S14) * xpush0(x), - V * ddspin(c,i,+S14) * xpush0(x), - col2, 1); - } - break; - - case patTriNet: - forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2)) if(celldist(c) != celldist(c2)) { - queueline(it->second*C0, gmatrix[c2]*C0, - darkena(backcolor ^ 0xFFFFFF, 0, col2), - 2); - } - break; - - case patTriRings: - forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && celldist(c) == celldist(c2)) - queueline(it->second*C0, gmatrix[c2]*C0, - darkena(backcolor ^ 0xFFFFFF, 0, col2), - 2); - break; - - case patHepta: - forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && pseudohept(c) == pseudohept(c2)) - queueline(it->second*C0, gmatrix[c2]*C0, - darkena(backcolor ^ 0xFFFFFF, 0, col2), - 2); - break; - - case patRhomb: - forCellEx(c2, c) if(c2 > c) if(gmatrix.count(c2) && pseudohept(c) != pseudohept(c2)) - queueline(it->second*C0, gmatrix[c2]*C0, - darkena(backcolor ^ 0xFFFFFF, 0, col2), - 2); - break; - - case patPalace: { - int a = polarb50(c); - if(pseudohept(c)) for(int i=0; i<7; i++) { - cell *c1 = createMov(c, (i+3) % 7); - cell *c2 = createMov(c, (i+4) % 7); - if(polarb50(c1) != a && polarb50(c2) != a) - queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), - V * ddspin(c,i,84*9/14) * xpush0(tessf/2), - col, 1); - } - break; - } - - case patPalacelike: - if(pseudohept(c)) for(int i=0; i<7; i++) - queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), - V * ddspin(c,i,84*9/14) * xpush0(tessf/2), - col1, 1); - break; - - case patBigTriangles: { - if(pseudohept(c) && !euclid) for(int i=0; imaster->move[i] < c->master) { - cell *c2 = c->master->move[i]->c7; - queueline(tC0(V), V*xspinpush0((purehepta?M_PI:0) -2*M_PI*i/S7, tessf), col2, 2); - } - break; - } - - case patTree: - if(c->type != 6 && !euclid) - queueline(tC0(V), V*ddi0(purehepta?S42:0, tessf), col1, 2); - break; - - case patAltTree: - if(c->type != 6 && !euclid && c->master->alt) { - for(int i=0; imaster->move[i] && c->master->move[i]->alt == c->master->alt->move[0]) - queueline(tC0(V), V*xspinpush0((purehepta?M_PI:0) -2*M_PI*i/S7, tessf), col, 2); - } - break; - - case patVine: { - int p = emeraldval(c); - double hdist = hdist0(heptmove[0] * heptmove[2] * C0); - if(pseudohept(c) && (p/4 == 10 || p/4 == 8)) - for(int i=0; imov[i] && emeraldval(c->mov[i]) == p-4) { - queueline(tC0(V), V*tC0(heptmove[i]), col, 2); - queueline(tC0(V), V*tC0(spin(-i * ALPHA) * xpush(-hdist/2)), col, 2); - } - break; - } - - case patPower: { - int a = emeraldval(c); - if(pseudohept(c) && a/4 == 8) for(int i=0; i<7; i++) { - heptagon *h1 = c->master->move[(i+1)%7]; - heptagon *h2 = c->master->move[(i+6)%7]; - if(!h1 || !h2) continue; - if(emeraldval(h1->c7)/4 == 8 && emeraldval(h2->c7)/4 == 8) - queueline(V * ddspin(c,i,84*5/14) * xpush0(tessf/2), - V * ddspin(c,i,84*9/14) * xpush0(tessf/2), - col, 1); - } - break; - } - } + drawPattern(id, col, c, V); } } } diff --git a/menus.cpp b/menus.cpp index f6a891b2..b5e0f4a1 100644 --- a/menus.cpp +++ b/menus.cpp @@ -8,6 +8,13 @@ ld whatever = 0; +void gotoHelp(const string& h, emtype c = cmode) { + help = h; + if(c != emHelp) lastmode = c; + cmode = emHelp; + printf("goto help, back = %d\n", c); + } + void showOverview() { DEBB(DF_GRAPH, (debugfile,"show overview\n")); mouseovers = XLAT("world overview"); @@ -48,7 +55,7 @@ void showOverview() { if(landUnlocked(l)) col = linf[l].color; else col = 0x404040; if(chaosmode && noChaos(l)) col = 0x400000; if(l == curland) - displayfrZ(1, i0, 1, vf-4, "*", 0xFFFFFF, 0); + displayfrZ(1, i0, 1, vf-4, "*", forecolor, 0); if(displayfrZ(xr*1, i0, 1, vf-4, XLAT1(linf[l].name), col, 0)) getcstat = 1000 + l; eItem it = treasureType(l); @@ -127,10 +134,7 @@ void handleOverview(int sym, int uni) { canmove = true; if(princ) fullcenter(); } - else { - lastmode = cmode; - cmode = emHelp; help = generateHelpForLand(eLand(umod)); - } + else gotoHelp(generateHelpForLand(eLand(umod))); } else if(udiv == 2 && umod < ittypes) { if(cheater && !hiliteclick) { @@ -144,29 +148,20 @@ void handleOverview(int sym, int uni) { if(hardcore) canmove = true; else checkmove(); } - else { - lastmode = cmode; - cmode = emHelp; help = generateHelpForItem(eItem(umod)); - } - } - else if(udiv == 3 && umod < walltypes) { - lastmode = cmode; - cmode = emHelp; help = generateHelpForWall(eWall(umod)); - } - else if(uni == SDLK_F1) { - lastmode = cmode; - cmode = emHelp; - help = - "This displays all lands available in the game. " - "Bonus lands (available only in separate challenges) " - "are not included. Lands written in dark have to be " - "unlocked, and lands in dark red are unavailable " - "because of using special options. Click on any " - "land or item to get information about it. Hover over " - "an Orb to know its relation to the current land. " - "Cheaters can click to move between lands, and use the " - "mousewheel to gain or lose treasures and orbs quickly (Ctrl = precise, Shift = reverse)."; + else gotoHelp(generateHelpForItem(eItem(umod))); } + else if(udiv == 3 && umod < walltypes) gotoHelp(generateHelpForWall(eWall(umod))); + else if(uni == SDLK_F1) gotoHelp( + "This displays all lands available in the game. " + "Bonus lands (available only in separate challenges) " + "are not included. Lands written in dark have to be " + "unlocked, and lands in dark red are unavailable " + "because of using special options. Click on any " + "land or item to get information about it. Hover over " + "an Orb to know its relation to the current land. " + "Cheaters can click to move between lands, and use the " + "mousewheel to gain or lose treasures and orbs quickly (Ctrl = precise, Shift = reverse)." + ); else if(dialog::handlePageButtons(uni)) ; else if(doexiton(sym, uni)) cmode = emNormal; } @@ -188,7 +183,10 @@ void showMainMenu() { dialog::init(XLAT("HyperRogue %1", VER), 0xC00000, 200, 100); dialog::addItem(XLAT("basic configuration"), 'b'); - dialog::addItem(XLAT("advanced configuration"), 'a'); + dialog::addItem(XLAT("graphics configuration"), 'g'); + dialog::addItem(XLAT("special display modes"), 'd'); + dialog::addItem(XLAT("special game modes"), 'm'); + #ifndef NOSAVE dialog::addItem(XLAT("local highscores"), 't'); #endif @@ -197,7 +195,6 @@ void showMainMenu() { dialog::addItem(XLAT("cheats"), 'c'); else dialog::addBreak(100); dialog::addItem(XLAT("restart game"), 'r'); dialog::lastItem().keycaption += " / F5"; - dialog::addItem(XLAT("special game modes"), 'm'); string q; #ifdef MOBILE @@ -215,10 +212,13 @@ void showMainMenu() { dialog::addItem(XLAT(q), SDLK_ESCAPE); dialog::addItem(XLAT("world overview"), 'o'); + if(inv::on) + dialog::addItem(XLAT("inventory"), 'i'); + if(checkHalloweenDate()) dialog::addItem(XLAT("Halloween mini-game"), 'y'-96); #ifdef ROGUEVIZ - dialog::addItem(XLAT("rogueviz menu"), 'g'); + dialog::addItem(XLAT("rogueviz menu"), 'u'); #endif #ifdef MOBILE @@ -241,14 +241,12 @@ void showMainMenu() { void handleMenuKey(int sym, int uni) { dialog::handleNavigation(sym, uni); - if(sym == SDLK_F1 || sym == 'h') { - lastmode = cmode; - cmode = emHelp; - } + if(sym == SDLK_F1 || sym == 'h') gotoHelp(help); else if(sym == 'c' && cheater) cmode = emCheatMenu; - else if(sym == 'b') cmode = emVisual1; - else if(sym == 'a') cmode = emVisual2; + else if(sym == 'b') cmode = emBasicConfig; + else if(sym == 'g') cmode = emGraphConfig; + else if(sym == 'd') cmode = emDisplayMode; else if(sym == 'm') cmode = emChangeMode; #ifndef NOSAVE else if(sym == 't') loadScores(); @@ -278,6 +276,10 @@ void handleMenuKey(int sym, int uni) { clearMessages(); cmode = emOverview; } + else if(sym == 'i') { + clearMessages(); + cmode = emInventory; + } else if(sym == SDLK_ESCAPE) { cmode = emQuit; achievement_final(false); @@ -291,7 +293,7 @@ void handleMenuKey(int sym, int uni) { #endif #endif #ifdef ROGUEVIZ - else if(uni == 'g') cmode = emRogueviz; + else if(uni == 'u') cmode = emRogueviz; #endif else if(doexiton(sym, uni)) { cmode = emNormal; @@ -299,91 +301,93 @@ void handleMenuKey(int sym, int uni) { } } -void showVisual1() { - dialog::init(XLAT("basic configuration")); - -#ifndef MOBILE - dialog::addSelItem(XLAT("video resolution"), its(vid.xres) + "x"+its(vid.yres), 0); +void showAllConfig() { + dialog::addBreak(50); + dialog::addItem(XLAT("exit configuration"), 'v'); +#ifndef NOCONFIG + dialog::addItem(XLAT("save the current config"), 's'); #endif + } + +void handleAllConfig(int sym, int uni) { + if(sym == SDLK_F1 || uni == 'h') gotoHelp(help); + + if(uni == 'v') cmode = emMenu; + if(sym == SDLK_ESCAPE) cmode = emNormal; +#ifndef NOCONFIG + if(uni == 's') saveConfig(); +#endif + } + +void showGraphConfig() { + + dialog::init(XLAT("graphics configuration")); + + #ifndef ONEGRAPH + #ifdef GL + dialog::addBoolItem(XLAT("openGL mode"), vid.usingGL, 'o'); + #endif + #endif + + if(!vid.usingGL) + dialog::addBoolItem(XLAT("anti-aliasing"), vid.antialias & AA_NOGL, 'O'); + + if(vid.usingGL) + dialog::addSelItem(XLAT("anti-aliasing"), + (vid.antialias & AA_POLY) ? "polygons" : + (vid.antialias & AA_LINES) ? "lines" : + "NO", 'O'); + + if(vid.usingGL) { + dialog::addSelItem(XLAT("line width"), fts(vid.linewidth), 'w'); +// dialog::addBoolItem(XLAT("finer lines at the boundary"), vid.antialias & AA_LINEWIDTH, 'b'); + } + + #ifndef MOBWEB + dialog::addSelItem(XLAT("framerate limit"), its(vid.framelimit), 'l'); + #endif + #ifndef IOS dialog::addBoolItem(XLAT("fullscreen mode"), (vid.full), 'f'); #endif + dialog::addSelItem(XLAT("scrolling speed"), fts(vid.sspeed), 'a'); - dialog::addSelItem(XLAT("movement animation speed"), fts(vid.mspeed), 'r'); - dialog::addSelItem(XLAT("projection"), fts(vid.alpha), 'p'); - dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z'); - -#ifdef LOCAL + dialog::addSelItem(XLAT("movement animation speed"), fts(vid.mspeed), 'm'); + + dialog::addBoolItem(XLAT("extra graphical effects"), (vid.particles), 'u'); + +#ifdef WHATEVER dialog::addSelItem(XLAT("whatever"), fts(whatever), 'j'); #endif - const char *wdmodes[6] = {"ASCII", "black", "plain", "Escher", "plain/3D", "Escher/3D"}; - const char *mdmodes[6] = {"ASCII", "items only", "items and monsters", "high contrast", - "3D", "high contrast/3D"}; - const char *glyphsortnames[6] = { "first on top", "first on bottom", "last on top", "last on bottom", "by land", "by number" }; - - - dialog::addSelItem(XLAT("items/kills mode"), XLAT(vid.graphglyph ? "images" : "letters"), 'd'); - dialog::addBoolItem(XLAT("mark heptagons"), (vid.darkhepta), '7'); - dialog::addBoolItem(XLAT("draw the grid"), (vid.grid), '6'); - dialog::addBoolItem(XLAT("extra graphical effects"), (vid.particles), 'u'); - - dialog::addSelItem(XLAT("wall display mode"), XLAT(wdmodes[vid.wallmode]), 'w'); - dialog::addSelItem(XLAT("monster display mode"), XLAT(mdmodes[vid.monmode]), 'm'); - const char *axmodes[5] = {"OFF", "auto", "light", "heavy", "arrows"}; - dialog::addSelItem(XLAT("help for keyboard users"), XLAT(axmodes[vid.axes]), 'c'); -#ifndef NOAUDIO - dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b'); - dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e'); -#endif -#ifndef NOTRANS - dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l'); -#endif - dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g'); - + + const char *glyphmodenames[3] = {"letters", "auto", "images"}; dialog::addSelItem(XLAT("inventory/kill sorting"), XLAT(glyphsortnames[glyphsortorder]), 'k'); - dialog::addBreak(50); - dialog::addItem(XLAT("exit configuration"), 'v'); -#ifndef NOCONFIG - dialog::addItem(XLAT("save the current config"), 's'); + dialog::addSelItem(XLAT("inventory/kill mode"), XLAT(glyphmodenames[vid.graphglyph]), 'd'); + +#ifdef MOBILE + dialog::addSelItem(XLAT("font scale"), its(fontscale), 'b'); #endif - if(lang() != 0) { - string tw = ""; - string s = XLAT("TRANSLATIONWARNING"); - if(s != "" && s != "TRANSLATIONWARNING") tw += s; - s = XLAT("TRANSLATIONWARNING2"); - if(s != "" && s != "TRANSLATIONWARNING2") { if(tw != "") tw += " "; tw += s; } - if(tw != "") { - dialog::addBreak(50); - dialog::addHelp(tw); - dialog::lastItem().color = 0xFF0000; - } - } + dialog::addSelItem(XLAT("sight range"), its(sightrange), 'r'); +#ifdef MOBILE + dialog::addSelItem(XLAT("compass size"), its(vid.mobilecompasssize), 'c'); +#endif + + dialog::addSelItem(XLAT("aura brightness"), its(vid.aurastr), 'z'); + dialog::addSelItem(XLAT("aura smoothening factor"), its(vid.aurasmoothen), 'x'); + + showAllConfig(); dialog::display(); } - -void projectionDialog() { - geom3::tc_alpha = ticks; - dialog::editNumber(vid.alpha, -5, 5, .1, 1, - XLAT("projection"), - XLAT("HyperRogue uses the Minkowski hyperboloid model internally. " - "Klein and Poincaré models can be obtained by perspective, " - "and the Gans model is obtained by orthogonal projection. " -// "This parameter specifies the distance from the hyperboloid center " -// "to the eye. " - "See also the conformal mode (in the special modes menu) " - "for more models.")); - dialog::sidedialog = true; - } - + void switchFullscreen() { vid.full = !vid.full; #ifdef ANDROID @@ -417,71 +421,142 @@ void switchGL() { #endif } -void switchHardcore() { - if(hardcore && !canmove) { - restartGame(); - hardcore = false; - cmode = emNormal; - } - else if(hardcore && canmove) { hardcore = false; } - else { hardcore = true; canmove = true; hardcoreAt = turncount; } - if(hardcore) - addMessage("One wrong move, and it is game over!"); - else - addMessage("Not so hardcore?"); - if(pureHardcore()) cmode = emNormal; - } - -void handleVisual1(int sym, int uni) { +void handleGraphConfig(int sym, int uni) { dialog::handleNavigation(sym, uni); - - char xuni = uni | 96; - - if(uni >= 32 && uni < 64) xuni = uni; - - if(xuni == 'p') projectionDialog(); - - if(xuni == '6') vid.grid = !vid.grid; - if(xuni == 'u') vid.particles = !vid.particles; - - if(xuni == 'd') vid.graphglyph = !vid.graphglyph; + if(uni == 'O') uni = 'o', shiftmul = -1; + + char xuni = uni | 96; + + if(xuni == 'u') vid.particles = !vid.particles; + if(xuni == 'd') vid.graphglyph = (1+vid.graphglyph)%3; + if(xuni == 'j') { dialog::editNumber(whatever, -10, 10, 1, 0, XLAT("whatever"), XLAT("Whatever.")); dialog::sidedialog = true; } - if(xuni == 'z') { - dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"), - XLAT("Scale the displayed model.")); - dialog::scaleLog(); - dialog::sidedialog = true; - } - if(xuni == 'a') dialog::editNumber(vid.sspeed, -5, 5, 1, 0, XLAT("scrolling speed"), XLAT("+5 = center instantly, -5 = do not center the map")); - if(xuni == 'r') dialog::editNumber(vid.mspeed, -5, 5, 1, 0, + if(xuni == 'm') dialog::editNumber(vid.mspeed, -5, 5, 1, 0, XLAT("movement animation speed"), XLAT("+5 = move instantly")); + if(xuni == 'r') { + dialog::editNumber(sightrange, 4, cheater ? 10 : 7, 1, 7, XLAT("sight range"), + XLAT("Roughly 42% cells are on the edge of your sight range. Reducing " + "the sight range makes HyperRogue work faster, but also makes " + "the game effectively harder.")); + dialog::sidedialog = true; + } + if(xuni == 'k') { glyphsortorder = eGlyphsortorder((glyphsortorder+6+(shiftmul>0?1:-1)) % gsoMAX); } if(xuni == 'f') switchFullscreen(); - - if(xuni == 'v') cmode = emNormal; - if(sym == SDLK_F2) cmode = emVisual2; -#ifndef NOCONFIG - if(xuni == 's') saveConfig(); + +#ifndef ONEGRAPH + if(xuni == 'o' && shiftmul > 0) switchGL(); #endif + + if(xuni == 'o' && shiftmul < 0) { + if(!vid.usingGL) + vid.antialias ^= AA_NOGL | AA_FONT; + else if(vid.antialias & AA_POLY) + vid.antialias ^= AA_POLY | AA_LINES; + else if(vid.antialias & AA_LINES) + vid.antialias |= AA_POLY; + else + vid.antialias |= AA_LINES; + } - if(xuni == '7') { vid.darkhepta = !vid.darkhepta; } - if(xuni == 'w') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; } - if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; } + // if(xuni == 'b') vid.antialias ^= AA_LINEWIDTH; + + if(xuni == 'w' && vid.usingGL) + dialog::editNumber(vid.linewidth, 0, 10, 0.1, 1, XLAT("line width"), ""); + + if(xuni == 'c') + dialog::editNumber(vid.mobilecompasssize, 0, 100, 10, 20, XLAT("compass size"), ""); + + if(xuni == 'l') + dialog::editNumber(vid.framelimit, 5, 300, 10, 300, XLAT("framerate limit"), ""); + +#ifdef MOBILE + if(xuni =='b') + dialog::editNumber(fontscale, 0, 400, 10, 100, XLAT("font scale"), ""); +#endif + + if(xuni =='z') + dialog::editNumber(vid.aurastr, 0, 256, 10, 128, XLAT("aura brightness"), ""); + else if(xuni =='x') + dialog::editNumber(vid.aurasmoothen, 1, 180, 1, 5, XLAT("aura smoothening factor"), ""); + + handleAllConfig(sym, xuni); + } + +void showBasicConfig() { + const char *axmodes[5] = {"OFF", "auto", "light", "heavy", "arrows"}; + dialog::init(XLAT("basic configuration")); + +#ifndef NOTRANS + dialog::addSelItem(XLAT("language"), XLAT("EN"), 'l'); +#endif + dialog::addSelItem(XLAT("player character"), numplayers() > 1 ? "" : csname(vid.cs), 'g'); + +#ifndef NOAUDIO + dialog::addSelItem(XLAT("background music volume"), its(musicvolume), 'b'); + dialog::addSelItem(XLAT("sound effects volume"), its(effvolume), 'e'); +#endif + +// input: + dialog::addSelItem(XLAT("help for keyboard users"), XLAT(axmodes[vid.axes]), 'c'); + + dialog::addBoolItem(XLAT("reverse pointer control"), (revcontrol), 'r'); + dialog::addBoolItem(XLAT("draw circle around the target"), (vid.drawmousecircle), 'd'); + + dialog::addSelItem(XLAT("message flash time"), its(vid.flashtime), 't'); +#ifdef MOBILE + dialog::addBoolItem(XLAT("targetting ranged Orbs long-click only"), (vid.shifttarget&2), 'i'); +#else + dialog::addBoolItem(XLAT("targetting ranged Orbs Shift+click only"), (vid.shifttarget&1), 'i'); +#endif +#ifdef STEAM + dialog::addBoolItem(XLAT("send scores to Steam leaderboards"), (vid.steamscore&1), 'l'); +#endif + +#ifndef MOBILE + dialog::addSelItem(XLAT("configure keys/joysticks"), "", 'p'); +#endif + + showAllConfig(); + + if(lang() != 0) { + string tw = ""; + string s = XLAT("TRANSLATIONWARNING"); + if(s != "" && s != "TRANSLATIONWARNING") tw += s; + s = XLAT("TRANSLATIONWARNING2"); + if(s != "" && s != "TRANSLATIONWARNING2") { if(tw != "") tw += " "; tw += s; } + if(tw != "") { + dialog::addBreak(50); + dialog::addHelp(tw); + dialog::lastItem().color = 0xFF0000; + } + } + + dialog::display(); + } + +void handleBasicConfig(int sym, int uni) { + dialog::handleNavigation(sym, uni); + + char xuni = uni | 96; + + if(uni >= 32 && uni < 64) xuni = uni; + if(xuni == 'c') { vid.axes += 60 + (shiftmul > 0 ? 1 : -1); vid.axes %= 5; } #ifndef NOAUDIO if(xuni == 'b') { @@ -507,10 +582,26 @@ void handleVisual1(int sym, int uni) { if(xuni == 'g') cmode = emCustomizeChar; -#ifdef LOCAL - extern void process_local(int); - process_local(sym); +#ifndef MOBILE + if(xuni == 'p') { + cmode = emShmupConfig; + multi::shmupcfg = shmup::on; + } #endif + + if(xuni == 'r') revcontrol = !revcontrol; + if(xuni == 'd') vid.drawmousecircle = !vid.drawmousecircle; + +#ifdef STEAM + if(xuni == 'l') vid.steamscore = vid.steamscore^1; +#endif + if(xuni == 't') + dialog::editNumber(vid.flashtime, 0, 64, 1, 8, XLAT("message flash time"), + XLAT("How long should the messages stay on the screen.")); + + if(xuni == 'i') { vid.shifttarget = vid.shifttarget^3; } + + handleAllConfig(sym, xuni); } void showJoystickConfig() { @@ -537,20 +628,33 @@ void handleJoystickConfig(int sym, int uni) { dialog::handleNavigation(sym, uni); char xuni = uni | 96; if(xuni == 'p') autojoy = !autojoy; - if(xuni == 'a') + else if(xuni == 'a') dialog::editNumber(vid.joyvalue, 0, 32768, 100, 4800, XLAT("first joystick: movement threshold"), ""); - if(xuni == 'b') + else if(xuni == 'b') dialog::editNumber(vid.joyvalue2, 0, 32768, 100, 5600, XLAT("first joystick: execute movement threshold"), ""); - if(xuni == 'c') + else if(xuni == 'c') dialog::editNumber(vid.joypanthreshold, 0, 32768, 100, 2500, XLAT("second joystick: pan threshold"), ""); - if(xuni == 'd') + else if(xuni == 'd') dialog::editNumber(vid.joypanspeed, 0, 1e-2, 1e-5, 1e-4, XLAT("second joystick: panning speed"), ""); - if(xuni == 'v') + else if(xuni == 'v') cmode = emShmupConfig; - if(sym == SDLK_F10) cmode = emNormal; - if(doexiton(sym, uni)) cmode = emShmupConfig; + else if(doexiton(sym, uni)) cmode = emShmupConfig; + } + +void projectionDialog() { + geom3::tc_alpha = ticks; + dialog::editNumber(vid.alpha, -5, 5, .1, 1, + XLAT("projection"), + XLAT("HyperRogue uses the Minkowski hyperboloid model internally. " + "Klein and Poincar‚ models can be obtained by perspective, " + "and the Gans model is obtained by orthogonal projection. " +// "This parameter specifies the distance from the hyperboloid center " +// "to the eye. " + "See also the conformal mode (in the special modes menu) " + "for more models.")); + dialog::sidedialog = true; } void show3D() { @@ -576,6 +680,7 @@ void show3D() { dialog::addBreak(50); dialog::addSelItem(XLAT("Y shift"), fts3(vid.yshift), 'y'); dialog::addSelItem(XLAT("camera rotation"), fts3(vid.camera_angle), 's'); + dialog::addSelItem(XLAT("distance between eyes"), fts3(vid.eye), 'e'); dialog::addBreak(50); dialog::addBoolItem(XLAT("ball model"), pmodel == mdBall, 'B'); dialog::addBoolItem(XLAT("hyperboloid model"), pmodel == mdHyperboloid, 'M'); @@ -700,6 +805,14 @@ void handle3D(int sym, int uni) { dialog::editNumber(geom3::rock_wall_ratio, 0, 1, .1, .9, XLAT("Rock-III to wall ratio"), ""); else if(uni == 'h') dialog::editNumber(geom3::human_wall_ratio, 0, 1, .1, .7, XLAT("Human to wall ratio"), ""); + + else if(uni == 'e') { + dialog::editNumber(vid.eye, -10, 10, 0.01, 0, XLAT("distance between eyes"), + XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " + "red/cyan 3D glasses.")); + dialog::sidedialog = true; + } + else if(uni == 'y') dialog::editNumber(vid.yshift, 0, 1, .1, 0, XLAT("Y shift"), "Don't center on the player character." @@ -720,139 +833,126 @@ void handle3D(int sym, int uni) { else if(uni == 'M') pmodel = (pmodel == mdHyperboloid ? mdDisk : mdHyperboloid); - else if(doexiton(sym, uni)) cmode = emVisual2; + else if(doexiton(sym, uni)) cmode = emDisplayMode; if(cmode == emNumber) dialog::sidedialog = true; } -void showVisual2() { +void showDisplayMode() { - dialog::init(XLAT("advanced configuration")); + dialog::init(XLAT("special display modes")); - #ifndef ONEGRAPH - #ifdef GL - dialog::addSelItem(XLAT("openGL & antialiasing mode"), vid.usingGL ? "OpenGL" : vid.usingAA ? "AA" : "OFF", 'o'); - #endif - #endif - dialog::addSelItem(XLAT("distance between eyes"), fts3(vid.eye), 'e'); - #ifndef MOBWEB - dialog::addSelItem(XLAT("framerate limit"), its(vid.framelimit), 'f'); - #endif + const char *wdmodes[6] = {"ASCII", "black", "plain", "Escher", "plain/3D", "Escher/3D"}; + const char *mdmodes[6] = {"ASCII", "items only", "items and monsters", "high contrast", + "3D", "high contrast/3D"}; -#ifndef MOBILE - dialog::addSelItem(XLAT("configure input"), "", 'p'); -#endif + dialog::addBoolItem(XLAT("orthogonal projection"), vid.alpha >= 500, '1'); + dialog::addBoolItem(XLAT("small Poincaré model"), vid.alpha == 1 && vid.scale < 1, '2'); + dialog::addBoolItem(XLAT("big Poincaré model"), vid.alpha == 1 && vid.scale >= 1, '3'); + dialog::addBoolItem(XLAT("Klein-Beltrami model"), vid.alpha == 0, '4'); + dialog::addSelItem(XLAT("wall display mode"), XLAT(wdmodes[vid.wallmode]), '5'); + dialog::addBoolItem(XLAT("draw the grid"), (vid.grid), '6'); + dialog::addBoolItem(XLAT("mark heptagons"), (vid.darkhepta), '7'); + dialog::addSelItem(XLAT("3D configuration"), "", '9'); -#ifdef MOBILE - dialog::addSelItem(XLAT("font scale"), its(fontscale), 'b'); -#endif - - dialog::addSelItem(XLAT("sight range"), its(sightrange), 'a'); - dialog::addBoolItem(XLAT("reverse pointer control"), (revcontrol), 'r'); - dialog::addBoolItem(XLAT("draw circle around the target"), (vid.drawmousecircle), 'd'); - - dialog::addSelItem(XLAT("message flash time"), its(vid.flashtime), 't'); -#ifdef MOBILE - dialog::addBoolItem(XLAT("targetting ranged Orbs long-click only"), (vid.shifttarget&2), 'i'); -#else - dialog::addBoolItem(XLAT("targetting ranged Orbs Shift+click only"), (vid.shifttarget&1), 'i'); -#endif -#ifdef STEAM - dialog::addBoolItem(XLAT("send scores to Steam leaderboards"), (vid.steamscore&1), 'l'); -#endif - dialog::addSelItem(XLAT("3D configuration"), "", '3'); -#ifdef MOBILE - dialog::addSelItem(XLAT("compass size"), its(vid.mobilecompasssize), 'c'); -#endif - - dialog::addSelItem(XLAT("aura brightness"), its(vid.aurastr), 'z'); - dialog::addSelItem(XLAT("aura smoothening factor"), its(vid.aurasmoothen), 'x'); + dialog::addSelItem(XLAT("scale factor"), fts(vid.scale), 'z'); + dialog::addSelItem(XLAT("monster display mode"), XLAT(mdmodes[vid.monmode]), 'm'); dialog::addBreak(50); - dialog::addItem(XLAT("exit configuration"), 'v'); -#ifndef NOCONFIG - dialog::addItem(XLAT("save the current config"), 's'); + +#ifndef NOEDIT + dialog::addBoolItem(XLAT("vector graphics editor"), (false), 'g'); #endif + // display modes +#ifndef NORUG + dialog::addBoolItem(XLAT("hypersian rug mode"), (rug::rugged), 'u'); +#endif +#ifndef NOMODEL + dialog::addBoolItem(XLAT("paper model creator"), (false), 'n'); +#endif + dialog::addBoolItem(XLAT("conformal/history mode"), (conformal::on), 'a'); + dialog::addBoolItem(XLAT("expansion"), viewdists, 'x'); + + showAllConfig(); dialog::display(); } -void handleVisual2(int sym, int uni) { +void gmodekeys(int sym, int uni) { + if(uni == '1') { vid.alpha = 999; vid.scale = 998; } + if(uni == '2') { vid.alpha = 1; vid.scale = 0.4; } + if(uni == '3') { vid.alpha = 1; vid.scale = 1; } + if(uni == '4') { vid.alpha = 0; vid.scale = 1; } + if(uni == '5') { vid.wallmode += 60 + (shiftmul > 0 ? 1 : -1); vid.wallmode %= 6; } + if(uni == '6') vid.grid = !vid.grid; + if(uni == '7') { vid.darkhepta = !vid.darkhepta; } + if(uni == '%' && sym == '5') { + if(vid.wallmode == 0) vid.wallmode = 6; + vid.wallmode--; + } + } + +void handleDisplayMode(int sym, int uni) { dialog::handleNavigation(sym, uni); char xuni = uni; if((xuni >= 'A' && xuni <= 'Z') || (xuni >= 1 && xuni <= 26)) xuni |= 32; - - if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal; -#ifndef NOCONFIG - if(xuni == 's') saveConfig(); -#endif - - if(xuni == '3') cmode = em3D; - - if(xuni == 'c') - dialog::editNumber(vid.mobilecompasssize, 0, 100, 10, 20, XLAT("compass size"), ""); - - if(sym == SDLK_F1 || sym == 'h') - lastmode = cmode, cmode = emHelp; -#ifndef ONEGRAPH - if(xuni == 'o' && shiftmul > 0) switchGL(); - -#ifndef MOBILE - if(xuni == 'o' && shiftmul < 0 && !vid.usingGL) { - vid.usingAA = !vid.usingAA; - if(vid.usingAA) addMessage(XLAT("anti-aliasing enabled")); - if(!vid.usingAA) addMessage(XLAT("anti-aliasing disabled")); - } -#endif -#endif - -#ifndef MOBILE - if(xuni == 'p') { - cmode = emShmupConfig; - multi::shmupcfg = shmup::on; - } -#endif + if(xuni == 'p') projectionDialog(); - if(xuni == 'f') - dialog::editNumber(vid.framelimit, 5, 300, 10, 300, XLAT("framerate limit"), ""); - - if(xuni == 'a') { - dialog::editNumber(sightrange, 4, cheater ? 10 : 7, 1, 7, XLAT("sight range"), - XLAT("Roughly 42% cells are on the edge of your sight range. Reducing " - "the sight range makes HyperRogue work faster, but also makes " - "the game effectively harder.")); + if(xuni == 'z') { + dialog::editNumber(vid.scale, .001, 1000, .1, 1, XLAT("scale factor"), + XLAT("Scale the displayed model.")); + dialog::scaleLog(); dialog::sidedialog = true; } - - if(xuni == 'r') revcontrol = !revcontrol; - if(xuni == 'd') vid.drawmousecircle = !vid.drawmousecircle; - -#ifdef MOBILE - if(xuni =='b') - dialog::editNumber(fontscale, 0, 400, 10, 100, XLAT("font scale"), ""); -#endif - - if(xuni =='z') - dialog::editNumber(vid.aurastr, 0, 256, 10, 128, XLAT("aura brightness"), ""); - if(xuni =='x') - dialog::editNumber(vid.aurasmoothen, 1, 180, 1, 5, XLAT("aura smoothening factor"), ""); - - if(xuni == 'e') { - dialog::editNumber(vid.eye, -10, 10, 0.01, 0, XLAT("distance between eyes"), - XLAT("Watch the Minkowski hyperboloid or the hypersian rug mode with the " - "red/cyan 3D glasses.")); - dialog::sidedialog = true; - } - -#ifdef STEAM - if(xuni == 'l') vid.steamscore = vid.steamscore^1; -#endif - if(xuni == 't') - dialog::editNumber(vid.flashtime, 0, 64, 1, 8, XLAT("message flash time"), - XLAT("How long should the messages stay on the screen.")); - if(xuni == 'i') { vid.shifttarget = vid.shifttarget^3; } + if(xuni == 'm') { vid.monmode += 60 + (shiftmul > 0 ? 1 : -1); vid.monmode %= 6; } + + if(xuni == '9') cmode = em3D; + +#ifndef NOEDIT + else if(xuni == 'g') { + cmode = emDraw; + mapeditor::initdraw(cwt.c); + } +#endif + + else if(xuni == 'x') { + viewdists = !viewdists; + cmode = emNormal; + } +#ifndef NORUG + else if(xuni == 'u') { + if(sphere) projectionDialog(); + else rug::select(); + } +#endif + else if(uni == 'a') + cmode = emConformal; + +#ifndef NOMODEL + else if(xuni == 'n') + cmode = emNetgen; +#endif + + else gmodekeys(sym, uni); + + handleAllConfig(sym, xuni); + } + +void switchHardcore() { + if(hardcore && !canmove) { + restartGame(); + hardcore = false; + cmode = emNormal; + } + else if(hardcore && canmove) { hardcore = false; } + else { hardcore = true; canmove = true; hardcoreAt = turncount; } + if(hardcore) + addMessage("One wrong move, and it is game over!"); + else + addMessage("Not so hardcore?"); + if(pureHardcore()) cmode = emNormal; } void showChangeMode() { @@ -876,6 +976,8 @@ void showChangeMode() { dialog::addBoolItem(XLAT("pure tactics mode"), (tactic::on), 't'); dialog::addBoolItem(XLAT("heptagonal mode"), (purehepta), '7'); dialog::addBoolItem(XLAT("Chaos mode"), (chaosmode), 'C'); + dialog::addBoolItem(XLAT("peaceful mode"), (chaosmode), 'P'); + dialog::addBoolItem(XLAT("inventory mode"), (inv::on), 'i'); dialog::addBreak(50); // cheating and map editor @@ -883,21 +985,8 @@ void showChangeMode() { dialog::addBoolItem(XLAT("cheat mode"), (cheater), 'c'); #ifndef NOEDIT dialog::addBoolItem(XLAT("map editor"), (false), 'm'); - dialog::addBreak(50); - dialog::addBoolItem(XLAT("vector graphics editor"), (false), 'g'); #endif - // display modes - -#ifndef NORUG - dialog::addBoolItem(XLAT("hypersian rug mode"), (rug::rugged), 'u'); -#endif -#ifndef NOMODEL - dialog::addBoolItem(XLAT("paper model creator"), (false), 'n'); -#endif - dialog::addBoolItem(XLAT("conformal/history mode"), (conformal::on), 'a'); - dialog::addBoolItem(XLAT("expansion"), viewdists, 'x'); - dialog::addBreak(50); dialog::addItem(XLAT("return to the game"), 'v'); @@ -908,7 +997,7 @@ void handleChangeMode(int sym, int uni) { dialog::handleNavigation(sym, uni); char xuni = uni; - if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal; + if(xuni == 'v' || sym == SDLK_ESCAPE) cmode = emNormal; else if(uni == 'c') { if(tactic::on && gold()) { @@ -929,43 +1018,27 @@ void handleChangeMode(int sym, int uni) { } } -#ifndef NOEDIT - else if(xuni == 'g') { - cmode = emDraw; - mapeditor::initdraw(cwt.c); - } -#endif else if(xuni == 'e') { cmode = emPickEuclidean; } - else if(xuni == 'x') { - viewdists = !viewdists; - cmode = emNormal; - } else if(xuni == 't') { clearMessages(); cmode = emTactic; } -#ifndef NORUG - else if(xuni == 'u') { - if(sphere) projectionDialog(); - else rug::select(); - } -#endif else if(xuni == 'y') { clearMessages(); if(yendor::everwon || autocheat) cmode = emYendor; - else { - cmode = emHelp; - help = yendor::chelp; - lastmode = emChangeMode; - } + else gotoHelp(yendor::chelp); } else if(xuni == '7') - restartGame('7'); - else if(uni == 'a') - cmode = emConformal; + restartGame('7'); + else if(xuni == 'P') + cmode = emPeace; + else if(xuni == 'i') { + restartGame('i'); + cmode = emNormal; + } #ifdef TOUR else if(uni == 'T') { cmode = emNormal; @@ -973,15 +1046,13 @@ void handleChangeMode(int sym, int uni) { } #endif else if(uni == 'C') { - if(!chaosmode) { - cmode = emHelp; - help = + if(!chaosmode) gotoHelp( "In the Chaos mode, lands change very often, and " "there are no walls between them. " "Some lands are incompatible with this." - "\n\nYou need to reach Crossroads IV to unlock the Chaos mode."; - lastmode = chaosUnlocked ? emNormal : emChangeMode; - } + "\n\nYou need to reach Crossroads IV to unlock the Chaos mode.", + chaosUnlocked ? emNormal : emChangeMode + ); if(chaosUnlocked) restartGame('C'); } else if(xuni == 'p') { @@ -1013,10 +1084,6 @@ void handleChangeMode(int sym, int uni) { cmode = emShmupConfig; #endif } -#ifndef NOMODEL - else if(xuni == 'n') - cmode = emNetgen; -#endif else if(xuni == 'h' && !shmup::on) switchHardcore(); else if(xuni == 'r') { @@ -1126,7 +1193,7 @@ void handleCustomizeChar(int sym, int uni) { if(xuni == 'd') switchcolor(cs.dresscolor, cat ? haircolors : dresscolors); if(xuni == 'f') switchcolor(cs.dresscolor2, dresscolors2); if(xuni == 'u') switchcolor(cs.uicolor, eyecolors); - if(xuni == 'v' || sym == SDLK_F2 || sym == SDLK_ESCAPE) cmode = emNormal; + if(xuni == 'v' || sym == SDLK_ESCAPE) cmode = emNormal; } int eupage = 0; @@ -1220,8 +1287,7 @@ void handleEuclidean(int sym, int uni) { } else euclidland = laIce; } - else if(uni == '2' || sym == SDLK_F1) { - help = + else if(uni == '2' || sym == SDLK_F1) gotoHelp( "If you want to know how much the gameplay is affected by the " "hyperbolic geometry in HyperRogue, this mode is for you!\n\n" @@ -1231,10 +1297,8 @@ void handleEuclidean(int sym, int uni) { "ultraparallel lines (Crossroads, Vineyard, Palace) cannot be " "faithfully represented in Euclidean, so yo get more " "or less simplified versions of them. Choose Crossroads to play a game " - "where many different lands appear."; - cmode = emHelp; - lastmode = emPickEuclidean; - } + "where many different lands appear." + ); else if(doexiton(sym, uni)) cmode = emNormal; } @@ -1259,12 +1323,12 @@ void showScores() { mouseovers = XLAT("t/left/right - change display, up/down - scroll, s - sort by") + modes; - displaystr(bx*4, vid.fsize*2, 0, vid.fsize, "#", 0xFFFFFF, 16); - displaystr(bx*8, vid.fsize*2, 0, vid.fsize, "$$$", 0xFFFFFF, 16); - displaystr(bx*12, vid.fsize*2, 0, vid.fsize, XLAT("kills"), 0xFFFFFF, 16); - displaystr(bx*18, vid.fsize*2, 0, vid.fsize, XLAT("time"), 0xFFFFFF, 16); - displaystr(bx*22, vid.fsize*2, 0, vid.fsize, XLAT("ver"), 0xFFFFFF, 16); - displaystr(bx*23, vid.fsize*2, 0, vid.fsize, displayfor(NULL), 0xFFFFFF, 0); + displaystr(bx*4, vid.fsize*2, 0, vid.fsize, "#", forecolor, 16); + displaystr(bx*8, vid.fsize*2, 0, vid.fsize, "$$$", forecolor, 16); + displaystr(bx*12, vid.fsize*2, 0, vid.fsize, XLAT("kills"), forecolor, 16); + displaystr(bx*18, vid.fsize*2, 0, vid.fsize, XLAT("time"), forecolor, 16); + displaystr(bx*22, vid.fsize*2, 0, vid.fsize, XLAT("ver"), forecolor, 16); + displaystr(bx*23, vid.fsize*2, 0, vid.fsize, displayfor(NULL), forecolor, 0); if(scorefrom < 0) scorefrom = 0; int id = 0; int omit = scorefrom; @@ -1448,7 +1512,6 @@ void showHelp() { getcstat = SDLK_ESCAPE; if(help == "HELPFUN") { help_delegate(); - dialog::display(); return; } @@ -1462,7 +1525,7 @@ void showHelp() { dialog::addHelp(help.substr(id+1)); } else { - dialog::init("help", 0xFFFFFF, 120, 100); + dialog::init("help", forecolor, 120, 100); dialog::addHelp(help); } @@ -1545,10 +1608,7 @@ void showDemo() { void handleDemoKey(int sym, int uni) { dialog::handleNavigation(sym, uni); - if(sym == SDLK_F1 || sym == 'h') { - lastmode = cmode; - cmode = emHelp; - } + if(sym == SDLK_F1 || sym == 'h') gotoHelp(help); else if(sym == 'a') { toggleanim(!demoanim); cmode = emNormal; @@ -1596,6 +1656,11 @@ void displayMenus() { if(cmode == emJoyConfig) showJoystickConfig(); if(cmode == emOverview) showOverview(); if(cmode == emYendor) yendor::showMenu(); + if(cmode == emPeace) peace::showMenu(); +#ifdef INV + if(cmode == emInventory) inv::showMenu(); +#endif + if(cmode == emSlideshows) tour::ss::showMenu(); if(cmode == emChangeMode) showChangeMode(); if(cmode == emCustomizeChar) showCustomizeChar(); if(cmode == emShmupConfig) shmup::showShmupConfig(); @@ -1604,8 +1669,9 @@ void displayMenus() { if(cmode == emPickEuclidean) showEuclideanMenu(); if(cmode == emMenu) showMainMenu(); if(cmode == emCheatMenu) showCheatMenu(); - if(cmode == emVisual1) showVisual1(); - if(cmode == emVisual2) showVisual2(); + if(cmode == emBasicConfig) showBasicConfig(); + if(cmode == emGraphConfig) showGraphConfig(); + if(cmode == emDisplayMode) showDisplayMode(); if(cmode == emColor) dialog::drawColorDialog(*dialog::colorPointer); if(cmode == emNumber) dialog::drawNumberDialog(); if(cmode == emLinepattern) linepatterns::showMenu(); diff --git a/nofont.cpp b/nofont.cpp index 634e2c6f..de9abb09 100644 --- a/nofont.cpp +++ b/nofont.cpp @@ -157,6 +157,7 @@ unsigned char fonttable[] = { 43,21,0,113,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,15,255,6,0,51,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,17,209,0,11,12,203,255,6,232,30,0,10,5,184,255,6,247,55,0,10,1,163,255,7,88,0,11,140,255,7,128,0,11,115,255,7,167,0,11,91,254,255,6,200,8,0,10,70,250,255,6,225,23,0,10,51,243,255,6,243,46,0,10,36,233,255,6,253,77,0,10,23,221,255,7,115,0,11,206,255,17,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,190, 43,26,0,6,158,255,2,155,3,0,3,3,155,255,2,157,0,13,9,208,255,2,179,10,0,1,10,180,255,2,207,8,0,14,36,240,255,2,200,42,201,255,2,240,35,0,16,80,255,3,254,255,3,79,0,18,138,255,5,138,0,90,255,23,0,3,255,23,0,3,255,23,0,3,255,23,0,3,255,22,163,0,16,50,245,255,6,195,6,0,15,27,229,255,6,221,20,0,15,10,205,255,6,239,40,0,15,1,174,255,6,251,67,0,16,136,255,7,101,0,16,95,255,7,140,0,16,61,249,255,6,177,2,0,15,34,235,255,6,206,11,0,15,15,214,255,6,229,27,0,15,4,186,255,6,245,50,0,16,150,255,6,253,80,0,16,110,255,7,117,0,16,73,252,255,6,155,0,16,43,241,255,6,189,5,0,15,22,223,255,6,216,17,0,15,7,197,255,6,236,36,0,16,164,255,22,0,3,255,23,0,3,255,23,0,3,255,23,0,3,255,23,0,235, 43,21,0,108,175,255,2,120,0,5,120,255,2,175,0,8,28,242,255,1,253,74,0,3,75,253,255,1,242,27,0,9,109,255,2,240,39,0,1,40,241,255,2,108,0,10,2,202,255,2,217,32,217,255,2,201,2,0,11,47,251,255,2,246,255,2,251,47,0,13,138,255,5,137,0,14,10,222,255,3,222,10,0,52,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,17,209,0,11,12,203,255,6,232,30,0,10,5,184,255,6,247,55,0,10,1,163,255,7,88,0,11,140,255,7,128,0,11,115,255,7,167,0,11,91,254,255,6,200,8,0,10,70,250,255,6,225,23,0,10,51,243,255,6,243,46,0,10,36,233,255,6,253,77,0,10,23,221,255,7,115,0,11,206,255,17,0,3,255,18,0,3,255,18,0,3,255,18,0,3,255,18,0,190, +43,25,0,182,40,115,172,207,234,245,253,243,228,193,144,67,2,0,10,32,183,255,12,221,77,0,8,32,234,255,15,0,8,165,255,16,0,8,234,255,16,0,8,245,255,5,98,25,6,2,9,15,34,55,91,138,214,0,8,197,255,5,169,87,44,15,0,15,70,253,255,8,240,190,130,51,0,12,83,235,255,11,207,83,0,10,77,230,255,13,178,15,0,7,95,253,255,15,200,14,0,5,57,249,255,6,214,207,249,255,8,155,0,4,2,212,255,5,232,77,0,2,5,50,148,252,255,5,253,45,0,3,86,255,5,237,37,0,6,67,248,255,5,130,0,3,169,255,5,116,0,8,128,255,5,199,0,3,224,255,5,35,0,8,41,255,5,228,0,3,247,255,5,6,0,8,7,255,5,248,0,3,242,255,5,13,0,8,12,255,5,239,0,3,221,255,5,56,0,8,56,255,5,218,0,3,179,255,5,148,0,8,152,255,5,173,0,3,108,255,5,252,71,0,6,77,253,255,5,102,0,3,22,243,255,5,250,141,48,9,10,50,145,252,255,5,239,16,0,4,129,255,18,119,0,5,5,188,255,16,177,2,0,6,14,180,255,14,172,11,0,8,1,106,227,255,10,225,101,0,12,4,81,147,204,229,247,247,230,204,148,81,4,0,231, 43,29,0,185,84,92,92,92,92,92,30,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,21,2,237,255,5,87,0,17,4,79,156,210,247,255,6,254,226,182,110,27,0,12,69,218,255,14,248,139,5,0,9,81,251,255,17,181,2,0,7,24,238,255,19,111,0,7,154,255,6,241,251,255,5,236,255,6,243,15,0,5,16,245,255,5,234,32,236,255,5,85,161,255,6,110,0,5,89,255,6,92,0,1,236,255,5,84,13,232,255,5,193,0,5,148,255,5,231,4,0,1,236,255,5,84,0,1,131,255,5,245,4,0,4,186,255,5,165,0,2,236,255,5,84,0,1,62,255,6,33,0,4,204,255,5,132,0,2,236,255,5,84,0,1,29,255,6,51,0,4,208,255,5,125,0,2,236,255,5,84,0,1,22,255,6,56,0,4,188,255,5,144,0,2,236,255,5,84,0,1,41,255,6,35,0,4,159,255,5,195,0,2,236,255,5,84,0,1,92,255,5,251,10,0,4,92,255,5,254,45,0,1,236,255,5,84,1,195,255,5,195,0,5,20,246,255,5,221,38,236,255,5,88,151,255,6,114,0,6,139,255,6,243,249,255,5,237,255,6,232,10,0,6,16,218,255,18,254,84,0,8,37,234,255,17,122,0,10,31,201,255,14,242,96,0,12,1,90,196,254,255,9,229,138,22,0,16,23,77,244,255,5,144,46,2,0,20,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,236,255,5,84,0,22,114,124,124,124,124,124,40,0,40, 43,25,0,6,255,4,0,3,255,4,0,14,255,4,0,3,255,4,0,14,255,4,0,3,255,4,0,14,255,4,0,3,255,4,0,111,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,18,0,7,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,6,0,19,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,6,255,19,0,228, 43,28,0,233,77,255,8,76,0,18,174,255,8,173,0,17,21,250,255,8,250,20,0,16,113,255,10,112,0,16,210,255,10,209,0,15,52,255,12,51,0,14,149,255,5,214,214,255,5,148,0,13,8,238,255,5,117,118,255,5,238,7,0,12,88,255,5,252,24,25,252,255,5,87,0,12,185,255,5,179,0,2,180,255,5,184,0,11,29,253,255,5,81,0,2,82,255,5,253,28,0,10,124,255,5,235,5,0,2,5,235,255,5,123,0,10,220,255,5,143,0,4,144,255,5,219,0,9,63,255,6,46,0,4,47,255,6,62,0,8,160,255,5,205,0,6,206,255,5,159,0,7,13,244,255,5,108,0,6,109,255,5,244,12,0,6,99,255,20,98,0,6,196,255,20,195,0,5,38,255,22,37,0,4,135,255,22,134,0,3,3,229,255,22,228,3,0,2,74,255,6,36,0,10,36,255,6,73,0,2,171,255,5,193,0,12,194,255,5,170,0,1,19,249,255,5,95,0,12,96,255,5,248,18,110,255,5,242,11,0,12,11,243,255,5,109,207,255,5,156,0,14,157,255,5,207,0,252, @@ -223,6 +224,7 @@ unsigned char fonttable[] = { 43,35,0,255,0,238,255,6,0,8,16,103,161,211,232,248,246,228,204,149,86,6,0,9,255,6,0,6,10,144,245,255,10,231,115,2,0,7,255,6,0,5,32,216,255,14,191,20,0,6,255,6,0,4,23,221,255,16,199,9,0,5,255,6,0,4,177,255,18,143,0,5,255,6,0,3,63,255,6,244,127,44,10,8,42,126,243,255,5,248,30,0,4,255,6,0,3,165,255,5,243,48,0,6,48,244,255,5,117,0,4,255,6,0,3,225,255,5,126,0,8,126,255,5,187,0,4,255,6,252,244,236,255,6,42,0,8,43,255,5,223,0,4,255,15,8,0,8,9,255,5,245,0,4,255,15,8,0,8,9,255,5,245,0,4,255,6,220,220,220,254,255,5,42,0,8,43,255,5,223,0,4,255,6,0,3,219,255,5,125,0,8,125,255,5,187,0,4,255,6,0,3,157,255,5,243,46,0,6,45,243,255,5,117,0,4,255,6,0,3,56,255,6,243,125,43,8,8,41,123,242,255,5,249,30,0,4,255,6,0,4,171,255,18,143,0,5,255,6,0,4,21,219,255,16,200,9,0,5,255,6,0,5,31,215,255,14,192,20,0,6,255,6,0,6,10,143,245,255,10,232,116,2,0,7,255,6,0,8,16,103,162,211,233,248,247,230,205,150,86,7,0,255,0,66, 43,23,0,255,0,72,8,90,163,206,236,247,255,10,0,6,63,227,255,15,0,5,38,246,255,16,0,5,161,255,17,0,5,228,255,17,0,5,250,255,5,151,39,8,0,3,255,6,0,5,235,255,5,17,0,5,255,6,0,5,173,255,5,152,38,7,0,3,255,6,0,5,58,254,255,16,0,6,125,255,16,0,7,136,254,255,14,0,8,128,255,14,0,7,4,216,255,14,0,7,105,255,6,113,0,2,255,6,0,6,13,233,255,5,221,6,0,2,255,6,0,6,132,255,6,86,0,3,255,6,0,5,27,245,255,5,200,0,4,255,6,0,5,159,255,6,60,0,4,255,6,0,4,46,253,255,5,175,0,5,255,6,0,4,185,255,5,251,39,0,5,255,6,0,209, 43,24,0,150,255,4,0,3,255,4,0,13,255,4,0,3,255,4,0,13,255,4,0,3,255,4,0,13,255,4,0,3,255,4,0,110,9,92,155,209,231,248,242,221,179,112,24,0,11,3,122,236,255,9,246,140,8,0,8,22,195,255,13,202,25,0,6,10,201,255,15,202,8,0,5,145,255,5,246,129,41,7,14,74,206,255,5,140,0,4,31,249,255,4,252,67,0,5,9,203,255,4,246,24,0,3,118,255,5,146,0,7,69,255,5,112,0,3,188,255,5,60,0,7,11,255,5,179,0,3,225,255,19,221,0,3,246,255,19,242,0,3,246,255,20,0,3,225,255,20,0,3,190,255,5,25,0,17,120,255,5,109,0,17,34,251,255,4,238,45,0,9,15,103,205,0,5,150,255,5,245,137,55,15,3,15,33,75,123,191,251,255,2,0,5,13,206,255,17,0,6,24,198,255,16,0,7,3,120,233,255,14,0,9,6,85,148,202,228,245,253,246,236,216,192,159,122,76,25,0,218, +43,17,0,113,9,12,12,12,2,0,12,196,255,3,56,0,12,196,255,3,56,0,12,196,255,3,56,0,8,2,0,3,196,255,3,56,0,5,75,193,247,252,219,128,9,196,255,3,56,0,4,122,255,6,204,211,255,3,56,0,3,63,254,255,3,202,144,178,254,255,4,56,0,3,181,255,3,167,1,0,2,104,255,4,56,0,3,245,255,3,51,0,3,3,237,255,3,56,0,2,14,255,4,17,0,4,206,255,3,56,0,2,6,255,4,30,0,4,219,255,3,56,0,3,219,255,3,93,0,3,32,251,255,3,56,0,3,130,255,3,230,74,16,49,199,255,4,56,0,3,14,221,255,6,254,242,255,3,56,0,4,31,203,255,4,241,92,196,255,3,56,0,5,1,66,121,127,92,17,0,1,49,64,64,64,14,0,255,0,86, 255 }; diff --git a/polygons.cpp b/polygons.cpp index fa70da4b..0e3d6751 100644 --- a/polygons.cpp +++ b/polygons.cpp @@ -11,6 +11,8 @@ bool first; bool fatborder; +int poly_outline; + #define PSHIFT 0 // #define STLSORT @@ -25,6 +27,10 @@ struct hpcshape { hpcshape *last = NULL; +#ifndef GL +typedef float GLfloat; +#endif + struct qpoly { transmatrix V; GLfloat *tab; @@ -36,9 +42,10 @@ struct qpoly { struct qline { hyperpoint H1, H2; int prf; + double width; }; -#define MAXQCHR 16 +#define MAXQCHR 40 struct qchr { char str[MAXQCHR]; @@ -122,17 +129,17 @@ SDL_Surface *aux; vector ptds2; +#define POLYMAX 60000 + #ifdef GL #define USEPOLY GLuint shapebuffer; -#define POLYMAX 60000 GLfloat glcoords[POLYMAX][3]; int qglcoords; extern void glcolor(int color); -#endif GLfloat *currentvertices; @@ -142,7 +149,25 @@ void activateVertexArray(GLfloat *f, int qty) { glVertexPointer(3, GL_FLOAT, 0, f); } +extern GLfloat *ourshape; +void activateShapes() { + if(currentvertices != ourshape) { + activateVertexArray(ourshape, qhpc); + } + } + +void activateGlcoords() { + activateVertexArray(glcoords[0], qglcoords); + } +#endif + +#ifdef GFX +#define POLYMAX 60000 +#define USEPOLY +#endif + +#ifdef USEPOLY GLfloat *ourshape = NULL; void initPolyForGL() { @@ -158,24 +183,11 @@ void initPolyForGL() { ourshape[id++] = hpc[i][1]; ourshape[id++] = hpc[i][2]; } - + +#ifdef GL currentvertices = NULL; +#endif } - -void activateShapes() { - if(currentvertices != ourshape) { - activateVertexArray(ourshape, qhpc); - } - } - -void activateGlcoords() { - activateVertexArray(glcoords[0], qglcoords); - } - - -#ifdef GFX -#define POLYMAX 60000 -#define USEPOLY #endif int polyi; @@ -189,6 +201,7 @@ hyperpoint gltopoint(GLfloat t[3]) { } void addpoint(const hyperpoint& H) { +#ifdef GL if(vid.usingGL) { if(polyi >= POLYMAX) return; if(pmodel) { @@ -211,6 +224,9 @@ void addpoint(const hyperpoint& H) { } qglcoords++; } +#else + if(0) {} +#endif else { if(polyi >= POLYMAX) return; hyperpoint Hscr; @@ -256,6 +272,7 @@ void filledPolygonColorI(SDL_Surface *s, int* polyx, int *polyy, int polyi, int } #endif +#ifdef GL void glcolor2(int color) { unsigned char *c = (unsigned char*) (&color); glColor4f(c[3] / 255.0, c[2] / 255.0, c[1]/255.0, c[0] / 255.0); @@ -339,7 +356,22 @@ void gldraw(int useV, const transmatrix& V, int ps, int pq, int col, int outline if(useV) glPopMatrix(); } } +#endif +double linewidthat(const hyperpoint& h) { + if(vid.antialias & AA_LINEWIDTH) { + double dz = h[2]; + if(dz < 1 || abs(dz-vid.scrdist) < 1e-6) return vid.linewidth; + else { + double dx = sqrt(dz * dz - 1); + double dfc = dx/(dz+1); + dfc = 1 - dfc*dfc; + return dfc * vid.linewidth; + } + } + return vid.linewidth; + } + void drawpolyline(const transmatrix& V, GLfloat* tab, int cnt, int col, int outline) { #ifdef GL if(vid.usingGL) { @@ -347,7 +379,8 @@ void drawpolyline(const transmatrix& V, GLfloat* tab, int cnt, int col, int outl const int pq = cnt; if(currentvertices != tab) activateVertexArray(tab, pq); - const int ps=0; + const int ps=0; + glLineWidth(linewidthat(tC0(V))); gldraw(1, V, ps, pq, col, outline); } else { @@ -388,7 +421,7 @@ void drawpolyline(const transmatrix& V, GLfloat* tab, int cnt, int col, int outl filledPolygonColorI(s, polyx, polyy, polyi, col); if(vid.goteyes) filledPolygonColorI(aux, polyxr, polyy, polyi, col); - (vid.usingAA?aapolylineColor:polylineColor)(s, polyx, polyy, polyi, outline); + ((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(s, polyx, polyy, polyi, outline); if(vid.goteyes) aapolylineColor(aux, polyxr, polyy, polyi, outline); if(vid.xres >= 2000 || fatborder) { @@ -448,6 +481,7 @@ void drawqueueitem(polytodraw& ptd) { drawpolyline(ptd.u.poly.V, ptd.u.poly.tab, ptd.u.poly.cnt, ptd.col, ptd.u.poly.outline); } else if(ptd.kind == pkLine) { + dynamicval d(vid.linewidth, ptd.u.line.width); prettyline(ptd.u.line.H1, ptd.u.line.H2, ptd.col, ptd.u.line.prf); } else if(ptd.kind == pkString) { @@ -456,13 +490,8 @@ void drawqueueitem(polytodraw& ptd) { if(svg::in) svg::text(q.x, q.y, q.size, q.str, q.frame, ptd.col, q.align); else { - if(q.frame) { - displaystr(q.x-q.frame, q.y, q.shift, q.size, q.str, 0, q.align); - displaystr(q.x+q.frame, q.y, q.shift, q.size, q.str, 0, q.align); - displaystr(q.x, q.y-q.frame, q.shift, q.size, q.str, 0, q.align); - displaystr(q.x, q.y+q.frame, q.shift, q.size, q.str, 0, q.align); - } - displaystr(q.x, q.y, q.shift, q.size, q.str, ptd.col, q.align); + int fr = q.frame & 255; + displayfrSP(q.x, q.y, q.shift, fr, q.size, q.str, ptd.col, q.align, q.frame >> 8); } #else displayfr(q.x, q.y, q.frame, q.size, q.str, ptd.col, q.align); @@ -489,6 +518,12 @@ void drawqueueitem(polytodraw& ptd) { } SDL_UnlockSurface(aux); } +#endif + } + +void initquickqueue() { + ptds.clear(); + poly_outline = OUTLINE_NONE; } void quickqueue() { @@ -565,13 +600,13 @@ void drawqueue() { drawqueueitem(ptd); } +#ifdef GL if(vid.goteyes && vid.usingGL) selectEyeGL(0), selectEyeMask(0); - -#endif #endif setcameraangle(false); curvedata.clear(); curvestart = 0; +#endif } hpcshape @@ -1574,8 +1609,6 @@ void initShape(int sg, int id) { } } -int poly_outline; - unsigned char& part(int& col, int i) { unsigned char* c = (unsigned char*) &col; return c[i]; } @@ -1698,6 +1731,7 @@ void queueline(const hyperpoint& H1, const hyperpoint& H2, int col, int prf = 0, ptd.u.line.H1 = H1; ptd.u.line.H2 = H2; ptd.u.line.prf = prf; + ptd.u.line.width = (linewidthat(H1) + linewidthat(H2)) / 2; ptd.col = (darkened(col >> 8) << 8) + (col & 0xFF); ptd.prio = prio << PSHIFT; } @@ -1713,7 +1747,7 @@ void queuestr(int x, int y, int shift, int size, string str, int col, int frame ptd.u.chr.shift = shift; ptd.u.chr.size = size; ptd.col = darkened(col); - ptd.u.chr.frame = frame; + ptd.u.chr.frame = frame ? (poly_outline & ~ 255) : 0; ptd.prio = PPR_TEXT << PSHIFT; } @@ -1728,7 +1762,7 @@ void queuechr(int x, int y, int shift, int size, char chr, int col, int frame = ptd.u.chr.size = size; ptd.u.chr.align = align; ptd.col = col; - ptd.u.chr.frame = frame; + ptd.u.chr.frame = frame ? (poly_outline & ~ 255) : 0; ptd.prio = PPR_TEXT << PSHIFT; } @@ -1912,6 +1946,7 @@ namespace svg { dynamicval v(vid, vid); dynamicval v2(in, true); dynamicval v4(cheater, 0); + dynamicval v5(ringcolor, 0x808080FF); vid.usingGL = false; vid.xres = vid.yres = svgsize ? svgsize : min(1 << (sightrange+7), 16384); diff --git a/rogueviz.cpp b/rogueviz.cpp index 7d920157..acc24c5c 100644 --- a/rogueviz.cpp +++ b/rogueviz.cpp @@ -163,11 +163,26 @@ void createViz(int id, cell *c, transmatrix at) { vd.m->at = at; } +void notimpl() { + printf("Not implemented\n"); exit(1); + } + +hyperpoint where(int i) { + auto m = vdata[i].m; + if(m->base == currentmap->gamestart()) return tC0(m->at); + else { + notimpl(); // actually probably that's a buug + return inverse(shmup::ggmatrix(currentmap->gamestart())) * (shmup::ggmatrix(m->base) * tC0(m->at)); + } + } + void addedge(int i, int j, edgeinfo *ei) { - double d = hdist(vdata[i].m->at * C0, vdata[j].m->at * C0); + hyperpoint hi = where(i); + hyperpoint hj = where(j); + double d = hdist(hi, hj); if(d >= 4) { // printf("splitting %lf\n", d); - hyperpoint h = mid(vdata[i].m->at * C0, vdata[j].m->at * C0); + hyperpoint h = mid(hi, hj); int id = size(vdata); vdata.resize(id+1); vertexdata& vd(vdata[id]); @@ -178,6 +193,7 @@ void addedge(int i, int j, edgeinfo *ei) { addedge(i, id, ei); addedge(id, j, ei); + shmup::virtualRebase(vd.m, true); } else addedge0(i, j, ei); } @@ -204,7 +220,14 @@ int dftcolor = 0x282828FF; namespace spiral { - void place(int N, ld mul) { + ld mul; + + transmatrix at(double d) { + return spin(log(d) * 2 * M_PI / log(mul)) * xpush(log(d)); + } + + void place(int N, ld _mul) { + mul = _mul; init(); kind = kSpiral; vdata.resize(N); @@ -213,7 +236,7 @@ namespace spiral { double d = i + 1; - transmatrix h = spin(log(d) * 2 * M_PI / log(mul)) * xpush(log(d)); + transmatrix h = at(d); createViz(i, cwt.c, h); vd.name = its(i+1); @@ -265,17 +288,35 @@ namespace collatz { } } -int readLabel(FILE *f) { +string readLabel_s(FILE *f) { char xlabel[10000]; - if(fscanf(f, "%9500s", xlabel) <= 0) return -1; - return getid(xlabel); + if(fscanf(f, "%9500s", xlabel) <= 0) return ""; + return xlabel; + } + +int readLabel(FILE *f) { + string s = readLabel_s(f); + if(s == "") return -1; + return getid(s); } namespace anygraph { double R, alpha, T; vector > coords; + + int N; + + void fixedges() { + for(int i=N; idead = true; + for(int i=0; iorig = NULL; + addedge(e->i, e->j, e); + } + } - void read(string fn, bool subdiv = true, bool doRebase = true) { + void read(string fn, bool subdiv = true, bool doRebase = true, bool doStore = true) { init(); kind = kAnyGraph; fname = fn; FILE *f = fopen((fn + "-coordinates.txt").c_str(), "rt"); @@ -285,17 +326,17 @@ namespace anygraph { } printf("Reading coordinates...\n"); char buf[100]; - int N; int err; err = fscanf(f, "%s%s%s%s%d%lf%lf%lf", buf, buf, buf, buf, &N, &anygraph::R, &anygraph::alpha, &anygraph::T); if(err < 8) { printf("Error: incorrect format of the first line\n"); exit(1); } vdata.reserve(N); while(true) { - int id = readLabel(f); - if(id < 0) break; + string s = readLabel_s(f); + if(s == "" || s == "-1") break; + int id = getid(s); vertexdata& vd(vdata[id]); - vd.name = its(id); + vd.name = s; vd.cp = colorpair(dftcolor); double r, alpha; @@ -333,6 +374,8 @@ namespace anygraph { } printf("Done.\n"); } + + if(doStore) storeall(); } } @@ -1030,8 +1073,7 @@ void drawVertex(const transmatrix &V, cell *c, shmup::monster *m) { transmatrix& gm1 = shmup::ggmatrix(vd1.m->base); transmatrix& gm2 = shmup::ggmatrix(vd2.m->base); - - + hyperpoint h1 = gm1 * vd1.m->at * C0; hyperpoint h2 = gm2 * vd2.m->at * C0; @@ -1046,11 +1088,25 @@ void drawVertex(const transmatrix &V, cell *c, shmup::monster *m) { } */ int col = - ((hilite ? 0xFF0000 : backcolor ? 0x808080 : 0xFFFFFF) << 8) + xlalpha; - - if(pmodel) { - queueline(h1, h2, col, 2); - lastptd().prio = PPR_STRUCT0; + ((hilite ? 0xFF0000 : forecolor) << 8) + xlalpha; + + bool onspiral = kind == kSpiral && abs(ei->i - ei->j) == 1; + if(pmodel || onspiral) { + if(onspiral) { + const int prec = 20; + transmatrix T = shmup::ggmatrix(currentmap->gamestart()); + hyperpoint l1 = T*tC0(spiral::at(1+ei->i)); + for(int z=1; z<=prec; z++) { + hyperpoint l2 = T*tC0(spiral::at(1+ei->i+(ei->j-ei->i) * z / (prec+.0))); + queueline(l1, l2, col, 0); + l1 = l2; + lastptd().prio = PPR_STRUCT0; + } + } + else { + queueline(h1, h2, col, 2); + lastptd().prio = PPR_STRUCT0; + } } else { @@ -1058,8 +1114,22 @@ void drawVertex(const transmatrix &V, cell *c, shmup::monster *m) { if(!ei->orig) { ei->orig = euclid ? cwt.c : viewctr.h->c7; // cwt.c; ei->prec.clear(); + transmatrix T = inverse(shmup::ggmatrix(ei->orig)); - storeline(ei->prec, T*h1, T*h2); + + if(kind == kSpiral && abs(ei->i - ei->j) == 1) { + ei->orig = currentmap->gamestart(); + hyperpoint l1 = tC0(spiral::at(1+ei->i)); + storevertex(ei->prec, l1); + const int prec = 20; + for(int z=1; z<=prec; z++) { + hyperpoint l2 = tC0(spiral::at(1+ei->i+(ei->j-ei->i) * z / (prec+.0))); + storeline(ei->prec, l1, l2); + l1 = l2; + } + } + else + storeline(ei->prec, T*h1, T*h2); } queuetable(shmup::ggmatrix(ei->orig), &ei->prec[0], size(ei->prec)/3, col, 0, PPR_STRUCT0); @@ -1180,12 +1250,15 @@ void drawExtra() { for(int i=0; i function roguevizslide(char c, T t) { }; } +template function roguevizslide_action(char c, T t, T1 act) { + return [c,t,act] (presmode mode) { + mapeditor::canvasback = 0x101010; + setCanvas(mode, c); + if(mode == 1 || mode == pmGeometryStart) t(); + + if(mode == 3 || mode == pmGeometry || mode == pmGeometryReset) { + rogueviz::close(); + shmup::clearMonsters(); + if(mode == pmGeometryReset) t(); + } + + act(mode); + }; + } + +#define RVPATH HYPERPATH "rogueviz/" + slide rvslides[] = { - {"HyperRogue", 999, LEGAL_ANY, + {"RogueViz", 999, LEGAL_ANY, "This is a presentation of RogueViz, which " "is an adaptation of HyperRogue as a visualization tool " "rather than a game. Hyperbolic space is great " @@ -1751,15 +1848,16 @@ slide rvslides[] = { , [] (presmode mode) { slidecommand = "the standard presentation"; + if(mode == pmStartAll) firstland = euclidland = laPalace; if(mode == 4) { tour::slides = default_slides; while(tour::on) restartGame('T', false); - firstland = euclidland = laIce; + firstland = euclidland = laIce; tour::start(); } } }, - {"HyperRogue", 999, LEGAL_ANY, + {"straight lines in the Palace", 999, LEGAL_ANY, "One simple slide about HyperRogue. Press '5' to show some hyperbolic straight lines.", [] (presmode mode) { using namespace linepatterns; @@ -1812,9 +1910,9 @@ slide rvslides[] = { drawthemap(); gmatrix0 = gmatrix; - rogueviz::sag::read("rogueviz/roguelikes/edges.csv"); - rogueviz::readcolor("rogueviz/roguelikes/color.csv"); - rogueviz::sag::loadsnake("rogueviz/roguelikes/" + cname()); + rogueviz::sag::read(RVPATH "roguelikes/edges.csv"); + rogueviz::readcolor(RVPATH "roguelikes/color.csv"); + rogueviz::sag::loadsnake(RVPATH "roguelikes/" + cname()); }) }, {"Programming languages of GitHub", 64, LEGAL_UNLIMITED, @@ -1832,9 +1930,9 @@ slide rvslides[] = { drawthemap(); gmatrix0 = gmatrix; - rogueviz::sag::read("rogueviz/lang/edges.csv"); - rogueviz::readcolor("rogueviz/lang/color.csv"); - rogueviz::sag::loadsnake("rogueviz/lang/" + cname()); + rogueviz::sag::read(RVPATH "lang/edges.csv"); + rogueviz::readcolor(RVPATH "lang/color.csv"); + rogueviz::sag::loadsnake(RVPATH "lang/" + cname()); if(euclid) rogueviz::legend.clear(); }) }, @@ -1853,9 +1951,9 @@ slide rvslides[] = { drawthemap(); gmatrix0 = gmatrix; - rogueviz::sag::read("rogueviz/boardgames/edges.csv"); - rogueviz::readcolor("rogueviz/boardgames/color.csv"); - rogueviz::sag::loadsnake("rogueviz/boardgames/" + cname()); + rogueviz::sag::read(RVPATH "boardgames/edges.csv"); + rogueviz::readcolor(RVPATH "boardgames/color.csv"); + rogueviz::sag::loadsnake(RVPATH "boardgames/" + cname()); }) }, {"Tree of Life", 61, LEGAL_UNLIMITED, @@ -1872,7 +1970,7 @@ slide rvslides[] = { drawthemap(); gmatrix0 = gmatrix; - rogueviz::tree::read("rogueviz/treeoflife/tol.txt"); + rogueviz::tree::read(RVPATH "treeoflife/tol.txt"); })}, {"THE END", 99, LEGAL_ANY | FINALSLIDE, "Press '5' to leave the presentation.", diff --git a/rug.cpp b/rug.cpp index 80ddb699..fa055e0a 100644 --- a/rug.cpp +++ b/rug.cpp @@ -8,6 +8,7 @@ #define TEXTURESIZE (texturesize) #define HTEXTURESIZE (texturesize/2) +#ifdef AVOID_GLEW #ifdef LINUX extern "C" { GLAPI void APIENTRY glGenFramebuffers (GLsizei n, GLuint *framebuffers); @@ -27,6 +28,7 @@ GLAPI void APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint *framebuffers) #ifdef MAC #define glFramebufferTexture glFramebufferTextureEXT #endif +#endif namespace rug { @@ -389,7 +391,11 @@ void initTexture() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +#ifdef TEX glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0); +#else + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0); +#endif GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, DrawBuffers); @@ -467,6 +473,11 @@ void closeTexture() { double xview, yview; +void glcolorClear(int color) { + unsigned char *c = (unsigned char*) (&color); + glClearColor(c[3] / 255.0, c[2] / 255.0, c[1]/255.0, c[0] / 255.0); + } + void drawRugScene() { GLfloat light_ambient[] = { 3.5, 3.5, 3.5, 1.0 }; GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; @@ -490,7 +501,10 @@ void drawRugScene() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glClearColor(0.05,0.05,0.05,1); + if(backcolor == 0) + glClearColor(0.05,0.05,0.05,1); + else + glcolorClear(backcolor << 8 | 0xFF); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -555,7 +569,7 @@ transmatrix rotmatrix(double rotation, int c0, int c1) { transmatrix currentrot; void init() { -#ifdef WINDOWS +#ifndef AVOID_GLEW if(!glew) { glew = true; GLenum err = glewInit(); diff --git a/shmup.cpp b/shmup.cpp index 7c796743..47975d1b 100644 --- a/shmup.cpp +++ b/shmup.cpp @@ -573,9 +573,9 @@ void initConfig() { char* t = vid.scfg.keyaction; t['w'] = 16 + 4; - t['s'] = 16 + 5; - t['a'] = 16 + 6; - t['d'] = 16 + 7; + t['d'] = 16 + 5; + t['s'] = 16 + 6; + t['a'] = 16 + 7; #ifndef MOBILE t[SDLK_KP8] = 16 + 4; @@ -2925,7 +2925,9 @@ void turn(int delta) { } } - for(monster *m: additional) active.push_back(m); additional.clear(); + for(monster *m: additional) + active.push_back(m); + additional.clear(); // deactivate all monsters for(monster *m: active) diff --git a/sound.cpp b/sound.cpp index 5364cdb7..4dc90ed0 100644 --- a/sound.cpp +++ b/sound.cpp @@ -69,9 +69,8 @@ void handlemusic() { DEBB(DF_GRAPH, (debugfile,"handle music\n")); if(audio && musicvolume) { eLand id = getCurrentLandForMusic(); -#ifdef LOCAL - extern bool local_changemusic(eLand& id); - if(local_changemusic(id)) return; +#ifdef EXTRA_MUSIC + if(extra::changemusic(id)) return; #endif if(outoffocus) id = eLand(0); if(musfname[id] == "LAST") id = cid; @@ -154,6 +153,7 @@ bool loadMusicInfo(string dir) { bool loadMusicInfo() { return loadMusicInfo(musicfile) + || loadMusicInfo(HYPERPATH "hyperrogue-music.txt") || loadMusicInfo("./hyperrogue-music.txt") || loadMusicInfo("music/hyperrogue-music.txt") // Destination set by ./configure (in the GitHub repository) @@ -187,7 +187,7 @@ map chunks; #ifdef SOUNDDESTDIR string wheresounds = SOUNDDESTDIR; #else -string wheresounds = "sounds/"; +string wheresounds = HYPERPATH "sounds/"; #endif void playSound(cell *c, const string& fname, int vol) { diff --git a/system.cpp b/system.cpp index 6b11e35b..f09ee4f9 100644 --- a/system.cpp +++ b/system.cpp @@ -26,6 +26,8 @@ void initgame() { firstland = safetyland; } + if(peace::on) euclidland = firstland = peace::whichland; + if(tactic::on && (euclid || sphere)) euclidland = firstland; if(firstland == laNone || firstland == laBarrier) @@ -50,7 +52,7 @@ void initgame() { setdist(cwt.c, BARLEV, NULL); - if((tactic::on || yendor::on) && isCyclic(firstland)) { + if((tactic::on || yendor::on || peace::on) && isCyclic(firstland)) { anthraxBonus = items[itHolyGrail]; cwt.c->mov[0]->land = firstland; if(firstland == laWhirlpool) cwt.c->mov[0]->wall = waSea; @@ -149,6 +151,8 @@ void initgame() { items[treasureType(firstland)] = 15; yendor::init(3); + peace::simon::init(); + multi::revive_queue.clear(); #ifdef TOUR if(tour::on) tour::presentation(tour::pmRestart); @@ -178,7 +182,10 @@ void initgame() { timerghost = true; truelotus = 0; survivalist = true; - if(!randomPatternsMode && !tactic::on && !yendor::on) { +#ifdef INV + if(inv::on) inv::init(); +#endif + if(!randomPatternsMode && !tactic::on && !yendor::on && !peace::on) { if(firstland != (princess::challenge ? laPalace : laIce)) cheater++; } if(tactic::trailer) ; @@ -206,6 +213,7 @@ void initgame() { addMessage(XLAT("You are playing %the1 in the Pure Tactics mode.", firstland)); else if(yendor::on) addMessage(XLAT("Welcome to the Yendor Challenge %1!", its(yendor::challenge))); + else if(peace::on) ; // no welcome message else if(shmup::on) ; // welcome message given elsewhere else if(euclid) addMessage(XLAT("Welcome to the Euclidean mode!")); @@ -598,7 +606,7 @@ void loadBoxHigh() { // certify that saves and achievements were received // in an official version of HyperRogue #ifdef CERTIFY -#include "certify.cpp" +#include "private/certify.cpp" #else namespace anticheat { @@ -636,6 +644,7 @@ void saveStats(bool emergency = false) { if(tour::on) return; #endif if(randomPatternsMode) return; + if(peace::on) return; remove_emergency_save(); @@ -718,6 +727,7 @@ void saveStats(bool emergency = false) { if(purehepta) fprintf(f, "Heptagons only mode\n"); if(chaosmode) fprintf(f, "Chaos mode\n"); if(shmup::on) fprintf(f, "Shoot-em up mode\n"); + if(inv::on) fprintf(f, "Inventory mode\n"); if(multi::players > 1) fprintf(f, "Multi-player (%d players)\n", multi::players); fprintf(f, "Number of cells explored, by distance from the player:\n"); {for(int i=0; i<10; i++) fprintf(f, " %d", explore[i]);} fprintf(f, "\n"); @@ -951,6 +961,16 @@ void restartGame(char switchWhat, bool push) { cellcount = 0; clearMemory(); } + if(switchWhat == 'P') { + peace::on = !peace::on; + tactic::on = yendor::on = princess::challenge = + randomPatternsMode = inv::on = false; + } + if(switchWhat == 'i') { + inv::on = !inv::on; + tactic::on = yendor::on = princess::challenge = + randomPatternsMode = peace::on = false; + } if(switchWhat == 'C') { geometry = gNormal; yendor::on = tactic::on = princess::challenge = false; @@ -960,7 +980,7 @@ void restartGame(char switchWhat, bool push) { #ifdef TOUR if(switchWhat == 'T') { geometry = gNormal; - yendor::on = tactic::on = princess::challenge = false; + yendor::on = tactic::on = princess::challenge = peace::on = inv::on = false; chaosmode = purehepta = randomPatternsMode = false; shmup::on = false; resetGeometry(); @@ -982,6 +1002,8 @@ void restartGame(char switchWhat, bool push) { if(switchWhat == 'y') { yendor::on = !yendor::on; tactic::on = false; + peace::on = false; + inv::on = false; princess::challenge = false; randomPatternsMode = false; chaosmode = false; @@ -990,6 +1012,8 @@ void restartGame(char switchWhat, bool push) { if(switchWhat == 't') { tactic::on = !tactic::on; yendor::on = false; + peace::on = false; + inv::on = false; randomPatternsMode = false; princess::challenge = false; chaosmode = false; @@ -1003,6 +1027,8 @@ void restartGame(char switchWhat, bool push) { randomPatternsMode = !randomPatternsMode; tactic::on = false; yendor::on = false; + peace::on = false; + inv::on = false; princess::challenge = false; } if(switchWhat == 'p') { @@ -1012,6 +1038,7 @@ void restartGame(char switchWhat, bool push) { tactic::on = false; yendor::on = false; chaosmode = false; + inv::on = false; } initcells(); @@ -1385,11 +1412,9 @@ bool applyCheat(char u, cell *c = NULL) { cblind = !cblind; return true; } -#ifdef LOCAL - if(u == 'K'-64) { - printf("viewctr = %p.%d\n", viewctr.h, viewctr.spin); - display(View); - } + if(u == 'P'-64) + peace::on = !peace::on; +#ifdef CHEAT_DISABLE_ALLOWED if(u == 'D'-64) { cheater = 0; autocheat = 0; return true; diff --git a/tour.cpp b/tour.cpp index fb0d2a45..2c07674a 100644 --- a/tour.cpp +++ b/tour.cpp @@ -72,7 +72,7 @@ void presentation(presmode mode) { } void slidehelp() { - if(texts) { + if(texts && slides[currentslide].help[0]) { help = helptitle(XLAT(slides[currentslide].name), 0xFF8000) + XLAT(slides[currentslide].help); @@ -87,7 +87,10 @@ bool handleKeyTour(int sym, int uni) { if(!normode) return false; int flags = slides[currentslide].flags; if((sym == SDLK_RETURN || sym == SDLK_KP_ENTER) && (cmode != emHelp || (flags & QUICKSKIP))) { - if(geometry || purehepta) { restartGame(0, false); return true; } + if(geometry || purehepta) { + restartGame(0, false); + if(!(flags & QUICKGEO)) return true; + } if(flags & FINALSLIDE) return true; presentation(pmStop); currentslide++; @@ -96,7 +99,10 @@ bool handleKeyTour(int sym, int uni) { return true; } if(sym == SDLK_BACKSPACE) { - if(geometry || purehepta) { restartGame(0, false); return true; } + if(geometry || purehepta) { + restartGame(0, false); + if(!(flags & QUICKGEO)) return true; + } if(currentslide == 0) { slidehelp(); return true; } presentation(pmStop); currentslide--; @@ -207,6 +213,10 @@ bool handleKeyTour(int sym, int uni) { conformal::includeHistory = !conformal::includeHistory; return true; } + if(sym == '9') { + cmode = emSlideshows; + return true; + } return false; } @@ -225,12 +235,76 @@ void checkGoodLand(eLand l) { } } +namespace ss { + vector slideshows; + slide *wts; + + void list(slide *ss) { + for(auto s: slideshows) if (s == ss) return; + slideshows.push_back(ss); + } + + int sssize; + + void showMenu() { + if(!wts) wts = slides; + + dialog::init(XLAT("slides"), forecolor, 150, 100); + + for(sssize=0;; sssize++) { + int i = sssize; + dialog::addBoolItem(XLAT(wts[i].name), wts == slides && i == currentslide, 'a'+i); + if(wts[i].flags & FINALSLIDE) break; + } + dialog::addBreak(50); + if(size(slideshows) > 1) dialog::addItem(XLAT("change slideshow"), '1'); + dialog::addItem(XLAT("exit menu"), '0'); + dialog::display(); + } + + void handleKey(int sym, int uni) { + if(uni >= 'a' && uni < 'a' + sssize) { + if(geometry || purehepta) { + restartGame(0, false); + presentation(pmGeometryReset); + } + if(slides != wts) { + while(tour::on) restartGame('T', false); + slides = wts; + tour::start(); + } + presentation(pmStop); + currentslide = uni - 'a'; + cmode = emNormal; + presentation(pmStart); + slidehelp(); + } + else if(uni == '1') { + list(wts); + for(int i=0; i c(chaosmode, false); + yendor::bestscore[modecode()][yendor::challenge] = + max(yendor::bestscore[modecode()][yendor::challenge], items[itOrbYendor]); + yendor::uploadScore(); + } + } + addMessage(XLAT("CONGRATULATIONS!")); + achievement_collection(itOrbYendor, pg, gold()); + achievement_victory(false); + } }; #define MAXTAC 20 @@ -795,6 +838,7 @@ int modecode() { #endif if(quotient) return 6; #endif + if(peace::on) return 6; int xcode = 0; if(shmup::on) xcode += 2; @@ -859,3 +903,166 @@ void buildmodetable() { for(int i=0; i path; + int tobuild; + + void build() { + if(otherpuzzles || !on) return; + while(size(path) < tobuild) { + cell *cp = path[size(path)-1]; + cell *cp2 = path[size(path)-2]; + vector> clister; + clister.emplace_back(cp, cp); + + int id = 0; + sval++; + while(id < size(clister)) { + cell *c = clister[id].first; + cell *fr = clister[id].second; + setdist(c, 5, NULL); + + forCellEx(c2,c) + if(!eq(c2->aitmp, sval) && passable(c2, c, 0) && (c2->land == whichland || c2->land == laTemple) && !c2->item) { + if(!id) fr = c2; + bool next; + if(whichland == laRlyeh) + next = c2->land == laTemple && (cp2->land == laRlyeh || celldistAlt(c2) < celldistAlt(cp2) - 8); + else + next = celldistance(c2, cp2) == 8; + if(next) { + path.push_back(fr); + fr->item = itDodeca; + goto again; + } + clister.emplace_back(c2, fr); + c2->aitmp = sval; + } + id++; + } + printf("Path broken, searched = %d\n", id); + for(auto t: clister) t.first->item = itPirate; + return; + again: ; + } + } + + void extend() { + int i = 0; + while(iitem != itDodeca) i++; + if(tobuild == i+9) + addMessage("You must collect all the dodecahedra on the path!"); + tobuild = i + 9; + build(); + } + + void init() { + tobuild = 0; + if(!on) return; + if(otherpuzzles) { items[itGreenStone] = 500; return; } + cell *c2 = cwt.c->mov[0]; + makeEmpty(c2); + c2->item = itOrbYendor; + + path.clear(); + path.push_back(cwt.c); + path.push_back(c2); + extend(); + } + + void restore() { + for(int i=1; iitem == itNone && items[itDodeca]) + path[i]->item = itDodeca, items[itDodeca]--; + } + } + + void handleKey(int sym, int uni) { + dialog::handleNavigation(sym, uni); + + if(uni == '1') otherpuzzles = !otherpuzzles; + else if(uni >= 'a' && uni < 'a' + qty) { + whichland = levellist[uni - 'a']; + restartGame(peace::on ? 0 : 'P'); + cmode = emNormal; + } + else if(uni == '2') { hint = !hint; cmode = emNormal; } + else if(uni == '0') { + firstland = laIce; + if(peace::on) restartGame('P'); + cmode = emNormal; + } + else if(uni == 'h' || sym == SDLK_F1) { + lastmode = cmode; + cmode = emHelp; + help = chelp; + } + else if(doexiton(sym, uni)) cmode = emNormal; + } + };