Major refactoring, multisampling

This commit is contained in:
Zeno Rogue 2017-07-10 20:47:38 +02:00
parent c46ab39d1e
commit 069f7b0caf
31 changed files with 20872 additions and 6856 deletions

1147
basegraph.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1501,17 +1501,7 @@ void clearCellMemory() {
allmaps.clear();
}
void clearMemory() {
extern void clearGameMemory();
clearGameMemory();
shmup::clearMemory();
cleargraphmemory();
#ifndef NOEDIT
mapeditor::clearModelCells();
#endif
clearCellMemory();
DEBMEM ( printf("ok\n"); )
}
auto cellhooks = addHook(clearmemory, 500, clearCellMemory);
int getHemisphere(cell *c, int which) {
if(torus) return 0;

View File

@ -2761,3 +2761,17 @@ namespace ca {
}
}
}
auto ccm = addHook(clearmemory, 0, [] () {
offscreen.clear();
princess::clear();
mirrors.clear();
clearing::bpdata.clear();
tortoise::emap.clear();
tortoise::babymap.clear();
prairie::lasttreasure = NULL;
prairie::enter = NULL;
prairie::tchoices.clear();
prairie::beaststogen.clear();
});

1008
config.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
// Hyperbolic Rogue -- the conformal/history mode
// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details
#include <complex>
namespace polygonal {
@ -11,8 +10,6 @@ namespace polygonal {
int deg = 20;
#define MSI 120
ld matrix[MSI][MSI];
ld ans[MSI];
@ -227,7 +224,14 @@ bool isbad(ld z) { return !isfinite(z) || fabs(z) > 1e6; }
namespace conformal {
void handleKeyC(int sym, int uni);
int lastprogress;
void progress_screen() {
gamescreen(0);
mouseovers = "";
}
void progress(string str) {
#ifndef NOSDL
@ -429,9 +433,9 @@ namespace conformal {
int siz = size(v);
for(int j=1; j<siz-1; j++) {
SDL_Surface *buffer = s;
emtype cm = cmode;
s = sav;
cmode = emProgress;
pushScreen(progress_screen);
char buf[128];
sprintf(buf, "#%03d", segid);
@ -440,7 +444,6 @@ namespace conformal {
calcparam();
vid.radius = bandhalf;
cmode = cm;
s = buffer;
viewctr.h = v[j]->base->master;
viewctr.spin = 0;
@ -462,6 +465,8 @@ namespace conformal {
int bwidth = x-bandhalf;
popScreen();
drawsegment:
for(int cy=0; cy<bandfull; cy++) for(int cx=0; cx<bwidth; cx++)
@ -572,10 +577,12 @@ namespace conformal {
dialog::addItem(XLAT("exit this menu"), 'q');
dialog::display();
mouseovers = XLAT("see http://www.roguetemple.com/z/hyper/conformal.php");
keyhandler = handleKeyC;
}
int ib = 0;
ld compbuf;
void applyIB() {
using namespace polygonal;
cld& tgt = coef[coefid];
@ -583,7 +590,7 @@ namespace conformal {
if(ib == 2) tgt = cld(real(tgt), compbuf);
}
void handleKey(int sym, int uni) {
void handleKeyC(int sym, int uni) {
dialog::handleNavigation(sym, uni);
ib = 0;
@ -624,7 +631,7 @@ namespace conformal {
dialog::sidedialog = true;
}
else if(sym == 'n' && pmodel == mdPolygonal) {
dialog::editNumber(polygonal::deg, 2, MSI-1, 1, 2, XLAT("degree of the approximation"), "");
dialog::editNumber(polygonal::deg, 2, polygonal::MSI-1, 1, 2, XLAT("degree of the approximation"), "");
dialog::sidedialog = true;
}
else if(sym == 'x' && pmodel == mdPolynomial) {
@ -642,7 +649,7 @@ namespace conformal {
ib = 2;
}
else if(sym == 'n' && pmodel == mdPolynomial)
dialog::editNumber(polygonal::coefid, 0, MSI-1, 1, 0, XLAT("which coefficient"), "");
dialog::editNumber(polygonal::coefid, 0, polygonal::MSI-1, 1, 0, XLAT("which coefficient"), "");
else if(sym == 'r') rotation += (shiftmul > 0 ? 1:3);
else if(sym == 'a')
dialog::editNumber(lvspeed, -5, 5, .1, 1, XLAT("animation speed"), "");
@ -654,7 +661,6 @@ namespace conformal {
#ifndef NOSDL
else if(uni == 'f' && pmodel == mdBand && on) createImage(dospiral);
#endif
else if(sym == 'q' || sym == SDLK_ESCAPE || sym == '0') { cmode = emNormal; }
else if(sym == 'i') {
if(canmove && !cheater) {
addMessage("Enable cheat mode or GAME OVER to use this");
@ -666,6 +672,7 @@ namespace conformal {
else if(sym == 'j') {
autobandhistory = !autobandhistory;
}
else if(doexiton(sym, uni)) popScreen();
}
void restore() {
@ -718,5 +725,15 @@ namespace conformal {
pmodel = spm;
includeHistory = ih;
#endif
}
}
auto hooks = addHook(clearmemory, 0, [] () {
conformal::renderAutoband();
conformal::on = false;
conformal::killhistory.clear();
conformal::findhistory.clear();
conformal::movehistory.clear();
conformal::includeHistory = false;
});
}

778
control.cpp Normal file
View File

@ -0,0 +1,778 @@
int frames;
bool outoffocus = false;
int mousex, mousey, joyx, joyy, panjoyx, panjoyy;
hyperpoint mouseh, mouseoh;
bool leftclick, rightclick, targetclick, hiliteclick, anyshiftclick, wheelclick,
forcetarget, lshiftclick, lctrlclick;
bool gtouched;
int getcstat, lgetcstat; ld getcshift; bool inslider;
int andmode = 0;
// is the player using mouse? (used for auto-cross)
bool mousing = true;
// is the mouse button pressed?
bool mousepressed = false;
bool mousemoved = false;
bool actonrelease = false;
ld shiftmul = 1;
cell *mouseover, *mouseover2, *lmouseover, *centerover;
ld modist, modist2, centdist;
movedir mousedest, joydir;
int lastt;
#ifdef WEB
Uint8 *SDL_GetKeyState(void *v) { static Uint8 tab[1024]; return tab; }
#endif
bool quitsaves() { return (items[itOrbSafety] && havesave); }
bool needConfirmation() {
return canmove && (gold() >= 30 || tkills() >= 50) && !cheater && !quitsaves();
}
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);
}
movedir vectodir(const hyperpoint& P) {
hyperpoint H = sphereflip * tC0(cwtV);
ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
transmatrix Centered = sphereflip * cwtV;
if(!euclid)
Centered = gpushxto0(H) * Centered;
else if(R > 1e-9)
Centered = eupush(-H[0], -H[1]) * Centered;
ld binv = 99;
ld dirdist[7];
for(int i=0; i<cwt.c->type; i++) {
dirdist[i] = intval(Centered * xspinpush0(-i * 2 * M_PI /cwt.c->type, .5), P);
}
movedir res;
res.d = -1;
for(int i=0; i<cwt.c->type; i++) {
if(dirdist[i] < binv) {
binv = dirdist[i];
res.d = i;
res.subdir = dirdist[(i+1)%cwt.c->type] < dirdist[(i+cwt.c->type-1)%cwt.c->type] ? 1 : -1;
if(sphere) res.subdir = -res.subdir;
}
}
// if(euclid) bdir = (bdir + 3) % 6;
return res;
}
void movepckeydir(int d) {
DEBB(DF_GRAPH, (debugfile,"movepckeydir\n"));
// EUCLIDEAN
movedir md =
vectodir(spin(-d * M_PI/4) * tC0(pushone()));
movepcto(md);
}
void calcMousedest() {
if(mouseout()) return;
if(vid.revcontrol == true) { mouseh[0] = -mouseh[0]; mouseh[1] = -mouseh[1]; }
ld mousedist = intval(mouseh, tC0(shmup::ggmatrix(cwt.c)));
mousedest.d = -1;
cellwalker bcwt = cwt;
ld dists[7];
for(int i=0; i<cwt.c->type; i++)
dists[i] = intval(mouseh, tC0(shmup::ggmatrix(cwt.c->mov[i])));
/* printf("curcell = %Lf\n", mousedist);
for(int i=0; i<cwt.c->type; i++)
printf("d%d = %Lf\n", i, dists[i]); */
for(int i=0; i<cwt.c->type; i++) if(dists[i] < mousedist) {
mousedist = dists[i];
mousedest.d = fixdir(i - cwt.spin, cwt.c);
mousedest.subdir =
dists[(i+1)%cwt.c->type] < dists[(i+cwt.c->type-1)%cwt.c->type] ? 1 : -1;
if(cwt.mirrored)
mousedest.d = fixdir(-mousedest.d, cwt.c),
mousedest.subdir = -mousedest.subdir;
if(sphere) mousedest.subdir = -mousedest.subdir;
}
if(vid.revcontrol == true) { mouseh[0] = -mouseh[0]; mouseh[1] = -mouseh[1]; }
cwt = bcwt;
}
void mousemovement() {
calcMousedest();
movepcto(mousedest);
lmouseover = NULL;
}
#ifndef NOSDL
SDL_Joystick* sticks[8];
int numsticks;
void initJoysticks() {
DEBB(DF_INIT, (debugfile,"init joysticks\n"));
numsticks = SDL_NumJoysticks();
if(numsticks > 8) numsticks = 8;
for(int i=0; i<numsticks; i++) {
sticks[i] = SDL_JoystickOpen(i);
/* printf("axes = %d, balls = %d, buttons = %d, hats = %d\n",
SDL_JoystickNumAxes(sticks[i]),
SDL_JoystickNumBalls(sticks[i]),
SDL_JoystickNumButtons(sticks[i]),
SDL_JoystickNumHats(sticks[i])
); */
}
}
void closeJoysticks() {
DEBB(DF_INIT, (debugfile,"close joysticks\n"));
for(int i=0; i<numsticks; i++) {
SDL_JoystickClose(sticks[i]), sticks[i] = NULL;
}
numsticks = 0;
}
void checkjoy() {
DEBB(DF_GRAPH, (debugfile,"check joy\n"));
if(!DEFAULTCONTROL) return;
ld joyvalue1 = sqr(vid.joyvalue);
ld joyvalue2 = sqr(vid.joyvalue2);
ld jx = joyx;
ld jy = joyy;
ld sq = jx*jx+jy*jy;
static int laststate = 0;
int curstate = sq < joyvalue1 ? 0 : sq < joyvalue2 ? 1 : 2;
if(curstate != laststate) flashMessages(), laststate = curstate;
if(autojoy) {
if(sq < joyvalue1) { if(joydir.d >= 0) movepcto(joydir); joydir.d = -1; return; }
if(sq < joyvalue2 && joydir.d == -1) return;
}
else {
if(sq < joyvalue1) { joydir.d = -1; return; }
}
joydir = vectodir(hpxy(jx, jy));
}
void checkpanjoy(double t) {
if(shmup::on) return;
if(vid.joypanspeed < 1e-7) return;
if(sqr(panjoyx) + sqr(panjoyy) < sqr(vid.joypanthreshold))
return;
ld jx = panjoyx * t * vid.joypanspeed;
ld jy = panjoyy * t * vid.joypanspeed;
playermoved = false;
View = gpushxto0(hpxy(jx, jy)) * View;
}
#endif
bool quitmainloop = false;
bool doexiton(int sym, int uni) {
if(sym == SDLK_ESCAPE) return true;
if(sym == SDLK_F10) return true;
if(uni != 0) return true;
return false;
}
void handleKeyQuit(int sym, int uni) {
dialog::handleNavigation(sym, uni);
// ignore the camera movement keys
#ifndef NORUG
if(rug::rugged && (sym == SDLK_UP || sym == SDLK_DOWN || sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN ||
sym == SDLK_RIGHT || sym == SDLK_LEFT))
sym = 0;
#endif
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_F10) quitmainloop = true;
else if(uni == 'r' || sym == SDLK_F5) {
restartGame(), popScreen();
msgs.clear();
}
else if(sym == SDLK_UP || sym == SDLK_KP8 || sym == PSEUDOKEY_WHEELUP) msgscroll++;
else if(sym == SDLK_DOWN || sym == SDLK_KP2 || sym == PSEUDOKEY_WHEELDOWN) msgscroll--;
else if(sym == SDLK_PAGEUP || sym == SDLK_KP9) msgscroll+=5;
else if(sym == SDLK_PAGEDOWN || sym == SDLK_KP3) msgscroll-=5;
else if(uni == 'v') popScreenAll(), pushScreen(showMainMenu);
else if(sym == SDLK_F3 || (sym == ' ' || sym == SDLK_HOME))
fullcenter();
else if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview();
#ifdef INV
else if(uni == 'i' && DEFAULTNOR(sym) && inv::on)
pushScreen(inv::show);
#endif
#ifndef NOSAVE
else if(uni == 't') {
if(!canmove) restartGame();
loadScores();
msgs.clear();
}
#endif
else if(doexiton(sym, uni) && !didsomething) {
popScreen();
msgscroll = 0;
msgs.clear();
if(!canmove) {
addMessage(XLAT("GAME OVER"));
addMessage(timeline());
}
}
}
bool didsomething;
#ifdef MOBILE
typedef int eventtype;
#else
typedef SDL_Event eventtype;
#endif
void handlePanning(int sym, int uni) {
if(rug::rugged) return;
#ifndef PANDORA
if(sym == SDLK_RIGHT) {
if(conformal::on)
conformal::lvspeed += 0.1 * shiftmul;
else
View = xpush(-0.2*shiftmul) * View, playermoved = false, didsomething = true;
}
if(sym == SDLK_LEFT) {
if(conformal::on)
conformal::lvspeed -= 0.1 * shiftmul;
else
View = xpush(+0.2*shiftmul) * View, playermoved = false, didsomething = true;
}
if(sym == SDLK_UP) {
if(conformal::on)
conformal::lvspeed += 0.1 * shiftmul;
else
View = ypush(+0.2*shiftmul) * View, playermoved = false, didsomething = true;
}
if(sym == SDLK_DOWN) {
if(conformal::on)
conformal::lvspeed -= 0.1 * shiftmul;
else
View = ypush(-0.2*shiftmul) * View, playermoved = false, didsomething = true;
}
#endif
if(sym == SDLK_PAGEUP) {
if(conformal::on)
conformal::rotation++;
else
View = spin(M_PI/S21*shiftmul) * View, didsomething = true;
}
if(sym == SDLK_PAGEDOWN) {
if(conformal::on)
conformal::rotation++;
else
View = spin(-M_PI/S21*shiftmul) * View, didsomething = true;
}
if(sym == SDLK_PAGEUP || sym == SDLK_PAGEDOWN)
if(isGravityLand(cwt.c->land)) playermoved = false;
if(sym == PSEUDOKEY_WHEELUP) {
ld jx = (mousex - vid.xcenter - .0) / vid.radius / 10;
ld jy = (mousey - vid.ycenter - .0) / vid.radius / 10;
playermoved = false;
View = gpushxto0(hpxy(jx, jy)) * View;
sym = 1;
}
}
void handleKeyNormal(int sym, int uni) {
if(cheater) {
if(applyCheat(uni, mouseover))
sym = 0;
}
if(DEFAULTNOR(sym)) handlePanning(sym, uni);
if(!(uni >= 'A' && uni <= 'Z') && DEFAULTCONTROL) {
if(sym == 'l' || sym == 'd' || sym == SDLK_KP6) movepckeydir(0);
if(sym == 'n' || sym == 'c' || sym == SDLK_KP3) movepckeydir(1);
if(sym == 'j' || sym == 'x' || sym == SDLK_KP2) movepckeydir(2);
if(sym == 'b' || sym == 'z' || sym == SDLK_KP1) movepckeydir(3);
if(sym == 'h' || sym == 'a' || sym == SDLK_KP4) movepckeydir(4);
if(sym == 'y' || sym == 'q' || sym == SDLK_KP7) movepckeydir(5);
if(sym == 'k' || sym == 'w' || sym == SDLK_KP8) movepckeydir(6);
if(sym == 'u' || sym == 'e' || sym == SDLK_KP9) movepckeydir(7);
}
#ifdef PANDORA
if(DEFAULTCONTROL) {
if(sym == SDLK_RIGHT) movepckeydir(0);
if(sym == SDLK_LEFT) movepckeydir(4);
if(sym == SDLK_DOWN) movepckeydir(2 + (leftclick?1:0) - (rightclick?1:0));
if(sym == SDLK_UP) movepckeydir(6 - (leftclick?1:0) + (rightclick?1:0));
}
#endif
if(uni == sym && DEFAULTNOR(sym)) {
gmodekeys(sym, uni);
if(sym == '8') {
backcolor = backcolor ^ 0xFFFFFF;
bordcolor = bordcolor ^ 0xFFFFFF;
forecolor = forecolor ^ 0xFFFFFF;
printf("back = %x\n", backcolor);
}
if(sym == '9') {
pmodel = eModel(8 - pmodel);
// vid.yshift = 1 - vid.yshift;
// vid.drawmousecircle = true;
}
if(sym == 'm' && canmove && cmode2 == smNormal && (centerover == cwt.c ? mouseover : centerover))
performMarkCommand(mouseover);
}
if(DEFAULTCONTROL) {
if(sym == '.' || sym == 's') movepcto(-1, 1);
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 && cmode2 == smNormal) {
if(playermoved && items[itStrongWind]) {
cell *c = whirlwind::jumpDestination(cwt.c);
if(c) centerover = c;
}
targetRangedOrb(centerover, roKeyboard);
sym = 0; uni = 0;
}
}
if(sym == SDLK_KP5 && DEFAULTCONTROL) movepcto(-1, 1);
// if(sym == SDLK_F4) restartGameSwitchEuclid();
if(sym == SDLK_F5) {
if(needConfirmation())
pushScreen(showMission);
else restartGame();
}
if(sym == SDLK_ESCAPE)
showMissionScreen();
if(sym == SDLK_F10) {
if(needConfirmation()) pushScreen(showMission);
else quitmainloop = true;
}
if(!canmove) {
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER) quitmainloop = true;
else if(uni == 'r') restartGame();
#ifndef NOSAVE
else if(uni == 't') {
restartGame();
loadScores();
}
#endif
#ifndef NORUG
else if(rug::rugged) ;
#endif
else if(sym == SDLK_UP || sym == SDLK_KP8) msgscroll++;
else if(sym == SDLK_DOWN || sym == SDLK_KP2) msgscroll--;
else if(sym == SDLK_PAGEUP || sym == SDLK_KP9) msgscroll+=5;
else if(sym == SDLK_PAGEDOWN || sym == SDLK_KP3) msgscroll-=5;
}
if(uni == 'o' && DEFAULTNOR(sym)) setAppropriateOverview();
#ifdef INV
if(uni == 'i' && DEFAULTNOR(sym) && inv::on)
pushScreen(inv::show);
#endif
if((sym == SDLK_HOME || sym == SDLK_F3 || sym == ' ') && DEFAULTNOR(sym))
fullcenter();
if(sym == 'v' && DEFAULTNOR(sym))
pushScreen(showMainMenu);
if(sym == '-' || sym == PSEUDOKEY_WHEELDOWN) {
actonrelease = false;
shmup::cpid = 0;
if(mouseover &&
targetclick && (!shmup::on || numplayers() == 1) && targetRangedOrb(mouseover, forcetarget ? roMouseForce : roMouse)) {
}
else if(forcetarget)
;
else if(!DEFAULTCONTROL) {
if(!shmup::on)
multi::mousemovement(mouseover);
}
else mousemovement();
}
if(sym == SDLK_F1) gotoHelp(help);
#ifdef ROGUEVIZ
rogueviz::processKey(sym, uni);
#endif
}
void handlekey(int sym, int uni) {
if(callhandlers(false, hooks_handleKey, sym, uni)) return;
keyhandler(sym, uni);
}
#ifdef NOSDL
void mainloopiter() { printf("(compiled without SDL -- no action)\n"); quitmainloop = true; }
#else
// Warning: a very long function! todo: refactor
int cframelimit = 1000;
void mainloopiter() {
DEBB(DF_GRAPH, (debugfile,"main loop\n"));
#ifndef GFX
#ifndef GL
vid.wallmode = 0;
vid.monmode = 0;
#endif
#endif
optimizeview();
if(conformal::on) conformal::apply();
ticks = SDL_GetTicks();
int timetowait = lastt + 1000 / cframelimit - ticks;
cframelimit = vid.framelimit;
if(outoffocus && cframelimit > 10) cframelimit = 10;
if(DOSHMUP && cmode2 == smNormal)
timetowait = 0, shmup::turn(ticks - lastt);
if(!DOSHMUP && (multi::alwaysuse || multi::players > 1) && cmode2 == smNormal)
timetowait = 0, multi::handleMulti(ticks - lastt);
if(vid.sspeed >= 5 && gmatrix.count(cwt.c) && !elliptic) {
cwtV = gmatrix[cwt.c] * ddspin(cwt.c, cwt.spin);
if(cwt.mirrored) playerV = playerV * Mirror;
}
#ifdef WEB
if(playermoved && vid.sspeed > -4.99 && !outoffocus) {
centerpc((ticks - lastt) / 1000.0 * exp(vid.sspeed));
}
if(!outoffocus) drawscreen();
#else
if(timetowait > 0)
SDL_Delay(timetowait);
else {
if(cmode2 == smNormal) {
if(playermoved && vid.sspeed > -4.99 && !outoffocus)
centerpc((ticks - lastt) / 1000.0 * exp(vid.sspeed));
if(panjoyx || panjoyy)
checkpanjoy((ticks - lastt) / 1000.0);
}
tortoise::updateVals(ticks - lastt);
frames++;
if(!outoffocus) {
drawscreen();
}
lastt = ticks;
}
#endif
Uint8 *keystate = SDL_GetKeyState(NULL);
rightclick = keystate[SDLK_RCTRL];
leftclick = keystate[SDLK_RSHIFT];
lctrlclick = keystate[SDLK_LCTRL];
lshiftclick = keystate[SDLK_LSHIFT];
forcetarget = (keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT]);
hiliteclick = keystate[SDLK_LALT] | keystate[SDLK_RALT];
anyshiftclick = keystate[SDLK_LSHIFT] | keystate[SDLK_RSHIFT];
wheelclick = false;
getcshift = 1;
if(keystate[SDLK_LSHIFT] || keystate[SDLK_RSHIFT]) getcshift = -1;
if(keystate[SDLK_LCTRL] || keystate[SDLK_RCTRL]) getcshift /= 10;
if(keystate[SDLK_LALT] || keystate[SDLK_RALT]) getcshift *= 10;
didsomething = false;
if(vid.shifttarget&1) {
leftclick = false;
targetclick = keystate[SDLK_RSHIFT] | keystate[SDLK_LSHIFT];
}
else {
leftclick = keystate[SDLK_RSHIFT];
targetclick = true;
}
#ifdef SDLAUDIO
if(audio) handlemusic();
#endif
SDL_Event ev;
DEBB(DF_GRAPH, (debugfile,"polling for events\n"));
achievement_pump();
while(SDL_PollEvent(&ev)) {
DEBB(DF_GRAPH, (debugfile,"got event type #%d\n", ev.type));
int sym = 0;
int uni = 0;
shiftmul = 1;
/* if(ev.type == SDL_JOYDEVICEADDED || ev.type == SDL_JOYDEVICEREMOVED) {
joyx = joyy = 0;
panjoyx = panjoyy = 0;
closeJoysticks();
initJoysticks();
}*/
if(ev.type == SDL_ACTIVEEVENT) {
if(ev.active.state & SDL_APPINPUTFOCUS) {
if(ev.active.gain) {
outoffocus = false;
}
else {
outoffocus = true;
}
}
}
if(ev.type == SDL_VIDEORESIZE) {
vid.xres = ev.resize.w;
vid.yres = ev.resize.h;
vid.killreduction = 0;
extern bool setfsize;
setfsize = true;
setvideomode();
#ifdef GL
if(vid.usingGL) glViewport(0, 0, vid.xres, vid.yres);
#endif
}
if(ev.type == SDL_VIDEOEXPOSE) {
drawscreen();
}
if(ev.type == SDL_JOYAXISMOTION) {
if(ev.jaxis.which == 0) {
if(ev.jaxis.axis == 0)
joyx = ev.jaxis.value;
else if(ev.jaxis.axis == 1)
joyy = ev.jaxis.value;
else if(ev.jaxis.axis == 3)
panjoyx = ev.jaxis.value;
else if(ev.jaxis.axis == 4)
panjoyy = ev.jaxis.value;
checkjoy();
// printf("panjoy = %d,%d\n", panjoyx, panjoyy);
}
else {
if(ev.jaxis.axis == 0)
panjoyx = ev.jaxis.value;
else
panjoyy = ev.jaxis.value;
}
}
if(ev.type == SDL_JOYBUTTONDOWN && cmode2 == smShmupConfig && vid.scfg.setwhat) {
int joyid = ev.jbutton.which;
int button = ev.jbutton.button;
if(joyid < 8 && button < 32)
vid.scfg.joyaction[joyid][button] = vid.scfg.setwhat;
vid.scfg.setwhat = 0;
}
else if(ev.type == SDL_JOYHATMOTION && cmode2 == smShmupConfig && vid.scfg.setwhat) {
int joyid = ev.jhat.which;
int hat = ev.jhat.hat;
int dir = 4;
if(ev.jhat.value == SDL_HAT_UP) dir = 0;
if(ev.jhat.value == SDL_HAT_RIGHT) dir = 1;
if(ev.jhat.value == SDL_HAT_DOWN) dir = 2;
if(ev.jhat.value == SDL_HAT_LEFT) dir = 3;
if(joyid < 8 && hat < 4 && dir < 4) {
vid.scfg.hataction[joyid][hat][dir] = vid.scfg.setwhat;
vid.scfg.setwhat = 0;
}
}
else if(ev.type == SDL_JOYBUTTONDOWN && DEFAULTCONTROL) {
flashMessages();
movepcto(joydir);
checkjoy();
}
if(ev.type == SDL_KEYDOWN) {
flashMessages();
mousing = false;
sym = ev.key.keysym.sym;
uni = ev.key.keysym.unicode;
if(ev.key.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) shiftmul = -1;
if(ev.key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) shiftmul /= 10;
if(sym == SDLK_RETURN && (ev.key.keysym.mod & (KMOD_LALT | KMOD_RALT))) {
sym = 0; uni = 0;
switchFullscreen();
}
}
dialog::handleZooming(ev);
if(sym == SDLK_F1 && cmode2 == smNormal && playermoved)
help = "@";
bool rollchange =
cmode2 == smOverview && getcstat >= 2000 && cheater;
if(ev.type == SDL_MOUSEBUTTONDOWN) {
flashMessages();
mousepressed = true;
mousing = true;
actonrelease = true;
if(ev.button.button==SDL_BUTTON_WHEELDOWN) {
sym = uni = PSEUDOKEY_WHEELDOWN;
}
if(ev.button.button==SDL_BUTTON_WHEELUP) {
sym = uni = PSEUDOKEY_WHEELUP;
}
else if(ev.button.button == SDL_BUTTON_RIGHT) {
sym = 1; didsomething = true;
}
else if(ev.button.button == SDL_BUTTON_MIDDLE) {
sym = 2; didsomething = true;
}
}
if(ev.type == SDL_MOUSEBUTTONUP) {
mousepressed = false;
mousing = true;
if(ev.button.button==SDL_BUTTON_RIGHT || leftclick)
sym = SDLK_F1;
else if(ev.button.button==SDL_BUTTON_MIDDLE || rightclick)
sym = 1, didsomething = true;
else if(ev.button.button == SDL_BUTTON_LEFT && actonrelease) {
sym = getcstat, uni = getcstat, shiftmul = getcshift;
}
else if(ev.button.button == SDL_BUTTON_WHEELUP && rollchange) {
sym = getcstat, uni = getcstat, shiftmul = getcshift, wheelclick = true;
}
else if(ev.button.button == SDL_BUTTON_WHEELDOWN && rollchange) {
sym = getcstat, uni = getcstat, shiftmul = -getcshift, wheelclick = true;
}
}
if(ev.type == SDL_MOUSEMOTION) {
mouseoh = mouseh;
mousing = true;
mousemoved = true;
mousex = ev.motion.x;
mousey = ev.motion.y;
#ifndef NORUG
if(rug::rugged)
mouseh = rug::gethyper(mousex, mousey);
else
#endif
mouseh = gethyper(mousex, mousey);
if((rightclick || (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MMASK)) && !mouseout2() &&
mouseh[2] < 50 && mouseoh[2] < 50) {
panning(mouseoh, mouseh);
}
#ifdef SIMULATE_JOYSTICK
// pretend that both joysticks are present
stick = panstick = (SDL_Joystick*) (&vid);
panjoyx = 20 * (mousex - vid.xcenter);
panjoyy = 20 * (mousey - vid.ycenter);
checkjoy();
#endif
if(mousepressed && inslider) {
sym = getcstat, uni = getcstat, shiftmul = getcshift;
}
}
if(ev.type == SDL_QUIT) {
if(needConfirmation() && cmode2 != smMission) showMissionScreen();
else quitmainloop = true;
}
handlekey(sym, uni);
}
}
#endif
void mainloop() {
lastt = 0;
#ifdef WEB
initweb();
emscripten_set_main_loop(mainloopiter, 0, true);
#else
while(!quitmainloop) mainloopiter();
#endif
}
#ifdef MOBILE
void displayabutton(int px, int py, string s, int col) {
// TMP
int siz = vid.yres > vid.xres ? vid.fsize*2 : vid.fsize * 3/2;
int vrx = min(vid.radius, vid.xres/2 - 40);
int vry = min(vid.radius, min(vid.ycenter, vid.yres - vid.ycenter) - 20);
int x = vid.xcenter + px * vrx;
int y = vid.ycenter + py * (vry - siz/2);
int vrr = int(hypot(vrx, vry) * sqrt(2.));
if(gtouched && !mouseover
&& abs(mousex - vid.xcenter) < vrr
&& abs(mousey - vid.ycenter) < vrr
&& hypot(mousex-vid.xcenter, mousey-vid.ycenter) > vrr
&& px == (mousex > vid.xcenter ? 1 : -1)
&& py == (mousey > vid.ycenter ? 1 : -1)
) col = 0xFF0000;
if(displayfr(x, y, 0, siz, s, col, 8+8*px))
buttonclicked = true;
}
#endif

View File

@ -386,7 +386,53 @@ namespace dialog {
int colorp = 0;
void drawColorDialog(int color) {
int *colorPointer;
bool handleKeyColor(int sym, int uni) {
int& color = *colorPointer;
if(uni >= 'A' && uni <= 'D') {
int x = (mousex - vid.xres/4) * 510 / vid.xres;
if(x < 0) x = 0;
if(x > 255) x = 255;
unsigned char* pts = (unsigned char*) &color;
pts[uni - 'A'] = x;
}
else if(uni == ' ') {
bool inHistory = false;
for(int i=0; i<10; i++) if(colorhistory[i] == (unsigned) color)
inHistory = true;
if(!inHistory) { colorhistory[lch] = color; lch++; lch %= 10; }
popScreen();
}
else if(uni >= '0' && uni <= '9') {
color = colorhistory[uni - '0'];
}
else if(palette && uni >= 'a' && uni < 'a'+(int) palette[0]) {
color = palette[1 + uni - 'a'];
}
else if(sym == SDLK_DOWN || sym == SDLK_KP2) {
colorp = (colorp-1) & 3;
}
else if(sym == SDLK_UP || sym == SDLK_KP8) {
colorp = (colorp+1) & 3;
}
else if(sym == SDLK_LEFT || sym == SDLK_KP4) {
unsigned char* pts = (unsigned char*) &color;
pts[colorp] -= abs(shiftmul) < .6 ? 1 : 17;
}
else if(sym == SDLK_RIGHT || sym == SDLK_KP6) {
unsigned char* pts = (unsigned char*) &color;
pts[colorp] += abs(shiftmul) < .6 ? 1 : 17;
}
else if(doexiton(sym, uni))
popScreen();
return false;
}
void drawColorDialog() {
int color = *colorPointer;
int ash = 8;
for(int j=0; j<10; j++) {
@ -427,60 +473,13 @@ namespace dialog {
}
displayColorButton(vid.xres/2, vid.yres/2+vid.fsize * 6, XLAT("select this color") + " : " + itsh(color), ' ', 8, 0, color >> ash);
keyhandler = handleKeyColor;
}
// 0: nothing happened, 1: color accepted, 2: break
int handleKeyColor(int sym, int uni, int& color) {
if(uni >= 'A' && uni <= 'D') {
int x = (mousex - vid.xres/4) * 510 / vid.xres;
if(x < 0) x = 0;
if(x > 255) x = 255;
unsigned char* pts = (unsigned char*) &color;
pts[uni - 'A'] = x;
}
else if(uni == ' ') {
bool inHistory = false;
for(int i=0; i<10; i++) if(colorhistory[i] == (unsigned) color)
inHistory = true;
if(!inHistory) { colorhistory[lch] = color; lch++; lch %= 10; }
return 1;
}
else if(uni >= '0' && uni <= '9') {
color = colorhistory[uni - '0'];
}
else if(palette && uni >= 'a' && uni < 'a'+(int) palette[0]) {
color = palette[1 + uni - 'a'];
}
else if(sym == SDLK_DOWN || sym == SDLK_KP2) {
colorp = (colorp-1) & 3;
}
else if(sym == SDLK_UP || sym == SDLK_KP8) {
colorp = (colorp+1) & 3;
}
else if(sym == SDLK_LEFT || sym == SDLK_KP4) {
unsigned char* pts = (unsigned char*) &color;
pts[colorp] -= abs(shiftmul) < .6 ? 1 : 17;
}
else if(sym == SDLK_RIGHT || sym == SDLK_KP6) {
unsigned char* pts = (unsigned char*) &color;
pts[colorp] += abs(shiftmul) < .6 ? 1 : 17;
}
else if(uni || sym == SDLK_F10) return 2;
return 0;
}
int *colorPointer;
emtype lastmode;
void openColorDialog(int& col, unsigned int *pal) {
colorPointer = &col; palette = pal;
lastmode = cmode; cmode = emColor;
}
void handleColor(int sym, int uni) {
int ret = handleKeyColor(sym, uni, *colorPointer);
if(ret) cmode = lastmode;
pushScreen(drawColorDialog);
}
struct numberEditor {
@ -511,28 +510,6 @@ namespace dialog {
ne.positive = true;
}
void editNumber(ld& x, ld vmin, ld vmax, ld step, ld dft, string title, string help) {
ne.editwhat = &x;
ne.s = fts(x);
ne.vmin = vmin;
ne.vmax = vmax;
ne.step = step;
ne.dft = dft;
ne.title = title;
ne.help = help;
lastmode = cmode; cmode = emNumber;
ne.scale = ne.inverse_scale = identity;
ne.intval = NULL;
ne.positive = false;
sidedialog = false;
}
void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help) {
editNumber(ne.intbuf, vmin, vmax, step, dft, title, help);
ne.intbuf = x; ne.intval = &x; ne.s = its(x);
sidedialog = true;
}
string disp(ld x) { if(ne.intval) return its((int) (x+.5)); else return fts(x); }
void affect(char kind) {
@ -603,14 +580,14 @@ namespace dialog {
if(ne.intval == &polygonal::coefid && polygonal::coefid < 0)
*ne.editwhat = *ne.intval = 0, affect('v');
if(ne.intval == &polygonal::coefid && polygonal::coefid >= MSI)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
if(ne.intval == &polygonal::coefid && polygonal::coefid >= polygonal::MSI)
*ne.editwhat = *ne.intval = polygonal::MSI-1, affect('v');
if(ne.intval == &polygonal::deg && polygonal::deg < 0)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
*ne.editwhat = *ne.intval = polygonal::MSI-1, affect('v');
if(ne.intval == &polygonal::deg && polygonal::deg >= MSI)
*ne.editwhat = *ne.intval = MSI-1, affect('v');
if(ne.intval == &polygonal::deg && polygonal::deg >= polygonal::MSI)
*ne.editwhat = *ne.intval = polygonal::MSI-1, affect('v');
if(ne.intval == &polygonal::SI) polygonal::solve();
if(ne.editwhat == &polygonal::STAR) polygonal::solve();
@ -623,13 +600,15 @@ namespace dialog {
if(ne.editwhat == &geom3::middetail && geom3::highdetail > geom3::middetail)
geom3::highdetail = geom3::middetail;
if(lastmode == em3D) buildpolys();
buildpolys();
#ifdef GL
if(lastmode == em3D) resetGL();
resetGL();
#endif
}
void drawNumberDialog() {
gamescreen(sidedialog ? 0 : 2);
cmode2 = smNumber;
init(ne.title);
addInfo(ne.s);
addSlider(ne.scale(ne.vmin), ne.scale(*ne.editwhat), ne.scale(ne.vmax), 500);
@ -644,7 +623,7 @@ namespace dialog {
addBreak(100);
if(lastmode == em3D) ne.help = explain3D(ne.editwhat);
ne.help = explain3D(ne.editwhat);
if(ne.help != "") {
addHelp(ne.help);
@ -671,70 +650,68 @@ namespace dialog {
addBoolItem("finer lines at the boundary", vid.antialias & AA_LINEWIDTH, 'o');
display();
}
void handleNumber(int sym, int uni) {
handleNavigation(sym, uni);
if((uni >= '0' && uni <= '9') || (uni == '.' && !ne.intval) || (uni == '-' && !ne.positive)) {
ne.s += uni;
affect('s');
}
else if(uni == '\b' || uni == '\t') {
ne.s = ne.s. substr(0, size(ne.s)-1);
sscanf(ne.s.c_str(), LDF, ne.editwhat);
affect('s');
}
#ifndef MOBILE
else if(sym == SDLK_RIGHT || sym == SDLK_KP6) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)++;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) + shiftmul * ne.step);
affect('v');
}
else if(sym == SDLK_LEFT || sym == SDLK_KP4) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)--;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) - shiftmul * ne.step);
affect('v');
}
#endif
else if(sym == SDLK_HOME) {
*ne.editwhat = ne.dft;
affect('v');
}
else if(uni == 500) {
int sl, sr;
if(sidescreen)
sl = vid.yres + vid.fsize*2, sr = vid.xres - vid.fsize*2;
else
sl = vid.xres/4, sr = vid.xres*3/4;
ld d = (mousex - sl + .0) / (sr-sl);
*ne.editwhat =
ne.inverse_scale(d * (ne.scale(ne.vmax) - ne.scale(ne.vmin)) + ne.scale(ne.vmin));
affect('v');
}
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";
}
else if(uni == 'k' && ne.editwhat == &vid.alpha) {
*ne.editwhat = 0; vid.scale = 1; ne.s = "0";
}
else if((uni == 'i' || uni == 'I' || uni == 'o' || uni == 'O') && ne.editwhat == &vid.alpha) {
double d = exp(shiftmul/10);
vid.alpha *= d;
vid.scale *= d;
ne.s = fts(vid.alpha);
}
else if(doexiton(sym, uni)) {
cmode = lastmode;
}
}
keyhandler = [] (int sym, int uni) {
handleNavigation(sym, uni);
if((uni >= '0' && uni <= '9') || (uni == '.' && !ne.intval) || (uni == '-' && !ne.positive)) {
ne.s += uni;
affect('s');
}
else if(uni == '\b' || uni == '\t') {
ne.s = ne.s. substr(0, size(ne.s)-1);
sscanf(ne.s.c_str(), LDF, ne.editwhat);
affect('s');
}
#ifndef MOBILE
else if(sym == SDLK_RIGHT || sym == SDLK_KP6) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)++;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) + shiftmul * ne.step);
affect('v');
}
else if(sym == SDLK_LEFT || sym == SDLK_KP4) {
if(ne.intval && abs(shiftmul) < .6)
(*ne.editwhat)--;
else
*ne.editwhat = ne.inverse_scale(ne.scale(*ne.editwhat) - shiftmul * ne.step);
affect('v');
}
#endif
else if(sym == SDLK_HOME) {
*ne.editwhat = ne.dft;
affect('v');
}
else if(uni == 500) {
int sl, sr;
if(sidescreen)
sl = vid.yres + vid.fsize*2, sr = vid.xres - vid.fsize*2;
else
sl = vid.xres/4, sr = vid.xres*3/4;
ld d = (mousex - sl + .0) / (sr-sl);
*ne.editwhat =
ne.inverse_scale(d * (ne.scale(ne.vmax) - ne.scale(ne.vmin)) + ne.scale(ne.vmin));
affect('v');
}
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";
}
else if(uni == 'k' && ne.editwhat == &vid.alpha) {
*ne.editwhat = 0; vid.scale = 1; ne.s = "0";
}
else if((uni == 'i' || uni == 'I' || uni == 'o' || uni == 'O') && ne.editwhat == &vid.alpha) {
double d = exp(shiftmul/10);
vid.alpha *= d;
vid.scale *= d;
ne.s = fts(vid.alpha);
}
else if(doexiton(sym, uni)) popScreen();
};
}
int nlpage = 1;
int wheelshift = 0;
@ -785,4 +762,26 @@ namespace dialog {
return true;
}
void editNumber(ld& x, ld vmin, ld vmax, ld step, ld dft, string title, string help) {
ne.editwhat = &x;
ne.s = fts(x);
ne.vmin = vmin;
ne.vmax = vmax;
ne.step = step;
ne.dft = dft;
ne.title = title;
ne.help = help;
ne.scale = ne.inverse_scale = identity;
ne.intval = NULL;
ne.positive = false;
sidedialog = false;
pushScreen(drawNumberDialog);
}
void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help) {
editNumber(ne.intbuf, vmin, vmax, step, dft, title, help);
ne.intbuf = x; ne.intval = &x; ne.s = its(x);
sidedialog = true;
}
};

View File

@ -5415,8 +5415,12 @@ void checkmove() {
if(movepcto(1, 1, true))
canmove = legalmoves[cwt.spin] = true;
if(kills[moPlayer]) canmove = false;
if(!canmove)
if(!canmove) {
achievement_final(true);
if(cmode2 == smNormal) showMissionScreen();
}
if(canmove && timerstopped) {
timerstart = time(NULL);
timerstopped = false;

4761
graph.cpp

File diff suppressed because it is too large Load Diff

816
help.cpp Normal file
View File

@ -0,0 +1,816 @@
string help;
#ifndef NOLAMBDAS
function<void()> help_delegate;
#endif
string buildHelpText() {
DEBB(DF_GRAPH, (debugfile,"buildHelpText\n"));
#ifdef ROGUEVIZ
if(rogueviz::on) return rogueviz::makehelp();
#endif
string h;
h += XLAT("Welcome to HyperRogue");
#ifdef ANDROID
h += XLAT(" for Android");
#endif
#ifdef IOS
h += XLAT(" for iOS");
#endif
h += XLAT("! (version %1)\n\n", VER);
h += XLAT(
"You have been trapped in a strange, non-Euclidean world. Collect as much treasure as possible "
"before being caught by monsters. The more treasure you collect, the more "
"monsters come to hunt you, as long as you are in the same land type. The "
"Orbs of Yendor are the ultimate treasure; get at least one of them to win the game!"
);
h += XLAT(" (press ESC for some hints about it).");
h += "\n\n";
h += XLAT(
"You can fight most monsters by moving into their location. "
"The monster could also kill you by moving into your location, but the game "
"automatically cancels all moves which result in that.\n\n"
);
h += XLAT(
"There are many lands in HyperRogue. Collect 10 treasure "
"in the given land type to complete it; this enables you to "
"find the magical Orbs of this land, and in some cases "
"get access to new lands. At 25 treasures "
"this type of Orbs starts appearing in other lands as well. Press 'o' to "
"get the details of all the Lands.\n\n");
h += "\n\n";
#ifdef MOBILE
h += XLAT(
"Usually, you move by touching somewhere on the map; you can also touch one "
"of the four buttons on the map corners to change this (to scroll the map "
"or get information about map objects). You can also touch the "
"numbers displayed to get their meanings.\n"
);
#else
h += XLAT(
"Move with mouse, num pad, qweadzxc, or hjklyubn. Wait by pressing 's' or '.'. Spin the world with arrows, PageUp/Down, and Home/Space. "
"To save the game you need an Orb of Safety. Press 'v' for the main menu (configuration, special modes, etc.), ESC for the quest status.\n\n"
);
h += XLAT(
"You can right click any element to get more information about it.\n\n"
);
h += XLAT("(You can also use right Shift)\n\n");
#endif
h += XLAT("See more on the website: ")
+ "http//roguetemple.com/z/hyper/\n\n";
#ifdef TOUR
h += XLAT("Try the Tutorial to help with understanding the "
"geometry of HyperRogue (menu -> special modes).\n\n");
#endif
h += XLAT("Still confused? Read the FAQ on the HyperRogue website!\n\n");
return h;
}
string buildCredits() {
string h;
h += XLAT("game design, programming, texts and graphics by Zeno Rogue <zeno@attnam.com>\n\n");
if(lang() != 0)
h += XLAT("add credits for your translation here");
#ifndef NOLICENSE
h += XLAT(
"released under GNU General Public License version 2 and thus "
"comes with absolutely no warranty; see COPYING for details\n\n"
);
#endif
h += XLAT(
"special thanks to the following people for their bug reports, feature requests, porting, and other help:\n\n%1\n\n",
"Konstantin Stupnik, ortoslon, chrysn, Adam Borowski, Damyan Ivanov, Ryan Farnsley, mcobit, Darren Grey, tricosahedron, Maciej Chojecki, Marek Čtrnáct, "
"wonderfullizardofoz, Piotr MigdaĹ, tehora, Michael Heerdegen, Sprite Guard, zelda0x181e, Vipul, snowyowl0, Patashu, phenomist, Alan Malloy, Tom Fryers, Sinquetica, _monad, CtrlAltDestroy, jruderman"
);
#ifdef EXTRALICENSE
h += EXTRALICENSE;
#endif
#ifndef MOBILE
h += XLAT(
"\n\nSee sounds/credits.txt for credits for sound effects"
);
#endif
if(musiclicense != "") h += musiclicense;
return h;
}
string pushtext(stringpar p) {
string s = XLAT(
"\n\nNote: when pushing %the1 off a heptagonal cell, you can control the pushing direction "
"by clicking left or right half of the heptagon.", p);
#ifndef MOBILE
s += XLAT(" With the keyboard, you can rotate the view for a similar effect (Page Up/Down).");
#endif
return s;
}
string princedesc() {
if(princessgender() == GEN_M)
return XLAT("Apparently a prince is kept locked somewhere, but you won't ever find him in this hyperbolic palace. ");
else
return XLAT("Apparently a princess is kept locked somewhere, but you won't ever find her in this hyperbolic palace. ");
}
string helptitle(string s, int col) {
return "@" + its(col) + "\t" + s + "\n";
}
string princessReviveHelp() {
string h = "\n\n" +
XLAT("Killed %1 can be revived with Orb of the Love, after you collect 20 more $$$.", moPrincess);
if(princess::reviveAt)
h += "\n\n" +
XLAT("%The1 will be revivable at %2 $$$", moPrincess, its(princess::reviveAt));
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);
help += XLAT(iinf[it].help);
if(it == itSavedPrincess || it == itOrbLove)
help += princessReviveHelp();
if(it == itTrollEgg)
help += XLAT("\n\nAfter the Trolls leave, you have 750 turns to collect %the1, or it gets stolen.", it);
if(it == itIvory || it == itAmethyst || it == itLotus || it == itMutant) {
help += XLAT(
"\n\nEasy %1 might disappear when you collect more of its kind.", it);
if(it != itMutant) help += XLAT(
" You need to go deep to collect lots of them.");
}
#ifdef MOBILE
if(it == itOrbSafety)
help += XLAT("This might be very useful for devices with limited memory.");
#else
if(it == itOrbSafety)
help += XLAT("Thus, it is potentially useful for extremely long games, which would eat all the memory on your system otherwise.\n");
#endif
if(isRangedOrb(it)) {
help += XLAT("\nThis is a ranged Orb. ");
#ifdef ISMOBILE
if(vid.shifttarget&2)
help += XLAT("\nRanged Orbs can be targeted by long touching the desired location.");
else
help += XLAT("\nRanged Orbs can be targeted by touching the desired location.");
#else
if(vid.shifttarget&1)
help += XLAT("\nRanged Orbs can be targeted by shift-clicking the desired location. "
else
help += XLAT("\nRanged Orbs can be targeted by clicking the desired location. ");
help += "You can also scroll to the desired location and then press 't'.");
#endif
help += XLAT("\nYou can never target cells which are adjacent to the player character, or ones out of the sight range.");
}
#ifdef MOBILE
if(it == itGreenStone)
help += XLAT("You can touch the Dead Orb in your inventory to drop it.");
#else
if(it == itGreenStone)
help += XLAT("You can press 'g' or click them in the list to drop a Dead Orb.");
#endif
if(it == itOrbLightning || it == itOrbFlash)
help += XLAT("\n\nThis Orb is triggered on your first attack or illegal move.");
if(it == itOrbShield)
help += XLAT("\n\nThis Orb protects you from attacks, scents, and insulates you "
"from electricity. It does not let you go through deadly terrain, but "
"if you are attacked with fire, it lets you stay in place in it.");
if(it == itOrbEmpathy) {
int cnt = 0;
for(int i=0; i<ittypes; i++) {
eItem it2 = eItem(i);
if(isEmpathyOrb(it2)) {
help += XLAT(cnt ? ", %1" : " %1", it2);
cnt++;
}
}
}
if(itemclass(it) == IC_ORB || it == itGreenStone || it == itOrbYendor) {
for(int i=0; i<ORBLINES; i++) {
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);
}
else if(oi.l == cwt.c->land) {
help += XLAT("\n\nSecondary orb: %1", oi.orb);
describeOrb(help, oi);
}
}
}
}
return help;
}
void addMinefieldExplanation(string& s) {
s += XLAT(
"\n\nOnce you collect 10 Bomberbird Eggs, "
"stepping on a cell with no adjacent mines also reveals the adjacent cells. "
"Collecting even more Eggs will increase the radius. Additionally, collecting "
"25 Bomberbird Eggs will reveal adjacent cells even in your future games."
);
s += "\n\n";
#ifdef MOBILE
s += XLAT("Known mines may be marked by pressing 'm'. Your allies won't step on marked mines.");
#else
s += XLAT("Known mines may be marked by touching while in drag mode. Your allies won't step on marked mines.");
#endif
}
string generateHelpForWall(eWall w) {
string s = helptitle(XLATN(winf[w].name), winf[w].color);
s += XLAT(winf[w].help);
if(w == waMineMine || w == waMineUnknown || w == waMineOpen)
addMinefieldExplanation(s);
if(isThumper(w)) s += pushtext(w);
if((w == waClosePlate || w == waOpenPlate) && purehepta)
s += "\n\n(For the heptagonal mode, the radius has been reduced to 2 for closing plates.)";
return s;
}
void buteol(string& s, int current, int req) {
int siz = size(s);
if(s[siz-1] == '\n') s.resize(siz-1);
char buf[100]; sprintf(buf, " (%d/%d)", current, req);
s += buf; s += "\n";
}
string generateHelpForMonster(eMonster m) {
string s = helptitle(XLATN(minf[m].name), minf[m].color);
if(m == moPlayer) {
#ifdef TOUR
if(tour::on)
return s+XLAT(
"A tourist from another world. They mutter something about the 'tutorial', "
"and claim that they are here just to learn, and to leave without any treasures. "
"Do not kill them!"
);
#endif
s += XLAT(
"This monster has come from another world, presumably to steal our treasures. "
"Not as fast as an Eagle, not as resilient as the guards from the Palace, "
"and not as huge as the Mutant Ivy from the Clearing; however, "
"they are very dangerous because of their intelligence, "
"and access to magical powers.\n\n");
if(cheater)
s += XLAT("Actually, their powers appear god-like...\n\n");
else if(!hardcore)
s += XLAT(
"Rogues will never make moves which result in their immediate death. "
"Even when cornered, they are able to instantly teleport back to their "
"home world at any moment, taking the treasures forever... but "
"at least they will not steal anything further!\n\n"
);
if(!euclid)
s += XLAT(
"Despite this intelligence, Rogues appear extremely surprised "
"by the most basic facts about geometry. They must come from "
"some really strange world.\n\n"
);
if(shmup::on)
s += XLAT("In the Shoot'em Up mode, you are armed with thrown Knives.");
return s;
}
s += XLAT(minf[m].help);
if(m == moPalace || m == moSkeleton)
s += pushtext(m);
if(m == moTroll) s += XLAT(trollhelp2);
if(isMonsterPart(m))
s += XLAT("\n\nThis is a part of a monster. It does not count for your total kills.", m);
if(isFriendly(m))
s += XLAT("\n\nThis is a friendly being. It does not count for your total kills.", m);
if(m == moTortoise)
s += XLAT("\n\nTortoises are not monsters! They are just annoyed. They do not count for your total kills.", m);
if(isGhost(m))
s += XLAT("\n\nA Ghost never moves to a cell which is adjacent to another Ghost of the same kind.", m);
if(m == moBat || m == moEagle)
s += XLAT("\n\nFast flying creatures may attack or go against gravity only in their first move.", m);
return s;
}
string generateHelpForLand(eLand l) {
string s = helptitle(XLATN(linf[l].name), linf[l].color);
if(l == laPalace) s += princedesc();
s += XLAT(linf[l].help);
if(l == laMinefield) addMinefieldExplanation(s);
s += "\n\n";
if(l == laIce || l == laCaves || l == laDesert || l == laMotion || l == laJungle ||
l == laCrossroads || l == laAlchemist)
s += XLAT("Always available.\n");
#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", 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(R30)
if(isCoastal(l))
s += XLAT("Coastal region -- connects inland and aquatic regions.\n");
if(isPureSealand(l))
s += XLAT("Aquatic region -- accessible only from coastal regions and other aquatic regions.\n");
if(l == laWhirlpool) ACCONLY(laOcean)
if(l == laRlyeh) ACCONLYF(laOcean)
if(l == laTemple) ACCONLY(laRlyeh)
if(l == laClearing) ACCONLY(laOvergrown)
if(l == laHaunted) ACCONLY(laGraveyard)
if(l == laPrincessQuest) ACCONLY(laPalace)
if(l == laMountain) ACCONLY(laJungle)
if(l == laCamelot) ACCONLY2(laCrossroads, laCrossroads3)
if(l == laDryForest || l == laWineyard || l == laDeadCaves || l == laHive || l == laRedRock ||
l == laOvergrown || l == laStorms || l == laWhirlwind || l == laRose ||
l == laCrossroads2 || l == laRlyeh)
TREQ(R60)
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(U5, itIvory)
if(l == laDungeon) TREQ2(U5, itPalace)
if(l == laMountain) TREQ2(U5, itIvory)
if(l == laMountain) TREQ2(U5, itRuby)
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(), R100);
}
if(l == laDragon) {
s += XLAT("Different kills required: %1.\n", "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 %2 treasure)\n", "9", its(R10));
buteol(s, orbsUnlocked(), 9);
}
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);
buteol(s, kills[moVizier], 1);
}
#define KILLREQ(who, where) { s += XLAT("Kills required: %1 (%2).\n", who, where); buteol(s, kills[who], 1); }
if(l == laPrincessQuest)
KILLREQ(moVizier, laPalace);
if(l == laElementalWall) {
KILLREQ(moFireElemental, laDragon);
KILLREQ(moEarthElemental, laDeadCaves);
KILLREQ(moWaterElemental, laLivefjord);
KILLREQ(moAirElemental, laWhirlwind);
}
if(l == laTrollheim) {
KILLREQ(moTroll, laCaves);
KILLREQ(moFjordTroll, laLivefjord);
KILLREQ(moDarkTroll, laDeadCaves);
KILLREQ(moStormTroll, laStorms);
KILLREQ(moForestTroll, laOvergrown);
KILLREQ(moRedTroll, laRedRock);
}
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.");
int rl = isRandland(l);
if(rl == 2)
s += XLAT("Variants of %the1 are always available in the Random Pattern Mode.", l);
else if(rl == 1)
s += XLAT(
"Variants of %the1 are available in the Random Pattern Mode after "
"getting a highscore of at least 10 %2.", l, treasureType(l));
if(l == laPrincessQuest) {
s += XLAT("Unavailable in the shmup mode.\n");
s += XLAT("Unavailable in the multiplayer mode.\n");
}
if(noChaos(l))
s += XLAT("Unavailable in the Chaos mode.\n");
if(l == laWildWest)
s += XLAT("Bonus land, available only in some special modes.\n");
if(l == laWhirlpool)
s += XLAT("Orbs of Safety always appear here, and may be used to escape.\n");
/* if(isHaunted(l) || l == laDungeon)
s += XLAT("You may be unable to leave %the1 if you are not careful!\n", l); */
if(l == laStorms) {
if(elec::lightningfast == 0) s += XLAT("\nSpecial conduct (still valid)\n");
else s += XLAT("\nSpecial conduct failed:\n");
s += XLAT(
"Avoid escaping from a discharge (\"That was close\").");
}
if(isHaunted(l)) {
if(survivalist) s += XLAT("\nSpecial conduct (still valid)\n");
else s += XLAT("\nSpecial conduct failed:\n");
s += XLAT(
"Avoid chopping trees, using Orbs, and non-graveyard monsters in the Haunted Woods."
);
}
#ifndef ISMOBILE
if(l == laCA)
s += XLAT("\n\nHint: use 'm' to toggle cells quickly");
#endif
return s;
}
bool instat;
string turnstring(int i) {
if(i == 1) return XLAT("1 turn");
else return XLAT("%1 turns", its(i));
}
void describeMouseover() {
DEBB(DF_GRAPH, (debugfile,"describeMouseover\n"));
cell *c = mousing ? mouseover : playermoved ? NULL : centerover;
string out = mouseovers;
if(!c || instat || getcstat) { }
else if(c->wall != waInvisibleFloor) {
out = XLAT1(linf[c->land].name);
help = generateHelpForLand(c->land);
// Celsius
// if(c->land == laIce) out = "Icy Lands (" + fts(60 * (c->heat - .4)) + " C)";
if(c->land == laIce || c->land == laCocytus)
out += " (" + fts(heat::celsius(c)) + " °C)";
if(c->land == laDryForest && c->landparam)
out += " (" + its(c->landparam)+"/10)";
if(c->land == laOcean && chaosmode)
out += " (" + its(c->CHAOSPARAM)+"S"+its(c->SEADIST)+"L"+its(c->LANDDIST)+")";
else if(c->land == laOcean && c->landparam <= 25) {
if(shmup::on)
out += " (" + its(c->landparam)+")";
else {
bool b = c->landparam >= tide[(turncount-1) % tidalsize];
int t = 1;
for(; t < 1000 && b == (c->landparam >= tide[(turncount+t-1) % tidalsize]); t++) ;
if(b)
out += " (" + turnstring(t) + XLAT(" to surface") + ")";
else
out += " (" + turnstring(t) + XLAT(" to submerge") + ")";
}
}
if(c->land == laTortoise && tortoise::seek()) out += " " + tortoise::measure(getBits(c));
/* if(c->land == laGraveyard || c->land == laHauntedBorder || c->land == laHaunted)
out += " (" + its(c->landparam)+")"; */
if(buggyGeneration) {
char buf[20]; sprintf(buf, " H=%d M=%d", c->landparam, c->mpdist); out += buf;
}
// if(c->land == laBarrier)
// out += "(" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
// out += "(" + its(c->bardir) + ":" + string(linf[c->barleft].name) + " / " + string(linf[c->barright].name) + ")";
// out += " MD"+its(c->mpdist);
// out += " WP:" + its(c->wparam);
// out += " rose:" + its(rosemap[c]/4) + "." + its(rosemap[c]%4);
// out += " MP:" + its(c->mpdist);
// out += " cda:" + its(celldistAlt(c));
/* out += " DP=" + its(celldistance(c, cwt.c));
out += " DO=" + its(celldist(c));
out += " PD=" + its(c->pathdist); */
if(false) {
out += " LP:" + itsh(c->landparam)+"/"+its(turncount);
out += " CD:" + its(celldist(c));
out += " D:" + its(c->mpdist);
char zz[64]; sprintf(zz, " P%p", c); out += zz;
// out += " rv" + its(rosedist(c));
// if(rosemap.count(c))
// out += " rv " + its(rosemap[c]/8) + "." + its(rosemap[c]%8);
// out += " ai" + its(c->aitmp);
if(euclid) {
for(int i=0; i<4; i++) out += " " + its(getEuclidCdata(c->master)->val[i]);
out += " " + itsh(getBits(c));
}
else {
for(int i=0; i<4; i++) out += " " + its(getHeptagonCdata(c->master)->val[i]);
// out += " " + itsh(getHeptagonCdata(c->master)->bits);
out += " " + fts(tortoise::getScent(getBits(c)));
}
// itsh(getHeptagonCdata(c->master)->bits);
// out += " barleft: " + s0 + dnameof(c->barleft);
// out += " barright: " + s0 + dnameof(c->barright);
}
// char zz[64]; sprintf(zz, " P%p", c); out += zz;
/* whirlwind::calcdirs(c);
for(int i=0; i<whirlwind::qdirs; i++)
out += " " + its(whirlwind::dfrom[i]) + ":" + its(whirlwind::dto[i]); */
// out += " : " + its(whirlwinddir(c));
if(randomPatternsMode)
out += " " + describeRPM(c->land);
if(euclid && cheater) {
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;
// out += " MD"+its(c->mpdist);
// out += " H "+its(c->heat);
// if(c->type != 6) out += " Z"+its(c->master->zebraval);
// out += " H"+its(c->heat);
/* // Hive debug
if(c->land == laHive) {
out += " [" + its(c->tmp) + " H" + its(int(c->heat));
if(c->tmp >= 0 && c->tmp < size(buginfo) && buginfo[c->tmp].where == c) {
buginfo_t b(buginfo[c->tmp]);
for(int k=0; k<3; k++) out += ":" + its(b.dist[k]);
for(int k=0; k<3; k++)
for(int i=0; i<size(bugqueue[k]); i++)
if(bugqueue[k][i] == c->tmp)
out += " B"+its(k)+":"+its(i);
}
out += "]";
} */
if(c->wall &&
!((c->wall == waFloorA || c->wall == waFloorB || c->wall == waFloorC || c->wall == waFloorD) && c->item)) {
out += ", "; out += XLAT1(winf[c->wall].name);
if(c->wall == waRose) out += " (" + its(7-rosephase) + ")";
if((c->wall == waBigTree || c->wall == waSmallTree) && c->land != laDryForest)
help =
"Trees in this forest can be chopped down. Big trees take two turns to chop down.";
else if(c->wall != waSea && c->wall != waPalace)
if(!((c->wall == waCavefloor || c->wall == waCavewall) && c->land == laEmerald))
help = generateHelpForWall(c->wall);
}
if(isActivable(c)) out += XLAT(" (touch to activate)");
if(hasTimeout(c)) out += " [" + turnstring(c->wparam) + "]";
if(isReptile(c->wall))
out += " [" + turnstring((unsigned char) c->wparam) + "]";
if(c->monst) {
out += ", "; out += XLAT1(minf[c->monst].name);
if(hasHitpoints(c->monst))
out += " (" + its(c->hitpoints)+" HP)";
if(isMutantIvy(c))
out += " (" + its((c->stuntime - mutantphase) & 15) + "*)";
else if(c->stuntime)
out += " (" + its(c->stuntime) + "*)";
if(c->monst == moTortoise && tortoise::seek())
out += " " + tortoise::measure(tortoise::getb(c));
help = generateHelpForMonster(c->monst);
}
if(c->item && !itemHiddenFromSight(c)) {
out += ", ";
out += XLAT1(iinf[c->item].name);
if(c->item == itBarrow) out += " (x" + its(c->landparam) + ")";
if(c->item == itBabyTortoise && tortoise::seek())
out += " " + tortoise::measure(tortoise::babymap[c]);
if(!c->monst) help = generateHelpForItem(c->item);
}
if(isPlayerOn(c) && !shmup::on) out += XLAT(", you"), help = generateHelpForMonster(moPlayer);
shmup::addShmupHelp(out);
if(rosedist(c) == 1)
out += ", wave of scent (front)";
if(rosedist(c) == 2)
out += ", wave of scent (back)";
if(sword::at(c)) out += ", Energy Sword";
if(rosedist(c) || c->land == laRose || c->wall == waRose)
help += s0 + "\n\n" + rosedesc;
if(isWarped(c) && !isWarped(c->land))
out += ", warped";
if(isWarped(c))
help += s0 + "\n\n" + warpdesc;
}
/*
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 == 'f')
out = XLAT("Reduce the framerate limit to conserve CPU energy");
}
else if(cmode == emBasicConfig) {
if(getcstat == 'c')
out = XLAT("The axes help with keyboard movement");
else if(getcstat == 'g')
out = XLAT("Affects looks and grammar");
#ifndef MOBILE
else if(getcstat == 's')
out = XLAT("Config file: %1", conffile);
#endif
else out = "";
}
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(cmode == emChangeMode) {
if(getcstat == 'h')
out = XLAT("One wrong move and it is game over!");
}
*/
mouseovers = out;
#ifdef ROGUEVIZ
rogueviz::describe(c);
#endif
int col = linf[cwt.c->land].color;
if(cwt.c->land == laRedRock) col = 0xC00000;
#ifndef MOBILE
displayfr(vid.xres/2, vid.fsize, 2, vid.fsize, out, col, 8);
#endif
if(mousey < vid.fsize * 3/2) getcstat = SDLK_F1;
}
void showHelp() {
cmode2 = smHelp;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
if(help == "@") help = buildHelpText();
string help2;
if(help[0] == '@') {
int iv = help.find("\t");
int id = help.find("\n");
dialog::init(help.substr(iv+1, id-iv-1), atoi(help.c_str()+1), 120, 100);
dialog::addHelp(help.substr(id+1));
}
else {
dialog::init("help", forecolor, 120, 100);
dialog::addHelp(help);
}
if(help == buildHelpText()) dialog::addItem("credits", 'c');
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(sym == SDLK_F1 && help != "@")
help = "@";
else if(uni == 'c')
help = buildCredits();
else if(doexiton(sym, uni))
popScreen();
};
}
void gotoHelp(const string& h) {
help = h;
pushScreen(showHelp);
}

460
hud.cpp Normal file
View File

@ -0,0 +1,460 @@
purehookset hooks_stats;
int monsterclass(eMonster m) {
if(isFriendly(m) || m == moTortoise) return 1;
else if(isMonsterPart(m)) return 2;
else return 0;
}
int glyphclass(int i) {
if(i < ittypes) {
eItem it = eItem(i);
return itemclass(it) == IC_TREASURE ? 0 : 1;
}
else {
eMonster m = eMonster(i-ittypes);
return monsterclass(m) == 0 ? 2 : 3;
}
}
int subclass(int i) {
if(i < ittypes)
return itemclass(eItem(i));
else
return monsterclass(eMonster(i-ittypes));
}
#define GLYPH_MARKTODO 1
#define GLYPH_MARKOVER 2
#define GLYPH_LOCAL 4
#define GLYPH_IMPORTANT 8
#define GLYPH_NONUMBER 16
#define GLYPH_DEMON 32
#define GLYPH_RUNOUT 64
#define GLYPH_INPORTRAIT 128
#define GLYPH_LOCAL2 256
#define GLYPH_TARGET 512
#define GLYPH_INSQUARE 1024
eGlyphsortorder glyphsortorder;
int zero = 0;
int& ikmerge(int i) {
if(i < ittypes) return items[i];
else if(i == ittypes) return zero;
else return kills[i-ittypes];
}
const int glyphs = ittypes + motypes;
int gfirsttime[glyphs], glasttime[glyphs], gcopy[glyphs], ikland[glyphs];
int glyphorder[glyphs];
void updatesort() {
for(int i=0; i<glyphs; i++) {
if(ikmerge(i) && gfirsttime[i] == 0)
gfirsttime[i] = ticks;
if(ikmerge(i) != gcopy[i])
gcopy[i] = items[i], glasttime[i] = ticks;
}
}
void preparesort() {
for(int i=0; i<glyphs; i++) glyphorder[i] = i;
for(int i=0; i<LAND_OVERX; i++) {
eLand l = land_over[i];
ikland[treasureType(l)] = i+1;
for(int mi=0; mi<motypes; mi++)
if(isNative(l, eMonster(mi)))
ikland[mi+ittypes] = i+1;
}
glyphsortorder = gsoLand; updatesort();
glyphsortorder = gsoFirstTop;
}
int glyphsortkey = 0;
int glyphcorner(int i) {
if(i < ittypes)
return itemclass(eItem(i)) == IC_ORB ? 2 : 0;
else
return 1;
}
bool glyphsort(int i, int j) {
if(subclass(i) != subclass(j))
return subclass(i) < subclass(j);
if(glyphsortorder == gsoFirstTop)
return gfirsttime[i] < gfirsttime[j];
if(glyphsortorder == gsoFirstBottom)
return gfirsttime[i] > gfirsttime[j];
if(glyphsortorder == gsoLastTop)
return glasttime[i] > glasttime[j];
if(glyphsortorder == gsoLastBottom)
return glasttime[i] < glasttime[j];
if(glyphsortorder == gsoValue)
return ikmerge(i) > ikmerge(j);
if(glyphsortorder == gsoLand)
return ikland[i] < ikland[j];
return 0;
}
int glyphflags(int gid) {
int f = 0;
if(gid < ittypes) {
eItem i = eItem(gid);
if(itemclass(i) == IC_NAI) f |= GLYPH_NONUMBER;
if(isElementalShard(i)) {
f |= GLYPH_LOCAL | GLYPH_INSQUARE;
if(i == localshardof(cwt.c->land)) f |= GLYPH_LOCAL2;
}
if(i == treasureType(cwt.c->land))
f |= GLYPH_LOCAL | GLYPH_LOCAL2 | GLYPH_IMPORTANT | GLYPH_INSQUARE;
if(i == itHolyGrail) {
if(items[i] >= 3) f |= GLYPH_MARKOVER;
}
else if(itemclass(i) == IC_TREASURE) {
if(items[i] >= 25 && items[i] < 100) f |= GLYPH_MARKOVER;
else if(items[i] < 10) f |= GLYPH_MARKTODO;
}
else {
f |= GLYPH_IMPORTANT | GLYPH_INSQUARE;
if(itemclass(i) == IC_ORB && items[i] < 10) f |= GLYPH_RUNOUT;
}
if(i == orbToTarget) f |= GLYPH_TARGET;
f |= GLYPH_INPORTRAIT;
}
else {
eMonster m = eMonster(gid-ittypes);
if(m == moLesser) f |= GLYPH_IMPORTANT | GLYPH_DEMON | GLYPH_INPORTRAIT | GLYPH_INSQUARE;
int isnat = isNative(cwt.c->land, m);
if(isnat) f |= GLYPH_LOCAL | GLYPH_IMPORTANT | GLYPH_INPORTRAIT | GLYPH_INSQUARE;
if(isnat == 2) f |= GLYPH_LOCAL2;
if(m == monsterToSummon) f |= GLYPH_TARGET;
}
return f;
}
bool graphglyph() {
return vid.graphglyph == 2 || (vid.graphglyph == 1 && vid.monmode);
}
bool displayglyph(int cx, int cy, int buttonsize, char glyph, int color, int qty, int flags, int id) {
bool b =
mousex >= cx && mousex < cx+buttonsize && mousey >= cy-buttonsize/2 && mousey <= cy-buttonsize/2+buttonsize;
int glsize = buttonsize;
if(glyph == '%' || glyph == 'M' || glyph == 'W') glsize = glsize*4/5;
if(graphglyph()) {
initquickqueue();
if(id >= ittypes) {
eMonster m = eMonster(id - ittypes);
int bsize = buttonsize;
if(m == moKrakenH) bsize /= 3;
if(m == moKrakenT || m == moDragonTail) bsize /= 2;
if(m == moSlime) bsize = (2*bsize+1)/3;
transmatrix V = atscreenpos(cx+buttonsize/2, cy, bsize);
int mcol = color;
mcol -= (color & 0xFCFCFC) >> 2;
drawMonsterType(m, NULL, V, mcol, 0);
}
else {
eItem it = eItem(id);
int bsize = buttonsize;
if(glyph =='*') bsize *= 2;
if(glyph == '$') bsize = (bsize*5+2)/3;
if(glyph == 'o') bsize = (bsize*3+1)/2;
if(glyph == 't') bsize = bsize*5/2;
if(it == itWarning) bsize *= 2;
if(it == itBombEgg || it == itTrollEgg || it == itDodeca) bsize = bsize*3/2;
transmatrix V = atscreenpos(cx+buttonsize/2, cy, bsize);
int icol = color;
icol -= (color & 0xFCFCFC) >> 2;
int ic = itemclass(it);
drawItemType(it, NULL, V, icol, (ic == IC_ORB || ic == IC_NAI) ? ticks*2 : ((glyph == 't' && qty%5) || it == itOrbYendor) ? ticks/2 : 0, false);
}
quickqueue();
}
else if(glyph == '*')
displaychr(cx + buttonsize/2, cy+buttonsize/4, 0, glsize*3/2, glyph, darkenedby(color, b?0:1));
else
displaychr(cx + buttonsize/2, cy, 0, glsize, glyph, darkenedby(color, b?0:1));
string fl = "";
string str = its(qty);
if(flags & GLYPH_TARGET) fl += "!";
if(flags & GLYPH_LOCAL2) fl += "+";
else if(flags & GLYPH_LOCAL) fl += "-";
if(flags & GLYPH_DEMON) fl += "X";
if(flags & GLYPH_MARKOVER) str += "!";
if(fl != "")
displaystr(cx + buttonsize, cy-buttonsize/2 + buttonsize/4, 0, buttonsize/2, fl, darkenedby(color, 0), 16);
if(flags & GLYPH_NONUMBER) str = "";
int bsize =
(qty < 10 && (flags & (GLYPH_MARKTODO | GLYPH_RUNOUT))) ? buttonsize*3/4 :
qty < 100 ? buttonsize / 2 :
buttonsize / 3;
if(str != "")
displayfr(cx + buttonsize, cy + buttonsize/2 - bsize/2, 1, bsize, str, color, 16);
return b;
}
void displayglyph2(int cx, int cy, int buttonsize, int i) {
char glyph = i < ittypes ? iinf[i].glyph : minf[i-ittypes].glyph;
int color = i < ittypes ? iinf[i].color : minf[i-ittypes].color;
int imp = glyphflags(i);
if(displayglyph(cx, cy, buttonsize, glyph, color, ikmerge(i), imp, i)) {
instat = true;
getcstat = SDLK_F1;
if(i < ittypes) {
eItem it = eItem(i);
int t = itemclass(it);
if(t == IC_TREASURE)
mouseovers = XLAT("treasure collected: %1", it);
if(t == IC_OTHER)
mouseovers = XLAT("objects found: %1", it);
if(t == IC_NAI)
mouseovers = XLAT("%1", it);
if(t == IC_ORB)
mouseovers = XLAT("orb power: %1", eItem(i));
if(it == itGreenStone) {
mouseovers += XLAT(" (click to drop)");
getcstat = 'g';
}
if(imp & GLYPH_LOCAL) mouseovers += XLAT(" (local treasure)");
help = generateHelpForItem(it);
}
else {
eMonster m = eMonster(i-ittypes);
if(isMonsterPart(m))
mouseovers = s0 + XLAT("parts destroyed: %1", m);
else if(isFriendly(m) && isNonliving(m))
mouseovers = s0 + XLAT("friends destroyed: %1", m);
else if(isFriendly(m))
mouseovers = s0 + XLAT("friends killed: %1", m);
else if(isNonliving(m))
mouseovers = s0 + XLAT("monsters destroyed: %1", m);
else if(m == moTortoise)
mouseovers = s0 + XLAT("animals killed: %1", m);
else
mouseovers = s0 + XLAT("monsters killed: %1", m);
if(imp & GLYPH_LOCAL2) mouseovers += XLAT(" (killing increases treasure spawn)");
else if(imp & GLYPH_LOCAL) mouseovers += XLAT(" (appears here)");
help = generateHelpForMonster(m);
}
}
}
bool nohud, nomenukey;
hookset<bool()> *hooks_prestats;
void drawStats() {
callhandlers(false, hooks_prestats);
#ifdef ROGUEVIZ
if(rogueviz::on || nohud) return;
#endif
if(viewdists && sidescreen) {
distcolors[0] = forecolor;
dialog::init("");
int qty[64];
vector<cell*>& ac = currentmap->allcells();
for(int i=0; i<64; i++) qty[i] = 0;
for(int i=0; i<size(ac); i++) {
int d = celldistance(ac[i], cwt.c);
if(d >= 0 && d < 64) qty[d]++;
}
if(geometry == gNormal)
for(int i=purehepta?6:8; i<=15; i++)
qty[i] =
purehepta ?
3*qty[i-1] - qty[i-2]
: qty[i-1] + qty[i-2] + qty[i-3] - qty[i-4];
if(geometry == gEuclid)
for(int i=8; i<=15; i++) qty[i] = 6*i;
for(int i=0; i<64; i++) if(qty[i])
dialog::addInfo(its(qty[i]), distcolors[i&7]);
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ᵈ", 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ᵈ", forecolor);
}
if(geometry == gEuclid) {
dialog::addBreak(300);
dialog::addInfo("a(d) = 6d", forecolor);
}
dialog::display();
}
if(sidescreen) return;
if(vid.xres > vid.yres * 85/100 && vid.yres > vid.xres * 85/100) {
int bycorner[4];
for(int u=0; u<4; u++) bycorner[u] = 0;
for(int i=0; i<glyphs; i++) if(ikmerge(i) && (glyphflags(i) & GLYPH_INSQUARE))
bycorner[glyphcorner(i)]++;
updatesort();
stable_sort(glyphorder, glyphorder+glyphs, glyphsort);
int rad = min(vid.xres, vid.yres) / 2;
for(int cor=0; cor<3; cor++) {
for(int a=5; a<41; a++) {
int s = min(vid.xres, vid.yres) / a;
int spots = 0;
for(int u=vid.fsize; u<vid.xres/2-s; u += s)
for(int v=vid.fsize; v<vid.yres/2-s; v += s)
if(hypot(vid.xres/2-u-s, vid.yres/2-v-s) > rad) {
spots++;
}
if(spots >= bycorner[cor] && spots >= 3) {
int next = 0;
vector<int> glyphstoshow;
for(int i=0; i<glyphs; i++) {
int g = glyphorder[i];
if(ikmerge(g) && (glyphflags(g) & GLYPH_INSQUARE) && glyphcorner(g) == cor)
glyphstoshow.push_back(g);
}
for(int u=vid.fsize; u<vid.xres/2-s; u += s)
for(int v=vid.fsize; v<vid.yres/2-s; v += s)
if(hypot(vid.xres/2-u-s, vid.yres/2-v-s) > rad) {
if(next >= size(glyphstoshow)) break;
int cx = u;
int cy = v + s/2;
if(cor&1) cx = vid.xres-1-s-cx;
if(cor&2) cy = vid.yres-1-cy;
displayglyph2(cx, cy, s, glyphstoshow[next++]);
}
break;
}
}
}
return;
}
instat = false;
bool portrait = vid.xres < vid.yres;
int colspace = portrait ? (vid.yres - vid.xres - vid.fsize*3) : (vid.xres - vid.yres - 16) / 2;
int rowspace = portrait ? vid.xres - 16 : vid.yres - vid.fsize * 4;
int colid[4], rowid[4];
int maxbyclass[4];
for(int z=0; z<4; z++) maxbyclass[z] = 0;
for(int i=0; i<glyphs; i++) if(ikmerge(i))
if(!portrait || (glyphflags(i) | GLYPH_INPORTRAIT))
maxbyclass[glyphclass(i)]++;
int buttonsize;
int columns, rows;
bool imponly = false;
int minsize = vid.fsize * (portrait ? 4 : 2);
rows = 0;
while((buttonsize = minsize - vid.killreduction)) {
columns = colspace / buttonsize;
rows = rowspace / buttonsize;
int coltaken = 0;
for(int z=0; z<4; z++) {
if(z == 2 && !portrait) {
if(coltaken > columns) { vid.killreduction++; continue; }
coltaken = 0;
}
colid[z] = coltaken, rowid[z] = 0,
coltaken += (maxbyclass[z] + rows-1) / rows;
}
if(coltaken > columns) { vid.killreduction++; continue; }
break;
}
if(buttonsize <= vid.fsize*3/4) {
imponly = true; buttonsize = minsize;
rows = rowspace / buttonsize; if(!rows) return;
colid[0] = 0; colid[2] = portrait ? 1 : 0;
}
updatesort();
stable_sort(glyphorder, glyphorder+glyphs, glyphsort);
for(int i0=0; i0<glyphs; i0++) {
int i = glyphorder[i0];
if(!ikmerge(i)) continue;
int z = glyphclass(i);
int imp = glyphflags(i);
if(imponly) { z &=~1; if(!(imp & GLYPH_IMPORTANT)) continue; }
int cx, cy;
if(portrait)
cx = 8 + buttonsize * rowid[z], cy = vid.fsize*2 + buttonsize * (colid[z]) + buttonsize/2;
else
cx = 8 + buttonsize * (colid[z]), cy = vid.fsize * 3 + buttonsize * rowid[z];
if(!portrait && z < 2) cx = vid.xres - cx - buttonsize;
rowid[z]++; if(rowid[z] >= rows) rowid[z] = 0, colid[z]++;
displayglyph2(cx, cy, buttonsize, i);
}
string s0;
if(displayButtonS(vid.xres - 8, vid.fsize, "score: " + its(gold()), forecolor, 16, vid.fsize)) {
mouseovers = XLAT("Your total wealth"),
instat = true,
getcstat = SDLK_F1,
help = helptitle(XLAT("Your total wealth"), 0xFFD500) +
XLAT(
"The total value of the treasure you have collected.\n\n"
"Every world type contains a specific type of treasure, worth 1 $$$; "
"your goal is to collect as much treasure as possible, but every treasure you find "
"causes more enemies to hunt you in its native land.\n\n"
"Orbs of Yendor are worth 50 $$$ each.\n\n"
);
}
if(displayButtonS(8, vid.fsize, "kills: " + its(tkills()), forecolor, 0, vid.fsize)) {
instat = true,
getcstat = SDLK_F1,
mouseovers = XLAT("Your total kills")+": " + its(tkills()),
help = helptitle(XLAT("Your total kills") + ": " + its(tkills()), 0x404040) +
XLAT(
"In most lands, more treasures are generated with each enemy native to this land you kill. "
"Moreover, 100 kills is a requirement to enter the Graveyard and the Hive.\n\n"
"Friendly creatures and parts of monsters (such as the Ivy) do appear in the list, "
"but are not counted in the total kill count.");
}
if(displayButtonS(4, vid.yres - 4 - vid.fsize/2, s0+VER+ " fps: " + its(calcfps()), 0x202020, 0, vid.fsize/2)) {
mouseovers = XLAT("frames per second"),
getcstat = SDLK_F1,
instat = true,
help =
helptitle(XLAT("frames per second"), 0xFF4040) +
XLAT(
"The higher the number, the smoother the animations in the game. "
"If you find that animations are not smooth enough, you can try "
"to change the options "
) +
#ifdef IOS
XLAT(
"(in the MENU). You can reduce the sight range, this should make "
"the animations smoother.");
#else
XLAT(
"(press v) and change the wall/monster mode to ASCII, or change "
"the resolution.");
#endif
}
achievement_display();
callhooks(hooks_stats);
}

View File

@ -387,11 +387,11 @@ else if(args()[0] == '-' && args()[1] == x && args()[2] == '0') { if(curphase ==
return 0;
}
hookset<bool(int argc, char** argv)> *hooks_main;
#ifndef NOMAIN
int main(int argc, char **argv) {
#ifdef EXTRA_MAIN
if(extra::main(argc, argv)) return 0;
#endif
if(callhandlers(false, hooks_main, argc, argv)) return 0;
#ifndef WEB
#ifdef LINUX
moreStack();
@ -409,25 +409,25 @@ int main(int argc, char **argv) {
#endif
#ifdef USE_COMMANDLINE
purehookset hooks_config;
hookset<int()> *hooks_args;
namespace arg {
int argc; char **argv;
auto ah = addHook(hooks_args, 0, readCommon);
void read(int phase) {
curphase = phase;
#ifdef EXTRA_CONFIG
extra::config();
#endif
callhooks(hooks_config);
while(argc) {
int r;
r = readCommon(); 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; }
#endif
for(auto& h: *hooks_args) {
int r = h.second(); if(r == 2) return; if(r == 0) { lshift(); goto cont; }
}
printf("Unknown option: %s\n", args());
exit(3);
cont: ;
}
}
}

227
hyper.h
View File

@ -151,6 +151,7 @@ void loadcs(FILE *f, charstyle& cs, int vernum);
namespace multi {
extern bool shmupcfg;
void recall();
extern cell *origpos[MAXPLAYER], *origtarget[MAXPLAYER];
extern int players;
@ -178,7 +179,11 @@ namespace multi {
char hataction[MAXJOY][MAXHAT][4];
int deadzoneval[MAXJOY][MAXAXE];
};
void saveConfig(FILE *f);
void loadConfig(FILE *f);
void initConfig();
charstyle scs[MAXPLAYER];
bool playerActive(int p);
@ -186,9 +191,11 @@ namespace multi {
cell *multiPlayerTarget(int i);
void checklastmove();
void leaveGame(int i);
void showShmupConfig();
}
namespace shmup {
using namespace multi;
void recall();
extern bool on;
extern bool safety;
@ -217,6 +224,7 @@ namespace shmup {
void virtualRebase(cell*& base, transmatrix& at, bool tohex);
void virtualRebase(shmup::monster *m, bool tohex);
void fixStorage();
void addShmupHelp(string& out);
}
// graph
@ -228,8 +236,6 @@ void showMissionScreen();
void restartGraph();
void resetmusic();
void cleargraphmemory();
void drawFlash(cell* c);
void drawBigFlash(cell* c);
void drawParticle(cell *c, int col, int maxspeed = 100);
@ -319,6 +325,7 @@ struct videopar {
int flashtime;
int wallmode, monmode, axes;
bool revcontrol;
// for OpenGL
float scrdist;
@ -331,6 +338,7 @@ struct videopar {
#define AA_POLY 8
#define AA_LINEWIDTH 16
#define AA_FONT 32
#define AA_MULTI 64
ld linewidth;
int joyvalue, joyvalue2, joypanthreshold;
@ -351,30 +359,11 @@ struct videopar {
extern videopar vid;
enum emtype {emNormal, emHelp,
emMenu,
emBasicConfig, emGraphConfig, emDisplayMode,
emChangeMode, emCustomizeChar,
emQuit, emDraw, emScores, emPickEuclidean,
emPickScores,
emShmupConfig,
emMapEditor,
emPatternPicker,
emOverview,
emNetgen,
emYendor, emTactic, emRugConfig,
emConformal,
emProgress,
emCheatMenu, emLeader,
emJoyConfig,
emColor, emNumber,
em3D, emRogueviz,
emLinepattern,
emPeace, emInventory,
emSlideshows
};
extern emtype cmode, lastmode;
extern vector< function<void()> > screens;
template<class T> void pushScreen(T& x) { screens.push_back(x); }
inline void popScreen() { screens.pop_back(); }
inline void popScreenAll() { while(size(screens)>1) popScreen(); }
extern transmatrix View; // current rotation, relative to viewctr
extern transmatrix cwtV; // player-relative view
@ -390,26 +379,36 @@ namespace mapeditor {
extern char whichCanvas;
extern int displaycodes;
int generateCanvas(cell *c);
void clearModelCells();
void applyModelcell(cell *c);
int realpattern(cell *c);
int patterndir(cell *c, char w = whichPattern);
int subpattern(cell *c);
extern cell *drawcell;
void initdraw(cell *c);
void showMapEditor();
void showDrawEditor();
}
#ifndef NORUG
namespace rug {
extern bool rugged;
extern bool renderonce;
extern bool rendernogl;
extern int texturesize;
extern double scale;
void show();
void init();
void close();
void actDraw();
void select();
void buildVertexInfo(cell *c, transmatrix V);
}
#endif
#define HASLINEVIEW
#include <complex>
typedef complex<ld> cld;
namespace conformal {
extern bool on;
extern vector<pair<cell*, eMonster> > killhistory;
@ -417,10 +416,15 @@ namespace conformal {
extern vector<cell*> movehistory;
extern bool includeHistory;
extern int rotation;
extern bool autoband;
extern bool autobandhistory;
extern bool dospiral;
extern ld lvspeed;
extern int bandsegment;
extern int bandhalf;
void create();
void clear();
void handleKey();
void show();
void apply();
void movetophase();
@ -428,11 +432,16 @@ namespace conformal {
extern vector<shmup::monster*> v;
extern double phase;
void applyIB();
}
namespace polygonal {
static const int MSI = 120;
extern int SI;
extern ld STAR;
extern int deg;
extern complex<ld> coef[MSI];
extern int maxcoef, coefid;
void solve();
pair<ld, ld> compute(ld x, ld y);
}
@ -805,12 +814,15 @@ namespace dialog {
int position;
};
extern vector<item> items;
item& lastItem();
extern unsigned int *palette;
void addSelItem(string body, string value, int key);
void addBoolItem(string body, bool value, int key);
void addColorItem(string body, int value, int key);
void openColorDialog(int& col, unsigned int *pal);
void openColorDialog(int& col, unsigned int *pal = palette);
void addHelp(string body);
void addInfo(string body, int color = 0xC0C0C0);
void addItem(string body, int key);
@ -821,9 +833,6 @@ namespace dialog {
void init(string title, int color = 0xE8E8E8, int scale = 150, int brk = 60);
void display();
void drawColorDialog(int color);
int handleKeyColor(int sym, int uni, int& color);
void editNumber(ld& x, ld vmin, ld vmax, ld step, ld dft, string title, string help);
void editNumber(int& x, int vmin, int vmax, int step, int dft, string title, string help);
void scaleLog();
@ -1002,6 +1011,7 @@ extern eGlyphsortorder glyphsortorder;
namespace rogueviz {
extern bool on;
string describe(shmup::monster *m);
void describe(cell *c);
void activate(shmup::monster *m);
void drawVertex(const transmatrix &V, cell *c, shmup::monster *m);
bool virt(shmup::monster *m);
@ -1011,6 +1021,8 @@ namespace rogueviz {
int readArgs();
void close();
void mark(cell *c);
void showMenu();
string makehelp();
}
#endif
@ -1149,11 +1161,10 @@ namespace tour {
extern string slidecommand;
extern int currentslide;
bool handleKeyTour(int sym, int uni);
enum presmode {
pmStartAll = 0,
pmStart = 1, pmFrame = 2, pmStop = 3, pmKey = 4, pmRestart = 5,
pmAfterFrame = 6,
pmGeometry = 11, pmGeometryReset = 13, pmGeometryStart = 15
};
@ -1192,7 +1203,6 @@ namespace tour {
namespace ss {
void showMenu();
void handleKey(int sym, int uni);
void list(slide*);
}
@ -1218,6 +1228,8 @@ extern bool dronemode;
extern ld whatever;
enum screenmode { smMenu, smNormal, smMission, smHelp, smMap, smDraw, smNumber, smShmupConfig, smOverview };
namespace linepatterns {
enum ePattern {
@ -1242,6 +1254,7 @@ namespace linepatterns {
void clearAll();
void setColor(ePattern id, int col);
void drawAll();
void showMenu();
};
transmatrix ddspin(cell *c, int d, int bonus = 0);
@ -1290,3 +1303,145 @@ bool graphglyph();
extern bool hiliteclick;
extern int antialiaslines;
extern int ringcolor;
#include <functional>
template<class T> class hookset : public map<int, function<T>> {};
typedef hookset<void()> *purehookset;
template<class T, class U> int addHook(hookset<T>*& m, int prio, const U& hook) {
if(!m) m = new hookset<T> ();
(*m)[prio] = hook;
return 0;
}
extern purehookset hooks_frame, hooks_stats, clearmemory;
template<class T, class... U> void callhooks(hookset<T> *h, U... args) {
if(h) for(auto& p: *h) p.second(args...);
}
template<class T, class V, class... U> V callhandlers(V zero, hookset<T> *h, U... args) {
if(h) for(auto& p: *h) {
auto z = p.second(args...);
if(z != zero) return z;
}
return zero;
}
extern hookset<bool(int sym, int uni)> *hooks_handleKey;
extern hookset<void(cell *c, const transmatrix& V)> *hooks_drawcell;
extern hookset<bool(int argc, char** argv)> *hooks_main;
extern hookset<int()> *hooks_args;
extern hookset<eLand(eLand)> *hooks_nextland;
// hooks to extend HyperRogue with an external program
// start compilation from another file which defines EXTRA_..., includes
// hyper.cpp, then defines the necessary functions
extern ld shiftmul;
void initcs(charstyle &cs);
charstyle& getcs();
struct msginfo {
int stamp;
char flashout;
char spamtype;
int quantity;
string msg;
};
extern vector<msginfo> msgs;
void flashMessages();
extern int lightat, safetyat;
int watercolor(int phase);
bool doHighlight();
string buildHelpText();
string buildCredits();
void setAppropriateOverview();
bool quitsaves();
extern bool sidescreen;
static const char* COLORBAR = "###";
int textwidth(int siz, const string &str);
#define GLERR(call) glError(call, __FILE__, __LINE__)
extern bool gtouched, mousepressed, mousemoved, actonrelease;
extern bool inslider;
#ifdef ROGUEVIZ
#define DOSHMUP (shmup::on || rogueviz::on)
#else
#define DOSHMUP shmup::on
#endif
extern bool outoffocus;
extern int frames;
extern transmatrix playerV;
extern bool didsomething;
extern void drawStats();
extern int calcfps();
extern int distcolors[8];
extern eItem orbToTarget;
extern eMonster monsterToSummon;
void panning(hyperpoint hf, hyperpoint ht);
extern transmatrix sphereflip;
void initConfig();
void loadConfig();
extern bool auraNOGL;
#ifndef NOSDL
extern void initJoysticks();
extern int joyx, joyy, panjoyx, panjoyy;
extern bool autojoy;
extern movedir joydir;
extern SDL_Joystick* sticks[8];
extern int numsticks;
void closeJoysticks();
#endif
void preparesort();
#ifdef MOBILE
#define SHMUPTITLE "shoot'em up mode"
#else
#define SHMUPTITLE "shoot'em up and multiplayer"
#endif
bool dodrawcell(cell *c);
void drawcell(cell *c, transmatrix V, int spinv, bool mirrored);
extern double downspin;
extern int frameid;
extern bool leftclick;
void clearMemory();
extern function <void(int sym, int uni)> keyhandler;
void gmodekeys(int sym, int uni);
void switchGL();
void switchFullscreen();
extern screenmode cmode2;
void gotoHelp(const string& h);
void showCustomizeChar();
void showScores();
void showPickScores();
void showCheatMenu();
void showDisplayMode();
void showChangeMode();
void showEuclideanMenu();
void show3D();
void gameoverscreen();
void showJoyConfig();
void gamescreen(int darken);
void showMission();
void handleKeyQuit(int sym, int uni);
void handlePanning(int sym, int uni);

View File

@ -474,3 +474,5 @@ transmatrix mzscale(const transmatrix& t, double fac) {
return res;
}
transmatrix pushone() { return euclid ? eupush(1, 0) : xpush(sphere?.5 : 1); }

561
hypgraph.cpp Normal file
View File

@ -0,0 +1,561 @@
ld ghx, ghy, ghgx, ghgy;
hyperpoint ghpm = C0;
void ghcheck(hyperpoint &ret, const hyperpoint &H) {
if(hypot(ret[0]-ghx, ret[1]-ghy) < hypot(ghgx-ghx, ghgy-ghy)) {
ghpm = H; ghgx = ret[0]; ghgy = ret[1];
}
}
void camrotate(ld& hx, ld& hy) {
ld cam = vid.camera_angle * M_PI / 180;
GLfloat cc = cos(cam);
GLfloat ss = sin(cam);
ld ux = hx, uy = hy * cc + ss, uz = cc - ss * hy;
hx = ux / uz, hy = uy / uz;
}
hyperpoint gethyper(ld x, ld y) {
ld hx = (x - vid.xcenter) / vid.radius;
ld hy = (y - vid.ycenter) / vid.radius;
if(pmodel) {
ghx = hx, ghy = hy;
return ghpm;
}
if(euclid)
return hpxy(hx * (EUCSCALE + vid.alphax), hy * (EUCSCALE + vid.alphax));
if(vid.camera_angle) camrotate(hx, hy);
ld hr = hx*hx+hy*hy;
if(hr > .9999 && !sphere) return Hypc;
// hz*hz-(hx/(hz+alpha))^2 - (hy/(hz+alpha))^2 =
// hz*hz-hr*(hz+alpha)^2 == 1
// hz*hz - hr*hr*hz*Hz
ld A, B, C;
ld curv = sphere ? 1 : -1;
A = 1+curv*hr;
B = 2*hr*vid.alphax*-curv;
C = 1 - curv*hr*vid.alphax*vid.alphax;
// Az^2 - Bz = C
B /= A; C /= A;
// z^2 - Bz = C
// z^2 - Bz + (B^2/4) = C + (B^2/4)
// z = (B/2) + sqrt(C + B^2/4)
ld rootsign = 1;
if(sphere && vid.alphax > 1) rootsign = -1;
ld hz = B / 2 + rootsign * sqrt(C + B*B/4);
hyperpoint H;
H[0] = hx * (hz+vid.alphax);
H[1] = hy * (hz+vid.alphax);
H[2] = hz;
return H;
}
void ballmodel(hyperpoint& ret, double alpha, double d, double zl) {
hyperpoint H = ypush(geom3::camera) * xpush(d) * ypush(zl) * C0;
ld tzh = vid.ballproj + H[2];
ld ax = H[0] / tzh;
ld ay = H[1] / tzh;
ld ball = vid.ballangle * M_PI / 180;
ld ca = cos(alpha), sa = sin(alpha);
ld cb = cos(ball), sb = sin(ball);
ret[0] = ax * ca;
ret[1] = ay * cb + ax * sa * sb;
ret[2] = - ax * sa * cb - ay * sb;
}
void applymodel(hyperpoint H, hyperpoint& ret) {
ld tz = euclid ? (EUCSCALE+vid.alphax) : vid.alphax+H[2];
if(tz < 1e-3 && tz > -1e-3) tz = 1000;
if(pmodel == mdUnchanged) {
for(int i=0; i<3; i++) ret[i] = H[i] / vid.radius;
return;
}
if(pmodel == mdBall) {
ld zlev = zlevel(H);
using namespace hyperpoint_vec;
H = H / zlev;
ld zl = geom3::depth-geom3::factor_to_lev(zlev);
double alpha = atan2(H[1], H[0]);
double d = hdist0(H);
ballmodel(ret, alpha, d, zl);
ghcheck(ret,H);
return;
}
if(pmodel == mdHyperboloid) {
ld ball = vid.ballangle * M_PI / 180;
ld cb = cos(ball), sb = sin(ball);
ret[0] = H[0] / 3;
ret[1] = (1 - H[2]) / 3 * cb + H[1] / 3 * sb;
ret[2] = H[1] / 3 * cb - (1 - H[2]) / 3 * sb;
ghcheck(ret,H);
return;
}
if(pmodel == mdDisk) {
if(!vid.camera_angle) {
ret[0] = H[0] / tz;
ret[1] = H[1] / tz;
ret[2] = (1 - vid.beta / tz);
}
else {
ld tx = H[0];
ld ty = H[1];
ld cam = vid.camera_angle * M_PI / 180;
GLfloat cc = cos(cam);
GLfloat ss = sin(cam);
ld ux = tx, uy = ty * cc - ss * tz, uz = tz * cc + ss * ty;
ret[0] = ux / uz;
ret[1] = uy / uz;
ret[2] = 1 - vid.beta / uz;
}
return;
}
ld zlev = 1;
if(wmspatial || mmspatial) {
zlev = zlevel(H);
using namespace hyperpoint_vec;
H = H / zlev;
}
if(pmodel == mdEquidistant || pmodel == mdEquiarea) {
ld rad = sqrt(H[0] * H[0] + H[1] * H[1]);
ld d = hdist0(H);
if(pmodel == 6 && sphere)
d = sqrt(2*(1 - cos(d))) * 1.25; // /1.5 to make it fit on the screen better
else if(pmodel == 6)
d = sqrt(2*(cosh(d) - 1)) / 1.5;
ret[0] = d * H[0] / rad / 4;
ret[1] = d * H[1] / rad / 4;
ret[2] = 0;
if(zlev != 1 && vid.goteyes)
ret[2] = geom3::factor_to_lev(zlev);
ghcheck(ret,H);
return;
}
tz = H[2]+vid.alphax;
if(pmodel == mdPolygonal || pmodel == mdPolynomial) {
pair<long double, long double> p = polygonal::compute(H[0]/tz, H[1]/tz);
ret[0] = p.first;
ret[1] = p.second;
ret[2] = 0;
ghcheck(ret,H);
return;
}
// Poincare to half-plane
ld x0, y0;
x0 = H[0] / tz;
y0 = H[1] / tz;
y0 += 1;
double rad = x0*x0 + y0*y0;
y0 /= rad;
x0 /= rad;
y0 -= .5;
if(pmodel == mdHalfplane) {
ret[0] = x0;
if(wmspatial || mmspatial) y0 *= zlev;
ret[1] = 1 - y0;
ret[2] = 0;
if(zlev != 1 && vid.goteyes)
ret[2] = y0 * geom3::factor_to_lev(zlev);
ghcheck(ret,H);
return;
}
// center
x0 *= 2; y0 *= 2;
// half-plane to band
double tau = (log((x0+1)*(x0+1) + y0*y0) - log((x0-1)*(x0-1) + y0*y0)) / 2;
double u=(1-x0*x0-y0*y0);
u = (1 - x0*x0 - y0*y0 + sqrt(u*u+4*y0*y0));
double yv = 2*y0 / u;
double sigma = 2 * atan(yv * zlev) - M_PI/2;
x0 = tau; y0 = sigma;
/* if(zlev != 1) {
double alp = (y0 * y0) / (1-y0*y0);
double gx = alp + sqrt(alp*alp-1);
double gy = y0 * (gx+1);
double yr = zlev * gy / (zlev * gx + 1);
printf("zlev = %10.5lf y0 = %20.10lf yr = %20.10lf\n", double(zlev), (double)y0, yr);
y0 = yr;
} */
ret[0] = x0/M_PI*2;
ret[1] = -y0/M_PI*2;
ret[2] = 0;
if(zlev != 1 && vid.goteyes)
ret[2] = geom3::factor_to_lev(zlev) / (1 + yv * yv);
ghcheck(ret,H);
}
// game-related graphics
transmatrix View; // current rotation, relative to viewctr
transmatrix cwtV; // player-relative view
transmatrix sphereflip; // on the sphere, flip
heptspin viewctr; // heptagon and rotation where the view is centered at
bool playerfound; // has player been found in the last drawing?
double eurad = 0.52;
double q3 = sqrt(double(3));
bool outofmap(hyperpoint h) {
if(euclid)
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;
}
hyperpoint mirrorif(const hyperpoint& V, bool b) {
if(b) return Mirror*V;
else return V;
}
// -1 if away, 0 if not away
int away(const transmatrix& V2) {
return intval(C0, V2 * xpush0(1)) > intval(C0, tC0(V2));
}
/* double zgrad(double f1, double f2, int nom, int den) {
using namespace geom3;
ld fo1 = factor_to_lev(f1);
ld fo2 = factor_to_lev(f2);
return lev_to_factor(fo1 + (fo2-fo1) * nom / den);
} */
double zgrad0(double l1, double l2, int nom, int den) {
using namespace geom3;
return lev_to_factor(l1 + (l2-l1) * nom / den);
}
bool behindsphere(const hyperpoint& h) {
if(!sphere) return false;
if(vid.alpha > 1) {
if(h[2] > -1/vid.alpha) return true;
}
if(vid.alpha <= 1) {
if(h[2] < -.8) return true;
}
return false;
}
bool behindsphere(const transmatrix& V) {
return behindsphere(tC0(V));
}
bool confusingGeometry() {
return elliptic || quotient == 1 || torus;
}
void drawrec(const heptspin& hs, int lev, hstate s, const transmatrix& V) {
// shmup::calc_relative_matrix(cwt.c, hs.h);
cell *c = hs.h->c7;
transmatrix V10;
const transmatrix& V1 = hs.mirrored ? (V10 = V * Mirror) : V;
if(dodrawcell(c)) {
reclevel = maxreclevel - lev;
drawcell(c, (hs.spin || purehepta) ? V1 * spin(hs.spin*2*M_PI/S7 + (purehepta ? M_PI:0)) : V1, hs.spin,
hs.mirrored);
}
if(lev <= 0) return;
if(!purehepta) for(int d=0; d<S7; d++) {
int ds = fixrot(hs.spin + d);
reclevel = maxreclevel - lev + 1;
// createMov(c, ds);
if(c->mov[ds] && c->spn(ds) == 0 && dodrawcell(c->mov[ds])) {
drawcell(c->mov[ds], V1 * hexmove[d], 0, hs.mirrored ^ c->mirror(ds));
}
}
if(lev <= 1) return;
for(int d=0; d<S7; d++) {
hstate s2 = transition(s, d);
if(s2 == hsError) continue;
heptspin hs2 = hsstep(hsspin(hs, d), 0);
drawrec(hs2, lev-2, s2, V * heptmove[d]);
}
}
int mindx=-7, mindy=-7, maxdx=7, maxdy=7;
transmatrix eumove(int x, int y) {
transmatrix Mat = Id;
Mat[2][2] = 1;
Mat[0][2] += (x + y * .5) * eurad;
// Mat[2][0] += (x + y * .5) * eurad;
Mat[1][2] += y * q3 /2 * eurad;
// Mat[2][1] += y * q3 /2 * eurad;
while(Mat[0][2] <= -16384 * eurad) Mat[0][2] += 32768 * eurad;
while(Mat[0][2] >= 16384 * eurad) Mat[0][2] -= 32768 * eurad;
while(Mat[1][2] <= -16384 * q3 * eurad) Mat[1][2] += 32768 * q3 * eurad;
while(Mat[1][2] >= 16384 * q3 * eurad) Mat[1][2] -= 32768 * q3 * eurad;
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=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);
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++) {
reclevel = eudist(dx, dy);
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;
Mat = View * Mat;
// Mat[0][0] = -1;
// Mat[1][1] = -1;
// Mat[2][0] = x*x/10;
// Mat[2][1] = y*y/10;
// Mat = Mat * xpush(x-30) * ypush(y-30);
int cx, cy, shift;
getcoord0(tC0(Mat), cx, cy, shift);
if(cx >= 0 && cy >= 0 && cx < vid.xres && cy < vid.yres) {
if(dx < mindx) mindx = dx;
if(dy < mindy) mindy = dy;
if(dx > maxdx) maxdx = dx;
if(dy > maxdy) maxdy = dy;
}
if(dodrawcell(c)) {
drawcell(c, Mat, 0, false);
}
}
}
void spinEdge(ld aspd) {
if(downspin > aspd) downspin = aspd;
if(downspin < -aspd) downspin = -aspd;
View = spin(downspin) * View;
}
void centerpc(ld aspd) {
if(vid.sspeed >= 4.99) aspd = 1000;
DEBB(DF_GRAPH, (debugfile,"center pc\n"));
hyperpoint H = ypush(-vid.yshift) * sphereflip * tC0(cwtV);
if(H[0] == 0 && H[1] == 0) return; // either already centered or direction unknown
ld R = hdist0(H); // = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R < 1e-9) {
/* if(playerfoundL && playerfoundR) {
} */
spinEdge(aspd);
fixmatrix(View);
return;
}
if(euclid) {
// 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;
}
else {
aspd *= (1+R+(shmup::on?1:0));
if(R < aspd) {
View = gpushxto0(H) * View;
}
else
View = rspintox(H) * xpush(-aspd) * spintox(H) * View;
fixmatrix(View);
spinEdge(aspd);
}
}
void optimizeview() {
DEBB(DF_GRAPH, (debugfile,"optimize view\n"));
int turn = 0;
ld best = INF;
transmatrix TB = Id;
for(int i=-1; i<S7; i++) {
ld trot = -i * M_PI * 2 / (S7+.0);
transmatrix T = i < 0 ? Id : spin(trot) * xpush(tessf) * pispin;
hyperpoint H = View * tC0(T);
if(H[2] < best) best = H[2], turn = i, TB = T;
}
if(turn >= 0) {
View = View * TB;
fixmatrix(View);
viewctr = hsspin(viewctr, turn);
viewctr = hsstep(viewctr, 0);
}
}
void addball(ld a, ld b, ld c) {
hyperpoint h;
ballmodel(h, a, b, c);
for(int i=0; i<3; i++) h[i] *= vid.radius;
curvepoint(h);
}
void ballgeometry() {
queuereset(vid.usingGL ? mdDisk : mdUnchanged, PPR_CIRCLE);
for(int i=0; i<60; i++)
addball(i * M_PI/30, 10, 0);
for(double d=10; d>=-10; d-=.2)
addball(0, d, 0);
for(double d=-10; d<=10; d+=.2)
addball(0, d, geom3::depth);
addball(0, 0, -geom3::camera);
addball(0, 0, geom3::depth);
addball(0, 0, -geom3::camera);
addball(0, -10, 0);
addball(0, 0, -geom3::camera);
queuecurve(darkena(0xFF, 0, 0x80), 0, PPR_CIRCLE);
queuereset(pmodel, PPR_CIRCLE);
}
void resetview() {
DEBB(DF_GRAPH, (debugfile,"reset view\n"));
View = Id;
// EUCLIDEAN
if(!euclid)
viewctr.h = cwt.c->master,
viewctr.spin = cwt.spin;
else centerover = cwt.c;
// SDL_LockSurface(s);
// SDL_UnlockSurface(s);
}
void panning(hyperpoint hf, hyperpoint ht) {
View =
rgpushxto0(hf) * rgpushxto0(gpushxto0(hf) * ht) * gpushxto0(hf) * View;
playermoved = false;
}
void fullcenter() {
if(playerfound && false) centerpc(INF);
else {
bfs();
resetview();
drawthemap();
centerpc(INF);
}
playermoved = true;
}
transmatrix screenpos(ld x, ld y) {
transmatrix V = Id;
V[0][2] += (x - vid.xcenter) / vid.radius * (1+vid.alphax);
V[1][2] += (y - vid.ycenter) / vid.radius * (1+vid.alphax);
return V;
}
transmatrix atscreenpos(ld x, ld y, ld size) {
transmatrix V = Id;
V[0][2] += (x - vid.xcenter);
V[1][2] += (y - vid.ycenter);
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;
return V;
}

View File

@ -1,6 +1,6 @@
#define VER "9.4n1"
#define VERNUM 9415
#define VERNUM_HEX 0x9415
#define VER "9.4n2"
#define VERNUM 9416
#define VERNUM_HEX 0x9416
#define GEN_M 0
#define GEN_F 1
@ -276,6 +276,23 @@ const char *loadlevel = NULL;
#ifdef EXTRA
#include "extra/extra.cpp"
#endif
#include "basegraph.cpp"
#include "help.cpp"
#include "config.cpp"
#include "scores.cpp"
#include "menus.cpp"
#ifdef FIXEDSIZE
#include "nofont.cpp"
#endif
#include "shmup.cpp"
#ifdef ROGUEVIZ
#include "rogueviz.cpp"
#endif
#include "conformal.cpp"
#include "rug.cpp"
#include "control.cpp"
#include "hud.cpp"
#include "hypgraph.cpp"
#include "graph.cpp"
#include "sound.cpp"
#include "achievement.cpp"
@ -299,7 +316,6 @@ void initAll() {
eLand f = firstland;
// initlanguage();
cmode = emNormal;
initgraph();
#ifndef NOSAVE
loadsave();
@ -396,7 +412,7 @@ bool useRangedOrb;
void handleclick(MOBPAR_FORMAL) {
if(!shmup::on && andmode == 0 && cmode == emNormal && canmove && !useRangedOrb && vid.mobilecompasssize > 0) {
if(!shmup::on && andmode == 0 && size(screens) == 1 && canmove && !useRangedOrb && vid.mobilecompasssize > 0) {
using namespace shmupballs;
int dx = mousex - xmove;
int dy = mousey - yb;
@ -404,7 +420,7 @@ void handleclick(MOBPAR_FORMAL) {
if(h < rad) {
if(h < rad*SKIPFAC) movepcto(MD_WAIT);
else {
double d = revcontrol ? -1 : 1;
double d = vid.revcontrol ? -1 : 1;
mouseh = hpxy(dx * d / rad, dy * d / rad);
mousemovement();
}
@ -415,7 +431,7 @@ void handleclick(MOBPAR_FORMAL) {
if(buttonclicked || mouseout()) {
if(andmode == 0 && getcstat == 'g' && !shmup::on && (cmode == emNormal || cmode == emQuit)) {
if(andmode == 0 && getcstat == 'g' && !shmup::on && size(screens) == 1) {
movepcto(MD_DROP);
getcstat = 0;
}
@ -424,7 +440,7 @@ void handleclick(MOBPAR_FORMAL) {
int px = mousex < vid.xcenter ? 0 : 1;
int py = mousey < vid.ycenter ? 0 : 1;
if(cmode == (canmove ? emNormal : emQuit)) {
if(size(screens) == 1) {
if(px == 0 && py == 1) {
if(andmode == 0 && shmup::on) ;
else andmode = 10;
@ -456,7 +472,7 @@ void handleclick(MOBPAR_FORMAL) {
}
}
if(andmode == 0 && cmode == (canmove ? emNormal : emQuit) && !mouseout()) {
if(andmode == 0 && size(screens) == 1 && !mouseout()) {
bool forcetarget = longclick;
@ -499,7 +515,7 @@ void mobile_draw(MOBPAR_FORMAL) {
if(playermoved && vid.sspeed > -4.99)
centerpc(tdiff / 1000.0 * exp(vid.sspeed));
if(shmup::on && (andmode == 0 || andmode == 10) && cmode == emNormal)
if(shmup::on && (andmode == 0 || andmode == 10) && size(screens) == 1)
shmup::turn(tdiff);
safety = false;
@ -520,7 +536,7 @@ void mobile_draw(MOBPAR_FORMAL) {
if(hypot(mousex - xmove, mousey - yb) < rad) targetclick = false;
}
if(cmode == emNormal) {
if(size(screens) == 1) {
lmouseover = (gtouched && lclicked) ? mouseover : NULL;
if(!shmup::on && !useRangedOrb && vid.mobilecompasssize) {
using namespace shmupballs;
@ -530,7 +546,7 @@ void mobile_draw(MOBPAR_FORMAL) {
if(h < rad) {
if(h < rad*SKIPFAC) { lmouseover = cwt.c; mousedest.d = -1; }
else {
double d = revcontrol ? -1 : 1;
double d = vid.revcontrol ? -1 : 1;
mouseh = hpxy(dx * d / rad, dy * d / rad);
calcMousedest();
}
@ -556,6 +572,8 @@ void mobile_draw(MOBPAR_FORMAL) {
shiftmul = getcshift;
calcMousedest();
inmenu = size(screens) > 1;
if(lclicked && !clicked && !inmenu) handleclick(MOBPAR_ACTUAL);
if(inmenu && !clicked && !lclicked) inmenu = false;
@ -581,29 +599,20 @@ void mobile_draw(MOBPAR_FORMAL) {
#ifdef ANDROIDSHARE
if(getcstat == 's'-96 && keyreact) {
cmode = canmove ? emQuit : emNormal;
popScreenAll().
shareScore(MOBPAR_ACTUAL);
cmode = emNormal;
}
#endif
if(andmode == 2 && cmode != emNormal) andmode = 12;
if(andmode == 2 && size(screens) != 1) andmode = 12;
if((cmode == emQuit && !canmove && keyreact && lclicked && !clicked) && !buttonclicked) {
cmode = emNormal; printf("back to quit\n");
popScreenAll(); printf("back to quit\n");
}
else if(cmode == emScores) handleScoreKeys(0, 0);
else if(getcstat && keyreact) {
if(cmode == (canmove ? emQuit : emNormal))
handleQuit(getcstat, getcstat);
else {
if(cmode != emNormal && cmode != emQuit) inmenu = true;
if(cmode == emMenu && getcstat == 'q') openURL();
else { extra ex; handlekey(getcstat, getcstat, ex); }
}
if(cmode == emMenu && getcstat == 'q') openURL();
else { extra ex; handlekey(getcstat, getcstat, ex); }
}
#ifdef IOS
@ -621,7 +630,7 @@ void mobile_draw(MOBPAR_FORMAL) {
if(andmode == 1 && lclicked && !clicked && !inmenu && mouseover)
performMarkCommand(mouseover);
if(clicked && andmode == 2 && (mouseover != lmouseover || mouseovers != lmouseovers) && cmode == emNormal) {
if(clicked && andmode == 2 && (mouseover != lmouseover || mouseovers != lmouseovers) && !inmenu) {
addMessage(mouseovers);
lmouseovers = mouseovers;
}
@ -630,7 +639,7 @@ void mobile_draw(MOBPAR_FORMAL) {
if(andmode == 20 && clicked != lclicked) andmode = 10;
if(andmode == 2 && lclicked && !clicked) {
if(cmode == emNormal)
if(!inmenu)
showHelp(MOBPAR_ACTUAL, help);
else if(cmode != emScores && cmode != emPickScores)
cmode = emNormal;
@ -664,35 +673,3 @@ 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);
}

View File

@ -68,9 +68,9 @@ void loadsamples(const char *fname) {
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;
for(int i=0; i<cols; i++)
if(fscanf(f, "%lf", &s.val[i]) != 1) { break; }
fgetc(f);
while(true) {
int c = fgetc(f);

View File

@ -1596,27 +1596,13 @@ bool createOnSea(eLand old) {
(old == laOcean && (chaosmode ? hrand(2) : !generatingEquidistant));
}
hookset<eLand(eLand)> *hooks_nextland;
eLand getNewLand(eLand old) {
#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
eLand l = callhandlers(laNone, hooks_nextland, old);
if(l) return l;
if(cheatdest != old) if(!isCyclic(cheatdest) && !isTechnicalLand(cheatdest)) return cheatdest;
if(old == laTortoise) return laDragon;

14103
language-data.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,11 +25,10 @@ namespace mapeditor {
#ifndef NOEDIT
map<int, cell*> modelcell;
void clearModelCells() {
modelcell.clear();
}
void handleKeyMap(int sym, int uni);
bool handleKeyFile(int sym, int uni);
void applyModelcell(cell *c) {
if(mapeditor::whichPattern == 'H') return;
if(mapeditor::whichPattern == 'H') return;
@ -157,7 +156,6 @@ namespace mapstream {
clearMemory();
initcells();
cleargraphmemory();
if(shmup::on) shmup::init();
while(true) {
@ -425,8 +423,6 @@ namespace mapeditor {
return true;
}
int subscreen; //0=normal, 1=config, 2=patterns, 3=predesigned
cell *drawcell;
#ifndef NOEDIT
@ -557,11 +553,15 @@ namespace mapeditor {
return f1.first < f2.first;
}
string filecaption, cfileext;
string *cfileptr;
void drawFileDialog() {
displayfr(vid.xres/2, 30 + vid.fsize, 2, vid.fsize,
XLAT(cmode == emDraw ? "pics to save/load:" : "level to save/load:"), forecolor, 8);
filecaption, forecolor, 8);
string cfile = cmode == emDraw ? picfile : levelfile;
string& cfile = *cfileptr;
displayfr(vid.xres/2, 34 + vid.fsize * 2, 2, vid.fsize,
cfile, editext ? 0xFF00FF : 0xFFFF00, 8);
@ -589,7 +589,7 @@ namespace mapeditor {
while ((dir = readdir(d)) != NULL) {
string s = dir->d_name;
if(s != ".." && s[0] == '.') ;
else if(size(s) > 4 && s.substr(size(s)-4) == (cmode == emDraw ? ".pic" : ".lev"))
else if(size(s) > 4 && s.substr(size(s)-4) == cfileext)
v.push_back(make_pair(s, CFILE));
else if(dir->d_type & DT_DIR)
v.push_back(make_pair(s+"/", CDIR));
@ -608,6 +608,8 @@ namespace mapeditor {
displayColorButton(x, y, v[i].first, 1000 + i, 0, 0, v[i].second, 0xFFFF00);
}
keyhandler = handleKeyFile;
}
void displayFunctionKeys() {
@ -630,142 +632,190 @@ namespace mapeditor {
v.push_back(make_pair(s, i));
}
void showPrePattern() {
dialog::init("predesigned patterns");
dialog::addItem(XLAT("Gameboard"), 'g');
dialog::addItem(XLAT("random colors"), 'r');
dialog::addItem(XLAT("rainbow landscape"), 'l');
dialog::addItem(XLAT("dark rainbow landscape"), 'd');
dialog::addItem(XLAT("football"), 'F');
dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e');
dialog::addSelItem(XLAT("four elements"), "palace", 'b');
dialog::addSelItem(XLAT("eight domains"), "palace", 'a');
dialog::addSelItem(XLAT("zebra pattern"), "zebra", 'z');
dialog::addSelItem(XLAT("four triangles"), "zebra", 't');
dialog::addSelItem(XLAT("three stripes"), "zebra", 'x');
dialog::addSelItem(XLAT("random black-and-white"), "current", 'w');
dialog::addSelItem(XLAT("field pattern C"), "field", 'C');
dialog::addSelItem(XLAT("field pattern D"), "field", 'D');
dialog::addSelItem(XLAT("field pattern N"), "field", 'N');
dialog::addSelItem(XLAT("field pattern S"), "field", 'S');
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if((uni >= 'a' && uni <= 'z') || (uni >= 'A' && uni <= 'Z')) {
whichCanvas = uni;
subcanvas = rand();
firstland = laCanvas; randomPatternsMode = false;
restartGame();
}
else if(doexiton(sym, uni)) popScreen();
};
}
void showPattern() {
dialog::init();
dialog::addBoolItem(XLAT(euclid ? "three colors" : "Emerald Pattern"), (whichPattern == 'f'), 'f');
dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == 'p'), 'p');
dialog::addBoolItem(XLAT(euclid ? "three colors rotated" : "Zebra Pattern"), (whichPattern == 'z'), 'z');
dialog::addBoolItem(XLAT("field pattern"), (whichPattern == 'F'), 'F');
if(whichPattern == 'f') symRotation = true;
if(whichPattern == 'F') ;
else if(!euclid) {
dialog::addBoolItem(XLAT("rotational symmetry"), (symRotation), '0');
dialog::addBoolItem(XLAT("symmetry 0-1"), (sym01), '1');
dialog::addBoolItem(XLAT("symmetry 0-2"), (sym02), '2');
dialog::addBoolItem(XLAT("symmetry 0-3"), (sym03), '3');
}
else
dialog::addBoolItem(XLAT("edit all three colors"), (symRotation), '0');
dialog::addBoolItem(XLAT("display pattern codes (full)"), (displaycodes == 1), 'd');
dialog::addBoolItem(XLAT("display pattern codes (simplified)"), (displaycodes == 2), 's');
dialog::addBoolItem(XLAT("display only hexagons"), (whichShape == '6'), '6');
dialog::addBoolItem(XLAT("display only heptagons"), (whichShape == '7'), '7');
dialog::addBoolItem(XLAT("display the triheptagonal grid"), (whichShape == '8'), '8');
dialog::addItem(XLAT("line patterns"), 'l');
dialog::addItem(XLAT("predesigned patterns"), 'r');
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 'f' || uni == 'p' || uni == 'z' || uni == 'H' || uni == 'F') {
if(whichPattern == uni) whichPattern = 0;
else whichPattern = uni;
modelcell.clear();
}
else if(uni == '0') symRotation = !symRotation;
else if(uni == '1') sym01 = !sym01;
else if(uni == '2') sym02 = !sym02;
else if(uni == '3') sym03 = !sym03;
else if(uni == '6' || uni == '7' || uni == '8') {
if(whichShape == uni) whichShape = 0;
else whichShape = uni;
}
else if(uni == '3') sym03 = !sym03;
else if(uni == 'd') displaycodes = displaycodes == 1 ? 0 : 1;
else if(uni == 's') displaycodes = displaycodes == 2 ? 0 : 2;
else if(uni == 'l')
pushScreen(linepatterns::showMenu);
else if(uni == 'r') pushScreen(showPrePattern);
else if(doexiton(sym, uni)) popScreen();
};
}
void showList() {
v.clear();
if(painttype == 4) painttype = 0;
switch(painttype) {
case 0:
for(int i=0; i<motypes; i++) {
eMonster m = eMonster(i);
if(
m == moTongue || m == moPlayer || m == moFireball || m == moBullet ||
m == moFlailBullet || m == moShadow || m == moAirball ||
m == moWolfMoved || m == moGolemMoved ||
m == moTameBomberbirdMoved || m == moKnightMoved ||
m == moDeadBug || m == moLightningBolt || m == moDeadBird ||
m == moMouseMoved || m == moPrincessMoved || m == moPrincessArmedMoved) ;
else vpush(i, minf[i].name);
}
break;
case 1:
for(int i=0; i<ittypes; i++) vpush(i, iinf[i].name);
break;
case 2:
for(int i=0; i<landtypes; i++) vpush(i, linf[i].name);
break;
case 3:
for(int i=0; i<walltypes; i++) if(i != waChasmD) vpush(i, winf[i].name);
break;
}
// sort(v.begin(), v.end());
if(infix != "") mouseovers = infix;
int q = v.size();
int percolumn = vid.yres / (vid.fsize+5) - 4;
int columns = 1 + (q-1) / percolumn;
for(int i=0; i<q; i++) {
int x = 16 + (vid.xres * (i/percolumn)) / columns;
int y = (vid.fsize+5) * (i % percolumn) + vid.fsize*2;
int actkey = 1000 + i;
string vv = v[i].first;
if(i < 9) { vv += ": "; vv += ('1' + i); }
displayButton(x, y, vv, actkey, 0);
}
keyhandler = [] (int sym, int uni) {
if(uni >= '1' && uni <= '9') uni = 1000 + uni - '1';
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == '-' || sym == SDLK_KP_MINUS) uni = 1000;
for(int z=0; z<size(v); z++) if(1000 + z == uni) {
paintwhat = v[z].second;
paintwhat_str = v[z].first;
mousepressed = false;
popScreen();
return;
}
if(editInfix(uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
void showMapEditor() {
cmode2 = smMap;
gamescreen(0);
if(choosefile) { drawFileDialog(); return; }
if(subscreen == 2) {
dialog::init();
int fs = vid.fsize + 5;
getcstat = '-';
dialog::addBoolItem(XLAT(euclid ? "three colors" : "Emerald Pattern"), (whichPattern == 'f'), 'f');
dialog::addBoolItem(XLAT("Palace Pattern"), (whichPattern == 'p'), 'p');
dialog::addBoolItem(XLAT(euclid ? "three colors rotated" : "Zebra Pattern"), (whichPattern == 'z'), 'z');
dialog::addBoolItem(XLAT("field pattern"), (whichPattern == 'F'), 'F');
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);
if(whichPattern == 'f') symRotation = true;
if(whichPattern == 'F') ;
else if(!euclid) {
dialog::addBoolItem(XLAT("rotational symmetry"), (symRotation), '0');
dialog::addBoolItem(XLAT("symmetry 0-1"), (sym01), '1');
dialog::addBoolItem(XLAT("symmetry 0-2"), (sym02), '2');
dialog::addBoolItem(XLAT("symmetry 0-3"), (sym03), '3');
}
else
dialog::addBoolItem(XLAT("edit all three colors"), (symRotation), '0');
dialog::addBoolItem(XLAT("display pattern codes (full)"), (displaycodes == 1), 'd');
dialog::addBoolItem(XLAT("display pattern codes (simplified)"), (displaycodes == 2), 's');
dialog::addBoolItem(XLAT("display only hexagons"), (whichShape == '6'), '6');
dialog::addBoolItem(XLAT("display only heptagons"), (whichShape == '7'), '7');
dialog::addBoolItem(XLAT("display the triheptagonal grid"), (whichShape == '8'), '8');
dialog::addItem(XLAT("line patterns"), 'l');
dialog::addItem(XLAT("predesigned patterns"), 'r');
dialog::display();
}
else if(subscreen == 3) {
dialog::init("predesigned patterns");
dialog::addItem(XLAT("Gameboard"), 'g');
dialog::addItem(XLAT("random colors"), 'r');
dialog::addItem(XLAT("rainbow landscape"), 'l');
dialog::addItem(XLAT("dark rainbow landscape"), 'd');
dialog::addItem(XLAT("football"), 'F');
dialog::addSelItem(XLAT("emerald pattern"), "emerald", 'e');
dialog::addSelItem(XLAT("four elements"), "palace", 'b');
dialog::addSelItem(XLAT("eight domains"), "palace", 'a');
dialog::addSelItem(XLAT("zebra pattern"), "zebra", 'z');
dialog::addSelItem(XLAT("four triangles"), "zebra", 't');
dialog::addSelItem(XLAT("three stripes"), "zebra", 'x');
dialog::addSelItem(XLAT("random black-and-white"), "current", 'w');
dialog::addSelItem(XLAT("field pattern C"), "field", 'C');
dialog::addSelItem(XLAT("field pattern D"), "field", 'D');
dialog::addSelItem(XLAT("field pattern N"), "field", 'N');
dialog::addSelItem(XLAT("field pattern S"), "field", 'S');
dialog::display();
}
else if(subscreen == 1 && painttype == 6)
dialog::drawColorDialog(paintwhat);
else if(subscreen == 1) {
v.clear();
if(painttype == 4) painttype = 0;
switch(painttype) {
case 0:
for(int i=0; i<motypes; i++) {
eMonster m = eMonster(i);
if(
m == moTongue || m == moPlayer || m == moFireball || m == moBullet ||
m == moFlailBullet || m == moShadow || m == moAirball ||
m == moWolfMoved || m == moGolemMoved ||
m == moTameBomberbirdMoved || m == moKnightMoved ||
m == moDeadBug || m == moLightningBolt || m == moDeadBird ||
m == moMouseMoved || m == moPrincessMoved || m == moPrincessArmedMoved) ;
else vpush(i, minf[i].name);
}
break;
case 1:
for(int i=0; i<ittypes; i++) vpush(i, iinf[i].name);
break;
case 2:
for(int i=0; i<landtypes; i++) vpush(i, linf[i].name);
break;
case 3:
for(int i=0; i<walltypes; i++) if(i != waChasmD) vpush(i, winf[i].name);
break;
}
// sort(v.begin(), v.end());
displayButton(8, 8+fs*4, XLAT("0-9 = radius (%1)", its(radius)), ('0' + (radius+1)%10), 0);
displayButton(8, 8+fs*5, XLAT("b = boundary"), 'b', 0);
displayButton(8, 8+fs*6, XLAT("m = monsters"), 'm', 0);
displayButton(8, 8+fs*7, XLAT("w = walls"), 'w', 0);
displayButton(8, 8+fs*8, XLAT("i = items"), 'i', 0);
displayButton(8, 8+fs*9, XLAT("l = lands"), 'l', 0);
displayfr(8, 8+fs*10, 2, vid.fsize, XLAT("c = copy"), 0xC0C0C0, 0);
displayButton(8, 8+fs*11, XLAT("u = undo"), 'u', 0);
if(painttype == 4)
displayButton(8, 8+fs*12, XLAT("f = flip %1", ONOFF(copyflip)), 'u', 0);
displayButton(8, 8+fs*13, XLAT("r = regular"), 'r', 0);
displayButton(8, 8+fs*14, XLAT("p = paint"), 'p', 0);
if(infix != "") mouseovers = infix;
int q = v.size();
int percolumn = vid.yres / (vid.fsize+5) - 4;
int columns = 1 + (q-1) / percolumn;
for(int i=0; i<q; i++) {
int x = 16 + (vid.xres * (i/percolumn)) / columns;
int y = (vid.fsize+5) * (i % percolumn) + vid.fsize*2;
int actkey = 1000 + i;
string vv = v[i].first;
if(i < 9) { vv += ": "; vv += ('1' + i); }
displayButton(x, y, vv, actkey, 0);
}
}
else {
/* displayfr(vid.xres/2, vid.ycenter - vid.radius * 3/4 - vid.fsize*3/2, 2,
vid.fsize,
XLAT("MAP EDITOR: ") + paintwhat_str,
0xFFFFFF, 8); */
int fs = vid.fsize + 5;
getcstat = '-';
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);
displayButton(8, 8+fs*5, XLAT("b = boundary"), 'b', 0);
displayButton(8, 8+fs*6, XLAT("m = monsters"), 'm', 0);
displayButton(8, 8+fs*7, XLAT("w = walls"), 'w', 0);
displayButton(8, 8+fs*8, XLAT("i = items"), 'i', 0);
displayButton(8, 8+fs*9, XLAT("l = lands"), 'l', 0);
displayfr(8, 8+fs*10, 2, vid.fsize, XLAT("c = copy"), 0xC0C0C0, 0);
displayButton(8, 8+fs*11, XLAT("u = undo"), 'u', 0);
if(painttype == 4)
displayButton(8, 8+fs*12, XLAT("f = flip %1", ONOFF(copyflip)), 'u', 0);
displayButton(8, 8+fs*13, XLAT("r = regular"), 'r', 0);
displayButton(8, 8+fs*14, XLAT("p = paint"), 'p', 0);
displayFunctionKeys();
}
displayFunctionKeys();
keyhandler = handleKeyMap;
}
int spillinc() {
@ -1032,16 +1082,16 @@ namespace mapeditor {
}
}
bool handleKeyFile(int uni, int& sym) {
string& s(cmode == emDraw ? picfile : levelfile);
bool handleKeyFile(int uni, int sym) {
string& s(*cfileptr);
int i = size(s) - (editext?0:4);
if(uni > 2000) sym = uni - 2000;
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == SDLK_ESCAPE) {
choosefile = false;
popScreen();
return true;
}
else if(sym == SDLK_F2 || sym == SDLK_F3) {
choosefile = false;
popScreen();
return false;
}
else if(sym == SDLK_F4) {
@ -1075,132 +1125,80 @@ namespace mapeditor {
return true;
}
void handleKey(int sym, int uni) {
if(choosefile && handleKeyFile(sym, uni)) ;
else if(subscreen == 1 && painttype == 6) {
paintwhat_str = "paint";
int v = dialog::handleKeyColor(sym, uni, paintwhat);
if(v == 1) subscreen = 0;
if(v == 2) cmode = emNormal;
}
else if(subscreen == 1) {
if(uni >= '1' && uni <= '9') uni = 1000 + uni - '1';
if(sym == SDLK_RETURN || sym == SDLK_KP_ENTER || sym == '-' || sym == SDLK_KP_MINUS) uni = 1000;
for(int z=0; z<size(v); z++) if(1000 + z == uni) {
paintwhat = v[z].second;
paintwhat_str = v[z].first;
subscreen = 0;
mousepressed = false;
}
if(editInfix(uni)) ;
else if(subscreen == 1 && uni != 0) cmode = emNormal;
}
else if(subscreen == 3) {
dialog::handleNavigation(sym, uni);
if((uni >= 'a' && uni <= 'z') || (uni >= 'A' && uni <= 'Z')) {
whichCanvas = uni;
subcanvas = rand();
firstland = laCanvas; randomPatternsMode = false;
restartGame(); subscreen = 0;
}
else if(uni != 0) subscreen = 0;
}
else if(subscreen == 2) {
dialog::handleNavigation(sym, uni);
if(uni == 'f' || uni == 'p' || uni == 'z' || uni == 'H' || uni == 'F') {
if(whichPattern == uni) whichPattern = 0;
else whichPattern = uni;
clearModelCells();
}
else if(uni == '0') symRotation = !symRotation;
else if(uni == '1') sym01 = !sym01;
else if(uni == '2') sym02 = !sym02;
else if(uni == '3') sym03 = !sym03;
else if(uni == '6' || uni == '7' || uni == '8') {
if(whichShape == uni) whichShape = 0;
else whichShape = uni;
}
else if(uni == '3') sym03 = !sym03;
else if(uni == 'd') displaycodes = displaycodes == 1 ? 0 : 1;
else if(uni == 's') displaycodes = displaycodes == 2 ? 0 : 2;
else if(uni == 'l')
cmode = emLinepattern;
void handleKeyMap(int sym, int uni) {
handlePanning(sym, uni);
else if(uni == 'r')
subscreen = 3;
else if(uni != 0) subscreen = 0;
// left-clicks are coded with '-', and right-clicks are coded with sym F1
if(uni == '-') undoLock();
if(mousepressed && mouseover && sym != SDLK_F1)
allInPattern(mouseover, radius, neighborId(mouseover, mouseover2));
if(mouseover) for(int i=0; i<mouseover->type; i++) createMov(mouseover, i);
if(uni == 'u') applyUndo();
else if(uni == 'v' || sym == SDLK_F10 || sym == SDLK_ESCAPE) popScreen();
else if(uni >= '0' && uni <= '9') radius = uni - '0';
else if(uni == 'm') pushScreen(showList), painttype = 0, infix = "";
else if(uni == 'i') pushScreen(showList), painttype = 1, infix = "";
else if(uni == 'l') pushScreen(showList), painttype = 2, infix = "";
else if(uni == 'w') pushScreen(showList), painttype = 3, infix = "";
else if(uni == 'r') pushScreen(showPattern);
else if(uni == 't' && mouseover) {
cwt.c = mouseover; playermoved = true;
cwt.spin = neighborId(mouseover, mouseover2);
}
else {
// left-clicks are coded with '-', and right-clicks are coded with sym F1
if(uni == '-') undoLock();
if(mousepressed && mouseover && sym != SDLK_F1)
allInPattern(mouseover, radius, neighborId(mouseover, mouseover2));
if(mouseover) for(int i=0; i<mouseover->type; i++) createMov(mouseover, i);
if(uni == 'u') applyUndo();
else if(uni == 'v' || sym == SDLK_F10 || sym == SDLK_ESCAPE) cmode = emNormal;
else if(uni >= '0' && uni <= '9') radius = uni - '0';
else if(uni == 'm') subscreen = 1, painttype = 0, infix = "";
else if(uni == 'i') subscreen = 1, painttype = 1, infix = "";
else if(uni == 'l') subscreen = 1, painttype = 2, infix = "";
else if(uni == 'w') subscreen = 1, painttype = 3, infix = "";
else if(uni == 'r') subscreen = 2;
else if(uni == 't' && mouseover) {
cwt.c = mouseover; playermoved = true;
cwt.spin = neighborId(mouseover, mouseover2);
}
else if(uni == 'b') painttype = 5, paintwhat_str = XLAT("boundary");
else if(uni == 'p')
subscreen = 1, paintwhat = (painttype ==6 ? paintwhat : 0x808080), painttype = 6;
else if(sym == SDLK_F2) {
if(mapstream::saveMap(levelfile.c_str()))
addMessage(XLAT("Map saved to %1", levelfile));
else
addMessage(XLAT("Failed to save map to %1", levelfile));
}
else if(sym == SDLK_F5) {
restartGame();
}
else if(sym == SDLK_F3) {
if(mapstream::loadMap(levelfile.c_str()))
addMessage(XLAT("Map loaded from %1", levelfile));
else
addMessage(XLAT("Failed to load map from %1", levelfile));
}
else if(sym == SDLK_F4)
choosefile = true;
else if(sym == SDLK_F6) {
saveHighQualityShot();
}
else if(sym == SDLK_F8) {
svg::render();
}
else if(sym == SDLK_F7) {
drawplayer = !drawplayer;
}
else if(uni == 'c') {
if(mouseover && mouseover2)
copydir = neighborId(mouseover, mouseover2);
if(copydir<0) copydir = 0;
copyflip = (uni == 'f');
copywhat = mouseover, painttype = 4;
paintwhat_str = XLAT("copying");
}
else if(uni == 'f') {
copyflip = !copyflip;
}
else if(uni == 'h' || sym == SDLK_F1) {
lastmode = cmode;
cmode = emHelp;
help = mehelptext();
}
else if(uni == ' ') {
cmode = emDraw;
initdraw(mouseover ? mouseover : cwt.c);
}
else if(uni == 'b') painttype = 5, paintwhat_str = XLAT("boundary");
else if(uni == 'p') {
painttype = 6;
paintwhat_str = "paint";
dialog::openColorDialog(paintwhat = (painttype ==6 ? paintwhat : 0x808080));
}
else if(sym == SDLK_F2) {
if(mapstream::saveMap(levelfile.c_str()))
addMessage(XLAT("Map saved to %1", levelfile));
else
addMessage(XLAT("Failed to save map to %1", levelfile));
}
else if(sym == SDLK_F5) {
restartGame();
}
else if(sym == SDLK_F3) {
if(mapstream::loadMap(levelfile.c_str()))
addMessage(XLAT("Map loaded from %1", levelfile));
else
addMessage(XLAT("Failed to load map from %1", levelfile));
}
else if(sym == SDLK_F4) {
cfileptr = &levelfile;
filecaption = XLAT("level to save/load:");
cfileext = ".lev";
pushScreen(drawFileDialog);
}
else if(sym == SDLK_F6) {
saveHighQualityShot();
}
else if(sym == SDLK_F8) {
svg::render();
}
else if(sym == SDLK_F7) {
drawplayer = !drawplayer;
}
else if(uni == 'c') {
if(mouseover && mouseover2)
copydir = neighborId(mouseover, mouseover2);
if(copydir<0) copydir = 0;
copyflip = (uni == 'f');
copywhat = mouseover, painttype = 4;
paintwhat_str = XLAT("copying");
}
else if(uni == 'f') {
copyflip = !copyflip;
}
else if(uni == 'h' || sym == SDLK_F1)
gotoHelp(mehelptext());
else if(uni == ' ') {
popScreen();
pushScreen(showDrawEditor);
initdraw(mouseover ? mouseover : cwt.c);
}
}
@ -1216,7 +1214,7 @@ namespace mapeditor {
"the screen for more keys.";
string drawhelptext() {
return XLAT(mapeditor::drawhelp);
return XLAT(drawhelp);
}
int dslayer;
@ -1235,83 +1233,57 @@ namespace mapeditor {
}
void drawGhosts(cell *c, const transmatrix& V, int ct) {
/* if(cmode == emDraw && cwt.c->type == 6 && ct == 6) for(int a=0; a<dsCur->rots; a++) {
transmatrix V2 = V * spin(M_PI + 2*M_PI*a/dsCur->rots);
if(mouseout()) break;
hyperpoint P2 = V2 * inverse(cwtV) * mouseh;
int xc, yc, sc;
getcoord(P2, xc, yc, sc);
displaychr(xc, yc, sc, 10, 'x', 0xFF);
if(crad > 0 && c->cpdist <= 3) {
lalpha = 0x80;
transmatrix movtocc = V2 * inverse(cwtV) * rgpushxto0(ccenter);
for(int d=0; d<84; d++)
drawline(movtocc * ddi(d+1, crad) * C0, movtocc * ddi(d, crad) * C0, 0xC00000);
lalpha = 0xFF;
}
} */
}
hyperpoint ccenter = C0;
hyperpoint coldcenter = C0;
void drawGrid() {
if(cmode == emDraw && !inHighQual) {
for(int d=0; d<84; d++) {
transmatrix d2 = drawtrans * rgpushxto0(ccenter);
int lalpha;
if(d % (84/drawcell->type) == 0)
lalpha = 0x40;
else
lalpha = 0x20;
int col = darkena(0xC0C0C0, 0, lalpha);
queueline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, col);
for(int u=2; u<=20; u++) {
if(u % 5 == 0) lalpha = 0x40;
else lalpha = 0x20;
queueline(
d2 * spin(M_PI*d/42)* xpush(u/20.) * C0,
d2 * spin(M_PI*(d+1)/42)* xpush(u/20.) * C0,
darkena(0xC0C0C0, 0, lalpha));
}
for(int d=0; d<84; d++) {
transmatrix d2 = drawtrans * rgpushxto0(ccenter);
int lalpha;
if(d % (84/drawcell->type) == 0)
lalpha = 0x40;
else
lalpha = 0x20;
int col = darkena(0xC0C0C0, 0, lalpha);
queueline(d2 * C0, d2 * spin(M_PI*d/42)* xpush(1) * C0, col);
for(int u=2; u<=20; u++) {
if(u % 5 == 0) lalpha = 0x40;
else lalpha = 0x20;
queueline(
d2 * spin(M_PI*d/42)* xpush(u/20.) * C0,
d2 * spin(M_PI*(d+1)/42)* xpush(u/20.) * C0,
darkena(0xC0C0C0, 0, lalpha));
}
queueline(drawtrans*ccenter, drawtrans*coldcenter, darkena(0xC0C0C0, 0, 0x20));
int sg = drawcellShapeGroup();
if(0) for(int i=0; i<USERSHAPEIDS; i++) if(editingShape(sg, i) && usershapes[sg][i]) {
usershapelayer &ds(usershapes[sg][i]->d[mapeditor::dslayer]);
for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = drawtrans * ds.list[a];
}
queueline(drawtrans*ccenter, drawtrans*coldcenter, darkena(0xC0C0C0, 0, 0x20));
int sg = drawcellShapeGroup();
queuechr(P2, 10, 'x',
darkena(a == 0 ? 0x00FF00 :
a == size(ds.list)-1 ? 0xFF0000 :
0xFFFF00, 0, 0xFF));
}
if(0) for(int i=0; i<USERSHAPEIDS; i++) if(editingShape(sg, i) && usershapes[sg][i]) {
usershapelayer &ds(usershapes[sg][i]->d[mapeditor::dslayer]);
for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = drawtrans * ds.list[a];
queuechr(P2, 10, 'x',
darkena(a == 0 ? 0x00FF00 :
a == size(ds.list)-1 ? 0xFF0000 :
0xFFFF00, 0, 0xFF));
}
}
}
void drawHandleKey(int sym, int uni);
void showDrawEditor() {
cmode2 = smDraw;
drawGrid();
if(!mouseout()) getcstat = '-';
if(coloring) {
dialog::drawColorDialog(colortouse);
return;
}
if(choosefile) { drawFileDialog(); return; }
int sg = drawcellShapeGroup();
string line1, line2;
@ -1395,6 +1367,8 @@ namespace mapeditor {
}
displayFunctionKeys();
keyhandler = drawHandleKey;
}
bool rebuildPolys = false;
@ -1588,17 +1562,10 @@ namespace mapeditor {
}
void drawHandleKey(int sym, int uni) {
if(choosefile && handleKeyFile(sym, uni)) return;
if(uni == SETMOUSEKEY) mousekey = newmousekey;
handlePanning(sym, uni);
if(coloring) {
int v = dialog::handleKeyColor(sym, uni, colortouse);
if(v == 2) { coloring = false; return; }
else if(v == 1) { coloring = false; uni = COLORKEY; }
else return;
}
if(uni == SETMOUSEKEY) mousekey = newmousekey;
dslayer %= USERLAYERS;
hyperpoint mh = inverse(drawtrans) * mouseh;
@ -1638,11 +1605,21 @@ namespace mapeditor {
if(uni == 'z') vid.scale *= 2;
if(uni == 'o') vid.scale /= 2;
if(uni == ' ' && cheater) cmode = emMapEditor;
if(uni == ' ' && cheater) {
popScreen();
pushScreen(showMapEditor);
}
if(uni == 'p') coloring = true;
if(uni == 'p')
dialog::openColorDialog(colortouse);
if(sym == SDLK_F4) choosefile = true;
if(sym == SDLK_F4) {
filecaption = XLAT("pics to save/load:");
cfileptr = &picfile;
cfileext = ".pic";
pushScreen(drawFileDialog);
return;
}
if(sym == SDLK_F2) {
FILE *f = fopen(picfile.c_str(), "wt");
@ -1728,20 +1705,28 @@ namespace mapeditor {
if(usershapes[i][j]) delete usershapes[i][j];
}
if(sym == SDLK_ESCAPE) cmode = emNormal;
if(sym == SDLK_ESCAPE) popScreen();
if(sym == SDLK_F1) {
lastmode = cmode;
cmode = emHelp;
sym = 0;
help = drawhelptext();
gotoHelp(drawhelptext());
}
if(sym == SDLK_F10) cmode = emNormal;
if(sym == SDLK_F10) popScreen();
if(rebuildPolys)
buildpolys(), rebuildPolys = false;
}
auto hooks = addHook(clearmemory, 0, [] () {
if(mapeditor::painttype == 4)
mapeditor::painttype = 0, mapeditor::paintwhat = 0,
mapeditor::paintwhat_str = "clear monster";
mapeditor::copywhat = NULL;
mapeditor::undo.clear();
if(!cheater) mapeditor::displaycodes = 0;
if(!cheater) mapeditor::whichShape = 0;
modelcell.clear();
});
#endif
int canvasback = linf[laCanvas].color >> 2;
@ -1897,7 +1882,7 @@ namespace mapeditor {
}
#ifndef NOEDIT
if(cmode == emDraw && mapeditor::editingShape(group, id)) {
if(cmode2 == smDraw && mapeditor::editingShape(group, id)) {
/* for(int a=0; a<size(ds.list); a++) {
hyperpoint P2 = V * ds.list[a];
@ -2264,12 +2249,13 @@ lessalphaif(col, behindsphere(V), behindsphere(gmatrix[c2]))
dialog::addInfo("change the alpha parameter to show the lines");
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni >= 'a' && uni < 'a' + numpat)
dialog::openColorDialog(patterns[uni - 'a'].color, NULL);
else if(doexiton(sym,uni)) popScreen();
};
}
void handleMenu(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni >= 'a' && uni < 'a' + numpat)
dialog::openColorDialog(patterns[uni - 'a'].color, NULL);
else if(doexiton(sym,uni)) cmode = emNormal;
}
};

1745
menus.cpp

File diff suppressed because it is too large Load Diff

View File

@ -659,49 +659,49 @@ namespace netgen {
dialog::display();
}
}
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(!loaded) {
loadData();
if(!loaded) {
addMessage(XLAT("Failed to load the file 'papermodeldata.txt'"));
cmode = emNormal;
loadData();
if(!loaded) {
addMessage(XLAT("Failed to load the file 'papermodeldata.txt'"));
popScreen();
return;
}
if(!created) {
View = Id;
if(centerover) viewctr.h = centerover->master;
else viewctr.h = cwt.c->master;
playermoved = false;
dataFromHR();
designNet();
created = 1;
return;
}
}
if(mode == 2 && uni != 0) {
mode = 0;
return;
}
if(!created) {
if(uni == 's') {
View = Id;
if(centerover) viewctr.h = centerover->master;
else viewctr.h = cwt.c->master;
playermoved = false;
dataFromHR();
designNet();
created = 1;
return;
}
}
if(mode == 2 && uni != 0) {
mode = 0;
return;
}
if(uni == 's') {
View = Id;
if(centerover) viewctr.h = centerover->master;
else viewctr.h = cwt.c->master;
playermoved = false;
}
else if(uni == 'c') {
createPapermodel();
addMessage(XLAT("The paper model created as papermodel-*.bmp"));
}
else if(uni == 'd') designNet();
else if(uni == 't') mode = 2;
else if(doexiton(sym, uni))
cmode = emNormal;
else if(uni == 'c') {
createPapermodel();
addMessage(XLAT("The paper model created as papermodel-*.bmp"));
}
else if(uni == 'd') designNet();
else if(uni == 't') mode = 2;
else if(doexiton(sym, uni))
popScreen();
};
}
}
#endif

View File

@ -955,9 +955,9 @@ string describe(shmup::monster *m) {
sort(alledges.begin(), alledges.end(), edgecmp);
help = "Edges: ";
::help = "Edges: ";
if(vd.info) help = (*vd.info) + "\n" + help;
if(vd.info) ::help = (*vd.info) + "\n" + help;
for(int j=0; j<size(alledges); j++) {
edgeinfo *ei = alledges[j];
@ -1741,37 +1741,37 @@ void showMenu() {
dialog::addItem(XLAT("exit menu"), 'v');
dialog::display();
}
void handleMenu(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 't')
dialog::editNumber(sag::temperature, sag::lowtemp, sag::hightemp, 1, 0, XLAT("temperature"), "");
else if(uni == 'm') {
sag::sagmode = sag::eSagmode( (1+sag::sagmode) % 3 );
}
else if(uni == 'l') showlabels = !showlabels;
else if(uni == 'v') rog3 = !rog3;
else if(uni == 'x') specialmark = !specialmark;
else if(uni == 'b') backcolor ^= 0xFFFFFF, bordcolor ^= 0xFFFFFF, forecolor ^= 0xFFFFFF;
else if(uni == 'g') {
dialog::editNumber(ggamma, 0, 5, .01, 0.5, XLAT("gamma value for edges"), "");
dialog::sidedialog = true;
}
else if(uni == 'z') {
for(int i=0; i<size(named)-1; i++) if(named[i] == cwt.c)
swap(named[i], named[i+1]);
if(!size(named) || named[size(named)-1] != cwt.c) named.push_back(cwt.c);
printf("named = %d\n", size(named));
cmode = emNormal;
}
else if(kind == kKohonen && kohonen::handleMenu(sym, uni)) ;
else if(doexiton(sym, uni)) cmode = emNormal;
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni == 't')
dialog::editNumber(sag::temperature, sag::lowtemp, sag::hightemp, 1, 0, XLAT("temperature"), "");
else if(uni == 'm') {
sag::sagmode = sag::eSagmode( (1+sag::sagmode) % 3 );
}
else if(uni == 'l') showlabels = !showlabels;
else if(uni == 'v') rog3 = !rog3;
else if(uni == 'x') specialmark = !specialmark;
else if(uni == 'b') backcolor ^= 0xFFFFFF, bordcolor ^= 0xFFFFFF, forecolor ^= 0xFFFFFF;
else if(uni == 'g') {
dialog::editNumber(ggamma, 0, 5, .01, 0.5, XLAT("gamma value for edges"), "");
dialog::sidedialog = true;
}
else if(uni == 'z') {
for(int i=0; i<size(named)-1; i++) if(named[i] == cwt.c)
swap(named[i], named[i+1]);
if(!size(named) || named[size(named)-1] != cwt.c) named.push_back(cwt.c);
printf("named = %d\n", size(named));
popScreen();
}
else if(kind == kKohonen && kohonen::handleMenu(sym, uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
void processKey(int sym, int uni) { }
string help() {
string makehelp() {
string ret =
"This is RogueViz, a visualization engine based on HyperRogue.\n\nUse WASD to move, v for menu.\n\n"
"Read more about RogueViz on : http://roguetemple.com/z/hyper/rogueviz.php\n\n";
@ -1822,15 +1822,16 @@ template<class T, class T1> function<void(presmode)> roguevizslide_action(char c
return [c,t,act] (presmode mode) {
mapeditor::canvasback = 0x101010;
setCanvas(mode, c);
if(mode == 1 || mode == pmGeometryStart) t();
if(mode == pmStart || mode == pmGeometryStart) t();
if(mode == 3 || mode == pmGeometry || mode == pmGeometryReset) {
act(mode);
if(mode == pmStop || mode == pmGeometry || mode == pmGeometryReset) {
rogueviz::close();
shmup::clearMonsters();
if(mode == pmGeometryReset) t();
}
act(mode);
};
}
@ -1983,4 +1984,11 @@ slide rvslides[] = {
}
auto hooks =
addHook(hooks_frame, 0, drawExtra) +
addHook(hooks_args, 100, readArgs) +
addHook(clearmemory, 0, clear) +
addHook(hooks_config, 0, [] () { ss::list(rogueviz::rvtour::rvslides); });
};

61
rug.cpp
View File

@ -667,50 +667,45 @@ void show() {
dialog::addBoolItem(XLAT("render texture without OpenGL"), (rendernogl), 'g');
dialog::addSelItem(XLAT("texture size"), its(texturesize)+"x"+its(texturesize), 's');
dialog::display();
}
keyhandler = [] (int sym, int uni) {
#ifdef PANDORA
rendernogl = true;
#endif
dialog::handleNavigation(sym, uni);
void handleKey(int sym, int uni) {
#ifdef PANDORA
rendernogl = true;
#endif
dialog::handleNavigation(sym, uni);
if(uni == 'h') {
lastmode = cmode;
cmode = emHelp;
help =
if(uni == 'h') gotoHelp(
"In this mode, HyperRogue is played on a 3D model of a part of the hyperbolic plane, "
"similar to one you get from the 'paper model creator' or by hyperbolic crocheting.\n\n"
"This requires some OpenGL extensions and may crash or not work correctly -- enabling "
"the 'render texture without OpenGL' options may be helpful in this case. Also the 'render once' option "
"will make the rendering faster, but the surface will be rendered only once, so "
"you won't be able to play a game on it.\n\n"
"Use arrow keys to rotate, Page Up/Down to zoom.";
}
else if(uni == 'u') {
if(sphere) restartGame('E');
if(euclid) restartGame('e');
rug::init();
cmode = emNormal;
}
else if(uni == 'o')
renderonce = !renderonce;
#ifndef PANDORA
else if(uni == 'g')
rendernogl = !rendernogl;
#endif
else if(uni == 's') {
texturesize *= 2;
if(texturesize == 8192) texturesize = 128;
dialog::scaleLog();
}
else if(doexiton(sym, uni))
cmode = emChangeMode;
"Use arrow keys to rotate, Page Up/Down to zoom."
);
else if(uni == 'u') {
if(sphere) restartGame('E');
if(euclid) restartGame('e');
rug::init();
popScreen();
}
else if(uni == 'o')
renderonce = !renderonce;
#ifndef PANDORA
else if(uni == 'g')
rendernogl = !rendernogl;
#endif
else if(uni == 's') {
texturesize *= 2;
if(texturesize == 8192) texturesize = 128;
dialog::scaleLog();
}
else if(doexiton(sym, uni)) popScreen();
};
}
void select() {
if(rug::rugged) rug::close();
else cmode = emRugConfig;
else pushScreen(rug::show);
}
}

288
scores.cpp Normal file
View File

@ -0,0 +1,288 @@
#ifndef NOSAVE
vector<score> scores;
int scoresort = 2;
int scoredisplay = 1;
int scorefrom = 0;
int scoremode = 0;
bool scorerev = false;
bool scorecompare(const score& s1, const score &s2) {
return s1.box[scoresort] > s2.box[scoresort];
}
bool fakescore() {
return fakebox[scoredisplay];
}
string displayfor(score* S) {
// printf("S=%p, scoredisplay = %d\n", S, scoredisplay);
if(S == NULL) {
return XLATN(boxname[scoredisplay]);
}
if(scoredisplay == 0) {
char buf[10];
snprintf(buf, 10, "%d:%02d", S->box[0]/60, S->box[0]%60);
return buf;
}
if(scoredisplay == 1) {
time_t tim = S->box[1];
char buf[128]; strftime(buf, 128, "%c", localtime(&tim));
return buf;
}
return its(S->box[scoredisplay]);
}
void loadScores() {
scores.clear();
FILE *f = fopen(scorefile, "rt");
if(!f) {
printf("Could not open the score file '%s'!\n", scorefile);
addMessage(s0 + "Could not open the score file: " + scorefile);
return;
}
while(!feof(f)) {
char buf[120];
if(fgets(buf, 120, f) == NULL) break;
if(buf[0] == 'H' && buf[1] == 'y') {
score sc; bool ok = true;
{if(fscanf(f, "%s", buf) <= 0) break;} sc.ver = buf;
for(int i=0; i<MAXBOX; i++) {
if(fscanf(f, "%d", &sc.box[i]) <= 0) { boxid = i; break; }
}
for(int i=boxid; i<MAXBOX; i++) sc.box[i] = 0;
if(sc.ver >= "4.4") {
sc.box[0] = sc.box[65];
// the first executable on Steam included a corruption
if(sc.box[65] > 1420000000 && sc.box[65] < 1430000000) {
sc.box[0] = sc.box[65] - sc.box[1];
sc.box[65] = sc.box[0];
}
// do not include saves
if(sc.box[65 + 4 + itOrbSafety - itOrbLightning]) ok = false;
}
else
sc.box[0] = sc.box[1] - sc.box[0]; // could not save then
if(ok && boxid > 20) scores.push_back(sc);
}
}
fclose(f);
addMessage(its(size(scores))+" games have been recorded in "+scorefile);
pushScreen(showScores);
boxid = 0; applyBoxes();
scoresort = 2; reverse(scores.begin(), scores.end());
scoremode = 0;
if(shmup::on) scoremode = 1;
else if(hardcore) scoremode = 2;
scorefrom = 0;
stable_sort(scores.begin(), scores.end(), scorecompare);
#ifdef MOBILE
extern int andmode;
andmode = 2;
#endif
}
vector<pair<string, int> > pickscore_options;
void sortScores() {
if(scorerev) reverse(scores.begin(), scores.end());
else {
scorerev = true;
scoresort = scoredisplay;
stable_sort(scores.begin(), scores.end(), scorecompare);
}
}
void shiftScoreDisplay(int delta) {
scoredisplay = (scoredisplay + POSSCORE + delta) % POSSCORE, scorerev = false;
if(fakescore()) shiftScoreDisplay(delta);
}
void showScores() {
int y = vid.fsize * 7/2;
int bx = vid.fsize;
getcstat = 1;
string modes =
scoremode == 0 ? XLAT(", m - mode: normal") :
scoremode == 1 ? XLAT(", m - mode: shoot'em up") :
scoremode == 2 ? XLAT(", m - mode: hardcore only") :
"?";
if(euclid) modes += XLAT(" (E:%1)", euclidland);
mouseovers = XLAT("t/left/right - change display, up/down - scroll, s - sort by") + modes;
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;
int rank = 0;
while(y < (ISMOBILE ? vid.yres - 5*vid.fsize : vid.yres - 2 * vid.fsize)) {
if(id >= size(scores)) break;
score& S(scores[id]);
bool wrongtype = false;
wrongtype |= (euclid && (!S.box[116] || S.box[120] != euclidland));
wrongtype |= (!euclid && S.box[116]);
wrongtype |= (scoremode == 1 && !S.box[119]);
wrongtype |= (scoremode != 1 && S.box[119]);
wrongtype |= (scoremode == 2 && (!S.box[117] || S.box[118] >= PUREHARDCORE_LEVEL));
if(wrongtype) { id++; continue; }
if(omit) { omit--; rank++; id++; continue; }
char buf[16];
rank++; sprintf(buf, "%d", rank);
displaystr(bx*4, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
sprintf(buf, "%d", S.box[2]);
displaystr(bx*8, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
sprintf(buf, "%d", S.box[3]);
displaystr(bx*12, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
sprintf(buf, "%d:%02d", S.box[0]/60, S.box[0] % 60);
displaystr(bx*18, y, 0, vid.fsize, buf, 0xC0C0C0, 16);
displaystr(bx*22, y, 0, vid.fsize, S.ver, 0xC0C0C0, 16);
displaystr(bx*23, y, 0, vid.fsize, displayfor(&S), 0xC0C0C0, 0);
y += vid.fsize*5/4; id++;
}
#ifdef MOBILE
buttonclicked = false;
displayabutton(-1, +1, XLAT("SORT"), BTON);
displayabutton( 0, +1, XLAT("PICK"), BTON);
displayabutton(+1, +1, XLAT("PLAY"), BTON);
#endif
keyhandler = [] (int sym, int uni) {
#ifndef MOBILE
if(sym == SDLK_LEFT || sym == SDLK_KP4 || sym == 'h' || sym == 'a')
shiftScoreDisplay(-1);
else if(sym == SDLK_RIGHT || sym == SDLK_KP6 || sym == 'l' || sym == 'd')
shiftScoreDisplay(1);
else if(sym == 't') { mapeditor::infix = ""; pushScreen(showPickScores); }
else if(sym == SDLK_UP || sym == 'k' || sym == 'w')
scorefrom -= 5;
else if(sym == SDLK_DOWN || sym == 'j' || sym == 'x')
scorefrom += 5;
else if(sym == PSEUDOKEY_WHEELUP)
scorefrom--;
else if(sym == PSEUDOKEY_WHEELDOWN)
scorefrom++;
else if(sym == 's') sortScores();
else if(sym == 'm') { scoremode++; scoremode %= 3; }
else if(doexiton(sym, uni)) popScreen();
#else
static int scoredragx, scoredragy;
extern bool clicked, lclicked;
extern int andmode;
if(andmode) {
if(!clicked && !lclicked) {
andmode = 0;
scoredragx = mousex;
scoredragy = mousey;
}
}
else {
if(clicked && !lclicked)
scoredragx = mousex, scoredragy = mousey;
else if(lclicked && !clicked) {
if(mousey > vid.ycenter - 2 * vid.fsize) {
if(mousex < vid.xcenter*2/3) sortScores();
else if(mousex < vid.xcenter*4/3)
cmode = emPickScores;
else andmode = 0, popScreen();
}
}
else if(clicked && lclicked) {
// if(mousex > scoredragx + 80) scoredragx += 80, shiftScoreDisplay(1);
// if(mousex < scoredragx - 80) scoredragx -= 80, shiftScoreDisplay(-1);
while(mousey > scoredragy + vid.fsize) scoredragy += vid.fsize, scorefrom--;
while(mousey < scoredragy - vid.fsize) scoredragy -= vid.fsize, scorefrom++;
}
}
#endif
};
}
bool monsterpage = false;
void showPickScores() {
getcstat = '0';
int d = scoredisplay;
pickscore_options.clear();
scorerev = false;
for(int i=0; i<POSSCORE; i++) {
scoredisplay = i;
if(!fakescore()) {
string s = displayfor(NULL);
if(mapeditor::hasInfix(s))
if(monsbox[scoredisplay] == monsterpage)
pickscore_options.push_back(make_pair(s, i));
}
}
sort(pickscore_options.begin(), pickscore_options.end());
int q = (int) pickscore_options.size();
int percolumn = vid.yres / (vid.fsize+3) - 4;
int columns = 1 + (q-1) / percolumn;
for(int i=0; i<q; i++) {
int x = 16 + (vid.xres * (i/percolumn)) / columns;
int y = (vid.fsize+3) * (i % percolumn) + vid.fsize*2;
scoredisplay = pickscore_options[i].second;
if(q <= 9)
pickscore_options[i].first = pickscore_options[i].first + " [" + its(i+1) + "]";
if(!fakescore())
displayButton(x, y, pickscore_options[i].first, 1000+i, 0);
}
displayButton(vid.xres/2, vid.yres - vid.fsize*2, "kills", 'm', 8);
scoredisplay = d;
mouseovers = mapeditor::infix;
keyhandler = [] (int sym, int uni) {
extern int andmode;
andmode = 2;
if(uni == 'm') monsterpage = !monsterpage; else
if(uni >= '1' && uni <= '9') uni = uni + 1000 - '1';
else if(uni >= 1000 && uni < 1000 + size(pickscore_options)) {
scoredisplay = pickscore_options[uni - 1000].second;
popScreen();
}
else if(mapeditor::editInfix(uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
#endif

View File

@ -4,12 +4,6 @@
// implementation of the shoot'em up mode
#ifdef MOBILE
#define SHMUPTITLE "shoot'em up mode"
#else
#define SHMUPTITLE "shoot'em up and multiplayer"
#endif
extern int mousex, mousey;
extern bool clicked;
@ -215,6 +209,8 @@ bool shmupcfg;
bool configdead;
void handleConfig(int sym, int uni);
void showShmupConfig() {
#ifndef NOSDL
@ -362,6 +358,8 @@ void showShmupConfig() {
dialog::display();
}
keyhandler = handleConfig;
#endif
}
@ -380,7 +378,7 @@ void handleConfig(int sym, int uni) {
else if(uni == '7') vid.scfg.subconfig = 8;
else if(uni == 'j') vid.scfg.subconfig = SCJOY;
else if(uni == 'a') multi::alwaysuse = !multi::alwaysuse;
else if(uni == 'b') cmode = emJoyConfig;
else if(uni == 'b') pushScreen(showJoyConfig);
else if(uni == 'r')
for(int i=0; i<MAXPLAYER; i++)
kills[i] = deaths[i] = treasures[i] = 0;
@ -396,20 +394,7 @@ void handleConfig(int sym, int uni) {
if(vid.scfg.players <= 0) vid.scfg.players += MAXPLAYER;
}
else if(sym == SDLK_F1 || uni == '?' || uni == 'h') {
lastmode = cmode;
cmode = emHelp;
/* help =
"In the shmup (shoot'em up) mode, you can play a hyperbolic shoot'em up "
"game. The game is based on the usual turn-based grid-based HyperRogue, "
"but there are some changes. You fight by throwing knives, and you "
"have three extra lives. There are no friendly monsters, so Orbs of "
"Life and Friendship give you extra lives instead. Some other rules have been "
"adapted too.\n\n"
"It is possible for two players to play the shmup mode cooperatively "
"(locally). When playing together, lives, orbs, and treasures are shared, "
"knives recharge slower, orbs drain faster, and player characters are not "
"allowed to separate."; */
gotoHelp("");
help =
XLAT(
@ -438,8 +423,8 @@ help += XLATN(iinf[itOrbSafety].name); help += "\n\n";
help += XLAT("This menu can be also used to configure keys.\n\n");
}
else if(uni || sym == SDLK_F10) {
cmode = emNormal;
else if(doexiton(sym, uni)) {
popScreen();
if(shmup::on != shmupcfg) { restartGame('s'); resetScores(); }
else if(vid.scfg.players != players) { restartGame(); resetScores(); }
}
@ -3334,9 +3319,24 @@ void virtualRebase(cell*& base, transmatrix& at, bool tohex) {
void virtualRebase(shmup::monster *m, bool tohex) {
virtualRebase(m->base, m->at, tohex);
}
}
void addShmupHelp(string& out) {
if(shmup::mousetarget && intval(mouseh, tC0(shmup::mousetarget->pat)) < .1) {
out += ", ";
#ifdef ROGUEVIZ
#include "rogueviz.cpp"
if(shmup::mousetarget->type == moRogueviz) {
help = XLAT(minf[shmup::mousetarget->type].help);
out += rogueviz::describe(shmup::mousetarget);
}
else
#endif
{
out += XLAT1(minf[shmup::mousetarget->type].name);
help = generateHelpForMonster(shmup::mousetarget->type);
}
}
}
auto hooks = addHook(clearmemory, 0, shmup::clearMemory);
}

View File

@ -65,13 +65,13 @@ int musfadeval = 2000;
eLand cid = laNone;
hookset<bool(eLand)> *hooks_music;
void handlemusic() {
DEBB(DF_GRAPH, (debugfile,"handle music\n"));
if(audio && musicvolume) {
eLand id = getCurrentLandForMusic();
#ifdef EXTRA_MUSIC
if(extra::changemusic(id)) return;
#endif
if(callhandlers(false, hooks_music, id)) return;
if(outoffocus) id = eLand(0);
if(musfname[id] == "LAST") id = cid;
if(!loaded[id]) {

View File

@ -925,6 +925,7 @@ namespace gamestack {
};
void restartGame(char switchWhat, bool push) {
popScreenAll();
DEBB(DF_INIT, (debugfile,"restartGame\n"));
if(push)
@ -1061,41 +1062,6 @@ void restartGame(char switchWhat, bool push) {
resetmusic();
}
void clearGameMemory() {
#ifdef HASLINEVIEW
conformal::renderAutoband();
conformal::on = false;
#endif
DEBB(DF_INIT, (debugfile,"clearGameMemory\n"));
pathq.clear();
dcal.clear();
yendor::yii = NOYENDOR; yendor::yi.clear();
clearshadow();
offscreen.clear();
princess::clear();
buggycells.clear();
mirrors.clear();
clearing::bpdata.clear();
tortoise::emap.clear();
tortoise::babymap.clear();
seenSevenMines = false;
#ifdef HASLINEVIEW
conformal::killhistory.clear();
conformal::findhistory.clear();
conformal::movehistory.clear();
conformal::includeHistory = false;
#endif
recallCell = NULL;
prairie::lasttreasure = NULL;
prairie::enter = NULL;
prairie::tchoices.clear();
prairie::beaststogen.clear();
butterflies.clear();
#ifdef ROGUEVIZ
rogueviz::close();
#endif
}
static int orbid = 0;
eItem nextOrb() {
@ -1222,7 +1188,6 @@ bool applyCheat(char u, cell *c = NULL) {
items[itOrbShield] += 1;
cheater++; addMessage(XLAT("Orb power gained!"));
canmove = true;
if(cmode == emQuit) cmode = emNormal;
}
return true;
}
@ -1235,12 +1200,12 @@ bool applyCheat(char u, cell *c = NULL) {
#ifndef NOEDIT
if(u == 'A') {
lastexplore = turncount;
cmode = emMapEditor;
pushScreen(mapeditor::showMapEditor);
return true;
}
if(u == 'A'-64) {
mapeditor::drawcell = mouseover ? mouseover : cwt.c;
cmode = emDraw;
pushScreen(mapeditor::showDrawEditor);
return true;
}
#endif
@ -1366,7 +1331,7 @@ bool applyCheat(char u, cell *c = NULL) {
return true;
}
if(u == 'W'-64) {
cmode = emLinepattern;
pushScreen(linepatterns::showMenu);
return true;
}
if(u == 'G'-64) {
@ -1423,3 +1388,19 @@ bool applyCheat(char u, cell *c = NULL) {
return false;
}
purehookset clearmemory;
void clearMemory() {
callhooks(clearmemory);
}
auto cgm = addHook(clearmemory, 40, [] () {
pathq.clear();
dcal.clear();
clearshadow();
seenSevenMines = false;
recallCell = NULL;
butterflies.clear();
buggycells.clear();
});

View File

@ -72,21 +72,20 @@ void presentation(presmode mode) {
}
void slidehelp() {
if(texts && slides[currentslide].help[0]) {
help =
helptitle(XLAT(slides[currentslide].name), 0xFF8000) +
XLAT(slides[currentslide].help);
if(cmode != emHelp)
lastmode = cmode;
cmode = emHelp;
}
if(texts && slides[currentslide].help[0])
gotoHelp(
help =
helptitle(XLAT(slides[currentslide].name), 0xFF8000) +
XLAT(slides[currentslide].help)
);
}
bool handleKeyTour(int sym, int uni) {
bool normode = (cmode == emHelp || cmode == emNormal || cmode == emQuit);
if(!normode) return false;
if(!tour::on) return false;
if(!cmode2) return false;
int flags = slides[currentslide].flags;
if((sym == SDLK_RETURN || sym == SDLK_KP_ENTER) && (cmode != emHelp || (flags & QUICKSKIP))) {
if((sym == SDLK_RETURN || sym == SDLK_KP_ENTER) && (cmode2 != smHelp || (flags & QUICKSKIP))) {
if(cmode2) popScreen();
if(geometry || purehepta) {
restartGame(0, false);
if(!(flags & QUICKGEO)) return true;
@ -106,7 +105,7 @@ bool handleKeyTour(int sym, int uni) {
if(currentslide == 0) { slidehelp(); return true; }
presentation(pmStop);
currentslide--;
if(cmode == emHelp) slidehelp();
if(cmode2 == smHelp) popScreen(), slidehelp();
presentation(pmStart);
return true;
}
@ -164,7 +163,7 @@ bool handleKeyTour(int sym, int uni) {
return true;
}
if(sym == '4') {
cmode = emNormal;
popScreenAll();
if(items[itOrbTeleport]) goto give_aether;
items[itOrbTeleport] = 1;
checkmove();
@ -214,15 +213,15 @@ bool handleKeyTour(int sym, int uni) {
return true;
}
if(sym == '9') {
cmode = emSlideshows;
pushScreen(ss::showMenu);
return true;
}
return false;
}
void checkGoodLand(eLand l) {
if(!showland(l) && texts) {
help = XLAT(
if(!showland(l) && texts)
gotoHelp(XLAT(
"This tutorial is different than most other game tutorials -- "
"you are not forced to do anything, and you can go wherever you want.\n\n"
"However, %the1 is not what we are talking about now. "
@ -230,9 +229,7 @@ void checkGoodLand(eLand l) {
"get lost there.\n\n"
"Remember that you can get to the next slide by pressing Enter.",
l
);
cmode = emHelp;
}
));
}
namespace ss {
@ -260,42 +257,38 @@ namespace ss {
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);
keyhandler = [] (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';
popScreenAll();
presentation(pmStart);
slidehelp();
}
if(slides != wts) {
while(tour::on) restartGame('T', false);
slides = wts;
tour::start();
else if(uni == '1') {
list(wts);
for(int i=0; i<size(slideshows)-1; i++) if(slideshows[i] == wts) {
wts = slideshows[i+1]; return;
}
wts = slideshows[0];
}
presentation(pmStop);
currentslide = uni - 'a';
cmode = emNormal;
presentation(pmStart);
slidehelp();
}
else if(uni == '1') {
list(wts);
for(int i=0; i<size(slideshows)-1; i++) if(slideshows[i] == wts) {
wts = slideshows[i+1]; return;
}
wts = slideshows[0];
}
else if(doexiton(sym, uni)) { wts = NULL; cmode = emNormal; }
else if(doexiton(sym, uni)) { wts = NULL; popScreen(); }
};
}
}
void start() {
ss::list(default_slides);
#ifdef ROGUEVIZ
ss::list(rogueviz::rvtour::rvslides);
#endif
currentslide = 0;
vid.scale = 1;
vid.alpha = 1;
@ -760,4 +753,8 @@ slide default_slides[] = {
slide *slides = default_slides;
auto a1 = addHook(hooks_frame, 100, [] () { if(tour::on) tour::presentation(tour::pmFrame); });
auto a2 = addHook(hooks_handleKey, 100, handleKeyTour);
auto a3 = addHook(hooks_nextland, 100, [] (eLand l) { return tour::on ? getNext(l) : laNone; });
}

View File

@ -23,6 +23,7 @@ typedef long double ld;
#define ASINH asinhl
#endif
long double sqr(long double x) { return x*x; }
template<class T> int size(const T& x) {return int(x.size()); }
string its(int i) { char buf[64]; sprintf(buf, "%d", i); return buf; }
string fts(float x) { char buf[64]; sprintf(buf, "%4.2f", x); return buf; }

View File

@ -412,6 +412,31 @@ namespace yendor {
};
vector<scoredata> scoreboard;
const char *chelp =
"There are many possible solutions to the Yendor Quest. In the Yendor "
"Challenge, you will try many of them!\n\n"
"Each challenge takes part in a specific land, and you have to use what "
"you have available.\n\n"
"You need to obtain an Orb of Yendor in the normal game to activate "
"this challenge, and (ever) collect 10 treasures in one or two lands "
"to activate a specific level.\n\n"
"After you complete each challenge, you can try it again, on a harder "
"difficulty level.\n\n"
"All the solutions showcased in the Yendor Challenge work in the normal "
"play too. However, passages to other lands, and (sometimes) some land features "
"are disabled in the Yendor "
"Challenge, so that you have to use the expected method. Also, "
"the generation rules are changed slightly for the Palace "
"and Minefield while you are looking for the Orb of Yendor, "
"to make the challenge more balanced "
"(but these changes are also active during the normal Yendor Quest).\n\n"
"You get 1000 points for each challenge won, and 1 extra point for "
"each extra difficulty level.";
void showMenu() {
int s = vid.fsize;
vid.fsize = vid.fsize * 4/5;
@ -475,57 +500,28 @@ namespace yendor {
yendor::uploadScore();
vid.fsize = s;
}
const char *chelp =
"There are many possible solutions to the Yendor Quest. In the Yendor "
"Challenge, you will try many of them!\n\n"
"Each challenge takes part in a specific land, and you have to use what "
"you have available.\n\n"
"You need to obtain an Orb of Yendor in the normal game to activate "
"this challenge, and (ever) collect 10 treasures in one or two lands "
"to activate a specific level.\n\n"
"After you complete each challenge, you can try it again, on a harder "
"difficulty level.\n\n"
"All the solutions showcased in the Yendor Challenge work in the normal "
"play too. However, passages to other lands, and (sometimes) some land features "
"are disabled in the Yendor "
"Challenge, so that you have to use the expected method. Also, "
"the generation rules are changed slightly for the Palace "
"and Minefield while you are looking for the Orb of Yendor, "
"to make the challenge more balanced "
"(but these changes are also active during the normal Yendor Quest).\n\n"
"You get 1000 points for each challenge won, and 1 extra point for "
"each extra difficulty level.";
void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni >= 'a' && uni < 'a'+YENDORLEVELS-1) {
challenge = uni-'a' + 1;
if(levelUnlocked(challenge) || autocheat) {
restartGame(yendor::on ? 0 : 'y');
cmode = emNormal;
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(uni >= 'a' && uni < 'a'+YENDORLEVELS-1) {
challenge = uni-'a' + 1;
if(levelUnlocked(challenge) || autocheat) {
restartGame(yendor::on ? 0 : 'y');
popScreen();
}
else
addMessage("Collect 10 treasures in various lands to unlock the challenges there");
}
else
addMessage("Collect 10 treasures in various lands to unlock the challenges there");
}
else if(uni == '0') {
if(yendor::on) restartGame('y');
cmode = emNormal;
}
else if(uni == '1') easy = !easy;
else if(uni == '2' || sym == SDLK_F1) {
lastmode = cmode;
cmode = emHelp;
help = chelp;
}
else if(doexiton(sym, uni)) cmode = emNormal;
else if(uni == '0') {
if(yendor::on) restartGame('y');
popScreen();
}
else if(uni == '1') easy = !easy;
else if(uni == '2' || sym == SDLK_F1) gotoHelp(chelp);
else if(doexiton(sym, uni)) popScreen();
};
}
void collected(cell* c2) {
int pg = gold();
playSound(c2, "tada");
@ -565,6 +561,10 @@ namespace yendor {
achievement_collection(itOrbYendor, pg, gold());
achievement_victory(false);
}
auto hooks = addHook(clearmemory, 0, [] () {
yendor::yii = NOYENDOR; yendor::yi.clear();
});
};
#define MAXTAC 20
@ -738,23 +738,20 @@ namespace tactic {
}
displayScore(scorehere, xr * 50);
}
}
keyhandler = [] (int sym, int uni) {
if(uni >= 1000 && uni < 1000 + LAND_TAC) {
firstland = euclidland = getLandById(uni - 1000);
restartGame(tactic::on ? 0 : 't');
popScreen();
}
else if(uni == '0') {
popScreen();
firstland = laIce;
if(tactic::on) restartGame('t');
}
void handleKey(int sym, int uni) {
if(uni >= 1000 && uni < 1000 + LAND_TAC) {
firstland = euclidland = getLandById(uni - 1000);
restartGame(tactic::on ? 0 : 't');
cmode = emNormal;
}
else if(uni == '0') {
cmode = emNormal;
firstland = laIce;
if(tactic::on) restartGame('t');
}
else if(sym == SDLK_F1) {
lastmode = cmode;
cmode = emHelp;
help =
else if(sym == SDLK_F1) gotoHelp(
"In the pure tactics mode, you concentrate on a specific land. "
"Your goal to obtain as high score as possible, without using "
"features of the other lands. You can then compare your score "
@ -775,12 +772,13 @@ namespace tactic {
"The rate of treasure spawn is static in this mode. It is not "
"increased by killing monsters.\n\n"
"Good luck, and have fun!";
}
else if(dialog::handlePageButtons(uni)) ;
else if(doexiton(sym, uni)) cmode = emNormal;
"Good luck, and have fun!"
);
else if(dialog::handlePageButtons(uni)) ;
else if(doexiton(sym, uni)) popScreen();
};
}
};
int modecodetable[42][6] = {
@ -931,6 +929,7 @@ namespace peace {
int qty;
eLand getNext(eLand last) {
if(!peace::on) return laNone;
if(isElemental(last) && hrand(100) < 90)
return laNone;
else if(createOnSea(last))
@ -949,23 +948,6 @@ namespace peace {
return false;
}
void showMenu() {
dialog::init(XLAT(otherpuzzles ? "hyperbolic puzzles" : "memory game"), 0x40A040, 150, 100);
levellist = otherpuzzles ? explorelevels : simonlevels;
for(qty = 0; levellist[qty]; qty++)
dialog::addItem(XLAT1(linf[levellist[qty]].name), 'a'+qty);
dialog::addBreak(100);
dialog::addItem(XLAT(otherpuzzles ? "memory game" : "other hyperbolic puzzles"), '1');
dialog::addBoolItem(XLAT("display hints"), hint, '2');
dialog::addItem(XLAT("Help"), SDLK_F1);
dialog::addItem(XLAT("Return to the normal game"), '0');
dialog::display();
}
const char *chelp = NODESCYET;
namespace simon {
@ -1043,26 +1025,41 @@ namespace peace {
}
}
void handleKey(int sym, int uni) {
dialog::handleNavigation(sym, uni);
void showMenu() {
dialog::init(XLAT(otherpuzzles ? "hyperbolic puzzles" : "memory game"), 0x40A040, 150, 100);
levellist = otherpuzzles ? explorelevels : simonlevels;
for(qty = 0; levellist[qty]; qty++)
dialog::addItem(XLAT1(linf[levellist[qty]].name), 'a'+qty);
dialog::addBreak(100);
dialog::addItem(XLAT(otherpuzzles ? "memory game" : "other hyperbolic puzzles"), '1');
dialog::addBoolItem(XLAT("display hints"), hint, '2');
dialog::addItem(XLAT("Help"), SDLK_F1);
dialog::addItem(XLAT("Return to the normal game"), '0');
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;
dialog::display();
keyhandler = [] (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');
popScreen();
}
else if(uni == '2') { hint = !hint; popScreen(); }
else if(uni == '0') {
firstland = laIce;
if(peace::on) restartGame('P');
popScreen();
}
else if(uni == 'h' || sym == SDLK_F1) gotoHelp(chelp);
else if(doexiton(sym, uni)) popScreen();
};
}
auto aNext = addHook(hooks_nextland, 100, getNext);
};