@muhammedaksam/opentui-doom 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -12
- package/doom/build/doom.js +1 -1
- package/doom/build/doom.wasm +0 -0
- package/doom/i_sound.c +2 -1
- package/doom/i_system.c +345 -0
- package/doom/s_sound.c +566 -0
- package/package.json +6 -1
- package/scripts/build-doom.sh +4 -2
- package/src/debug.ts +27 -0
- package/src/doom-audio.ts +4 -11
- package/src/doom-engine.ts +120 -2
- package/src/doom-input.ts +18 -3
- package/src/doom-saves.ts +121 -0
- package/src/index.ts +49 -2
package/doom/i_system.c
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright(C) 1993-1996 Id Software, Inc.
|
|
3
|
+
// Copyright(C) 2005-2014 Simon Howard
|
|
4
|
+
//
|
|
5
|
+
// This program is free software; you can redistribute it and/or
|
|
6
|
+
// modify it under the terms of the GNU General Public License
|
|
7
|
+
// as published by the Free Software Foundation; either version 2
|
|
8
|
+
// of the License, or (at your option) any later version.
|
|
9
|
+
//
|
|
10
|
+
// This program is distributed in the hope that it will be useful,
|
|
11
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
// GNU General Public License for more details.
|
|
14
|
+
//
|
|
15
|
+
// DESCRIPTION:
|
|
16
|
+
// OpenTUI-modified i_system.c - System-specific interface functions
|
|
17
|
+
// Modified to support proper exit handling in WebAssembly builds.
|
|
18
|
+
//
|
|
19
|
+
|
|
20
|
+
#include <stdarg.h>
|
|
21
|
+
#include <stdio.h>
|
|
22
|
+
#include <stdlib.h>
|
|
23
|
+
#include <string.h>
|
|
24
|
+
#include <unistd.h>
|
|
25
|
+
|
|
26
|
+
// Include DOOM headers BEFORE emscripten to avoid true/false macro conflicts
|
|
27
|
+
#include "config.h"
|
|
28
|
+
#include "deh_str.h"
|
|
29
|
+
#include "doomtype.h"
|
|
30
|
+
#include "i_joystick.h"
|
|
31
|
+
#include "i_sound.h"
|
|
32
|
+
#include "i_system.h"
|
|
33
|
+
#include "i_timer.h"
|
|
34
|
+
#include "i_video.h"
|
|
35
|
+
#include "m_argv.h"
|
|
36
|
+
#include "m_config.h"
|
|
37
|
+
#include "m_misc.h"
|
|
38
|
+
#include "w_wad.h"
|
|
39
|
+
#include "z_zone.h"
|
|
40
|
+
|
|
41
|
+
// Include emscripten AFTER doom headers to avoid true/false conflicts
|
|
42
|
+
#include <emscripten.h>
|
|
43
|
+
|
|
44
|
+
#define DEFAULT_RAM 6 /* MiB */
|
|
45
|
+
#define MIN_RAM 6 /* MiB */
|
|
46
|
+
|
|
47
|
+
typedef struct atexit_listentry_s atexit_listentry_t;
|
|
48
|
+
|
|
49
|
+
struct atexit_listentry_s {
|
|
50
|
+
atexit_func_t func;
|
|
51
|
+
boolean run_on_error;
|
|
52
|
+
atexit_listentry_t *next;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
static atexit_listentry_t *exit_funcs = NULL;
|
|
56
|
+
|
|
57
|
+
void I_AtExit(atexit_func_t func, boolean run_on_error) {
|
|
58
|
+
atexit_listentry_t *entry;
|
|
59
|
+
|
|
60
|
+
entry = malloc(sizeof(*entry));
|
|
61
|
+
|
|
62
|
+
entry->func = func;
|
|
63
|
+
entry->run_on_error = run_on_error;
|
|
64
|
+
entry->next = exit_funcs;
|
|
65
|
+
exit_funcs = entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Tactile feedback function, probably used for the Logitech Cyberman
|
|
69
|
+
|
|
70
|
+
void I_Tactile(int on, int off, int total) {}
|
|
71
|
+
|
|
72
|
+
// Zone memory auto-allocation function that allocates the zone size
|
|
73
|
+
// by trying progressively smaller zone sizes until one is found that
|
|
74
|
+
// works.
|
|
75
|
+
|
|
76
|
+
static byte *AutoAllocMemory(int *size, int default_ram, int min_ram) {
|
|
77
|
+
byte *zonemem;
|
|
78
|
+
|
|
79
|
+
// Allocate the zone memory. This loop tries progressively smaller
|
|
80
|
+
// zone sizes until a size is found that can be allocated.
|
|
81
|
+
// If we used the -mb command line parameter, only the parameter
|
|
82
|
+
// provided is accepted.
|
|
83
|
+
|
|
84
|
+
zonemem = NULL;
|
|
85
|
+
|
|
86
|
+
while (zonemem == NULL) {
|
|
87
|
+
// We need a reasonable minimum amount of RAM to start.
|
|
88
|
+
|
|
89
|
+
if (default_ram < min_ram) {
|
|
90
|
+
I_Error("Unable to allocate %i MiB of RAM for zone", default_ram);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Try to allocate the zone memory.
|
|
94
|
+
|
|
95
|
+
*size = default_ram * 1024 * 1024;
|
|
96
|
+
|
|
97
|
+
zonemem = malloc(*size);
|
|
98
|
+
|
|
99
|
+
// Failed to allocate? Reduce zone size until we reach a size
|
|
100
|
+
// that is acceptable.
|
|
101
|
+
|
|
102
|
+
if (zonemem == NULL) {
|
|
103
|
+
default_ram -= 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return zonemem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
byte *I_ZoneBase(int *size) {
|
|
111
|
+
byte *zonemem;
|
|
112
|
+
int min_ram, default_ram;
|
|
113
|
+
int p;
|
|
114
|
+
|
|
115
|
+
//!
|
|
116
|
+
// @arg <mb>
|
|
117
|
+
//
|
|
118
|
+
// Specify the heap size, in MiB (default 16).
|
|
119
|
+
//
|
|
120
|
+
|
|
121
|
+
p = M_CheckParmWithArgs("-mb", 1);
|
|
122
|
+
|
|
123
|
+
if (p > 0) {
|
|
124
|
+
default_ram = atoi(myargv[p + 1]);
|
|
125
|
+
min_ram = default_ram;
|
|
126
|
+
} else {
|
|
127
|
+
default_ram = DEFAULT_RAM;
|
|
128
|
+
min_ram = MIN_RAM;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
zonemem = AutoAllocMemory(size, default_ram, min_ram);
|
|
132
|
+
|
|
133
|
+
printf("zone memory: %p, %x allocated for zone\n", zonemem, *size);
|
|
134
|
+
|
|
135
|
+
return zonemem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void I_PrintBanner(char *msg) {
|
|
139
|
+
int i;
|
|
140
|
+
int spaces = 35 - (strlen(msg) / 2);
|
|
141
|
+
|
|
142
|
+
for (i = 0; i < spaces; ++i)
|
|
143
|
+
putchar(' ');
|
|
144
|
+
|
|
145
|
+
puts(msg);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void I_PrintDivider(void) {
|
|
149
|
+
int i;
|
|
150
|
+
|
|
151
|
+
for (i = 0; i < 75; ++i) {
|
|
152
|
+
putchar('=');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
putchar('\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
void I_PrintStartupBanner(char *gamedescription) {
|
|
159
|
+
I_PrintDivider();
|
|
160
|
+
I_PrintBanner(gamedescription);
|
|
161
|
+
I_PrintDivider();
|
|
162
|
+
|
|
163
|
+
printf(" " PACKAGE_NAME
|
|
164
|
+
" is free software, covered by the GNU General Public\n"
|
|
165
|
+
" License. There is NO warranty; not even for MERCHANTABILITY or "
|
|
166
|
+
"FITNESS\n"
|
|
167
|
+
" FOR A PARTICULAR PURPOSE. You are welcome to change and distribute\n"
|
|
168
|
+
" copies under certain conditions. See the source for more "
|
|
169
|
+
"information.\n");
|
|
170
|
+
|
|
171
|
+
I_PrintDivider();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//
|
|
175
|
+
// I_ConsoleStdout
|
|
176
|
+
//
|
|
177
|
+
// Returns true if stdout is a real console, false if it is a file
|
|
178
|
+
//
|
|
179
|
+
|
|
180
|
+
boolean I_ConsoleStdout(void) {
|
|
181
|
+
// In WASM environment, always return 0
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
//
|
|
186
|
+
// I_Quit
|
|
187
|
+
//
|
|
188
|
+
// Modified for OpenTUI: Call JavaScript to properly exit the application
|
|
189
|
+
//
|
|
190
|
+
|
|
191
|
+
void I_Quit(void) {
|
|
192
|
+
atexit_listentry_t *entry;
|
|
193
|
+
|
|
194
|
+
// Signal JavaScript to exit the application FIRST
|
|
195
|
+
// This must happen before atexit handlers because they may prevent
|
|
196
|
+
// this code from being reached (e.g., by calling exit() or longjmp)
|
|
197
|
+
EM_ASM({
|
|
198
|
+
if (typeof Module.quitGame === 'function') {
|
|
199
|
+
Module.quitGame();
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// Run through all exit functions
|
|
204
|
+
entry = exit_funcs;
|
|
205
|
+
|
|
206
|
+
while (entry != NULL) {
|
|
207
|
+
entry->func();
|
|
208
|
+
entry = entry->next;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
//
|
|
213
|
+
// I_Error
|
|
214
|
+
//
|
|
215
|
+
|
|
216
|
+
static boolean already_quitting = false;
|
|
217
|
+
|
|
218
|
+
void I_Error(char *error, ...) {
|
|
219
|
+
char msgbuf[512];
|
|
220
|
+
va_list argptr;
|
|
221
|
+
atexit_listentry_t *entry;
|
|
222
|
+
|
|
223
|
+
if (already_quitting) {
|
|
224
|
+
fprintf(stderr, "Warning: recursive call to I_Error detected.\n");
|
|
225
|
+
return;
|
|
226
|
+
} else {
|
|
227
|
+
already_quitting = true;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Message first.
|
|
231
|
+
va_start(argptr, error);
|
|
232
|
+
vfprintf(stderr, error, argptr);
|
|
233
|
+
fprintf(stderr, "\n\n");
|
|
234
|
+
va_end(argptr);
|
|
235
|
+
fflush(stderr);
|
|
236
|
+
|
|
237
|
+
// Write a copy of the message into buffer.
|
|
238
|
+
va_start(argptr, error);
|
|
239
|
+
memset(msgbuf, 0, sizeof(msgbuf));
|
|
240
|
+
M_vsnprintf(msgbuf, sizeof(msgbuf), error, argptr);
|
|
241
|
+
va_end(argptr);
|
|
242
|
+
|
|
243
|
+
// Shutdown. Here might be other errors.
|
|
244
|
+
entry = exit_funcs;
|
|
245
|
+
|
|
246
|
+
while (entry != NULL) {
|
|
247
|
+
if (entry->run_on_error) {
|
|
248
|
+
entry->func();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
entry = entry->next;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// In WASM, we can't really exit, but we signal an error
|
|
255
|
+
EM_ASM(
|
|
256
|
+
{
|
|
257
|
+
var msg = UTF8ToString($0);
|
|
258
|
+
console.error("DOOM Error: " + msg);
|
|
259
|
+
if (typeof Module.quitGame === 'function') {
|
|
260
|
+
Module.quitGame();
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
msgbuf);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
//
|
|
267
|
+
// Read Access Violation emulation.
|
|
268
|
+
//
|
|
269
|
+
// From PrBoom+, by entryway.
|
|
270
|
+
//
|
|
271
|
+
|
|
272
|
+
#define DOS_MEM_DUMP_SIZE 10
|
|
273
|
+
|
|
274
|
+
static const unsigned char mem_dump_dos622[DOS_MEM_DUMP_SIZE] = {
|
|
275
|
+
0x57, 0x92, 0x19, 0x00, 0xF4, 0x06, 0x70, 0x00, 0x16, 0x00};
|
|
276
|
+
static const unsigned char mem_dump_win98[DOS_MEM_DUMP_SIZE] = {
|
|
277
|
+
0x9E, 0x0F, 0xC9, 0x00, 0x65, 0x04, 0x70, 0x00, 0x16, 0x00};
|
|
278
|
+
static const unsigned char mem_dump_dosbox[DOS_MEM_DUMP_SIZE] = {
|
|
279
|
+
0x00, 0x00, 0x00, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00};
|
|
280
|
+
static unsigned char mem_dump_custom[DOS_MEM_DUMP_SIZE];
|
|
281
|
+
|
|
282
|
+
static const unsigned char *dos_mem_dump = mem_dump_dos622;
|
|
283
|
+
|
|
284
|
+
boolean I_GetMemoryValue(unsigned int offset, void *value, int size) {
|
|
285
|
+
static boolean firsttime = true;
|
|
286
|
+
|
|
287
|
+
if (firsttime) {
|
|
288
|
+
int p, i, val;
|
|
289
|
+
|
|
290
|
+
firsttime = false;
|
|
291
|
+
i = 0;
|
|
292
|
+
|
|
293
|
+
//!
|
|
294
|
+
// @category compat
|
|
295
|
+
// @arg <version>
|
|
296
|
+
//
|
|
297
|
+
// Specify DOS version to emulate for NULL pointer dereference
|
|
298
|
+
// emulation. Supported versions are: dos622, dos71, dosbox.
|
|
299
|
+
// The default is to emulate DOS 7.1 (Windows 98).
|
|
300
|
+
//
|
|
301
|
+
|
|
302
|
+
p = M_CheckParmWithArgs("-setmem", 1);
|
|
303
|
+
|
|
304
|
+
if (p > 0) {
|
|
305
|
+
if (!strcasecmp(myargv[p + 1], "dos622")) {
|
|
306
|
+
dos_mem_dump = mem_dump_dos622;
|
|
307
|
+
}
|
|
308
|
+
if (!strcasecmp(myargv[p + 1], "dos71")) {
|
|
309
|
+
dos_mem_dump = mem_dump_win98;
|
|
310
|
+
} else if (!strcasecmp(myargv[p + 1], "dosbox")) {
|
|
311
|
+
dos_mem_dump = mem_dump_dosbox;
|
|
312
|
+
} else {
|
|
313
|
+
for (i = 0; i < DOS_MEM_DUMP_SIZE; ++i) {
|
|
314
|
+
++p;
|
|
315
|
+
|
|
316
|
+
if (p >= myargc || myargv[p][0] == '-') {
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
M_StrToInt(myargv[p], &val);
|
|
321
|
+
mem_dump_custom[i++] = (unsigned char)val;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
dos_mem_dump = mem_dump_custom;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
switch (size) {
|
|
330
|
+
case 1:
|
|
331
|
+
*((unsigned char *)value) = dos_mem_dump[offset];
|
|
332
|
+
return true;
|
|
333
|
+
case 2:
|
|
334
|
+
*((unsigned short *)value) =
|
|
335
|
+
dos_mem_dump[offset] | (dos_mem_dump[offset + 1] << 8);
|
|
336
|
+
return true;
|
|
337
|
+
case 4:
|
|
338
|
+
*((unsigned int *)value) =
|
|
339
|
+
dos_mem_dump[offset] | (dos_mem_dump[offset + 1] << 8) |
|
|
340
|
+
(dos_mem_dump[offset + 2] << 16) | (dos_mem_dump[offset + 3] << 24);
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return false;
|
|
345
|
+
}
|