other changes in 9.4n

This commit is contained in:
Zeno Rogue
2017-06-18 18:51:46 +02:00
parent 131dfb2b4b
commit b172d3930d
7 changed files with 759 additions and 227 deletions
+112 -96
View File
@@ -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; p<numplayers(); p++) {
cell *c2 = shpos[p][(cshpos+SHSIZE-k-1)%SHSIZE];
if(c2) tbd += bulldistance(c, c2);
}
return tbd;
}
void determinizeBull(cell *c, int *posdir, int& nc) {
// determinize the Angry Beast movement:
// use the previous PC's positions as the tiebreaker
for(int k=0; k<SHSIZE && nc>1; k++) {
int pts[10];
for(int d=0; d<nc; d++) pts[d] = totalbulldistance(c->mov[posdir[d]], k);
int bestpts = 1000;
for(int d=0; d<nc; d++) if(pts[d] < bestpts) bestpts = pts[d];
int nc0 = 0;
for(int d=0; d<nc; d++) if(pts[d] == bestpts) posdir[nc0++] = posdir[d];
nc = nc0;
}
}
int determinizeBullPush(cellwalker bull) {
int nc = 2;
int dirs[2], positive;
cwstep(bull);
cell *c2 = bull.c;
if(c2->type == 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; k<SHSIZE && nc>1; k++) {
int pts[10];
for(int d=0; d<nc; d++) pts[d] = 0;
for(int d=0; d<nc; d++)
for(int p=0; p<numplayers(); p++) {
cell *c2 = shpos[p][(cshpos+SHSIZE-k-1)%SHSIZE];
if(c2) pts[d] += bulldistance(c->mov[posdir[d]], c2);
}
int bestpts = 1000;
for(int d=0; d<nc; d++)
if(pts[d] < bestpts) bestpts = pts[d];
int nc0 = 0;
for(int d=0; d<nc; d++) if(pts[d] == bestpts) posdir[nc0++] = posdir[d];
nc = nc0;
}
}
if(c->monst == 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<class T>
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)
+148 -124
View File
@@ -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; i<USERLAYERS; i++) {
usershapelayer& ds(us->d[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; a<size(ds.list); a++) {
hyperpoint P2 = V * ds.list[a];
int xc, yc, sc;
getcoord(P2, xc, yc, sc);
queuechr(xc, yc, sc, 10, 'x',
a == 0 ? 0x00FF00 :
a == size(ds.list)-1 ? 0xFF0000 :
0xFFFF00);
} */
hyperpoint mh = inverse(mapeditor::drawtrans) * mouseh;
for(int a=0; a<ds.rots; a++)
for(int b=0; b<(ds.sym?2:1); b++) {
if(outofmap(mouseh)) break;
hyperpoint P2 = V * spin(2*M_PI*a/ds.rots) * (b?Mirror*mh:mh);
queuechr(P2, 10, 'x', 0xFF00FF);
}
}
#endif
return true;
#endif
hyperpoint mirrorif(const hyperpoint& V, bool b) {
if(b) return Mirror*V;
else return V;
}
string csnameid(int id) {
@@ -1773,7 +1739,7 @@ bool drawItemType(eItem it, cell *c, const transmatrix& V, int icol, int ticks,
xsh = NULL;
}
else if(drawUserShape(V, 2, it, darkena(icol, 0, 0xFF))) ;
else if(mapeditor::drawUserShape(V, 2, it, darkena(icol, 0, 0xFF), c)) ;
else if(it == itRose) {
for(int u=0; u<4; u++)
@@ -1838,11 +1804,6 @@ bool drawMonsterType(eMonster m, cell *where, const transmatrix& V, int col, dou
char xch = minf[m].glyph;
#ifndef NOEDIT
if(where == mapeditor::drawcell)
mapeditor::drawtrans = V;
#endif
if(m == moTortoise && where && where->stuntime >= 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; i<ORBLINES; i++) {
orbinfo& oi(orbinfos[i]);
if(oi.orb == it) {
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));
const orbinfo& oi(orbinfos[i]);
if(oi.orb == it) describeOrb(help, oi);
}
}
if(itemclass(it) == IC_TREASURE) {
for(int i=0; i<ORBLINES; i++) {
const orbinfo& oi(orbinfos[i]);
if(treasureType(oi.l) == it) {
if(oi.gchance > 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; i<multi::players; i++) {
multi::ccdist[i] = 1e20; multi::ccat[i] = NULL;
@@ -6544,7 +6557,7 @@ void drawthemap() {
#ifdef MOBILE
mouseovers = XLAT("No info about this...");
#endif
if(outofmap(mouseh))
if(mouseout())
modist = -5;
playerfound = false;
// playerfoundL = false;
@@ -6617,7 +6630,7 @@ void drawthemap() {
Uint8 *keystate = SDL_GetKeyState(NULL);
lmouseover = mouseover;
bool useRangedOrb = (!(vid.shifttarget & 1) && haveRangedOrb() && lmouseover && lmouseover->cpdist > 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);
}
+5
View File
@@ -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);
+43
View File
@@ -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<bool(eLand)> showland;
void start();
struct slide {
const char *name; int unused_id; int flags; const char *help;
function<void(presmode mode)> 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);
+4 -4
View File
@@ -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
+3 -3
View File
@@ -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
+444
View File
@@ -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<double> kohvec;
struct sample {
kohvec val;
string name;
};
vector<sample> data;
int whattodraw[3];
struct neuron {
kohvec net;
cell *where;
double udist;
int lpbak;
int col;
int samples, csample;
};
kohvec weights;
vector<neuron> net;
void alloc(kohvec& k) { k.resize(cols); }
bool neurons_indexed = false;
int samples;
template<class T> T sqr(T x) { return x*x; }
vector<neuron*> whowon;
void normalize() {
alloc(weights);
for(int k=0; k<cols; k++) {
double sum = 0, sqsum = 0;
for(sample& s: data)
sum += s.val[k],
sqsum += s.val[k] * s.val[k];
double variance = sqsum/samples - sqr(sum/samples);
weights[k] = 1 / sqrt(variance);
}
}
double vnorm(kohvec& a, kohvec& b) {
double diff = 0;
for(int k=0; k<cols; k++) diff += sqr((a[k]-b[k]) * weights[k]);
return diff;
}
void loadsamples(const char *fname) {
normalize();
FILE *f = fopen(fname, "rt");
if(!f) return;
if(fscanf(f, "%d", &cols) != 1) { fclose(f); return; }
while(true) {
sample s;
alloc(s.val);
for(int i=0; i<cols; i++)
if(fscanf(f, "%lf", &s.val[i]) != 1) { fclose(f); return; }
if(feof(f)) break;
fgetc(f);
while(true) {
int c = fgetc(f);
if(c == -1 || c == 10 || c == 13) break;
if(c != 32 && c != 9) s.name += c;
}
data.push_back(move(s));
}
fclose(f);
samples = size(data);
normalize();
vdata.resize(samples);
for(int i=0; i<samples; i++) {
vdata[i].name = data[i].name;
vdata[i].cp = dftcolor;
createViz(i, cwt.c, Id);
}
storeall();
}
int t;
int lpct, mul, maxdist, cells, perdist;
double maxfac;
neuron& winner(int id) {
double bdiff = 1e20;
neuron *bcell = NULL;
for(neuron& n: net) {
double diff = vnorm(n.net, data[id].val);
if(diff < bdiff) bdiff = diff, bcell = &n;
}
return *bcell;
}
void setindex(bool b) {
if(b == neurons_indexed) return;
neurons_indexed = b;
if(b) {
for(neuron& n: net) n.lpbak = n.where->landparam, 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<double> 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; i<cells; i++)
part(net[i].where->landparam, 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; id<samples; id++) {
auto& w = winner(id);
whowon[id] = &w;
w.samples++;
}
for(int id=0; id<samples; id++) {
auto& w = *whowon[id];
vdata[id].m->base = 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<cellcrawlerdata> 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; i<size(data); i++) {
cellwalker cw0 = data[i].orig;
for(int j=0; j<cw0.c->type; 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; i<size(data); i++) {
cellcrawlerdata& s = data[i];
s.target = data[s.from].target;
if(!s.target.c) continue;
cwspin(s.target, s.spin);
if(cwstepcreates(s.target)) s.target.c = NULL;
else cwstep(s.target);
}
}
};
cellcrawler s0, s1; // hex and non-hex
void buildcellcrawler(cell *c) {
(c->type == 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; k<cols; k++)
n2.net[k] += nu * (irisdata[id][k] - n2.net[k]);
} */
cellcrawler& s = n.where->type == 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; k<cols; k++)
n2->net[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<cell*>& allcells = currentmap->allcells();
cells = size(allcells);
net.resize(cells);
for(int i=0; i<cells; i++) net[i].where = allcells[i], allcells[i]->landparam = i;
for(int i=0; i<cells; i++) {
net[i].where->land = laCanvas;
alloc(net[i].net);
for(int k=0; k<cols; k++)
for(int z=0; z<Z; z++)
net[i].net[k] += data[hrand(samples)].val[k] / Z;
}
for(neuron& n: net) for(int d=BARLEV; d>=7; d--) setdist(n.where, d, NULL);
cell *c1 = net[cells/2].where;
vector<int> 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; k<cols; k++) help += " " + fts(n->net[k]);
help += ", u-matrix = " + fts(n->udist);
help += "\n";
for(int s=0; s<samples; s++) if(whowon[s] == n) {
help += "sample "+its(s)+":";
for(int k=0; k<cols; k++) help += " " + fts(data[s].val[k]);
help += " "; help += data[s].name; help += "\n";
}
}
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<cols; k++) fprintf(f, "%.4lf ", n.net[k]); fprintf(f, "\n");
}
fclose(f);
}
void kload(const char *fname) {
int xcells;
FILE *f = fopen(fname, "rt");
if(!f) return;
if(fscanf(f, "%d%d\n", &xcells, &t) != 2) return;
if(xcells != cells) {
printf("Error: bad number of cells\n");
exit(1);
}
for(neuron& n: net) {
for(int k=0; k<cols; k++) if(fscanf(f, "%lf", &n.net[k]) != 1) return;
}
fclose(f);
analyze();
}
void steps() {
if(!kohonen::finished()) {
unsigned int t = SDL_GetTicks();
while(SDL_GetTicks() < t+20) kohonen::step();
setindex(false);
}
}
void showMenu() {
string parts[3] = {"red", "green", "blue"};
for(int i=0; i<3; i++) {
string c;
if(whattodraw[i] == -1) c = "u-matrix";
else if(whattodraw[i] == -2) c = "u-matrix reversed";
else if(whattodraw[i] == -3) c = "distance from marked ('m')";
else c = "column " + its(whattodraw[i]);
dialog::addSelItem(XLAT("coloring (%1)", parts[i]), c, '1'+i);
}
}
bool handleMenu(int sym, int uni) {
if(uni >= '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();
}