2 Copyright (C) Prikol Software 1996-1997
3 Copyright (C) Aleksey Volynskov 1996-1997
4 Copyright (C) <ARembo@gmail.com> 2011
6 This file is part of the Doom2D:Rembo project.
8 Doom2D:Rembo is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as
10 published by the Free Software Foundation.
12 Doom2D:Rembo is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/> or
19 write to the Free Software Foundation, Inc.,
20 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
50 static byte pcolortab
[PCOLORN
] = {
51 0x18, 0x20, 0x40, 0x58, 0x60, 0x70, 0x80, 0xB0, 0xC0, 0xD0
53 static int p1color
= 5;
54 static int p2color
= 4;
62 static int stack_p
= -1;
64 #define GM_MAX_INPUT 24
65 char ibuf
[GM_MAX_INPUT
];
73 static int qsnd
[QSND_NUM
];
74 static snd_t
*csnd1
, *csnd2
, *msnd1
, *msnd2
, *msnd3
, *msnd4
, *msnd5
, *msnd6
;
78 static void GM_stop (void) {
89 static int GM_say (const char nm
[8]) {
90 snd_t
*snd
= S_load(nm
);
94 voc_ch
= S_play(voc
, 0, 255);
99 int GM_init_int0 (menu_msg_t
*msg
, int i
, int a
, int b
, int s
) {
108 int GM_init_int (menu_msg_t
*msg
, int i
, int a
, int b
, int s
) {
112 return GM_init_int0(msg
, min(max(i
, a
), b
), a
, b
, s
);
115 int GM_init_str (menu_msg_t
*msg
, char *str
, int maxlen
) {
120 msg
->string
.maxlen
= maxlen
;
124 int basic_menu_handler (menu_msg_t
*msg
, byte type
, char *title
, char *say
, int n
, int *cur
) {
126 assert(type
== GM_BIG
|| type
== GM_SMALL
);
127 assert(title
!= NULL
);
131 case GM_QUERY
: return GM_init_int0(msg
, *cur
, n
, n
, type
);
132 case GM_GETTITLE
: return GM_init_str(msg
, title
, strlen(title
));
133 case GM_ENTER
: return say
? GM_say(say
) : 1;
134 case GM_UP
: *cur
= GM_CYCLE(*cur
- 1, 0, n
- 1); return 1;
135 case GM_DOWN
: *cur
= GM_CYCLE(*cur
+ 1, 0, n
- 1); return 1;
140 int simple_menu_handler (menu_msg_t
*msg
, int i
, int n
, const simple_menu_t
*m
, int *cur
) {
143 assert(i
>= 0 && i
< n
);
147 case GM_GETENTRY
: return GM_init_int0(msg
, m
->type
== GM_SMALL
? GM_SMALL_BUTTON
: GM_BUTTON
, 0, 0, 0);
148 case GM_GETCAPTION
: return GM_init_str(msg
, m
->entries
[i
].caption
, strlen(m
->entries
[i
].caption
));
149 case GM_SELECT
: return m
->entries
[i
].submenu
? GM_push(m
->entries
[i
].submenu
) : 1;
151 return basic_menu_handler(msg
, m
->type
, m
->title
, m
->say
, n
, cur
);
154 static int start_game (int twoplayers
, int dm
, int level
) {
157 g_map
= level
? level
: 1;
159 pl1
.color
= pcolortab
[p1color
];
160 pl2
.color
= pcolortab
[p2color
];
165 static int new_game_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
167 enum { ONEPLAYER
, TWOPLAYERS
, DEATHMATCH
, __NUM__
};
168 static const simple_menu_t sm
= {
169 GM_BIG
, "New Game", "_NEWGAME",
171 { "One Player", NULL
},
172 { "Two Players", NULL
},
173 { "Deathmatch", NULL
},
176 if (msg
->type
== GM_SELECT
) {
178 case ONEPLAYER
: GM_say("_1PLAYER"); return start_game(0, 0, _warp
);
179 case TWOPLAYERS
: GM_say("_2PLAYER"); return start_game(1, 0, _warp
);
180 case DEATHMATCH
: GM_say("_DM"); return start_game(1, 1, _warp
);
184 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
187 static const menu_t new_game_menu
= {
188 NULL
, &new_game_menu_handler
191 static int load_game_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
193 const int max_slots
= 7;
194 assert(i
>= 0 && i
< max_slots
);
196 case GM_ENTER
: F_getsavnames(); break;
197 case GM_GETENTRY
: return GM_init_int0(msg
, GM_TEXTFIELD_BUTTON
, 0, 0, 0);
198 case GM_GETSTR
: return GM_init_str(msg
, (char*)savname
[i
], 24);
206 return basic_menu_handler(msg
, GM_BIG
, "Load game", "_OLDGAME", max_slots
, &cur
);
209 static const menu_t load_game_menu
= {
210 NULL
, &load_game_menu_handler
213 static int save_game_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
215 const int max_slots
= 7;
216 assert(i
>= 0 && i
< max_slots
);
219 if (g_st
== GS_GAME
) {
225 case GM_GETENTRY
: return GM_init_int0(msg
, GM_TEXTFIELD
, 0, 0, 0);
226 case GM_GETSTR
: return GM_init_str(msg
, (char*)savname
[i
], 24);
228 if (g_st
== GS_GAME
) {
229 assert(msg
->string
.maxlen
>= 24);
230 F_savegame(i
, msg
->string
.s
);
234 return basic_menu_handler(msg
, GM_BIG
, "Save game", "_SAVGAME", max_slots
, &cur
);
237 static const menu_t save_game_menu
= {
238 NULL
, &save_game_menu_handler
241 static int sound_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
243 enum { VOLUME
, __NUM__
};
244 static const simple_menu_t sm
= {
245 GM_BIG
, "Sound", NULL
,
252 case GM_GETENTRY
: return GM_init_int0(msg
, GM_SCROLLER
, 0, 0, 0);
253 case GM_GETINT
: return GM_init_int(msg
, snd_vol
, 0, 128, 8);
254 case GM_SETINT
: S_volume(msg
->integer
.i
); return 1;
257 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
260 static const menu_t sound_menu
= {
261 NULL
, &sound_menu_handler
264 static int music_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
266 enum { VOLUME
, MUSIC
, __NUM__
};
267 static const simple_menu_t sm
= {
268 GM_BIG
, "Music", NULL
,
276 case GM_GETENTRY
: return GM_init_int0(msg
, GM_SCROLLER
, 0, 0, 0);
277 case GM_GETINT
: return GM_init_int(msg
, mus_vol
, 0, 128, 8);
278 case GM_SETINT
: S_volumemusic(msg
->integer
.i
); return 1;
280 } else if (i
== MUSIC
) {
282 case GM_GETSTR
: return GM_init_str(msg
, g_music
, strlen(g_music
));
287 S_startmusic(music_time
* 2); // ???
291 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
294 static const menu_t music_menu
= {
295 NULL
, &music_menu_handler
298 static int options_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
300 enum { VIDEO
, SOUND
, MUSIC
, __NUM__
};
301 static const simple_menu_t sm
= {
302 GM_BIG
, "Options", NULL
,
305 { "Sound", &sound_menu
},
306 { "Music", &music_menu
},
309 if (msg
->type
== GM_SELECT
) {
311 const menu_t
*mm
= R_menu();
312 return mm
? GM_push(mm
) : 1;
315 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
318 static const menu_t options_menu
= {
319 NULL
, &options_menu_handler
322 static int exit_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
324 enum { YES
, NO
, __NUM__
};
325 static const simple_menu_t sm
= {
326 GM_SMALL
, "You are sure?", NULL
,
332 if (msg
->type
== GM_ENTER
) {
333 return GM_say(rand() & 1 ? "_EXIT1" : "_EXIT2");
334 } else if (msg
->type
== GM_SELECT
) {
339 Z_sound(S_get(qsnd
[myrand(QSND_NUM
)]), 255);
347 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
350 static const menu_t exit_menu
= {
351 NULL
, &exit_menu_handler
354 static int main_menu_handler (menu_msg_t
*msg
, const menu_t
*m
, void *data
, int i
) {
356 enum { NEWGAME
, OLDGAME
, SAVEGAME
, OPTIONS
, EXIT
, __NUM__
};
357 assert(i
>= 0 && i
< __NUM__
);
358 static const simple_menu_t sm
= {
359 GM_BIG
, "Menu", NULL
,
361 { "New Game", &new_game_menu
},
362 { "Load Game", &load_game_menu
},
363 { "Save Game", &save_game_menu
},
364 { "Options", &options_menu
},
365 { "Exit", &exit_menu
},
368 return simple_menu_handler(msg
, i
, __NUM__
, &sm
, &cur
);
371 static const menu_t main_menu
= {
372 NULL
, &main_menu_handler
375 int GM_push (const menu_t
*m
) {
377 assert(stack_p
>= -1);
378 assert(stack_p
< MAX_STACK
- 1);
381 stack
[stack_p
].m
= m
;
383 GM_send_this(m
, &msg
);
388 assert(stack_p
>= 0);
392 GM_send_this(stack
[stack_p
+ 1].m
, &msg
);
396 int GM_popall (void) {
398 for (i
= 0; i
>= -1; i
--) {
404 const menu_t
*GM_get (void) {
406 return stack
[stack_p
].m
;
412 static void GM_normalize_message (menu_msg_t
*msg
) {
415 msg
->integer
.i
= min(max(msg
->integer
.i
, msg
->integer
.a
), msg
->integer
.b
);
418 assert(msg
->string
.maxlen
>= 0);
423 int GM_send_this (const menu_t
*m
, menu_msg_t
*msg
) {
426 if (m
->handler
!= NULL
) {
427 GM_normalize_message(msg
);
428 return m
->handler(msg
, m
, m
->data
, 0);
433 int GM_send (const menu_t
*m
, int i
, menu_msg_t
*msg
) {
437 if (m
->handler
!= NULL
) {
438 GM_normalize_message(msg
);
439 return m
->handler(msg
, m
, m
->data
, i
);
447 if(memcmp(cbuf
+32-5,"IDDQD",5)==0) {
448 PL_hit(&pl1
,400,0,HIT_SOME
);
449 if(_2pl
) PL_hit(&pl2
,400,0,HIT_SOME
);
451 }else if(memcmp(cbuf
+32-4,"TANK",4)==0) {
452 pl1
.life
=pl1
.armor
=200;pl1
.drawst
|=PL_DRAWARMOR
|PL_DRAWLIFE
;
453 if(_2pl
) {pl2
.life
=pl2
.armor
=200;pl2
.drawst
|=PL_DRAWARMOR
|PL_DRAWLIFE
;}
454 }else if(memcmp(cbuf
+32-8,"BULLFROG",8)==0) {
455 PL_JUMP
=(PL_JUMP
==10)?20:10;
456 }else if(memcmp(cbuf
+32-8,"FORMULA1",8)==0) {
457 PL_RUN
=(PL_RUN
==8)?24:8;
458 }else if(memcmp(cbuf
+32-5,"RAMBO",5)==0) {
459 pl1
.ammo
=pl1
.shel
=pl1
.rock
=pl1
.cell
=pl1
.fuel
=30000;
460 pl1
.wpns
=0x7FF;pl1
.drawst
|=PL_DRAWWPN
|PL_DRAWKEYS
;
463 pl2
.ammo
=pl2
.shel
=pl2
.rock
=pl2
.cell
=pl1
.fuel
=30000;
464 pl2
.wpns
=0x7FF;pl2
.drawst
|=PL_DRAWWPN
|PL_DRAWKEYS
;
467 }else if(memcmp(cbuf
+32-5,"UJHTW",5)==0) {
468 p_immortal
=!p_immortal
;
469 }else if(memcmp(cbuf
+32-9,",TKSQJHTK",9)==0) {
471 }else if(memcmp(cbuf
+32-6,"CBVCBV",6)==0) {
473 }else if(memcmp(cbuf
+32-7,"GOODBYE",7)==0) {
475 }else if(memcmp(cbuf
+32-9,"GJITKYF",7)==0) {
476 if(cbuf
[30]>='0' && cbuf
[30]<='9' && cbuf
[31]>='0' && cbuf
[31]<='9') {
477 g_map
=(cbuf
[30]=='0')?0:(cbuf
[30]-'0')*10;
478 g_map
+=(cbuf
[31]=='0')?0:(cbuf
[31]-'0');
486 static int strnlen (const char *s
, int len
) {
488 while (i
< len
&& s
[i
] != 0) {
494 static int state_for_anykey (int x
) {
495 return x
== GS_TITLE
|| x
== GS_ENDSCR
;
501 const menu_t
*m
= GM_get();
503 if (lastkey
== KEY_ESCAPE
|| (state_for_anykey(g_st
) && lastkey
!= KEY_UNKNOWN
)) {
509 if (GM_send_this(m
, &msg
)) {
512 msg
.type
= GM_GETENTRY
;
513 if (GM_send(m
, cur
, &msg
)) {
514 type
= msg
.integer
.i
;
517 if (type
== GM_TEXTFIELD
&& input
) {
519 Y_disable_text_input();
520 msg
.type
= GM_CANCEL
;
521 GM_send(m
, cur
, &msg
);
530 msg
.type
= lastkey
== KEY_UP
? GM_UP
: GM_DOWN
;
531 if (GM_send(m
, cur
, &msg
)) {
538 if (type
== GM_SCROLLER
) {
539 msg
.integer
.type
= GM_GETINT
;
540 if (GM_send(m
, cur
, &msg
)) {
541 msg
.integer
.type
= GM_SETINT
;
542 msg
.integer
.i
+= lastkey
== KEY_LEFT
? -msg
.integer
.s
: msg
.integer
.s
;
543 msg
.integer
.i
= min(max(msg
.integer
.i
, msg
.integer
.a
), msg
.integer
.b
);
544 if (GM_send(m
, cur
, &msg
)) {
545 Z_sound(lastkey
== KEY_LEFT
? msnd5
: msnd6
, 255);
548 } else if (type
== GM_TEXTFIELD
) {
550 // icur += lastkey == KEY_LEFT ? -1 : +1;
551 // icur = min(max(icur, 0), strnlen(ibuf, imax));
556 if (type
== GM_TEXTFIELD
) {
557 if (input
&& icur
> 0) {
558 // FIXIT buffers in strncpy must not overlap
559 strncpy(&ibuf
[icur
- 1], &ibuf
[icur
], imax
- icur
);
566 if (type
== GM_TEXTFIELD
) {
569 Y_disable_text_input();
572 msg
.string
.maxlen
= imax
;
573 GM_send(m
, cur
, &msg
);
575 msg
.type
= GM_GETSTR
;
576 if (GM_send(m
, cur
, &msg
)) {
577 imax
= min(msg
.string
.maxlen
, GM_MAX_INPUT
);
578 strncpy(ibuf
, msg
.string
.s
, imax
);
579 icur
= strnlen(ibuf
, imax
);
581 memset(ibuf
, 0, GM_MAX_INPUT
);
586 Y_enable_text_input();
588 GM_send(m
, cur
, &msg
);
592 msg
.type
= GM_SELECT
;
593 if (cur
< 0) abort();
594 if (GM_send(m
, cur
, &msg
)) {
603 lastkey
= KEY_UNKNOWN
;
607 void GM_input (int ch
) {
608 if (ch
!= 0 && input
) {
619 void GM_key (int key
, int down
) {
623 if (!_2pl
|| cheat
) {
624 for (i
= 0; i
< 31; i
++) {
625 cbuf
[i
] = cbuf
[i
+ 1];
627 if (key
>= KEY_0
&& key
<= KEY_9
) {
628 cbuf
[31] = key
- KEY_0
+ '0';
629 } else if (key
>= KEY_A
&& key
<= KEY_Z
) {
630 cbuf
[31] = key
- KEY_A
+ 'A';
638 void GM_init (void) {
641 static const char nm
[QSND_NUM
][6] = {
642 "CYBSIT", "KNTDTH", "MNPAIN", "PEPAIN", "SLOP", "MANSIT", "BOSPN", "VILACT",
643 "PLFALL", "BGACT", "BGDTH2", "POPAIN", "SGTATK", "VILDTH"
647 for (i
= 0; i
< QSND_NUM
; ++i
) {
648 memcpy(s
+ 2, nm
[i
], 6);
649 qsnd
[i
] = F_getresid(s
);
651 csnd1
= Z_getsnd("HAHA1");
652 csnd2
= Z_getsnd("RADIO");
653 msnd1
= Z_getsnd("PSTOP");
654 msnd2
= Z_getsnd("PISTOL");
655 msnd3
= Z_getsnd("SWTCHN");
656 msnd4
= Z_getsnd("SWTCHX");
657 msnd5
= Z_getsnd("SUDI");
658 msnd6
= Z_getsnd("TUDI");