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