1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
4 // Copyright(C) 1993-1996 Id Software, Inc.
5 // Copyright(C) 2005 Simon Howard
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 //-----------------------------------------------------------------------------
59 // Needs access to LFB.
72 // SKY handling - still the wrong place.
81 #define SAVEGAMESIZE 0x2c000
85 boolean
G_CheckDemoStatus (void);
86 void G_ReadDemoTiccmd (ticcmd_t
* cmd
);
87 void G_WriteDemoTiccmd (ticcmd_t
* cmd
);
88 void G_PlayerReborn (int player
);
89 void G_InitNew (skill_t skill
, int episode
, int map
);
91 void G_DoReborn (int playernum
);
93 void G_DoLoadLevel (void);
94 void G_DoNewGame (void);
95 void G_DoLoadGame (void);
96 void G_DoPlayDemo (void);
97 void G_DoCompleted (void);
98 void G_DoVictory (void);
99 void G_DoWorldDone (void);
100 void G_DoSaveGame (void);
102 // Gamestate the last time G_Ticker was called.
104 gamestate_t oldgamestate
;
106 gameaction_t gameaction
;
107 gamestate_t gamestate
;
109 boolean respawnmonsters
;
113 // If non-zero, exit the level after this number of minutes.
118 boolean sendpause
; // send a pause event next tic
119 boolean sendsave
; // send a save event next tic
120 boolean usergame
; // ok to save / end game
122 boolean timingdemo
; // if true, exit with report on completion
123 boolean nodrawers
; // for comparative timing purposes
124 boolean noblit
; // for comparative timing purposes
125 int starttime
; // for comparative timing purposes
129 boolean deathmatch
; // only if started as net death
130 boolean netgame
; // only true if packets are broadcast
131 boolean playeringame
[MAXPLAYERS
];
132 player_t players
[MAXPLAYERS
];
134 boolean turbodetected
[MAXPLAYERS
];
136 int consoleplayer
; // player taking events and displaying
137 int displayplayer
; // view being displayed
139 int levelstarttic
; // gametic at level start
140 int totalkills
, totalitems
, totalsecret
; // for intermission
143 boolean demorecording
;
144 boolean longtics
; // cph's doom 1.91 longtics hack
145 boolean lowres_turn
; // low resolution turning for longtics
146 boolean demoplayback
;
151 boolean singledemo
; // quit after playing a demo from cmdline
153 boolean precache
= true; // if true, load all graphics at start
155 boolean testcontrols
= false; // Invoked by setup to test controls
157 wbstartstruct_t wminfo
; // parms for world map / intermission
159 byte consistancy
[MAXPLAYERS
][BACKUPTICS
];
165 int key_right
= KEY_RIGHTARROW
;
166 int key_left
= KEY_LEFTARROW
;
168 int key_up
= KEY_UPARROW
;
169 int key_down
= KEY_DOWNARROW
;
170 int key_strafeleft
= ',';
171 int key_straferight
= '.';
172 int key_fire
= KEY_RCTRL
;
174 int key_strafe
= KEY_RALT
;
175 int key_speed
= KEY_RSHIFT
;
177 int key_weapon1
= '1';
178 int key_weapon2
= '2';
179 int key_weapon3
= '3';
180 int key_weapon4
= '4';
181 int key_weapon5
= '5';
182 int key_weapon6
= '6';
183 int key_weapon7
= '7';
184 int key_weapon8
= '8';
186 int key_pause
= KEY_PAUSE
;
189 int mousebstrafe
= 1;
190 int mousebforward
= 2;
192 int mousebstrafeleft
= -1;
193 int mousebstraferight
= -1;
194 int mousebbackward
= -1;
197 // Control whether if a mouse button is double clicked, it acts like
198 // "use" has been pressed
206 int joybstrafeleft
= -1;
207 int joybstraferight
= -1;
209 // fraggle: Disallow mouse and joystick movement to cause forward/backward
210 // motion. Specified with the '-novert' command line parameter.
211 // This is an int to allow saving to config file
217 #define MAXPLMOVE (forwardmove[1])
219 #define TURBOTHRESHOLD 0x32
221 fixed_t forwardmove
[2] = {0x19, 0x32};
222 fixed_t sidemove
[2] = {0x18, 0x28};
223 fixed_t angleturn
[3] = {640, 1280, 320}; // + slow turn
225 static int *weapon_keys
[] = {
236 #define SLOWTURNTICS 6
240 static boolean gamekeydown
[NUMKEYS
];
241 static int turnheld
; // for accelerative turning
243 static boolean mousearray
[4];
244 static boolean
*mousebuttons
= &mousearray
[1]; // allow [-1]
246 // mouse values are used once
250 static int dclicktime
;
251 static boolean dclickstate
;
253 static int dclicktime2
;
254 static boolean dclickstate2
;
257 #define MAX_JOY_BUTTONS 20
259 // joystick values are repeated
262 static boolean joyarray
[MAX_JOY_BUTTONS
+ 1];
263 static boolean
*joybuttons
= &joyarray
[1]; // allow [-1]
265 static int savegameslot
;
266 static char savedescription
[32];
268 static int testcontrols_mousespeed
;
270 #define BODYQUESIZE 32
272 mobj_t
* bodyque
[BODYQUESIZE
];
275 int vanilla_savegame_limit
= 1;
276 int vanilla_demo_limit
= 1;
279 #define MOUSE_SPEED_BOX_WIDTH 16
280 #define COLOR_RED 0xb0
281 #define COLOR_BLACK 0x00
282 #define COLOR_WHITE 0x04
283 #define COLOR_YELLOW 0xe7
285 void G_DrawMouseSpeedBox(void)
297 // If the mouse is turned off or acceleration is turned off, don't
298 // draw the box at all.
300 if (!usemouse
|| fabs(mouse_acceleration
- 1) < 0.01)
305 // Calculate box position
307 box_x
= SCREENWIDTH
- MOUSE_SPEED_BOX_WIDTH
* 8;
308 box_y
= SCREENHEIGHT
- 9;
314 for (i
=0; i
<MOUSE_SPEED_BOX_WIDTH
; ++i
)
318 lumpname
= "M_LSLEFT";
320 else if (i
== MOUSE_SPEED_BOX_WIDTH
- 1)
322 lumpname
= "M_LSRGHT";
326 lumpname
= "M_LSCNTR";
329 V_DrawPatchDirect(x
, box_y
, 0, W_CacheLumpName(DEH_String(lumpname
),
334 // Calculate the position of the red line. This is 1/3 of the way
337 redline_x
= (MOUSE_SPEED_BOX_WIDTH
/ 3) * 8;
339 // Undo acceleration and get back the original mouse speed
341 if (testcontrols_mousespeed
< mouse_threshold
)
343 original_speed
= testcontrols_mousespeed
;
347 original_speed
= testcontrols_mousespeed
- mouse_threshold
;
348 original_speed
= (int) (original_speed
/ mouse_acceleration
);
349 original_speed
+= mouse_threshold
;
352 // Calculate line length
354 linelen
= (original_speed
* redline_x
) / mouse_threshold
;
356 // Draw horizontal "thermometer"
358 for (x
=0; x
<(MOUSE_SPEED_BOX_WIDTH
- 1) * 8; ++x
)
368 color
= COLOR_YELLOW
;
376 screens
[0][(box_y
- 4) * SCREENWIDTH
+ box_x
+ x
+ 1] = color
;
381 for (y
=box_y
- 8; y
<box_y
; ++y
)
383 screens
[0][y
* SCREENWIDTH
+ box_x
+ redline_x
] = COLOR_RED
;
387 int G_CmdChecksum (ticcmd_t
* cmd
)
392 for (i
=0 ; i
< sizeof(*cmd
)/4 - 1 ; i
++)
393 sum
+= ((int *)cmd
)[i
];
401 // Builds a ticcmd from all of the available inputs
402 // or reads it from the demo buffer.
403 // If recording a demo, write it out
405 void G_BuildTiccmd (ticcmd_t
* cmd
)
415 memset(cmd
, 0, sizeof(ticcmd_t
));
418 consistancy
[consoleplayer
][maketic
%BACKUPTICS
];
420 strafe
= gamekeydown
[key_strafe
] || mousebuttons
[mousebstrafe
]
421 || joybuttons
[joybstrafe
];
423 // fraggle: support the old "joyb_speed = 31" hack which
424 // allowed an autorun effect
426 speed
= key_speed
>= NUMKEYS
427 || joybspeed
>= MAX_JOY_BUTTONS
428 || gamekeydown
[key_speed
]
429 || joybuttons
[joybspeed
];
433 // use two stage accelerative turning
434 // on the keyboard and joystick
437 || gamekeydown
[key_right
]
438 || gamekeydown
[key_left
])
443 if (turnheld
< SLOWTURNTICS
)
444 tspeed
= 2; // slow turn
448 // let movement keys cancel each other out
451 if (gamekeydown
[key_right
])
453 // fprintf(stderr, "strafe right\n");
454 side
+= sidemove
[speed
];
456 if (gamekeydown
[key_left
])
458 // fprintf(stderr, "strafe left\n");
459 side
-= sidemove
[speed
];
462 side
+= sidemove
[speed
];
464 side
-= sidemove
[speed
];
469 if (gamekeydown
[key_right
])
470 cmd
->angleturn
-= angleturn
[tspeed
];
471 if (gamekeydown
[key_left
])
472 cmd
->angleturn
+= angleturn
[tspeed
];
474 cmd
->angleturn
-= angleturn
[tspeed
];
476 cmd
->angleturn
+= angleturn
[tspeed
];
479 if (gamekeydown
[key_up
])
481 // fprintf(stderr, "up\n");
482 forward
+= forwardmove
[speed
];
484 if (gamekeydown
[key_down
])
486 // fprintf(stderr, "down\n");
487 forward
-= forwardmove
[speed
];
491 forward
+= forwardmove
[speed
];
493 forward
-= forwardmove
[speed
];
495 if (gamekeydown
[key_strafeleft
]
496 || joybuttons
[joybstrafeleft
]
497 || mousebuttons
[mousebstrafeleft
])
499 side
-= sidemove
[speed
];
502 if (gamekeydown
[key_straferight
]
503 || joybuttons
[joybstraferight
]
504 || mousebuttons
[mousebstraferight
])
506 side
+= sidemove
[speed
];
510 cmd
->chatchar
= HU_dequeueChatChar();
512 if (gamekeydown
[key_fire
] || mousebuttons
[mousebfire
]
513 || joybuttons
[joybfire
])
514 cmd
->buttons
|= BT_ATTACK
;
516 if (gamekeydown
[key_use
]
517 || joybuttons
[joybuse
]
518 || mousebuttons
[mousebuse
])
520 cmd
->buttons
|= BT_USE
;
521 // clear double clicks if hit use button
525 // chainsaw overrides
527 for (i
=0; i
<arrlen(weapon_keys
); ++i
)
529 int key
= *weapon_keys
[i
];
531 if (gamekeydown
[key
])
533 cmd
->buttons
|= BT_CHANGE
;
534 cmd
->buttons
|= i
<<BT_WEAPONSHIFT
;
540 if (mousebuttons
[mousebforward
])
542 forward
+= forwardmove
[speed
];
544 if (mousebuttons
[mousebbackward
])
546 forward
-= forwardmove
[speed
];
551 // forward double click
552 if (mousebuttons
[mousebforward
] != dclickstate
&& dclicktime
> 1 )
554 dclickstate
= mousebuttons
[mousebforward
];
559 cmd
->buttons
|= BT_USE
;
567 dclicktime
+= ticdup
;
575 // strafe double click
577 mousebuttons
[mousebstrafe
]
578 || joybuttons
[joybstrafe
];
579 if (bstrafe
!= dclickstate2
&& dclicktime2
> 1 )
581 dclickstate2
= bstrafe
;
586 cmd
->buttons
|= BT_USE
;
594 dclicktime2
+= ticdup
;
595 if (dclicktime2
> 20)
603 // fraggle: allow disabling mouse y movement
613 cmd
->angleturn
-= mousex
*0x8;
617 // No movement in the previous frame
619 testcontrols_mousespeed
= 0;
624 if (forward
> MAXPLMOVE
)
626 else if (forward
< -MAXPLMOVE
)
627 forward
= -MAXPLMOVE
;
628 if (side
> MAXPLMOVE
)
630 else if (side
< -MAXPLMOVE
)
633 cmd
->forwardmove
+= forward
;
634 cmd
->sidemove
+= side
;
640 cmd
->buttons
= BT_SPECIAL
| BTS_PAUSE
;
646 cmd
->buttons
= BT_SPECIAL
| BTS_SAVEGAME
| (savegameslot
<<BTS_SAVESHIFT
);
653 // round angleturn to the nearest 256 boundary
654 // for recording demos with single byte values for turn
656 cmd
->angleturn
= (cmd
->angleturn
+ 128) & 0xff00;
664 extern gamestate_t wipegamestate
;
666 void G_DoLoadLevel (void)
671 // First thing, we have a dummy sky texture name,
672 // a flat. The data is in the WAD only because
673 // we look for an actual index, instead of simply
676 skyflatnum
= R_FlatNumForName(DEH_String(SKYFLATNAME
));
678 levelstarttic
= gametic
; // for time calculation
680 if (wipegamestate
== GS_LEVEL
)
681 wipegamestate
= -1; // force a wipe
683 gamestate
= GS_LEVEL
;
685 for (i
=0 ; i
<MAXPLAYERS
; i
++)
687 turbodetected
[i
] = false;
688 if (playeringame
[i
] && players
[i
].playerstate
== PST_DEAD
)
689 players
[i
].playerstate
= PST_REBORN
;
690 memset (players
[i
].frags
,0,sizeof(players
[i
].frags
));
693 P_SetupLevel (gameepisode
, gamemap
, 0, gameskill
);
694 displayplayer
= consoleplayer
; // view the guy you are playing
695 gameaction
= ga_nothing
;
698 // clear cmd building stuff
700 memset (gamekeydown
, 0, sizeof(gamekeydown
));
701 joyxmove
= joyymove
= 0;
703 sendpause
= sendsave
= paused
= false;
704 memset (mousebuttons
, 0, sizeof(mousebuttons
));
705 memset (joybuttons
, 0, sizeof(joybuttons
));
709 players
[consoleplayer
].message
= "Press escape to quit.";
714 static void SetJoyButtons(unsigned int buttons_mask
)
718 for (i
=0; i
<MAX_JOY_BUTTONS
; ++i
)
720 joybuttons
[i
] = (buttons_mask
& (1 << i
)) != 0;
726 // Get info needed to make ticcmd_ts for the players.
728 boolean
G_Responder (event_t
* ev
)
730 // allow spy mode changes even during the demo
731 if (gamestate
== GS_LEVEL
&& ev
->type
== ev_keydown
732 && ev
->data1
== KEY_F12
&& (singledemo
|| !deathmatch
) )
738 if (displayplayer
== MAXPLAYERS
)
740 } while (!playeringame
[displayplayer
] && displayplayer
!= consoleplayer
);
744 // any other key pops up menu if in demos
745 if (gameaction
== ga_nothing
&& !singledemo
&&
746 (demoplayback
|| gamestate
== GS_DEMOSCREEN
)
749 if (ev
->type
== ev_keydown
||
750 (ev
->type
== ev_mouse
&& ev
->data1
) ||
751 (ev
->type
== ev_joystick
&& ev
->data1
) )
753 M_StartControlPanel ();
759 if (gamestate
== GS_LEVEL
)
762 if (devparm
&& ev
->type
== ev_keydown
&& ev
->data1
== ';')
764 G_DeathMatchSpawnPlayer (0);
768 if (HU_Responder (ev
))
769 return true; // chat ate the event
770 if (ST_Responder (ev
))
771 return true; // status window ate it
772 if (AM_Responder (ev
))
773 return true; // automap ate it
776 if (gamestate
== GS_FINALE
)
778 if (F_Responder (ev
))
779 return true; // finale ate the event
782 if (testcontrols
&& ev
->type
== ev_mouse
)
784 // If we are invoked by setup to test the controls, save the
785 // mouse speed so that we can display it on-screen.
786 // Perform a low pass filter on this so that the thermometer
787 // appears to move smoothly.
789 testcontrols_mousespeed
= abs(ev
->data2
);
795 if (ev
->data1
== key_pause
)
799 else if (ev
->data1
<NUMKEYS
)
801 gamekeydown
[ev
->data1
] = true;
804 return true; // eat key down events
807 if (ev
->data1
<NUMKEYS
)
808 gamekeydown
[ev
->data1
] = false;
809 return false; // always let key up events filter down
812 mousebuttons
[0] = ev
->data1
& 1;
813 mousebuttons
[1] = ev
->data1
& 2;
814 mousebuttons
[2] = ev
->data1
& 4;
815 mousex
= ev
->data2
*(mouseSensitivity
+5)/10;
816 mousey
= ev
->data3
*(mouseSensitivity
+5)/10;
817 return true; // eat events
820 SetJoyButtons(ev
->data1
);
821 joyxmove
= ev
->data2
;
822 joyymove
= ev
->data3
;
823 return true; // eat events
836 // Make ticcmd_ts for the players.
844 // do player reborns if needed
845 for (i
=0 ; i
<MAXPLAYERS
; i
++)
846 if (playeringame
[i
] && players
[i
].playerstate
== PST_REBORN
)
849 // do things to change the game state
850 while (gameaction
!= ga_nothing
)
880 players
[consoleplayer
].message
= DEH_String("screen shot");
881 gameaction
= ga_nothing
;
888 // get commands, check consistancy,
889 // and build new consistancy check
890 buf
= (gametic
/ticdup
)%BACKUPTICS
;
892 for (i
=0 ; i
<MAXPLAYERS
; i
++)
896 cmd
= &players
[i
].cmd
;
898 memcpy (cmd
, &netcmds
[i
][buf
], sizeof(ticcmd_t
));
901 G_ReadDemoTiccmd (cmd
);
903 G_WriteDemoTiccmd (cmd
);
905 // check for turbo cheats
907 // check ~ 4 seconds whether to display the turbo message.
908 // store if the turbo threshold was exceeded in any tics
909 // over the past 4 seconds. offset the checking period
910 // for each player so messages are not displayed at the
913 if (cmd
->forwardmove
> TURBOTHRESHOLD
)
915 turbodetected
[i
] = true;
918 if ((gametic
& 31) == 0
919 && ((gametic
>> 5) % MAXPLAYERS
) == i
922 static char turbomessage
[80];
923 extern char *player_names
[4];
924 sprintf (turbomessage
, "%s is turbo!",player_names
[i
]);
925 players
[consoleplayer
].message
= turbomessage
;
926 turbodetected
[i
] = false;
929 if (netgame
&& !netdemo
&& !(gametic
%ticdup
) )
931 if (gametic
> BACKUPTICS
932 && consistancy
[i
][buf
] != cmd
->consistancy
)
934 I_Error ("consistency failure (%i should be %i)",
935 cmd
->consistancy
, consistancy
[i
][buf
]);
938 consistancy
[i
][buf
] = players
[i
].mo
->x
;
940 consistancy
[i
][buf
] = rndindex
;
945 // check for special buttons
946 for (i
=0 ; i
<MAXPLAYERS
; i
++)
950 if (players
[i
].cmd
.buttons
& BT_SPECIAL
)
952 switch (players
[i
].cmd
.buttons
& BT_SPECIALMASK
)
963 if (!savedescription
[0])
964 strcpy (savedescription
, "NET GAME");
966 (players
[i
].cmd
.buttons
& BTS_SAVEMASK
)>>BTS_SAVESHIFT
;
967 gameaction
= ga_savegame
;
974 // Have we just finished displaying an intermission screen?
976 if (oldgamestate
== GS_INTERMISSION
&& gamestate
!= GS_INTERMISSION
)
981 oldgamestate
= gamestate
;
993 case GS_INTERMISSION
:
1009 // PLAYER STRUCTURE FUNCTIONS
1010 // also see P_SpawnPlayer in P_Things
1015 // Called at the start.
1016 // Called by the game initialization functions.
1018 void G_InitPlayer (int player
)
1022 // set up the saved info
1023 p
= &players
[player
];
1025 // clear everything else to defaults
1026 G_PlayerReborn (player
);
1033 // G_PlayerFinishLevel
1034 // Can when a player completes a level.
1036 void G_PlayerFinishLevel (int player
)
1040 p
= &players
[player
];
1042 memset (p
->powers
, 0, sizeof (p
->powers
));
1043 memset (p
->cards
, 0, sizeof (p
->cards
));
1044 p
->mo
->flags
&= ~MF_SHADOW
; // cancel invisibility
1045 p
->extralight
= 0; // cancel gun flashes
1046 p
->fixedcolormap
= 0; // cancel ir gogles
1047 p
->damagecount
= 0; // no palette changes
1054 // Called after a player dies
1055 // almost everything is cleared and initialized
1057 void G_PlayerReborn (int player
)
1061 int frags
[MAXPLAYERS
];
1066 memcpy (frags
,players
[player
].frags
,sizeof(frags
));
1067 killcount
= players
[player
].killcount
;
1068 itemcount
= players
[player
].itemcount
;
1069 secretcount
= players
[player
].secretcount
;
1071 p
= &players
[player
];
1072 memset (p
, 0, sizeof(*p
));
1074 memcpy (players
[player
].frags
, frags
, sizeof(players
[player
].frags
));
1075 players
[player
].killcount
= killcount
;
1076 players
[player
].itemcount
= itemcount
;
1077 players
[player
].secretcount
= secretcount
;
1079 p
->usedown
= p
->attackdown
= true; // don't do anything immediately
1080 p
->playerstate
= PST_LIVE
;
1081 p
->health
= deh_initial_health
; // Use dehacked value
1082 p
->readyweapon
= p
->pendingweapon
= wp_pistol
;
1083 p
->weaponowned
[wp_fist
] = true;
1084 p
->weaponowned
[wp_pistol
] = true;
1085 p
->ammo
[am_clip
] = deh_initial_bullets
;
1087 for (i
=0 ; i
<NUMAMMO
; i
++)
1088 p
->maxammo
[i
] = maxammo
[i
];
1094 // Returns false if the player cannot be respawned
1095 // at the given mapthing_t spot
1096 // because something is occupying it
1098 void P_SpawnPlayer (mapthing_t
* mthing
);
1103 mapthing_t
* mthing
)
1112 if (!players
[playernum
].mo
)
1114 // first spawn of level, before corpses
1115 for (i
=0 ; i
<playernum
; i
++)
1116 if (players
[i
].mo
->x
== mthing
->x
<< FRACBITS
1117 && players
[i
].mo
->y
== mthing
->y
<< FRACBITS
)
1122 x
= mthing
->x
<< FRACBITS
;
1123 y
= mthing
->y
<< FRACBITS
;
1125 if (!P_CheckPosition (players
[playernum
].mo
, x
, y
) )
1128 // flush an old corpse if needed
1129 if (bodyqueslot
>= BODYQUESIZE
)
1130 P_RemoveMobj (bodyque
[bodyqueslot
%BODYQUESIZE
]);
1131 bodyque
[bodyqueslot
%BODYQUESIZE
] = players
[playernum
].mo
;
1134 // spawn a teleport fog
1135 ss
= R_PointInSubsector (x
,y
);
1136 an
= ( ANG45
* (((unsigned int) mthing
->angle
)/45) ) >> ANGLETOFINESHIFT
;
1138 mo
= P_SpawnMobj (x
+20*finecosine
[an
], y
+20*finesine
[an
]
1139 , ss
->sector
->floorheight
1142 if (players
[consoleplayer
].viewz
!= 1)
1143 S_StartSound (mo
, sfx_telept
); // don't start sound on first frame
1150 // G_DeathMatchSpawnPlayer
1151 // Spawns a player at one of the random death match spots
1152 // called at level load and each death
1154 void G_DeathMatchSpawnPlayer (int playernum
)
1159 selections
= deathmatch_p
- deathmatchstarts
;
1161 I_Error ("Only %i deathmatch spots, 4 required", selections
);
1163 for (j
=0 ; j
<20 ; j
++)
1165 i
= P_Random() % selections
;
1166 if (G_CheckSpot (playernum
, &deathmatchstarts
[i
]) )
1168 deathmatchstarts
[i
].type
= playernum
+1;
1169 P_SpawnPlayer (&deathmatchstarts
[i
]);
1174 // no good spot, so the player will probably get stuck
1175 P_SpawnPlayer (&playerstarts
[playernum
]);
1181 void G_DoReborn (int playernum
)
1187 // reload the level from scratch
1188 gameaction
= ga_loadlevel
;
1192 // respawn at the start
1194 // first dissasociate the corpse
1195 players
[playernum
].mo
->player
= NULL
;
1197 // spawn at random spot if in death match
1200 G_DeathMatchSpawnPlayer (playernum
);
1204 if (G_CheckSpot (playernum
, &playerstarts
[playernum
]) )
1206 P_SpawnPlayer (&playerstarts
[playernum
]);
1210 // try to spawn at one of the other players spots
1211 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1213 if (G_CheckSpot (playernum
, &playerstarts
[i
]) )
1215 playerstarts
[i
].type
= playernum
+1; // fake as other player
1216 P_SpawnPlayer (&playerstarts
[i
]);
1217 playerstarts
[i
].type
= i
+1; // restore
1220 // he's going to be inside something. Too bad.
1222 P_SpawnPlayer (&playerstarts
[playernum
]);
1227 void G_ScreenShot (void)
1229 gameaction
= ga_screenshot
;
1238 {0,30,75,120,90,165,180,180,30,165},
1239 {0,90,90,90,120,90,360,240,30,170},
1240 {0,90,45,90,150,90,90,165,30,135}
1243 // DOOM II Par Times
1246 30,90,120,120,90,150,120,120,270,90, // 1-10
1247 210,150,150,150,210,150,420,150,210,150, // 11-20
1248 240,150,180,150,150,300,330,420,300,180, // 21-30
1257 extern char* pagename
;
1259 void G_ExitLevel (void)
1262 gameaction
= ga_completed
;
1265 // Here's for the german edition.
1266 void G_SecretExitLevel (void)
1268 // IF NO WOLF3D LEVELS, NO SECRET EXIT!
1269 if ( (gamemode
== commercial
)
1270 && (W_CheckNumForName("map31")<0))
1274 gameaction
= ga_completed
;
1277 void G_DoCompleted (void)
1281 gameaction
= ga_nothing
;
1283 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1284 if (playeringame
[i
])
1285 G_PlayerFinishLevel (i
); // take away cards and stuff
1290 if (gamemode
!= commercial
)
1292 // Chex Quest ends after 5 levels, rather than 8.
1294 if (gameversion
== exe_chex
)
1298 gameaction
= ga_victory
;
1307 gameaction
= ga_victory
;
1310 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1311 players
[i
].didsecret
= true;
1319 && (gamemode
!= commercial
) )
1322 gameaction
= ga_victory
;
1327 && (gamemode
!= commercial
) )
1329 // exit secret level
1330 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1331 players
[i
].didsecret
= true;
1336 wminfo
.didsecret
= players
[consoleplayer
].didsecret
;
1337 wminfo
.epsd
= gameepisode
-1;
1338 wminfo
.last
= gamemap
-1;
1340 // wminfo.next is 0 biased, unlike gamemap
1341 if ( gamemode
== commercial
)
1346 case 15: wminfo
.next
= 30; break;
1347 case 31: wminfo
.next
= 31; break;
1353 case 32: wminfo
.next
= 15; break;
1354 default: wminfo
.next
= gamemap
;
1360 wminfo
.next
= 8; // go to secret level
1361 else if (gamemap
== 9)
1363 // returning from secret level
1364 switch (gameepisode
)
1381 wminfo
.next
= gamemap
; // go to next level
1384 wminfo
.maxkills
= totalkills
;
1385 wminfo
.maxitems
= totalitems
;
1386 wminfo
.maxsecret
= totalsecret
;
1387 wminfo
.maxfrags
= 0;
1388 if ( gamemode
== commercial
)
1389 wminfo
.partime
= TICRATE
*cpars
[gamemap
-1];
1391 wminfo
.partime
= TICRATE
*pars
[gameepisode
][gamemap
];
1392 wminfo
.pnum
= consoleplayer
;
1394 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1396 wminfo
.plyr
[i
].in
= playeringame
[i
];
1397 wminfo
.plyr
[i
].skills
= players
[i
].killcount
;
1398 wminfo
.plyr
[i
].sitems
= players
[i
].itemcount
;
1399 wminfo
.plyr
[i
].ssecret
= players
[i
].secretcount
;
1400 wminfo
.plyr
[i
].stime
= leveltime
;
1401 memcpy (wminfo
.plyr
[i
].frags
, players
[i
].frags
1402 , sizeof(wminfo
.plyr
[i
].frags
));
1405 gamestate
= GS_INTERMISSION
;
1407 automapactive
= false;
1416 void G_WorldDone (void)
1418 gameaction
= ga_worlddone
;
1421 players
[consoleplayer
].didsecret
= true;
1423 if ( gamemode
== commercial
)
1441 void G_DoWorldDone (void)
1443 gamestate
= GS_LEVEL
;
1444 gamemap
= wminfo
.next
+1;
1446 gameaction
= ga_nothing
;
1453 // G_InitFromSavegame
1454 // Can be called by the startup code or the menu task.
1456 extern boolean setsizeneeded
;
1457 void R_ExecuteSetViewSize (void);
1461 void G_LoadGame (char* name
)
1463 strcpy (savename
, name
);
1464 gameaction
= ga_loadgame
;
1467 #define VERSIONSIZE 16
1470 void G_DoLoadGame (void)
1474 gameaction
= ga_nothing
;
1476 save_stream
= fopen(savename
, "rb");
1478 if (save_stream
== NULL
)
1483 if (!P_ReadSaveGameHeader())
1485 fclose(save_stream
);
1489 savedleveltime
= leveltime
;
1491 // load a base level
1492 G_InitNew (gameskill
, gameepisode
, gamemap
);
1494 leveltime
= savedleveltime
;
1496 // dearchive all the modifications
1497 P_UnArchivePlayers ();
1498 P_UnArchiveWorld ();
1499 P_UnArchiveThinkers ();
1500 P_UnArchiveSpecials ();
1502 if (!P_ReadSaveGameEOF())
1503 I_Error ("Bad savegame");
1505 fclose(save_stream
);
1508 R_ExecuteSetViewSize ();
1510 // draw the pattern into the back screen
1511 R_FillBackScreen ();
1517 // Called by the menu task.
1518 // Description is a 24 byte text string
1525 savegameslot
= slot
;
1526 strcpy (savedescription
, description
);
1530 void G_DoSaveGame (void)
1532 char *savegame_file
;
1533 char *temp_savegame_file
;
1535 temp_savegame_file
= P_TempSaveGameFile();
1536 savegame_file
= P_SaveGameFile(savegameslot
);
1538 // Open the savegame file for writing. We write to a temporary file
1539 // and then rename it at the end if it was successfully written.
1540 // This prevents an existing savegame from being overwritten by
1541 // a corrupted one, or if a savegame buffer overrun occurs.
1543 save_stream
= fopen(temp_savegame_file
, "wb");
1545 if (save_stream
== NULL
)
1550 P_WriteSaveGameHeader(savedescription
);
1552 P_ArchivePlayers ();
1554 P_ArchiveThinkers ();
1555 P_ArchiveSpecials ();
1557 P_WriteSaveGameEOF();
1559 // Enforce the same savegame size limit as in Vanilla Doom,
1560 // except if the vanilla_savegame_limit setting is turned off.
1562 if (vanilla_savegame_limit
&& ftell(save_stream
) > SAVEGAMESIZE
)
1564 I_Error ("Savegame buffer overrun");
1567 // Finish up, close the savegame file.
1569 fclose(save_stream
);
1571 // Now rename the temporary savegame file to the actual savegame
1572 // file, overwriting the old savegame if there was one there.
1574 remove(savegame_file
);
1575 rename(temp_savegame_file
, savegame_file
);
1577 gameaction
= ga_nothing
;
1578 strcpy(savedescription
, "");
1580 players
[consoleplayer
].message
= DEH_String(GGSAVED
);
1582 // draw the pattern into the back screen
1583 R_FillBackScreen ();
1589 // Can be called by the startup code or the menu task,
1590 // consoleplayer, displayplayer, playeringame[] should be set.
1603 d_episode
= episode
;
1605 gameaction
= ga_newgame
;
1609 void G_DoNewGame (void)
1611 demoplayback
= false;
1615 playeringame
[1] = playeringame
[2] = playeringame
[3] = 0;
1616 respawnparm
= false;
1620 G_InitNew (d_skill
, d_episode
, d_map
);
1621 gameaction
= ga_nothing
;
1624 // The sky texture to be used instead of the F_SKY1 dummy.
1625 extern int skytexture
;
1634 char *skytexturename
;
1644 if (skill
> sk_nightmare
)
1645 skill
= sk_nightmare
;
1648 // This was quite messy with SPECIAL and commented parts.
1649 // Supposedly hacks to make the latest edition work.
1650 // It might not work properly.
1654 if ( gamemode
== retail
)
1659 else if ( gamemode
== shareware
)
1662 episode
= 1; // only start episode 1 on shareware
1676 && ( gamemode
!= commercial
) )
1681 if (skill
== sk_nightmare
|| respawnparm
)
1682 respawnmonsters
= true;
1684 respawnmonsters
= false;
1686 if (fastparm
|| (skill
== sk_nightmare
&& gameskill
!= sk_nightmare
) )
1688 for (i
=S_SARG_RUN1
; i
<=S_SARG_PAIN2
; i
++)
1689 states
[i
].tics
>>= 1;
1690 mobjinfo
[MT_BRUISERSHOT
].speed
= 20*FRACUNIT
;
1691 mobjinfo
[MT_HEADSHOT
].speed
= 20*FRACUNIT
;
1692 mobjinfo
[MT_TROOPSHOT
].speed
= 20*FRACUNIT
;
1694 else if (skill
!= sk_nightmare
&& gameskill
== sk_nightmare
)
1696 for (i
=S_SARG_RUN1
; i
<=S_SARG_PAIN2
; i
++)
1697 states
[i
].tics
<<= 1;
1698 mobjinfo
[MT_BRUISERSHOT
].speed
= 15*FRACUNIT
;
1699 mobjinfo
[MT_HEADSHOT
].speed
= 10*FRACUNIT
;
1700 mobjinfo
[MT_TROOPSHOT
].speed
= 10*FRACUNIT
;
1704 // force players to be initialized upon first level load
1705 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1706 players
[i
].playerstate
= PST_REBORN
;
1708 usergame
= true; // will be set false if a demo
1710 demoplayback
= false;
1711 automapactive
= false;
1713 gameepisode
= episode
;
1719 // Set the sky to use.
1721 // Note: This IS broken, but it is how Vanilla Doom behaves.
1722 // See http://doom.wikia.com/wiki/Sky_never_changes_in_Doom_II.
1724 // Because we set the sky here at the start of a game, not at the
1725 // start of a level, the sky texture never changes unless we
1726 // restore from a saved game. This was fixed before the Doom
1727 // source release, but this IS the way Vanilla DOS Doom behaves.
1729 if (gamemode
== commercial
)
1732 skytexturename
= "SKY1";
1733 else if (gamemap
< 21)
1734 skytexturename
= "SKY2";
1736 skytexturename
= "SKY3";
1740 switch (gameepisode
)
1744 skytexturename
= "SKY1";
1747 skytexturename
= "SKY2";
1750 skytexturename
= "SKY3";
1752 case 4: // Special Edition sky
1753 skytexturename
= "SKY4";
1758 skytexturename
= DEH_String(skytexturename
);
1760 skytexture
= R_TextureNumForName(skytexturename
);
1770 #define DEMOMARKER 0x80
1773 void G_ReadDemoTiccmd (ticcmd_t
* cmd
)
1775 if (*demo_p
== DEMOMARKER
)
1777 // end of demo data stream
1778 G_CheckDemoStatus ();
1781 cmd
->forwardmove
= ((signed char)*demo_p
++);
1782 cmd
->sidemove
= ((signed char)*demo_p
++);
1784 // If this is a longtics demo, read back in higher resolution
1788 cmd
->angleturn
= *demo_p
++;
1789 cmd
->angleturn
|= (*demo_p
++) << 8;
1793 cmd
->angleturn
= ((unsigned char) *demo_p
++)<<8;
1796 cmd
->buttons
= (unsigned char)*demo_p
++;
1799 // Increase the size of the demo buffer to allow unlimited demos
1801 static void IncreaseDemoBuffer(void)
1804 byte
*new_demobuffer
;
1808 // Find the current size
1810 current_length
= demoend
- demobuffer
;
1812 // Generate a new buffer twice the size
1813 new_length
= current_length
* 2;
1815 new_demobuffer
= Z_Malloc(new_length
, PU_STATIC
, 0);
1816 new_demop
= new_demobuffer
+ (demo_p
- demobuffer
);
1818 // Copy over the old data
1820 memcpy(new_demobuffer
, demobuffer
, current_length
);
1822 // Free the old buffer and point the demo pointers at the new buffer.
1826 demobuffer
= new_demobuffer
;
1828 demoend
= demobuffer
+ new_length
;
1831 void G_WriteDemoTiccmd (ticcmd_t
* cmd
)
1835 if (gamekeydown
['q']) // press q to end demo recording
1836 G_CheckDemoStatus ();
1838 demo_start
= demo_p
;
1840 *demo_p
++ = cmd
->forwardmove
;
1841 *demo_p
++ = cmd
->sidemove
;
1843 // If this is a longtics demo, record in higher resolution
1847 *demo_p
++ = (cmd
->angleturn
& 0xff);
1848 *demo_p
++ = (cmd
->angleturn
>> 8) & 0xff;
1852 *demo_p
++ = cmd
->angleturn
>> 8;
1855 *demo_p
++ = cmd
->buttons
;
1857 // reset demo pointer back
1858 demo_p
= demo_start
;
1860 if (demo_p
> demoend
- 16)
1862 if (vanilla_demo_limit
)
1865 G_CheckDemoStatus ();
1870 // Vanilla demo limit disabled: unlimited
1873 IncreaseDemoBuffer();
1877 G_ReadDemoTiccmd (cmd
); // make SURE it is exactly the same
1885 void G_RecordDemo (char* name
)
1891 strcpy (demoname
, name
);
1892 strcat (demoname
, ".lmp");
1900 // Specify the demo buffer size (KiB)
1903 i
= M_CheckParm ("-maxdemo");
1904 if (i
&& i
<myargc
-1)
1905 maxsize
= atoi(myargv
[i
+1])*1024;
1906 demobuffer
= Z_Malloc (maxsize
,PU_STATIC
,NULL
);
1907 demoend
= demobuffer
+ maxsize
;
1909 demorecording
= true;
1913 void G_BeginRecording (void)
1920 // Record a high resolution "Doom 1.91" demo.
1923 longtics
= M_CheckParm("-longtics") != 0;
1925 // If not recording a longtics demo, record in low res
1927 lowres_turn
= !longtics
;
1929 demo_p
= demobuffer
;
1931 // Save the right version code for this demo
1935 *demo_p
++ = DOOM_191_VERSION
;
1939 *demo_p
++ = DOOM_VERSION
;
1942 *demo_p
++ = gameskill
;
1943 *demo_p
++ = gameepisode
;
1944 *demo_p
++ = gamemap
;
1945 *demo_p
++ = deathmatch
;
1946 *demo_p
++ = respawnparm
;
1947 *demo_p
++ = fastparm
;
1948 *demo_p
++ = nomonsters
;
1949 *demo_p
++ = consoleplayer
;
1951 for (i
=0 ; i
<MAXPLAYERS
; i
++)
1952 *demo_p
++ = playeringame
[i
];
1962 void G_DeferedPlayDemo (char* name
)
1965 gameaction
= ga_playdemo
;
1968 // Generate a string describing a demo version
1970 static char *DemoVersionDescription(int version
)
1972 static char resultbuf
[16];
1981 return "v1.6/v1.666";
1983 return "v1.7/v1.7a";
1992 // Unknown version. Perhaps this is a pre-v1.4 IWAD? If the version
1993 // byte is in the range 0-4 then it can be a v1.0-v1.2 demo.
1995 if (version
>= 0 && version
<= 4)
1997 return "v1.0/v1.1/v1.2";
2001 sprintf(resultbuf
, "%i.%i (unknown)", version
/ 100, version
% 100);
2006 void G_DoPlayDemo (void)
2009 int i
, episode
, map
;
2012 gameaction
= ga_nothing
;
2013 demobuffer
= demo_p
= W_CacheLumpName (defdemoname
, PU_STATIC
);
2015 demoversion
= *demo_p
++;
2017 if (demoversion
== DOOM_VERSION
)
2021 else if (demoversion
== DOOM_191_VERSION
)
2023 // demo recorded with cph's modified "v1.91" doom exe
2028 char *message
= "Demo is from a different game version!\n"
2029 "(read %i, should be %i)\n"
2031 "*** You may need to upgrade your version "
2032 "of Doom to v1.9. ***\n"
2033 " See: http://doomworld.com/files/patches.shtml\n"
2034 " This appears to be %s.";
2036 I_Error(message
, demoversion
, DOOM_VERSION
,
2037 DemoVersionDescription(demoversion
));
2041 episode
= *demo_p
++;
2043 deathmatch
= *demo_p
++;
2044 respawnparm
= *demo_p
++;
2045 fastparm
= *demo_p
++;
2046 nomonsters
= *demo_p
++;
2047 consoleplayer
= *demo_p
++;
2049 for (i
=0 ; i
<MAXPLAYERS
; i
++)
2050 playeringame
[i
] = *demo_p
++;
2055 // Play back a demo recorded in a netgame with a single player.
2058 if (playeringame
[1] || M_CheckParm("-netdemo") > 0)
2064 // don't spend a lot of time in loadlevel
2066 G_InitNew (skill
, episode
, map
);
2068 starttime
= I_GetTime ();
2071 demoplayback
= true;
2077 void G_TimeDemo (char* name
)
2082 // Disable rendering the screen entirely.
2085 nodrawers
= M_CheckParm ("-nodraw");
2090 // Disable blitting the screen.
2093 noblit
= M_CheckParm ("-noblit");
2098 gameaction
= ga_playdemo
;
2107 = Called after a death or level completion to allow demos to be cleaned up
2108 = Returns true if a new demo loop action will take place
2112 boolean
G_CheckDemoStatus (void)
2121 endtime
= I_GetTime ();
2122 realtics
= endtime
- starttime
;
2123 fps
= ((float) gametic
* TICRATE
) / realtics
;
2125 // Prevent recursive calls
2127 demoplayback
= false;
2129 I_Error ("timed %i gametics in %i realtics (%f fps)",
2130 gametic
, realtics
, fps
);
2135 W_ReleaseLumpName(defdemoname
);
2136 demoplayback
= false;
2140 playeringame
[1] = playeringame
[2] = playeringame
[3] = 0;
2141 respawnparm
= false;
2156 *demo_p
++ = DEMOMARKER
;
2157 M_WriteFile (demoname
, demobuffer
, demo_p
- demobuffer
);
2158 Z_Free (demobuffer
);
2159 demorecording
= false;
2160 I_Error ("Demo %s recorded",demoname
);