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
48 static byte pcolortab
[PCOLORN
] = {
49 0x18, 0x20, 0x40, 0x58, 0x60, 0x70, 0x80, 0xB0, 0xC0, 0xD0
51 static int p1color
= 5;
52 static int p2color
= 4;
61 static int stack_p
= -1;
63 #define GM_MAX_INPUT 24
64 char ibuf
[GM_MAX_INPUT
];
72 static int qsnd
[QSND_NUM
];
73 static snd_t
*csnd1
, *csnd2
, *msnd1
, *msnd2
, *msnd3
, *msnd4
, *msnd5
, *msnd6
;
77 static void GM_stop (void) {
88 static void GM_say (const char nm
[8]) {
89 snd_t
*snd
= S_load(nm
);
93 voc_ch
= S_play(voc
, 0, 255);
97 int GM_init_int0 (new_msg_t
*msg
, int i
, int a
, int b
, int s
) {
106 int GM_init_int (new_msg_t
*msg
, int i
, int a
, int b
, int s
) {
110 return GM_init_int0(msg
, min(max(i
, a
), b
), a
, b
, s
);
113 int GM_init_str (new_msg_t
*msg
, char *str
, int maxlen
) {
118 msg
->string
.maxlen
= maxlen
;
122 static int GM_newgame_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
124 intptr_t i
= (intptr_t)data
;
133 case 0: GM_say("_1PLAYER"); break;
134 case 1: GM_say("_2PLAYER"); break;
135 case 2: GM_say("_DM"); break;
139 case 2: // DEATHMATCH
141 case 1: // COOPERATIVE
143 case 0: // SINGLEPLAYER
144 g_map
= _warp
? _warp
: 1;
146 pl1
.color
= pcolortab
[p1color
];
147 pl2
.color
= pcolortab
[p2color
];
157 static int GM_var_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
159 if (data
== &snd_vol
) {
161 case GM_GETINT
: return GM_init_int(msg
, snd_vol
, 0, 128, 8);
162 case GM_SETINT
: S_volume(msg
->integer
.i
); return 1;
164 } else if (data
== &mus_vol
) {
166 case GM_GETINT
: return GM_init_int(msg
, mus_vol
, 0, 128, 8);
167 case GM_SETINT
: S_volumemusic(msg
->integer
.i
); return 1;
169 } else if (data
== g_music
) {
172 return GM_init_str(msg
, g_music
, 8);
177 S_startmusic(music_time
* 2); // ???
184 static int GM_load_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
186 intptr_t i
= (intptr_t)data
;
192 return GM_init_str(msg
, (char*)savname
[i
], 24);
204 static int GM_save_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
206 intptr_t i
= (intptr_t)data
;
209 if (g_st
== GS_GAME
) {
217 return GM_init_str(msg
, (char*)savname
[i
], 24);
219 if (g_st
== GS_GAME
) {
220 F_savegame(i
, msg
->string
.s
); // TODO check size
229 static int GM_options_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
231 case GM_SELECT
: GM_push(R_menu()); return 1;
236 static int GM_exit_handler (new_msg_t
*msg
, const new_menu_t
*m
, void *data
) {
239 GM_say(rand() & 1 ? "_EXIT1" : "_EXIT2");
245 Z_sound(S_get(qsnd
[myrand(QSND_NUM
)]), 255);
256 static const new_menu_t newgame_menu
= {
257 GM_BIG
, "New game", NULL
, NULL
,
259 { GM_BUTTON
, "One player", (void*)0, &GM_newgame_handler
, NULL
},
260 { GM_BUTTON
, "Two players", (void*)1, &GM_newgame_handler
, NULL
},
261 { GM_BUTTON
, "Deathmatch", (void*)2, &GM_newgame_handler
, NULL
},
262 { 0, NULL
, NULL
, NULL
, NULL
} // end
265 GM_BIG
, "Load game", NULL
, &GM_load_handler
,
267 { GM_TEXTFIELD_BUTTON
, "", (void*)0, &GM_load_handler
, NULL
},
268 { GM_TEXTFIELD_BUTTON
, "", (void*)1, &GM_load_handler
, NULL
},
269 { GM_TEXTFIELD_BUTTON
, "", (void*)2, &GM_load_handler
, NULL
},
270 { GM_TEXTFIELD_BUTTON
, "", (void*)3, &GM_load_handler
, NULL
},
271 { GM_TEXTFIELD_BUTTON
, "", (void*)4, &GM_load_handler
, NULL
},
272 { GM_TEXTFIELD_BUTTON
, "", (void*)5, &GM_load_handler
, NULL
},
273 { GM_TEXTFIELD_BUTTON
, "", (void*)6, &GM_load_handler
, NULL
},
274 { 0, NULL
, NULL
, NULL
, NULL
} // end
277 GM_BIG
, "Save game", NULL
, &GM_save_handler
,
279 { GM_TEXTFIELD
, "", (void*)0, &GM_save_handler
, NULL
},
280 { GM_TEXTFIELD
, "", (void*)1, &GM_save_handler
, NULL
},
281 { GM_TEXTFIELD
, "", (void*)2, &GM_save_handler
, NULL
},
282 { GM_TEXTFIELD
, "", (void*)3, &GM_save_handler
, NULL
},
283 { GM_TEXTFIELD
, "", (void*)4, &GM_save_handler
, NULL
},
284 { GM_TEXTFIELD
, "", (void*)5, &GM_save_handler
, NULL
},
285 { GM_TEXTFIELD
, "", (void*)6, &GM_save_handler
, NULL
},
286 { 0, NULL
, NULL
, NULL
, NULL
} // end
289 GM_BIG
, "Sound", NULL
, NULL
,
291 { GM_SCROLLER
, "Volume", &snd_vol
, &GM_var_handler
, NULL
},
292 { 0, NULL
, NULL
, NULL
, NULL
} // end
295 GM_BIG
, "Music", NULL
, NULL
,
297 { GM_SCROLLER
, "Volume", &mus_vol
, &GM_var_handler
, NULL
},
298 { GM_BUTTON
, "Music: ", g_music
, &GM_var_handler
, NULL
},
299 { 0, NULL
, NULL
, NULL
, NULL
} // end
302 GM_BIG
, "Options", NULL
, NULL
,
304 { GM_BUTTON
, "Video", NULL
, &GM_options_handler
, NULL
},
305 { GM_BUTTON
, "Sound", NULL
, NULL
, &sound_menu
},
306 { GM_BUTTON
, "Music", NULL
, NULL
, &music_menu
},
307 { 0, NULL
, NULL
, NULL
, NULL
} // end
310 GM_SMALL
, "You are sure?", NULL
, &GM_exit_handler
,
312 { GM_SMALL_BUTTON
, "Yes", (void*)1, &GM_exit_handler
, NULL
},
313 { GM_SMALL_BUTTON
, "No", (void*)0, &GM_exit_handler
, NULL
},
314 { 0, NULL
, NULL
, NULL
, NULL
} // end
317 GM_BIG
, "Menu", NULL
, NULL
,
319 { GM_BUTTON
, "New game", NULL
, NULL
, &newgame_menu
},
320 { GM_BUTTON
, "Load game", NULL
, NULL
, &loadgame_menu
},
321 { GM_BUTTON
, "Save game", NULL
, NULL
, &savegame_menu
},
322 { GM_BUTTON
, "Options", NULL
, NULL
, &options_menu
},
323 { GM_BUTTON
, "Exit", NULL
, NULL
, &exit_menu
},
324 { 0, NULL
, NULL
, NULL
, NULL
} // end
328 void GM_push (const new_menu_t
*m
) {
330 assert(stack_p
>= -1);
331 assert(stack_p
< MAX_STACK
- 1);
334 if (stack
[stack_p
].m
!= m
) {
335 stack
[stack_p
].n
= 0;
336 stack
[stack_p
].m
= m
;
339 GM_send_this(m
, &msg
);
343 assert(stack_p
>= 0);
347 GM_send_this(stack
[stack_p
+ 1].m
, &msg
);
350 void GM_popall (void) {
352 for (i
= 0; i
>= -1; i
--) {
357 const new_menu_t
*GM_get (void) {
359 return stack
[stack_p
].m
;
367 return stack
[stack_p
].n
;
373 static void GM_normalize_message (new_msg_t
*msg
) {
376 msg
->integer
.i
= min(max(msg
->integer
.i
, msg
->integer
.a
), msg
->integer
.b
);
379 assert(msg
->string
.maxlen
>= 0);
384 static int count_menu_entries (const new_menu_t
*m
) {
387 while (m
->entries
[i
].type
!= 0) {
393 int GM_send_this (const new_menu_t
*m
, new_msg_t
*msg
) {
399 n
= count_menu_entries(m
);
400 return GM_init_int0(msg
, GM_geti(), n
, n
, m
->type
);
402 return GM_init_str(msg
, m
->title
, strlen(m
->title
));
404 if (m
->handler
!= NULL
) {
405 GM_normalize_message(msg
);
406 return m
->handler(msg
, m
, m
->data
);
412 int GM_send (const new_menu_t
*m
, int i
, new_msg_t
*msg
) {
416 const new_var_t
*v
= &m
->entries
[i
];
418 case GM_GETENTRY
: return GM_init_int0(msg
, v
->type
, 0, 0, 0);
419 case GM_GETCAPTION
: return GM_init_str(msg
, v
->caption
, strlen(v
->caption
));
421 if (v
->handler
!= NULL
) {
422 GM_normalize_message(msg
);
423 return v
->handler(msg
, m
, v
->data
);
432 if(memcmp(cbuf
+32-5,"IDDQD",5)==0) {
433 PL_hit(&pl1
,400,0,HIT_SOME
);
434 if(_2pl
) PL_hit(&pl2
,400,0,HIT_SOME
);
436 }else if(memcmp(cbuf
+32-4,"TANK",4)==0) {
437 pl1
.life
=pl1
.armor
=200;pl1
.drawst
|=PL_DRAWARMOR
|PL_DRAWLIFE
;
438 if(_2pl
) {pl2
.life
=pl2
.armor
=200;pl2
.drawst
|=PL_DRAWARMOR
|PL_DRAWLIFE
;}
439 }else if(memcmp(cbuf
+32-8,"BULLFROG",8)==0) {
440 PL_JUMP
=(PL_JUMP
==10)?20:10;
441 }else if(memcmp(cbuf
+32-8,"FORMULA1",8)==0) {
442 PL_RUN
=(PL_RUN
==8)?24:8;
443 }else if(memcmp(cbuf
+32-5,"RAMBO",5)==0) {
444 pl1
.ammo
=pl1
.shel
=pl1
.rock
=pl1
.cell
=pl1
.fuel
=30000;
445 pl1
.wpns
=0x7FF;pl1
.drawst
|=PL_DRAWWPN
|PL_DRAWKEYS
;
448 pl2
.ammo
=pl2
.shel
=pl2
.rock
=pl2
.cell
=pl1
.fuel
=30000;
449 pl2
.wpns
=0x7FF;pl2
.drawst
|=PL_DRAWWPN
|PL_DRAWKEYS
;
452 }else if(memcmp(cbuf
+32-5,"UJHTW",5)==0) {
453 p_immortal
=!p_immortal
;
454 }else if(memcmp(cbuf
+32-9,",TKSQJHTK",9)==0) {
456 }else if(memcmp(cbuf
+32-6,"CBVCBV",6)==0) {
458 }else if(memcmp(cbuf
+32-7,"GOODBYE",7)==0) {
460 }else if(memcmp(cbuf
+32-9,"GJITKYF",7)==0) {
461 if(cbuf
[30]>='0' && cbuf
[30]<='9' && cbuf
[31]>='0' && cbuf
[31]<='9') {
462 g_map
=(cbuf
[30]=='0')?0:(cbuf
[30]-'0')*10;
463 g_map
+=(cbuf
[31]=='0')?0:(cbuf
[31]-'0');
471 static int strnlen (const char *s
, int len
) {
473 while (i
< len
&& s
[i
] != 0) {
479 static int state_for_anykey (int x
) {
480 return x
== GS_TITLE
|| x
== GS_ENDSCR
;
487 const new_menu_t
*m
= GM_get ();
489 if (lastkey
== KEY_ESCAPE
|| (state_for_anykey(g_st
) && lastkey
!= KEY_UNKNOWN
)) {
494 n
= count_menu_entries(m
);
495 cur
= stack
[stack_p
].n
;
496 v
= &m
->entries
[cur
];
499 if (v
->type
== GM_TEXTFIELD
&& input
) {
501 Y_disable_text_input();
502 msg
.type
= GM_CANCEL
;
503 GM_send(m
, cur
, &msg
);
510 stack
[stack_p
].n
= stack
[stack_p
].n
- 1 < 0 ? n
- 1 : stack
[stack_p
].n
- 1;
514 stack
[stack_p
].n
= stack
[stack_p
].n
+ 1 >= n
? 0 : stack
[stack_p
].n
+ 1;
519 if (v
->type
== GM_SCROLLER
) {
520 msg
.integer
.type
= GM_GETINT
;
521 if (GM_send(m
, cur
, &msg
)) {
522 msg
.integer
.type
= GM_SETINT
;
523 msg
.integer
.i
+= lastkey
== KEY_LEFT
? -msg
.integer
.s
: msg
.integer
.s
;
524 msg
.integer
.i
= min(max(msg
.integer
.i
, msg
.integer
.a
), msg
.integer
.b
);
525 if (GM_send(m
, cur
, &msg
)) {
526 Z_sound(lastkey
== KEY_LEFT
? msnd5
: msnd6
, 255);
529 } else if (v
->type
== GM_TEXTFIELD
&& input
) {
530 //icur += lastkey == KEY_LEFT ? -1 : +1;
531 //icur = min(max(icur, 0), strnlen(ibuf, imax));
535 if (v
->type
== GM_TEXTFIELD
&& input
) {
537 // FIXIT buffers in strncpy must not overlap
538 strncpy(&ibuf
[icur
- 1], &ibuf
[icur
], imax
- icur
);
545 if (v
->submenu
!= NULL
) {
548 } else if (v
->type
== GM_TEXTFIELD
) {
551 Y_disable_text_input();
554 msg
.string
.maxlen
= imax
;
555 GM_send(m
, cur
, &msg
);
557 msg
.type
= GM_GETSTR
;
558 if (GM_send(m
, cur
, &msg
)) {
559 imax
= min(msg
.string
.maxlen
, GM_MAX_INPUT
);
560 strncpy(ibuf
, msg
.string
.s
, imax
);
561 icur
= strnlen(ibuf
, imax
);
564 Y_enable_text_input();
566 GM_send(m
, cur
, &msg
);
569 msg
.type
= GM_SELECT
;
570 GM_send(m
, cur
, &msg
);
575 lastkey
= KEY_UNKNOWN
;
579 void GM_input (int ch
) {
580 if (ch
!= 0 && input
) {
591 void GM_key (int key
, int down
) {
595 if (!_2pl
|| cheat
) {
596 for (i
= 0; i
< 31; i
++) {
597 cbuf
[i
] = cbuf
[i
+ 1];
599 if (key
>= KEY_0
&& key
<= KEY_9
) {
600 cbuf
[31] = key
- KEY_0
+ '0';
601 } else if (key
>= KEY_A
&& key
<= KEY_Z
) {
602 cbuf
[31] = key
- KEY_A
+ 'A';
610 void GM_init (void) {
613 static const char nm
[QSND_NUM
][6] = {
614 "CYBSIT", "KNTDTH", "MNPAIN", "PEPAIN", "SLOP", "MANSIT", "BOSPN", "VILACT",
615 "PLFALL", "BGACT", "BGDTH2", "POPAIN", "SGTATK", "VILDTH"
619 for (i
= 0; i
< QSND_NUM
; ++i
) {
620 memcpy(s
+ 2, nm
[i
], 6);
621 qsnd
[i
] = F_getresid(s
);
623 csnd1
= Z_getsnd("HAHA1");
624 csnd2
= Z_getsnd("RADIO");
625 msnd1
= Z_getsnd("PSTOP");
626 msnd2
= Z_getsnd("PISTOL");
627 msnd3
= Z_getsnd("SWTCHN");
628 msnd4
= Z_getsnd("SWTCHX");
629 msnd5
= Z_getsnd("SUDI");
630 msnd6
= Z_getsnd("TUDI");