1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: g_game.c 1566 2020-12-19 06:22:58Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: g_game.c,v $
21 // Revision 1.50 2004/09/12 19:40:05 darkwolf95
22 // additional chex quest 1 support
23 //
24 // Revision 1.49 2004/07/27 08:19:35 exl
25 // New fmod, fs functions, bugfix or 2, patrol nodes
26 //
27 // Revision 1.48 2003/11/22 00:49:33 darkwolf95
28 //
29 // Revision 1.47 2003/11/22 00:22:09 darkwolf95
30 // get rid of FS hud pics on level exit and new game, also added exl's fix for clearing hub variables on new game
31 //
32 // Revision 1.46 2003/03/22 22:35:59 hurdler
33 //
34 // Revision 1.45 2002/09/27 16:40:08 tonyd
35 // First commit of acbot
36 //
37 // Revision 1.44 2002/08/24 22:42:02 hurdler
38 // Apply Robert Hogberg patches
39 //
40 // Revision 1.43 2001/12/26 17:24:46 hurdler
41 // Update Linux version
42 //
43 // Revision 1.42 2001/12/15 18:41:35 hurdler
44 // small commit, mainly splitscreen fix
45 //
46 // Revision 1.41 2001/08/20 20:40:39 metzgermeister
47 //
48 // Revision 1.40 2001/08/20 18:34:18 bpereira
49 // glide ligthing and map30 bug
50 //
51 // Revision 1.39 2001/08/12 15:21:04 bpereira
52 // see my log
53 //
54 // Revision 1.38 2001/08/02 19:15:59 bpereira
55 // fix player reset in secret level of doom2
56 //
57 // Revision 1.37 2001/07/16 22:35:40 bpereira
58 // - fixed crash of e3m8 in heretic
59 // - fixed crosshair not drawed bug
60 //
61 // Revision 1.36 2001/05/16 21:21:14 bpereira
62 // Revision 1.35 2001/05/03 21:22:25 hurdler
63 //
64 // Revision 1.34 2001/04/17 22:26:07 calumr
65 // Initial Mac add
66 //
67 // Revision 1.33 2001/04/01 17:35:06 bpereira
68 // Revision 1.32 2001/03/03 06:17:33 bpereira
69 // Revision 1.31 2001/02/24 13:35:19 bpereira
70 // Revision 1.30 2001/02/10 12:27:13 bpereira
71 //
72 // Revision 1.29 2001/01/25 22:15:41 bpereira
73 // added heretic support
74 //
75 // Revision 1.28 2000/11/26 20:36:14 hurdler
76 // Adding autorun2
77 //
78 // Revision 1.27 2000/11/11 13:59:45 bpereira
79 // Revision 1.26 2000/11/06 20:52:15 bpereira
80 // Revision 1.25 2000/11/04 16:23:42 bpereira
81 // Revision 1.24 2000/11/02 19:49:35 bpereira
82 //
83 // Revision 1.23 2000/11/02 17:50:06 stroggonmeth
84 // Big 3Dfloors & FraggleScript commit!!
85 //
86 // Revision 1.22 2000/10/21 08:43:28 bpereira
87 // Revision 1.21 2000/10/09 14:03:31 crashrl
88 // Revision 1.20 2000/10/08 13:30:00 bpereira
89 //
90 // Revision 1.19 2000/10/07 20:36:13 crashrl
91 // Added deathmatch team-start-sectors via sector/line-tag and linedef-type 1000-1031
92 //
93 // Revision 1.18 2000/10/01 10:18:17 bpereira
94 // Revision 1.17 2000/09/28 20:57:14 bpereira
95 // Revision 1.16 2000/08/31 14:30:55 bpereira
96 // Revision 1.15 2000/08/10 14:08:48 hurdler
97 // Revision 1.14 2000/04/30 10:30:10 bpereira
98 // Revision 1.13 2000/04/23 16:19:52 bpereira
99 //
100 // Revision 1.12 2000/04/19 10:56:51 hurdler
101 // commited for exe release and tag only
102 //
103 // Revision 1.11 2000/04/16 18:38:07 bpereira
104 //
105 // Revision 1.10 2000/04/11 19:07:23 stroggonmeth
106 // Finished my logs, fixed a crashing bug.
107 //
108 // Revision 1.9 2000/04/07 23:11:17 metzgermeister
109 // added mouse move
110 //
111 // Revision 1.8 2000/04/06 20:40:22 hurdler
112 // Mostly remove warnings under windows
113 //
114 // Revision 1.7 2000/04/04 00:32:45 stroggonmeth
115 // Initial Boom compatability plus few misc changes all around.
116 //
117 // Revision 1.6 2000/03/29 19:39:48 bpereira
118 //
119 // Revision 1.5 2000/03/23 22:54:00 metzgermeister
120 // added support for HOME/.legacy under Linux
121 //
122 // Revision 1.4 2000/02/27 16:30:28 hurdler
123 // dead player bug fix + add allowmlook <yes|no>
124 //
125 // Revision 1.3 2000/02/27 00:42:10 hurdler
126 // Revision 1.2 2000/02/26 00:28:42 hurdler
127 // Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)
128 //
129 //
130 // DESCRIPTION:
131 // game loop functions, events handling
132 //
133 //-----------------------------------------------------------------------------
134
135
136 // [WDJ] To show the demo version on the console
137 #define SHOW_DEMOVERSION
138 #define DEBUG_DEMO
139 // Stick with one demo version because of other ports, and have separate
140 // fields record DoomLegacy specific version and enables.
141 // This only changes the demo header, not the content.
142 // Writes demoversion 143 and up, and can read any DoomLegacy demo.
143 // Older DoomLegacy demos are demo versions 111..143.
144
145 #include "doomincl.h"
146 #include "doomstat.h"
147 #include "command.h"
148 #include "console.h"
149 #include "dstrings.h"
150
151 #include "d_main.h"
152 #include "d_net.h"
153 #include "d_netcmd.h"
154 #include "f_finale.h"
155 #include "p_setup.h"
156 #include "p_saveg.h"
157
158 #include "i_system.h"
159
160 #include "wi_stuff.h"
161 #include "am_map.h"
162 #include "m_random.h"
163 #include "p_local.h"
164 #include "p_tick.h"
165
166 // SKY handling - still the wrong place.
167 #include "r_data.h"
168 #include "r_draw.h"
169 #include "r_main.h"
170 #include "r_sky.h"
171 #include "r_things.h"
172
173 #include "s_sound.h"
174
175 #include "g_game.h"
176 #include "g_input.h"
177
178 //added:16-01-98:quick hack test of rocket trails
179 #include "p_fab.h"
180 #include "m_cheat.h"
181 #include "m_misc.h"
182 #include "m_menu.h"
183 #include "m_argv.h"
184
185 #include "hu_stuff.h"
186
187 #include "st_stuff.h"
188
189 #include "keys.h"
190 #include "i_joy.h"
191 #include "w_wad.h"
192 #include "z_zone.h"
193
194 #include "i_video.h"
195 #include "p_inter.h"
196 #include "p_info.h"
197 #include "byteptr.h"
198 #include "t_script.h"
199
200 #include "b_game.h" //added by AC for acbot
201
202
203
204
205 boolean G_CheckDemoStatus (void);
206 void G_ReadDemoTiccmd (ticcmd_t* cmd,int playernum);
207 void G_WriteDemoTiccmd (ticcmd_t* cmd,int playernum);
208 void G_InitNew (skill_e skill, const char* mapname, boolean resetplayer);
209
210 void G_DoCompleted (void);
211 void G_DoVictory (void);
212 void G_DoWorldDone (void);
213
214
215 // demoversion the 'dynamic' version number, this should be == game VERSION
216 // when playing back demos, 'demoversion' receives the version number of the
217 // demo. At each change to the game play, demoversion is compared to
218 // the game version, if it's older, the changes are not done, and the older
219 // code is used for compatibility.
220 //
221 byte demoversion; // engine behavior version
222 uint16_t demoversion_rev; // demoversion and revision
223
224 // Determined by menu selection, or demo.
225 skill_e gameskill;
226 byte gameepisode; // current game episode number 1..4
227 byte gamemap; // current game map number 1..31
228 char game_map_filename[MAX_WADPATH]; // an external wad filename
229
230
231 // Determined by gamemode and wad.
232 gamemode_e gamemode = indetermined; // Game Mode - identify IWAD as shareware, retail etc.
233
234 // [WDJ] Enables for fast (test for zero) feature tests in the engine.
235 // Byte is efficient and fast to test for 0/1, int is not.
236 // EN_xxx are enables, value = 0/1.
237 // EV_xxx are enum, when value = 0..255, use a byte for efficiency.
238
239 // These are set from gamemode. Still use gamemode in the main setup.
240 // Set by gamemode, but may be enabled by demos too.
241 byte EN_doom_etc; // doom, boom, mbf, common behavior (not heretic, hexen, strife)
242 byte EN_boom; // Boom features (boom demo compatibility=0)
243 byte EN_mbf; // MBF (Marines Best Friend) enable (similar prboom mbf_features)
244 byte EV_legacy; // DoomLegacy version, 0 when some other demo.
245
246 // Raven: Heretic, Hexen, and Strife may be Raven, but code reader
247 // should not need to know that. Keep names explicit for easy code reading.
248 byte EN_heretic_hexen; // common features
249 byte EN_heretic;
250 byte EN_hexen;
251 byte EN_strife;
252
253 // Secondary features.
254 // [WDJ] Prevent demo from altering user game settings.
255 // When a cv_ value range is less than 256, test the EV field (ON/OFF/ENUM).
256 // Demo settings may change the cv_xxx.EV fields or EN_xxx variables.
257 // The cv user settings will be restored after the demo by
258 // CV_Restore_User_Settings (setting .EV from .value).
259 // Derive EN_ enables for special code logic. Need to be set in DemoAdapt
260 // so they are set properly for games and demos.
261 // Boom
262 byte EN_variable_friction; // Boom demo flag, Heretic, and Legacy.
263 byte EN_pushers;
264 byte EN_skull_bounce_fix; // !comp[comp_soul]
265 byte EN_skull_bounce_floor; // PrBoom has this enabled by comp level.
266 byte EN_boom_physics; // !comp[comp_model]
267 byte EN_blazing_double_sound; // comp[comp_blazing]
268 byte EN_vile_revive_bug; // comp[comp_vile]
269 byte EN_sleeping_sarg_bug; // fixed PrBoom 4, no comp
270 byte EN_doorlight; // !comp[comp_doorlight]
271 byte EN_invul_god; // !comp[comp_god]
272 byte EN_boom_floor; // !comp[comp_floors]
273 byte EN_doom_movestep_bug; // comp[comp_moveblock]
274 // MBF (1998-2000)
275 byte EN_mbf_pursuit; // !comp[comp_pursuit]
276 byte EN_mbf_telefrag; // !comp[comp_telefrag]
277 fixed_t EV_mbf_distfriend;
278 // Heretic, Hexen
279 byte EN_inventory;
280
281 #ifdef DOGS
282 byte extra_dog_count = 0;
283 static uint16_t extra_dog_respawn = 0; // save on extra tests
284 #define EXTRA_DOG_RESPAWN_TIME (5 * TICRATE)
285 #endif
286
287 // Demo playback enables
288 static char * playdemo_name = NULL; // malloc
289 static byte EN_demotic_109; // old demo tic format
290 static byte EN_boom_longtics; // 16 bit boom angle in demo tic
291
292
293
294 // [WDJ] PrBoom compatibility enum, to read Boom demo.
295 enum {
296 comp_telefrag,
297 comp_dropoff,
298 comp_vile,
299 comp_pain,
300 comp_skull,
301 comp_blazing,
302 comp_doorlight,
303 comp_model,
304 comp_god,
305 comp_falloff,
306 comp_floors,
307 comp_skymap,
308 comp_pursuit,
309 comp_doorstuck,
310 comp_staylift,
311 comp_zombie,
312 comp_stairs,
313 comp_infcheat,
314 comp_zerotags,
315 comp_moveblock,
316 comp_respawn,
317 comp_sound,
318 comp_666,
319 comp_soul,
320 comp_maskedanim,
321 COMP_NUM,
322 COMP_TOTAL=32
323 };
324
325
326 // -------------------------------------------
327 // Boom and MBF compatibility flags
328 // cv or EN : DoomLegacy handling of the demo flags.
329 // demo_compatibility === (compatibility_level < boom_compatibility_compatibility)
330 // EN_boom = (compatibility_level >= boom_compatibility_compatibility)
331 // compatibility === (compatibility_level <= boom_compatibility_compatibility)
332 // mbf_features === (compatibility_level >= mbf_compatibility)
333 // EN_mbf = (compatibility_level >= mbf_compatibility)
334 // compatibility flag in demo - turn off Boom features
335 // EN_boom = ! compatibility // but is demoversion specific
336 // comp_telefrag - monsters used to telefrag only on MAP30,
337 // now they do it for spawners only.
338 // EN_telefrag = ! comp[comp_telefrag] // demo support only
339 // comp_dropoff - MBF encourages things to drop off of overhangs
340 // cv_mbf_dropoff = ! comp[comp_dropoff]
341 // comp_vile - original Doom archville bugs like ghosts
342 // EN_vile_revive_bug = comp[comp_vile]
343 // comp_pain - original Doom limits Pain Elementals from spawning too many skulls
344 // EN_skull_limit = comp[comp_pain]
345 // comp_skull - original Doom let skulls be spit through walls by Pain Elementals
346 // EN_old_pain_spawn = comp[comp_skull]
347 // comp_blazing - original Doom duplicated blazing door sound
348 // EN_blazing_double_sound = comp[comp_blazing]
349 // comp_doorlight - MBF made door lighting changes more gradual
350 // EN_doorlight = ! comp[comp_doorlight]
351 // comp_model - improvements to the game physics
352 // EN_boom_physics = ! comp[comp_model]
353 // comp_god - fixes to God mode
354 // comp_falloff - MBF encourages things to drop off of overhangs
355 // cv_mbf_falloff = ! comp[comp_falloff]
356 // comp_floors - fixes for moving floors bugs
357 // comp_skymap - original Doom invul skymap colormap
358 // comp_pursuit - MBF AI change, limited pursuit?
359 // cv_mbf_pursuit = ! comp[comp_pursuit]
360 // comp_doorstuck - monsters stuck in doors fix
361 // cv_mbf_doorstuck = ! comp[comp_doorstuck]
362 // comp_staylift - MBF AI change, monsters try to stay on lifts
363 // cv_mbf_staylift = ! comp[comp_staylift]
364 // comp_zombie - prevent dead players triggering stuff
365 // comp_stairs - see p_floor.c
366 // comp_infcheat - FIXME
367 // comp_zerotags - allow zero tags in wads
368 // comp_moveblock - enables keygrab and mancubi shots going thru walls
369 // EN_doom_movestep_bug = comp[comp_moveblock]
370 // comp_respawn - objects which aren't on the map at game start respawn at (0,0)
371 // cph - this is the inverse of comp_respawnfix from eternity.
372 // comp_sound - see s_sound.c
373 // comp_666 - enables tag 666 in non-ExM8 levels
374 // comp_soul - enables lost souls bouncing (see P_ZMovement)
375 // EN_skull_bounce_fix = ! comp[comp_soul] // normally on
376 // comp_maskedanim - 2s mid textures don't animate
377
378 #if 0
379 static const struct {
380 complevel_t fix; // level at which fix/change was introduced
381 complevel_t opt; // level at which fix/change was made optional
382 } levels[] = {
383 // comp_doorstuck - monsters stuck in doors fix
384 { boom_202_compatibility, mbf_compatibility },
385
386 // comp_vile - original Doom archville bugs like ghosts
387 // comp_pain - original Doom limits Pain Elementals from spawning too many skulls
388 // comp_skull - original Doom let skulls be spit through walls by Pain Elementals
389 // comp_blazing - original Doom duplicated blazing door sound
390 // comp_doorlight - MBF made door lighting changes more gradual
391 // comp_model - improvements to the game physics
392 // comp_god - fixes to God mode
393 // comp_skymap
394 // comp_zerotags - allow zero tags in wads */
395 { boom_compatibility (==boom_201_compatibility), mbf_compatibility },
396
397 // comp_floors - fixes for moving floors bugs
398 // comp_stairs - see p_floor.c
399 { boom_compatibility_compatibility (==boom_200_compatibility), mbf_compatibility },
400
401 // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only
402 // comp_dropoff - MBF encourages things to drop off of overhangs
403 // comp_falloff - MBF encourages things to drop off of overhangs
404 // comp_pursuit - MBF AI change, limited pursuit?
405 // comp_staylift - MBF AI change, monsters try to stay on lifts
406 // comp_infcheat - FIXME
407 { mbf_compatibility, mbf_compatibility },
408
409 // comp_zombie - prevent dead players triggering stuff
410 { lxdoom_1_compatibility, mbf_compatibility },
411 // comp_moveblock - enables keygrab and mancubi shots going thru walls
412 { lxdoom_1_compatibility, prboom_2_compatibility },
413 // comp_respawn - objects which aren't on the map at game start respawn at (0,0)
414 { prboom_2_compatibility, prboom_2_compatibility },
415 // comp_sound - see s_sound.c
416 { boom_compatibility_compatibility (==boom_200_compatibility), prboom_3_compatibility },
417 // comp_666 - enables tag 666 in non-ExM8 levels
418 { ultdoom_compatibility, prboom_4_compatibility },
419 // comp_soul - enables lost souls bouncing (see P_ZMovement)
420 { prboom_4_compatibility, prboom_4_compatibility },
421 // comp_maskedanim - 2s mid textures don't animate
422 { doom_1666_compatibility, prboom_4_compatibility },
423 };
424 #endif
425
426
427 // Engine state
428 gamestate_e gamestate = GS_NULL;
429 gameaction_e gameaction;
430 byte paused; // multiple pause bits
431
432 boolean netgame; // only true if packets are broadcast
433 boolean multiplayer;
434
435 // players and bots
436 byte num_game_players = 0; // number of actual players, from playeringame, incl bots
437 byte playeringame[MAXPLAYERS]; // player active
438 byte player_state[MAXPLAYERS]; // from where, and pending player
439 player_t players[MAXPLAYERS];
440
441 // [WDJ] Whenever assign to these must update the _ptr too.
442 // They are not changed anywhere as often as players[] appears in IF stmts.
443 int consoleplayer; // player taking events and displaying
444 int displayplayer; // view being displayed
445 int displayplayer2 = -1; // for splitscreen, -1 when not in use
446 int statusbarplayer; // player who's statusbar is displayed
447 // (for spying with F12)
448
449 // [WDJ] Simplify every test against a player ptr, and splitscreen
450 player_t * consoleplayer_ptr = &players[0];
451 player_t * displayplayer_ptr = &players[0];
452 player_t * displayplayer2_ptr = NULL; // NULL when not in use
453
454 tic_t gametic;
455 tic_t levelstarttic; // gametic at level start
456 // [WDJ] Derived from PrBoom basetic.
457 // A tic that always starts at 0, and only runs while the demo runs.
458 tic_t game_comp_tic; // gametic - basetic
459
460
461 // [WDJ] Keep rarely used state information separate so cache usage is cleaner.
462
463 // Support
464 boolean precache = true; // if true, load all graphics at start
465 boolean gameplay_msg = false; // enable game play message control
466 boolean modifiedgame; // Set if homebrew PWAD stuff has been added.
467 language_t language = english; // Language.
468
469 // Intermission state
470 int totalkills, totalitems, totalsecret;
471 wb_start_t wminfo; // parms for world map / intermission
472
473 // Demo state
474 #define DEMONAME_LEN 32
475 char demoname[DEMONAME_LEN+5];
476 boolean demorecording;
477 boolean demoplayback;
478 byte* demobuffer;
479 byte* demo_p;
480 byte* demoend;
481 boolean singledemo; // quit after playing a demo from cmdline
482
483 // Timing demo state
484 boolean timingdemo; // if true, exit with report on completion
485 boolean nodrawers; // for comparative timing purposes
486 boolean noblit; // for comparative timing purposes
487 tic_t demostarttime; // for comparative timing purposes
488
489
490
491 void ShowMessage_OnChange(void);
492 void AllowTurbo_OnChange(void);
493
494 CV_PossibleValue_t showmessages_cons_t[]={{0,"Off"},{1,"Minimal"},{2,"Play"},{3,"Verbose"},{4,"Debug"},{5,"Dev"},{0,NULL}};
495 CV_PossibleValue_t pickupflash_cons_t[] ={{0,"Off"},{1,"Status"},{2,"Half"},{3,"Vanilla"},{0,NULL}};
496
497 // [0]=main player [1]=splitscreen player
498 consvar_t cv_autorun[2] = {
499 {"autorun" ,"0",CV_SAVE,CV_OnOff},
500 {"autorun2" ,"0",CV_SAVE,CV_OnOff}
501 };
502 consvar_t cv_alwaysfreelook[2] = {
503 {"alwaysmlook" ,"0",CV_SAVE,CV_OnOff},
504 {"alwaysmlook2","0",CV_SAVE,CV_OnOff}
505 };
506 consvar_t cv_mouse_move[2] = {
507 {"mousemove" ,"1",CV_SAVE,CV_OnOff},
508 {"mousemove2" ,"1",CV_SAVE,CV_OnOff}
509 };
510
511 consvar_t cv_mouse_invert = {"invertmouse" ,"0",CV_SAVE,CV_OnOff};
512 #ifdef MOUSE2
513 consvar_t cv_mouse2_invert = {"invertmouse2","0",CV_SAVE,CV_OnOff};
514 #endif
515
516 CV_PossibleValue_t joy_deadzone_cons_t[]={{0,"MIN"},{20,"INC"},{2000,"MAX"},{0,NULL}};
517 consvar_t cv_joy_deadzone = {"joydeadzone" ,"800",CV_SAVE,joy_deadzone_cons_t};
518
519 consvar_t cv_showmessages = {"showmessages","2",CV_SAVE | CV_CALL | CV_NOINIT,showmessages_cons_t,ShowMessage_OnChange};
520 consvar_t cv_pickupflash = {"pickupflash" ,"1",CV_SAVE, pickupflash_cons_t};
521 consvar_t cv_weapon_recoil = {"weaponrecoil","0",CV_SAVE | CV_NETVAR, CV_OnOff}; // Boom weapon recoil
522
523 consvar_t cv_allowturbo = {"allowturbo" ,"0",CV_NETVAR | CV_CALL, CV_YesNo, AllowTurbo_OnChange};
524 consvar_t cv_allowjump = {"allowjump" ,"1",CV_NETVAR,CV_YesNo};
525 consvar_t cv_allowautoaim = {"allowautoaim","1",CV_NETVAR,CV_YesNo};
526 //SoM: 3/28/2000: Working rocket jumping.
527 consvar_t cv_allowrocketjump = {"allowrocketjump","0",CV_NETVAR,CV_YesNo};
528 consvar_t cv_allowmlook = {"allowmlook" ,"1",CV_NETVAR,CV_YesNo};
529 consvar_t cv_allowexitlevel = {"allowexitlevel", "1", CV_NETVAR, CV_YesNo, NULL };
530
531 // oof when hit 2s line (in PrBoom enabled by ! comp_sound)
532 consvar_t cv_oof_2s = {"oof_2s", "0", CV_SAVE|CV_CALL, CV_OnOff, DemoAdapt_p_map};
533
534 #if MAXPLAYERS>32
535 #error please update "player_name" table using the new value for MAXPLAYERS
536 #endif
537 #if MAXPLAYERNAME!=21
538 #error please update "player_name" table using the new value for MAXPLAYERNAME
539 #endif
540 // changed to 2d array 19990220 by Kin
541 char player_names[MAXPLAYERS][MAXPLAYERNAME] =
542 {
543 // THESE SHOULD BE AT LEAST MAXPLAYERNAME CHARS
544 "Player 1\0a123456789a\0",
545 "Player 2\0a123456789a\0",
546 "Player 3\0a123456789a\0",
547 "Player 4\0a123456789a\0",
548 "Player 5\0a123456789a\0", // added 14-1-98 for support 8 players
549 "Player 6\0a123456789a\0", // added 14-1-98 for support 8 players
550 "Player 7\0a123456789a\0", // added 14-1-98 for support 8 players
551 "Player 8\0a123456789a\0", // added 14-1-98 for support 8 players
552 "Player 9\0a123456789a\0",
553 "Player 10\0a123456789\0",
554 "Player 11\0a123456789\0",
555 "Player 12\0a123456789\0",
556 "Player 13\0a123456789\0",
557 "Player 14\0a123456789\0",
558 "Player 15\0a123456789\0",
559 "Player 16\0a123456789\0",
560 "Player 17\0a123456789\0",
561 "Player 18\0a123456789\0",
562 "Player 19\0a123456789\0",
563 "Player 20\0a123456789\0",
564 "Player 21\0a123456789\0",
565 "Player 22\0a123456789\0",
566 "Player 23\0a123456789\0",
567 "Player 24\0a123456789\0",
568 "Player 25\0a123456789\0",
569 "Player 26\0a123456789\0",
570 "Player 27\0a123456789\0",
571 "Player 28\0a123456789\0",
572 "Player 29\0a123456789\0",
573 "Player 30\0a123456789\0",
574 "Player 31\0a123456789\0",
575 "Player 32\0a123456789\0"
576 };
577
578
579 // DEATHMATCH
580 void Deathmatch_OnChange(void);
581
582 // Coop 0: multiple players, coop map objects
583 // Deathmatch 1: placed weapons respawn immediately
584 // Deathmatch 2: items respawn
585 // Deathmatch 3: items respawn, placed weapons respawn immediately
586 // Keep original values for demo and savegame compatibility.
587 CV_PossibleValue_t deathmatch_cons_t[] = {
588 {0x80, "Coop_SP_Map"}, {0x30, "Coop_60"}, {0x20, "Coop_80"}, {0x10, "Coop"}, {0, "Coop_weapons"},
589 {4, "DM"}, {1, "DM_weapons"}, {2, "DM_items"}, {3, "DM_both"}, {0, NULL} };
590 consvar_t cv_deathmatch = { "deathmatch", "0", CV_NETVAR | CV_CALL, deathmatch_cons_t, Deathmatch_OnChange };
591
592 byte deathmatch;
593 byte weapon_persist; // deathmatch weapon pickup multiple times
594
595 // deathmatch (0..3)
596 byte deathmatch_to_itemrespawn[4] = { 0, 0, 1, 1 };
597
Deathmatch_OnChange(void)598 void Deathmatch_OnChange(void)
599 {
600 deathmatch = (cv_deathmatch.EV < 0x0F)? (cv_deathmatch.EV & 0x07) : 0;
601 weapon_persist = 0;
602
603 if( cv_deathmatch.EV < 4 )
604 {
605 // [WDJ] Server and Client, change other cvar affected by deathmatch, locally.
606 // Do not modify cvar here, and expect NETVAR to update them in clients.
607
608 // weapon respawn global enable
609 weapon_persist = (cv_deathmatch.EV != 2); // only the orig modes
610
611 // itemrespawn for deathmatch 2,3
612 CV_SetParam( &cv_itemrespawn, deathmatch_to_itemrespawn[ deathmatch & 0x03 ] );
613 // itemrespawntime is NETVAR, and will have been distributed at join game.
614
615 // [WDJ] Respawn weapons in the itemrespawn queue, for weapon_persist.
616 // Fixed code inconsistency: it did not do this when going to coop mode.
617 if( weapon_persist )
618 P_RespawnWeapons();
619 }
620
621 // give all key to the players
622 if( deathmatch )
623 {
624 int j;
625 for (j = 0; j < MAXPLAYERS; j++)
626 {
627 if (playeringame[j])
628 players[j].cards = it_allkeys;
629 }
630 }
631 }
632
633
634 // TIMELIMIT, FRAGLIMIT
635
636 void TimeLimit_OnChange(void);
637 consvar_t cv_timelimit = { "timelimit", "0", CV_NETVAR | CV_VALUE | CV_CALL | CV_NOINIT, CV_Unsigned, TimeLimit_OnChange };
638
639 uint32_t timelimit_tics = 0;
640
TimeLimit_OnChange(void)641 void TimeLimit_OnChange(void)
642 {
643 // CV_VALUE, may be too large for EV
644 if (cv_timelimit.value)
645 {
646 GenPrintf(EMSG_hud, "Levels will end after %d minute(s).\n", cv_timelimit.value);
647 timelimit_tics = cv_timelimit.value * 60 * TICRATE;
648 }
649 else
650 {
651 GenPrintf(EMSG_hud, "Time limit disabled\n");
652 timelimit_tics = 0;
653 }
654 }
655
656 void FragLimit_OnChange(void);
657 CV_PossibleValue_t fraglimit_cons_t[] = { {0, "MIN"}, {1000, "MAX"}, {0, NULL} };
658 consvar_t cv_fraglimit = { "fraglimit", "0", CV_NETVAR | CV_VALUE | CV_CALL | CV_NOINIT, fraglimit_cons_t, FragLimit_OnChange };
659
FragLimit_OnChange(void)660 void FragLimit_OnChange(void)
661 {
662 int i;
663
664 // CV_VALUE, may be too large for EV
665 if (cv_fraglimit.value > 0)
666 {
667 for (i = 0; i < MAXPLAYERS; i++)
668 P_CheckFragLimit(&players[i]);
669 }
670 }
671
672
673 // TEAM STATE
674
675 team_info_t* team_info[MAXTEAMS]; // allocated
676 byte num_teams = 0;
677
678 // Create the team if it does not exist.
get_team(int team_num)679 team_info_t* get_team( int team_num )
680 {
681 if( team_num >= MAXTEAMS )
682 return NULL;
683
684 // Create missing teams
685 while( team_num >= num_teams )
686 {
687 team_info[num_teams] = Z_Malloc( sizeof(team_info_t), PU_STATIC, NULL);
688 team_info[num_teams]->name = NULL;
689 num_teams++;
690 }
691 return team_info[team_num];
692 }
693
694 // Set the team name.
695 // Create the team if it does not exist.
set_team_name(int team_num,const char * str)696 void set_team_name( int team_num, const char * str )
697 {
698 // Create the team if it does not exist.
699 // Because of the complexity, for now, will create team at init.
700 get_team( team_num );
701
702 if( team_num <= num_teams )
703 {
704 char * name = team_info[team_num]->name;
705 if( name )
706 Z_Free( name );
707 name = Z_Malloc( strlen(str)+6, PU_STATIC, NULL );
708 sprintf(name,"%s team", str);
709 team_info[team_num]->name = name;
710 }
711 }
712
get_team_name(int team_num)713 char * get_team_name( int team_num )
714 {
715 if( team_num <= num_teams )
716 {
717 if( team_info[team_num]->name )
718 return team_info[team_num]->name;
719 }
720 return "Unknown team";
721 }
722
723
724 CV_PossibleValue_t teamplay_cons_t[] = { {0, "Off"}, {1, "Color"}, {2, "Skin"}, {3, NULL} };
725
726 void TeamPlay_OnChange( void );
727 consvar_t cv_teamplay = { "teamplay", "0", CV_NETVAR | CV_CALL, teamplay_cons_t, TeamPlay_OnChange };
728 consvar_t cv_teamdamage = { "teamdamage", "0", CV_NETVAR, CV_OnOff };
729
730
TeamPlay_OnChange(void)731 void TeamPlay_OnChange(void)
732 {
733 int i;
734 // Change the name of the teams
735
736 if(cv_teamplay.EV == 1)
737 {
738 // color
739 for(i=0; i<NUMSKINCOLORS; i++)
740 set_team_name( i, Color_Names[i]);
741 }
742 else
743 if(cv_teamplay.EV == 2)
744 {
745 // skins
746 for(i=0; i<numskins; i++)
747 set_team_name( i, skins[i]->name);
748 }
749 }
750
751
752 // Support
753
754 // Simplified body queue. The Doom bodyqueue was way complicated.
755 // A way to have player corpses stay around, but limit how many.
756 mobj_t* bodyque[BODYQUESIZE];
757 int bodyqueslot;
758
759
760 void* statcopy; // for statistics driver
761
ShowMessage_OnChange(void)762 void ShowMessage_OnChange(void)
763 {
764 if( !cv_showmessages.EV )
765 CONS_Printf("%s\n",MSGOFF);
766 else
767 CONS_Printf("%s: %s\n",MSGON, cv_showmessages.string );
768 }
769
770
771 // Build an original game map name from episode and map number,
772 // based on the game mode (doom1, doom2...)
773 //
G_BuildMapName(int episode,int map)774 char* G_BuildMapName (int episode, int map)
775 {
776 static char mapname[9]; // internal map name (wad resource name)
777
778 if (gamemode==doom2_commercial)
779 strcpy (mapname, va("MAP%#02d",map));
780 else
781 {
782 mapname[0] = 'E';
783 mapname[1] = '0' + episode;
784 mapname[2] = 'M';
785 mapname[3] = '0' + map;
786 mapname[4] = 0;
787 }
788 return mapname;
789 }
790
791
792 //
793 // Clip the console player mouse aiming to the current view,
794 // also returns a signed char for the player ticcmd if needed.
795 // Used whenever the player view pitch is changed manually
796 //
797 //added:22-02-98:
798 //changed:3-3-98: do a angle limitation now
G_ClipAimingPitch(angle_t aiming)799 angle_t G_ClipAimingPitch(angle_t aiming)
800 {
801 int32_t limitangle;
802
803 //note: the current software mode implementation doesn't have true perspective
804 if (rendermode == render_soft)
805 limitangle = 732<<ANGLETOFINESHIFT;
806 else
807 limitangle = ANG90 - 1;
808
809 int32_t p = aiming; // into signed to make comparisions simpler
810
811 if (p > limitangle)
812 p = limitangle;
813 else if (p < -limitangle)
814 p = -limitangle;
815
816 return p; // back into angle_t (unsigned)
817 }
818
819
820 //
821 // G_BuildTiccmd
822 // Builds a ticcmd from all of the available inputs
823 // or reads it from the demo buffer.
824 // If recording a demo, write it out
825 //
826 // set displayplayer2_ptr to build player 2's ticcmd in splitscreen mode
827 //
828 // [0]=main player, [1]=splitscreen player
829 angle_t localaiming[2];
830 angle_t localangle[2];
831
832 //added:06-02-98: mouseaiming (looking up/down with the mouse or keyboard)
833 #define KB_LOOKSPEED (1<<25)
834 #define MAXPLMOVE (forwardmove[1])
835 #define TURBOTHRESHOLD 0x32
836 #define SLOWTURNTICS (6*NEWTICRATERATIO)
837
838 static fixed_t forwardmove[2] = {25/NEWTICRATERATIO, 50/NEWTICRATERATIO};
839 static fixed_t sidemove[2] = {24/NEWTICRATERATIO, 40/NEWTICRATERATIO};
840 static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn
841
842
843 // for change this table change also nextweapon func in g_game and P_PlayerThink
844 char extraweapons[8]={wp_chainsaw,-1,wp_supershotgun,-1,-1,-1,-1,-1};
845 byte nextweaponorder[NUMWEAPONS]={wp_fist,wp_chainsaw,wp_pistol,
846 wp_shotgun,wp_supershotgun,wp_chaingun,wp_missile,wp_plasma,wp_bfg};
847
NextWeapon(player_t * player,int step)848 byte NextWeapon(player_t *player,int step)
849 {
850 byte w;
851 int i;
852 for (i=0;i<NUMWEAPONS;i++)
853 {
854 if( player->readyweapon == nextweaponorder[i] )
855 {
856 i = (i+NUMWEAPONS+step)%NUMWEAPONS;
857 break;
858 }
859 }
860 for (;nextweaponorder[i]!=player->readyweapon; i=(i+NUMWEAPONS+step)%NUMWEAPONS)
861 {
862 w = nextweaponorder[i];
863
864 // skip super shotgun for non-Doom2
865 if (gamemode!=doom2_commercial && w==wp_supershotgun)
866 continue;
867
868 // skip plasma-bfg in sharware
869 if (gamemode==doom_shareware && (w==wp_plasma || w==wp_bfg))
870 continue;
871
872 if ( player->weaponowned[w] &&
873 player->ammo[player->weaponinfo[w].ammo] >= player->weaponinfo[w].ammopershoot )
874 {
875 if(w==wp_chainsaw)
876 return (BT_CHANGE | BT_EXTRAWEAPON | (wp_fist<<BT_WEAPONSHIFT));
877 if(w==wp_supershotgun)
878 return (BT_CHANGE | BT_EXTRAWEAPON | (wp_shotgun<<BT_WEAPONSHIFT));
879 return (BT_CHANGE | (w<<BT_WEAPONSHIFT));
880 }
881 }
882 return 0;
883 }
884
BestWeapon(player_t * player)885 byte BestWeapon(player_t *player)
886 {
887 int newweapon = FindBestWeapon(player);
888
889 if (newweapon == player->readyweapon)
890 return 0;
891
892 if (newweapon == wp_chainsaw)
893 return (BT_CHANGE | BT_EXTRAWEAPON | (wp_fist<<BT_WEAPONSHIFT));
894
895 if (newweapon == wp_supershotgun)
896 return (BT_CHANGE | BT_EXTRAWEAPON | (wp_shotgun<<BT_WEAPONSHIFT));
897
898 return (BT_CHANGE | (newweapon<<BT_WEAPONSHIFT));
899 }
900
901 // pind : 0,1 for split player identity
902 static
G_InventoryResponder(player_t * ply,byte pind,int gc[num_gamecontrols][2],event_t * ev)903 boolean G_InventoryResponder(player_t *ply, byte pind,
904 int gc[num_gamecontrols][2], event_t *ev)
905 {
906 // [WDJ] 1/9/2009 Do not get to process any keyup events, unless also saw
907 // the keydown event. Now other Responders intercepting
908 // the keydown event work correctly. Specifically heretic will no longer
909 // use up an inventory item when game saving.
910 static byte keyup_armed[2] = {0,0}; // player1, player2
911
912 // Do not mess with inventory when menu or console are open.
913 if( menuactive || console_open )
914 return false;
915
916 if (! EN_inventory)
917 return false;
918
919 switch (ev->type)
920 {
921 case ev_keydown:
922 if( ev->data1 == gc[gc_invprev][0] || ev->data1 == gc[gc_invprev][1] )
923 {
924 if( ply->st_inventoryTics )
925 {
926 ply->inv_ptr--;
927 if( ply->inv_ptr < 0 )
928 ply->inv_ptr = 0;
929 else
930 {
931 ply->st_curpos--;
932 if( ply->st_curpos < 0 )
933 ply->st_curpos = 0;
934 }
935 }
936 ply->st_inventoryTics = 5*TICRATE;
937 goto used_key;
938 }
939 else if( ev->data1 == gc[gc_invnext][0] || ev->data1 == gc[gc_invnext][1] )
940 {
941 if( ply->st_inventoryTics )
942 {
943 ply->inv_ptr++;
944 if( ply->inv_ptr >= ply->inventorySlotNum )
945 {
946 ply->inv_ptr--;
947 if( ply->inv_ptr < 0)
948 ply->inv_ptr = 0;
949 }
950 else
951 {
952 ply->st_curpos++;
953 if( ply->st_curpos > 6 )
954 ply->st_curpos = 6;
955 }
956 }
957 ply->st_inventoryTics = 5*TICRATE;
958 goto used_key;
959 }
960 else if( ev->data1 == gc[gc_invuse ][0] || ev->data1 == gc[gc_invuse ][1] ){
961 goto arm_key;
962 }
963
964 break;
965
966 case ev_keyup:
967 if( ev->data1 == gc[gc_invuse ][0] || ev->data1 == gc[gc_invuse ][1] )
968 {
969 if( keyup_armed[pind] ) // [WDJ] Only if the keydown was not intercepted by some other responder
970 {
971 if( ply->st_inventoryTics )
972 ply->st_inventoryTics = 0;
973 else if( ply->inventory[ply->inv_ptr].count>0 )
974 {
975 Send_NetXCmd_pind( XD_USEARTIFACT, &ply->inventory[ply->inv_ptr].type, 1, pind);
976 }
977 goto used_key;
978 }
979 }
980 else if( ev->data1 == gc[gc_invprev][0] || ev->data1 == gc[gc_invprev][1] ||
981 ev->data1 == gc[gc_invnext][0] || ev->data1 == gc[gc_invnext][1] )
982 goto used_key;
983 break;
984
985 default:
986 break; // shut up compiler
987 }
988
989 keyup_armed[pind] = 0; // blanket unused
990 return false;
991
992 arm_key:
993 keyup_armed[pind] = 1; // ready for keyup event
994 return true;
995
996 used_key:
997 keyup_armed[pind] = 0; // used up
998 return true;
999 }
1000
1001
1002
1003 // pind : player index, [0]=main player, [1]=splitscreen player
G_BuildTiccmd(ticcmd_t * cmd,int realtics,byte pind)1004 void G_BuildTiccmd(ticcmd_t* cmd, int realtics, byte pind)
1005 {
1006 int i;
1007
1008 ticcmd_t *base = I_BaseTiccmd (); // empty, or external driver
1009 memcpy (cmd,base,sizeof(*cmd));
1010
1011
1012 player_t *this_player;
1013 int (*gcc)[2];
1014
1015 #define G_KEY_DOWN(k) (gamekeydown[gcc[(k)][0]] || gamekeydown[gcc[(k)][1]])
1016 #define G_KEY_PRESSED(k) (G_KEY_DOWN(k) || gamekeytapped[gcc[(k)][0]] || gamekeytapped[gcc[(k)][1]])
1017
1018 angle_t pitch;
1019
1020 if( pind == 0 )
1021 {
1022 this_player = consoleplayer_ptr;
1023 gcc = gamecontrol;
1024 } else {
1025 this_player = displayplayer2_ptr;
1026 gcc = gamecontrol2;
1027 }
1028 pitch = localaiming[pind];
1029
1030 // Exit now if locked
1031 if (this_player->locked)
1032 goto done;
1033
1034 // a little clumsy, but then the g_input.c became a lot simpler!
1035 boolean strafe = G_KEY_DOWN(gc_strafe);
1036 int speed = G_KEY_DOWN(gc_speed) ^ cv_autorun[pind].EV;
1037
1038 boolean turnright = G_KEY_DOWN(gc_turnright);
1039 boolean turnleft = G_KEY_DOWN(gc_turnleft);
1040 boolean mouseaiming = G_KEY_DOWN(gc_mouseaiming) ^ cv_alwaysfreelook[pind].EV;
1041
1042 int forward = 0, side = 0; // these must not wrap around, so we need bigger ranges than chars
1043
1044 // strafing and yaw
1045 if (strafe)
1046 {
1047 if (turnright)
1048 side += sidemove[speed];
1049 if (turnleft)
1050 side -= sidemove[speed];
1051 }
1052 else
1053 {
1054 // use two stage accelerative turning
1055 // on the keyboard and joystick
1056 static int turnheld[2]; // for accelerative turning
1057
1058 if (turnleft || turnright)
1059 turnheld[pind] += realtics;
1060 else
1061 turnheld[pind] = 0;
1062
1063 int tspeed = (turnheld[pind] < SLOWTURNTICS) ? 2 : speed;
1064
1065 if (turnright)
1066 cmd->angleturn -= angleturn[tspeed];
1067 if (turnleft)
1068 cmd->angleturn += angleturn[tspeed];
1069 }
1070
1071 // forwards/backwards, strafing
1072 if (G_KEY_DOWN(gc_forward))
1073 forward += forwardmove[speed];
1074 if (G_KEY_DOWN(gc_backward))
1075 forward -= forwardmove[speed];
1076 //added:07-02-98: some people strafe left & right with mouse buttons
1077 if (G_KEY_DOWN(gc_straferight))
1078 side += sidemove[speed];
1079 if (G_KEY_DOWN(gc_strafeleft))
1080 side -= sidemove[speed];
1081
1082 //added:07-02-98: fire with any button/key
1083 if (G_KEY_DOWN(gc_fire))
1084 cmd->buttons |= BT_ATTACK;
1085
1086 //added:07-02-98: use with any button/key
1087 if (G_KEY_DOWN(gc_use))
1088 cmd->buttons |= BT_USE;
1089
1090 //added:22-02-98: jump button
1091 if (cv_allowjump.EV && G_KEY_DOWN(gc_jump))
1092 cmd->buttons |= BT_JUMP;
1093
1094
1095 //added:07-02-98: any key / button can trigger a weapon
1096 // chainsaw overrides
1097 if (G_KEY_PRESSED(gc_nextweapon))
1098 cmd->buttons |= NextWeapon(this_player,1);
1099 else if (G_KEY_PRESSED(gc_prevweapon))
1100 cmd->buttons |= NextWeapon(this_player,-1);
1101 else if (G_KEY_PRESSED(gc_bestweapon))
1102 cmd->buttons |= BestWeapon(this_player);
1103 else
1104 for (i=gc_weapon1; i<gc_weapon1+NUMWEAPONS-1; i++)
1105 {
1106 if (G_KEY_PRESSED(i))
1107 {
1108 cmd->buttons |= BT_CHANGE | BT_EXTRAWEAPON; // extra by default
1109 cmd->buttons |= (i-gc_weapon1)<<BT_WEAPONSHIFT;
1110 // already have extraweapon in hand switch to the normal one
1111 if (this_player->readyweapon == extraweapons[i-gc_weapon1])
1112 cmd->buttons &= ~BT_EXTRAWEAPON;
1113 break;
1114 }
1115 }
1116
1117
1118 // pitch
1119 static byte keyboard_look[2]; // true if lookup/down using keyboard
1120
1121
1122 // spring back if not using keyboard neither mouselookin'
1123 if (!keyboard_look[pind] && !mouseaiming)
1124 pitch = 0;
1125
1126 if (G_KEY_DOWN(gc_lookup))
1127 {
1128 pitch += KB_LOOKSPEED;
1129 keyboard_look[pind] = true;
1130 }
1131 else
1132 if (G_KEY_DOWN(gc_lookdown))
1133 {
1134 pitch -= KB_LOOKSPEED;
1135 keyboard_look[pind] = true;
1136 }
1137 else
1138 if (G_KEY_PRESSED(gc_centerview))
1139 {
1140 pitch = 0;
1141 keyboard_look[pind] = false;
1142 }
1143
1144 // mice
1145
1146 // mouse look stuff (mouse look is not the same as mouse aim)
1147 if (pind == 0)
1148 {
1149 if (mouseaiming)
1150 {
1151 keyboard_look[pind] = false;
1152
1153 // looking up/down
1154 if (cv_mouse_invert.EV)
1155 pitch -= mousey<<19;
1156 else
1157 pitch += mousey<<19;
1158 }
1159 else if (cv_mouse_move[0].EV)
1160 forward += mousey;
1161
1162 if (strafe)
1163 side += mousex*2;
1164 else
1165 cmd->angleturn -= mousex*8;
1166
1167 mousex = mousey = 0;
1168 }
1169 else
1170 {
1171 if (mouseaiming)
1172 {
1173 keyboard_look[pind] = false;
1174
1175 // looking up/down
1176 #ifdef MOUSE2
1177 if (cv_mouse2_invert.EV)
1178 pitch -= mouse2y<<19;
1179 else
1180 #endif
1181 pitch += mouse2y<<19;
1182 }
1183 else if (cv_mouse_move[1].EV)
1184 forward += mouse2y;
1185
1186 if (strafe)
1187 side += mouse2x*2;
1188 else
1189 cmd->angleturn -= mouse2x*8;
1190
1191 mouse2x = mouse2y = 0;
1192 }
1193
1194 // Finally the joysticks.
1195 for (i=0; i < num_joybindings; i++)
1196 {
1197 joybinding_t j = joybindings[i];
1198
1199 if (j.playnum != pind)
1200 continue;
1201
1202 int joyvalue = I_JoystickGetAxis(j.joynum, j.axisnum);
1203 if( joyvalue >= -cv_joy_deadzone.value && joyvalue <= cv_joy_deadzone.value) joyvalue = 0; // Deadzone
1204 int value = (int)(j.scale * joyvalue);
1205
1206 switch (j.action)
1207 {
1208 case ja_pitch:
1209 pitch = value << 16;
1210 break;
1211 case ja_move:
1212 if(speed == 1) value *= 2; // Double value if player is running
1213 forward += value;
1214 break;
1215 case ja_turn:
1216 cmd->angleturn += value;
1217 break;
1218 case ja_strafe:
1219 if(speed == 1) value *= 2; // Double value if player is running
1220 side += value;
1221 break;
1222 default:
1223 break;
1224 }
1225 }
1226
1227
1228 // Do not go faster than max. speed
1229 if (forward > MAXPLMOVE)
1230 forward = MAXPLMOVE;
1231 else if (forward < -MAXPLMOVE)
1232 forward = -MAXPLMOVE;
1233 if (side > MAXPLMOVE)
1234 side = MAXPLMOVE;
1235 else if (side < -MAXPLMOVE)
1236 side = -MAXPLMOVE;
1237
1238 cmd->forwardmove += forward;
1239 cmd->sidemove += side;
1240
1241 //26/02/2000: added by Hurdler: accept no mlook for network games
1242 if (!cv_allowmlook.EV)
1243 pitch = 0;
1244
1245 pitch = G_ClipAimingPitch(pitch); // clip pitch to a reasonable sector
1246 cmd->aiming = pitch >> 16; // to short
1247
1248 // Generated cmd are absolute angles
1249 localangle[pind] += (cmd->angleturn<<16);
1250 cmd->angleturn = localangle[pind] >> 16;
1251 localaiming[pind] = pitch;
1252
1253 if( gamemode == heretic )
1254 {
1255 if (G_KEY_DOWN(gc_flydown))
1256 #ifdef TICCMD_148
1257 cmd->ticflags |= TC_flydown;
1258 else
1259 cmd->ticflags &= ~TC_flydown;
1260 #else
1261 cmd->angleturn |= BT_FLYDOWN;
1262 else
1263 cmd->angleturn &= ~BT_FLYDOWN;
1264 #endif
1265 }
1266
1267 done:
1268 memset(gamekeytapped, 0, sizeof(gamekeytapped)); // we're done, reset key-tapping status
1269 #ifdef TICCMD_148
1270 cmd->ticflags |= TC_received;
1271 #endif
1272 }
1273
1274
1275 static fixed_t originalforwardmove[2] = {0x19, 0x32};
1276 static fixed_t originalsidemove[2] = {0x18, 0x28};
1277
AllowTurbo_OnChange(void)1278 void AllowTurbo_OnChange(void)
1279 {
1280 if(!cv_allowturbo.EV && netgame)
1281 {
1282 // like turbo 100
1283 forwardmove[0] = originalforwardmove[0];
1284 forwardmove[1] = originalforwardmove[1];
1285 sidemove[0] = originalsidemove[0];
1286 sidemove[1] = originalsidemove[1];
1287 }
1288 }
1289
1290 // turbo <10-255>
1291 //
Command_Turbo_f(void)1292 void Command_Turbo_f (void)
1293 {
1294 int scale = 200;
1295
1296 if(!cv_allowturbo.EV && netgame)
1297 {
1298 CONS_Printf("This server don't allow turbo\n");
1299 return;
1300 }
1301
1302 if (COM_Argc()!=2)
1303 {
1304 CONS_Printf("turbo <10-255> : set turbo");
1305 return;
1306 }
1307
1308 scale = atoi (COM_Argv(1));
1309
1310 if (scale < 10)
1311 scale = 10;
1312 if (scale > 255)
1313 scale = 255;
1314
1315 CONS_Printf ("turbo scale: %i%%\n",scale);
1316
1317 forwardmove[0] = originalforwardmove[0]*scale/100;
1318 forwardmove[1] = originalforwardmove[1]*scale/100;
1319 sidemove[0] = originalsidemove[0]*scale/100;
1320 sidemove[1] = originalsidemove[1]*scale/100;
1321 }
1322
1323
1324 //
1325 // G_DoLoadLevel
1326 //
G_DoLoadLevel(boolean resetplayer)1327 void G_DoLoadLevel (boolean resetplayer)
1328 {
1329 int i;
1330
1331 levelstarttic = gametic; // for time calculation
1332 // [WDJ] Derived from PrBoom, gametic demosync.
1333 if( EN_boom && !EN_mbf )
1334 game_comp_tic = 0; // Boom demos start at tic 0
1335
1336 gameplay_msg = false;
1337
1338 // Reset certain attributes
1339 // (should be in resetplayer 'if'?)
1340 fs_fadealpha = 0;
1341 extramovefactor = 0;
1342 jumpgravity = (6*FRACUNIT/NEWTICRATERATIO); // re-init
1343 consoleplayer_ptr->locked = false;
1344
1345 if (wipegamestate == GS_LEVEL)
1346 wipegamestate = GS_FORCEWIPE; // force a wipe
1347
1348 gamestate = GS_LEVEL;
1349
1350 for (i=0 ; i<MAXPLAYERS ; i++)
1351 {
1352 if( resetplayer || (playeringame[i] && players[i].playerstate == PST_DEAD))
1353 players[i].playerstate = PST_REBORN;
1354 memset (players[i].frags,0,sizeof(players[i].frags));
1355 players[i].addfrags = 0;
1356 }
1357
1358 #ifdef DOGS
1359 extra_dog_count = 0;
1360 #endif
1361
1362 // game_map_filename is external wad
1363 if (!P_SetupLevel (gameepisode, gamemap, gameskill, game_map_filename ))
1364 {
1365 // fail so reset game stuff
1366 Command_ExitGame_f();
1367 return;
1368 }
1369
1370 // [WDJ] Some demos specify a console player that does not exist.
1371 // This happens before demoplayback is set.
1372 // Have not been able to determine anything better to do.
1373 if ( consoleplayer_ptr->weaponinfo == NULL )
1374 {
1375 G_AddPlayer( consoleplayer ); // to prevent segfaults
1376 playeringame[consoleplayer] = true; // needs an mobj
1377 }
1378
1379 if( ! demoplayback ) // because demo sets it too
1380 {
1381 displayplayer = consoleplayer; // view the guy you are playing
1382 displayplayer_ptr = consoleplayer_ptr;
1383 }
1384
1385 if(!cv_splitscreen.EV)
1386 {
1387 // [WDJ] Changed to a testable off for player 2
1388 displayplayer2 = -1;
1389 displayplayer2_ptr = NULL; // use as test for player2 active
1390 }
1391
1392 DemoAdapt_bots();
1393 if( server )
1394 {
1395 B_Regulate_Bots( cv_bots.EV );
1396 }
1397
1398 gameaction = ga_nothing;
1399 #ifdef PARANOIA
1400 Z_CheckHeap (-2);
1401 #endif
1402
1403 if (camera.chase)
1404 P_ResetCamera ( displayplayer_ptr );
1405
1406 // clear cmd building stuff
1407 memset(gamekeydown, 0, sizeof(gamekeydown));
1408 memset(gamekeytapped, 0, sizeof(gamekeytapped));
1409 mousex = mousey = mouse2x = mouse2y = 0;
1410 I_StartupMouse( true ); // play mode
1411
1412 // [WDJ] In case demo is from other than player1 (from prboom, killough)
1413 ST_Start();
1414 // clear hud messages remains (usually from game startup)
1415 HU_Clear_FSPics();
1416 CON_Clear_HUD ();
1417
1418 gameplay_msg = true;
1419 }
1420
1421 //
1422 // G_Responder
1423 // Get info needed to make ticcmd_ts for the players.
1424 //
1425 // return true if event is acted upon
G_Responder(event_t * ev)1426 boolean G_Responder (event_t* ev)
1427 {
1428 // allow spy mode changes even during the demo
1429 if (gamestate == GS_LEVEL && ev->type == ev_keydown
1430 && ev->data1 == KEY_F12
1431 && ( singledemo || ! deathmatch ) )
1432 {
1433 // spy mode
1434 do
1435 {
1436 displayplayer++;
1437 if (displayplayer == MAXPLAYERS)
1438 displayplayer = 0;
1439 } while (!playeringame[displayplayer] && displayplayer != consoleplayer);
1440 displayplayer_ptr = &players[displayplayer];
1441
1442 //added:16-01-98:change statusbar also if playingback demo
1443 if( singledemo )
1444 ST_Change_DemoView ();
1445
1446 //added:11-04-98: tell who's the view
1447 GenPrintf(EMSG_hud, "Viewpoint : %s\n", player_names[displayplayer]);
1448 goto handled;
1449 }
1450
1451 // any other key pops up menu if in demos
1452 if (gameaction == ga_nothing && !singledemo &&
1453 (demoplayback || gamestate == GS_DEMOSCREEN) )
1454 {
1455 if (ev->type == ev_keydown)
1456 {
1457 M_StartControlPanel ();
1458 goto handled;
1459 }
1460 goto rejected;
1461 }
1462
1463 if (gamestate == GS_LEVEL)
1464 {
1465 #if 0
1466 if (devparm && ev->type == ev_keydown && ev->data1 == ';')
1467 {
1468 // added Boris : test different player colors
1469 consoleplayer_ptr->skincolor = (consoleplayer_ptr->skincolor+1) % NUMSKINCOLORS;
1470 consoleplayer_ptr->mo->flags |= (consoleplayer_ptr->skincolor)<<MF_TRANSSHIFT;
1471 G_DeathMatchSpawnPlayer (0);
1472 goto handled;
1473 }
1474 #endif
1475 if(!multiplayer)
1476 {
1477 if( cht_Responder (ev))
1478 goto handled;
1479 }
1480 if (HU_Responder (ev))
1481 goto handled; // chat ate the event
1482 if (ST_Responder (ev))
1483 goto handled; // status window ate it
1484 if (AM_Responder (ev))
1485 goto handled; // automap ate it
1486 if (G_InventoryResponder (consoleplayer_ptr, 0, gamecontrol, ev))
1487 goto handled;
1488 if (displayplayer2_ptr
1489 && G_InventoryResponder (displayplayer2_ptr, 1, gamecontrol2, ev))
1490 goto handled;
1491 //added:07-02-98: map the event (key/mouse/joy) to a gamecontrol
1492 }
1493
1494 if (gamestate == GS_FINALE)
1495 {
1496 if (F_Responder (ev))
1497 goto handled; // finale ate the event
1498 }
1499
1500
1501 // update keys current state
1502 G_MapEventsToControls (ev);
1503
1504 switch (ev->type)
1505 {
1506 case ev_keydown:
1507 if (ev->data1 == KEY_PAUSE // keyboard
1508 || ev->data1 == gamecontrol[gc_pause][0] || ev->data1 == gamecontrol[gc_pause][1] ) // joystick
1509 {
1510 COM_BufAddText("pause\n");
1511 goto handled;
1512 }
1513 goto handled;
1514
1515 case ev_keyup:
1516 goto rejected; // always let key up events filter down
1517
1518 case ev_mouse:
1519 goto handled; // eat events
1520
1521 default:
1522 break;
1523 }
1524
1525 rejected:
1526 return false;
1527
1528 handled:
1529 return true;
1530 }
1531
1532
1533 //
1534 // G_Ticker
1535 // Make ticcmd_ts for the players.
1536 //
G_Ticker(void)1537 void G_Ticker (void)
1538 {
1539 int i;
1540 int buf;
1541 ticcmd_t* cmd;
1542
1543 // do player reborns if needed
1544 if( gamestate == GS_LEVEL )
1545 {
1546 for (i=0 ; i<MAXPLAYERS ; i++)
1547 {
1548 if (playeringame[i])
1549 {
1550 if( players[i].playerstate == PST_REBORN )
1551 G_DoReborn (i);
1552 if( players[i].st_inventoryTics )
1553 players[i].st_inventoryTics--;
1554 }
1555 }
1556 #ifdef DOGS
1557 // [WDJ] MBF dogs, extension for DoomLegacy.
1558 if( extra_dog_respawn ) // coop respawn
1559 {
1560 extra_dog_respawn--; // counter
1561 if( extra_dog_respawn == 0 )
1562 {
1563 G_SpawnExtraDog( NULL );
1564 if( extra_dog_count < cv_mbf_dogs.EV )
1565 extra_dog_count = EXTRA_DOG_RESPAWN_TIME;
1566 }
1567 }
1568 #endif
1569 }
1570
1571 // Do things to change the game state.
1572 while (gameaction != ga_nothing)
1573 {
1574 switch (gameaction)
1575 {
1576 case ga_completed:
1577 G_DoCompleted ();
1578 G_Start_Intermission();
1579 #ifdef WAIT_GAME_START_INTERMISSION
1580 // This must be after G_Start_Intermission because it overrides
1581 // wait_game_start_timer that is set to default for deathmatch.
1582 if( server )
1583 SV_Add_game_start_waiting_players( 0 );
1584 #endif
1585 break;
1586 case ga_worlddone:
1587 G_DoWorldDone ();
1588 break;
1589 case ga_playdemo:
1590 G_DoPlayDemo( playdemo_name );
1591 break;
1592 case ga_nothing:
1593 break;
1594 default:
1595 // [WDJ] Softer recovery.
1596 I_SoftError("GAME: gameaction = %d\n", gameaction);
1597 gameaction = ga_nothing;
1598 break;
1599 }
1600 }
1601
1602 // [WDJ] From PrBoom, MBF, EternityEngine
1603 // killough 9/29/98: Skip some commands while pausing during demo playback,
1604 // or while the menu is active.
1605 //
1606 // Do not increment game_comp_tic and skip processing if a demo being played back
1607 // is paused or if the menu is active while a non-net game is being played,
1608 // to maintain sync while allowing pauses.
1609 //
1610 // P_Ticker() does not stop netgames if a menu is activated, so
1611 // we do not need to stop if a menu is pulled up during netgames.
1612 if( (paused & 0x02)
1613 || (!demoplayback && menuactive && !netgame ) )
1614 {
1615 goto main_actions;
1616 }
1617
1618 game_comp_tic++; // For revenant tracers and RNG -- we must maintain sync
1619
1620 buf = gametic%BACKUPTICS;
1621
1622 // read/write demo and check turbo cheat
1623 for (i=0 ; i<MAXPLAYERS ; i++)
1624 {
1625 // BP: i==0 for playback of demos 1.29 now new players is added with xcmd
1626 if ((playeringame[i] || i==0) && !dedicated)
1627 {
1628 cmd = &players[i].cmd;
1629
1630 // All clients run the bots, identically.
1631 if (players[i].bot) //added by AC for acbot
1632 B_BuildTiccmd(&players[i], &netcmds[buf][i]);
1633
1634 if (demoplayback)
1635 {
1636 G_ReadDemoTiccmd (cmd,i);
1637 }
1638 else
1639 {
1640 // Copy the network ticcmd (and indirectly the local ticcmd) to the player.
1641 memcpy (cmd, &netcmds[buf][i], sizeof(ticcmd_t));
1642 }
1643
1644 if (demorecording)
1645 G_WriteDemoTiccmd (cmd,i);
1646
1647 // check for turbo cheats
1648 if (cmd->forwardmove > TURBOTHRESHOLD
1649 && !(gametic % (32*NEWTICRATERATIO)) && ((gametic / (32*NEWTICRATERATIO))&3) == i )
1650 {
1651 #define TURBO_MSG_LEN 80
1652 static char turbomessage[TURBO_MSG_LEN];
1653 snprintf (turbomessage, TURBO_MSG_LEN-1, "%s is turbo!", player_names[i]);
1654 turbomessage[TURBO_MSG_LEN-1] = 0;
1655 consoleplayer_ptr->message = turbomessage;
1656 }
1657 }
1658 }
1659
1660 main_actions:
1661
1662 // do main actions
1663 switch (gamestate)
1664 {
1665 case GS_LEVEL:
1666 //IO_Color(0,255,0,0);
1667 // Apply player cmds to players, then run thinkers and level animations for this gametic.
1668 P_Ticker (); // tic the game
1669 //IO_Color(0,0,255,0);
1670 ST_Ticker ();
1671 AM_Ticker ();
1672 HU_Ticker ();
1673 break;
1674
1675 case GS_INTERMISSION:
1676 WI_Ticker ();
1677 break;
1678
1679 case GS_FINALE:
1680 F_Ticker ();
1681 break;
1682
1683 case GS_DEMOSCREEN:
1684 D_PageTicker ();
1685 break;
1686
1687 case GS_WAITINGPLAYERS:
1688 case GS_DEDICATEDSERVER:
1689 case GS_NULL:
1690 default:
1691 // do nothing
1692 gameplay_msg = false;
1693 break;
1694 }
1695 }
1696
1697
1698 // Spawn Test
1699 // [WDJ] Use a temporary mobj to test position.
1700 // This can be modified to suit,
1701 // and being static does not leave dangling ptrs into stack space.
1702 // Need flags, flags2, radius, height.
1703 static mobj_t tstobj;
1704
1705 // testtype: determines the test mobj size, how much radius is needed
1706 // Return false when an collision with an existing object would occur.
1707 static
test_spot_unoccupied(mobjtype_t testtype,fixed_t x,fixed_t y,fixed_t z)1708 boolean test_spot_unoccupied( mobjtype_t testtype, fixed_t x, fixed_t y, fixed_t z )
1709 {
1710 // [WDJ] Test spawn spot for any player or blocking object.
1711 // Needed for spawning off of map spawn spots, and for multiple players.
1712 // Spawn test position is already set.
1713 // MF_SOLID is required to test against objects.
1714 // MF_PICKUP is off to prevent picking up objects.
1715 // MF2_PASSMOBJ is off, as in Heretic.
1716 tstobj.x = x;
1717 tstobj.y = y;
1718 tstobj.z = z;
1719 tstobj.player = NULL; // so cannot take damage during test
1720 tstobj.type = testtype;
1721 tstobj.info = &mobjinfo[testtype];
1722 tstobj.radius = tstobj.info->radius;
1723 tstobj.height = tstobj.info->height;
1724 tstobj.flags2 = tstobj.info->flags2 & ~MF2_PASSMOBJ;
1725 tstobj.flags = MF_SOLID|MF_SHOOTABLE|MF_DROPOFF;
1726 return P_CheckPosition( &tstobj, x, y );
1727 }
1728
1729
1730 boolean G_Player_SpawnSpot( int playernum, mapthing_t* spot );
1731
1732
1733 // Extra dynamic spawn spots
1734 // Kept static because mobj will keep a ptr to it, and NULL is not good either.
1735 mapthing_t extra_coop_spawn; // roving coop spawn
1736 // Static spawn index, so if a player gets a difficult spawn,
1737 // it does not repeat every spawn.
1738 static int32_t spind = 1;
1739
1740
1741 static
scatter_spawn(mobjtype_t spawn_type,int playernum,mapthing_t * spot)1742 boolean scatter_spawn( mobjtype_t spawn_type, int playernum, mapthing_t * spot )
1743 {
1744 int i;
1745
1746 extra_coop_spawn = * spot; // copy, will be modified
1747 tstobj.x = spot->x<<16; // spot map location
1748 tstobj.y = spot->y<<16;
1749
1750 for(i=255; i>0; i--)
1751 {
1752 spind += 83; // scatter the pattern with prime 83
1753 // The low 8 bits of rv will cycle through all patterns in 256 iter.
1754 // Range (-15..15) * (player_radius + 2)
1755 extra_coop_spawn.x = spot->x + (((spind & 0x0F) - 8) * 18);
1756 extra_coop_spawn.y = spot->y + ((((spind >> 4) & 0x0F) - 8) * 18);
1757
1758 // Not allowed to cross any blocking lines, to keep it out of the void.
1759 if( P_CheckCrossLine( &tstobj, extra_coop_spawn.x<<16, extra_coop_spawn.y<<16 ) ) continue;
1760
1761 if( spawn_type == MT_PLAYER )
1762 {
1763 if (G_Player_SpawnSpot(playernum, &extra_coop_spawn) )
1764 return true;
1765 }
1766 #ifdef DOGS
1767 else
1768 {
1769 if (G_SpawnExtraDog(&extra_coop_spawn) )
1770 return true;
1771 }
1772 #endif
1773 }
1774 return false;
1775 }
1776
1777
1778
1779 #ifdef DOGS
1780 // [WDJ] Spawn dogs.
1781 // MBF spawns extra dogs at map load, only for single player.
1782 // DoomLegacy also spawns dogs for Coop.
1783
1784 // Do not modify level map spot due to reusing them during coop.
1785 // A player may join and use a spot that was previously used for a dog.
1786 static mapthing_t extra_dog_spot;
1787
1788 // Spawn extra player dog.
1789 // These are dogs that start as player spots, limited by cv_mbf_dogs.
1790 // Dogs that are level map objects spawn normally, as monsters or friends.
G_SpawnExtraDog(mapthing_t * spot)1791 boolean G_SpawnExtraDog( mapthing_t * spot )
1792 {
1793 fixed_t x, y;
1794 sector_t * sec;
1795
1796 // Spawn a dog on one of the unused player starts, up to cv_mbf_dogs.
1797 // Avoid multiple dogs in case of multiple starts, using playerstart.
1798 // Extra playerstarts will already be voodoo doll spots.
1799 if( extra_dog_count >= cv_mbf_dogs.EV ) goto no_more_dogs;
1800
1801 if( deathmatch ) goto no_more_dogs;
1802
1803 if( spot == NULL )
1804 {
1805 // [WDJ] Have run out of start spots.
1806 // This is a recursive call.
1807 int i;
1808 // Try to spawn near one of the other player spots.
1809 for (i=0 ; i<MAXPLAYERS ; i++)
1810 {
1811 if( playerstarts[i] == NULL ) continue;
1812 if( scatter_spawn( MT_DOG, 0, playerstarts[i] ) )
1813 return true;
1814 }
1815 return false;
1816 }
1817
1818 // Avoid modify of level map things.
1819 memcpy( &extra_dog_spot, spot, sizeof(mapthing_t) );
1820
1821 // killough 10/98: force it to be a friend
1822 // [WDJ] Make sure it is not blocked (MTF_MPSPAWN, MTF_NODM, MTF_NOCOOP).
1823 extra_dog_spot.options |= MTF_FRIEND | 0x07;
1824 extra_dog_spot.options &= ~(MTF_MPSPAWN | MTF_NODM | MTF_NOCOOP);
1825
1826 // haleyjd 9/22/99: deh, bex substitution
1827 extra_dog_spot.type = ( helper_MT < ENDDOOM_MT )? helper_MT : MT_DOG;
1828
1829 // [WDJ] Test spawn spot for any player or blocking object.
1830 // Use tstobj, so do not need player mobj. There may not be one.
1831 // The spawn spot location.
1832 x = extra_dog_spot.x << FRACBITS;
1833 y = extra_dog_spot.y << FRACBITS;
1834 sec = R_PointInSubsector(x,y)->sector;
1835 if( ! test_spot_unoccupied( extra_dog_spot.type, x, y, sec->floorheight ) )
1836 return false;
1837
1838 // SpawnMapthing keeps a reference to the spawn spot in the mobj.
1839 P_SpawnMapthing( &extra_dog_spot );
1840
1841 extra_dog_count ++;
1842 return true;
1843
1844 no_more_dogs:
1845 extra_dog_respawn = 0;
1846 return false;
1847 }
1848
1849 // To deal with respawning dog issues.
G_KillDog(mobj_t * mo)1850 void G_KillDog( mobj_t * mo )
1851 {
1852 if( mo->spawnpoint != &extra_dog_spot ) return;
1853
1854 if( !(mo->flags & MF_FRIEND) ) return;
1855
1856 if( multiplayer && ( ! deathmatch ) // coop respawn
1857 && !cv_respawnmonsters.EV ) // not otherwise respawned
1858 {
1859 extra_dog_count --;
1860 if( extra_dog_respawn == 0 )
1861 extra_dog_respawn = EXTRA_DOG_RESPAWN_TIME;
1862 }
1863 }
1864
1865 #endif
1866
1867 //
1868 // PLAYER STRUCTURE FUNCTIONS
1869 // also see P_SpawnPlayer in P_Things
1870 //
1871
1872 //
1873 // G_InitPlayer
1874 // Called at the start.
1875 // Called by the game initialization functions.
1876 //
1877 /* BP:UNUSED !
1878 void G_InitPlayer (int player)
1879 {
1880 player_t* p;
1881
1882 // set up the saved info
1883 p = &players[player];
1884
1885 // clear everything else to defaults
1886 G_PlayerReborn (player);
1887 }
1888 */
1889
1890
1891 //
1892 // G_PlayerFinishLevel
1893 // Can when a player completes a level.
1894 //
G_PlayerFinishLevel(int player)1895 void G_PlayerFinishLevel (int player)
1896 {
1897 player_t* p;
1898 mobj_t * pmo;
1899 int i;
1900
1901 p = &players[player];
1902 pmo = p->mo;
1903 for(i=0; i<p->inventorySlotNum; i++)
1904 {
1905 if( p->inventory[i].count>1)
1906 p->inventory[i].count = 1;
1907 }
1908 if( ! deathmatch )
1909 {
1910 for(i = 0; i < MAXARTECONT; i++)
1911 P_PlayerUseArtifact(p, arti_fly);
1912 }
1913 memset (p->powers, 0, sizeof (p->powers));
1914 if( gamemode == heretic )
1915 p->weaponinfo = wpnlev1info; // cancel power weapons
1916 else
1917 p->weaponinfo = doomweaponinfo;
1918 p->cards = 0;
1919 if( pmo )
1920 pmo->flags &= ~MF_SHADOW; // cancel invisibility
1921 p->extralight = 0; // cancel gun flashes
1922 p->fixedcolormap = 0; // cancel ir gogles
1923 p->damagecount = 0; // no palette changes
1924 p->bonuscount = 0;
1925 p->health_pickup = 0;
1926 p->armor_pickup = 0;
1927 p->weapon_pickup = 0;
1928 p->ammo_pickup = 0;
1929 p->key_pickup = 0;
1930 p->aiming = 0; // reset freelook
1931
1932 if(p->chickenTics)
1933 {
1934 if( pmo )
1935 p->readyweapon = pmo->special1; // Restore weapon
1936 p->chickenTics = 0;
1937 }
1938 p->rain1 = NULL;
1939 p->rain2 = NULL;
1940 }
1941
1942
1943 // added 2-2-98 for hacking with dehacked patch
1944 int initial_health=100; //MAXHEALTH;
1945 int initial_bullets=50;
1946
1947 void VerifFavoritWeapon (player_t *player);
1948
1949 //
1950 // G_PlayerReborn
1951 // Called after a player dies
1952 // almost everything is cleared and initialized
1953 //
1954 // Called by P_SpawnPlayer when PST_REBORN.
G_PlayerReborn(int player)1955 void G_PlayerReborn (int player)
1956 {
1957 player_t* p;
1958 int i;
1959 uint16_t frags[MAXPLAYERS];
1960 uint16_t addfrags;
1961 int killcount;
1962 int itemcount;
1963 int secretcount;
1964
1965 //from Boris
1966 int skincolor;
1967 char favoritweapon[NUMWEAPONS];
1968 boolean originalweaponswitch;
1969 boolean autoaim;
1970 int skin; //Fab: keep same skin
1971 #ifdef CLIENTPREDICTION2
1972 mobj_t *spirit;
1973 #endif
1974 bot_t* bot; //added by AC for acbot
1975
1976 memcpy (frags,players[player].frags,sizeof(frags));
1977 addfrags = players[player].addfrags;
1978 killcount = players[player].killcount;
1979 itemcount = players[player].itemcount;
1980 secretcount = players[player].secretcount;
1981
1982 //from Boris
1983 skincolor = players[player].skincolor;
1984 originalweaponswitch = players[player].originalweaponswitch;
1985 memcpy (favoritweapon,players[player].favoritweapon,NUMWEAPONS);
1986 autoaim = players[player].autoaim_toggle;
1987 skin = players[player].skin;
1988 #ifdef CLIENTPREDICTION2
1989 spirit = players[player].spirit;
1990 #endif
1991 bot = players[player].bot; //added by AC for acbot
1992
1993 p = &players[player];
1994 memset (p, 0, sizeof(*p));
1995
1996 memcpy (players[player].frags, frags, sizeof(players[player].frags));
1997 players[player].addfrags=addfrags;
1998 players[player].killcount = killcount;
1999 players[player].itemcount = itemcount;
2000 players[player].secretcount = secretcount;
2001
2002 // save player config truth reborn
2003 players[player].skincolor = skincolor;
2004 players[player].originalweaponswitch = originalweaponswitch;
2005 memcpy (players[player].favoritweapon,favoritweapon,NUMWEAPONS);
2006 players[player].autoaim_toggle = autoaim;
2007 players[player].skin = skin;
2008 #ifdef CLIENTPREDICTION2
2009 players[player].spirit = spirit;
2010 #endif
2011 players[player].bot = bot; //added by AC for acbot
2012
2013 p->usedown = p->attackdown = true; // don't do anything immediately
2014 p->playerstate = PST_LIVE;
2015 p->health = initial_health;
2016 if( gamemode == heretic )
2017 {
2018 // wand start
2019 p->weaponinfo = wpnlev1info;
2020 p->readyweapon = p->pendingweapon = wp_goldwand;
2021 p->weaponowned[wp_staff] = true;
2022 p->weaponowned[wp_goldwand] = true;
2023 p->ammo[am_goldwand] = 50;
2024 }
2025 else
2026 {
2027 // pistol start
2028 p->weaponinfo = doomweaponinfo;
2029 p->readyweapon = p->pendingweapon = wp_pistol;
2030 p->weaponowned[wp_fist] = true;
2031 p->weaponowned[wp_pistol] = true;
2032 p->ammo[am_clip] = initial_bullets;
2033 }
2034
2035 // Boris stuff
2036 if(!p->originalweaponswitch)
2037 VerifFavoritWeapon(p);
2038 //eof Boris
2039
2040 for (i=0 ; i<NUMAMMO ; i++)
2041 p->maxammo[i] = maxammo[i];
2042 }
2043
2044
2045 //
2046 // G_Player_SpawnSpot
2047 // Returns false if the player cannot be respawned
2048 // at the given mapthing_t spot because something is occupying it
2049 // Generate spawn fog.
2050 // Spawn player at the spot.
2051 //
2052 // playernum : the player to check and spawn
2053 // spot : the level map spawn spot
2054 // Return true when spawn spot is clear.
G_Player_SpawnSpot(int playernum,mapthing_t * spot)2055 boolean G_Player_SpawnSpot( int playernum, mapthing_t* spot )
2056 {
2057 fixed_t x, y;
2058 subsector_t* ss;
2059 sector_t * ssec;
2060 mobj_t* mo;
2061 player_t * player = & players[playernum];
2062
2063 // added 25-4-98 : maybe there is no player start
2064 if(!spot || spot->type<0) goto failexit;
2065 if( ! player ) goto failexit;
2066
2067 // [WDJ] kill bob momentum or player will keep bobbing at spawn spot
2068 player->bob_momx = player->bob_momy = 0;
2069 player->aiming = 0; // reset freelook
2070
2071 // The spawn spot location
2072 x = spot->x << FRACBITS;
2073 y = spot->y << FRACBITS;
2074
2075 #if 0
2076 // First spawn with no checks, is only kept because it is in Doom.
2077 // This does not work after any player moves an inch,
2078 // such as joining a network game.
2079 // Using static tstobj, tests now can be done without player->mo.
2080 if ((gametic == levelstarttic) && (player->mo == NULL))
2081 {
2082 int i;
2083 // first spawn of level, before corpses
2084 // Not all player[i].mo are init yet, see P_SetupLevel().
2085 for (i=0 ; i<playernum ; i++)
2086 {
2087 // Check if another player is on this spot.
2088 // added 15-1-98 check if player is in game (mistake from id)
2089 if (playeringame[i]
2090 && players[i].mo->x == x
2091 && players[i].mo->y == y)
2092 goto failexit;
2093 }
2094 // No fog, and no spawn sound.
2095 goto silent_spawn;
2096 }
2097 #endif
2098
2099 ss = R_PointInSubsector (x,y);
2100 ssec = ss->sector;
2101
2102 // check for respawn in team-sector.
2103 // Dogs do not know how to play teams.
2104 if(ssec->teamstartsec)
2105 {
2106 if(cv_teamplay.EV == 1)
2107 {
2108 // color
2109 if(player->skincolor!=(ssec->teamstartsec-1)) // -1 because wanted to know when it is set
2110 goto failexit;
2111 }
2112 else
2113 if(cv_teamplay.EV == 2)
2114 {
2115 // skins
2116 if(player->skin!=(ssec->teamstartsec-1)) // -1 because wanted to know when it is set
2117 goto failexit;
2118 }
2119 }
2120
2121 // [WDJ] Test spawn spot for any player or blocking object.
2122 // Use tstobj, so do not need player mobj. There may not be one.
2123 if( ! test_spot_unoccupied( MT_PLAYER, x, y, ssec->floorheight ) )
2124 goto failexit;
2125
2126 // Spawn Spot accepted. Start spawn process.
2127
2128 // If there is no corpse, there is no respawn fog nor sound.
2129 if( player->mo == NULL ) goto silent_spawn;
2130
2131 // Flush an old corpse from queue, if needed.
2132 if (bodyqueslot >= BODYQUESIZE)
2133 P_RemoveMobj (bodyque[bodyqueslot%BODYQUESIZE]);
2134 // Put player mobj in the body queue.
2135 bodyque[bodyqueslot%BODYQUESIZE] = player->mo;
2136 bodyqueslot++;
2137
2138 // spawn a teleport fog
2139 // [WDJ] Note prboom fix doc (cph 2001/04/05), of Vanilla Doom bug found by Ville Vuorinen.
2140 // Signed mapthing_t angle would create table lookup using negative index.
2141 // Current prboom emulates buggy code that accesses outside of finecosine,
2142 // finecosine[-4096] -> finetangent[2048].
2143 // This code fixes the bug.
2144 // Unsigned fine angle worked, but better to use angle_t conversion too,
2145 // which is done by wad_to_angle returning unsigned angle_t.
2146 int angf = ANGLE_TO_FINE( wad_to_angle(spot->angle) );
2147
2148 mo = P_SpawnMobj (x+20*finecosine[angf], y+20*finesine[angf],
2149 ssec->floorheight, MT_TFOG);
2150
2151 //added:16-01-98:consoleplayer -> displayplayer (hear snds from viewpt)
2152 // removed 9-12-98: why not ????
2153 if ( displayplayer_ptr->viewz != 1 )
2154 S_StartObjSound(mo, sfx_telept); // don't start sound on first frame
2155
2156 silent_spawn:
2157 // Spawn the player at the spawn spot.
2158 P_SpawnPlayer (spot, playernum);
2159 return true;
2160
2161 failexit:
2162 return false;
2163 }
2164
2165
2166 //
2167 // G_DeathMatchSpawnPlayer
2168 // Spawns a player at one of the random death match spots
2169 // called at level load and each death
2170 //
2171 // Return true when spawned.
G_DeathMatchSpawnPlayer(int playernum)2172 boolean G_DeathMatchSpawnPlayer (int playernum)
2173 {
2174 int i,j,n;
2175
2176 if( !numdmstarts )
2177 {
2178 I_SoftError("No deathmatch start in this map!");
2179 return false;
2180 }
2181
2182 if( EV_legacy < 123 )
2183 n=20; // Doom, Boom
2184 else
2185 n=64;
2186
2187 // Random select a deathmatch spot. Try n times for an unoccupied one.
2188 for (j=0 ; j<n ; j++)
2189 {
2190 i = PP_Random(pr_dmspawn) % numdmstarts;
2191 if( G_Player_SpawnSpot( playernum, deathmatchstarts[i]) )
2192 return true;
2193 }
2194
2195 if(demoversion<113)
2196 {
2197 // Doom method of last recourse.
2198 // no good spot, so the player will probably get stuck
2199 P_SpawnPlayer (playerstarts[playernum], playernum);
2200 return true;
2201 }
2202
2203 // [WDJ] Spawn at random offsets from the last random deathmatch spawn location.
2204 // This allows more players than spawn spots.
2205 if( deathmatchstarts[i] )
2206 {
2207 if( scatter_spawn( MT_PLAYER, playernum, deathmatchstarts[i] ) )
2208 return true;
2209 }
2210
2211 return false;
2212 }
2213
2214 // Will always spawn the player somewhere.
G_CoopSpawnPlayer(int playernum)2215 void G_CoopSpawnPlayer (int playernum)
2216 {
2217 mapthing_t * coop_spawn = playerstarts[playernum];
2218 int i;
2219
2220 // Check for the COOP player spot unoccupied.
2221 if( G_Player_SpawnSpot(playernum, coop_spawn) )
2222 return;
2223
2224 // Try to spawn at one of the other players spots.
2225 for (i=0 ; i<MAXPLAYERS ; i++)
2226 {
2227 if( G_Player_SpawnSpot( playernum, playerstarts[i]) )
2228 return;
2229 }
2230
2231 if(demoversion<113)
2232 {
2233 // Doom method of last recourse.
2234 P_SpawnPlayer (coop_spawn, playernum);
2235 return;
2236 }
2237
2238 // [WDJ] Spawn at random offsets from the coop_spawn location.
2239 // This allows more players than spawn spots.
2240 if( coop_spawn == NULL )
2241 coop_spawn = playerstarts[0]; // first player start should always exist
2242
2243 if( coop_spawn )
2244 {
2245 if( scatter_spawn( MT_PLAYER, playernum, coop_spawn ) )
2246 return;
2247 }
2248
2249 // Try to use a deathmatch spot.
2250 // No message about deathmatch starts in coop mode.
2251 if( numdmstarts && ( ! deathmatch ) )
2252 {
2253 if( G_DeathMatchSpawnPlayer( playernum ) )
2254 return;
2255 }
2256
2257 // Probably will spawn within someone.
2258 P_SpawnPlayer (coop_spawn, playernum);
2259 }
2260
2261 //
2262 // G_DoReborn
2263 //
2264 // Called from: P_SetupLevel, G_Ticker
G_DoReborn(int playernum)2265 void G_DoReborn (int playernum)
2266 {
2267 player_t* player = &players[playernum];
2268
2269 // boris comment : this test is like 'single player game'
2270 // all this kind of hiden variable must be removed
2271 if( (! multiplayer) && (! deathmatch) )
2272 {
2273 // reload the level from scratch
2274 G_DoLoadLevel (true);
2275 }
2276 else
2277 {
2278 // respawn at the start
2279
2280 // first dissasociate the corpse
2281 if(player->mo)
2282 {
2283 player->mo->player = NULL;
2284 player->mo->flags2 &= ~MF2_DONTDRAW;
2285 }
2286 // spawn at random spot if in death match
2287 if( deathmatch )
2288 {
2289 if(G_DeathMatchSpawnPlayer (playernum))
2290 return;
2291 // use coop spots too if deathmatch spots occupied
2292 }
2293
2294 G_CoopSpawnPlayer (playernum);
2295 }
2296 }
2297
G_AddPlayer(int playernum)2298 void G_AddPlayer( int playernum )
2299 {
2300 player_t *p=&players[playernum];
2301
2302 p->playerstate = PST_REBORN;
2303 memset(p->inventory, 0, sizeof( p->inventory ));
2304 p->inventorySlotNum = 0;
2305 p->inv_ptr = 0;
2306 p->st_curpos = 0;
2307 p->st_inventoryTics = 0;
2308
2309 if( gamemode == heretic )
2310 p->weaponinfo = wpnlev1info;
2311 else
2312 p->weaponinfo = doomweaponinfo;
2313 }
2314
2315 // [WDJ] Par times can now be modified.
2316 // DOOM Par Times
2317 int pars[4][10] =
2318 {
2319 {0},
2320 {0,30,75,120,90,165,180,180,30,165},
2321 {0,90,90,90,120,90,360,240,30,170},
2322 {0,90,45,90,150,90,90,165,30,135}
2323 };
2324
2325 // DOOM II Par Times
2326 int cpars[32] =
2327 {
2328 30,90,120,120,90,150,120,120,270,90, // 1-10
2329 210,150,150,150,210,150,420,150,210,150, // 11-20
2330 240,150,180,150,150,300,330,420,300,180, // 21-30
2331 120,30 // 31-32
2332 };
2333
2334
2335 //
2336 // G_DoCompleted
2337 //
2338 boolean secretexit;
2339
G_ExitLevel(void)2340 void G_ExitLevel (void)
2341 {
2342 if( gamestate==GS_LEVEL )
2343 {
2344 secretexit = false;
2345 gameaction = ga_completed;
2346 }
2347 }
2348
2349 // Here's for the german edition.
G_SecretExitLevel(void)2350 void G_SecretExitLevel (void)
2351 {
2352 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
2353 if ( (gamemode == doom2_commercial)
2354 && ( ! VALID_LUMP( W_CheckNumForName("map31") ) ))
2355 secretexit = false;
2356 else
2357 secretexit = true;
2358 gameaction = ga_completed;
2359 }
2360
G_DoCompleted(void)2361 void G_DoCompleted (void)
2362 {
2363 int i;
2364
2365 gameaction = ga_nothing;
2366
2367 for (i=0 ; i<MAXPLAYERS ; i++)
2368 {
2369 if (playeringame[i])
2370 G_PlayerFinishLevel (i); // take away cards and stuff
2371 }
2372
2373 if (automapactive)
2374 AM_Stop ();
2375
2376 automapactive = false;
2377 }
2378
G_Start_Intermission(void)2379 void G_Start_Intermission( void )
2380 {
2381 int i;
2382
2383 if (gamemode != doom2_commercial)
2384 {
2385 switch(gamemap)
2386 {
2387 case 8:
2388 //BP add comment : no intermission screen
2389 if( deathmatch )
2390 wminfo.lev_next = 0;
2391 else
2392 {
2393 // also for heretic
2394 // disconnect from network
2395 CL_Reset();
2396 F_StartFinale();
2397 return;
2398 }
2399 break; // [WDJ] 4/11/2012 map 8 is not secret level, and prboom and boom do not fall thru here.
2400 case 9:
2401 for (i=0 ; i<MAXPLAYERS ; i++)
2402 players[i].didsecret = true;
2403 break;
2404 }
2405 }
2406 //DarkWolf95: September 11, 2004: More chex stuff
2407 if (gamemode == chexquest1)
2408 {
2409 if( !modifiedgame && gamemap == 5 ) // original chexquest ends at E1M5
2410 {
2411 if( deathmatch )
2412 wminfo.lev_next = 0;
2413 else
2414 {
2415 CL_Reset();
2416 F_StartFinale();
2417 return;
2418 }
2419 }
2420 }
2421
2422 if(!dedicated)
2423 wminfo.didsecret = consoleplayer_ptr->didsecret;
2424 // 0 based
2425 wminfo.epsd = gameepisode -1;
2426 wminfo.lev_prev = gamemap -1;
2427
2428 // go to next level
2429 // wminfo.lev_next is 0 biased, unlike gamemap
2430 wminfo.lev_next = gamemap;
2431
2432 // overwrite next level in some cases
2433 if (gamemode == doom2_commercial)
2434 {
2435 if (secretexit)
2436 {
2437 switch(gamemap)
2438 {
2439 case 15 : wminfo.lev_next = 30; break;
2440 case 31 : wminfo.lev_next = 31; break;
2441 default : wminfo.lev_next = 15;break;
2442 }
2443 }
2444 else
2445 {
2446 switch(gamemap)
2447 {
2448 case 31:
2449 case 32: wminfo.lev_next = 15; break;
2450 default: wminfo.lev_next = gamemap;
2451 }
2452 }
2453 }
2454 else
2455 if (gamemode == heretic)
2456 {
2457 static const int afterSecret[5] = { 7, 5, 5, 5, 4 };
2458 if (secretexit)
2459 wminfo.lev_next = 8; // go to secret level
2460 else if (gamemap == 9)
2461 wminfo.lev_next = afterSecret[gameepisode-1]-1;
2462 }
2463 else
2464 {
2465 if (secretexit)
2466 wminfo.lev_next = 8; // go to secret level
2467 else if (gamemap == 9)
2468 {
2469 // returning from secret level
2470 switch (gameepisode)
2471 {
2472 case 1 : wminfo.lev_next = 3; break;
2473 case 2 : wminfo.lev_next = 5; break;
2474 case 3 : wminfo.lev_next = 6; break;
2475 case 4 : wminfo.lev_next = 2; break;
2476 default : wminfo.lev_next = 0; break;
2477 }
2478 }
2479 else
2480 {
2481 if (gamemap == 8)
2482 wminfo.lev_next = 0; // wrap around in deathmatch
2483 }
2484 }
2485
2486 wminfo.maxkills = totalkills;
2487 wminfo.maxitems = totalitems;
2488 wminfo.maxsecret = totalsecret;
2489 wminfo.maxfrags = 0;
2490 if( info_partime != -1)
2491 wminfo.partime = TICRATE*info_partime;
2492 else if ( gamemode == doom2_commercial )
2493 wminfo.partime = TICRATE*cpars[gamemap-1];
2494 else
2495 wminfo.partime = TICRATE*pars[gameepisode][gamemap];
2496 wminfo.pnum = consoleplayer;
2497
2498 for (i=0 ; i<MAXPLAYERS ; i++)
2499 {
2500 wminfo.plyr[i].in = playeringame[i];
2501 wminfo.plyr[i].skills = players[i].killcount;
2502 wminfo.plyr[i].sitems = players[i].itemcount;
2503 wminfo.plyr[i].ssecret = players[i].secretcount;
2504 wminfo.plyr[i].stime = leveltime;
2505 memcpy (wminfo.plyr[i].frags, players[i].frags
2506 , sizeof(wminfo.plyr[i].frags));
2507 wminfo.plyr[i].addfrags = players[i].addfrags;
2508 }
2509
2510 if (statcopy)
2511 memcpy (statcopy, &wminfo, sizeof(wminfo));
2512
2513 gamestate = GS_INTERMISSION;
2514
2515 WI_Start (&wminfo);
2516 }
2517
2518
2519 //
2520 // G_NextLevel (WorldDone)
2521 //
2522 // init next level or go to the final scene
2523 // called by end of intermision screen (wi_stuff)
G_NextLevel(void)2524 void G_NextLevel (void)
2525 {
2526 gameaction = ga_worlddone;
2527 if (secretexit)
2528 consoleplayer_ptr->didsecret = true;
2529
2530 if ( gamemode == doom2_commercial)
2531 {
2532 if( deathmatch )
2533 {
2534 if( gamemap == 30 )
2535 wminfo.lev_next = 0; // wrap around in deathmatch
2536 }
2537 else
2538 {
2539 switch (gamemap)
2540 {
2541 case 15:
2542 case 31:
2543 if (!secretexit)
2544 break;
2545 case 6:
2546 case 11:
2547 case 20:
2548 case 30:
2549 if( gamemap == 30 )
2550 CL_Reset(); // end of game disconnect from server
2551 gameaction = ga_nothing;
2552 F_StartFinale ();
2553 break;
2554 }
2555 }
2556 }
2557 }
2558
G_DoWorldDone(void)2559 void G_DoWorldDone (void)
2560 {
2561 if( demoversion<129 )
2562 {
2563 gamemap = wminfo.lev_next+1;
2564 G_DoLoadLevel (true);
2565 }
2566 else
2567 {
2568 // not in demo because demo have the mapcommand on it
2569 if(server && !demoplayback)
2570 {
2571 if( ! deathmatch )
2572 {
2573 // don't reset player between maps
2574 COM_BufAddText (va("map \"%s\" -noresetplayers\n",G_BuildMapName(gameepisode, wminfo.lev_next+1)));
2575 }
2576 else
2577 {
2578 // resetplayer in deathmatch for more equality
2579 COM_BufAddText (va("map \"%s\"\n",G_BuildMapName(gameepisode, wminfo.lev_next+1)));
2580 }
2581 }
2582 }
2583
2584 gameaction = ga_nothing;
2585 }
2586
2587
2588 // compose menu message from strings
2589 static
compose_message(const char * str1,const char * str2)2590 void compose_message( const char * str1, const char * str2 )
2591 {
2592 char msgtemp[128];
2593 if( str2 == NULL ) str2 = "";
2594 sprintf( msgtemp, "%s %s\n\nPress ESC\n", str1, str2 );
2595 M_SimpleMessage ( msgtemp );
2596 }
2597
2598
2599 extern char savegamedir[SAVESTRINGSIZE];
2600 char savegamename[MAX_WADPATH];
2601
2602 // Must be able to handle 99 savegame slots, even when
2603 // not SAVEGAME99, so net game saves are universally accepted.
G_Savegame_Name(char * namebuf,int slot)2604 void G_Savegame_Name( /*OUT*/ char * namebuf, /*IN*/ int slot )
2605 {
2606 #ifdef SAVEGAMEDIR
2607 sprintf(namebuf, savegamename, savegamedir, slot);
2608 #else
2609 sprintf(namebuf, savegamename, slot);
2610 #endif
2611 #ifdef SMIF_PC_DOS
2612 if( slot > 9 )
2613 {
2614 // shorten name to 8 char
2615 int ln = strlen( namebuf );
2616 memmove( &namebuf[ln-4], &namebuf[ln-3], 4 );
2617 }
2618 #endif
2619 }
2620
2621 //
2622 // G_InitFromSavegame
2623 // Can be called by the startup code or the menu task.
2624 //
2625 // Called from menu M_LoadSelect from M_Responder,
2626 // and from D_Main code for -loadgame command line switch.
G_Load_Game(int slot)2627 void G_Load_Game (int slot)
2628 {
2629 // [WDJ] will handle 99 slots
2630 COM_BufAddText(va("load %d\n",slot));
2631 // net command call to G_DoLoadGame
2632 }
2633
2634 // Called from network command, sent from G_LoadGame
2635 // Reads the save game file.
G_DoLoadGame(int slot)2636 void G_DoLoadGame (int slot)
2637 {
2638 char savename[255];
2639 savegame_info_t sginfo; // read header info
2640
2641 G_Savegame_Name( savename, slot );
2642
2643 if( P_Savegame_Readfile( savename ) < 0 ) goto cannot_read_file;
2644 // file is open and savebuffer allocated
2645
2646 if( ! P_Savegame_Read_header( &sginfo, 0 ) ) goto load_header_failed;
2647 if( ! sginfo.have_game ) goto wrong_game;
2648 if( ! sginfo.have_wad ) goto wrong_wad;
2649
2650 D_DisableDemo(); // turn off demos and keeps them off
2651
2652 //added:27-02-98: reset the game version
2653 G_setup_VERSION();
2654
2655 paused = 0;
2656 automapactive = false;
2657
2658 // dearchive all the modifications
2659 P_Savegame_Load_game(); // read game data in savebuffer, defer error test
2660 if( P_Savegame_Closefile( 0 ) < 0 ) goto load_failed;
2661 // savegame buffer deallocated, and file closed
2662
2663 #ifdef BASETIC_DEMOSYNC
2664 # if 0
2665 // [WDJ] PrBoom savegames indirectly save the gametic.
2666 // I see no need for a demo fix to affect savegames.
2667 // killough 11/98: load revenant tracer state
2668 basetic = gametic - *save_p++;
2669 # endif
2670 #endif
2671
2672 gameaction = ga_nothing;
2673 gamestate = GS_LEVEL;
2674
2675 displayplayer = consoleplayer;
2676 displayplayer_ptr = consoleplayer_ptr;
2677
2678 // done
2679 multiplayer = playeringame[1];
2680 if(playeringame[1] && !netgame)
2681 CV_SetValue(&cv_splitscreen,1);
2682
2683 if (setsizeneeded)
2684 R_ExecuteSetViewSize ();
2685
2686 // draw the pattern into the back screen
2687 R_FillBackScreen ();
2688 CON_ToggleOff ();
2689 return;
2690
2691 cannot_read_file:
2692 CONS_Printf ("Couldn't read file %s", savename);
2693 goto failed_exit;
2694
2695 load_header_failed:
2696 compose_message( sginfo.msg, NULL );
2697 goto failed_exit;
2698
2699 wrong_game:
2700 compose_message( "savegame requires game:", sginfo.game );
2701 goto failed_exit;
2702
2703 wrong_wad:
2704 compose_message( "savegame requires wad:", sginfo.wad );
2705 goto failed_exit;
2706
2707 load_failed:
2708 M_SimpleMessage("savegame file corrupted\n\nPress ESC\n" );
2709 Command_ExitGame_f();
2710 failed_exit:
2711 P_Savegame_Error_Closefile(); // to dealloate buffer
2712 // were not playing, but server got started by sending load message
2713 if( gamestate == GS_WAITINGPLAYERS )
2714 {
2715 // [WDJ] fix ALLREADYPLAYING message, so that still not playing
2716 Command_ExitGame_f();
2717 }
2718 return;
2719 }
2720
2721 //
2722 // G_SaveGame
2723 // Called by the menu task.
2724 // Description is a 24 byte text string
2725 //
2726 // Called from menu M_DoSave from M_Responder.
G_Save_Game(int slot,const char * description)2727 void G_Save_Game ( int slot, const char* description )
2728 {
2729 // Solo player has server, net player without server cannot save.
2730 if (server)
2731 {
2732 // [WDJ] will handle 99 slots
2733 COM_BufAddText(va("save %d \"%s\"\n",slot,description));
2734 // Net command call to G_DoSaveGame
2735 }
2736 }
2737
2738 // Called from network command sent from G_SaveGame.
2739 // Writes the save game file.
G_DoSaveGame(int savegameslot,const char * savedescription)2740 void G_DoSaveGame (int savegameslot, const char* savedescription)
2741 {
2742 char savename[256];
2743
2744 gameaction = ga_nothing;
2745
2746 G_Savegame_Name( savename, savegameslot );
2747
2748 gameaction = ga_nothing;
2749
2750 if( P_Savegame_Writefile( savename ) < 0 ) return;
2751
2752 P_Savegame_Write_header( savedescription, 0 );
2753 P_Savegame_Save_game(); // Write game data to savegame buffer.
2754
2755 if( P_Savegame_Closefile( 1 ) < 0 ) return;
2756
2757 gameaction = ga_nothing;
2758
2759 consoleplayer_ptr->message = GGSAVED;
2760
2761 // draw the pattern into the back screen
2762 R_FillBackScreen ();
2763 ST_Drawer( 1 ); // [WDJ] refresh status background without global flags
2764 }
2765
2766
2767 //
2768 // G_InitNew
2769 // Can be called by the startup code or the menu task,
2770 // consoleplayer, displayplayer, playeringame[] should be set.
2771 //
2772 // Boris comment : single player start game
2773 // Called by SF_StartSkill, M_ChooseSkill, M_VerifyNightmare
2774 // Called by cht_Responder on clev, CheatWarpFunc
G_DeferedInitNew(skill_e skill,const char * mapname,boolean StartSplitScreenGame)2775 void G_DeferedInitNew (skill_e skill, const char* mapname, boolean StartSplitScreenGame)
2776 {
2777 paused = 0;
2778
2779 if( demoplayback )
2780 COM_BufAddText ("stopdemo\n"); // invokes G_CheckDemoStatus
2781
2782 D_DisableDemo(); // turn off demos and keeps them off
2783
2784 G_setup_VERSION(); // [WDJ] should be after demo is stopped
2785
2786 // this leave the actual game if needed
2787 SV_StartSinglePlayerServer();
2788
2789 // Setup before start of game.
2790 COM_BufAddText (va("splitscreen %d;deathmatch 0;fastmonsters 0;"
2791 "respawnmonsters 0;timelimit 0;fraglimit 0\n",
2792 StartSplitScreenGame));
2793
2794 COM_BufAddText (va("map \"%s\" -skill %d -monsters 1\n",mapname,skill+1));
2795 }
2796
2797 //
2798 // This is the map command interpretation something like Command_Map_f
2799 //
2800 // called at : map cmd execution, doloadgame, doplaydemo
G_InitNew(skill_e skill,const char * mapname,boolean resetplayer)2801 void G_InitNew (skill_e skill, const char* mapname, boolean resetplayer)
2802 {
2803 //added:27-02-98: disable selected features for compatibility with
2804 // older demos, plus reset new features as default
2805 if(!G_Downgrade (demoversion))
2806 {
2807 CONS_Printf("Cannot Downgrade engine\n");
2808 CL_Reset();
2809 D_StartTitle();
2810 return;
2811 }
2812
2813 if (paused)
2814 {
2815 paused = 0;
2816 S_ResumeSound ();
2817 }
2818
2819 if (skill > sk_nightmare)
2820 skill = sk_nightmare;
2821
2822 M_ClearRandom ();
2823
2824 if( server && skill == sk_nightmare )
2825 {
2826 // NETVAR, not saved
2827 #if 1
2828 CV_SetParam(&cv_respawnmonsters,1);
2829 CV_SetParam(&cv_fastmonsters,1);
2830 #else
2831 CV_SetValue(&cv_respawnmonsters,1);
2832 CV_SetValue(&cv_fastmonsters,1);
2833 #endif
2834 }
2835
2836 // for internal maps only
2837 if (FIL_CheckExtension(mapname))
2838 {
2839 // external map file
2840 strncpy (game_map_filename, mapname, MAX_WADPATH-1);
2841 game_map_filename[MAX_WADPATH-1] = 0;
2842 // dummy values, to be set by P_SetupLevel.
2843 gameepisode = 1;
2844 gamemap = 1;
2845 }
2846 else
2847 {
2848 // internal game map
2849 // well this check is useless because it is done before (d_netcmd.c::command_map_f)
2850 // but in case of for demos....
2851 if( ! VALID_LUMP( W_CheckNumForName(mapname) ) )
2852 {
2853 CONS_Printf("\2Internal game map '%s' not found\n"
2854 "(use .wad extension for external maps)\n",mapname);
2855 Command_ExitGame_f();
2856 return;
2857 }
2858
2859 game_map_filename[0] = 0; // means not an external wad file
2860 if (gamemode==doom2_commercial) //doom2
2861 {
2862 gamemap = atoi(mapname+3); // get xx out of MAPxx
2863 gameepisode = 1;
2864 }
2865 else
2866 {
2867 gamemap = mapname[3]-'0'; // ExMy
2868 gameepisode = mapname[1]-'0';
2869 }
2870 }
2871
2872 gameskill = skill;
2873 playerdeadview = false;
2874 automapactive = false;
2875
2876 G_DoLoadLevel (resetplayer);
2877 }
2878
2879
2880 // Sets defaults according to current master EN_
2881 // Do not call after a Demo has set these settings.
2882 static
G_gamemode_EN_defaults(void)2883 void G_gamemode_EN_defaults( void )
2884 {
2885 // Fixes and buggy.
2886 // Heretic never fixed this, but PrBoom did. Default to fixed.
2887 EN_skull_bounce_fix = 1; // Off only for old demos, incl Legacy demos.
2888 EN_skull_bounce_floor = 1;
2889 EN_catch_respawn_0 = 1;
2890 // Boom
2891 EN_pushers = EN_boom;
2892 EN_doorlight = EN_boom;
2893 EN_invul_god = EN_boom;
2894 EN_boom_physics = EN_boom;
2895 EN_boom_floor = EN_boom | EN_heretic;
2896 EN_blazing_double_sound = 0;
2897 EN_vile_revive_bug = 0;
2898 EN_sleeping_sarg_bug = 0;
2899 EN_skull_limit = 0;
2900 EN_old_pain_spawn = 0;
2901 EN_doom_movestep_bug = 0;
2902 // MBF
2903 EN_mbf_telefrag = EN_mbf | EN_heretic;
2904 }
2905
2906
2907 // [WDJ] Set the gamemode, and all EN_ that are dependent upon it.
2908 // Done here to be near G_Downgrade.
G_set_gamemode(byte new_gamemode)2909 void G_set_gamemode( byte new_gamemode )
2910 {
2911 gamemode = new_gamemode;
2912 EV_legacy = VERSION; // current DoomLegacy version
2913 // Legacy defaults.
2914 EN_doom_etc = 1;
2915 EN_boom = 1;
2916 EN_mbf = 1;
2917 // Doom and doom-like defaults.
2918 EN_heretic = EN_hexen = EN_strife = 0;
2919 EN_heretic_hexen = 0;
2920 EN_inventory = 0;
2921 // Hexen and Strife are setup even though not implemented yet,
2922 // as placeholders and to prevent bad assumptions.
2923 switch( gamemode )
2924 {
2925 case heretic:
2926 EN_heretic = 1;
2927 goto not_doom;
2928 case hexen:
2929 EN_hexen = 1;
2930 goto not_doom;
2931 case strife:
2932 EN_strife = 1;
2933 goto not_doom;
2934 case chexquest1: // is doom
2935 default:
2936 break;
2937 }
2938 goto finish;
2939
2940 not_doom:
2941 EN_heretic_hexen = EN_heretic || EN_hexen;
2942 EN_doom_etc = EN_mbf = EN_boom = 0;
2943 EN_inventory = 1;
2944
2945 finish:
2946 G_gamemode_EN_defaults();
2947 return;
2948 }
2949
2950
2951 // Sets defaults according to current master EN_
2952 // Do not call after a Demo has set these settings.
2953 // Called after getting demoversion, EN_doom, etc, but before setting
2954 // individual demo settings.
2955 static
G_demo_defaults(void)2956 void G_demo_defaults( void )
2957 {
2958 // For DoomLegacy demos, generally, after version 1.44 when DoomLegacy got a capability,
2959 // it got a flag in the demo header. Default them to off.
2960 friction_model = FR_orig;
2961 monster_infight = INFT_infight; // Default is to infight, DEH can turn it off.
2962 voodoo_mode = VM_vanilla;
2963 cv_viewheight.EV = 41; // vanilla viewheight
2964 cv_solidcorpse.EV = 0;
2965 cv_instadeath.EV = 0; // Die
2966 cv_monstergravity.EV = 0;
2967 cv_monbehavior.EV = 0; // Vanilla
2968 cv_monsterfriction.EV = 0; // Vanilla
2969 EN_skull_bounce_fix = 0; // Vanilla and DoomLegacy < 1.47
2970 EN_catch_respawn_0 = 0;
2971
2972 // Boom
2973 cv_rndsoundpitch.EV = EN_boom; // normal in Boom, calls M_Random
2974 EN_pushers = EN_boom;
2975 // introduced Boom 2.00 without demo flag
2976 EN_doom_movestep_bug = EN_doom_etc && ! EN_boom;
2977 EN_variable_friction =
2978 EN_boom_floor = EN_boom && (demoversion >= 200);
2979 // introduced Boom 2.01 without demo flag
2980 EN_boom_physics =
2981 EN_doorlight =
2982 EN_invul_god =
2983 cv_invul_skymap.EV =
2984 cv_zerotags.EV = EN_boom && (demoversion >= 201); // 0=Vanilla, 1=Boom
2985 EN_blazing_double_sound =
2986 EN_skull_limit =
2987 EN_old_pain_spawn =
2988 EN_vile_revive_bug = EN_doom_etc && !( EN_boom && (demoversion >= 201)); // fixed Boom 2.01
2989 // introduced Boom 2.02 without demo flag
2990 cv_doorstuck.EV = EN_boom && (demoversion >= 202); // Boom 2.02
2991 // introduced Boom 2.04
2992 EN_sleeping_sarg_bug = EN_doom_etc && (demoversion < 204); // fixed Boom 2.04
2993
2994 // MBF
2995 cv_mbf_dropoff.EV = EN_mbf;
2996 cv_mbf_falloff.EV = EN_mbf;
2997 cv_mbf_monster_avoid_hazard.EV = EN_mbf;
2998 cv_mbf_monster_backing.EV = EN_mbf;
2999 cv_mbf_pursuit.EV = EN_mbf;
3000 cv_mbf_staylift.EV = EN_mbf;
3001 cv_mbf_help_friend.EV = EN_mbf;
3002 cv_mbf_monkeys.EV = EN_mbf;
3003 #ifdef DOGS
3004 cv_mbf_dogs.EV = EN_mbf;
3005 cv_mbf_dog_jumping.EV = EN_mbf;
3006 #endif
3007
3008 #ifdef DOORDELAY_CONTROL
3009 adj_ticks_per_sec = 35; // default
3010 #endif
3011 }
3012
3013
3014 static
G_restore_user_settings(void)3015 void G_restore_user_settings( void )
3016 {
3017 // Force some restore to invoke CV_CALL functions.
3018 cv_monbehavior.EV = 255; // infight
3019 cv_voodoo_mode.EV = 255;
3020 #ifdef DOORDELAY_CONTROL
3021 cv_doordelay.EV = 255;
3022 #endif
3023
3024 cv_mbf_distfriend.EV = ~cv_mbf_distfriend.value; // forced mismatch
3025
3026 // Restore all modifed cvar
3027 CV_Restore_User_Settings(); // Set EV = value
3028 }
3029
3030
3031
3032 //added:03-02-98:
3033 //
3034 // 'Downgrade' the game engine so that it is compatible with older demo
3035 // versions. This will probably get harder and harder with each new
3036 // 'feature' that we add to the game. This will stay until it cannot
3037 // be done a 'clean' way, then we'll have to forget about old demos..
3038 //
3039 // demoversion is usually set before this is called
G_Downgrade(int version)3040 boolean G_Downgrade(int version)
3041 {
3042 int i;
3043
3044 if (verbose > 1)
3045 {
3046 GenPrintf(EMSG_info|EMSG_all,"Downgrade to version: %i\n", version);
3047 }
3048
3049 if (version<109)
3050 return false;
3051
3052 // always true now, might be false in the future, if couldn't
3053 // go backward and disable all the features...
3054 demoversion = version;
3055
3056 if( version<130 )
3057 {
3058 mobjinfo[MT_BLOOD].radius = 20*FRACUNIT;
3059 mobjinfo[MT_BLOOD].height = 16*FRACUNIT;
3060 mobjinfo[MT_BLOOD].flags = MF_NOBLOCKMAP;
3061 }
3062 else
3063 {
3064 mobjinfo[MT_BLOOD].radius = 3*FRACUNIT;
3065 mobjinfo[MT_BLOOD].height = 0*FRACUNIT;
3066 mobjinfo[MT_BLOOD].flags = 0;
3067 }
3068
3069 // smoke trails for skull head attack since v1.25
3070 if (version<125)
3071 {
3072 states[S_ROCKET].action.acv = NULL;
3073
3074 states[S_SKULL_ATK3].action.acv = NULL;
3075 states[S_SKULL_ATK4].action.acv = NULL;
3076 }
3077 else
3078 {
3079 //activate rocket trails by default
3080 states[S_ROCKET].action.acv = A_SmokeTrailer;
3081
3082 // smoke trails behind the skull heads
3083 states[S_SKULL_ATK3].action.acv = A_SmokeTrailer;
3084 states[S_SKULL_ATK4].action.acv = A_SmokeTrailer;
3085 }
3086
3087 if(version <= 109)
3088 {
3089 // disable rocket trails
3090 states[S_ROCKET].action.acv = NULL; //NULL like in Doom2 v1.9
3091
3092 // Boris : for older demos, initialize the new skincolor value
3093 // also disable the new preferred weapons order.
3094 for(i=0;i<4;i++)
3095 {
3096 players[i].skincolor = i % NUMSKINCOLORS;
3097 players[i].originalweaponswitch=true;
3098 }//eof Boris
3099 }
3100
3101 if(version <= 111 || version >= 200)
3102 {
3103 //added:16-02-98: make sure autoaim is used for older
3104 // demos not using mouse aiming
3105 cv_allowautoaim.EV = 9; // force autoaim
3106 for(i=0;i<MAXPLAYERS;i++)
3107 players[i].autoaim_toggle = true;
3108 }
3109
3110 // PrBoom has this enabled by comp level.
3111 // It is only off for old Doom demos.
3112 EN_skull_bounce_floor = EN_skull_bounce_fix
3113 || ( version > 109 && version < 212 );
3114
3115 //SoM: 3/17/2000: Demo compatability
3116 // EN_boom has been loaded from Boom demo compatiblity.
3117 if(gamemode == heretic)
3118 {
3119 EN_boom = 0; // expected to be OFF
3120 EN_pushers = 0;
3121 EN_variable_friction = 1; // Needed for ICE E2M4
3122 EN_sleeping_sarg_bug = 0;
3123 }
3124 else if(version < 129 || ! EN_boom )
3125 {
3126 // Boom demo_compatibility mode (boom demo version < 200)
3127 EN_pushers = 0;
3128 EN_variable_friction = 0;
3129 EN_sleeping_sarg_bug = 1;
3130 }
3131 else if( version < 200 )
3132 {
3133 // Legacy
3134 // Flags loaded by (Boom, MBF, prboom) demos, but not others.
3135 EN_pushers = 1; // of Boom 2.02
3136 EN_variable_friction = 1; // of Boom 2.02
3137 EN_sleeping_sarg_bug = EV_legacy < 144;
3138 }
3139
3140 if( !demoplayback || friction_model == FR_orig )
3141 {
3142 friction_model =
3143 (gamemode == heretic)? FR_heretic
3144 : (gamemode == hexen)? FR_hexen
3145 : (version <= 132)? FR_orig // older legacy demos, and doom demos
3146 : (version <= 143)? FR_boom // old legacy demos
3147 : (version > 200) ?
3148 (
3149 (version <= 202)? FR_boom // boom 200, 201, 202
3150 : (version == 203)? FR_mbf
3151 : FR_prboom // prboom
3152 )
3153 : FR_legacy; // new model, default
3154 }
3155
3156 #if 0
3157 // EN_boom_invul_skymap, was not enabled for DoomLegacy before 1.47,
3158 // but does not affect demo sync. Is a matter of preference.
3159 if( version < 147 )
3160 cv_invul_skymap.EV = 0;
3161 #endif
3162
3163 #if 0
3164 // [WDJ]
3165 // TODO:
3166 // auto weapon change on pickup
3167 if( demoplayback )
3168 {
3169 // values that are set by the demo
3170 }
3171 else
3172 {
3173 }
3174 #endif
3175
3176 DemoAdapt_p_user(); // local enables of p_user
3177 DemoAdapt_p_mobj(); // local enables of p_mobj
3178 DemoAdapt_p_enemy(); // local enables of p_enemy
3179 DemoAdapt_p_fab(); // local enables of p_fab
3180 DemoAdapt_p_floor(); // local enables of p_floor, TNT MAP30 fix
3181 DemoAdapt_p_map(); // local enables of p_map
3182 DemoAdapt_bots(); // local enables of bots
3183 return true;
3184 }
3185
3186 // Make it easy to setup the VERSION play, without mistakes.
G_setup_VERSION(void)3187 void G_setup_VERSION( void )
3188 {
3189 #ifdef PARANOIA
3190 if( !EN_mbf )
3191 {
3192 GenPrintf( EMSG_warn, "Setup_VERSION: EN_mbf=0, possibly after demo\n" );
3193 G_set_gamemode( gamemode ); // restore EN set by gamemode
3194 }
3195 #endif
3196 // Reset demoversion to normal
3197 EV_legacy = VERSION;
3198 G_Downgrade( VERSION );
3199 }
3200
3201
3202
3203 //
3204 // DEMO RECORDING
3205 //
3206
3207 #define ZT_FWD 0x01
3208 #define ZT_SIDE 0x02
3209 #define ZT_ANGLE 0x04
3210 #define ZT_BUTTONS 0x08
3211 #define ZT_AIMING 0x10
3212 #define ZT_CHAT 0x20 // no more used
3213 #define ZT_EXTRADATA 0x40
3214 #define DEMOMARKER 0x80 // demoend
3215
3216 // SERVER_ID appears in Demo 1.48
3217 #if SERVER_PID < MAXPLAYERS
3218 # error "SERVER_PID must be > MAXPLAYERS"
3219 #endif
3220
3221 ticcmd_t oldcmd[MAXPLAYERS];
3222
3223 // Only called when demoplayback.
G_ReadDemoTiccmd(ticcmd_t * cmd,int playernum)3224 void G_ReadDemoTiccmd (ticcmd_t* cmd,int playernum)
3225 {
3226 if( (*demo_p == DEMOMARKER) || (demo_p > demoend) )
3227 {
3228 // end of demo data stream
3229 G_CheckDemoStatus ();
3230 return;
3231 }
3232
3233 if( EN_demotic_109 ) // vanilla demo tic format
3234 {
3235 // Doom, Boom, MBF, prboom demo
3236 cmd->forwardmove = READCHAR(demo_p);
3237 cmd->sidemove = READCHAR(demo_p);
3238 if( EN_boom_longtics )
3239 {
3240 cmd->angleturn = READ16(demo_p);
3241 }
3242 else
3243 {
3244 cmd->angleturn = READBYTE(demo_p)<<8;
3245 }
3246 cmd->buttons = READBYTE(demo_p);
3247 // demo does not have
3248 cmd->aiming = 0;
3249 }
3250 else
3251 {
3252 // DoomLegacy advanced demos
3253 char ziptic=*demo_p++; // bit flags for ZT_
3254
3255 if(ziptic & ZT_FWD)
3256 oldcmd[playernum].forwardmove = READCHAR(demo_p);
3257
3258 if(ziptic & ZT_SIDE)
3259 oldcmd[playernum].sidemove = READCHAR(demo_p);
3260
3261 if(ziptic & ZT_ANGLE)
3262 {
3263 if(demoversion<125)
3264 oldcmd[playernum].angleturn = READBYTE(demo_p)<<8;
3265 else
3266 oldcmd[playernum].angleturn = READ16(demo_p);
3267 }
3268
3269 if(ziptic & ZT_BUTTONS)
3270 oldcmd[playernum].buttons = READBYTE(demo_p);
3271
3272 if(ziptic & ZT_AIMING)
3273 {
3274 if(demoversion<128)
3275 oldcmd[playernum].aiming = READCHAR(demo_p);
3276 else
3277 oldcmd[playernum].aiming = READ16(demo_p);
3278 }
3279
3280 if(ziptic & ZT_CHAT)
3281 demo_p++;
3282
3283 if(ziptic & ZT_EXTRADATA)
3284 ReadLmpExtraData(&demo_p,playernum);
3285 #if 0
3286 // only used to clear textcmd, which is now done in TryRunTics
3287 else
3288 ReadLmpExtraData(0,playernum);
3289 #endif
3290
3291 memcpy(cmd,&(oldcmd[playernum]),sizeof(ticcmd_t));
3292 }
3293 }
3294
3295
G_WriteDemoTiccmd(ticcmd_t * cmd,int playernum)3296 void G_WriteDemoTiccmd (ticcmd_t* cmd,int playernum)
3297 {
3298 char ziptic=0;
3299 byte *ziptic_p;
3300
3301 ziptic_p=demo_p++; // the ziptic
3302 // write at the end of this function
3303
3304 if(cmd->forwardmove != oldcmd[playernum].forwardmove)
3305 {
3306 *demo_p++ = cmd->forwardmove;
3307 oldcmd[playernum].forwardmove = cmd->forwardmove;
3308 ziptic|=ZT_FWD;
3309 }
3310
3311 if(cmd->sidemove != oldcmd[playernum].sidemove)
3312 {
3313 *demo_p++ = cmd->sidemove;
3314 oldcmd[playernum].sidemove=cmd->sidemove;
3315 ziptic|=ZT_SIDE;
3316 }
3317
3318 if(cmd->angleturn != oldcmd[playernum].angleturn)
3319 {
3320 WRITE16(demo_p,cmd->angleturn);
3321 oldcmd[playernum].angleturn=cmd->angleturn;
3322 ziptic|=ZT_ANGLE;
3323 }
3324
3325 if(cmd->buttons != oldcmd[playernum].buttons)
3326 {
3327 *demo_p++ = cmd->buttons;
3328 oldcmd[playernum].buttons=cmd->buttons;
3329 ziptic|=ZT_BUTTONS;
3330 }
3331
3332 if(cmd->aiming != oldcmd[playernum].aiming)
3333 {
3334 WRITE16(demo_p,cmd->aiming);
3335 oldcmd[playernum].aiming=cmd->aiming;
3336 ziptic|=ZT_AIMING;
3337 }
3338
3339 if(AddLmpExtradata(&demo_p,playernum))
3340 ziptic|=ZT_EXTRADATA;
3341
3342 *ziptic_p=ziptic;
3343 //added:16-02-98: attention here for the ticcmd size!
3344 // latest demos with mouse aiming byte in ticcmd
3345 if (ziptic_p > demoend - (5*MAXPLAYERS))
3346 {
3347 G_CheckDemoStatus (); // no more space
3348 return;
3349 }
3350
3351 // don't work in network the consistency is not copyed in the cmd
3352 // demo_p = ziptic_p;
3353 // G_ReadDemoTiccmd (cmd,playernum); // make SURE it is exactly the same
3354 }
3355
3356
3357
3358 //
3359 // G_RecordDemo
3360 //
G_RecordDemo(const char * name)3361 void G_RecordDemo (const char* name)
3362 {
3363 int i;
3364 int maxsize;
3365
3366 strncpy (demoname, name, DEMONAME_LEN);
3367 demoname[DEMONAME_LEN-1] = 0;
3368 strcat (demoname, ".lmp");
3369 maxsize = 0x20000;
3370 i = M_CheckParm ("-maxdemo");
3371 if (i && i<myargc-1)
3372 maxsize = atoi(myargv[i+1])*1024;
3373 demobuffer = Z_Malloc (maxsize,PU_STATIC,NULL);
3374 demoend = demobuffer + maxsize;
3375
3376 demorecording = true;
3377 }
3378
3379
G_BeginRecording(void)3380 void G_BeginRecording (void)
3381 {
3382 int i;
3383 int rec_version = VERSION;
3384
3385 #if 0
3386 // If ever need to record something other than VERSION
3387 // make sure they agree this time.
3388 if( rec_version != VERSION )
3389 {
3390 G_Downgrade( rec_version );
3391 }
3392 #endif
3393
3394 demo_p = demobuffer;
3395
3396 // DoomLegacy version 1.44, 1.45, and after will all use demo header 144,
3397 // The actual DoomLegacy version is recorded in its header fields.
3398 // Do not change this header, except to add new fields in the empty space.
3399
3400 // write DL format (demo144) header
3401 *demo_p++ = 144; // Mark all DoomLegacy demo as version 144.
3402 *demo_p++ = 'D'; // "DL" for DoomLegacy
3403 *demo_p++ = 'L';
3404 *demo_p++ = 1; // non-zero format version (demo144_format)
3405 // 0 would be an older version with new header.
3406 *demo_p++ = VERSION; // version of doomlegacy that recorded it.
3407 *demo_p++ = rec_version; // actual DoomLegacy demoversion recorded
3408 *demo_p++ = REVISION; // demo subversion, when needed
3409 *demo_p++ = gameskill;
3410 *demo_p++ = gameepisode;
3411 *demo_p++ = gamemap;
3412 // Save EV value to get correct values when invoked by command line or saved game.
3413 *demo_p++ = cv_deathmatch.EV;
3414 *demo_p++ = cv_respawnmonsters.EV;
3415 *demo_p++ = cv_fastmonsters.EV;
3416 *demo_p++ = nomonsters;
3417 *demo_p++ = consoleplayer;
3418 *demo_p++ = cv_timelimit.value; // just to be compatible with old demo (no more used)
3419 *demo_p++ = multiplayer; // 1..31
3420
3421 for (i=0 ; i<MAXPLAYERS ; i++)
3422 {
3423 if(playeringame[i])
3424 *demo_p++ = 1;
3425 else
3426 *demo_p++ = 0;
3427 }
3428
3429 byte * demo_p_next = demo_p + 64;
3430 // more settings that affect playback
3431 *demo_p++ = cv_solidcorpse.EV;
3432 #ifdef DOORDELAY_CONTROL
3433 *demo_p++ = adj_ticks_per_sec; // doordelay, 0 is not default
3434 #else
3435 *demo_p++ = 0; // no doordelay
3436 #endif
3437 *demo_p++ = 0x40 + voodoo_mode; // 0 is not default
3438 *demo_p++ = cv_instadeath.EV; // voodoo doll instadeath, 0 is default
3439 *demo_p++ = cv_monsterfriction.EV;
3440 *demo_p++ = friction_model;
3441 *demo_p++ = cv_rndsoundpitch.EV; // uses M_Random
3442 *demo_p++ = cv_monbehavior.EV;
3443 *demo_p++ = cv_doorstuck.EV;
3444 *demo_p++ = cv_monstergravity.EV;
3445 // 10
3446 // Boom and MBF derived controls.
3447 *demo_p++ = cv_monster_remember.EV;
3448 *demo_p++ = cv_weapon_recoil.EV;
3449 *demo_p++ = cv_invul_skymap.EV;
3450 *demo_p++ = cv_zerotags.EV;
3451 *demo_p++ = cv_mbf_dropoff.EV;
3452 *demo_p++ = cv_mbf_falloff.EV;
3453 *demo_p++ = cv_mbf_pursuit.EV;
3454 *demo_p++ = cv_mbf_monster_avoid_hazard.EV;
3455 *demo_p++ = cv_mbf_monster_backing.EV;
3456 *demo_p++ = cv_mbf_staylift.EV;
3457 *demo_p++ = cv_mbf_help_friend.EV;
3458 *demo_p++ = (cv_mbf_distfriend.value >> 8); // MSB
3459 *demo_p++ = cv_mbf_distfriend.value & 0xFF; // LSB
3460 *demo_p++ = cv_mbf_monkeys.EV;
3461 #ifdef DOGS
3462 *demo_p++ = cv_mbf_dogs.EV;
3463 *demo_p++ = cv_mbf_dog_jumping.EV;
3464 #else
3465 *demo_p++ = 0;
3466 *demo_p++ = 0;
3467 #endif
3468 // 26
3469 *demo_p++ = (cv_respawnmonsterstime.value >> 8); // MSB
3470 *demo_p++ = cv_respawnmonsterstime.value & 0xFF; // LSB
3471 *demo_p++ = (cv_itemrespawntime.value >> 8); // MSB
3472 *demo_p++ = cv_itemrespawntime.value & 0xFF; // LSB
3473 // 30
3474 *demo_p++ = (game_comp_tic >> 24); // MSB
3475 *demo_p++ = (game_comp_tic >> 16);
3476 *demo_p++ = (game_comp_tic >> 8);
3477 *demo_p++ = game_comp_tic & 0xFF; // LSB
3478
3479 // empty space
3480 while( demo_p < demo_p_next ) *demo_p++ = 0;
3481
3482 *demo_p++ = 0x55; // Sync mark, start of data
3483 memset(oldcmd,0,sizeof(oldcmd));
3484 }
3485
3486
3487 // The following are set by DemoAdapt:
3488 // voodoo_mode,_doordelay; // see DemoAdapt_p_fab
3489
3490 // The following are init by starting a game (demos cannot occur during game):
3491 // deathmatch, multiplayer, nomonsters, respawnmonsters, fastmonsters
3492 // timelimit.
3493 // Timelimit is NOT saved to config.
3494
3495 // The following are set by G_Downgrade and/or G_DoPlayDemo:
3496 // EN_variable_friction, EN_pushers
3497
3498 static byte pdss_settings_valid = 0;
3499 static uint16_t pdss_respawnmonsterstime;
3500 static uint16_t pdss_itemrespawntime;
3501
playdemo_save_settings(void)3502 void playdemo_save_settings( void )
3503 {
3504 // Still have a few settings that need save, restore.
3505 if( pdss_settings_valid == 0 )
3506 {
3507 pdss_settings_valid = 1;
3508 pdss_respawnmonsterstime = cv_respawnmonsterstime.value;
3509 pdss_itemrespawntime = cv_itemrespawntime.value;
3510 }
3511 }
3512
playdemo_restore_settings(void)3513 void playdemo_restore_settings( void )
3514 {
3515 if( pdss_settings_valid )
3516 {
3517 cv_respawnmonsterstime.value = pdss_respawnmonsterstime;
3518 cv_itemrespawntime.value = pdss_itemrespawntime;
3519
3520 // only restore when demo has changed some settings
3521 G_restore_user_settings();
3522 }
3523 pdss_settings_valid = 0; // so user can change settings between demos
3524 }
3525
3526
3527 //
3528 // G_PlayDemo
3529 //
3530 // Called by D_DoAdvanceDemo to start a demo
3531 // Called by D_DoomMain to play a command line demo
3532 // Called by G_TimeDemo to play and time a demo
G_DeferedPlayDemo(const char * name)3533 void G_DeferedPlayDemo (const char* name)
3534 {
3535 // [WDJ] All as one string, or else it executes partial string
3536 // COM_BufAddText(va("playdemo \"%s\"\n", name));
3537
3538 // Using console command adds extra tics that cause sync problems.
3539 // Copy the demo name, as some are from stack buffers.
3540 if( playdemo_name == NULL )
3541 {
3542 playdemo_name = (char*) malloc(MAX_WADPATH);
3543 }
3544 strncpy( playdemo_name, name, MAX_WADPATH-1); // parameter
3545 playdemo_name[MAX_WADPATH-1] = '\0';
3546
3547 gameaction = ga_playdemo; // play demo after finishing this
3548 }
3549
3550
3551 //
3552 // Start a demo from a .LMP file or from a wad resource (eg: DEMO1)
3553 //
3554 // Called from SF_PlayDemo, fragglescript plays a demo lump
3555 // Called from Command_Playdemo_f, command play demo file or lump
G_DoPlayDemo(const char * defdemoname)3556 void G_DoPlayDemo (const char *defdemoname)
3557 {
3558 skill_e skill;
3559 lumpnum_t lmp;
3560 int i, episode, map;
3561 int demo_size;
3562 int num_players = 4;
3563 boolean boomdemo = 0;
3564 byte demo144_format = 0;
3565 byte boom_compatibility_mode = 0; // Boom 2.00 compatibility flag
3566 byte boom_compatibility_level = 0;
3567
3568 playdemo_save_settings(); // [WDJ] Save user settings.
3569
3570 // Enables that might be set directly by the demo.
3571 // Defaults
3572 EN_boom = 0;
3573 EN_mbf = 0;
3574 EV_legacy = 0;
3575 // Default demo tic read
3576 EN_demotic_109 = 0;
3577 EN_boom_longtics = 0;
3578
3579 // [WDJ] Adapted from PrBoom, keep some old demos in sync.
3580 game_comp_tic = 0;
3581
3582 //
3583 // load demo file / resource
3584 //
3585
3586 //it's an internal demo
3587 strncpy (demoname, defdemoname, DEMONAME_LEN);
3588 demoname[DEMONAME_LEN-1] = 0;
3589
3590 lmp = W_CheckNumForName(defdemoname);
3591 if( VALID_LUMP( lmp ) )
3592 {
3593 // lump
3594 demobuffer = demo_p = W_CacheLumpNum (lmp, PU_STATIC);
3595 demo_size = W_LumpLength( lmp );
3596 }
3597 else
3598 {
3599 // external file
3600 FIL_DefaultExtension(demoname,".lmp");
3601 demo_size = FIL_ReadFile (demoname, &demobuffer);
3602 if ( demo_size <= 0 )
3603 {
3604 GenPrintf(EMSG_warn, "\2ERROR: couldn't open file '%s'.\n", demoname);
3605 goto no_demo;
3606 }
3607 demo_p = demobuffer;
3608 }
3609 demoend = demo_p + demo_size - 1;
3610
3611 //
3612 // read demo header
3613 //
3614
3615 gameaction = ga_nothing;
3616 demoversion = READBYTE(demo_p);
3617 // header[0]: byte : demo version
3618 // 101 = Strife 1.01 (unsupported)
3619 // 104 = Doom 1.4 beta (unsupported)
3620 // 105 = Doom 1.5 beta (unsupported)
3621 // 106 = Doom 1.6 beta, 1.666 (unsupported)
3622 // 107 = Doom2 1.7, 1.7a (unsupported)
3623 // 108 = Doom 1.8, Doom2 1.8 (unsupported)
3624 // 109 = Doom 1.9, Doom2 1.9
3625 // 110 = Doom, published source code
3626 // 111..143 = Legacy
3627 // 144 = Legacy DL format
3628 // 200 = Boom 2.00 (supported badly, no sync)
3629 // 201 = Boom 2.01 (supported badly, no sync)
3630 // 202 = Boom 2.02 (supported badly, no sync)
3631 // 203 = LxDoom or MBF (supported badly, no sync)
3632 // 210..214 = prboom (supported badly, no sync)
3633 // Do not have version: Hexen, Heretic, Doom 1.2 and before
3634 if( demoversion < 109 )
3635 goto bad_demo_version;
3636
3637 if( demoversion < 111 )
3638 {
3639 EN_demotic_109 = 1; // vanilla demo tic format
3640 }
3641 else if( demoversion >= 111 && demoversion <= 144 )
3642 {
3643 // DoomLegacy Demos
3644 if( demoversion == 144 ) // DoomLegacy demo DL format number
3645 {
3646 if( READBYTE(demo_p) != 'D' ) goto broken_header;
3647 if( READBYTE(demo_p) != 'L' ) goto broken_header;
3648 demo144_format = *demo_p++; // DL format num, (1)
3649 demo_p++; // recording legacy version number
3650 demoversion = READBYTE(demo_p); // DoomLegacy DL demoversion number
3651 byte rev = READBYTE(demo_p);
3652 demoversion_rev = VERREV(demoversion, rev); // with revision
3653 // maybe DL header on old demo
3654 if( demoversion < 111 ) goto broken_header;
3655 if( demoversion < 143 ) demo144_format = 0;
3656 }
3657 EV_legacy = demoversion; // is a DoomLegacy version
3658 // Older demos (which could have had a demo144_format header put on them)
3659 EN_demotic_109 = (demoversion < 112); // vanilla demo tic format
3660 EN_boom = (demoversion >= 129);
3661 // [WDJ] enable of "Marine's Best Friend" feature emulation
3662 EN_mbf = (demoversion >= 147);
3663 }
3664 else if (demoversion >= 200 && demoversion <= 214)
3665 {
3666 // Boom, MBF, and prboom headers
3667 // Used by FreeDoom
3668
3669 // Read the "Boom" or "MBF" header line
3670 // Signature starts with 0x1d, end with 0xe6, padded to 6 bytes.
3671 // Signature Boom: 0x1d 'B' 'o' 'o' 'm' 0xe6
3672 // Signature MBF: 0x1d 'M' 'B' 'F' 0xe6 0x00
3673 if( *demo_p == 0x1d )
3674 {
3675 // Read signature into header buf and terminate as string.
3676 byte header[10];
3677 for ( i=0; i<5; i++ )
3678 {
3679 header[i] = demo_p[i+1];
3680 if( header[i] == 0xe6 ) break;
3681 }
3682 header[i] = 0;
3683 demo_p += 6; // signature is always 6 bytes
3684
3685 boom_compatibility_level = demoversion; // default
3686 if( (demoversion == 203) && (header[0] == 'B') )
3687 {
3688 // LxDoom
3689 boom_compatibility_mode = 0;
3690 boom_compatibility_level = 200; // LxDoom not supported
3691 EN_boom = 1;
3692 #ifdef DEBUG_DEMO
3693 debug_Printf( " LxDoom demo\n" );
3694 #endif
3695 }
3696 else
3697 {
3698 // MBF and prboom header have compatibility flag,
3699 // which in newer demos will be ignored.
3700 boom_compatibility_mode = *demo_p++;
3701 EN_boom = ! boom_compatibility_mode;
3702 #ifdef DEBUG_DEMO
3703 debug_Printf( " Boom demo\n" );
3704 #endif
3705 }
3706
3707 // Complicated decoding for various boom versions.
3708 if( boom_compatibility_mode )
3709 {
3710 if(demoversion <= 202)
3711 {
3712 boom_compatibility_level = 200;
3713 }
3714 }
3715
3716 EN_demotic_109 = 1;
3717 if( demoversion == 214 )
3718 {
3719 EN_boom_longtics = 1;
3720 }
3721
3722 EN_mbf = EN_boom && (header[0] == 'M') && (boom_compatibility_level >= 203);
3723 #ifdef DEBUG_DEMO
3724 debug_Printf( " demo header: %s.\n", header );
3725 debug_Printf( " compatibility 0x%x.\n", boom_compatibility_mode );
3726 debug_Printf( " compatibility_level 0x%x.\n", boom_compatibility_level );
3727 debug_Printf( " EN_boom %i EN_mbf %i.\n", EN_boom, EN_mbf );
3728 #endif
3729 boomdemo = 1;
3730 }
3731 else
3732 {
3733 goto broken_header;
3734 }
3735 }
3736 else
3737 {
3738 goto bad_demo_version;
3739 }
3740
3741
3742 #ifdef SHOW_DEMOVERSION
3743 CONS_Printf( "Demo Version %i.\n", (int)demoversion );
3744 #endif
3745 #ifdef DEBUG_DEMO
3746 debug_Printf( "Demo version %i.\n", (int)demoversion );
3747 #endif
3748
3749 if (demoversion < VERSION)
3750 CONS_Printf ("\2Demo is from an older game version\n");
3751
3752 if( demo_p > demoend ) goto broken_header;
3753
3754 G_demo_defaults(); // Per EN_boom, EN_mbf
3755
3756 // header[1]: byte: skill level 0..4
3757 skill = *demo_p++;
3758 // header[2]: byte: Doom episode 1..3, Doom2 and above use 1
3759 episode = *demo_p++;
3760 // header[3]: byte: map level 1..32
3761 map = *demo_p++;
3762 #ifdef DEBUG_DEMO
3763 debug_Printf( " skill %i.\n", (int)skill );
3764 debug_Printf( " episode %i.\n", (int)episode );
3765 debug_Printf( " map %i.\n", (int)map );
3766 #endif
3767 // header[4]: byte: play mode 0..2
3768 // 0 = single player or coop
3769 // 1 = deathmatch
3770 // 2 = alt deathmatch
3771 #ifdef DEBUG_DEMO
3772 debug_Printf( " play mode/deathmatch %i.\n", (int)demo_p[0] );
3773 #endif
3774 if (demoversion < 127 || demo144_format || boomdemo)
3775 {
3776 // store it, using the console will set it too late
3777 cv_deathmatch.EV = *demo_p++;
3778 Deathmatch_OnChange();
3779 }
3780 else
3781 demo_p++; // old legacy demo, ignore deathmatch
3782
3783 if( ! boomdemo )
3784 {
3785 #ifdef DEBUG_DEMO
3786 debug_Printf( " respawn %i.\n", (int)demo_p[1] );
3787 debug_Printf( " fast monsters %i.\n", (int)demo_p[2] );
3788 #endif
3789 // header[5]: byte: respawn boolean
3790 if (demoversion < 128 || demo144_format)
3791 {
3792 // store it, using the console will set it too late
3793 cv_respawnmonsters.EV = *demo_p++;
3794 }
3795 else
3796 demo_p++; // legacy demo, ignore respawnmonsters
3797
3798 // header[6]: byte: fast boolean
3799 if (demoversion < 128 || demo144_format)
3800 {
3801 // store it, using the console will set it too late
3802 cv_fastmonsters.EV = *demo_p++;
3803 cv_fastmonsters.func();
3804 }
3805 else
3806 demo_p++; // legacy demo, ignore fastmonsters
3807
3808 // header[7]: byte: no monsters present boolean
3809 nomonsters = *demo_p++;
3810 #ifdef DEBUG_DEMO
3811 debug_Printf( " no monsters %i.\n", (int)nomonsters );
3812 #endif
3813 cv_rndsoundpitch.EV = 0;
3814 }
3815
3816 // header[8]: byte: viewing player 0..3, 0=player1
3817 //added:08-02-98: added displayplayer because the status bar links
3818 // to the display player when playing back a demo.
3819 displayplayer = consoleplayer = *demo_p++;
3820 displayplayer_ptr = consoleplayer_ptr = &players[consoleplayer]; // [WDJ]
3821
3822 #ifdef DEBUG_DEMO
3823 debug_Printf( " viewing player %i.\n", (int)displayplayer );
3824 #endif
3825
3826 // support old v1.9 demos with ONLY 4 PLAYERS ! Man! what a shame!!!
3827 if( demoversion==109 )
3828 {
3829 // header[9..12]: byte: player[1..4] present boolean
3830 num_players = 4;
3831 }
3832 else if( boomdemo )
3833 {
3834 cv_rndsoundpitch.EV = EN_boom; // normal in Boom, call M_Random
3835
3836 // Boom ReadOptions
3837 // [WDJ] according to prboom
3838 // [0] monsters remember
3839 // [1] variable friction
3840 // [2] weapon recoil
3841 // [3] allow pushers
3842 // [4] ??
3843 // [5] player bobbing
3844 // [6] respawn
3845 // [7] fast monsters
3846 // [8] no monsters
3847 cv_monster_remember.EV = demo_p[0];
3848 EN_variable_friction = demo_p[1];
3849 cv_weapon_recoil.EV = demo_p[2];
3850 EN_pushers = demo_p[3];
3851 #ifdef DEBUG_DEMO
3852 debug_Printf( " respawn %i.\n", (int)demo_p[6] );
3853 debug_Printf( " fast monsters %i.\n", (int)demo_p[7] );
3854 #endif
3855 cv_respawnmonsters.EV = demo_p[6]; // respawn monsters, boolean
3856 cv_fastmonsters.EV = demo_p[7]; // fast monsters, boolean
3857 cv_fastmonsters.func();
3858 nomonsters = demo_p[8]; // nomonsters, boolean
3859 #ifdef DEBUG_DEMO
3860 debug_Printf( " no monsters %i.\n", (int)nomonsters );
3861 #endif
3862 // [9] demo insurance
3863 // [10..13] random number seed
3864 // When demo insurance, Boom has random number generator per usage,
3865 // all initialized from this seed. DoomLegacy does not have this.
3866 // Seed is not needed for the standard random number generators.
3867 if( demo_p[9] )
3868 debug_Printf( " demo insurance RNG, not implemented.\n" );
3869
3870 if( demoversion >= 203 ) // MBF and prboom
3871 {
3872 // [14] monster infighting
3873 // [15] dogs
3874 // [16..17] ??
3875 // [18..19] distfriend
3876 // [20] monster backing
3877 // [21] monster avoid hazards
3878 // [22] monster friction
3879 // [23] help friends
3880 // [24] dog jumping
3881 // [25] monkeys
3882 // [26..57] comp vector x32
3883 // [58] force old BSP
3884 // monster_infight from demo is 0/1
3885 // Feature enables 1=ON, Do not notify NET
3886 cv_monbehavior.EV = demo_p[14]? 2:5; // (infight:off)
3887 #ifdef DOGS
3888 cv_mbf_dogs.EV = demo_p[15];
3889 #endif
3890 EV_mbf_distfriend = ((demo_p[18]<<8) + demo_p[19]) << FRACBITS;
3891 cv_mbf_monster_backing.EV = demo_p[20];
3892 cv_mbf_monster_avoid_hazard.EV = demo_p[21];
3893 // Pass EN_monster_friction, and flag cv_monsterfriction
3894 EN_monster_friction = demo_p[22];
3895 cv_monsterfriction.EV = 0x80; // MBF, Vanilla;
3896 cv_mbf_help_friend.EV = demo_p[23];
3897 #ifdef DOGS
3898 cv_mbf_dog_jumping.EV = demo_p[24];
3899 #endif
3900 cv_mbf_monkeys.EV = demo_p[25];
3901 // comp vector at [26], 1=old demo compatibility
3902 byte * comp = demo_p + 26;
3903 EN_mbf_telefrag = ! comp[comp_telefrag];
3904 cv_mbf_dropoff.EV = ! comp[comp_dropoff];
3905 EN_vile_revive_bug = comp[comp_vile]; // Vanilla
3906 EN_skull_limit = comp[comp_pain];
3907 EN_old_pain_spawn = comp[comp_skull];
3908 EN_blazing_double_sound = comp[comp_blazing]; // Vanilla
3909 EN_doorlight = ! comp[comp_doorlight];
3910 EN_boom_physics = ! comp[comp_model];
3911 EN_invul_god = ! comp[comp_god];
3912 cv_mbf_falloff.EV = ! comp[comp_falloff];
3913 EN_boom_floor = ! comp[comp_floors];
3914 cv_invul_skymap.EV = ! comp[comp_pursuit]; // 0=Vanilla, 1=Boom
3915 cv_mbf_pursuit.EV = ! comp[comp_pursuit];
3916 cv_doorstuck.EV = comp[comp_doorstuck]? 0:2; // Vanilla : MBF
3917 cv_mbf_staylift.EV = ! comp[comp_staylift];
3918 EN_catch_respawn_0 = ! comp[comp_respawn];
3919 EN_skull_bounce_fix = ! comp[comp_soul];
3920 cv_zerotags.EV = ! comp[comp_zerotags]; // 0=Vanilla, 1=Boom
3921 EN_doom_movestep_bug = comp[comp_moveblock]; // 1=Vanilla
3922 }
3923 else
3924 {
3925 // Boom, not MBF
3926 cv_doorstuck.EV = EN_boom; // 1=Boom
3927 }
3928
3929 demo_p += (demoversion == 200)? 256 : 64; // option area size
3930
3931
3932 // byte: player[1..32] present boolean
3933 // Boom saved room for 32 players even though only supported 4
3934 num_players = (boom_compatibility_level < 200)? 4 : 32;
3935
3936 if( boom_compatibility_mode )
3937 {
3938 #ifdef DEBUG_DEMO
3939 debug_Printf( " Boom demo imitating Doom2\n" );
3940 #endif
3941 demoversion = 110; // imitate non-Boom demo
3942 }
3943 }
3944 else
3945 {
3946 #ifdef DEBUG_DEMO
3947 debug_Printf( " time limit %i.\n", (int)*demo_p );
3948 #endif
3949 if(demoversion<128)
3950 {
3951 // Here is a byte, but user value may exceed a byte.
3952 cv_timelimit.value = *demo_p++;
3953 cv_timelimit.func();
3954 }
3955 else
3956 demo_p++;
3957
3958 if (demoversion<113)
3959 {
3960 // header[9..16]: byte: player[1..8] present boolean
3961 num_players = 8;
3962 }
3963 else
3964 {
3965 // header[17]: byte: multiplayer boolean
3966 if( demoversion>=131 ) {
3967 multiplayer = *demo_p++;
3968 #ifdef DEBUG_DEMO
3969 debug_Printf( " multi-player %i.\n", (int)multiplayer );
3970 #endif
3971 }
3972
3973 // header[18..50]: byte: player[1..32] present boolean
3974 num_players = 32;
3975 }
3976 }
3977
3978 if( demo_p > demoend ) goto broken_header;
3979
3980 #if MAXPLAYERS>32
3981 #error Please add support for old lmps
3982 #endif
3983
3984 // Read players in game.
3985 memset( playeringame, 0, sizeof(playeringame) );
3986 for (i=0 ; i<num_players ; i++)
3987 {
3988 playeringame[i] = *demo_p++;
3989 #ifdef DEBUG_DEMO
3990 if( playeringame[i] )
3991 debug_Printf( " player %i\n", i+1 );
3992 #endif
3993 }
3994
3995 // FIXME: do a proper test here
3996 if( demoversion<131 )
3997 multiplayer = playeringame[1];
3998
3999 if( demo_p > demoend ) goto broken_header;
4000
4001 // [WDJ]
4002 if( demo144_format )
4003 {
4004 byte * demo_p_next = demo_p + ((demoversion < 147)? 32 : 64);
4005 // more settings that affect playback
4006 cv_solidcorpse.EV = *demo_p++;
4007 #ifdef DOORDELAY_CONTROL
4008 adj_ticks_per_sec = *demo_p++; // 0 is not default
4009 if( adj_ticks_per_sec < 20 ) adj_ticks_per_sec = 35; // default
4010 #else
4011 demo_p++; // no doordelay
4012 #endif
4013 if( *demo_p >= 0x40 ) // Voodoo doll control
4014 voodoo_mode = *demo_p++ - 0x40; // 0 is not default
4015 else
4016 voodoo_mode = VM_auto; // default
4017 cv_instadeath.EV = *demo_p++; // voodoo doll instadeath, 0 is default
4018 cv_monsterfriction.EV = *demo_p++;
4019 friction_model = *demo_p++;
4020 cv_rndsoundpitch.EV = *demo_p++; // uses M_Random
4021 cv_monbehavior.EV = *demo_p++;
4022 if( demoversion_rev < VERREV(148,5) )
4023 {
4024 // Previous versions implemented full infight.
4025 if( cv_monbehavior.EV == 2 ) cv_monbehavior.EV = 6;
4026 else if( cv_monbehavior.EV == 4 ) cv_monbehavior.EV = 7;
4027 }
4028 cv_doorstuck.EV = *demo_p++;
4029 cv_monstergravity.EV = *demo_p++;
4030 // Boom and MBF derived controls.
4031 cv_monster_remember.EV = *demo_p++;
4032 cv_weapon_recoil.EV = *demo_p++;
4033 cv_invul_skymap.EV = *demo_p++;
4034 cv_zerotags.EV = *demo_p++;
4035 cv_mbf_dropoff.EV = *demo_p++;
4036 cv_mbf_falloff.EV = *demo_p++;
4037 cv_mbf_pursuit.EV = *demo_p++;
4038 cv_mbf_monster_avoid_hazard.EV = *demo_p++;
4039 cv_mbf_monster_backing.EV = *demo_p++;
4040 cv_mbf_staylift.EV = *demo_p++;
4041 cv_mbf_help_friend.EV = *demo_p++;
4042 EV_mbf_distfriend = ((demo_p[0]<<8) + demo_p[1]) << FRACBITS;
4043 demo_p += 2;
4044 cv_mbf_monkeys.EV = *demo_p++;
4045 #ifdef DOGS
4046 cv_mbf_dogs.EV = *demo_p++;
4047 cv_mbf_dog_jumping.EV = *demo_p++;
4048 #else
4049 demo_p++;
4050 demo_p++;
4051 #endif
4052 cv_respawnmonsterstime.value = (demo_p[0]<<8) + demo_p[1];
4053 demo_p += 2;
4054 cv_itemrespawntime.value = (demo_p[0]<<8) + demo_p[1];
4055 demo_p += 2;
4056 game_comp_tic = (((((demo_p[0]<<8) + demo_p[1])<<8) + demo_p[2])<<8) + demo_p[3];
4057 demo_p += 4;
4058
4059 demo_p = demo_p_next; // skip rest of settings
4060 if( *demo_p++ != 0x55 ) goto broken_header; // Sync mark, start of data
4061 }
4062
4063 if( demo_p > demoend ) goto kill_demo;
4064
4065 memset(oldcmd,0,sizeof(oldcmd));
4066
4067 demoplayback = true;
4068
4069 // don't spend a lot of time in loadlevel
4070 if(demoversion<127 || boomdemo)
4071 {
4072 precache = false;
4073 G_InitNew (skill, G_BuildMapName(episode, map),true);
4074 precache = true;
4075 }
4076 else
4077 {
4078 // wait map command in the demo
4079 // gamestate = wipegamestate = GS_WAITINGPLAYERS; // will display waiting counter
4080 // gamestate = wipegamestate = GS_DEMOSCREEN; // will advance to next demo
4081 gamestate = wipegamestate = GS_NULL;
4082 }
4083
4084 CON_ToggleOff (); // may be also done at the end of map command
4085 return;
4086
4087
4088 bad_demo_version:
4089 GenPrintf(EMSG_warn, "\2ERROR: Incompatible demo (version %d). Legacy supports demo versions 109-%d.\n", demoversion, VERSION);
4090 goto kill_demo;
4091
4092 broken_header:
4093 #ifdef DEBUG_DEMO
4094 debug_Printf( " broken demo header\n" );
4095 #endif
4096
4097 kill_demo:
4098 Z_Free (demobuffer);
4099 playdemo_restore_settings();
4100 G_set_gamemode( gamemode ); // restore EN set by gamemode
4101 G_setup_VERSION();
4102 no_demo:
4103 gameaction = ga_nothing;
4104 return;
4105 }
4106
4107 //
4108 // G_TimeDemo
4109 // NOTE: name is a full filename for external demos
4110 //
4111 static byte EV_restore_cv_vidwait = 0;
4112
G_TimeDemo(const char * name)4113 void G_TimeDemo (const char* name)
4114 {
4115 nodrawers = M_CheckParm ("-nodraw");
4116 noblit = M_CheckParm ("-noblit");
4117 EV_restore_cv_vidwait = cv_vidwait.EV;
4118 if( cv_vidwait.EV )
4119 CV_Set( &cv_vidwait, "0");
4120 timingdemo = true;
4121 singletics = true;
4122 framecount = 0;
4123 demostarttime = I_GetTime ();
4124 G_DeferedPlayDemo (name);
4125 }
4126
4127
G_DoneLevelLoad(void)4128 void G_DoneLevelLoad(void)
4129 {
4130 CONS_Printf("Load Level in %f sec\n",(float)(I_GetTime()-demostarttime)/TICRATE);
4131 framecount = 0;
4132 demostarttime = I_GetTime ();
4133 }
4134
4135
4136 // Called after a death or level completion to allow demos to be cleaned up
4137 // reset engine variable set for the demos
4138 // called from stopdemo command, map command, and g_checkdemoStatus.
G_StopDemo(void)4139 void G_StopDemo(void)
4140 {
4141 Z_Free (demobuffer);
4142 demoplayback = false;
4143 timingdemo = false;
4144 singletics = false;
4145
4146 playdemo_restore_settings(); // [WDJ] restore user settings
4147 G_set_gamemode( gamemode ); // restore EN set by gamemode
4148 G_setup_VERSION();
4149
4150 gamestate=wipegamestate=GS_NULL;
4151 SV_StopServer();
4152 // SV_StartServer();
4153 SV_ResetServer();
4154
4155 // cleanup
4156 if( playdemo_name )
4157 {
4158 free(playdemo_name);
4159 playdemo_name = NULL;
4160 }
4161 }
4162
4163 // Called by G_DeferedInitNew, G_ReadDemoTiccmd, G_WriteDemoTiccmd
4164 // return value is not used by any caller
G_CheckDemoStatus(void)4165 boolean G_CheckDemoStatus (void)
4166 {
4167 if (timingdemo)
4168 {
4169 int time;
4170 float f1,f2;
4171 time = I_GetTime () - demostarttime;
4172 if(!time) return true;
4173 G_StopDemo ();
4174 timingdemo = false;
4175 f1=time;
4176 f2=framecount*TICRATE;
4177 CONS_Printf ("timed %i gametics in %i realtics\n"
4178 "%f seconds, %f avg fps\n"
4179 ,leveltime,time,f1/TICRATE,f2/f1);
4180 if( EV_restore_cv_vidwait != cv_vidwait.EV )
4181 CV_SetValue(&cv_vidwait, EV_restore_cv_vidwait);
4182 D_AdvanceDemo ();
4183 return true;
4184 }
4185
4186 if (demoplayback)
4187 {
4188 if (singledemo)
4189 I_Quit(); // No return
4190 G_StopDemo();
4191 D_AdvanceDemo ();
4192 return true;
4193 }
4194
4195 if (demorecording)
4196 {
4197 *demo_p++ = DEMOMARKER;
4198 FIL_WriteFile (demoname, demobuffer, demo_p - demobuffer);
4199 Z_Free (demobuffer);
4200 demorecording = false;
4201
4202 GenPrintf(EMSG_hud, "\2Demo %s recorded\n", demoname);
4203 return true;
4204 }
4205
4206 return false;
4207 }
4208