1 /* Copyright (C) 2020 SovietPony
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdlib.h> // srand exit
26 #include "player.h" // pl1 pl2
27 #include "menu.h" // G_keyf
28 #include "error.h" // logo
29 #include "monster.h" // nomon
31 #include "files.h" // F_startup F_addwad F_initwads F_allocres
32 #include "config.h" // CFG_args CFG_load CFG_save
33 #include "args.h" // ARG_parse
34 #include "memory.h" // M_startup
35 #include "game.h" // G_init G_act
36 #include "sound.h" // S_init S_done
37 #include "music.h" // S_initmusic S_updatemusic S_donemusic
38 #include "render.h" // R_init R_draw R_done
41 static videomode_size_t wlist
[3] = {
46 static videomode_t vlist
= {
51 static byte
*buf
= NULL
;
54 static struct rgb_pal
{
58 static const cfg_t arg
[] = {
59 {"file", NULL
, Y_FILES
},
60 {"cheat", &cheat
, Y_SW_ON
},
61 // {"vga", &shot_vga, Y_SW_ON},
62 // {"musvol", &mus_vol, Y_WORD},
63 {"mon", &nomon
, Y_SW_OFF
},
64 {"warp", &_warp
, Y_BYTE
},
65 // {"config", NULL, cfg_file, Y_STRING},
66 {NULL
, NULL
, 0} // end
69 static const cfg_t cfg
[] = {
70 // {"screenshot", &shot_vga, Y_SW_ON},
71 // {"music_volume", &mus_vol, Y_WORD},
72 // {"music_random", &music_random, Y_SW_ON},
73 // {"music_time", &music_time, Y_DWORD},
74 // {"music_fade", &music_fade, Y_DWORD},
75 {"pl1_left", &pl1
.kl
, Y_KEY
},
76 {"pl1_right",&pl1
.kr
, Y_KEY
},
77 {"pl1_up", &pl1
.ku
, Y_KEY
},
78 {"pl1_down", &pl1
.kd
, Y_KEY
},
79 {"pl1_jump", &pl1
.kj
, Y_KEY
},
80 {"pl1_fire", &pl1
.kf
, Y_KEY
},
81 {"pl1_next", &pl1
.kwr
, Y_KEY
},
82 {"pl1_prev", &pl1
.kwl
, Y_KEY
},
83 {"pl1_use", &pl1
.kp
, Y_KEY
},
84 {"pl2_left", &pl2
.kl
, Y_KEY
},
85 {"pl2_right", &pl2
.kr
, Y_KEY
},
86 {"pl2_up", &pl2
.ku
, Y_KEY
},
87 {"pl2_down", &pl2
.kd
, Y_KEY
},
88 {"pl2_jump", &pl2
.kj
, Y_KEY
},
89 {"pl2_fire", &pl2
.kf
, Y_KEY
},
90 {"pl2_next", &pl2
.kwr
, Y_KEY
},
91 {"pl2_prev", &pl2
.kwl
, Y_KEY
},
92 {"pl2_use", &pl2
.kp
, Y_KEY
},
93 {NULL
, NULL
, 0} // end
96 static void CFG_args (int argc
, char **argv
) {
97 const cfg_t
*list
[] = { arg
, R_args(), S_args(), MUS_args() };
98 ARG_parse(argc
, argv
, 4, list
);
101 static void CFG_load (void) {
102 const cfg_t
*list
[] = { cfg
, R_conf(), S_conf(), MUS_conf() };
103 CFG_read_config("default.cfg", 4, list
);
104 CFG_read_config("doom2d.cfg", 4, list
);
107 static void CFG_save (void) {
108 const cfg_t
*list
[] = { cfg
, R_conf(), S_conf(), MUS_conf() };
109 CFG_update_config("doom2d.cfg", "doom2d.cfg", 4, list
, "generated by doom2d, do not modify");
112 /* --- error.h --- */
114 void logo (const char *s
, ...) {
122 void logo_gas (int cur
, int all
) {
126 void ERR_failinit (char *s
, ...) {
136 void ERR_fatal (char *s
, ...) {
141 puts("\nCRITICAL ERROR:");
150 void ERR_quit (void) {
154 /* --- system.h --- */
156 static int Y_resize_window (int w
, int h
, int fullscreen
) {
160 return Y_set_videomode_software(w
, h
, fullscreen
);
165 int Y_set_videomode_opengl (int w
, int h
, int fullscreen
) {
172 static void SetupWindow (int w
, int h
, const char *title
) {
173 int flags
= KOS32_WIN_FLAG_CAPTION
| KOS32_WIN_FLAG_RELATIVE
| KOS32_WIN_FLAG_NOFILL
;
174 int skin_h
= GetSkinHeight();
175 CreateWindow(0, 0, w
+ 5*2, h
+ 5 + skin_h
, KOS32_WIN_STYLE_FIXED
, flags
, 0x000000, 0x000000, title
);
178 int Y_set_videomode_software (int w
, int h
, int fullscreen
) {
182 byte
*new_buf
= malloc(size
);
183 if (new_buf
!= NULL
) {
185 memset(new_buf
, 0, size
);
190 SetupWindow(w
, h
, "Doom2D (software render)");
196 void Y_get_videomode (int *w
, int *h
) {
201 int Y_videomode_setted (void) {
205 void Y_unset_videomode (void) {
214 const videomode_t
*Y_get_videomode_list_opengl (int fullscreen
) {
218 const videomode_t
*Y_get_videomode_list_software (int fullscreen
) {
222 void Y_set_fullscreen (int yes
) {
226 int Y_get_fullscreen (void) {
231 void Y_swap_buffers (void) {
235 void Y_get_buffer (byte
**buf_ref
, int *w
, int *h
, int *pitch
) {
236 assert(buf_ref
!= NULL
);
239 assert(pitch
!= NULL
);
246 void Y_set_vga_palette (byte
*vgapal
) {
250 assert(vgapal
!= NULL
);
251 for (i
= 0; i
< 256; i
++) {
252 rgbpal
[i
].r
= p
[0] * 255 / 63;
253 rgbpal
[i
].g
= p
[1] * 255 / 63;
254 rgbpal
[i
].b
= p
[2] * 255 / 63;
259 void Y_repaint_rect (int x
, int y
, int w
, int h
) {
263 void Y_repaint (void) {
266 SetupWindow(buf_w
, buf_h
, NULL
);
267 PutImageExt(buf
, buf_w
, buf_h
, 0, 0, 8, rgbpal
, 0);
271 void Y_enable_text_input (void) {
272 SetInputMode(KOS32_INPUT_MODE_ASCII
);
275 void Y_disable_text_input (void) {
276 SetInputMode(KOS32_INPUT_MODE_SCANCODE
);
281 static int scancode_to_key (int scancode
) {
283 case KOS32_SC_0
: return KEY_0
;
284 case KOS32_SC_1
: return KEY_1
;
285 case KOS32_SC_2
: return KEY_2
;
286 case KOS32_SC_3
: return KEY_3
;
287 case KOS32_SC_4
: return KEY_4
;
288 case KOS32_SC_5
: return KEY_5
;
289 case KOS32_SC_6
: return KEY_6
;
290 case KOS32_SC_7
: return KEY_7
;
291 case KOS32_SC_8
: return KEY_8
;
292 case KOS32_SC_9
: return KEY_9
;
293 case KOS32_SC_A
: return KEY_A
;
294 case KOS32_SC_B
: return KEY_B
;
295 case KOS32_SC_C
: return KEY_C
;
296 case KOS32_SC_D
: return KEY_D
;
297 case KOS32_SC_E
: return KEY_E
;
298 case KOS32_SC_F
: return KEY_F
;
299 case KOS32_SC_G
: return KEY_G
;
300 case KOS32_SC_H
: return KEY_H
;
301 case KOS32_SC_I
: return KEY_I
;
302 case KOS32_SC_J
: return KEY_J
;
303 case KOS32_SC_K
: return KEY_K
;
304 case KOS32_SC_L
: return KEY_L
;
305 case KOS32_SC_M
: return KEY_M
;
306 case KOS32_SC_N
: return KEY_N
;
307 case KOS32_SC_O
: return KEY_O
;
308 case KOS32_SC_P
: return KEY_P
;
309 case KOS32_SC_Q
: return KEY_Q
;
310 case KOS32_SC_R
: return KEY_R
;
311 case KOS32_SC_S
: return KEY_S
;
312 case KOS32_SC_T
: return KEY_T
;
313 case KOS32_SC_U
: return KEY_U
;
314 case KOS32_SC_V
: return KEY_V
;
315 case KOS32_SC_W
: return KEY_W
;
316 case KOS32_SC_X
: return KEY_X
;
317 case KOS32_SC_Y
: return KEY_Y
;
318 case KOS32_SC_Z
: return KEY_Z
;
319 case KOS32_SC_RETURN
: return KEY_RETURN
;
320 case KOS32_SC_ESCAPE
: return KEY_ESCAPE
;
321 case KOS32_SC_BACKSPACE
: return KEY_BACKSPACE
;
322 case KOS32_SC_TAB
: return KEY_TAB
;
323 case KOS32_SC_SPACE
: return KEY_SPACE
;
324 case KOS32_SC_MINUS
: return KEY_MINUS
;
325 case KOS32_SC_EQUALS
: return KEY_EQUALS
;
326 case KOS32_SC_LEFTBRACKET
: return KEY_LEFTBRACKET
;
327 case KOS32_SC_RIGHTBRACKET
: return KEY_RIGHTBRACKET
;
328 case KOS32_SC_BACKSLASH
: return KEY_BACKSLASH
;
329 case KOS32_SC_SEMICOLON
: return KEY_SEMICOLON
;
330 case KOS32_SC_APOSTROPHE
: return KEY_APOSTROPHE
;
331 case KOS32_SC_GRAVE
: return KEY_GRAVE
;
332 case KOS32_SC_COMMA
: return KEY_COMMA
;
333 case KOS32_SC_PERIOD
: return KEY_PERIOD
;
334 case KOS32_SC_SLASH
: return KEY_SLASH
;
335 case KOS32_SC_CAPSLOCK
: return KEY_CAPSLOCK
;
336 case KOS32_SC_F1
: return KEY_F1
;
337 case KOS32_SC_F2
: return KEY_F2
;
338 case KOS32_SC_F3
: return KEY_F3
;
339 case KOS32_SC_F4
: return KEY_F4
;
340 case KOS32_SC_F5
: return KEY_F5
;
341 case KOS32_SC_F6
: return KEY_F6
;
342 case KOS32_SC_F7
: return KEY_F7
;
343 case KOS32_SC_F8
: return KEY_F8
;
344 case KOS32_SC_F9
: return KEY_F9
;
345 case KOS32_SC_F10
: return KEY_F10
;
346 case KOS32_SC_F11
: return KEY_F11
;
347 case KOS32_SC_F12
: return KEY_F12
;
348 case KOS32_SC_SCROLLLOCK
: return KEY_SCROLLLOCK
;
349 case KOS32_SC_NUMLOCK
: return KEY_NUMLOCK
;
350 case KOS32_SC_KP_MULTIPLY
: return KEY_KP_MULTIPLY
;
351 case KOS32_SC_KP_MINUS
: return KEY_KP_MINUS
;
352 case KOS32_SC_KP_PLUS
: return KEY_KP_PLUS
;
353 case KOS32_SC_KP_0
: return KEY_KP_0
;
354 case KOS32_SC_KP_1
: return KEY_KP_1
;
355 case KOS32_SC_KP_2
: return KEY_KP_2
;
356 case KOS32_SC_KP_3
: return KEY_KP_3
;
357 case KOS32_SC_KP_4
: return KEY_KP_4
;
358 case KOS32_SC_KP_5
: return KEY_KP_5
;
359 case KOS32_SC_KP_6
: return KEY_KP_6
;
360 case KOS32_SC_KP_7
: return KEY_KP_7
;
361 case KOS32_SC_KP_8
: return KEY_KP_8
;
362 case KOS32_SC_KP_9
: return KEY_KP_9
;
363 case KOS32_SC_KP_PERIOD
: return KEY_KP_PERIOD
;
364 case KOS32_SC_LCTRL
: return KEY_LCTRL
;
365 case KOS32_SC_LSHIFT
: return KEY_LSHIFT
;
366 case KOS32_SC_LALT
: return KEY_LALT
;
367 default: return KEY_UNKNOWN
;
371 static int ext_scancode_to_key (int scancode
) {
373 case KOS32_SC_INSERT
: return KEY_INSERT
;
374 case KOS32_SC_HOME
: return KEY_HOME
;
375 case KOS32_SC_PAGEUP
: return KEY_PAGEUP
;
376 case KOS32_SC_DELETE
: return KEY_DELETE
;
377 case KOS32_SC_END
: return KEY_END
;
378 case KOS32_SC_PAGEDOWN
: return KEY_PAGEDOWN
;
379 case KOS32_SC_RIGHT
: return KEY_RIGHT
;
380 case KOS32_SC_LEFT
: return KEY_LEFT
;
381 case KOS32_SC_DOWN
: return KEY_DOWN
;
382 case KOS32_SC_UP
: return KEY_UP
;
383 case KOS32_SC_KP_DIVIDE
: return KEY_KP_DIVIDE
;
384 case KOS32_SC_KP_ENTER
: return KEY_KP_ENTER
;
385 case KOS32_SC_LSUPER
: return KEY_LSUPER
;
386 case KOS32_SC_RCTRL
: return KEY_RCTRL
;
387 case KOS32_SC_RSHIFT
: return KEY_RSHIFT
;
388 case KOS32_SC_RALT
: return KEY_RALT
;
389 case KOS32_SC_RSUPER
: return KEY_RSUPER
;
390 default: return KEY_UNKNOWN
;
394 static void handle_scancode (int code
) {
397 ST_print_down_1
, ST_print_down_2
,
398 ST_print_up_1
, ST_print_up_2
,
399 ST_pause_1
, ST_pause_2
, ST_pause_3
, ST_pause_4
, ST_pause_5
,
403 // logo("scancode >> 0x%x\n", code);
406 if (code
== KOS32_SC_EXTENDED
) {
408 } else if (code
== KOS32_SC_EXTENDED_PAUSE
) {
412 k
= scancode_to_key(code
& 0x7f);
413 down
= !((code
>> 7) & 1);
418 state
= ST_print_down_1
;
419 } else if (code
== 0xB7) {
420 state
= ST_print_up_1
;
423 k
= ext_scancode_to_key(code
& 0x7f);
424 down
= !((code
>> 7) & 1);
427 case ST_print_down_1
:
428 assert(code
== 0xE0);
429 state
= ST_print_down_2
;
431 case ST_print_down_2
:
432 assert(code
== 0x37);
438 assert(code
== 0xE0);
439 state
= ST_print_up_2
;
442 assert(code
== 0xAA);
448 assert(code
== 0x1D);
452 assert(code
== 0x45);
456 assert(code
== 0xE1);
460 assert(code
== 0x9D);
464 assert(code
== 0xC5);
470 ERR_fatal("handle_scancode: invalid state: %i\n", state
);
472 if (state
== ST_ok
) {
474 // logo("key: %s (%i, %s)\n", I_key_to_string(k), k, down ? "down" : "up");
484 static void poll_events (void) {
485 int ev
, key
, button
, code
, ch
, k
;
486 while((ev
= CheckEvent()) != KOS32_EVENT_NONE
) {
488 case KOS32_EVENT_REDRAW
:
490 Y_repaint(); /* redraw window */
493 case KOS32_EVENT_KEYBOARD
:
495 if ((key
& 0xff) == 0) {
496 switch (GetInputMode()) {
497 case KOS32_INPUT_MODE_ASCII
:
498 ch
= (key
>> 8) & 0xff;
499 code
= (key
>> 16) & 0x7f;
500 k
= scancode_to_key(code
);
507 case KOS32_INPUT_MODE_SCANCODE
:
509 handle_scancode(code
);
514 case KOS32_EVENT_BUTTON
:
515 button
= GetButton();
516 quit
= button
== 256; /* close button + left click */
519 ERR_fatal("poll_events: unhandled event: %i\n", ev
);
524 static void game_loop (void) {
525 static long ticks
; /* ns */
526 ticks
= GetTimeCountPro();
530 long t
= GetTimeCountPro(); /* ns */
531 int n
= (t
- ticks
) / ((DELAY
+ 1) * 1000000);
532 ticks
= ticks
+ n
* ((DELAY
+ 1) * 1000000);
544 int main (int argc
, char **argv
) {
545 CFG_args(argc
, argv
);
546 logo("system: initialize engine\n");
547 SetEventsMask(KOS32_EVENT_FLAG_REDRAW
| KOS32_EVENT_FLAG_KEYBOARD
| KOS32_EVENT_FLAG_BUTTON
);
548 Y_disable_text_input();
554 pl1
.kf
= KEY_PAGEDOWN
;
569 srand(GetIdleCount());
571 F_addwad("doom2d.wad");
577 logo("system: game loop\n");
579 logo("system: finalize engine\n");
584 logo("system: halt\n");