2018-02-08 23:40:26 +00:00
|
|
|
// Hyperbolic Rogue
|
|
|
|
// This is the main file when the online version of HyperRogue is compiled with Emscripten.
|
|
|
|
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
|
|
|
|
|
2017-07-22 23:33:27 +00:00
|
|
|
#define ISWEB 1
|
2019-05-06 23:24:43 +00:00
|
|
|
#define ISMINI 0
|
2017-08-13 18:49:38 +00:00
|
|
|
#define CAP_AUDIO 0
|
|
|
|
#define CAP_SDLGFX 0
|
|
|
|
#define CAP_PNG 0
|
|
|
|
#define CAP_TOUR 1
|
2017-07-22 23:33:27 +00:00
|
|
|
#define CAP_SDLTTF 0
|
2017-08-13 18:49:38 +00:00
|
|
|
#define CAP_SHMUP 0
|
2018-02-03 13:31:17 +00:00
|
|
|
#define CAP_RUG 1
|
2018-02-11 20:39:47 +00:00
|
|
|
#define CAP_INV 0
|
2018-09-05 13:34:13 +00:00
|
|
|
#define CAP_URL 1
|
2018-02-11 18:08:17 +00:00
|
|
|
#define GLES_ONLY
|
2020-05-22 18:38:02 +00:00
|
|
|
#define CAP_COMPLEX2 1
|
2017-03-23 10:53:57 +00:00
|
|
|
|
2019-09-13 15:46:07 +00:00
|
|
|
#if CAP_ROGUEVIZ
|
|
|
|
#define MAXMDIM 4
|
|
|
|
#else
|
|
|
|
#define MAXMDIM 3
|
|
|
|
#endif
|
|
|
|
|
2019-07-12 21:25:17 +00:00
|
|
|
// we want newconformist, but we don't want CAP_GD there
|
|
|
|
#define CAP_NCONF 1
|
|
|
|
#define CAP_GD 0
|
|
|
|
|
|
|
|
#ifndef EMSCRIPTEN
|
|
|
|
#define EMSCRIPTEN
|
|
|
|
#endif
|
|
|
|
|
2017-03-23 10:53:57 +00:00
|
|
|
#ifdef FAKEWEB
|
2018-06-10 23:58:31 +00:00
|
|
|
namespace hr { void mainloopiter(); }
|
2017-03-23 10:53:57 +00:00
|
|
|
template<class A, class B, class C> void emscripten_set_main_loop(A a, B b, C c) { while(true) mainloopiter(); }
|
|
|
|
#else
|
|
|
|
#include <emscripten.h>
|
2018-02-11 20:39:47 +00:00
|
|
|
#include <emscripten/html5.h>
|
2017-03-23 10:53:57 +00:00
|
|
|
#endif
|
|
|
|
|
2018-06-13 22:06:54 +00:00
|
|
|
#include <string>
|
|
|
|
|
2018-06-10 23:58:31 +00:00
|
|
|
namespace hr {
|
|
|
|
void initweb();
|
|
|
|
void emscripten_get_commandline();
|
2017-03-23 10:53:57 +00:00
|
|
|
|
2018-06-10 23:58:31 +00:00
|
|
|
void loadCompressedChar(int &otwidth, int &otheight, int *tpix);
|
2017-03-23 10:53:57 +00:00
|
|
|
|
2018-06-10 23:58:31 +00:00
|
|
|
const char *wheresounds;
|
2020-01-19 10:49:49 +00:00
|
|
|
|
|
|
|
std::string get_value(std::string name);
|
2020-09-21 10:00:52 +00:00
|
|
|
|
|
|
|
void offer_download(std::string sfilename, std::string smimetype);
|
2018-06-10 23:58:31 +00:00
|
|
|
}
|
2017-04-15 02:48:59 +00:00
|
|
|
|
2019-09-13 01:47:55 +00:00
|
|
|
#include "hyper.cpp"
|
2018-06-13 22:06:54 +00:00
|
|
|
|
2018-06-10 23:58:31 +00:00
|
|
|
namespace hr {
|
2017-03-23 10:53:57 +00:00
|
|
|
|
2020-01-19 10:49:49 +00:00
|
|
|
string get_value(string name) {
|
|
|
|
char *str = (char*)EM_ASM_INT({
|
|
|
|
var name = UTF8ToString($0, $1);
|
|
|
|
var value = document.getElementById(name).value;
|
|
|
|
var lengthBytes = lengthBytesUTF8(value)+1;
|
|
|
|
var stringOnWasmHeap = _malloc(lengthBytes);
|
|
|
|
stringToUTF8(value, stringOnWasmHeap, lengthBytes);
|
|
|
|
return stringOnWasmHeap;
|
|
|
|
}, name.c_str(), int(name.size())
|
|
|
|
);
|
|
|
|
string res = str;
|
|
|
|
free(str);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2020-09-21 10:00:52 +00:00
|
|
|
void offer_download(string sfilename, string smimetype) {
|
|
|
|
|
|
|
|
EM_ASM({
|
|
|
|
var name = UTF8ToString($0, $1);
|
|
|
|
var mime = UTF8ToString($2, $3);
|
|
|
|
|
|
|
|
let content = Module.FS.readFile(name);
|
|
|
|
console.log(`Offering download of "${name}", with ${content.length} bytes...`);
|
|
|
|
|
|
|
|
var a = document.createElement('a');
|
|
|
|
a.download = name;
|
|
|
|
a.href = URL.createObjectURL(new Blob([content], {type: mime}));
|
|
|
|
a.style.display = 'none';
|
|
|
|
|
|
|
|
document.body.appendChild(a);
|
|
|
|
a.click();
|
|
|
|
setTimeout(() => {
|
|
|
|
document.body.removeChild(a);
|
|
|
|
URL.revokeObjectURL(a.href);
|
|
|
|
}, 2000);
|
|
|
|
}, sfilename.c_str(), isize(sfilename), smimetype.c_str(), isize(smimetype)
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
reaction_t on_use_file = [] {};
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
void use_file() {
|
|
|
|
on_use_file();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void offer_choose_file(reaction_t r) {
|
|
|
|
on_use_file = r;
|
|
|
|
EM_ASM({
|
|
|
|
fileElem.click();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-08-13 18:49:38 +00:00
|
|
|
// -- demo --
|
|
|
|
|
2019-08-09 19:00:52 +00:00
|
|
|
#if CAP_URL
|
|
|
|
EX void open_url(string s) {
|
2018-09-05 13:34:13 +00:00
|
|
|
EM_ASM_({
|
2019-06-01 15:03:16 +00:00
|
|
|
window.open(UTF8ToString($0, 1000));
|
2018-09-05 13:34:13 +00:00
|
|
|
}, s.c_str());
|
|
|
|
}
|
2019-08-09 19:00:52 +00:00
|
|
|
#endif
|
2019-06-01 15:03:16 +00:00
|
|
|
|
|
|
|
// window.open(Pointer_stringify($0));
|
2017-08-13 18:49:38 +00:00
|
|
|
bool demoanim;
|
|
|
|
|
|
|
|
void toggleanim(bool v) {
|
|
|
|
demoanim = v;
|
|
|
|
if(v) {
|
2018-04-09 13:55:43 +00:00
|
|
|
sightrange_bonus = -3;
|
2017-08-13 18:49:38 +00:00
|
|
|
vid.wallmode = 5;
|
|
|
|
vid.particles = true;
|
|
|
|
vid.sspeed = -1;
|
|
|
|
vid.mspeed = -1;
|
2019-06-01 15:03:33 +00:00
|
|
|
vid.highdetail = vid.middetail = 5;
|
2017-08-13 18:49:38 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-04-09 13:55:43 +00:00
|
|
|
sightrange_bonus = 0;
|
2017-08-13 18:49:38 +00:00
|
|
|
vid.sspeed = 5;
|
|
|
|
vid.mspeed = 5;
|
|
|
|
vid.particles = false;
|
|
|
|
vid.wallmode = 3;
|
2019-06-01 15:03:33 +00:00
|
|
|
vid.highdetail = vid.middetail = -1;
|
2017-08-13 18:49:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void showDemo() {
|
|
|
|
gamescreen(2);
|
|
|
|
|
|
|
|
getcstat = ' ';
|
|
|
|
|
|
|
|
dialog::init(XLAT("HyperRogue %1: online demo", VER), 0xC00000, 200, 100);
|
|
|
|
dialog::addBreak(50);
|
|
|
|
|
2018-10-23 15:06:47 +00:00
|
|
|
dialog::addItem(XLAT("play the game"), 'f');
|
|
|
|
dialog::addItem(XLAT("learn about hyperbolic geometry"), 'T');
|
2019-09-12 22:31:54 +00:00
|
|
|
dialog::addHelp();
|
2018-02-11 18:08:17 +00:00
|
|
|
// dialog::addItem(XLAT("toggle high detail"), 'a');
|
2017-08-13 18:49:38 +00:00
|
|
|
dialog::addBreak(100);
|
|
|
|
|
|
|
|
dialog::addTitle("highlights", 0xC00000, 120);
|
|
|
|
dialog::addItem(XLAT("Temple of Cthulhu"), 't');
|
|
|
|
dialog::addItem(XLAT("Land of Storms"), 'l');
|
|
|
|
dialog::addItem(XLAT("Burial Grounds"), 'b');
|
|
|
|
|
|
|
|
dialog::display();
|
|
|
|
|
|
|
|
keyhandler = [] (int sym, int uni) {
|
|
|
|
dialog::handleNavigation(sym, uni);
|
2018-12-06 11:31:51 +00:00
|
|
|
if(sym == SDLK_F1 || uni == 'h') gotoHelp(help);
|
|
|
|
else if(uni == 'a') {
|
2017-08-13 18:49:38 +00:00
|
|
|
toggleanim(!demoanim);
|
|
|
|
popScreen();
|
|
|
|
}
|
2018-12-06 11:31:51 +00:00
|
|
|
else if(uni == 'f') {
|
2017-08-13 18:49:38 +00:00
|
|
|
firstland = laIce;
|
2018-06-10 22:58:38 +00:00
|
|
|
restart_game(tactic::on ? rg::tactic : rg::nothing);
|
2017-08-13 18:49:38 +00:00
|
|
|
}
|
|
|
|
#if CAP_TOUR
|
2018-12-06 11:31:51 +00:00
|
|
|
else if(uni == 'T') {
|
2017-08-13 18:49:38 +00:00
|
|
|
firstland = laIce;
|
|
|
|
if(!tour::on) tour::start();
|
|
|
|
}
|
|
|
|
#endif
|
2018-12-06 11:31:51 +00:00
|
|
|
else if(uni == 't') {
|
2017-08-13 18:49:38 +00:00
|
|
|
firstland = laTemple;
|
2018-06-10 22:58:38 +00:00
|
|
|
restart_game(tactic::on ? rg::tactic : rg::nothing);
|
2017-08-13 18:49:38 +00:00
|
|
|
}
|
2018-12-06 11:31:51 +00:00
|
|
|
else if(uni == 'l') {
|
2017-08-13 18:49:38 +00:00
|
|
|
firstland = laStorms;
|
2018-06-10 22:58:38 +00:00
|
|
|
restart_game(tactic::on ? rg::tactic : rg::nothing);
|
2017-08-13 18:49:38 +00:00
|
|
|
}
|
2018-12-06 11:31:51 +00:00
|
|
|
else if(uni == 'b') {
|
2017-08-13 18:49:38 +00:00
|
|
|
firstland = laBurial;
|
2018-06-10 22:58:38 +00:00
|
|
|
restart_game(tactic::on ? rg::tactic : rg::nothing);
|
2017-08-13 18:49:38 +00:00
|
|
|
items[itOrbSword] = 60;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2017-03-23 10:53:57 +00:00
|
|
|
|
2019-07-12 21:17:35 +00:00
|
|
|
int bak_xres, bak_yres;
|
|
|
|
|
2018-02-11 20:39:47 +00:00
|
|
|
EM_BOOL fsc_callback(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData) {
|
|
|
|
if(fullscreenChangeEvent->isFullscreen) {
|
2019-07-12 21:17:35 +00:00
|
|
|
bak_xres = vid.xres;
|
|
|
|
bak_yres = vid.yres;
|
2018-02-11 21:11:28 +00:00
|
|
|
vid.xres = vid.xscr = fullscreenChangeEvent->screenWidth;
|
|
|
|
vid.yres = vid.yscr = fullscreenChangeEvent->screenHeight;
|
|
|
|
vid.full = true;
|
|
|
|
printf("set to %d x %d\n", vid.xres, vid.yres);
|
2018-02-11 20:39:47 +00:00
|
|
|
setvideomode();
|
|
|
|
}
|
|
|
|
else {
|
2019-07-12 21:17:35 +00:00
|
|
|
vid.xres = vid.xscr = bak_xres;
|
|
|
|
vid.yres = vid.yscr = bak_yres;
|
2018-02-11 21:11:28 +00:00
|
|
|
vid.full = true;
|
|
|
|
printf("reset to %d x %d\n", vid.xres, vid.yres);
|
2018-02-11 20:39:47 +00:00
|
|
|
setvideomode();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-23 10:53:57 +00:00
|
|
|
void initweb() {
|
2018-02-11 18:08:17 +00:00
|
|
|
// toggleanim(false);
|
2018-02-11 21:11:28 +00:00
|
|
|
emscripten_set_fullscreenchange_callback(0, NULL, false, fsc_callback);
|
2018-02-12 15:21:19 +00:00
|
|
|
printf("showstartmenu = %d\n", showstartmenu);
|
|
|
|
if(showstartmenu) pushScreen(showDemo);
|
2017-03-23 10:53:57 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 13:09:22 +00:00
|
|
|
#if CAP_ORIENTATION
|
2018-02-11 20:39:47 +00:00
|
|
|
transmatrix getOrientation() {
|
|
|
|
ld alpha, beta, gamma;
|
|
|
|
alpha = EM_ASM_DOUBLE({ return rotation_alpha; });
|
|
|
|
beta = EM_ASM_DOUBLE({ return rotation_beta; });
|
|
|
|
gamma = EM_ASM_DOUBLE({ return rotation_gamma; });
|
|
|
|
return
|
2019-08-09 21:59:32 +00:00
|
|
|
cspin(0, 1, alpha * degree) *
|
|
|
|
cspin(1, 2, beta * degree) *
|
|
|
|
cspin(0, 2, gamma * degree);
|
2018-02-11 20:39:47 +00:00
|
|
|
}
|
2018-09-02 13:09:22 +00:00
|
|
|
#endif
|
2018-02-12 11:49:20 +00:00
|
|
|
|
2018-02-26 12:14:20 +00:00
|
|
|
void emscripten_get_commandline() {
|
|
|
|
#ifdef EMSCRIPTEN_FIXED_ARG
|
|
|
|
string s = EMSCRIPTEN_FIXED_ARG;
|
|
|
|
#else
|
2018-02-12 11:49:20 +00:00
|
|
|
char *str = (char*)EM_ASM_INT({
|
|
|
|
var jsString = document.location.href;
|
2019-07-12 21:17:53 +00:00
|
|
|
if (typeof(default_arg) != 'undefined' && jsString.indexOf('?') == -1)
|
|
|
|
jsString = default_arg;
|
2018-02-12 11:49:20 +00:00
|
|
|
var lengthBytes = lengthBytesUTF8(jsString)+1;
|
|
|
|
var stringOnWasmHeap = _malloc(lengthBytes);
|
|
|
|
stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1);
|
|
|
|
return stringOnWasmHeap;
|
|
|
|
});
|
|
|
|
string s = str;
|
2018-02-26 12:14:20 +00:00
|
|
|
#endif
|
2018-02-12 11:49:20 +00:00
|
|
|
s += "+xxxxxx";
|
2018-06-22 12:47:24 +00:00
|
|
|
for(int i=0; i<isize(s); i++) if(s[i] == '?') {
|
2018-02-26 12:14:20 +00:00
|
|
|
#ifndef EMSCRIPTEN_FIXED_ARG
|
2018-02-12 12:37:01 +00:00
|
|
|
printf("HREF: %s\n", str);
|
2018-02-26 12:14:20 +00:00
|
|
|
#endif
|
|
|
|
arg::argument.push_back("hyperweb"); arg::lshift();
|
2018-02-12 11:49:20 +00:00
|
|
|
string next = ""; i += 3;
|
2018-06-22 12:47:24 +00:00
|
|
|
for(; i<isize(s); i++) {
|
2018-02-12 11:49:20 +00:00
|
|
|
if(s[i] == '+') {
|
2018-02-26 12:14:20 +00:00
|
|
|
arg::argument.push_back(next);
|
2018-02-12 11:49:20 +00:00
|
|
|
next = "";
|
|
|
|
}
|
|
|
|
else if(s[i] == '%') {
|
|
|
|
string s2 = "";
|
|
|
|
s2 += s[i+1];
|
|
|
|
s2 += s[i+2];
|
|
|
|
i += 2;
|
|
|
|
next += strtol(s2.c_str(), NULL, 16);
|
|
|
|
}
|
2018-09-06 20:34:54 +00:00
|
|
|
else if(s[i] == '&') {
|
|
|
|
arg::argument.push_back(next); break;
|
|
|
|
}
|
2018-02-12 11:49:20 +00:00
|
|
|
else next += s[i];
|
|
|
|
}
|
2018-02-26 12:14:20 +00:00
|
|
|
printf("Arguments:"); for(string s: arg::argument) printf(" %s", s.c_str()); printf("\n");
|
|
|
|
break;
|
2018-02-12 11:49:20 +00:00
|
|
|
}
|
2018-02-26 12:14:20 +00:00
|
|
|
|
|
|
|
#ifndef EMSCRIPTEN_FIXED_ARG
|
2018-02-12 11:49:20 +00:00
|
|
|
free(str);
|
2018-02-26 12:14:20 +00:00
|
|
|
#endif
|
2018-02-12 11:49:20 +00:00
|
|
|
}
|
2018-06-10 23:58:31 +00:00
|
|
|
}
|
2018-02-12 11:49:20 +00:00
|
|
|
|