1 // Hyperbolic Rogue
2 // This is the main file when the online version of HyperRogue is compiled with Emscripten.
3 // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
4
5 #ifndef ISWEB
6 #define ISWEB 1
7 #define ISMINI 0
8 #define CAP_INV 0
9 #define CAP_URL 1
10 #define GLES_ONLY
11 #define SCU
12 #endif
13
14 #if CAP_ROGUEVIZ || defined(MAXMDIM)
15 #define MAXMDIM 4
16 #else
17 #define MAXMDIM 3
18 #endif
19
20 // we want newconformist, but we don't want CAP_GD there
21 #define CAP_NCONF 1
22 #define CAP_GD 0
23
24 #ifndef EMSCRIPTEN
25 #define EMSCRIPTEN
26 #endif
27
28 #ifdef FAKEWEB
29 namespace hr { void mainloopiter(); }
emscripten_set_main_loop(A a,B b,C c)30 template<class A, class B, class C> void emscripten_set_main_loop(A a, B b, C c) { while(true) mainloopiter(); }
31 #else
32 #include <emscripten.h>
33 #include <emscripten/html5.h>
34 #endif
35
36 #include <string>
37
38 namespace hr {
39 void initweb();
40 void emscripten_get_commandline();
41
42 void loadCompressedChar(int &otwidth, int &otheight, int *tpix);
43 void get_canvas_size();
44
45 const char *wheresounds;
46
47 std::string get_value(std::string name);
48
49 void offer_download(std::string sfilename, std::string smimetype);
50 }
51
52 #ifdef SCU
53 #include "hyper.cpp"
54 #else
55 #include "hyper.h"
56 #endif
57
58 namespace hr {
59
get_value(string name)60 string get_value(string name) {
61 char *str = (char*)EM_ASM_INT({
62 var name = UTF8ToString($0, $1);
63 var value = document.getElementById(name).value;
64 var lengthBytes = lengthBytesUTF8(value)+1;
65 var stringOnWasmHeap = _malloc(lengthBytes);
66 stringToUTF8(value, stringOnWasmHeap, lengthBytes);
67 return stringOnWasmHeap;
68 }, name.c_str(), int(name.size())
69 );
70 string res = str;
71 free(str);
72 return res;
73 }
74
offer_download(string sfilename,string smimetype)75 EX void offer_download(string sfilename, string smimetype) {
76
77 EM_ASM({
78 var name = UTF8ToString($0, $1);
79 var mime = UTF8ToString($2, $3);
80
81 let content = Module.FS.readFile(name);
82 console.log(`Offering download of "${name}", with ${content.length} bytes...`);
83
84 var a = document.createElement('a');
85 a.download = name;
86 a.href = URL.createObjectURL(new Blob([content], {type: mime}));
87 a.style.display = 'none';
88
89 document.body.appendChild(a);
90 a.click();
91 setTimeout(() => {
92 document.body.removeChild(a);
93 URL.revokeObjectURL(a.href);
94 }, 2000);
95 }, sfilename.c_str(), isize(sfilename), smimetype.c_str(), isize(smimetype)
96 );
97
98 }
99
__anon0fa804e30102null100 reaction_t on_use_file = [] {};
101
102 extern "C" {
use_file()103 void use_file() {
104 on_use_file();
105 }
106 }
107
offer_choose_file(reaction_t r)108 EX void offer_choose_file(reaction_t r) {
109 on_use_file = r;
110 EM_ASM({
111 fileElem.click();
112 });
113 }
114
115 // window.open(Pointer_stringify($0));
116 bool demoanim;
117
toggleanim(bool v)118 void toggleanim(bool v) {
119 demoanim = v;
120 if(v) {
121 sightrange_bonus = -3;
122 vid.wallmode = 5;
123 vid.particles = true;
124 vid.sspeed = -1;
125 vid.mspeed = -1;
126 vid.highdetail = vid.middetail = 5;
127 }
128 else {
129 sightrange_bonus = 0;
130 vid.sspeed = 5;
131 vid.mspeed = 5;
132 vid.particles = false;
133 vid.wallmode = 3;
134 vid.highdetail = vid.middetail = -1;
135 }
136 }
137
showDemo()138 void showDemo() {
139 gamescreen(2);
140
141 getcstat = ' ';
142
143 dialog::init(XLAT("HyperRogue %1: online demo", VER), 0xC00000, 200, 100);
144 dialog::addBreak(50);
145
146 dialog::addItem(XLAT("play the game"), 'f');
147 dialog::addItem(XLAT("learn about hyperbolic geometry"), 'T');
148 dialog::addHelp();
149 // dialog::addItem(XLAT("toggle high detail"), 'a');
150 dialog::addBreak(100);
151
152 dialog::addTitle("highlights", 0xC00000, 120);
153 dialog::addItem(XLAT("Temple of Cthulhu"), 't');
154 dialog::addItem(XLAT("Land of Storms"), 'l');
155 dialog::addItem(XLAT("Burial Grounds"), 'b');
156
157 dialog::display();
158
159 keyhandler = [] (int sym, int uni) {
160 dialog::handleNavigation(sym, uni);
161 if(sym == SDLK_F1 || uni == 'h') gotoHelp(help);
162 else if(uni == 'a') {
163 toggleanim(!demoanim);
164 popScreen();
165 }
166 else if(uni == 'f') {
167 firstland = laIce;
168 restart_game(tactic::on ? rg::tactic : rg::nothing);
169 }
170 #if CAP_TOUR
171 else if(uni == 'T') {
172 firstland = laIce;
173 if(!tour::on) tour::start();
174 }
175 #endif
176 else if(uni == 't') {
177 firstland = laTemple;
178 restart_game(tactic::on ? rg::tactic : rg::nothing);
179 }
180 else if(uni == 'l') {
181 firstland = laStorms;
182 restart_game(tactic::on ? rg::tactic : rg::nothing);
183 }
184 else if(uni == 'b') {
185 firstland = laBurial;
186 restart_game(tactic::on ? rg::tactic : rg::nothing);
187 items[itOrbSword] = 60;
188 }
189 };
190 }
191
192 int bak_xres, bak_yres;
193
fsc_callback(int eventType,const EmscriptenFullscreenChangeEvent * fullscreenChangeEvent,void * userData)194 EM_BOOL fsc_callback(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData) {
195 if(fullscreenChangeEvent->isFullscreen) {
196 bak_xres = vid.xres;
197 bak_yres = vid.yres;
198 vid.xres = vid.xscr = fullscreenChangeEvent->screenWidth;
199 vid.yres = vid.yscr = fullscreenChangeEvent->screenHeight;
200 vid.full = true;
201 printf("set to %d x %d\n", vid.xres, vid.yres);
202 setvideomode();
203 }
204 else {
205 vid.xres = vid.xscr = bak_xres;
206 vid.yres = vid.yscr = bak_yres;
207 vid.full = true;
208 printf("reset to %d x %d\n", vid.xres, vid.yres);
209 setvideomode();
210 }
211 return true;
212 }
213
get_canvas_size()214 EX void get_canvas_size() {
215 vid.xscr = vid.xres = EM_ASM_INT({
216 var d = document.getElementById("this_wide");
217 if(!d) return window.innerWidth;
218 return d.clientWidth;
219 });
220 if(vid.full) vid.yscr = vid.yres = EM_ASM_INT({
221 var d = document.getElementById("this_wide");
222 if(!d) return window.innerWidth;
223 return d.clientHeight;
224 });
225 else {
226 vid.xscr = vid.xres = vid.xres - 32;
227 vid.yscr = vid.yres = EM_ASM_INT({
228 return window.innerHeight;
229 }) - 32;
230 vid.yscr = vid.yres = min(vid.yscr, vid.xscr * 9 / 16);
231 vid.xscr = vid.xres = min(vid.xscr, vid.yscr * 16 / 9);
232 }
233 println(hlog, "X = ", vid.xscr, " Y = ", vid.yscr);
234 }
235
resize_callback(int eventType,const EmscriptenUiEvent * resizeEvent,void * userData)236 EM_BOOL resize_callback(int eventType, const EmscriptenUiEvent *resizeEvent, void *userData) {
237 if(vid.full) return true;
238 get_canvas_size();
239 setvideomode();
240 return true;
241 }
242
initweb()243 EX void initweb() {
244 // toggleanim(false);
245 emscripten_set_fullscreenchange_callback(0, NULL, false, fsc_callback);
246 emscripten_set_resize_callback(0, NULL, false, resize_callback);
247 printf("showstartmenu = %d\n", showstartmenu);
248 if(showstartmenu) pushScreen(showDemo);
249 }
250
251 #if CAP_ORIENTATION
getOrientation()252 transmatrix getOrientation() {
253 ld alpha, beta, gamma;
254 alpha = EM_ASM_DOUBLE({ return rotation_alpha; });
255 beta = EM_ASM_DOUBLE({ return rotation_beta; });
256 gamma = EM_ASM_DOUBLE({ return rotation_gamma; });
257 return
258 cspin(0, 1, alpha * degree) *
259 cspin(1, 2, beta * degree) *
260 cspin(0, 2, gamma * degree);
261 }
262 #endif
263
emscripten_get_commandline()264 EX void emscripten_get_commandline() {
265 #ifdef EMSCRIPTEN_FIXED_ARG
266 string s = EMSCRIPTEN_FIXED_ARG;
267 #else
268 char *str = (char*)EM_ASM_INT({
269 var jsString = document.location.href;
270 if (typeof(default_arg) != 'undefined' && jsString.indexOf('?') == -1)
271 jsString = default_arg;
272 var lengthBytes = lengthBytesUTF8(jsString)+1;
273 var stringOnWasmHeap = _malloc(lengthBytes);
274 stringToUTF8(jsString, stringOnWasmHeap, lengthBytes+1);
275 return stringOnWasmHeap;
276 });
277 string s = str;
278 #endif
279 s += "+xxxxxx";
280 for(int i=0; i<isize(s); i++) if(s[i] == '?') {
281 #ifndef EMSCRIPTEN_FIXED_ARG
282 printf("HREF: %s\n", str);
283 #endif
284 arg::argument.push_back("hyperweb"); arg::lshift();
285 string next = ""; i += 3;
286 for(; i<isize(s); i++) {
287 if(s[i] == '+') {
288 arg::argument.push_back(next);
289 next = "";
290 }
291 else if(s[i] == '%') {
292 string s2 = "";
293 s2 += s[i+1];
294 s2 += s[i+2];
295 i += 2;
296 next += strtol(s2.c_str(), NULL, 16);
297 }
298 else if(s[i] == '&') {
299 arg::argument.push_back(next); break;
300 }
301 else next += s[i];
302 }
303 printf("Arguments:"); for(string s: arg::argument) printf(" %s", s.c_str()); printf("\n");
304 break;
305 }
306
307 #ifndef EMSCRIPTEN_FIXED_ARG
308 free(str);
309 #endif
310 }
311 }
312
313