From b172d3930dedd050d73f9a61b8e33a4df2203cde Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Sun, 18 Jun 2017 18:51:46 +0200 Subject: [PATCH] other changes in 9.4n --- game.cpp | 208 ++++++++++++------------ graph.cpp | 272 +++++++++++++++++--------------- hyper.cpp | 5 + hyper.h | 43 +++++ hyper.rc | 8 +- init.cpp | 6 +- kohonen.cpp | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 759 insertions(+), 227 deletions(-) create mode 100644 kohonen.cpp diff --git a/game.cpp b/game.cpp index 77de4beb..833397ec 100644 --- a/game.cpp +++ b/game.cpp @@ -848,7 +848,7 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) { if((flags & AF_ONLY_FBUG) && m2 != moPlayer && !isFriendlyOrBug(c2)) return false; if((flags & AF_ONLY_ENEMY) && (m2 == moPlayer || isFriendlyOrBug(c2))) return false; - if(m2 == moHedge && !(flags & (AF_STAB | AF_TOUGH | AF_EAT | AF_MAGIC | AF_LANCE | AF_SWORD_INTO | AF_HORNS))) + if(m2 == moHedge && !(flags & (AF_STAB | AF_TOUGH | AF_EAT | AF_MAGIC | AF_LANCE | AF_SWORD_INTO | AF_HORNS | AF_BULL))) if(!checkOrb(m1, itOrbThorns)) return false; if(m2 == moDraugr && !(flags & (AF_SWORD | AF_MAGIC | AF_SWORD_INTO | AF_HORNS))) return false; @@ -906,17 +906,17 @@ bool canAttack(cell *c1, eMonster m1, cell *c2, eMonster m2, flagtype flags) { // if(m2 == moTortoise && !(flags & AF_MAGIC)) return false; if(m2 == moRoseBeauty) - if(!(flags & (AF_MAGIC | AF_LANCE | AF_GUN | AF_SWORD_INTO))) + if(!(flags & (AF_MAGIC | AF_LANCE | AF_GUN | AF_SWORD_INTO | AF_BULL))) if(!isMimic(m1)) if(!checkOrb(m1, itOrbBeauty) && !checkOrb(m1, itOrbAether) && !checkOrb(m1, itOrbShield)) if(!c1 || !c2 || !withRose(c1,c2)) return false; if(m2 == moFlailer && !c2->stuntime) - if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_SWORD_INTO))) return false; + if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_SWORD_INTO | AF_BULL))) return false; if(m2 == moVizier && c2->hitpoints > 1) - if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_FAST))) return false; + if(!(flags & (AF_MAGIC | AF_TOUGH | AF_EAT | AF_HORNS | AF_LANCE | AF_BACK | AF_FAST | AF_BULL))) return false; return true; } @@ -1582,8 +1582,8 @@ void stunMonster(cell *c2) { c2->hitpoints--; if(c2->monst == moPrincess) playSound(c2, princessgender() ? "hit-princess" : "hit-prince"); - } - c2->stuntime = ( + } + int newtime = ( c2->monst == moFatGuard ? 2 : c2->monst == moSkeleton && c2->land != laPalace && c2->land != laHalloween ? 7 : isMetalBeast(c2->monst) ? 7 : @@ -1599,6 +1599,7 @@ void stunMonster(cell *c2) { c2->monst == moHedge ? 1 : c2->monst == moFlailer ? 1 : 3); + if(c2->stuntime < newtime) c2->stuntime = newtime; if(isBull(c2->monst)) c2->mondir = NODIR; checkStunKill(c2); } @@ -2116,6 +2117,10 @@ bool attackMonster(cell *c, flagtype flags, eMonster killer) { bool dostun = (flags & AF_ORSTUN) && attackJustStuns(c); if((flags & AF_HORNS) && hornStuns(c)) dostun = true; + if((flags & AF_BULL) && c->monst == moVizier && c->hitpoints > 1) { + dostun = true; + c->stuntime = 2; + } if(c->monst == moSkeleton && (flags & AF_SWORD)) dostun = false; @@ -3265,6 +3270,7 @@ int moveval(cell *c1, cell *c2, int d, int mf) { if(isWorm(m) && !passable_for(c1->monst, c2, c1, P_MONSTER)) return -1700; if(canAttack(c1, m, c2, c2->monst, AF_GETPLAYER | mf) && !(mf & MF_NOATTACKS)) { + if(m == moRagingBull && c1->mondir != NODIR) return -1700; if(mf & MF_MOUNT) { if(c2 == dragon::target) return 3000; else if(isFriendlyOrBug(c2)) return 500; @@ -3369,6 +3375,43 @@ int stayval(cell *c, flagtype mf) { return 1000; } +int totalbulldistance(cell *c, int k) { + int tbd = 0; + for(int p=0; p1; k++) { + int pts[10]; + for(int d=0; dmov[posdir[d]], k); + + int bestpts = 1000; + for(int d=0; dtype == 6) return 1; // irrelevant + cwspin(bull, 3); dirs[0] = positive = bull.spin; + cwspin(bull, -6); dirs[1] = bull.spin; + determinizeBull(c2, dirs, nc); + if(dirs[0] == positive) return -1; + return 1; + } + int pickMoveDirection(cell *c, flagtype mf) { int posdir[10], nc = 0, bestval = stayval(c, mf); @@ -3381,26 +3424,9 @@ int pickMoveDirection(cell *c, flagtype mf) { if(val == bestval) posdir[nc++] = d; } - if(c->monst == moRagingBull) { - // determinize the Angry Beast movement: - // use the previous PC's positions as the tiebreaker - for(int k=0; k1; k++) { - int pts[10]; - for(int d=0; dmov[posdir[d]], c2); - } - int bestpts = 1000; - for(int d=0; dmonst == moRagingBull) + determinizeBull(c, posdir, nc); + if(!nc) return -1; nc = hrand(nc); return posdir[nc]; @@ -3427,6 +3453,32 @@ int pickDownDirection(cell *c, flagtype mf) { return downs[hrand(qdowns)]; } +template +cell *determinePush(cellwalker who, cell *c2, int subdir, T valid) { + cellwalker push = who; + cwstep(push); + cwspin(push, 3 * -subdir); + cwstep(push); + if(valid(push.c)) return push.c; + if(c2->type == 7) { + cwstep(push); + cwspin(push, 1 * -subdir); + cwstep(push); + if(valid(push.c)) return push.c; + } + if(gravityLevel(push.c) < gravityLevel(c2)) { + cwstep(push); cwspin(push, 1); cwstep(push); + if(gravityLevel(push.c) < gravityLevel(c2)) { + cwstep(push); cwspin(push, -2); cwstep(push); + } + if(gravityLevel(push.c) < gravityLevel(c2)) { + cwstep(push); cwspin(push, 1); cwstep(push); + } + if(valid(push.c)) return push.c; + } + return c2; + } + // Angry Beast attack // note: this is done both before and after movement void beastAttack(cell *c, bool player) { @@ -3436,8 +3488,27 @@ void beastAttack(cell *c, bool player) { int flags = AF_BULL | AF_ORSTUN; if(player) flags |= AF_GETPLAYER; if(!opposite) flags |= AF_ONLY_FBUG; - if(canAttack(c, moRagingBull, c2, c2->monst, flags)) + if(canAttack(c, moRagingBull, c2, c2->monst, flags)) { attackMonster(c2, flags | AF_MSG, moRagingBull); + if(c2->monst && c2->stuntime) { + cellwalker bull (c, d); + int subdir = determinizeBullPush(bull); + cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }); + if(c3 && c3 != c2) + pushMonster(c3, c2); + } + } + if(c2->wall == waThumperOff) { + playSound(c2, "click"); + c2->wall = waThumperOn; + } + if(c2->wall == waThumperOn) { + cellwalker bull (c, d); + int subdir = determinizeBullPush(bull); + cell *c3 = determinePush(bull, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, c); }); + if(c3 && c3 != c2) + pushThumper(c2, c3); + } } } @@ -6358,6 +6429,10 @@ void killFriendlyIvy() { killMonster(c2, moPlayer, 0); } +bool monsterPushable(cell *c2) { + return (c2->monst != moFatGuard && !(isMetalBeast(c2->monst) && c2->stuntime < 2) && c2->monst != moTortoise); + } + bool movepcto(int d, int subdir, bool checkonly) { global_pushto = NULL; bool switchplaces = false; @@ -6440,21 +6515,8 @@ bool movepcto(int d, int subdir, bool checkonly) { } if(c2->wall == waThumperOn && !c2->monst && !nonAdjacentPlayer(c2, cwt.c)) { - cellwalker push = cwt; - cwstep(push); - cwspin(push, 3 * -subdir); - cwstep(push); -/* if(w == waBigStatue && push.c->type == 7) { - if(checkonly) return false; - addMessage(XLAT("%The1 is too heavy to put it back on the pedestal.", c2->wall)); - return false; - } */ - if((!canPushThumperOn(push.c, c2, cwt.c) && c2->type == 7)) { - cwstep(push); - cwspin(push, 1 * -subdir); - cwstep(push); - } - if(!canPushThumperOn(push.c, c2, cwt.c)) { + cell *c3 = determinePush(cwt, c2, subdir, [c2] (cell *c) { return canPushThumperOn(c, c2, cwt.c); }); + if(c3 == c2) { if(checkonly) return false; addMessage(XLAT("No room to push %the1.", c2->wall)); return false; @@ -6463,40 +6525,13 @@ bool movepcto(int d, int subdir, bool checkonly) { if(!checkonly && errormsgs) wouldkill("%The1 would kill you there!"); return false; } - global_pushto = push.c; + global_pushto = c3; if(checkonly) return true; addMessage(XLAT("You push %the1.", c2->wall)); lastmovetype = lmPush; lastmove = cwt.c; - pushThumper(c2, push.c); + pushThumper(c2, c3); } -/* if((c2->wall == waBigStatue) && c2->type == 7 && !monstersnear(c2)) { - int q = 0; - for(int i=3; i<=4; i++) { - cellwalker push = cwt; - cwstep(push); - cwspin(push, i); - cwstep(push); - if(passable(push.c, c2, false, true)) q++; - } - if(!q) { - if(checkonly) return false; - addMessage(XLAT("No room to push %the1.", c2->wall)); - return false; - } - if(checkonly) return true; - addMessage(XLAT("You push %the1.", c2->wall)); - c2->wall = waNone; - for(int i=3; i<=4; i++) { - cellwalker push = cwt; - cwstep(push); - cwspin(push, i); - cwstep(push); - if(passable(push.c, c2, false, true)) - push.c->wall = waBigStatue; - } - } */ - if(c2->item == itHolyGrail && roundTableRadius(c2) < newRoundTableRadius()) { if(checkonly) return false; addMessage(XLAT("That was not a challenge. Find a larger castle!")); @@ -6658,33 +6693,14 @@ bool movepcto(int d, int subdir, bool checkonly) { return false; } + // pushto=c2 means that the monster is not killed and thus + // still counts for lightning in monstersnear cell *pushto = NULL; if(isStunnable(c2->monst) && c2->hitpoints > 1) { - // pushto=c2 means that the monster is not killed and thus - // still counts for lightning in monstersnear - pushto = c2; - if(c2->monst != moFatGuard && !(isMetalBeast(c2->monst) && c2->stuntime < 2) && c2->monst != moTortoise) { - cellwalker push = cwt; - cwstep(push); - cwspin(push, 3 * -subdir); - cwstep(push); - if(c2->type == 7 && !passable(push.c, c2, P_BLOW)) { - cwstep(push); - cwspin(push, 1 * -subdir); - cwstep(push); - } - if(!passable(push.c, c2, P_BLOW) && gravityLevel(push.c) < gravityLevel(c2)) { - cwstep(push); cwspin(push, 1); cwstep(push); - if(gravityLevel(push.c) < gravityLevel(c2)) { - cwstep(push); cwspin(push, -2); cwstep(push); - } - if(gravityLevel(push.c) < gravityLevel(c2)) { - cwstep(push); cwspin(push, 1); cwstep(push); - } - } - if(passable(push.c, c2, P_BLOW)) - pushto = push.c; - } + if(monsterPushable(c2)) + pushto = determinePush(cwt, c2, subdir, [c2] (cell *c) { return passable(c, c2, P_BLOW); }); + else + pushto = c2; } if(c2->monst == moTroll || c2->monst == moFjordTroll || c2->monst == moForestTroll || c2->monst == moStormTroll || c2->monst == moVineSpirit) diff --git a/graph.cpp b/graph.cpp index ae2aef4d..c7ec8c50 100644 --- a/graph.cpp +++ b/graph.cpp @@ -114,14 +114,14 @@ movedir mousedest, joydir; int mousex, mousey, joyx, joyy, panjoyx, panjoyy; bool autojoy = true; -hyperpoint mouseh; +hyperpoint mouseh, mouseoh; bool leftclick, rightclick, targetclick, hiliteclick, anyshiftclick, wheelclick, forcetarget, lshiftclick, lctrlclick; bool gtouched; bool revcontrol; -int getcstat; ld getcshift; bool inslider; +int getcstat, lgetcstat; ld getcshift; bool inslider; int ZZ; @@ -1252,13 +1252,23 @@ double q3 = sqrt(double(3)); bool outofmap(hyperpoint h) { if(euclid) - return h[0] * h[0] + h[1] * h[1] > 15 * eurad; + return false; // h[0] * h[0] + h[1] * h[1] > 15 * eurad; else if(sphere) return h[2] < .1 && h[2] > -.1 && h[1] > -.1 && h[1] < .1 && h[0] > -.1 && h[0] < .1; else return h[2] < .5; } +bool mouseout() { + if((getcstat != '-' && getcstat) || (lgetcstat && lgetcstat != '-')) return true; + return outofmap(mouseh); + } + +bool mouseout2() { + if((getcstat && getcstat != '-') || (lgetcstat && lgetcstat != '-')) return true; + return outofmap(mouseh) || outofmap(mouseoh); + } + void drawShield(const transmatrix& V, eItem it) { float ds = ticks / 300.; int col = iinf[it].color; @@ -1432,53 +1442,9 @@ void drawStunStars(const transmatrix& V, int t) { } } -bool drawUserShape(transmatrix V, int group, int id, int color) { -#ifdef MOBILE - return false; -#else - usershape *us = usershapes[group][id]; - if(!us) return false; - - for(int i=0; id[i]); - hpcshape& sh(ds.sh); - - if(sh.s != sh.e) - queuepoly(V, sh, ds.color ? ds.color : color); - } - -#ifndef NOEDIT - if(cmode == emDraw && mapeditor::editingShape(group, id)) { - - usershapelayer &ds(usershapes[group][id]->d[mapeditor::dslayer]); - - /* for(int a=0; astuntime >= 3) drawStunStars(V, where->stuntime-2); else if (m == moTortoise || m == moPlayer || (where && !where->stuntime)) ; @@ -1860,8 +1821,8 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou charstyle& cs = getcs(); - bool havus = drawUserShape(V, 0, cs.charid, cs.skincolor); - + bool havus = mapeditor::drawUserShape(V, 0, cs.charid, cs.skincolor, where); + if(mapeditor::drawplayer && !havus) { if(cs.charid >= 8) { @@ -1974,12 +1935,12 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou } } - else if(drawUserShape(V, 1, m, darkena(col, 0, 0xFF))) return false; + else if(mapeditor::drawUserShape(V, 1, m, darkena(col, 0, 0xFF), where)) return false; else if(isMimic(m) || m == moShadow || m == moIllusion) { charstyle& cs = getcs(); - if(drawUserShape(V, 0, (cs.charid&1)?1:0, darkena(col, 0, 0x80))) return false; + if(mapeditor::drawUserShape(V, 0, (cs.charid&1)?1:0, darkena(col, 0, 0x80), where)) return false; if(cs.charid >= 8) { queuepoly(VABODY, shWolfBody, darkena(col, 0, 0xC0)); @@ -2729,11 +2690,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { else Vb = Vb * ddspin(c, c->mondir); -#ifndef NOEDIT - if(c == mapeditor::drawcell) mapeditor::drawtrans = Vb; -#endif - - if(drawUserShape(Vb, 1, c->monst, (col << 8) + 0xFF)) return false; + if(mapeditor::drawUserShape(Vb, 1, c->monst, (col << 8) + 0xFF, c)) return false; if(isIvy(c) || isMutantIvy(c) || c->monst == moFriendlyIvy) queuepoly(Vb, shIBranch, (col << 8) + 0xFF); @@ -2863,7 +2820,7 @@ bool drawMonster(const transmatrix& Vparam, int ct, cell *c, int col) { if(flipplayer) Vs = Vs * pispin; - if(!outofmap(mouseh) && !nospins) { + if(!mouseout() && !nospins) { // transmatrix invxy = Id; invxy[0][0] = invxy[1][1] = -1; hyperpoint P2 = Vs * inverse(cwtV) * mouseh; @@ -4091,7 +4048,11 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { ivoryz = isGravityLand(c->land); transmatrix& gm = gmatrix[c]; - bool orig = (gm[2][2] == 0 || fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8); + bool orig = + gm[2][2] == 0 ? true : + torus ? hypot(gm[0][2], gm[1][2]) >= hypot(V[0][2], V[1][2]) : + (sphere && vid.alphax >= 1.001) ? fabs(gm[2][2]-1) <= fabs(V[2][2]-1) : + fabs(gm[2][2]-1) >= fabs(V[2][2]-1) - 1e-8; if(orig) gm = V; @@ -4163,12 +4124,14 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { modist2 = intval(mouseh, VC0); mouseover2 = c; } - - double dfc = euclid ? intval(VC0, C0) : VC0[2]; - if(dfc < centdist) { - centdist = dfc; - centerover = c; + if(!torus) { + double dfc = euclid ? intval(VC0, C0) : VC0[2]; + + if(dfc < centdist) { + centdist = dfc; + centerover = c; + } } int orbrange = (items[itRevolver] ? 3 : 2); @@ -4356,12 +4319,6 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { bool eoh = euclid || purehepta; -#ifndef NOEDIT - if(c == mapeditor::drawcell && c != cwt.c && !c->monst && !c->item) { - mapeditor::drawtrans = Vpdir; - } -#endif - if(c->wall == waChasm) { if(c->land == laZebra) fd++; if(c->land == laHalloween && !wmblack) { @@ -4372,8 +4329,8 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } #ifndef NOEDIT - if(drawUserShape(Vpdir, mapeditor::cellShapeGroup(), mapeditor::realpatternsh(c), - darkena(fcol, fd, cmode == emDraw ? 0xC0 : 0xFF))); + if(mapeditor::drawUserShape(Vpdir, mapeditor::cellShapeGroup(), mapeditor::realpatternsh(c), + darkena(fcol, fd, cmode == emDraw ? 0xC0 : 0xFF), c)); else if(mapeditor::whichShape == '7') { if(ishept(c)) @@ -5309,6 +5266,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { #ifndef NOEDIT if(cmode == emMapEditor && !mapeditor::subscreen && lmouseover && darken == 0 && + !mouseout() && (mapeditor::whichPattern ? mapeditor::subpattern(c) == mapeditor::subpattern(lmouseover) : c == lmouseover)) { queuecircle(V, .78, 0x00FFFFFF); } @@ -5338,7 +5296,7 @@ void drawcell(cell *c, transmatrix V, int spinv, bool mirrored) { } bool confusingGeometry() { - return elliptic || quotient == 1; + return elliptic || quotient == 1 || torus; } struct flashdata { @@ -5717,6 +5675,25 @@ string princessReviveHelp() { return h; } +void describeOrb(string& help, const orbinfo& oi) { + eOrbLandRelation olr = getOLR(oi.orb, cwt.c->land); + eItem tr = treasureType(oi.l); + help += "\n\n" + XLAT(olrDescriptions[olr], cwt.c->land, tr, treasureType(cwt.c->land)); + int t = items[tr] * landMultiplier(oi.l); + if(t >= 25) + if(olr == olrPrize25 || olr == olrPrize3 || olr == olrGuest || olr == olrMonster || olr == olrAlways) { + help += XLAT("\nSpawn rate (as prize Orb): %1%/%2\n", + its(int(.5 + 100 * orbprizefun(t))), + its(oi.gchance)); + } + if(t >= 10) + if(olr == olrHub) { + help += XLAT("\nSpawn rate (in Hubs): %1%/%2\n", + its(int(.5 + 100 * orbcrossfun(t))), + its(oi.gchance)); + } + } + string generateHelpForItem(eItem it) { string help = helptitle(XLATN(iinf[it].name), iinf[it].color); @@ -5786,25 +5763,23 @@ string generateHelpForItem(eItem it) { } if(itemclass(it) == IC_ORB || it == itGreenStone || it == itOrbYendor) { - eOrbLandRelation olr = getOLR(it, cwt.c->land); - for(int i=0; iland, tr, treasureType(cwt.c->land)); - int t = items[tr] * landMultiplier(oi.l); - if(t >= 25) - if(olr == olrPrize25 || olr == olrPrize3 || olr == olrGuest || olr == olrMonster || olr == olrAlways) { - help += XLAT("\nSpawn rate (as prize Orb): %1%/%2\n", - its(int(.5 + 100 * orbprizefun(t))), - its(oi.gchance)); + const orbinfo& oi(orbinfos[i]); + if(oi.orb == it) describeOrb(help, oi); + } + } + + if(itemclass(it) == IC_TREASURE) { + for(int i=0; i 0) { + help += XLAT("\n\nOrb unlocked: %1", oi.orb); + describeOrb(help, oi); } - if(t >= 10) - if(olr == olrHub) { - help += XLAT("\nSpawn rate (in Hubs): %1%/%2\n", - its(int(.5 + 100 * orbcrossfun(t))), - its(oi.gchance)); + else if(oi.l == cwt.c->land) { + help += XLAT("\n\nSecondary orb: %1", oi.orb); + describeOrb(help, oi); } } } @@ -6192,9 +6167,14 @@ void describeMouseover() { out += " " + describeRPM(c->land); if(euclid && cheater) { - eucoord x, y; - decodeMaster(c->master, x, y); - out += " ("+its(short(x))+","+its(short(y))+")"; + if(torus) { + out += " ("+its(decodeId(c->master))+")"; + } + else { + eucoord x, y; + decodeMaster(c->master, x, y); + out += " ("+its(short(x))+","+its(short(y))+")"; + } } // char zz[64]; sprintf(zz, " P%d", princess::dist(c)); out += zz; @@ -6233,10 +6213,10 @@ void describeMouseover() { if(isActivable(c)) out += XLAT(" (touch to activate)"); - if(hasTimeout(c)) out += XLAT(" [" + turnstring(c->wparam) + "]"); + if(hasTimeout(c)) out += " [" + turnstring(c->wparam) + "]"; if(isReptile(c->wall)) - out += XLAT(" [" + turnstring((unsigned char) c->wparam) + "]"); + out += " [" + turnstring((unsigned char) c->wparam) + "]"; if(c->monst) { out += ", "; out += XLAT1(minf[c->monst].name); @@ -6299,7 +6279,6 @@ void describeMouseover() { if(isWarped(c)) help += s0 + "\n\n" + warpdesc; - } else if(cmode == emVisual1) { if(getcstat == 'p') { @@ -6351,6 +6330,10 @@ void describeMouseover() { } mouseovers = out; + +#ifdef ROGUEVIZ + rogueviz::describe(c); +#endif int col = linf[cwt.c->land].color; if(cwt.c->land == laRedRock) col = 0xC00000; @@ -6422,25 +6405,52 @@ transmatrix eumove(int x, int y) { return Mat; } +transmatrix eumovedir(int d) { + d = fix6(d); + switch(d) { + case 0: return eumove(1,0); + case 1: return eumove(0,1); + case 2: return eumove(-1,1); + case 3: return eumove(-1,0); + case 4: return eumove(0,-1); + case 5: return eumove(1,-1); + } + return eumove(0,0); + } + void drawEuclidean() { DEBB(DF_GRAPH, (debugfile,"drawEuclidean\n")); - eucoord px, py; + eucoord px=0, py=0; if(!centerover) centerover = cwt.c; // printf("centerover = %p player = %p [%d,%d]-[%d,%d]\n", lcenterover, cwt.c, // mindx, mindy, maxdx, maxdy); - decodeMaster(centerover->master, px, py); + int pid; + const bool b = torus; + if(b) + pid = decodeId(centerover->master); + else + decodeMaster(centerover->master, px, py); int minsx = mindx-1, maxsx=maxdx+1, minsy=mindy-1, maxsy=maxdy+1; mindx=maxdx=mindy=maxdy=0; for(int dx=minsx; dx<=maxsx; dx++) for(int dy=minsy; dy<=maxsy; dy++) { - eucoord x = dx+px; - eucoord y = dy+py; reclevel = eudist(dx, dy); - cell *c = euclideanAt(x,y); + cell *c; + transmatrix Mat; + if(b) { + reclevel = eudist(dx, dy); + c = getTorusId(pid+torusconfig::dx*dx+torusconfig::dy*dy); + Mat = eumove(dx,dy); + } + else { + eucoord x = dx+px; + eucoord y = dy+py; + c = euclideanAt(x,y); + Mat = eumove(x, y); + } if(!c) continue; - transmatrix Mat = eumove(x, y); Mat = View * Mat; // Mat[0][0] = -1; @@ -6525,7 +6535,9 @@ void drawthemap() { keycelldist = YDIST - i; } } - + + if(mapeditor::autochoose) mapeditor::ew = mapeditor::ewsearch; + mapeditor::ewsearch.dist = 1e30; modist = 1e20; mouseover = NULL; modist2 = 1e20; mouseover2 = NULL; mouseovers = XLAT("Press F1 or right click for help"); @@ -6535,7 +6547,8 @@ void drawthemap() { #ifdef TOUR if(tour::on) mouseovers = tour::tourhelp; #endif - centdist = 1e20; centerover = NULL; + centdist = 1e20; + if(!torus) centerover = NULL; for(int i=0; icpdist > 1) || (keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT]); - if(!useRangedOrb && cmode != emMapEditor && DEFAULTCONTROL && !outofmap(mouseh)) { + if(!useRangedOrb && cmode != emMapEditor && DEFAULTCONTROL && !mouseout()) { void calcMousedest(); calcMousedest(); cellwalker cw = cwt; bool f = flipplayer; @@ -6661,7 +6674,7 @@ void centerpc(ld aspd) { // Euclidean aspd *= (2+3*R*R); if(aspd > R) aspd = R; - + View[0][2] -= cwtV[0][2] * aspd / R; View[1][2] -= cwtV[1][2] * aspd / R; } @@ -6744,7 +6757,7 @@ void optimizeview() { hyperpoint H = View * tC0(T); if(H[2] < best) best = H[2], turn = i, TB = T; } - + if(turn >= 0) { View = View * TB; fixmatrix(View); @@ -6796,7 +6809,7 @@ void movepckeydir(int d) { } void calcMousedest() { - if(outofmap(mouseh)) return; + if(mouseout()) return; if(revcontrol == true) { mouseh[0] = -mouseh[0]; mouseh[1] = -mouseh[1]; } ld mousedist = intval(mouseh, tC0(shmup::ggmatrix(cwt.c))); mousedest.d = -1; @@ -6918,6 +6931,7 @@ void calcparam() { vid.alphax = vid.alpha + eye; vid.goteyes = vid.eye > 0.001 || vid.eye < -0.001; vid.goteyes2 = vid.goteyes; + vid.scrdist = vid.radius; } void displayButton(int x, int y, const string& name, int key, int align, int rad) { @@ -6927,6 +6941,16 @@ void displayButton(int x, int y, const string& name, int key, int align, int rad } } +char mousekey = 'n'; +char newmousekey; + +void displaymm(char c, int x, int y, int rad, int size, const string& title, int align) { + if(displayfr(x, y, rad, size, title, c == mousekey ? 0xFF8000 : 0xC0C0C0, align)) { + displayfr(x, y, rad, size, title, 0xFFFF00, align); + getcstat = SETMOUSEKEY, newmousekey = c; + } + } + bool displayButtonS(int x, int y, const string& name, int col, int align, int size) { if(displaystr(x, y, 0, size, name, col, align)) { displaystr(x, y, 0, size, name, 0xFFFF00, align); @@ -7413,8 +7437,8 @@ transmatrix atscreenpos(ld x, ld y, ld size) { V[0][2] += (x - vid.xcenter); V[1][2] += (y - vid.ycenter); - V[0][0] = size * 2 * crossf / hcrossf; - V[1][1] = size * 2 * crossf / hcrossf; + V[0][0] = size * 2 * hcrossf / crossf; + V[1][1] = size * 2 * hcrossf / crossf; V[2][2] = vid.scrdist; if(euclid) V[2][2] /= EUCSCALE; @@ -7964,6 +7988,7 @@ void drawscreen() { if(conformal::includeHistory && cmode != emProgress) conformal::restoreBack(); + lgetcstat = getcstat; getcstat = 0; inslider = false; if(cmode == emNormal || cmode == emQuit) drawStats(); @@ -8132,7 +8157,7 @@ void restartGraph() { linepatterns::clearAll(); if(currentmap) { if(euclid) { - centerover = euclideanAtCreate(0,0); + centerover = torus ? getTorusId(0) : euclideanAtCreate(0,0); } else { viewctr.h = currentmap->getOrigin(); @@ -9210,7 +9235,7 @@ void mainloopiter() { } if(ev.type == SDL_MOUSEMOTION) { - hyperpoint mouseoh = mouseh; + mouseoh = mouseh; mousing = true; mousemoved = true; @@ -9223,9 +9248,8 @@ void mainloopiter() { else #endif mouseh = gethyper(mousex, mousey); - - if((rightclick || (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MMASK)) && - !outofmap(mouseh) && !outofmap(mouseoh) && + + if((rightclick || (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MMASK)) && !mouseout2() && mouseh[2] < 50 && mouseoh[2] < 50) { panning(mouseoh, mouseh); } diff --git a/hyper.cpp b/hyper.cpp index 432df068..58f3103a 100644 --- a/hyper.cpp +++ b/hyper.cpp @@ -309,6 +309,11 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { if(curphase == else if(argis("-svgsize")) { shift(); sscanf(args(), "%d/%d", &svg::svgsize, &svg::divby); } + else if(argis("-svgfont")) { + shift(); svg::font = args(); + // note: use '-svgfont latex' to produce text output as: \myfont{size}{text} + // (this is helpful with Inkscape's PDF+TeX output feature; define \myfont yourself) + } #ifndef NOPNG else if(argis("-pngsize")) { shift(); sscanf(args(), "%d", &pngres); diff --git a/hyper.h b/hyper.h index d55abdb6..14fed305 100644 --- a/hyper.h +++ b/hyper.h @@ -216,6 +216,7 @@ namespace shmup { void virtualRebase(cell*& base, transmatrix& at, bool tohex); void virtualRebase(shmup::monster *m, bool tohex); + void fixStorage(); } // graph @@ -384,6 +385,7 @@ namespace mapeditor { int patterndir(cell *c, char w = whichPattern); int subpattern(cell *c); extern cell *drawcell; + void initdraw(cell *c); } #ifndef NORUG @@ -992,6 +994,7 @@ namespace rogueviz { void fixparam(); int readArgs(); void close(); + void mark(cell *c); } #endif @@ -1004,6 +1007,7 @@ void movecost(cell* from, cell *to); void checkmove(); transmatrix eumove(int x, int y); +transmatrix eumovedir(int d); #ifndef NOSAVE void loadScores(); @@ -1136,6 +1140,8 @@ namespace tour { pmGeometry = 11, pmGeometryReset = 13, pmGeometryStart = 15 }; + void setCanvas(presmode mode, char canv); + void presentation(presmode mode); void checkGoodLand(eLand l); int getid(); @@ -1145,12 +1151,34 @@ namespace tour { extern function showland; void start(); + + struct slide { + const char *name; int unused_id; int flags; const char *help; + function action; + } ; + + extern slide *slides; + extern slide default_slides[]; + + static const int LEGAL_NONE=0; + static const int LEGAL_UNLIMITED=1; + static const int LEGAL_HYPERBOLIC=2; + static const int LEGAL_ANY=3; + static const int LEGAL_NONEUC=4; + static const int QUICKSKIP=8; + static const int FINALSLIDE=16; + + extern slide slideHypersian; + extern slide slideExpansion; }; #endif namespace rogueviz { extern bool rog3; extern bool rvwarp; + namespace rvtour { + extern tour::slide rvslides[]; + } }; extern bool doCross; @@ -1199,3 +1227,18 @@ int celldistance(cell *c1, cell *c2); bool behindsphere(const transmatrix& V); extern hyperpoint pirateCoords; +bool mouseout(); + +bool againstWind(cell *c2, cell *c1); // to, from + +transmatrix atscreenpos(ld x, ld y, ld size); + +hyperpoint mirrorif(const hyperpoint& V, bool b); + +#define SETMOUSEKEY 5000 +extern char mousekey; +extern char newmousekey; +void displaymm(char c, int x, int y, int rad, int size, const string& title, int align); + +bool canPushThumperOn(cell *tgt, cell *thumper, cell *player); +void pushThumper(cell *th, cell *cto); diff --git a/hyper.rc b/hyper.rc index 80d0de37..a477bc8e 100644 --- a/hyper.rc +++ b/hyper.rc @@ -1,8 +1,8 @@ id ICON "hr-icon.ico" 1 VERSIONINFO -FILEVERSION 9,4,0,12 -PRODUCTVERSION 9,4,0,12 +FILEVERSION 9,4,0,14 +PRODUCTVERSION 9,4,0,14 BEGIN BLOCK "StringFileInfo" BEGIN @@ -10,12 +10,12 @@ BEGIN BEGIN VALUE "CompanyName", "Zeno Rogue" VALUE "FileDescription", "A roguelike in non-euclidean space" - VALUE "FileVersion", "94k" + VALUE "FileVersion", "94n" VALUE "InternalName", "hyper" VALUE "LegalCopyright", "Zeno Rogue" VALUE "OriginalFilename", "hyper.exe" VALUE "ProductName", "HyperRogue" - VALUE "ProductVersion", "9.4l" + VALUE "ProductVersion", "9.4n" END END diff --git a/init.cpp b/init.cpp index 525b2eb3..3c71260c 100644 --- a/init.cpp +++ b/init.cpp @@ -1,6 +1,6 @@ -#define VER "9.4l" -#define VERNUM 9412 -#define VERNUM_HEX 0x9412 +#define VER "9.4n" +#define VERNUM 9414 +#define VERNUM_HEX 0x9414 #define GEN_M 0 #define GEN_F 1 diff --git a/kohonen.cpp b/kohonen.cpp new file mode 100644 index 00000000..e5561603 --- /dev/null +++ b/kohonen.cpp @@ -0,0 +1,444 @@ +// Hyperbolic Rogue +// Copyright (C) 2011-2017 Zeno and Tehora Rogue, see 'hyper.cpp' for details + +// Kohonen's self-organizing networks. +// This is a part of RogueViz, not a part of HyperRogue. + +namespace kohonen { + +int cols; + +typedef vector kohvec; + +struct sample { + kohvec val; + string name; + }; + +vector data; + +int whattodraw[3]; + +struct neuron { + kohvec net; + cell *where; + double udist; + int lpbak; + int col; + int samples, csample; + }; + +kohvec weights; + +vector net; + +void alloc(kohvec& k) { k.resize(cols); } + +bool neurons_indexed = false; + +int samples; + +template T sqr(T x) { return x*x; } + +vector whowon; + +void normalize() { + alloc(weights); + for(int k=0; klandparam, n.where->landparam = (&n - &net[0]); + } + else { + for(neuron& n: net) n.where->landparam = n.lpbak; + } + } + +neuron *getNeuron(cell *c) { + if(!c) return NULL; + setindex(true); + if(c->landparam < 0 || c->landparam >= cells) return NULL; + neuron& ret = net[c->landparam]; + if(ret.where != c) return NULL; + return &ret; + } + +neuron *getNeuronSlow(cell *c) { + if(neurons_indexed) return getNeuron(c); + for(neuron& n: net) if(n.where == c) return &n; + return NULL; + } + +double maxudist; + +neuron *distfrom; + +void coloring() { + setindex(false); + for(int pid=0; pid<3; pid++) { + int c = whattodraw[pid]; + vector listing; + for(neuron& n: net) switch(c) { + case -3: + if(distfrom) + listing.push_back(vnorm(n.net, distfrom->net)); + else + listing.push_back(0); + break; + + case -2: + listing.push_back(n.udist); + break; + + case -1: + listing.push_back(-n.udist); + break; + + default: + listing.push_back(n.net[c]); + break; + } + + double minl = listing[0], maxl = listing[0]; + for(double& d: listing) minl = min(minl, d), maxl = max(maxl, d); + if(maxl-minl < 1e-3) maxl = minl+1e-3; + + for(int i=0; ilandparam, pid) = (255 * (listing[i] - minl)) / (maxl - minl); + } + } + +void analyze() { + + setindex(true); + + maxudist = 0; + for(neuron& n: net) { + int qty = 0; + double total = 0; + forCellEx(c2, n.where) { + neuron *n2 = getNeuron(c2); + if(!n2) continue; + qty++; + total += sqrt(vnorm(n.net, n2->net)); + } + n.udist = total / qty; + maxudist = max(maxudist, n.udist); + } + + whowon.resize(samples); + + for(neuron& n: net) n.samples = 0; + + for(int id=0; idbase = w.where; + vdata[id].m->at = + spin(2*M_PI*w.csample / w.samples) * xpush(.25 * (w.samples-1) / w.samples); + w.csample++; + } + + shmup::fixStorage(); + setindex(false); + coloring(); + } + +struct cellcrawler { + + struct cellcrawlerdata { + cellwalker orig; + int from, spin, dist; + cellwalker target; + cellcrawlerdata(const cellwalker& o, int fr, int sp) : orig(o), from(fr), spin(sp) {} + }; + + vector data; + + void store(const cellwalker& o, int from, int spin) { + if(eq(o.c->aitmp, sval)) return; + o.c->aitmp = sval; + data.emplace_back(o, from, spin); + } + + void build(const cellwalker& start) { + sval++; + data.clear(); + store(start, 0, 0); + for(int i=0; itype; j++) { + cellwalker cw = cw0; + cwspin(cw, j); cwstep(cw); + if(!getNeuron(cw.c)) continue; + store(cw, i, j); + } + } + for(cellcrawlerdata& s: data) + s.dist = celldistance(s.orig.c, start.c); + } + + void sprawl(const cellwalker& start) { + data[0].target = start; + + for(int i=1; itype == 6 ? s0 : s1).build(cellwalker(c,0)); + } + +bool finished() { return t == 0; } + +void step() { + double sigma = maxdist * t / (perdist*(double) mul); + if(t == 0) return; +// double sigma = maxdist * exp(-t / t1); + int pct = (int) (100 * ((t*(double) mul) / perdist)); + if(pct != lpct) { + lpct = pct; + analyze(); + printf("t = %6d/%2dx%6d pct = %3d sigma=%10.7lf maxudist=%10.7lf\n", t, mul, perdist, pct, sigma, maxudist); + } + int id = hrand(samples); + neuron& n = winner(id); + + /* + for(neuron& n2: net) { + int d = celldistance(n.where, n2.where); + double nu = maxfac; +// nu *= exp(-t*(double)maxdist/perdist); +// nu *= exp(-t/t2); + nu *= exp(-sqr(d/sigma)); + for(int k=0; ktype == 6 ? s0 : s1; + s.sprawl(cellwalker(n.where, 0)); + for(auto& sd: s.data) { + neuron *n2 = getNeuron(sd.target.c); + if(!n2) continue; + double nu = maxfac; + nu *= exp(-sqr(sd.dist/sigma)); + for(int k=0; knet[k] += nu * (data[id].val[k] - n2->net[k]); + } + + t--; + if(t == 0) analyze(); + } + +void run(const char *fname, int _perdist, double _maxfac) { + perdist = _perdist; + maxfac = _maxfac; + init(); kind = kKohonen; + + loadsamples(fname); + + /* if(geometry != gQuotient1) { + targetGeometry = gQuotient1; + restartGame('g'); + } + if(!purehepta) restartGame('7'); */ + +#define Z 1 + + vector& allcells = currentmap->allcells(); + cells = size(allcells); + net.resize(cells); + for(int i=0; ilandparam = i; + for(int i=0; iland = laCanvas; + alloc(net[i].net); + + for(int k=0; k=7; d--) setdist(n.where, d, NULL); + + cell *c1 = net[cells/2].where; + vector mapdist; + for(neuron &n2: net) mapdist.push_back(celldistance(c1,n2.where)); + sort(mapdist.begin(), mapdist.end()); + maxdist = mapdist[size(mapdist)*5/6]; + + printf("samples = %d cells = %d maxdist = %d\n", samples, cells, maxdist); + + c1 = currentmap->gamestart(); + cell *c2 = createMov(c1, 0); + buildcellcrawler(c1); + if(c1->type != c2->type) buildcellcrawler(c2); + + lpct = -46130; + mul = 1; + t = perdist*mul; + step(); + for(int i=0; i<3; i++) whattodraw[i] = -2; + analyze(); + } + +void describe(cell *c) { + if(cmode == emHelp) return; + neuron *n = getNeuronSlow(c); + if(!n) return; + help += "cell number: " + its(n - &net[0]) + "\n"; + help += "parameters:"; for(int k=0; knet[k]); + help += ", u-matrix = " + fts(n->udist); + help += "\n"; + for(int s=0; s= '1' && uni <= '3') { + int i = uni - '1'; + whattodraw[i]++; + if(whattodraw[i] == cols) whattodraw[i] = -3; + coloring(); + return true; + } + if(uni == '0') { + for(char x: {'1','2','3'}) handleMenu(x, x); + return true; + } + return false; + } + +} + +void mark(cell *c) { + using namespace kohonen; + distfrom = getNeuronSlow(c); + coloring(); + }