diff options
Diffstat (limited to 'src/g_game.c')
-rw-r--r-- | src/g_game.c | 2970 |
1 files changed, 2970 insertions, 0 deletions
diff --git a/src/g_game.c b/src/g_game.c new file mode 100644 index 0000000..c7984b9 --- /dev/null +++ b/src/g_game.c | |||
@@ -0,0 +1,2970 @@ | |||
1 | /* Emacs style mode select -*- C++ -*- | ||
2 | *----------------------------------------------------------------------------- | ||
3 | * | ||
4 | * | ||
5 | * PrBoom: a Doom port merged with LxDoom and LSDLDoom | ||
6 | * based on BOOM, a modified and improved DOOM engine | ||
7 | * Copyright (C) 1999 by | ||
8 | * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman | ||
9 | * Copyright (C) 1999-2004 by | ||
10 | * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze | ||
11 | * Copyright 2005, 2006 by | ||
12 | * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
27 | * 02111-1307, USA. | ||
28 | * | ||
29 | * DESCRIPTION: none | ||
30 | * The original Doom description was none, basically because this file | ||
31 | * has everything. This ties up the game logic, linking the menu and | ||
32 | * input code to the underlying game by creating & respawning players, | ||
33 | * building game tics, calling the underlying thing logic. | ||
34 | * | ||
35 | *----------------------------------------------------------------------------- | ||
36 | */ | ||
37 | |||
38 | #include <stdio.h> | ||
39 | #include <stdarg.h> | ||
40 | #include <stdlib.h> | ||
41 | #ifdef _MSC_VER | ||
42 | #define F_OK 0 /* Check for file existence */ | ||
43 | #define W_OK 2 /* Check for write permission */ | ||
44 | #define R_OK 4 /* Check for read permission */ | ||
45 | #include <io.h> | ||
46 | #else | ||
47 | #include <unistd.h> | ||
48 | #endif | ||
49 | #include <fcntl.h> | ||
50 | |||
51 | #ifdef HAVE_CONFIG_H | ||
52 | #include "config.h" | ||
53 | #endif | ||
54 | |||
55 | #include "doomstat.h" | ||
56 | #include "d_net.h" | ||
57 | #include "f_finale.h" | ||
58 | #include "m_argv.h" | ||
59 | #include "m_misc.h" | ||
60 | #include "m_menu.h" | ||
61 | #include "m_random.h" | ||
62 | #include "p_setup.h" | ||
63 | #include "p_saveg.h" | ||
64 | #include "p_tick.h" | ||
65 | #include "p_map.h" | ||
66 | #include "p_checksum.h" | ||
67 | #include "d_main.h" | ||
68 | #include "wi_stuff.h" | ||
69 | #include "hu_stuff.h" | ||
70 | #include "st_stuff.h" | ||
71 | #include "am_map.h" | ||
72 | #include "w_wad.h" | ||
73 | #include "r_main.h" | ||
74 | #include "r_draw.h" | ||
75 | #include "p_map.h" | ||
76 | #include "s_sound.h" | ||
77 | #include "dstrings.h" | ||
78 | #include "sounds.h" | ||
79 | #include "r_data.h" | ||
80 | #include "r_sky.h" | ||
81 | #include "d_deh.h" // Ty 3/27/98 deh declarations | ||
82 | #include "p_inter.h" | ||
83 | #include "g_game.h" | ||
84 | #include "lprintf.h" | ||
85 | #include "i_main.h" | ||
86 | #include "i_system.h" | ||
87 | #include "r_demo.h" | ||
88 | #include "r_fps.h" | ||
89 | |||
90 | #define SAVEGAMESIZE 0x20000 | ||
91 | #define SAVESTRINGSIZE 24 | ||
92 | |||
93 | static size_t savegamesize = SAVEGAMESIZE; // killough | ||
94 | static boolean netdemo; | ||
95 | static const byte *demobuffer; /* cph - only used for playback */ | ||
96 | static int demolength; // check for overrun (missing DEMOMARKER) | ||
97 | static FILE *demofp; /* cph - record straight to file */ | ||
98 | static const byte *demo_p; | ||
99 | static short consistancy[MAXPLAYERS][BACKUPTICS]; | ||
100 | |||
101 | gameaction_t gameaction; | ||
102 | gamestate_t gamestate; | ||
103 | skill_t gameskill; | ||
104 | boolean respawnmonsters; | ||
105 | int gameepisode; | ||
106 | int gamemap; | ||
107 | boolean paused; | ||
108 | // CPhipps - moved *_loadgame vars here | ||
109 | static boolean forced_loadgame = false; | ||
110 | static boolean command_loadgame = false; | ||
111 | |||
112 | boolean usergame; // ok to save / end game | ||
113 | boolean timingdemo; // if true, exit with report on completion | ||
114 | boolean fastdemo; // if true, run at full speed -- killough | ||
115 | boolean nodrawers; // for comparative timing purposes | ||
116 | boolean noblit; // for comparative timing purposes | ||
117 | int starttime; // for comparative timing purposes | ||
118 | boolean deathmatch; // only if started as net death | ||
119 | boolean netgame; // only true if packets are broadcast | ||
120 | boolean playeringame[MAXPLAYERS]; | ||
121 | player_t players[MAXPLAYERS]; | ||
122 | int consoleplayer; // player taking events and displaying | ||
123 | int displayplayer; // view being displayed | ||
124 | int gametic; | ||
125 | int basetic; /* killough 9/29/98: for demo sync */ | ||
126 | int totalkills, totallive, totalitems, totalsecret; // for intermission | ||
127 | boolean demorecording; | ||
128 | boolean demoplayback; | ||
129 | int demover; | ||
130 | boolean singledemo; // quit after playing a demo from cmdline | ||
131 | wbstartstruct_t wminfo; // parms for world map / intermission | ||
132 | boolean haswolflevels = false;// jff 4/18/98 wolf levels present | ||
133 | static byte *savebuffer; // CPhipps - static | ||
134 | int autorun = false; // always running? // phares | ||
135 | int totalleveltimes; // CPhipps - total time for all completed levels | ||
136 | int longtics; | ||
137 | |||
138 | // | ||
139 | // controls (have defaults) | ||
140 | // | ||
141 | |||
142 | int key_right; | ||
143 | int key_left; | ||
144 | int key_up; | ||
145 | int key_down; | ||
146 | int key_menu_right; // phares 3/7/98 | ||
147 | int key_menu_left; // | | ||
148 | int key_menu_up; // V | ||
149 | int key_menu_down; | ||
150 | int key_menu_backspace; // ^ | ||
151 | int key_menu_escape; // | | ||
152 | int key_menu_enter; // phares 3/7/98 | ||
153 | int key_strafeleft; | ||
154 | int key_straferight; | ||
155 | int key_fire; | ||
156 | int key_use; | ||
157 | int key_strafe; | ||
158 | int key_speed; | ||
159 | int key_escape = KEYD_ESCAPE; // phares 4/13/98 | ||
160 | int key_savegame; // phares | ||
161 | int key_loadgame; // | | ||
162 | int key_autorun; // V | ||
163 | int key_reverse; | ||
164 | int key_zoomin; | ||
165 | int key_zoomout; | ||
166 | int key_chat; | ||
167 | int key_backspace; | ||
168 | int key_enter; | ||
169 | int key_map_right; | ||
170 | int key_map_left; | ||
171 | int key_map_up; | ||
172 | int key_map_down; | ||
173 | int key_map_zoomin; | ||
174 | int key_map_zoomout; | ||
175 | int key_map; | ||
176 | int key_map_gobig; | ||
177 | int key_map_follow; | ||
178 | int key_map_mark; | ||
179 | int key_map_clear; | ||
180 | int key_map_grid; | ||
181 | int key_map_overlay; // cph - map overlay | ||
182 | int key_map_rotate; // cph - map rotation | ||
183 | int key_help = KEYD_F1; // phares 4/13/98 | ||
184 | int key_soundvolume; | ||
185 | int key_hud; | ||
186 | int key_quicksave; | ||
187 | int key_endgame; | ||
188 | int key_messages; | ||
189 | int key_quickload; | ||
190 | int key_quit; | ||
191 | int key_gamma; | ||
192 | int key_spy; | ||
193 | int key_pause; | ||
194 | int key_setup; | ||
195 | int destination_keys[MAXPLAYERS]; | ||
196 | int key_weapontoggle; | ||
197 | int key_weapon1; | ||
198 | int key_weapon2; | ||
199 | int key_weapon3; | ||
200 | int key_weapon4; | ||
201 | int key_weapon5; | ||
202 | int key_weapon6; | ||
203 | int key_weapon7; // ^ | ||
204 | int key_weapon8; // | | ||
205 | int key_weapon9; // phares | ||
206 | |||
207 | int key_screenshot; // killough 2/22/98: screenshot key | ||
208 | int mousebfire; | ||
209 | int mousebstrafe; | ||
210 | int mousebforward; | ||
211 | int joybfire; | ||
212 | int joybstrafe; | ||
213 | int joybuse; | ||
214 | int joybspeed; | ||
215 | |||
216 | #define MAXPLMOVE (forwardmove[1]) | ||
217 | #define TURBOTHRESHOLD 0x32 | ||
218 | #define SLOWTURNTICS 6 | ||
219 | #define QUICKREVERSE (short)32768 // 180 degree reverse // phares | ||
220 | #define NUMKEYS 512 | ||
221 | |||
222 | fixed_t forwardmove[2] = {0x19, 0x32}; | ||
223 | fixed_t sidemove[2] = {0x18, 0x28}; | ||
224 | fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn | ||
225 | |||
226 | // CPhipps - made lots of key/button state vars static | ||
227 | static boolean gamekeydown[NUMKEYS]; | ||
228 | static int turnheld; // for accelerative turning | ||
229 | |||
230 | static boolean mousearray[4]; | ||
231 | static boolean *mousebuttons = &mousearray[1]; // allow [-1] | ||
232 | |||
233 | // mouse values are used once | ||
234 | static int mousex; | ||
235 | static int mousey; | ||
236 | static int dclicktime; | ||
237 | static int dclickstate; | ||
238 | static int dclicks; | ||
239 | static int dclicktime2; | ||
240 | static int dclickstate2; | ||
241 | static int dclicks2; | ||
242 | |||
243 | // joystick values are repeated | ||
244 | static int joyxmove; | ||
245 | static int joyymove; | ||
246 | static boolean joyarray[5]; | ||
247 | static boolean *joybuttons = &joyarray[1]; // allow [-1] | ||
248 | |||
249 | // Game events info | ||
250 | static buttoncode_t special_event; // Event triggered by local player, to send | ||
251 | static byte savegameslot; // Slot to load if gameaction == ga_loadgame | ||
252 | char savedescription[SAVEDESCLEN]; // Description to save in savegame if gameaction == ga_savegame | ||
253 | |||
254 | //jff 3/24/98 define defaultskill here | ||
255 | int defaultskill; //note 1-based | ||
256 | |||
257 | // killough 2/8/98: make corpse queue variable in size | ||
258 | int bodyqueslot, bodyquesize; // killough 2/8/98 | ||
259 | mobj_t **bodyque = 0; // phares 8/10/98 | ||
260 | |||
261 | static void G_DoSaveGame (boolean menu); | ||
262 | static const byte* G_ReadDemoHeader(const byte* demo_p, size_t size, boolean failonerror); | ||
263 | |||
264 | // | ||
265 | // G_BuildTiccmd | ||
266 | // Builds a ticcmd from all of the available inputs | ||
267 | // or reads it from the demo buffer. | ||
268 | // If recording a demo, write it out | ||
269 | // | ||
270 | static inline signed char fudgef(signed char b) | ||
271 | { | ||
272 | static int c; | ||
273 | if (!b || !demo_compatibility || longtics) return b; | ||
274 | if (++c & 0x1f) return b; | ||
275 | b |= 1; if (b>2) b-=2; | ||
276 | return b; | ||
277 | } | ||
278 | |||
279 | static inline signed short fudgea(signed short b) | ||
280 | { | ||
281 | if (!b || !demo_compatibility || !longtics) return b; | ||
282 | b |= 1; if (b>2) b-=2; | ||
283 | return b; | ||
284 | } | ||
285 | |||
286 | |||
287 | void G_BuildTiccmd(ticcmd_t* cmd) | ||
288 | { | ||
289 | boolean strafe; | ||
290 | boolean bstrafe; | ||
291 | int speed; | ||
292 | int tspeed; | ||
293 | int forward; | ||
294 | int side; | ||
295 | int newweapon; // phares | ||
296 | /* cphipps - remove needless I_BaseTiccmd call, just set the ticcmd to zero */ | ||
297 | memset(cmd,0,sizeof*cmd); | ||
298 | cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; | ||
299 | |||
300 | strafe = gamekeydown[key_strafe] || mousebuttons[mousebstrafe] | ||
301 | || joybuttons[joybstrafe]; | ||
302 | //e6y: the "RUN" key inverts the autorun state | ||
303 | speed = (gamekeydown[key_speed] || joybuttons[joybspeed] ? !autorun : autorun); // phares | ||
304 | |||
305 | forward = side = 0; | ||
306 | |||
307 | // use two stage accelerative turning | ||
308 | // on the keyboard and joystick | ||
309 | if (joyxmove < 0 || joyxmove > 0 || | ||
310 | gamekeydown[key_right] || gamekeydown[key_left]) | ||
311 | turnheld += ticdup; | ||
312 | else | ||
313 | turnheld = 0; | ||
314 | |||
315 | if (turnheld < SLOWTURNTICS) | ||
316 | tspeed = 2; // slow turn | ||
317 | else | ||
318 | tspeed = speed; | ||
319 | |||
320 | // turn 180 degrees in one keystroke? // phares | ||
321 | // | | ||
322 | if (gamekeydown[key_reverse]) // V | ||
323 | { | ||
324 | cmd->angleturn += QUICKREVERSE; // ^ | ||
325 | gamekeydown[key_reverse] = false; // | | ||
326 | } // phares | ||
327 | |||
328 | // let movement keys cancel each other out | ||
329 | |||
330 | if (strafe) | ||
331 | { | ||
332 | if (gamekeydown[key_right]) | ||
333 | side += sidemove[speed]; | ||
334 | if (gamekeydown[key_left]) | ||
335 | side -= sidemove[speed]; | ||
336 | if (joyxmove > 0) | ||
337 | side += sidemove[speed]; | ||
338 | if (joyxmove < 0) | ||
339 | side -= sidemove[speed]; | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | if (gamekeydown[key_right]) | ||
344 | cmd->angleturn -= angleturn[tspeed]; | ||
345 | if (gamekeydown[key_left]) | ||
346 | cmd->angleturn += angleturn[tspeed]; | ||
347 | if (joyxmove > 0) | ||
348 | cmd->angleturn -= angleturn[tspeed]; | ||
349 | if (joyxmove < 0) | ||
350 | cmd->angleturn += angleturn[tspeed]; | ||
351 | } | ||
352 | |||
353 | if (gamekeydown[key_up]) | ||
354 | forward += forwardmove[speed]; | ||
355 | if (gamekeydown[key_down]) | ||
356 | forward -= forwardmove[speed]; | ||
357 | if (joyymove < 0) | ||
358 | forward += forwardmove[speed]; | ||
359 | if (joyymove > 0) | ||
360 | forward -= forwardmove[speed]; | ||
361 | if (gamekeydown[key_straferight]) | ||
362 | side += sidemove[speed]; | ||
363 | if (gamekeydown[key_strafeleft]) | ||
364 | side -= sidemove[speed]; | ||
365 | |||
366 | // buttons | ||
367 | cmd->chatchar = HU_dequeueChatChar(); | ||
368 | |||
369 | if (gamekeydown[key_fire] || mousebuttons[mousebfire] || | ||
370 | joybuttons[joybfire]) | ||
371 | cmd->buttons |= BT_ATTACK; | ||
372 | |||
373 | if (gamekeydown[key_use] || joybuttons[joybuse]) | ||
374 | { | ||
375 | cmd->buttons |= BT_USE; | ||
376 | // clear double clicks if hit use button | ||
377 | dclicks = 0; | ||
378 | } | ||
379 | |||
380 | // Toggle between the top 2 favorite weapons. // phares | ||
381 | // If not currently aiming one of these, switch to // phares | ||
382 | // the favorite. Only switch if you possess the weapon. // phares | ||
383 | |||
384 | // killough 3/22/98: | ||
385 | // | ||
386 | // Perform automatic weapons switch here rather than in p_pspr.c, | ||
387 | // except in demo_compatibility mode. | ||
388 | // | ||
389 | // killough 3/26/98, 4/2/98: fix autoswitch when no weapons are left | ||
390 | |||
391 | if ((!demo_compatibility && players[consoleplayer].attackdown && // killough | ||
392 | !P_CheckAmmo(&players[consoleplayer])) || gamekeydown[key_weapontoggle]) | ||
393 | newweapon = P_SwitchWeapon(&players[consoleplayer]); // phares | ||
394 | else | ||
395 | { // phares 02/26/98: Added gamemode checks | ||
396 | newweapon = | ||
397 | gamekeydown[key_weapon1] ? wp_fist : // killough 5/2/98: reformatted | ||
398 | gamekeydown[key_weapon2] ? wp_pistol : | ||
399 | gamekeydown[key_weapon3] ? wp_shotgun : | ||
400 | gamekeydown[key_weapon4] ? wp_chaingun : | ||
401 | gamekeydown[key_weapon5] ? wp_missile : | ||
402 | gamekeydown[key_weapon6] && gamemode != shareware ? wp_plasma : | ||
403 | gamekeydown[key_weapon7] && gamemode != shareware ? wp_bfg : | ||
404 | gamekeydown[key_weapon8] ? wp_chainsaw : | ||
405 | (!demo_compatibility && gamekeydown[key_weapon9] && gamemode == commercial) ? wp_supershotgun : | ||
406 | wp_nochange; | ||
407 | |||
408 | // killough 3/22/98: For network and demo consistency with the | ||
409 | // new weapons preferences, we must do the weapons switches here | ||
410 | // instead of in p_user.c. But for old demos we must do it in | ||
411 | // p_user.c according to the old rules. Therefore demo_compatibility | ||
412 | // determines where the weapons switch is made. | ||
413 | |||
414 | // killough 2/8/98: | ||
415 | // Allow user to switch to fist even if they have chainsaw. | ||
416 | // Switch to fist or chainsaw based on preferences. | ||
417 | // Switch to shotgun or SSG based on preferences. | ||
418 | |||
419 | if (!demo_compatibility) | ||
420 | { | ||
421 | const player_t *player = &players[consoleplayer]; | ||
422 | |||
423 | // only select chainsaw from '1' if it's owned, it's | ||
424 | // not already in use, and the player prefers it or | ||
425 | // the fist is already in use, or the player does not | ||
426 | // have the berserker strength. | ||
427 | |||
428 | if (newweapon==wp_fist && player->weaponowned[wp_chainsaw] && | ||
429 | player->readyweapon!=wp_chainsaw && | ||
430 | (player->readyweapon==wp_fist || | ||
431 | !player->powers[pw_strength] || | ||
432 | P_WeaponPreferred(wp_chainsaw, wp_fist))) | ||
433 | newweapon = wp_chainsaw; | ||
434 | |||
435 | // Select SSG from '3' only if it's owned and the player | ||
436 | // does not have a shotgun, or if the shotgun is already | ||
437 | // in use, or if the SSG is not already in use and the | ||
438 | // player prefers it. | ||
439 | |||
440 | if (newweapon == wp_shotgun && gamemode == commercial && | ||
441 | player->weaponowned[wp_supershotgun] && | ||
442 | (!player->weaponowned[wp_shotgun] || | ||
443 | player->readyweapon == wp_shotgun || | ||
444 | (player->readyweapon != wp_supershotgun && | ||
445 | P_WeaponPreferred(wp_supershotgun, wp_shotgun)))) | ||
446 | newweapon = wp_supershotgun; | ||
447 | } | ||
448 | // killough 2/8/98, 3/22/98 -- end of weapon selection changes | ||
449 | } | ||
450 | |||
451 | if (newweapon != wp_nochange) | ||
452 | { | ||
453 | cmd->buttons |= BT_CHANGE; | ||
454 | cmd->buttons |= newweapon<<BT_WEAPONSHIFT; | ||
455 | } | ||
456 | |||
457 | // mouse | ||
458 | if (mousebuttons[mousebforward]) | ||
459 | forward += forwardmove[speed]; | ||
460 | |||
461 | // forward double click | ||
462 | if (mousebuttons[mousebforward] != dclickstate && dclicktime > 1 ) | ||
463 | { | ||
464 | dclickstate = mousebuttons[mousebforward]; | ||
465 | if (dclickstate) | ||
466 | dclicks++; | ||
467 | if (dclicks == 2) | ||
468 | { | ||
469 | cmd->buttons |= BT_USE; | ||
470 | dclicks = 0; | ||
471 | } | ||
472 | else | ||
473 | dclicktime = 0; | ||
474 | } | ||
475 | else | ||
476 | if ((dclicktime += ticdup) > 20) | ||
477 | { | ||
478 | dclicks = 0; | ||
479 | dclickstate = 0; | ||
480 | } | ||
481 | |||
482 | // strafe double click | ||
483 | |||
484 | bstrafe = mousebuttons[mousebstrafe] || joybuttons[joybstrafe]; | ||
485 | if (bstrafe != dclickstate2 && dclicktime2 > 1 ) | ||
486 | { | ||
487 | dclickstate2 = bstrafe; | ||
488 | if (dclickstate2) | ||
489 | dclicks2++; | ||
490 | if (dclicks2 == 2) | ||
491 | { | ||
492 | cmd->buttons |= BT_USE; | ||
493 | dclicks2 = 0; | ||
494 | } | ||
495 | else | ||
496 | dclicktime2 = 0; | ||
497 | } | ||
498 | else | ||
499 | if ((dclicktime2 += ticdup) > 20) | ||
500 | { | ||
501 | dclicks2 = 0; | ||
502 | dclickstate2 = 0; | ||
503 | } | ||
504 | forward += mousey; | ||
505 | if (strafe) | ||
506 | side += mousex / 4; /* mead Don't want to strafe as fast as turns.*/ | ||
507 | else | ||
508 | cmd->angleturn -= mousex; /* mead now have enough dynamic range 2-10-00 */ | ||
509 | |||
510 | mousex = mousey = 0; | ||
511 | |||
512 | if (forward > MAXPLMOVE) | ||
513 | forward = MAXPLMOVE; | ||
514 | else if (forward < -MAXPLMOVE) | ||
515 | forward = -MAXPLMOVE; | ||
516 | if (side > MAXPLMOVE) | ||
517 | side = MAXPLMOVE; | ||
518 | else if (side < -MAXPLMOVE) | ||
519 | side = -MAXPLMOVE; | ||
520 | |||
521 | cmd->forwardmove += fudgef((signed char)forward); | ||
522 | cmd->sidemove += side; | ||
523 | cmd->angleturn = fudgea(cmd->angleturn); | ||
524 | |||
525 | // CPhipps - special events (game new/load/save/pause) | ||
526 | if (special_event & BT_SPECIAL) { | ||
527 | cmd->buttons = special_event; | ||
528 | special_event = 0; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | // | ||
533 | // G_RestartLevel | ||
534 | // | ||
535 | |||
536 | void G_RestartLevel(void) | ||
537 | { | ||
538 | special_event = BT_SPECIAL | (BTS_RESTARTLEVEL & BT_SPECIALMASK); | ||
539 | } | ||
540 | |||
541 | #include "z_bmalloc.h" | ||
542 | // | ||
543 | // G_DoLoadLevel | ||
544 | // | ||
545 | |||
546 | static void G_DoLoadLevel (void) | ||
547 | { | ||
548 | int i; | ||
549 | |||
550 | // Set the sky map. | ||
551 | // First thing, we have a dummy sky texture name, | ||
552 | // a flat. The data is in the WAD only because | ||
553 | // we look for an actual index, instead of simply | ||
554 | // setting one. | ||
555 | |||
556 | skyflatnum = R_FlatNumForName ( SKYFLATNAME ); | ||
557 | |||
558 | // DOOM determines the sky texture to be used | ||
559 | // depending on the current episode, and the game version. | ||
560 | if (gamemode == commercial) | ||
561 | // || gamemode == pack_tnt //jff 3/27/98 sorry guys pack_tnt,pack_plut | ||
562 | // || gamemode == pack_plut) //aren't gamemodes, this was matching retail | ||
563 | { | ||
564 | skytexture = R_TextureNumForName ("SKY3"); | ||
565 | if (gamemap < 12) | ||
566 | skytexture = R_TextureNumForName ("SKY1"); | ||
567 | else | ||
568 | if (gamemap < 21) | ||
569 | skytexture = R_TextureNumForName ("SKY2"); | ||
570 | } | ||
571 | else //jff 3/27/98 and lets not forget about DOOM and Ultimate DOOM huh? | ||
572 | switch (gameepisode) | ||
573 | { | ||
574 | case 1: | ||
575 | skytexture = R_TextureNumForName ("SKY1"); | ||
576 | break; | ||
577 | case 2: | ||
578 | skytexture = R_TextureNumForName ("SKY2"); | ||
579 | break; | ||
580 | case 3: | ||
581 | skytexture = R_TextureNumForName ("SKY3"); | ||
582 | break; | ||
583 | case 4: // Special Edition sky | ||
584 | skytexture = R_TextureNumForName ("SKY4"); | ||
585 | break; | ||
586 | }//jff 3/27/98 end sky setting fix | ||
587 | |||
588 | /* cph 2006/07/31 - took out unused levelstarttic variable */ | ||
589 | |||
590 | if (!demo_compatibility && !mbf_features) // killough 9/29/98 | ||
591 | basetic = gametic; | ||
592 | |||
593 | if (wipegamestate == GS_LEVEL) | ||
594 | wipegamestate = -1; // force a wipe | ||
595 | |||
596 | gamestate = GS_LEVEL; | ||
597 | |||
598 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
599 | { | ||
600 | if (playeringame[i] && players[i].playerstate == PST_DEAD) | ||
601 | players[i].playerstate = PST_REBORN; | ||
602 | memset (players[i].frags,0,sizeof(players[i].frags)); | ||
603 | } | ||
604 | |||
605 | // initialize the msecnode_t freelist. phares 3/25/98 | ||
606 | // any nodes in the freelist are gone by now, cleared | ||
607 | // by Z_FreeTags() when the previous level ended or player | ||
608 | // died. | ||
609 | |||
610 | { | ||
611 | DECLARE_BLOCK_MEMORY_ALLOC_ZONE(secnodezone); | ||
612 | NULL_BLOCK_MEMORY_ALLOC_ZONE(secnodezone); | ||
613 | //extern msecnode_t *headsecnode; // phares 3/25/98 | ||
614 | //headsecnode = NULL; | ||
615 | } | ||
616 | |||
617 | P_SetupLevel (gameepisode, gamemap, 0, gameskill); | ||
618 | if (!demoplayback) // Don't switch views if playing a demo | ||
619 | displayplayer = consoleplayer; // view the guy you are playing | ||
620 | gameaction = ga_nothing; | ||
621 | Z_CheckHeap (); | ||
622 | |||
623 | // clear cmd building stuff | ||
624 | memset (gamekeydown, 0, sizeof(gamekeydown)); | ||
625 | joyxmove = joyymove = 0; | ||
626 | mousex = mousey = 0; | ||
627 | special_event = 0; paused = false; | ||
628 | memset (mousebuttons, 0, sizeof(mousebuttons)); | ||
629 | memset (joybuttons, 0, sizeof(joybuttons)); | ||
630 | |||
631 | // killough 5/13/98: in case netdemo has consoleplayer other than green | ||
632 | ST_Start(); | ||
633 | HU_Start(); | ||
634 | } | ||
635 | |||
636 | |||
637 | // | ||
638 | // G_Responder | ||
639 | // Get info needed to make ticcmd_ts for the players. | ||
640 | // | ||
641 | |||
642 | boolean G_Responder (event_t* ev) | ||
643 | { | ||
644 | // allow spy mode changes even during the demo | ||
645 | // killough 2/22/98: even during DM demo | ||
646 | // | ||
647 | // killough 11/98: don't autorepeat spy mode switch | ||
648 | |||
649 | if (ev->data1 == key_spy && netgame && (demoplayback || !deathmatch) && | ||
650 | gamestate == GS_LEVEL) | ||
651 | { | ||
652 | if (ev->type == ev_keyup) | ||
653 | gamekeydown[key_spy] = false; | ||
654 | if (ev->type == ev_keydown && !gamekeydown[key_spy]) | ||
655 | { | ||
656 | gamekeydown[key_spy] = true; | ||
657 | do // spy mode | ||
658 | if (++displayplayer >= MAXPLAYERS) | ||
659 | displayplayer = 0; | ||
660 | while (!playeringame[displayplayer] && displayplayer!=consoleplayer); | ||
661 | |||
662 | ST_Start(); // killough 3/7/98: switch status bar views too | ||
663 | HU_Start(); | ||
664 | S_UpdateSounds(players[displayplayer].mo); | ||
665 | R_ActivateSectorInterpolations(); | ||
666 | R_SmoothPlaying_Reset(NULL); | ||
667 | } | ||
668 | return true; | ||
669 | } | ||
670 | |||
671 | // any other key pops up menu if in demos | ||
672 | // | ||
673 | // killough 8/2/98: enable automap in -timedemo demos | ||
674 | // | ||
675 | // killough 9/29/98: make any key pop up menu regardless of | ||
676 | // which kind of demo, and allow other events during playback | ||
677 | |||
678 | if (gameaction == ga_nothing && (demoplayback || gamestate == GS_DEMOSCREEN)) | ||
679 | { | ||
680 | // killough 9/29/98: allow user to pause demos during playback | ||
681 | if (ev->type == ev_keydown && ev->data1 == key_pause) | ||
682 | { | ||
683 | if (paused ^= 2) | ||
684 | S_PauseSound(); | ||
685 | else | ||
686 | S_ResumeSound(); | ||
687 | return true; | ||
688 | } | ||
689 | |||
690 | // killough 10/98: | ||
691 | // Don't pop up menu, if paused in middle | ||
692 | // of demo playback, or if automap active. | ||
693 | // Don't suck up keys, which may be cheats | ||
694 | |||
695 | return gamestate == GS_DEMOSCREEN && | ||
696 | !(paused & 2) && !(automapmode & am_active) && | ||
697 | ((ev->type == ev_keydown) || | ||
698 | (ev->type == ev_mouse && ev->data1) || | ||
699 | (ev->type == ev_joystick && ev->data1)) ? | ||
700 | M_StartControlPanel(), true : false; | ||
701 | } | ||
702 | |||
703 | if (gamestate == GS_FINALE && F_Responder(ev)) | ||
704 | return true; // finale ate the event | ||
705 | |||
706 | switch (ev->type) | ||
707 | { | ||
708 | case ev_keydown: | ||
709 | if (ev->data1 == key_pause) // phares | ||
710 | { | ||
711 | special_event = BT_SPECIAL | (BTS_PAUSE & BT_SPECIALMASK); | ||
712 | return true; | ||
713 | } | ||
714 | if (ev->data1 <NUMKEYS) | ||
715 | gamekeydown[ev->data1] = true; | ||
716 | return true; // eat key down events | ||
717 | |||
718 | case ev_keyup: | ||
719 | if (ev->data1 <NUMKEYS) | ||
720 | gamekeydown[ev->data1] = false; | ||
721 | return false; // always let key up events filter down | ||
722 | |||
723 | case ev_mouse: | ||
724 | mousebuttons[0] = ev->data1 & 1; | ||
725 | mousebuttons[1] = ev->data1 & 2; | ||
726 | mousebuttons[2] = ev->data1 & 4; | ||
727 | /* | ||
728 | * bmead@surfree.com | ||
729 | * Modified by Barry Mead after adding vastly more resolution | ||
730 | * to the Mouse Sensitivity Slider in the options menu 1-9-2000 | ||
731 | * Removed the mouseSensitivity "*4" to allow more low end | ||
732 | * sensitivity resolution especially for lsdoom users. | ||
733 | */ | ||
734 | mousex += (ev->data2*(mouseSensitivity_horiz))/10; /* killough */ | ||
735 | mousey += (ev->data3*(mouseSensitivity_vert))/10; /*Mead rm *4 */ | ||
736 | return true; // eat events | ||
737 | |||
738 | case ev_joystick: | ||
739 | joybuttons[0] = ev->data1 & 1; | ||
740 | joybuttons[1] = ev->data1 & 2; | ||
741 | joybuttons[2] = ev->data1 & 4; | ||
742 | joybuttons[3] = ev->data1 & 8; | ||
743 | joyxmove = ev->data2; | ||
744 | joyymove = ev->data3; | ||
745 | return true; // eat events | ||
746 | |||
747 | default: | ||
748 | break; | ||
749 | } | ||
750 | return false; | ||
751 | } | ||
752 | |||
753 | // | ||
754 | // G_Ticker | ||
755 | // Make ticcmd_ts for the players. | ||
756 | // | ||
757 | |||
758 | void G_Ticker (void) | ||
759 | { | ||
760 | int i; | ||
761 | static gamestate_t prevgamestate; | ||
762 | |||
763 | // CPhipps - player colour changing | ||
764 | if (!demoplayback && mapcolor_plyr[consoleplayer] != mapcolor_me) { | ||
765 | // Changed my multiplayer colour - Inform the whole game | ||
766 | int net_cl = LONG(mapcolor_me); | ||
767 | #ifdef HAVE_NET | ||
768 | D_NetSendMisc(nm_plcolour, sizeof(net_cl), &net_cl); | ||
769 | #endif | ||
770 | G_ChangedPlayerColour(consoleplayer, mapcolor_me); | ||
771 | } | ||
772 | P_MapStart(); | ||
773 | // do player reborns if needed | ||
774 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
775 | if (playeringame[i] && players[i].playerstate == PST_REBORN) | ||
776 | G_DoReborn (i); | ||
777 | P_MapEnd(); | ||
778 | |||
779 | // do things to change the game state | ||
780 | while (gameaction != ga_nothing) | ||
781 | { | ||
782 | switch (gameaction) | ||
783 | { | ||
784 | case ga_loadlevel: | ||
785 | // force players to be initialized on level reload | ||
786 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
787 | players[i].playerstate = PST_REBORN; | ||
788 | G_DoLoadLevel (); | ||
789 | break; | ||
790 | case ga_newgame: | ||
791 | G_DoNewGame (); | ||
792 | break; | ||
793 | case ga_loadgame: | ||
794 | G_DoLoadGame (); | ||
795 | break; | ||
796 | case ga_savegame: | ||
797 | G_DoSaveGame (false); | ||
798 | break; | ||
799 | case ga_playdemo: | ||
800 | G_DoPlayDemo (); | ||
801 | break; | ||
802 | case ga_completed: | ||
803 | G_DoCompleted (); | ||
804 | break; | ||
805 | case ga_victory: | ||
806 | F_StartFinale (); | ||
807 | break; | ||
808 | case ga_worlddone: | ||
809 | G_DoWorldDone (); | ||
810 | break; | ||
811 | case ga_nothing: | ||
812 | break; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | if (paused & 2 || (!demoplayback && menuactive && !netgame)) | ||
817 | basetic++; // For revenant tracers and RNG -- we must maintain sync | ||
818 | else { | ||
819 | // get commands, check consistancy, and build new consistancy check | ||
820 | int buf = (gametic/ticdup)%BACKUPTICS; | ||
821 | |||
822 | for (i=0 ; i<MAXPLAYERS ; i++) { | ||
823 | if (playeringame[i]) | ||
824 | { | ||
825 | ticcmd_t *cmd = &players[i].cmd; | ||
826 | |||
827 | memcpy(cmd, &netcmds[i][buf], sizeof *cmd); | ||
828 | |||
829 | if (demoplayback) | ||
830 | G_ReadDemoTiccmd (cmd); | ||
831 | if (demorecording) | ||
832 | G_WriteDemoTiccmd (cmd); | ||
833 | |||
834 | // check for turbo cheats | ||
835 | // killough 2/14/98, 2/20/98 -- only warn in netgames and demos | ||
836 | |||
837 | if ((netgame || demoplayback) && cmd->forwardmove > TURBOTHRESHOLD && | ||
838 | !(gametic&31) && ((gametic>>5)&3) == i ) | ||
839 | { | ||
840 | extern char *player_names[]; | ||
841 | /* cph - don't use sprintf, use doom_printf */ | ||
842 | doom_printf ("%s is turbo!", player_names[i]); | ||
843 | } | ||
844 | |||
845 | if (netgame && !netdemo && !(gametic%ticdup) ) | ||
846 | { | ||
847 | if (gametic > BACKUPTICS | ||
848 | && consistancy[i][buf] != cmd->consistancy) | ||
849 | I_Error("G_Ticker: Consistency failure (%i should be %i)", | ||
850 | cmd->consistancy, consistancy[i][buf]); | ||
851 | if (players[i].mo) | ||
852 | consistancy[i][buf] = players[i].mo->x; | ||
853 | else | ||
854 | consistancy[i][buf] = 0; // killough 2/14/98 | ||
855 | } | ||
856 | } | ||
857 | } | ||
858 | |||
859 | // check for special buttons | ||
860 | for (i=0; i<MAXPLAYERS; i++) { | ||
861 | if (playeringame[i]) | ||
862 | { | ||
863 | if (players[i].cmd.buttons & BT_SPECIAL) | ||
864 | { | ||
865 | switch (players[i].cmd.buttons & BT_SPECIALMASK) | ||
866 | { | ||
867 | case BTS_PAUSE: | ||
868 | paused ^= 1; | ||
869 | if (paused) | ||
870 | S_PauseSound (); | ||
871 | else | ||
872 | S_ResumeSound (); | ||
873 | break; | ||
874 | |||
875 | case BTS_SAVEGAME: | ||
876 | if (!savedescription[0]) | ||
877 | strcpy(savedescription, "NET GAME"); | ||
878 | savegameslot = | ||
879 | (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; | ||
880 | gameaction = ga_savegame; | ||
881 | break; | ||
882 | |||
883 | // CPhipps - remote loadgame request | ||
884 | case BTS_LOADGAME: | ||
885 | savegameslot = | ||
886 | (players[i].cmd.buttons & BTS_SAVEMASK)>>BTS_SAVESHIFT; | ||
887 | gameaction = ga_loadgame; | ||
888 | forced_loadgame = netgame; // Force if a netgame | ||
889 | command_loadgame = false; | ||
890 | break; | ||
891 | |||
892 | // CPhipps - Restart the level | ||
893 | case BTS_RESTARTLEVEL: | ||
894 | if (demoplayback || (compatibility_level < lxdoom_1_compatibility)) | ||
895 | break; // CPhipps - Ignore in demos or old games | ||
896 | gameaction = ga_loadlevel; | ||
897 | break; | ||
898 | } | ||
899 | players[i].cmd.buttons = 0; | ||
900 | } | ||
901 | } | ||
902 | } | ||
903 | } | ||
904 | |||
905 | // cph - if the gamestate changed, we may need to clean up the old gamestate | ||
906 | if (gamestate != prevgamestate) { | ||
907 | switch (prevgamestate) { | ||
908 | case GS_LEVEL: | ||
909 | // This causes crashes at level end - Neil Stevens | ||
910 | // The crash is because the sounds aren't stopped before freeing them | ||
911 | // the following is a possible fix | ||
912 | // This fix does avoid the crash wowever, with this fix in, the exit | ||
913 | // switch sound is cut off | ||
914 | // S_Stop(); | ||
915 | // Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1); | ||
916 | break; | ||
917 | case GS_INTERMISSION: | ||
918 | WI_End(); | ||
919 | default: | ||
920 | break; | ||
921 | } | ||
922 | prevgamestate = gamestate; | ||
923 | } | ||
924 | |||
925 | // e6y | ||
926 | // do nothing if a pause has been pressed during playback | ||
927 | // pausing during intermission can cause desynchs without that | ||
928 | if (paused & 2 && gamestate != GS_LEVEL) | ||
929 | return; | ||
930 | |||
931 | // do main actions | ||
932 | switch (gamestate) | ||
933 | { | ||
934 | case GS_LEVEL: | ||
935 | P_Ticker (); | ||
936 | ST_Ticker (); | ||
937 | AM_Ticker (); | ||
938 | HU_Ticker (); | ||
939 | break; | ||
940 | |||
941 | case GS_INTERMISSION: | ||
942 | WI_Ticker (); | ||
943 | break; | ||
944 | |||
945 | case GS_FINALE: | ||
946 | F_Ticker (); | ||
947 | break; | ||
948 | |||
949 | case GS_DEMOSCREEN: | ||
950 | D_PageTicker (); | ||
951 | break; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | // | ||
956 | // PLAYER STRUCTURE FUNCTIONS | ||
957 | // also see P_SpawnPlayer in P_Things | ||
958 | // | ||
959 | |||
960 | // | ||
961 | // G_PlayerFinishLevel | ||
962 | // Can when a player completes a level. | ||
963 | // | ||
964 | |||
965 | static void G_PlayerFinishLevel(int player) | ||
966 | { | ||
967 | player_t *p = &players[player]; | ||
968 | memset(p->powers, 0, sizeof p->powers); | ||
969 | memset(p->cards, 0, sizeof p->cards); | ||
970 | p->mo = NULL; // cph - this is allocated PU_LEVEL so it's gone | ||
971 | p->extralight = 0; // cancel gun flashes | ||
972 | p->fixedcolormap = 0; // cancel ir gogles | ||
973 | p->damagecount = 0; // no palette changes | ||
974 | p->bonuscount = 0; | ||
975 | } | ||
976 | |||
977 | // CPhipps - G_SetPlayerColour | ||
978 | // Player colours stuff | ||
979 | // | ||
980 | // G_SetPlayerColour | ||
981 | |||
982 | #include "r_draw.h" | ||
983 | |||
984 | void G_ChangedPlayerColour(int pn, int cl) | ||
985 | { | ||
986 | int i; | ||
987 | |||
988 | if (!netgame) return; | ||
989 | |||
990 | mapcolor_plyr[pn] = cl; | ||
991 | |||
992 | // Rebuild colour translation tables accordingly | ||
993 | R_InitTranslationTables(); | ||
994 | // Change translations on existing player mobj's | ||
995 | for (i=0; i<MAXPLAYERS; i++) { | ||
996 | if ((gamestate == GS_LEVEL) && playeringame[i] && (players[i].mo != NULL)) { | ||
997 | players[i].mo->flags &= ~MF_TRANSLATION; | ||
998 | players[i].mo->flags |= playernumtotrans[i] << MF_TRANSSHIFT; | ||
999 | } | ||
1000 | } | ||
1001 | } | ||
1002 | |||
1003 | // | ||
1004 | // G_PlayerReborn | ||
1005 | // Called after a player dies | ||
1006 | // almost everything is cleared and initialized | ||
1007 | // | ||
1008 | |||
1009 | void G_PlayerReborn (int player) | ||
1010 | { | ||
1011 | player_t *p; | ||
1012 | int i; | ||
1013 | int frags[MAXPLAYERS]; | ||
1014 | int killcount; | ||
1015 | int itemcount; | ||
1016 | int secretcount; | ||
1017 | |||
1018 | memcpy (frags, players[player].frags, sizeof frags); | ||
1019 | killcount = players[player].killcount; | ||
1020 | itemcount = players[player].itemcount; | ||
1021 | secretcount = players[player].secretcount; | ||
1022 | |||
1023 | p = &players[player]; | ||
1024 | |||
1025 | // killough 3/10/98,3/21/98: preserve cheats across idclev | ||
1026 | { | ||
1027 | int cheats = p->cheats; | ||
1028 | memset (p, 0, sizeof(*p)); | ||
1029 | p->cheats = cheats; | ||
1030 | } | ||
1031 | |||
1032 | memcpy(players[player].frags, frags, sizeof(players[player].frags)); | ||
1033 | players[player].killcount = killcount; | ||
1034 | players[player].itemcount = itemcount; | ||
1035 | players[player].secretcount = secretcount; | ||
1036 | |||
1037 | p->usedown = p->attackdown = true; // don't do anything immediately | ||
1038 | p->playerstate = PST_LIVE; | ||
1039 | p->health = initial_health; // Ty 03/12/98 - use dehacked values | ||
1040 | p->readyweapon = p->pendingweapon = wp_pistol; | ||
1041 | p->weaponowned[wp_fist] = true; | ||
1042 | p->weaponowned[wp_pistol] = true; | ||
1043 | p->ammo[am_clip] = initial_bullets; // Ty 03/12/98 - use dehacked values | ||
1044 | |||
1045 | for (i=0 ; i<NUMAMMO ; i++) | ||
1046 | p->maxammo[i] = maxammo[i]; | ||
1047 | } | ||
1048 | |||
1049 | // | ||
1050 | // G_CheckSpot | ||
1051 | // Returns false if the player cannot be respawned | ||
1052 | // at the given mapthing_t spot | ||
1053 | // because something is occupying it | ||
1054 | // | ||
1055 | |||
1056 | static boolean G_CheckSpot(int playernum, mapthing_t *mthing) | ||
1057 | { | ||
1058 | fixed_t x,y; | ||
1059 | subsector_t *ss; | ||
1060 | int i; | ||
1061 | |||
1062 | if (!players[playernum].mo) | ||
1063 | { | ||
1064 | // first spawn of level, before corpses | ||
1065 | for (i=0 ; i<playernum ; i++) | ||
1066 | if (players[i].mo->x == mthing->x << FRACBITS | ||
1067 | && players[i].mo->y == mthing->y << FRACBITS) | ||
1068 | return false; | ||
1069 | return true; | ||
1070 | } | ||
1071 | |||
1072 | x = mthing->x << FRACBITS; | ||
1073 | y = mthing->y << FRACBITS; | ||
1074 | |||
1075 | // killough 4/2/98: fix bug where P_CheckPosition() uses a non-solid | ||
1076 | // corpse to detect collisions with other players in DM starts | ||
1077 | // | ||
1078 | // Old code: | ||
1079 | // if (!P_CheckPosition (players[playernum].mo, x, y)) | ||
1080 | // return false; | ||
1081 | |||
1082 | players[playernum].mo->flags |= MF_SOLID; | ||
1083 | i = P_CheckPosition(players[playernum].mo, x, y); | ||
1084 | players[playernum].mo->flags &= ~MF_SOLID; | ||
1085 | if (!i) | ||
1086 | return false; | ||
1087 | |||
1088 | // flush an old corpse if needed | ||
1089 | // killough 2/8/98: make corpse queue have an adjustable limit | ||
1090 | // killough 8/1/98: Fix bugs causing strange crashes | ||
1091 | |||
1092 | if (bodyquesize > 0) | ||
1093 | { | ||
1094 | static int queuesize; | ||
1095 | if (queuesize < bodyquesize) | ||
1096 | { | ||
1097 | bodyque = realloc(bodyque, bodyquesize*sizeof*bodyque); | ||
1098 | memset(bodyque+queuesize, 0, | ||
1099 | (bodyquesize-queuesize)*sizeof*bodyque); | ||
1100 | queuesize = bodyquesize; | ||
1101 | } | ||
1102 | if (bodyqueslot >= bodyquesize) | ||
1103 | P_RemoveMobj(bodyque[bodyqueslot % bodyquesize]); | ||
1104 | bodyque[bodyqueslot++ % bodyquesize] = players[playernum].mo; | ||
1105 | } | ||
1106 | else | ||
1107 | if (!bodyquesize) | ||
1108 | P_RemoveMobj(players[playernum].mo); | ||
1109 | |||
1110 | // spawn a teleport fog | ||
1111 | ss = R_PointInSubsector (x,y); | ||
1112 | { // Teleport fog at respawn point | ||
1113 | fixed_t xa,ya; | ||
1114 | int an; | ||
1115 | mobj_t *mo; | ||
1116 | |||
1117 | /* BUG: an can end up negative, because mthing->angle is (signed) short. | ||
1118 | * We have to emulate original Doom's behaviour, deferencing past the start | ||
1119 | * of the array, into the previous array (finetangent) */ | ||
1120 | an = ( ANG45 * ((signed)mthing->angle/45) ) >> ANGLETOFINESHIFT; | ||
1121 | xa = finecosine[an]; | ||
1122 | ya = finesine[an]; | ||
1123 | |||
1124 | if (compatibility_level <= finaldoom_compatibility || compatibility_level == prboom_4_compatibility) | ||
1125 | switch (an) { | ||
1126 | case -4096: xa = finetangent[2048]; // finecosine[-4096] | ||
1127 | ya = finetangent[0]; // finesine[-4096] | ||
1128 | break; | ||
1129 | case -3072: xa = finetangent[3072]; // finecosine[-3072] | ||
1130 | ya = finetangent[1024]; // finesine[-3072] | ||
1131 | break; | ||
1132 | case -2048: xa = finesine[0]; // finecosine[-2048] | ||
1133 | ya = finetangent[2048]; // finesine[-2048] | ||
1134 | break; | ||
1135 | case -1024: xa = finesine[1024]; // finecosine[-1024] | ||
1136 | ya = finetangent[3072]; // finesine[-1024] | ||
1137 | break; | ||
1138 | case 1024: | ||
1139 | case 2048: | ||
1140 | case 3072: | ||
1141 | case 4096: | ||
1142 | case 0: break; /* correct angles set above */ | ||
1143 | default: I_Error("G_CheckSpot: unexpected angle %d\n",an); | ||
1144 | } | ||
1145 | |||
1146 | mo = P_SpawnMobj(x+20*xa, y+20*ya, ss->sector->floorheight, MT_TFOG); | ||
1147 | |||
1148 | if (players[consoleplayer].viewz != 1) | ||
1149 | S_StartSound(mo, sfx_telept); // don't start sound on first frame | ||
1150 | } | ||
1151 | |||
1152 | return true; | ||
1153 | } | ||
1154 | |||
1155 | |||
1156 | // G_DeathMatchSpawnPlayer | ||
1157 | // Spawns a player at one of the random death match spots | ||
1158 | // called at level load and each death | ||
1159 | // | ||
1160 | void G_DeathMatchSpawnPlayer (int playernum) | ||
1161 | { | ||
1162 | int j, selections = deathmatch_p - deathmatchstarts; | ||
1163 | |||
1164 | if (selections < MAXPLAYERS) | ||
1165 | I_Error("G_DeathMatchSpawnPlayer: Only %i deathmatch spots, %d required", | ||
1166 | selections, MAXPLAYERS); | ||
1167 | |||
1168 | for (j=0 ; j<20 ; j++) | ||
1169 | { | ||
1170 | int i = P_Random(pr_dmspawn) % selections; | ||
1171 | if (G_CheckSpot (playernum, &deathmatchstarts[i]) ) | ||
1172 | { | ||
1173 | deathmatchstarts[i].type = playernum+1; | ||
1174 | P_SpawnPlayer (playernum, &deathmatchstarts[i]); | ||
1175 | return; | ||
1176 | } | ||
1177 | } | ||
1178 | |||
1179 | // no good spot, so the player will probably get stuck | ||
1180 | P_SpawnPlayer (playernum, &playerstarts[playernum]); | ||
1181 | } | ||
1182 | |||
1183 | // | ||
1184 | // G_DoReborn | ||
1185 | // | ||
1186 | |||
1187 | void G_DoReborn (int playernum) | ||
1188 | { | ||
1189 | if (!netgame) | ||
1190 | gameaction = ga_loadlevel; // reload the level from scratch | ||
1191 | else | ||
1192 | { // respawn at the start | ||
1193 | int i; | ||
1194 | |||
1195 | // first dissasociate the corpse | ||
1196 | players[playernum].mo->player = NULL; | ||
1197 | |||
1198 | // spawn at random spot if in death match | ||
1199 | if (deathmatch) | ||
1200 | { | ||
1201 | G_DeathMatchSpawnPlayer (playernum); | ||
1202 | return; | ||
1203 | } | ||
1204 | |||
1205 | if (G_CheckSpot (playernum, &playerstarts[playernum]) ) | ||
1206 | { | ||
1207 | P_SpawnPlayer (playernum, &playerstarts[playernum]); | ||
1208 | return; | ||
1209 | } | ||
1210 | |||
1211 | // try to spawn at one of the other players spots | ||
1212 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
1213 | { | ||
1214 | if (G_CheckSpot (playernum, &playerstarts[i]) ) | ||
1215 | { | ||
1216 | P_SpawnPlayer (playernum, &playerstarts[i]); | ||
1217 | return; | ||
1218 | } | ||
1219 | // he's going to be inside something. Too bad. | ||
1220 | } | ||
1221 | P_SpawnPlayer (playernum, &playerstarts[playernum]); | ||
1222 | } | ||
1223 | } | ||
1224 | |||
1225 | // DOOM Par Times | ||
1226 | int pars[4][10] = { | ||
1227 | {0}, | ||
1228 | {0,30,75,120,90,165,180,180,30,165}, | ||
1229 | {0,90,90,90,120,90,360,240,30,170}, | ||
1230 | {0,90,45,90,150,90,90,165,30,135} | ||
1231 | }; | ||
1232 | |||
1233 | // DOOM II Par Times | ||
1234 | int cpars[32] = { | ||
1235 | 30,90,120,120,90,150,120,120,270,90, // 1-10 | ||
1236 | 210,150,150,150,210,150,420,150,210,150, // 11-20 | ||
1237 | 240,150,180,150,150,300,330,420,300,180, // 21-30 | ||
1238 | 120,30 // 31-32 | ||
1239 | }; | ||
1240 | |||
1241 | static boolean secretexit; | ||
1242 | |||
1243 | void G_ExitLevel (void) | ||
1244 | { | ||
1245 | secretexit = false; | ||
1246 | gameaction = ga_completed; | ||
1247 | } | ||
1248 | |||
1249 | // Here's for the german edition. | ||
1250 | // IF NO WOLF3D LEVELS, NO SECRET EXIT! | ||
1251 | |||
1252 | void G_SecretExitLevel (void) | ||
1253 | { | ||
1254 | if (gamemode!=commercial || haswolflevels) | ||
1255 | secretexit = true; | ||
1256 | else | ||
1257 | secretexit = false; | ||
1258 | gameaction = ga_completed; | ||
1259 | } | ||
1260 | |||
1261 | // | ||
1262 | // G_DoCompleted | ||
1263 | // | ||
1264 | |||
1265 | void G_DoCompleted (void) | ||
1266 | { | ||
1267 | int i; | ||
1268 | |||
1269 | gameaction = ga_nothing; | ||
1270 | |||
1271 | for (i=0; i<MAXPLAYERS; i++) | ||
1272 | if (playeringame[i]) | ||
1273 | G_PlayerFinishLevel(i); // take away cards and stuff | ||
1274 | |||
1275 | if (automapmode & am_active) | ||
1276 | AM_Stop(); | ||
1277 | |||
1278 | if (gamemode != commercial) // kilough 2/7/98 | ||
1279 | switch(gamemap) | ||
1280 | { | ||
1281 | // cph - Remove ExM8 special case, so it gets summary screen displayed | ||
1282 | case 9: | ||
1283 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
1284 | players[i].didsecret = true; | ||
1285 | break; | ||
1286 | } | ||
1287 | |||
1288 | wminfo.didsecret = players[consoleplayer].didsecret; | ||
1289 | wminfo.epsd = gameepisode -1; | ||
1290 | wminfo.last = gamemap -1; | ||
1291 | |||
1292 | // wminfo.next is 0 biased, unlike gamemap | ||
1293 | if (gamemode == commercial) | ||
1294 | { | ||
1295 | if (secretexit) | ||
1296 | switch(gamemap) | ||
1297 | { | ||
1298 | case 15: | ||
1299 | wminfo.next = 30; break; | ||
1300 | case 31: | ||
1301 | wminfo.next = 31; break; | ||
1302 | } | ||
1303 | else | ||
1304 | switch(gamemap) | ||
1305 | { | ||
1306 | case 31: | ||
1307 | case 32: | ||
1308 | wminfo.next = 15; break; | ||
1309 | default: | ||
1310 | wminfo.next = gamemap; | ||
1311 | } | ||
1312 | } | ||
1313 | else | ||
1314 | { | ||
1315 | if (secretexit) | ||
1316 | wminfo.next = 8; // go to secret level | ||
1317 | else | ||
1318 | if (gamemap == 9) | ||
1319 | { | ||
1320 | // returning from secret level | ||
1321 | switch (gameepisode) | ||
1322 | { | ||
1323 | case 1: | ||
1324 | wminfo.next = 3; | ||
1325 | break; | ||
1326 | case 2: | ||
1327 | wminfo.next = 5; | ||
1328 | break; | ||
1329 | case 3: | ||
1330 | wminfo.next = 6; | ||
1331 | break; | ||
1332 | case 4: | ||
1333 | wminfo.next = 2; | ||
1334 | break; | ||
1335 | } | ||
1336 | } | ||
1337 | else | ||
1338 | wminfo.next = gamemap; // go to next level | ||
1339 | } | ||
1340 | |||
1341 | wminfo.maxkills = totalkills; | ||
1342 | wminfo.maxitems = totalitems; | ||
1343 | wminfo.maxsecret = totalsecret; | ||
1344 | wminfo.maxfrags = 0; | ||
1345 | |||
1346 | if ( gamemode == commercial ) | ||
1347 | wminfo.partime = TICRATE*cpars[gamemap-1]; | ||
1348 | else | ||
1349 | wminfo.partime = TICRATE*pars[gameepisode][gamemap]; | ||
1350 | |||
1351 | wminfo.pnum = consoleplayer; | ||
1352 | |||
1353 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
1354 | { | ||
1355 | wminfo.plyr[i].in = playeringame[i]; | ||
1356 | wminfo.plyr[i].skills = players[i].killcount; | ||
1357 | wminfo.plyr[i].sitems = players[i].itemcount; | ||
1358 | wminfo.plyr[i].ssecret = players[i].secretcount; | ||
1359 | wminfo.plyr[i].stime = leveltime; | ||
1360 | memcpy (wminfo.plyr[i].frags, players[i].frags, | ||
1361 | sizeof(wminfo.plyr[i].frags)); | ||
1362 | } | ||
1363 | |||
1364 | /* cph - modified so that only whole seconds are added to the totalleveltimes | ||
1365 | * value; so our total is compatible with the "naive" total of just adding | ||
1366 | * the times in seconds shown for each level. Also means our total time | ||
1367 | * will agree with Compet-n. | ||
1368 | */ | ||
1369 | wminfo.totaltimes = (totalleveltimes += (leveltime - leveltime%35)); | ||
1370 | |||
1371 | gamestate = GS_INTERMISSION; | ||
1372 | automapmode &= ~am_active; | ||
1373 | |||
1374 | // lmpwatch.pl engine-side demo testing support | ||
1375 | // print "FINISHED: <mapname>" when the player exits the current map | ||
1376 | if (nodrawers && (demoplayback || timingdemo)) { | ||
1377 | if (gamemode == commercial) | ||
1378 | lprintf(LO_INFO, "FINISHED: MAP%02d\n", gamemap); | ||
1379 | else | ||
1380 | lprintf(LO_INFO, "FINISHED: E%dM%d\n", gameepisode, gamemap); | ||
1381 | } | ||
1382 | |||
1383 | WI_Start (&wminfo); | ||
1384 | } | ||
1385 | |||
1386 | // | ||
1387 | // G_WorldDone | ||
1388 | // | ||
1389 | |||
1390 | void G_WorldDone (void) | ||
1391 | { | ||
1392 | gameaction = ga_worlddone; | ||
1393 | |||
1394 | if (secretexit) | ||
1395 | players[consoleplayer].didsecret = true; | ||
1396 | |||
1397 | if (gamemode == commercial) | ||
1398 | { | ||
1399 | switch (gamemap) | ||
1400 | { | ||
1401 | case 15: | ||
1402 | case 31: | ||
1403 | if (!secretexit) | ||
1404 | break; | ||
1405 | case 6: | ||
1406 | case 11: | ||
1407 | case 20: | ||
1408 | case 30: | ||
1409 | F_StartFinale (); | ||
1410 | break; | ||
1411 | } | ||
1412 | } | ||
1413 | else if (gamemap == 8) | ||
1414 | gameaction = ga_victory; // cph - after ExM8 summary screen, show victory stuff | ||
1415 | } | ||
1416 | |||
1417 | void G_DoWorldDone (void) | ||
1418 | { | ||
1419 | idmusnum = -1; //jff 3/17/98 allow new level's music to be loaded | ||
1420 | gamestate = GS_LEVEL; | ||
1421 | gamemap = wminfo.next+1; | ||
1422 | G_DoLoadLevel(); | ||
1423 | gameaction = ga_nothing; | ||
1424 | AM_clearMarks(); //jff 4/12/98 clear any marks on the automap | ||
1425 | } | ||
1426 | |||
1427 | // killough 2/28/98: A ridiculously large number | ||
1428 | // of players, the most you'll ever need in a demo | ||
1429 | // or savegame. This is used to prevent problems, in | ||
1430 | // case more players in a game are supported later. | ||
1431 | |||
1432 | #define MIN_MAXPLAYERS 32 | ||
1433 | |||
1434 | extern boolean setsizeneeded; | ||
1435 | |||
1436 | //CPhipps - savename variable redundant | ||
1437 | |||
1438 | /* killough 12/98: | ||
1439 | * This function returns a signature for the current wad. | ||
1440 | * It is used to distinguish between wads, for the purposes | ||
1441 | * of savegame compatibility warnings, and options lookups. | ||
1442 | */ | ||
1443 | |||
1444 | static uint_64_t G_UpdateSignature(uint_64_t s, const char *name) | ||
1445 | { | ||
1446 | int i, lump = W_CheckNumForName(name); | ||
1447 | if (lump != -1 && (i = lump+10) < numlumps) | ||
1448 | do | ||
1449 | { | ||
1450 | int size = W_LumpLength(i); | ||
1451 | const byte *p = W_CacheLumpNum(i); | ||
1452 | while (size--) | ||
1453 | s <<= 1, s += *p++; | ||
1454 | W_UnlockLumpNum(i); | ||
1455 | } | ||
1456 | while (--i > lump); | ||
1457 | return s; | ||
1458 | } | ||
1459 | |||
1460 | static uint_64_t G_Signature(void) | ||
1461 | { | ||
1462 | static uint_64_t s = 0; | ||
1463 | static boolean computed = false; | ||
1464 | char name[9]; | ||
1465 | int episode, map; | ||
1466 | |||
1467 | if (!computed) { | ||
1468 | computed = true; | ||
1469 | if (gamemode == commercial) | ||
1470 | for (map = haswolflevels ? 32 : 30; map; map--) | ||
1471 | sprintf(name, "map%02d", map), s = G_UpdateSignature(s, name); | ||
1472 | else | ||
1473 | for (episode = gamemode==retail ? 4 : | ||
1474 | gamemode==shareware ? 1 : 3; episode; episode--) | ||
1475 | for (map = 9; map; map--) | ||
1476 | sprintf(name, "E%dM%d", episode, map), s = G_UpdateSignature(s, name); | ||
1477 | } | ||
1478 | return s; | ||
1479 | } | ||
1480 | |||
1481 | // | ||
1482 | // killough 5/15/98: add forced loadgames, which allow user to override checks | ||
1483 | // | ||
1484 | |||
1485 | void G_ForcedLoadGame(void) | ||
1486 | { | ||
1487 | // CPhipps - net loadgames are always forced, so we only reach here | ||
1488 | // in single player | ||
1489 | gameaction = ga_loadgame; | ||
1490 | forced_loadgame = true; | ||
1491 | } | ||
1492 | |||
1493 | // killough 3/16/98: add slot info | ||
1494 | // killough 5/15/98: add command-line | ||
1495 | void G_LoadGame(int slot, boolean command) | ||
1496 | { | ||
1497 | if (!demoplayback && !command) { | ||
1498 | // CPhipps - handle savegame filename in G_DoLoadGame | ||
1499 | // - Delay load so it can be communicated in net game | ||
1500 | // - store info in special_event | ||
1501 | special_event = BT_SPECIAL | (BTS_LOADGAME & BT_SPECIALMASK) | | ||
1502 | ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); | ||
1503 | forced_loadgame = netgame; // CPhipps - always force load netgames | ||
1504 | } else { | ||
1505 | // Do the old thing, immediate load | ||
1506 | gameaction = ga_loadgame; | ||
1507 | forced_loadgame = false; | ||
1508 | savegameslot = slot; | ||
1509 | demoplayback = false; | ||
1510 | // Don't stay in netgame state if loading single player save | ||
1511 | // while watching multiplayer demo | ||
1512 | netgame = false; | ||
1513 | } | ||
1514 | command_loadgame = command; | ||
1515 | R_SmoothPlaying_Reset(NULL); // e6y | ||
1516 | } | ||
1517 | |||
1518 | // killough 5/15/98: | ||
1519 | // Consistency Error when attempting to load savegame. | ||
1520 | |||
1521 | static void G_LoadGameErr(const char *msg) | ||
1522 | { | ||
1523 | Z_Free(savebuffer); // Free the savegame buffer | ||
1524 | M_ForcedLoadGame(msg); // Print message asking for 'Y' to force | ||
1525 | if (command_loadgame) // If this was a command-line -loadgame | ||
1526 | { | ||
1527 | D_StartTitle(); // Start the title screen | ||
1528 | gamestate = GS_DEMOSCREEN; // And set the game state accordingly | ||
1529 | } | ||
1530 | } | ||
1531 | |||
1532 | // CPhipps - size of version header | ||
1533 | #define VERSIONSIZE 16 | ||
1534 | |||
1535 | const char * comp_lev_str[MAX_COMPATIBILITY_LEVEL] = | ||
1536 | { "doom v1.2", "doom v1.666", "doom/doom2 v1.9", "ultimate doom", "final doom", | ||
1537 | "dosdoom compatibility", "tasdoom compatibility", "\"boom compatibility\"", "boom v2.01", "boom v2.02", "lxdoom v1.3.2+", | ||
1538 | "MBF", "PrBoom 2.03beta", "PrBoom v2.1.0-2.1.1", "PrBoom v2.1.2-v2.2.6", | ||
1539 | "PrBoom v2.3.x", "PrBoom 2.4.0", "Current PrBoom" }; | ||
1540 | |||
1541 | // comp_options_by_version removed - see G_Compatibility | ||
1542 | |||
1543 | static byte map_old_comp_levels[] = | ||
1544 | { 0, 1, 2, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; | ||
1545 | |||
1546 | static const struct { | ||
1547 | int comp_level; | ||
1548 | const char* ver_printf; | ||
1549 | int version; | ||
1550 | } version_headers[] = { | ||
1551 | /* cph - we don't need a new version_header for prboom_3_comp/v2.1.1, since | ||
1552 | * the file format is unchanged. */ | ||
1553 | { prboom_3_compatibility, "PrBoom %d", 210}, | ||
1554 | { prboom_5_compatibility, "PrBoom %d", 211}, | ||
1555 | { prboom_6_compatibility, "PrBoom %d", 212} | ||
1556 | }; | ||
1557 | |||
1558 | static const size_t num_version_headers = sizeof(version_headers) / sizeof(version_headers[0]); | ||
1559 | |||
1560 | void G_DoLoadGame(void) | ||
1561 | { | ||
1562 | int length, i; | ||
1563 | // CPhipps - do savegame filename stuff here | ||
1564 | char name[PATH_MAX+1]; // killough 3/22/98 | ||
1565 | int savegame_compatibility = -1; | ||
1566 | |||
1567 | G_SaveGameName(name,sizeof(name),savegameslot, demoplayback); | ||
1568 | |||
1569 | gameaction = ga_nothing; | ||
1570 | |||
1571 | length = M_ReadFile(name, &savebuffer); | ||
1572 | if (length<=0) | ||
1573 | I_Error("Couldn't read file %s: %s", name, "(Unknown Error)"); | ||
1574 | save_p = savebuffer + SAVESTRINGSIZE; | ||
1575 | |||
1576 | // CPhipps - read the description field, compare with supported ones | ||
1577 | for (i=0; (size_t)i<num_version_headers; i++) { | ||
1578 | char vcheck[VERSIONSIZE]; | ||
1579 | // killough 2/22/98: "proprietary" version string :-) | ||
1580 | sprintf (vcheck, version_headers[i].ver_printf, version_headers[i].version); | ||
1581 | |||
1582 | if (!strncmp(save_p, vcheck, VERSIONSIZE)) { | ||
1583 | savegame_compatibility = version_headers[i].comp_level; | ||
1584 | i = num_version_headers; | ||
1585 | } | ||
1586 | } | ||
1587 | if (savegame_compatibility == -1) { | ||
1588 | if (forced_loadgame) { | ||
1589 | savegame_compatibility = MAX_COMPATIBILITY_LEVEL-1; | ||
1590 | } else { | ||
1591 | G_LoadGameErr("Unrecognised savegame version!\nAre you sure? (y/n) "); | ||
1592 | return; | ||
1593 | } | ||
1594 | } | ||
1595 | |||
1596 | save_p += VERSIONSIZE; | ||
1597 | |||
1598 | // CPhipps - always check savegames even when forced, | ||
1599 | // only print a warning if forced | ||
1600 | { // killough 3/16/98: check lump name checksum (independent of order) | ||
1601 | uint_64_t checksum = 0; | ||
1602 | |||
1603 | checksum = G_Signature(); | ||
1604 | |||
1605 | if (memcmp(&checksum, save_p, sizeof checksum)) { | ||
1606 | if (!forced_loadgame) { | ||
1607 | char *msg = malloc(strlen(save_p + sizeof checksum) + 128); | ||
1608 | strcpy(msg,"Incompatible Savegame!!!\n"); | ||
1609 | if (save_p[sizeof checksum]) | ||
1610 | strcat(strcat(msg,"Wads expected:\n\n"), save_p + sizeof checksum); | ||
1611 | strcat(msg, "\nAre you sure?"); | ||
1612 | G_LoadGameErr(msg); | ||
1613 | free(msg); | ||
1614 | return; | ||
1615 | } else | ||
1616 | lprintf(LO_WARN, "G_DoLoadGame: Incompatible savegame\n"); | ||
1617 | } | ||
1618 | save_p += sizeof checksum; | ||
1619 | } | ||
1620 | |||
1621 | save_p += strlen(save_p)+1; | ||
1622 | |||
1623 | compatibility_level = (savegame_compatibility >= prboom_4_compatibility) ? *save_p : savegame_compatibility; | ||
1624 | if (savegame_compatibility < prboom_6_compatibility) | ||
1625 | compatibility_level = map_old_comp_levels[compatibility_level]; | ||
1626 | save_p++; | ||
1627 | |||
1628 | gameskill = *save_p++; | ||
1629 | gameepisode = *save_p++; | ||
1630 | gamemap = *save_p++; | ||
1631 | |||
1632 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
1633 | playeringame[i] = *save_p++; | ||
1634 | save_p += MIN_MAXPLAYERS-MAXPLAYERS; // killough 2/28/98 | ||
1635 | |||
1636 | idmusnum = *save_p++; // jff 3/17/98 restore idmus music | ||
1637 | if (idmusnum==255) idmusnum=-1; // jff 3/18/98 account for unsigned byte | ||
1638 | |||
1639 | /* killough 3/1/98: Read game options | ||
1640 | * killough 11/98: move down to here | ||
1641 | */ | ||
1642 | save_p = (char*)G_ReadOptions(save_p); | ||
1643 | |||
1644 | // load a base level | ||
1645 | G_InitNew (gameskill, gameepisode, gamemap); | ||
1646 | |||
1647 | /* get the times - killough 11/98: save entire word */ | ||
1648 | memcpy(&leveltime, save_p, sizeof leveltime); | ||
1649 | save_p += sizeof leveltime; | ||
1650 | |||
1651 | /* cph - total episode time */ | ||
1652 | if (compatibility_level >= prboom_2_compatibility) { | ||
1653 | memcpy(&totalleveltimes, save_p, sizeof totalleveltimes); | ||
1654 | save_p += sizeof totalleveltimes; | ||
1655 | } | ||
1656 | else totalleveltimes = 0; | ||
1657 | |||
1658 | // killough 11/98: load revenant tracer state | ||
1659 | basetic = gametic - *save_p++; | ||
1660 | |||
1661 | // dearchive all the modifications | ||
1662 | P_MapStart(); | ||
1663 | P_UnArchivePlayers (); | ||
1664 | P_UnArchiveWorld (); | ||
1665 | P_UnArchiveThinkers (); | ||
1666 | P_UnArchiveSpecials (); | ||
1667 | P_UnArchiveRNG (); // killough 1/18/98: load RNG information | ||
1668 | P_UnArchiveMap (); // killough 1/22/98: load automap information | ||
1669 | P_MapEnd(); | ||
1670 | R_SmoothPlaying_Reset(NULL); // e6y | ||
1671 | |||
1672 | if (*save_p != 0xe6) | ||
1673 | I_Error ("G_DoLoadGame: Bad savegame"); | ||
1674 | |||
1675 | // done | ||
1676 | Z_Free (savebuffer); | ||
1677 | |||
1678 | if (setsizeneeded) | ||
1679 | R_ExecuteSetViewSize (); | ||
1680 | |||
1681 | // draw the pattern into the back screen | ||
1682 | R_FillBackScreen (); | ||
1683 | |||
1684 | /* killough 12/98: support -recordfrom and -loadgame -playdemo */ | ||
1685 | if (!command_loadgame) | ||
1686 | singledemo = false; /* Clear singledemo flag if loading from menu */ | ||
1687 | else | ||
1688 | if (singledemo) { | ||
1689 | gameaction = ga_loadgame; /* Mark that we're loading a game before demo */ | ||
1690 | G_DoPlayDemo(); /* This will detect it and won't reinit level */ | ||
1691 | } else /* Command line + record means it's a recordfrom */ | ||
1692 | if (demorecording) | ||
1693 | G_BeginRecording(); | ||
1694 | } | ||
1695 | |||
1696 | // | ||
1697 | // G_SaveGame | ||
1698 | // Called by the menu task. | ||
1699 | // Description is a 24 byte text string | ||
1700 | // | ||
1701 | |||
1702 | void G_SaveGame(int slot, char *description) | ||
1703 | { | ||
1704 | strcpy(savedescription, description); | ||
1705 | if (demoplayback) { | ||
1706 | /* cph - We're doing a user-initiated save game while a demo is | ||
1707 | * running so, go outside normal mechanisms | ||
1708 | */ | ||
1709 | savegameslot = slot; | ||
1710 | G_DoSaveGame(true); | ||
1711 | } | ||
1712 | // CPhipps - store info in special_event | ||
1713 | special_event = BT_SPECIAL | (BTS_SAVEGAME & BT_SPECIALMASK) | | ||
1714 | ((slot << BTS_SAVESHIFT) & BTS_SAVEMASK); | ||
1715 | #ifdef HAVE_NET | ||
1716 | D_NetSendMisc(nm_savegamename, strlen(savedescription)+1, savedescription); | ||
1717 | #endif | ||
1718 | } | ||
1719 | |||
1720 | // Check for overrun and realloc if necessary -- Lee Killough 1/22/98 | ||
1721 | void (CheckSaveGame)(size_t size, const char* file, int line) | ||
1722 | { | ||
1723 | size_t pos = save_p - savebuffer; | ||
1724 | |||
1725 | #ifdef RANGECHECK | ||
1726 | /* cph 2006/08/07 - after-the-fact sanity checking of CheckSaveGame calls */ | ||
1727 | static size_t prev_check; | ||
1728 | static const char* prevf; | ||
1729 | static int prevl; | ||
1730 | |||
1731 | if (pos > prev_check) | ||
1732 | I_Error("CheckSaveGame at %s:%d called for insufficient buffer (%u < %u)", prevf, prevl, prev_check, pos); | ||
1733 | prev_check = size + pos; | ||
1734 | prevf = file; | ||
1735 | prevl = line; | ||
1736 | #endif | ||
1737 | |||
1738 | size += 1024; // breathing room | ||
1739 | if (pos+size > savegamesize) | ||
1740 | save_p = (savebuffer = realloc(savebuffer, | ||
1741 | savegamesize += (size+1023) & ~1023)) + pos; | ||
1742 | } | ||
1743 | |||
1744 | /* killough 3/22/98: form savegame name in one location | ||
1745 | * (previously code was scattered around in multiple places) | ||
1746 | * cph - Avoid possible buffer overflow problems by passing | ||
1747 | * size to this function and using snprintf */ | ||
1748 | |||
1749 | void G_SaveGameName(char *name, size_t size, int slot, boolean demoplayback) | ||
1750 | { | ||
1751 | const char* sgn = demoplayback ? "demosav" : savegamename; | ||
1752 | #ifdef HAVE_SNPRINTF | ||
1753 | snprintf (name, size, "%s/%s%d.dsg", basesavegame, sgn, slot); | ||
1754 | #else | ||
1755 | sprintf (name, "%s/%s%d.dsg", basesavegame, sgn, slot); | ||
1756 | #endif | ||
1757 | } | ||
1758 | |||
1759 | static void G_DoSaveGame (boolean menu) | ||
1760 | { | ||
1761 | char name[PATH_MAX+1]; | ||
1762 | char name2[VERSIONSIZE]; | ||
1763 | char *description; | ||
1764 | int length, i; | ||
1765 | |||
1766 | gameaction = ga_nothing; // cph - cancel savegame at top of this function, | ||
1767 | // in case later problems cause a premature exit | ||
1768 | |||
1769 | G_SaveGameName(name,sizeof(name),savegameslot, demoplayback && !menu); | ||
1770 | |||
1771 | description = savedescription; | ||
1772 | |||
1773 | save_p = savebuffer = malloc(savegamesize); | ||
1774 | |||
1775 | CheckSaveGame(SAVESTRINGSIZE+VERSIONSIZE+sizeof(uint_64_t)); | ||
1776 | memcpy (save_p, description, SAVESTRINGSIZE); | ||
1777 | save_p += SAVESTRINGSIZE; | ||
1778 | memset (name2,0,sizeof(name2)); | ||
1779 | |||
1780 | // CPhipps - scan for the version header | ||
1781 | for (i=0; (size_t)i<num_version_headers; i++) | ||
1782 | if (version_headers[i].comp_level == best_compatibility) { | ||
1783 | // killough 2/22/98: "proprietary" version string :-) | ||
1784 | sprintf (name2,version_headers[i].ver_printf,version_headers[i].version); | ||
1785 | memcpy (save_p, name2, VERSIONSIZE); | ||
1786 | i = num_version_headers+1; | ||
1787 | } | ||
1788 | |||
1789 | save_p += VERSIONSIZE; | ||
1790 | |||
1791 | { /* killough 3/16/98, 12/98: store lump name checksum */ | ||
1792 | uint_64_t checksum = G_Signature(); | ||
1793 | memcpy(save_p, &checksum, sizeof checksum); | ||
1794 | save_p += sizeof checksum; | ||
1795 | } | ||
1796 | |||
1797 | // killough 3/16/98: store pwad filenames in savegame | ||
1798 | { | ||
1799 | // CPhipps - changed for new wadfiles handling | ||
1800 | size_t i; | ||
1801 | for (i = 0; i<numwadfiles; i++) | ||
1802 | { | ||
1803 | const char *const w = wadfiles[i].name; | ||
1804 | CheckSaveGame(strlen(w)+2); | ||
1805 | strcpy(save_p, w); | ||
1806 | save_p += strlen(save_p); | ||
1807 | *save_p++ = '\n'; | ||
1808 | } | ||
1809 | *save_p++ = 0; | ||
1810 | } | ||
1811 | |||
1812 | CheckSaveGame(GAME_OPTION_SIZE+MIN_MAXPLAYERS+14); | ||
1813 | |||
1814 | *save_p++ = compatibility_level; | ||
1815 | |||
1816 | *save_p++ = gameskill; | ||
1817 | *save_p++ = gameepisode; | ||
1818 | *save_p++ = gamemap; | ||
1819 | |||
1820 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
1821 | *save_p++ = playeringame[i]; | ||
1822 | |||
1823 | for (;i<MIN_MAXPLAYERS;i++) // killough 2/28/98 | ||
1824 | *save_p++ = 0; | ||
1825 | |||
1826 | *save_p++ = idmusnum; // jff 3/17/98 save idmus state | ||
1827 | |||
1828 | save_p = G_WriteOptions(save_p); // killough 3/1/98: save game options | ||
1829 | |||
1830 | /* cph - FIXME - endianness? */ | ||
1831 | /* killough 11/98: save entire word */ | ||
1832 | memcpy(save_p, &leveltime, sizeof leveltime); | ||
1833 | save_p += sizeof leveltime; | ||
1834 | |||
1835 | /* cph - total episode time */ | ||
1836 | if (compatibility_level >= prboom_2_compatibility) { | ||
1837 | memcpy(save_p, &totalleveltimes, sizeof totalleveltimes); | ||
1838 | save_p += sizeof totalleveltimes; | ||
1839 | } | ||
1840 | else totalleveltimes = 0; | ||
1841 | |||
1842 | // killough 11/98: save revenant tracer state | ||
1843 | *save_p++ = (gametic-basetic) & 255; | ||
1844 | |||
1845 | // killough 3/22/98: add Z_CheckHeap after each call to ensure consistency | ||
1846 | Z_CheckHeap(); | ||
1847 | P_ArchivePlayers(); | ||
1848 | Z_CheckHeap(); | ||
1849 | |||
1850 | // phares 9/13/98: Move mobj_t->index out of P_ArchiveThinkers so the | ||
1851 | // indices can be used by P_ArchiveWorld when the sectors are saved. | ||
1852 | // This is so we can save the index of the mobj_t of the thinker that | ||
1853 | // caused a sound, referenced by sector_t->soundtarget. | ||
1854 | P_ThinkerToIndex(); | ||
1855 | |||
1856 | P_ArchiveWorld(); | ||
1857 | Z_CheckHeap(); | ||
1858 | P_ArchiveThinkers(); | ||
1859 | |||
1860 | // phares 9/13/98: Move index->mobj_t out of P_ArchiveThinkers, simply | ||
1861 | // for symmetry with the P_ThinkerToIndex call above. | ||
1862 | |||
1863 | P_IndexToThinker(); | ||
1864 | |||
1865 | Z_CheckHeap(); | ||
1866 | P_ArchiveSpecials(); | ||
1867 | P_ArchiveRNG(); // killough 1/18/98: save RNG information | ||
1868 | Z_CheckHeap(); | ||
1869 | P_ArchiveMap(); // killough 1/22/98: save automap information | ||
1870 | |||
1871 | *save_p++ = 0xe6; // consistancy marker | ||
1872 | |||
1873 | length = save_p - savebuffer; | ||
1874 | |||
1875 | Z_CheckHeap(); | ||
1876 | doom_printf( "%s", M_WriteFile(name, savebuffer, length) | ||
1877 | ? s_GGSAVED /* Ty - externalised */ | ||
1878 | : "Game save failed!"); // CPhipps - not externalised | ||
1879 | |||
1880 | free(savebuffer); // killough | ||
1881 | savebuffer = save_p = NULL; | ||
1882 | |||
1883 | savedescription[0] = 0; | ||
1884 | } | ||
1885 | |||
1886 | static skill_t d_skill; | ||
1887 | static int d_episode; | ||
1888 | static int d_map; | ||
1889 | |||
1890 | void G_DeferedInitNew(skill_t skill, int episode, int map) | ||
1891 | { | ||
1892 | d_skill = skill; | ||
1893 | d_episode = episode; | ||
1894 | d_map = map; | ||
1895 | gameaction = ga_newgame; | ||
1896 | } | ||
1897 | |||
1898 | /* cph - | ||
1899 | * G_Compatibility | ||
1900 | * | ||
1901 | * Initialises the comp[] array based on the compatibility_level | ||
1902 | * For reference, MBF did: | ||
1903 | * for (i=0; i < COMP_TOTAL; i++) | ||
1904 | * comp[i] = compatibility; | ||
1905 | * | ||
1906 | * Instead, we have a lookup table showing at what version a fix was | ||
1907 | * introduced, and made optional (replaces comp_options_by_version) | ||
1908 | */ | ||
1909 | |||
1910 | void G_Compatibility(void) | ||
1911 | { | ||
1912 | static const struct { | ||
1913 | complevel_t fix; // level at which fix/change was introduced | ||
1914 | complevel_t opt; // level at which fix/change was made optional | ||
1915 | } levels[] = { | ||
1916 | // comp_telefrag - monsters used to telefrag only on MAP30, now they do it for spawners only | ||
1917 | { mbf_compatibility, mbf_compatibility }, | ||
1918 | // comp_dropoff - MBF encourages things to drop off of overhangs | ||
1919 | { mbf_compatibility, mbf_compatibility }, | ||
1920 | // comp_vile - original Doom archville bugs like ghosts | ||
1921 | { boom_compatibility, mbf_compatibility }, | ||
1922 | // comp_pain - original Doom limits Pain Elementals from spawning too many skulls | ||
1923 | { boom_compatibility, mbf_compatibility }, | ||
1924 | // comp_skull - original Doom let skulls be spit through walls by Pain Elementals | ||
1925 | { boom_compatibility, mbf_compatibility }, | ||
1926 | // comp_blazing - original Doom duplicated blazing door sound | ||
1927 | { boom_compatibility, mbf_compatibility }, | ||
1928 | // e6y: "Tagged doors don't trigger special lighting" handled wrong | ||
1929 | // http://sourceforge.net/tracker/index.php?func=detail&aid=1411400&group_id=148658&atid=772943 | ||
1930 | // comp_doorlight - MBF made door lighting changes more gradual | ||
1931 | { boom_compatibility, mbf_compatibility }, | ||
1932 | // comp_model - improvements to the game physics | ||
1933 | { boom_compatibility, mbf_compatibility }, | ||
1934 | // comp_god - fixes to God mode | ||
1935 | { boom_compatibility, mbf_compatibility }, | ||
1936 | // comp_falloff - MBF encourages things to drop off of overhangs | ||
1937 | { mbf_compatibility, mbf_compatibility }, | ||
1938 | // comp_floors - fixes for moving floors bugs | ||
1939 | { boom_compatibility_compatibility, mbf_compatibility }, | ||
1940 | // comp_skymap | ||
1941 | { boom_compatibility, mbf_compatibility }, | ||
1942 | // comp_pursuit - MBF AI change, limited pursuit? | ||
1943 | { mbf_compatibility, mbf_compatibility }, | ||
1944 | // comp_doorstuck - monsters stuck in doors fix | ||
1945 | { boom_202_compatibility, mbf_compatibility }, | ||
1946 | // comp_staylift - MBF AI change, monsters try to stay on lifts | ||
1947 | { mbf_compatibility, mbf_compatibility }, | ||
1948 | // comp_zombie - prevent dead players triggering stuff | ||
1949 | { lxdoom_1_compatibility, mbf_compatibility }, | ||
1950 | // comp_stairs - see p_floor.c | ||
1951 | { boom_compatibility_compatibility, mbf_compatibility }, | ||
1952 | // comp_infcheat - FIXME | ||
1953 | { mbf_compatibility, mbf_compatibility }, | ||
1954 | // comp_zerotags - allow zero tags in wads */ | ||
1955 | { boom_compatibility, mbf_compatibility }, | ||
1956 | // comp_moveblock - enables keygrab and mancubi shots going thru walls | ||
1957 | { lxdoom_1_compatibility, prboom_2_compatibility }, | ||
1958 | // comp_respawn - objects which aren't on the map at game start respawn at (0,0) | ||
1959 | { prboom_2_compatibility, prboom_2_compatibility }, | ||
1960 | // comp_sound - see s_sound.c | ||
1961 | { boom_compatibility_compatibility, prboom_3_compatibility }, | ||
1962 | // comp_666 - enables tag 666 in non-ExM8 levels | ||
1963 | { ultdoom_compatibility, prboom_4_compatibility }, | ||
1964 | // comp_soul - enables lost souls bouncing (see P_ZMovement) | ||
1965 | { prboom_4_compatibility, prboom_4_compatibility }, | ||
1966 | // comp_maskedanim - 2s mid textures don't animate | ||
1967 | { doom_1666_compatibility, prboom_4_compatibility }, | ||
1968 | }; | ||
1969 | int i; | ||
1970 | |||
1971 | if (sizeof(levels)/sizeof(*levels) != COMP_NUM) | ||
1972 | I_Error("G_Compatibility: consistency error"); | ||
1973 | |||
1974 | for (i = 0; i < sizeof(levels)/sizeof(*levels); i++) | ||
1975 | if (compatibility_level < levels[i].opt) | ||
1976 | comp[i] = (compatibility_level < levels[i].fix); | ||
1977 | |||
1978 | if (!mbf_features) { | ||
1979 | monster_infighting = 1; | ||
1980 | monster_backing = 0; | ||
1981 | monster_avoid_hazards = 0; | ||
1982 | monster_friction = 0; | ||
1983 | help_friends = 0; | ||
1984 | |||
1985 | #ifdef DOGS | ||
1986 | dogs = 0; | ||
1987 | dog_jumping = 0; | ||
1988 | #endif | ||
1989 | |||
1990 | monkeys = 0; | ||
1991 | } | ||
1992 | } | ||
1993 | |||
1994 | #ifdef DOGS | ||
1995 | /* killough 7/19/98: Marine's best friend :) */ | ||
1996 | static int G_GetHelpers(void) | ||
1997 | { | ||
1998 | int j = M_CheckParm ("-dog"); | ||
1999 | |||
2000 | if (!j) | ||
2001 | j = M_CheckParm ("-dogs"); | ||
2002 | return j ? j+1 < myargc ? atoi(myargv[j+1]) : 1 : default_dogs; | ||
2003 | } | ||
2004 | #endif | ||
2005 | |||
2006 | // killough 3/1/98: function to reload all the default parameter | ||
2007 | // settings before a new game begins | ||
2008 | |||
2009 | void G_ReloadDefaults(void) | ||
2010 | { | ||
2011 | // killough 3/1/98: Initialize options based on config file | ||
2012 | // (allows functions above to load different values for demos | ||
2013 | // and savegames without messing up defaults). | ||
2014 | |||
2015 | weapon_recoil = default_weapon_recoil; // weapon recoil | ||
2016 | |||
2017 | player_bobbing = default_player_bobbing; // whether player bobs or not | ||
2018 | |||
2019 | /* cph 2007/06/31 - for some reason, the default_* of the next 2 vars was never implemented */ | ||
2020 | variable_friction = default_variable_friction; | ||
2021 | allow_pushers = default_allow_pushers; | ||
2022 | |||
2023 | |||
2024 | monsters_remember = default_monsters_remember; // remember former enemies | ||
2025 | |||
2026 | monster_infighting = default_monster_infighting; // killough 7/19/98 | ||
2027 | |||
2028 | #ifdef DOGS | ||
2029 | dogs = netgame ? 0 : G_GetHelpers(); // killough 7/19/98 | ||
2030 | dog_jumping = default_dog_jumping; | ||
2031 | #endif | ||
2032 | |||
2033 | distfriend = default_distfriend; // killough 8/8/98 | ||
2034 | |||
2035 | monster_backing = default_monster_backing; // killough 9/8/98 | ||
2036 | |||
2037 | monster_avoid_hazards = default_monster_avoid_hazards; // killough 9/9/98 | ||
2038 | |||
2039 | monster_friction = default_monster_friction; // killough 10/98 | ||
2040 | |||
2041 | help_friends = default_help_friends; // killough 9/9/98 | ||
2042 | |||
2043 | monkeys = default_monkeys; | ||
2044 | |||
2045 | // jff 1/24/98 reset play mode to command line spec'd version | ||
2046 | // killough 3/1/98: moved to here | ||
2047 | respawnparm = clrespawnparm; | ||
2048 | fastparm = clfastparm; | ||
2049 | nomonsters = clnomonsters; | ||
2050 | |||
2051 | //jff 3/24/98 set startskill from defaultskill in config file, unless | ||
2052 | // it has already been set by a -skill parameter | ||
2053 | if (startskill==sk_none) | ||
2054 | startskill = (skill_t)(defaultskill-1); | ||
2055 | |||
2056 | demoplayback = false; | ||
2057 | singledemo = false; // killough 9/29/98: don't stop after 1 demo | ||
2058 | netdemo = false; | ||
2059 | |||
2060 | // killough 2/21/98: | ||
2061 | memset(playeringame+1, 0, sizeof(*playeringame)*(MAXPLAYERS-1)); | ||
2062 | |||
2063 | consoleplayer = 0; | ||
2064 | |||
2065 | compatibility_level = default_compatibility_level; | ||
2066 | { | ||
2067 | int i = M_CheckParm("-complevel"); | ||
2068 | if (i && (1+i) < myargc) { | ||
2069 | int l = atoi(myargv[i+1]);; | ||
2070 | if (l >= -1) compatibility_level = l; | ||
2071 | } | ||
2072 | } | ||
2073 | if (compatibility_level == -1) | ||
2074 | compatibility_level = best_compatibility; | ||
2075 | |||
2076 | if (mbf_features) | ||
2077 | memcpy(comp, default_comp, sizeof comp); | ||
2078 | G_Compatibility(); | ||
2079 | |||
2080 | // killough 3/31/98, 4/5/98: demo sync insurance | ||
2081 | demo_insurance = default_demo_insurance == 1; | ||
2082 | |||
2083 | rngseed += I_GetRandomTimeSeed() + gametic; // CPhipps | ||
2084 | } | ||
2085 | |||
2086 | void G_DoNewGame (void) | ||
2087 | { | ||
2088 | G_ReloadDefaults(); // killough 3/1/98 | ||
2089 | netgame = false; // killough 3/29/98 | ||
2090 | deathmatch = false; | ||
2091 | G_InitNew (d_skill, d_episode, d_map); | ||
2092 | gameaction = ga_nothing; | ||
2093 | |||
2094 | //jff 4/26/98 wake up the status bar in case were coming out of a DM demo | ||
2095 | ST_Start(); | ||
2096 | } | ||
2097 | |||
2098 | // killough 4/10/98: New function to fix bug which caused Doom | ||
2099 | // lockups when idclev was used in conjunction with -fast. | ||
2100 | |||
2101 | void G_SetFastParms(int fast_pending) | ||
2102 | { | ||
2103 | static int fast = 0; // remembers fast state | ||
2104 | int i; | ||
2105 | if (fast != fast_pending) { /* only change if necessary */ | ||
2106 | if ((fast = fast_pending)) | ||
2107 | { | ||
2108 | for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) | ||
2109 | if (states[i].tics != 1 || demo_compatibility) // killough 4/10/98 | ||
2110 | states[i].tics >>= 1; // don't change 1->0 since it causes cycles | ||
2111 | mobjinfo[MT_BRUISERSHOT].speed = 20*FRACUNIT; | ||
2112 | mobjinfo[MT_HEADSHOT].speed = 20*FRACUNIT; | ||
2113 | mobjinfo[MT_TROOPSHOT].speed = 20*FRACUNIT; | ||
2114 | } | ||
2115 | else | ||
2116 | { | ||
2117 | for (i=S_SARG_RUN1; i<=S_SARG_PAIN2; i++) | ||
2118 | states[i].tics <<= 1; | ||
2119 | mobjinfo[MT_BRUISERSHOT].speed = 15*FRACUNIT; | ||
2120 | mobjinfo[MT_HEADSHOT].speed = 10*FRACUNIT; | ||
2121 | mobjinfo[MT_TROOPSHOT].speed = 10*FRACUNIT; | ||
2122 | } | ||
2123 | } | ||
2124 | } | ||
2125 | |||
2126 | // | ||
2127 | // G_InitNew | ||
2128 | // Can be called by the startup code or the menu task, | ||
2129 | // consoleplayer, displayplayer, playeringame[] should be set. | ||
2130 | // | ||
2131 | |||
2132 | void G_InitNew(skill_t skill, int episode, int map) | ||
2133 | { | ||
2134 | int i; | ||
2135 | |||
2136 | if (paused) | ||
2137 | { | ||
2138 | paused = false; | ||
2139 | S_ResumeSound(); | ||
2140 | } | ||
2141 | |||
2142 | if (skill > sk_nightmare) | ||
2143 | skill = sk_nightmare; | ||
2144 | |||
2145 | if (episode < 1) | ||
2146 | episode = 1; | ||
2147 | |||
2148 | if (gamemode == retail) | ||
2149 | { | ||
2150 | if (episode > 4) | ||
2151 | episode = 4; | ||
2152 | } | ||
2153 | else | ||
2154 | if (gamemode == shareware) | ||
2155 | { | ||
2156 | if (episode > 1) | ||
2157 | episode = 1; // only start episode 1 on shareware | ||
2158 | } | ||
2159 | else | ||
2160 | if (episode > 3) | ||
2161 | episode = 3; | ||
2162 | |||
2163 | if (map < 1) | ||
2164 | map = 1; | ||
2165 | if (map > 9 && gamemode != commercial) | ||
2166 | map = 9; | ||
2167 | |||
2168 | G_SetFastParms(fastparm || skill == sk_nightmare); // killough 4/10/98 | ||
2169 | |||
2170 | M_ClearRandom(); | ||
2171 | |||
2172 | respawnmonsters = skill == sk_nightmare || respawnparm; | ||
2173 | |||
2174 | // force players to be initialized upon first level load | ||
2175 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
2176 | players[i].playerstate = PST_REBORN; | ||
2177 | |||
2178 | usergame = true; // will be set false if a demo | ||
2179 | paused = false; | ||
2180 | automapmode &= ~am_active; | ||
2181 | gameepisode = episode; | ||
2182 | gamemap = map; | ||
2183 | gameskill = skill; | ||
2184 | |||
2185 | totalleveltimes = 0; // cph | ||
2186 | |||
2187 | //jff 4/16/98 force marks on automap cleared every new level start | ||
2188 | AM_clearMarks(); | ||
2189 | |||
2190 | G_DoLoadLevel (); | ||
2191 | } | ||
2192 | |||
2193 | // | ||
2194 | // DEMO RECORDING | ||
2195 | // | ||
2196 | |||
2197 | #define DEMOMARKER 0x80 | ||
2198 | |||
2199 | void G_ReadDemoTiccmd (ticcmd_t* cmd) | ||
2200 | { | ||
2201 | unsigned char at; // e6y: tasdoom stuff | ||
2202 | |||
2203 | if (*demo_p == DEMOMARKER) | ||
2204 | G_CheckDemoStatus(); // end of demo data stream | ||
2205 | else if (demoplayback && demo_p + (longtics?5:4) > demobuffer + demolength) | ||
2206 | { | ||
2207 | lprintf(LO_WARN, "G_ReadDemoTiccmd: missing DEMOMARKER\n"); | ||
2208 | G_CheckDemoStatus(); | ||
2209 | } | ||
2210 | else | ||
2211 | { | ||
2212 | cmd->forwardmove = ((signed char)*demo_p++); | ||
2213 | cmd->sidemove = ((signed char)*demo_p++); | ||
2214 | if (!longtics) { | ||
2215 | cmd->angleturn = ((unsigned char)(at = *demo_p++))<<8; | ||
2216 | } else { | ||
2217 | unsigned int lowbyte = (unsigned char)*demo_p++; | ||
2218 | cmd->angleturn = (((signed int)(*demo_p++))<<8) + lowbyte; | ||
2219 | } | ||
2220 | cmd->buttons = (unsigned char)*demo_p++; | ||
2221 | // e6y: ability to play tasdoom demos directly | ||
2222 | if (compatibility_level == tasdoom_compatibility) | ||
2223 | { | ||
2224 | signed char k = cmd->forwardmove; | ||
2225 | cmd->forwardmove = cmd->sidemove; | ||
2226 | cmd->sidemove = (signed char)at; | ||
2227 | cmd->angleturn = ((unsigned char)cmd->buttons)<<8; | ||
2228 | cmd->buttons = (byte)k; | ||
2229 | } | ||
2230 | } | ||
2231 | } | ||
2232 | |||
2233 | /* Demo limits removed -- killough | ||
2234 | * cph - record straight to file | ||
2235 | */ | ||
2236 | void G_WriteDemoTiccmd (ticcmd_t* cmd) | ||
2237 | { | ||
2238 | char buf[5]; | ||
2239 | char *p = buf; | ||
2240 | |||
2241 | *p++ = cmd->forwardmove; | ||
2242 | *p++ = cmd->sidemove; | ||
2243 | if (!longtics) { | ||
2244 | *p++ = (cmd->angleturn+128)>>8; | ||
2245 | } else { | ||
2246 | signed short a = cmd->angleturn; | ||
2247 | *p++ = a & 0xff; | ||
2248 | *p++ = (a >> 8) & 0xff; | ||
2249 | } | ||
2250 | *p++ = cmd->buttons; | ||
2251 | if (fwrite(buf, p-buf, 1, demofp) != 1) | ||
2252 | I_Error("G_WriteDemoTiccmd: error writing demo"); | ||
2253 | |||
2254 | /* cph - alias demo_p to it so we can read it back */ | ||
2255 | demo_p = buf; | ||
2256 | G_ReadDemoTiccmd (cmd); // make SURE it is exactly the same | ||
2257 | } | ||
2258 | |||
2259 | // | ||
2260 | // G_RecordDemo | ||
2261 | // | ||
2262 | |||
2263 | void G_RecordDemo (const char* name) | ||
2264 | { | ||
2265 | char demoname[PATH_MAX]; | ||
2266 | usergame = false; | ||
2267 | AddDefaultExtension(strcpy(demoname, name), ".lmp"); // 1/18/98 killough | ||
2268 | demorecording = true; | ||
2269 | /* cph - Record demos straight to file | ||
2270 | * If file already exists, try to continue existing demo | ||
2271 | */ | ||
2272 | if (access(demoname, F_OK)) { | ||
2273 | demofp = fopen(demoname, "wb"); | ||
2274 | } else { | ||
2275 | demofp = fopen(demoname, "r+"); | ||
2276 | if (demofp) { | ||
2277 | int slot = -1; | ||
2278 | int rc; | ||
2279 | int bytes_per_tic; | ||
2280 | const byte* pos; | ||
2281 | |||
2282 | { /* Read the demo header for options etc */ | ||
2283 | byte buf[200]; | ||
2284 | size_t len = fread(buf, 1, sizeof(buf), demofp); | ||
2285 | pos = G_ReadDemoHeader(buf, len, false); | ||
2286 | if (pos) | ||
2287 | { | ||
2288 | fseek(demofp, pos - buf, SEEK_SET); | ||
2289 | } | ||
2290 | } | ||
2291 | bytes_per_tic = longtics ? 5 : 4; | ||
2292 | if (pos) | ||
2293 | /* Now read the demo to find the last save slot */ | ||
2294 | do { | ||
2295 | byte buf[5]; | ||
2296 | |||
2297 | rc = fread(buf, 1, bytes_per_tic, demofp); | ||
2298 | if (buf[0] == DEMOMARKER) break; | ||
2299 | if (buf[bytes_per_tic-1] & BT_SPECIAL) | ||
2300 | if ((buf[bytes_per_tic-1] & BT_SPECIALMASK) == BTS_SAVEGAME) | ||
2301 | slot = (buf[bytes_per_tic-1] & BTS_SAVEMASK)>>BTS_SAVESHIFT; | ||
2302 | } while (rc == bytes_per_tic); | ||
2303 | |||
2304 | if (slot == -1) I_Error("G_RecordDemo: No save in demo, can't continue"); | ||
2305 | |||
2306 | /* Return to the last save position, and load the relevant savegame */ | ||
2307 | fseek(demofp, -rc, SEEK_CUR); | ||
2308 | G_LoadGame(slot, false); | ||
2309 | autostart = false; | ||
2310 | } | ||
2311 | } | ||
2312 | if (!demofp) I_Error("G_RecordDemo: failed to open %s", name); | ||
2313 | } | ||
2314 | |||
2315 | // These functions are used to read and write game-specific options in demos | ||
2316 | // and savegames so that demo sync is preserved and savegame restoration is | ||
2317 | // complete. Not all options (for example "compatibility"), however, should | ||
2318 | // be loaded and saved here. It is extremely important to use the same | ||
2319 | // positions as before for the variables, so if one becomes obsolete, the | ||
2320 | // byte(s) should still be skipped over or padded with 0's. | ||
2321 | // Lee Killough 3/1/98 | ||
2322 | |||
2323 | extern int forceOldBsp; | ||
2324 | |||
2325 | byte *G_WriteOptions(byte *demo_p) | ||
2326 | { | ||
2327 | byte *target = demo_p + GAME_OPTION_SIZE; | ||
2328 | |||
2329 | *demo_p++ = monsters_remember; // part of monster AI | ||
2330 | |||
2331 | *demo_p++ = variable_friction; // ice & mud | ||
2332 | |||
2333 | *demo_p++ = weapon_recoil; // weapon recoil | ||
2334 | |||
2335 | *demo_p++ = allow_pushers; // MT_PUSH Things | ||
2336 | |||
2337 | *demo_p++ = 0; | ||
2338 | |||
2339 | *demo_p++ = player_bobbing; // whether player bobs or not | ||
2340 | |||
2341 | // killough 3/6/98: add parameters to savegame, move around some in demos | ||
2342 | *demo_p++ = respawnparm; | ||
2343 | *demo_p++ = fastparm; | ||
2344 | *demo_p++ = nomonsters; | ||
2345 | |||
2346 | *demo_p++ = demo_insurance; // killough 3/31/98 | ||
2347 | |||
2348 | // killough 3/26/98: Added rngseed. 3/31/98: moved here | ||
2349 | *demo_p++ = (byte)((rngseed >> 24) & 0xff); | ||
2350 | *demo_p++ = (byte)((rngseed >> 16) & 0xff); | ||
2351 | *demo_p++ = (byte)((rngseed >> 8) & 0xff); | ||
2352 | *demo_p++ = (byte)( rngseed & 0xff); | ||
2353 | |||
2354 | // Options new to v2.03 begin here | ||
2355 | |||
2356 | *demo_p++ = monster_infighting; // killough 7/19/98 | ||
2357 | |||
2358 | #ifdef DOGS | ||
2359 | *demo_p++ = dogs; // killough 7/19/98 | ||
2360 | #else | ||
2361 | *demo_p++ = 0; | ||
2362 | #endif | ||
2363 | |||
2364 | *demo_p++ = 0; | ||
2365 | *demo_p++ = 0; | ||
2366 | |||
2367 | *demo_p++ = (distfriend >> 8) & 0xff; // killough 8/8/98 | ||
2368 | *demo_p++ = distfriend & 0xff; // killough 8/8/98 | ||
2369 | |||
2370 | *demo_p++ = monster_backing; // killough 9/8/98 | ||
2371 | |||
2372 | *demo_p++ = monster_avoid_hazards; // killough 9/9/98 | ||
2373 | |||
2374 | *demo_p++ = monster_friction; // killough 10/98 | ||
2375 | |||
2376 | *demo_p++ = help_friends; // killough 9/9/98 | ||
2377 | |||
2378 | #ifdef DOGS | ||
2379 | *demo_p++ = dog_jumping; | ||
2380 | #else | ||
2381 | *demo_p++ = 0; | ||
2382 | #endif | ||
2383 | |||
2384 | *demo_p++ = monkeys; | ||
2385 | |||
2386 | { // killough 10/98: a compatibility vector now | ||
2387 | int i; | ||
2388 | for (i=0; i < COMP_TOTAL; i++) | ||
2389 | *demo_p++ = comp[i] != 0; | ||
2390 | } | ||
2391 | |||
2392 | *demo_p++ = (compatibility_level >= prboom_2_compatibility) && forceOldBsp; // cph 2002/07/20 | ||
2393 | |||
2394 | //---------------- | ||
2395 | // Padding at end | ||
2396 | //---------------- | ||
2397 | while (demo_p < target) | ||
2398 | *demo_p++ = 0; | ||
2399 | |||
2400 | if (demo_p != target) | ||
2401 | I_Error("G_WriteOptions: GAME_OPTION_SIZE is too small"); | ||
2402 | |||
2403 | return target; | ||
2404 | } | ||
2405 | |||
2406 | /* Same, but read instead of write | ||
2407 | * cph - const byte*'s | ||
2408 | */ | ||
2409 | |||
2410 | const byte *G_ReadOptions(const byte *demo_p) | ||
2411 | { | ||
2412 | const byte *target = demo_p + GAME_OPTION_SIZE; | ||
2413 | |||
2414 | monsters_remember = *demo_p++; | ||
2415 | |||
2416 | variable_friction = *demo_p; // ice & mud | ||
2417 | demo_p++; | ||
2418 | |||
2419 | weapon_recoil = *demo_p; // weapon recoil | ||
2420 | demo_p++; | ||
2421 | |||
2422 | allow_pushers = *demo_p; // MT_PUSH Things | ||
2423 | demo_p++; | ||
2424 | |||
2425 | demo_p++; | ||
2426 | |||
2427 | player_bobbing = *demo_p; // whether player bobs or not | ||
2428 | demo_p++; | ||
2429 | |||
2430 | // killough 3/6/98: add parameters to savegame, move from demo | ||
2431 | respawnparm = *demo_p++; | ||
2432 | fastparm = *demo_p++; | ||
2433 | nomonsters = *demo_p++; | ||
2434 | |||
2435 | demo_insurance = *demo_p++; // killough 3/31/98 | ||
2436 | |||
2437 | // killough 3/26/98: Added rngseed to demos; 3/31/98: moved here | ||
2438 | |||
2439 | rngseed = *demo_p++ & 0xff; | ||
2440 | rngseed <<= 8; | ||
2441 | rngseed += *demo_p++ & 0xff; | ||
2442 | rngseed <<= 8; | ||
2443 | rngseed += *demo_p++ & 0xff; | ||
2444 | rngseed <<= 8; | ||
2445 | rngseed += *demo_p++ & 0xff; | ||
2446 | |||
2447 | // Options new to v2.03 | ||
2448 | if (mbf_features) | ||
2449 | { | ||
2450 | monster_infighting = *demo_p++; // killough 7/19/98 | ||
2451 | |||
2452 | #ifdef DOGS | ||
2453 | dogs = *demo_p++; // killough 7/19/98 | ||
2454 | #else | ||
2455 | demo_p++; | ||
2456 | #endif | ||
2457 | |||
2458 | demo_p += 2; | ||
2459 | |||
2460 | distfriend = *demo_p++ << 8; // killough 8/8/98 | ||
2461 | distfriend+= *demo_p++; | ||
2462 | |||
2463 | monster_backing = *demo_p++; // killough 9/8/98 | ||
2464 | |||
2465 | monster_avoid_hazards = *demo_p++; // killough 9/9/98 | ||
2466 | |||
2467 | monster_friction = *demo_p++; // killough 10/98 | ||
2468 | |||
2469 | help_friends = *demo_p++; // killough 9/9/98 | ||
2470 | |||
2471 | #ifdef DOGS | ||
2472 | dog_jumping = *demo_p++; // killough 10/98 | ||
2473 | #else | ||
2474 | demo_p++; | ||
2475 | #endif | ||
2476 | |||
2477 | monkeys = *demo_p++; | ||
2478 | |||
2479 | { // killough 10/98: a compatibility vector now | ||
2480 | int i; | ||
2481 | for (i=0; i < COMP_TOTAL; i++) | ||
2482 | comp[i] = *demo_p++; | ||
2483 | } | ||
2484 | |||
2485 | forceOldBsp = *demo_p++; // cph 2002/07/20 | ||
2486 | } | ||
2487 | else /* defaults for versions <= 2.02 */ | ||
2488 | { | ||
2489 | /* G_Compatibility will set these */ | ||
2490 | } | ||
2491 | |||
2492 | G_Compatibility(); | ||
2493 | return target; | ||
2494 | } | ||
2495 | |||
2496 | void G_BeginRecording (void) | ||
2497 | { | ||
2498 | int i; | ||
2499 | byte *demostart, *demo_p; | ||
2500 | demostart = demo_p = malloc(1000); | ||
2501 | longtics = 0; | ||
2502 | |||
2503 | /* cph - 3 demo record formats supported: MBF+, BOOM, and Doom v1.9 */ | ||
2504 | if (mbf_features) { | ||
2505 | { /* Write version code into demo */ | ||
2506 | unsigned char v; | ||
2507 | switch(compatibility_level) { | ||
2508 | case mbf_compatibility: v = 203; break; // e6y: Bug in MBF compatibility mode fixed | ||
2509 | case prboom_2_compatibility: v = 210; break; | ||
2510 | case prboom_3_compatibility: v = 211; break; | ||
2511 | case prboom_4_compatibility: v = 212; break; | ||
2512 | case prboom_5_compatibility: v = 213; break; | ||
2513 | case prboom_6_compatibility: | ||
2514 | v = 214; | ||
2515 | longtics = 1; | ||
2516 | break; | ||
2517 | } | ||
2518 | *demo_p++ = v; | ||
2519 | } | ||
2520 | |||
2521 | // signature | ||
2522 | *demo_p++ = 0x1d; | ||
2523 | *demo_p++ = 'M'; | ||
2524 | *demo_p++ = 'B'; | ||
2525 | *demo_p++ = 'F'; | ||
2526 | *demo_p++ = 0xe6; | ||
2527 | *demo_p++ = '\0'; | ||
2528 | |||
2529 | /* killough 2/22/98: save compatibility flag in new demos | ||
2530 | * cph - FIXME? MBF demos will always be not in compat. mode */ | ||
2531 | *demo_p++ = 0; | ||
2532 | |||
2533 | *demo_p++ = gameskill; | ||
2534 | *demo_p++ = gameepisode; | ||
2535 | *demo_p++ = gamemap; | ||
2536 | *demo_p++ = deathmatch; | ||
2537 | *demo_p++ = consoleplayer; | ||
2538 | |||
2539 | demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options | ||
2540 | |||
2541 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
2542 | *demo_p++ = playeringame[i]; | ||
2543 | |||
2544 | // killough 2/28/98: | ||
2545 | // We always store at least MIN_MAXPLAYERS bytes in demo, to | ||
2546 | // support enhancements later w/o losing demo compatibility | ||
2547 | |||
2548 | for (; i<MIN_MAXPLAYERS; i++) | ||
2549 | *demo_p++ = 0; | ||
2550 | |||
2551 | } else if (compatibility_level > boom_compatibility_compatibility) { | ||
2552 | byte v, c; /* Nominally, version and compatibility bits */ | ||
2553 | switch (compatibility_level) { | ||
2554 | case boom_compatibility_compatibility: v = 202, c = 1; break; | ||
2555 | case boom_201_compatibility: v = 201; c = 0; break; | ||
2556 | case boom_202_compatibility: v = 202, c = 0; break; | ||
2557 | default: I_Error("G_BeginRecording: Boom compatibility level unrecognised?"); | ||
2558 | } | ||
2559 | *demo_p++ = v; | ||
2560 | |||
2561 | // signature | ||
2562 | *demo_p++ = 0x1d; | ||
2563 | *demo_p++ = 'B'; | ||
2564 | *demo_p++ = 'o'; | ||
2565 | *demo_p++ = 'o'; | ||
2566 | *demo_p++ = 'm'; | ||
2567 | *demo_p++ = 0xe6; | ||
2568 | |||
2569 | /* CPhipps - save compatibility level in demos */ | ||
2570 | *demo_p++ = c; | ||
2571 | |||
2572 | *demo_p++ = gameskill; | ||
2573 | *demo_p++ = gameepisode; | ||
2574 | *demo_p++ = gamemap; | ||
2575 | *demo_p++ = deathmatch; | ||
2576 | *demo_p++ = consoleplayer; | ||
2577 | |||
2578 | demo_p = G_WriteOptions(demo_p); // killough 3/1/98: Save game options | ||
2579 | |||
2580 | for (i=0 ; i<MAXPLAYERS ; i++) | ||
2581 | *demo_p++ = playeringame[i]; | ||
2582 | |||
2583 | // killough 2/28/98: | ||
2584 | // We always store at least MIN_MAXPLAYERS bytes in demo, to | ||
2585 | // support enhancements later w/o losing demo compatibility | ||
2586 | |||
2587 | for (; i<MIN_MAXPLAYERS; i++) | ||
2588 | *demo_p++ = 0; | ||
2589 | } else { // cph - write old v1.9 demos (might even sync) | ||
2590 | longtics = M_CheckParm("-longtics"); | ||
2591 | *demo_p++ = longtics ? 111 : 109; // v1.9 has best chance of syncing these | ||
2592 | *demo_p++ = gameskill; | ||
2593 | *demo_p++ = gameepisode; | ||
2594 | *demo_p++ = gamemap; | ||
2595 | *demo_p++ = deathmatch; | ||
2596 | *demo_p++ = respawnparm; | ||
2597 | *demo_p++ = fastparm; | ||
2598 | *demo_p++ = nomonsters; | ||
2599 | *demo_p++ = consoleplayer; | ||
2600 | for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough | ||
2601 | *demo_p++ = playeringame[i]; | ||
2602 | } | ||
2603 | |||
2604 | if (fwrite(demostart, 1, demo_p-demostart, demofp) != (size_t)(demo_p-demostart)) | ||
2605 | I_Error("G_BeginRecording: Error writing demo header"); | ||
2606 | free(demostart); | ||
2607 | } | ||
2608 | |||
2609 | // | ||
2610 | // G_PlayDemo | ||
2611 | // | ||
2612 | |||
2613 | static const char *defdemoname; | ||
2614 | |||
2615 | void G_DeferedPlayDemo (const char* name) | ||
2616 | { | ||
2617 | defdemoname = name; | ||
2618 | gameaction = ga_playdemo; | ||
2619 | } | ||
2620 | |||
2621 | static int demolumpnum = -1; | ||
2622 | |||
2623 | static int G_GetOriginalDoomCompatLevel(int ver) | ||
2624 | { | ||
2625 | { | ||
2626 | int lev; | ||
2627 | int i = M_CheckParm("-complevel"); | ||
2628 | if (i && (i+1 < myargc)) | ||
2629 | { | ||
2630 | lev = atoi(myargv[i+1]); | ||
2631 | if (lev>=0) | ||
2632 | return lev; | ||
2633 | } | ||
2634 | } | ||
2635 | if (ver < 107) return doom_1666_compatibility; | ||
2636 | if (gamemode == retail) return ultdoom_compatibility; | ||
2637 | if (gamemission >= pack_tnt) return finaldoom_compatibility; | ||
2638 | return doom2_19_compatibility; | ||
2639 | } | ||
2640 | |||
2641 | //e6y: Check for overrun | ||
2642 | static boolean CheckForOverrun(const byte *start_p, const byte *current_p, size_t maxsize, size_t size, boolean failonerror) | ||
2643 | { | ||
2644 | size_t pos = current_p - start_p; | ||
2645 | if (pos + size > maxsize) | ||
2646 | { | ||
2647 | if (failonerror) | ||
2648 | I_Error("G_ReadDemoHeader: wrong demo header\n"); | ||
2649 | else | ||
2650 | return true; | ||
2651 | } | ||
2652 | return false; | ||
2653 | } | ||
2654 | |||
2655 | static const byte* G_ReadDemoHeader(const byte *demo_p, size_t size, boolean failonerror) | ||
2656 | { | ||
2657 | skill_t skill; | ||
2658 | int i, episode, map; | ||
2659 | |||
2660 | // e6y | ||
2661 | // The local variable should be used instead of demobuffer, | ||
2662 | // because demobuffer can be uninitialized | ||
2663 | const byte *header_p = demo_p; | ||
2664 | |||
2665 | const byte *option_p = NULL; /* killough 11/98 */ | ||
2666 | |||
2667 | basetic = gametic; // killough 9/29/98 | ||
2668 | |||
2669 | // killough 2/22/98, 2/28/98: autodetect old demos and act accordingly. | ||
2670 | // Old demos turn on demo_compatibility => compatibility; new demos load | ||
2671 | // compatibility flag, and other flags as well, as a part of the demo. | ||
2672 | |||
2673 | //e6y: check for overrun | ||
2674 | if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) | ||
2675 | return NULL; | ||
2676 | |||
2677 | demover = *demo_p++; | ||
2678 | longtics = 0; | ||
2679 | |||
2680 | // e6y | ||
2681 | // Handling of unrecognized demo formats | ||
2682 | // Versions up to 1.2 use a 7-byte header - first byte is a skill level. | ||
2683 | // Versions after 1.2 use a 13-byte header - first byte is a demoversion. | ||
2684 | // BOOM's demoversion starts from 200 | ||
2685 | if (!((demover >= 0 && demover <= 4) || | ||
2686 | (demover >= 104 && demover <= 111) || | ||
2687 | (demover >= 200 && demover <= 214))) | ||
2688 | { | ||
2689 | I_Error("G_ReadDemoHeader: Unknown demo format %d.", demover); | ||
2690 | } | ||
2691 | |||
2692 | if (demover < 200) // Autodetect old demos | ||
2693 | { | ||
2694 | if (demover >= 111) longtics = 1; | ||
2695 | |||
2696 | // killough 3/2/98: force these variables to be 0 in demo_compatibility | ||
2697 | |||
2698 | variable_friction = 0; | ||
2699 | |||
2700 | weapon_recoil = 0; | ||
2701 | |||
2702 | allow_pushers = 0; | ||
2703 | |||
2704 | monster_infighting = 1; // killough 7/19/98 | ||
2705 | |||
2706 | #ifdef DOGS | ||
2707 | dogs = 0; // killough 7/19/98 | ||
2708 | dog_jumping = 0; // killough 10/98 | ||
2709 | #endif | ||
2710 | |||
2711 | monster_backing = 0; // killough 9/8/98 | ||
2712 | |||
2713 | monster_avoid_hazards = 0; // killough 9/9/98 | ||
2714 | |||
2715 | monster_friction = 0; // killough 10/98 | ||
2716 | help_friends = 0; // killough 9/9/98 | ||
2717 | monkeys = 0; | ||
2718 | |||
2719 | // killough 3/6/98: rearrange to fix savegame bugs (moved fastparm, | ||
2720 | // respawnparm, nomonsters flags to G_LoadOptions()/G_SaveOptions()) | ||
2721 | |||
2722 | if ((skill=demover) >= 100) // For demos from versions >= 1.4 | ||
2723 | { | ||
2724 | //e6y: check for overrun | ||
2725 | if (CheckForOverrun(header_p, demo_p, size, 8, failonerror)) | ||
2726 | return NULL; | ||
2727 | |||
2728 | compatibility_level = G_GetOriginalDoomCompatLevel(demover); | ||
2729 | skill = *demo_p++; | ||
2730 | episode = *demo_p++; | ||
2731 | map = *demo_p++; | ||
2732 | deathmatch = *demo_p++; | ||
2733 | respawnparm = *demo_p++; | ||
2734 | fastparm = *demo_p++; | ||
2735 | nomonsters = *demo_p++; | ||
2736 | consoleplayer = *demo_p++; | ||
2737 | } | ||
2738 | else | ||
2739 | { | ||
2740 | //e6y: check for overrun | ||
2741 | if (CheckForOverrun(header_p, demo_p, size, 2, failonerror)) | ||
2742 | return NULL; | ||
2743 | |||
2744 | compatibility_level = doom_12_compatibility; | ||
2745 | episode = *demo_p++; | ||
2746 | map = *demo_p++; | ||
2747 | deathmatch = respawnparm = fastparm = | ||
2748 | nomonsters = consoleplayer = 0; | ||
2749 | } | ||
2750 | G_Compatibility(); | ||
2751 | } | ||
2752 | else // new versions of demos | ||
2753 | { | ||
2754 | demo_p += 6; // skip signature; | ||
2755 | switch (demover) { | ||
2756 | case 200: /* BOOM */ | ||
2757 | case 201: | ||
2758 | //e6y: check for overrun | ||
2759 | if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) | ||
2760 | return NULL; | ||
2761 | |||
2762 | if (!*demo_p++) | ||
2763 | compatibility_level = boom_201_compatibility; | ||
2764 | else | ||
2765 | compatibility_level = boom_compatibility_compatibility; | ||
2766 | break; | ||
2767 | case 202: | ||
2768 | //e6y: check for overrun | ||
2769 | if (CheckForOverrun(header_p, demo_p, size, 1, failonerror)) | ||
2770 | return NULL; | ||
2771 | |||
2772 | if (!*demo_p++) | ||
2773 | compatibility_level = boom_202_compatibility; | ||
2774 | else | ||
2775 | compatibility_level = boom_compatibility_compatibility; | ||
2776 | break; | ||
2777 | case 203: | ||
2778 | /* LxDoom or MBF - determine from signature | ||
2779 | * cph - load compatibility level */ | ||
2780 | switch (*(header_p + 2)) { | ||
2781 | case 'B': /* LxDoom */ | ||
2782 | /* cph - DEMOSYNC - LxDoom demos recorded in compatibility modes support dropped */ | ||
2783 | compatibility_level = lxdoom_1_compatibility; | ||
2784 | break; | ||
2785 | case 'M': | ||
2786 | compatibility_level = mbf_compatibility; | ||
2787 | demo_p++; | ||
2788 | break; | ||
2789 | } | ||
2790 | break; | ||
2791 | case 210: | ||
2792 | compatibility_level = prboom_2_compatibility; | ||
2793 | demo_p++; | ||
2794 | break; | ||
2795 | case 211: | ||
2796 | compatibility_level = prboom_3_compatibility; | ||
2797 | demo_p++; | ||
2798 | break; | ||
2799 | case 212: | ||
2800 | compatibility_level = prboom_4_compatibility; | ||
2801 | demo_p++; | ||
2802 | break; | ||
2803 | case 213: | ||
2804 | compatibility_level = prboom_5_compatibility; | ||
2805 | demo_p++; | ||
2806 | break; | ||
2807 | case 214: | ||
2808 | compatibility_level = prboom_6_compatibility; | ||
2809 | longtics = 1; | ||
2810 | demo_p++; | ||
2811 | break; | ||
2812 | } | ||
2813 | //e6y: check for overrun | ||
2814 | if (CheckForOverrun(header_p, demo_p, size, 5, failonerror)) | ||
2815 | return NULL; | ||
2816 | |||
2817 | skill = *demo_p++; | ||
2818 | episode = *demo_p++; | ||
2819 | map = *demo_p++; | ||
2820 | deathmatch = *demo_p++; | ||
2821 | consoleplayer = *demo_p++; | ||
2822 | |||
2823 | /* killough 11/98: save option pointer for below */ | ||
2824 | if (mbf_features) | ||
2825 | option_p = demo_p; | ||
2826 | |||
2827 | //e6y: check for overrun | ||
2828 | if (CheckForOverrun(header_p, demo_p, size, GAME_OPTION_SIZE, failonerror)) | ||
2829 | return NULL; | ||
2830 | |||
2831 | demo_p = G_ReadOptions(demo_p); // killough 3/1/98: Read game options | ||
2832 | |||
2833 | if (demover == 200) // killough 6/3/98: partially fix v2.00 demos | ||
2834 | demo_p += 256-GAME_OPTION_SIZE; | ||
2835 | } | ||
2836 | |||
2837 | if (sizeof(comp_lev_str)/sizeof(comp_lev_str[0]) != MAX_COMPATIBILITY_LEVEL) | ||
2838 | I_Error("G_ReadDemoHeader: compatibility level strings incomplete"); | ||
2839 | lprintf(LO_INFO, "G_DoPlayDemo: playing demo with %s compatibility\n", | ||
2840 | comp_lev_str[compatibility_level]); | ||
2841 | |||
2842 | if (demo_compatibility) // only 4 players can exist in old demos | ||
2843 | { | ||
2844 | //e6y: check for overrun | ||
2845 | if (CheckForOverrun(header_p, demo_p, size, 4, failonerror)) | ||
2846 | return NULL; | ||
2847 | |||
2848 | for (i=0; i<4; i++) // intentionally hard-coded 4 -- killough | ||
2849 | playeringame[i] = *demo_p++; | ||
2850 | for (;i < MAXPLAYERS; i++) | ||
2851 | playeringame[i] = 0; | ||
2852 | } | ||
2853 | else | ||
2854 | { | ||
2855 | //e6y: check for overrun | ||
2856 | if (CheckForOverrun(header_p, demo_p, size, MAXPLAYERS, failonerror)) | ||
2857 | return NULL; | ||
2858 | |||
2859 | for (i=0 ; i < MAXPLAYERS; i++) | ||
2860 | playeringame[i] = *demo_p++; | ||
2861 | demo_p += MIN_MAXPLAYERS - MAXPLAYERS; | ||
2862 | } | ||
2863 | |||
2864 | if (playeringame[1]) | ||
2865 | { | ||
2866 | netgame = true; | ||
2867 | netdemo = true; | ||
2868 | } | ||
2869 | |||
2870 | if (gameaction != ga_loadgame) { /* killough 12/98: support -loadgame */ | ||
2871 | G_InitNew(skill, episode, map); | ||
2872 | } | ||
2873 | |||
2874 | for (i=0; i<MAXPLAYERS;i++) // killough 4/24/98 | ||
2875 | players[i].cheats = 0; | ||
2876 | |||
2877 | return demo_p; | ||
2878 | } | ||
2879 | |||
2880 | void G_DoPlayDemo(void) | ||
2881 | { | ||
2882 | char basename[9]; | ||
2883 | |||
2884 | ExtractFileBase(defdemoname,basename); // killough | ||
2885 | basename[8] = 0; | ||
2886 | |||
2887 | /* cph - store lump number for unlocking later */ | ||
2888 | demolumpnum = W_GetNumForName(basename); | ||
2889 | demobuffer = W_CacheLumpNum(demolumpnum); | ||
2890 | demolength = W_LumpLength(demolumpnum); | ||
2891 | |||
2892 | demo_p = G_ReadDemoHeader(demobuffer, demolength, true); | ||
2893 | |||
2894 | gameaction = ga_nothing; | ||
2895 | usergame = false; | ||
2896 | |||
2897 | demoplayback = true; | ||
2898 | R_SmoothPlaying_Reset(NULL); // e6y | ||
2899 | |||
2900 | starttime = I_GetTime_RealTime (); | ||
2901 | } | ||
2902 | |||
2903 | /* G_CheckDemoStatus | ||
2904 | * | ||
2905 | * Called after a death or level completion to allow demos to be cleaned up | ||
2906 | * Returns true if a new demo loop action will take place | ||
2907 | */ | ||
2908 | boolean G_CheckDemoStatus (void) | ||
2909 | { | ||
2910 | P_ChecksumFinal(); | ||
2911 | |||
2912 | if (demorecording) | ||
2913 | { | ||
2914 | demorecording = false; | ||
2915 | fputc(DEMOMARKER, demofp); | ||
2916 | I_Error("G_CheckDemoStatus: Demo recorded"); | ||
2917 | return false; // killough | ||
2918 | } | ||
2919 | |||
2920 | if (timingdemo) | ||
2921 | { | ||
2922 | int endtime = I_GetTime_RealTime (); | ||
2923 | // killough -- added fps information and made it work for longer demos: | ||
2924 | unsigned realtics = endtime-starttime; | ||
2925 | I_Error ("Timed %u gametics in %u realtics = %-.1f frames per second", | ||
2926 | (unsigned) gametic,realtics, | ||
2927 | (unsigned) gametic * (double) TICRATE / realtics); | ||
2928 | } | ||
2929 | |||
2930 | if (demoplayback) | ||
2931 | { | ||
2932 | if (singledemo) | ||
2933 | exit(0); // killough | ||
2934 | |||
2935 | if (demolumpnum != -1) { | ||
2936 | // cph - unlock the demo lump | ||
2937 | W_UnlockLumpNum(demolumpnum); | ||
2938 | demolumpnum = -1; | ||
2939 | } | ||
2940 | G_ReloadDefaults(); // killough 3/1/98 | ||
2941 | netgame = false; // killough 3/29/98 | ||
2942 | deathmatch = false; | ||
2943 | D_AdvanceDemo (); | ||
2944 | return true; | ||
2945 | } | ||
2946 | return false; | ||
2947 | } | ||
2948 | |||
2949 | // killough 1/22/98: this is a "Doom printf" for messages. I've gotten | ||
2950 | // tired of using players->message=... and so I've added this dprintf. | ||
2951 | // | ||
2952 | // killough 3/6/98: Made limit static to allow z_zone functions to call | ||
2953 | // this function, without calling realloc(), which seems to cause problems. | ||
2954 | |||
2955 | #define MAX_MESSAGE_SIZE 1024 | ||
2956 | |||
2957 | // CPhipps - renamed to doom_printf to avoid name collision with glibc | ||
2958 | void doom_printf(const char *s, ...) | ||
2959 | { | ||
2960 | static char msg[MAX_MESSAGE_SIZE]; | ||
2961 | va_list v; | ||
2962 | va_start(v,s); | ||
2963 | #ifdef HAVE_VSNPRINTF | ||
2964 | vsnprintf(msg,sizeof(msg),s,v); /* print message in buffer */ | ||
2965 | #else | ||
2966 | vsprintf(msg,s,v); | ||
2967 | #endif | ||
2968 | va_end(v); | ||
2969 | players[consoleplayer].message = msg; // set new message | ||
2970 | } | ||