- Added skill definitions to MAPINFO.

SVN r558 (trunk)
This commit is contained in:
Christoph Oelckers 2007-11-02 22:03:03 +00:00
parent 170b633e91
commit 52e5f8b8e1
9 changed files with 387 additions and 161 deletions

View file

@ -1,3 +1,6 @@
November 2, 2007 (Changes by Graf Zahl)
- Added skill definitions to MAPINFO.
October 29, 2007 (Changes by Graf Zahl)
- added two new things which can set a sector's color without the need of tags
or scripts. ColorSetter (#9038) sets the sector's color and FadeSetter (#9039)

View file

@ -104,6 +104,7 @@ typedef enum
typedef float skill_t;
/*
enum ESkillLevels
{
sk_baby,
@ -112,6 +113,7 @@ enum ESkillLevels
sk_hard,
sk_nightmare
};
*/

View file

@ -71,6 +71,7 @@
#include "version.h"
#include "m_menu.h"
#include "statnums.h"
#include "vectors.h"
#include "gi.h"
@ -100,6 +101,9 @@ static void SetLevelNum (level_info_t *info, int num);
static void ClearEpisodes ();
static void ClearLevelInfoStrings (level_info_t *linfo);
static void ClearClusterInfoStrings (cluster_info_t *cinfo);
static void ParseSkill ();
static void G_VerifySkill();
static void InitializeDefaultSkills();
static FRandom pr_classchoice ("RandomPlayerClassChoice");
@ -134,6 +138,7 @@ level_locals_t level; // info about current level
static TArray<cluster_info_t> wadclusterinfos;
TArray<level_info_t> wadlevelinfos;
TArray<FSkillInfo> AllSkills;
// MAPINFO is parsed slightly differently when the map name is just a number.
static bool HexenHack;
@ -170,6 +175,8 @@ static const char *MapInfoTopLevel[] =
"clusterdef",
"episode",
"clearepisodes",
"skill",
"clearskills",
NULL
};
@ -179,7 +186,9 @@ enum
MITL_DEFAULTMAP,
MITL_CLUSTERDEF,
MITL_EPISODE,
MITL_CLEAREPISODES
MITL_CLEAREPISODES,
MITL_SKILL,
MITL_CLEARSKILLS,
};
static const char *MapInfoMapLevel[] =
@ -515,6 +524,7 @@ void G_ParseMapInfo ()
int lump, lastlump = 0;
atterm (G_UnloadMapInfo);
InitializeDefaultSkills();
// Parse the default MAPINFO for the current game.
switch (gameinfo.gametype)
@ -564,6 +574,10 @@ void G_ParseMapInfo ()
{
I_FatalError ("You cannot use clearepisodes in a MAPINFO if you do not define any new episodes after it.");
}
if (AllSkills.Size()==0)
{
InitializeDefaultSkills();
}
}
static void G_DoParseMapInfo (int lump)
@ -721,6 +735,15 @@ static void G_DoParseMapInfo (int lump)
case MITL_CLEAREPISODES:
ClearEpisodes ();
break;
case MITL_SKILL:
ParseSkill();
break;
case MITL_CLEARSKILLS:
AllSkills.Clear();
break;
}
}
SC_Close ();
@ -1489,12 +1512,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
}
UnlatchCVars ();
if (gameskill > sk_nightmare)
gameskill = sk_nightmare;
else if (gameskill < sk_baby)
gameskill = sk_baby;
G_VerifySkill();
UnlatchCVars ();
if (paused)
@ -3015,52 +3033,252 @@ static void InitPlayerClasses ()
}
int G_SkillProperty(ESkillProperty prop)
static void ParseSkill ()
{
switch(prop)
FSkillInfo skill;
skill.AmmoFactor = FRACUNIT;
skill.DamageFactor = FRACUNIT;
skill.FastMonsters = false;
skill.DisableCheats = false;
skill.EasyBossBrain = false;
skill.AutoUseHealth = false;
skill.RespawnCounter = 0;
skill.Aggressiveness = FRACUNIT;
skill.SpawnFilter = 0;
skill.ACSReturn = AllSkills.Size();
skill.MenuNameIsLump = false;
skill.MustConfirm = false;
skill.shortcut=0;
SC_MustGetString();
skill.name = sc_String;
while (SC_GetString ())
{
case SKILLP_AmmoFactor:
if (gameskill == sk_baby || (gameskill == sk_nightmare && gameinfo.gametype != GAME_Strife))
if (SC_Compare ("ammofactor"))
{
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
return FRACUNIT;
else
return FRACUNIT*3/2;
SC_MustGetFloat ();
skill.AmmoFactor = FLOAT2FIXED(sc_Float);
}
return FRACUNIT;
case SKILLP_DamageFactor:
if (gameskill == sk_baby) return FRACUNIT/2;
return FRACUNIT;
case SKILLP_FastMonsters:
return (gameskill == sk_nightmare || (dmflags & DF_FAST_MONSTERS));
case SKILLP_Respawn:
if (dmflags & DF_MONSTERS_RESPAWN ||
gameinfo.gametype & (GAME_DoomStrife) && gameskill == sk_nightmare)
else if (SC_Compare ("damagefactor"))
{
return TICRATE * (gameinfo.gametype != GAME_Strife ? 12 : 16);
SC_MustGetFloat ();
skill.AmmoFactor = FLOAT2FIXED(sc_Float);
}
else if (SC_Compare ("fastmonsters"))
{
skill.FastMonsters = true;
}
else if (SC_Compare ("disablecheats"))
{
skill.DisableCheats = true;
}
else if (SC_Compare ("easybossbrain"))
{
skill.EasyBossBrain = true;
}
else if (SC_Compare("autousehealth"))
{
skill.AutoUseHealth = true;
}
else if (SC_Compare("respawntime"))
{
SC_MustGetFloat ();
skill.RespawnCounter = int(sc_Float*TICRATE);
}
else if (SC_Compare("Aggressiveness"))
{
SC_MustGetFloat ();
skill.Aggressiveness = FRACUNIT - FLOAT2FIXED(clamp<float>(sc_Float, 0,1));
}
else if (SC_Compare("SpawnFilter"))
{
SC_MustGetString ();
strlwr(sc_String);
if (strstr(sc_String, "easy")) skill.SpawnFilter|=MTF_EASY;
if (strstr(sc_String, "normal")) skill.SpawnFilter|=MTF_NORMAL;
if (strstr(sc_String, "hard")) skill.SpawnFilter|=MTF_HARD;
}
else if (SC_Compare("ACSReturn"))
{
SC_MustGetNumber ();
skill.ACSReturn = sc_Number;
}
else if (SC_Compare("MenuName"))
{
SC_MustGetString ();
skill.MenuName = sc_String;
skill.MenuNameIsLump = false;
}
else if (SC_Compare("MenuLump"))
{
SC_MustGetString ();
skill.MenuName = sc_String;
skill.MenuNameIsLump = true;
}
else if (SC_Compare("MustConfirm"))
{
skill.MustConfirm = true;
}
else
{
return 0;
SC_UnGet ();
break;
}
}
for(int i=0;i<AllSkills.Size();i++)
{
if (AllSkills[i].name == skill.name)
{
AllSkills[i] = skill;
return;
}
}
AllSkills.Push(skill);
}
case SKILLP_Aggressiveness:
return FRACUNIT;
int G_SkillProperty(ESkillProperty prop)
{
if (AllSkills.Size() > 0)
{
switch(prop)
{
case SKILLP_AmmoFactor:
return AllSkills[gameskill].AmmoFactor;
case SKILLP_DisableCheats:
return gameskill == sk_nightmare;
case SKILLP_DamageFactor:
return AllSkills[gameskill].DamageFactor;
case SKILLP_AutoUseHealth:
return gameskill == sk_baby;
case SKILLP_FastMonsters:
return AllSkills[gameskill].FastMonsters || (dmflags & DF_FAST_MONSTERS);
case SKILLP_EasyBossBrain:
return gameskill == sk_baby;
case SKILLP_Respawn:
if (dmflags & DF_MONSTERS_RESPAWN && AllSkills[gameskill].RespawnCounter==0)
return TICRATE * (gameinfo.gametype != GAME_Strife ? 12 : 16);
return AllSkills[gameskill].RespawnCounter;
case SKILLP_SpawnFilter:
return gameskill <= sk_easy? MTF_EASY : gameskill == sk_medium? MTF_NORMAL : MTF_HARD;
case SKILLP_Aggressiveness:
return AllSkills[gameskill].Aggressiveness;
case SKILLP_DisableCheats:
return AllSkills[gameskill].DisableCheats;
case SKILLP_AutoUseHealth:
return AllSkills[gameskill].AutoUseHealth;
case SKILLP_EasyBossBrain:
return AllSkills[gameskill].EasyBossBrain;
case SKILLP_SpawnFilter:
return AllSkills[gameskill].SpawnFilter;
case SKILLP_ACSReturn:
return AllSkills[gameskill].ACSReturn;
}
}
return 0;
}
static void InitializeDefaultSkills()
{
FSkillInfo skill;
EGameType g = gameinfo.gametype;
skill.shortcut=0;
// sk_baby
skill.name = "baby";
skill.AmmoFactor = (g & GAME_DoomStrife) ? FRACUNIT*2 : FRACUNIT*3/2;
skill.DamageFactor = FRACUNIT/2;
skill.FastMonsters = false;
skill.DisableCheats = false;
skill.EasyBossBrain = true;
skill.AutoUseHealth = true;
skill.RespawnCounter = 0;
skill.Aggressiveness = FRACUNIT;
skill.SpawnFilter = MTF_EASY;
skill.ACSReturn = 0;
skill.MenuName = g&GAME_DoomStrife ? "M_JKILL" : "MNU_WETNURSE";
skill.MenuNameIsLump = !!(g&GAME_DoomStrife);
skill.MustConfirm = false;
if (g & GAME_Hexen)
{
skill.MenuNamesForPlayerClass["fighter"] = "MNU_SQUIRE";
skill.MenuNamesForPlayerClass["cleric"] = "MNU_ALTARBOY";
skill.MenuNamesForPlayerClass["mage"] = "MNU_APPRENTICE";
}
AllSkills.Push(skill);
// sk_easy
skill.name = "easy";
skill.AmmoFactor = FRACUNIT;
skill.DamageFactor = FRACUNIT;
skill.EasyBossBrain = false;
skill.AutoUseHealth = false;
skill.RespawnCounter = 0;
skill.Aggressiveness = FRACUNIT;
skill.SpawnFilter = MTF_EASY;
skill.ACSReturn = 1;
skill.MenuName = g&GAME_DoomStrife ? "M_ROUGH" : "MNU_YELLOWBELLIES";
if (g & GAME_Hexen)
{
skill.MenuNamesForPlayerClass["fighter"] = "MNU_KNIGHT";
skill.MenuNamesForPlayerClass["cleric"] = "MNU_ACOLYTE";
skill.MenuNamesForPlayerClass["mage"] = "MNU_ENCHANTER";
}
AllSkills.Push(skill);
// sk_normal
skill.name = "normal";
skill.SpawnFilter = MTF_NORMAL;
skill.ACSReturn = 2;
skill.MenuName = g&GAME_DoomStrife ? "M_HURT" : "MNU_BRINGEST";
if (g & GAME_Hexen)
{
skill.MenuNamesForPlayerClass["fighter"] = "MNU_WARRIOR";
skill.MenuNamesForPlayerClass["cleric"] = "MNU_PRIEST";
skill.MenuNamesForPlayerClass["mage"] = "MNU_SORCERER";
}
AllSkills.Push(skill);
// sk_hard
skill.name = "hard";
skill.SpawnFilter = MTF_HARD;
skill.ACSReturn = 3;
skill.MenuName = g&GAME_DoomStrife ? "M_ULTRA" : "MNU_SMITE";
if (g & GAME_Hexen)
{
skill.MenuNamesForPlayerClass["fighter"] = "MNU_BERSERKER";
skill.MenuNamesForPlayerClass["cleric"] = "MNU_CARDINAL";
skill.MenuNamesForPlayerClass["mage"] = "MNU_WARLOCK";
}
AllSkills.Push(skill);
// sk_nightmare
skill.name = "nightmare";
skill.AmmoFactor = (g & GAME_DoomStrife) ? FRACUNIT*2 : FRACUNIT*3/2;
skill.DamageFactor = FRACUNIT;
skill.FastMonsters = true;
skill.DisableCheats = true;
skill.RespawnCounter = (g & GAME_Raven)? 0 : TICRATE * (g != GAME_Strife ? 12 : 16);
skill.Aggressiveness = FRACUNIT;
skill.ACSReturn = 4;
skill.MenuName = g&GAME_DoomStrife ? "M_NMARE" : "MNU_BLACKPLAGUE";
skill.MustConfirm = true;
if (g & GAME_Hexen)
{
skill.MenuNamesForPlayerClass["fighter"] = "MNU_TITAN";
skill.MenuNamesForPlayerClass["cleric"] = "MNU_POPE";
skill.MenuNamesForPlayerClass["mage"] = "MNU_ARCHMAGE";
}
AllSkills.Push(skill);
}
void G_VerifySkill()
{
if (gameskill >= AllSkills.Size())
gameskill = AllSkills.Size()-1;
else if (gameskill < 0)
gameskill = 0;
}

View file

@ -365,8 +365,61 @@ enum ESkillProperty
SKILLP_AutoUseHealth,
SKILLP_SpawnFilter,
SKILLP_EasyBossBrain,
SKILLP_ACSReturn,
SKILLP_Confirm,
};
int G_SkillProperty(ESkillProperty prop);
typedef TMap<FName, FString> SkillMenuNames;
struct FSkillInfo
{
FName name;
fixed_t AmmoFactor;
fixed_t DamageFactor;
bool FastMonsters;
bool DisableCheats;
bool AutoUseHealth;
bool EasyBossBrain;
int RespawnCounter;
fixed_t Aggressiveness;
int SpawnFilter;
int ACSReturn;
FString MenuName;
SkillMenuNames MenuNamesForPlayerClass;
bool MenuNameIsLump;
bool MustConfirm;
char shortcut;
FSkillInfo() {}
FSkillInfo(const FSkillInfo &other)
{
operator=(other);
}
FSkillInfo &operator=(const FSkillInfo &other)
{
name = other.name;
AmmoFactor = other.AmmoFactor;
DamageFactor = other.DamageFactor;
FastMonsters = other.FastMonsters;
DisableCheats = other.DisableCheats;
AutoUseHealth = other.AutoUseHealth;
EasyBossBrain = other.EasyBossBrain;
RespawnCounter= other.RespawnCounter;
Aggressiveness= other.Aggressiveness;
SpawnFilter = other.SpawnFilter;
ACSReturn = other.ACSReturn;
MenuName = other.MenuName;
MenuNamesForPlayerClass = other.MenuNamesForPlayerClass;
MenuNameIsLump = other.MenuNameIsLump;
MustConfirm = other.MustConfirm;
shortcut = other.shortcut;
return *this;
}
};
extern TArray<FSkillInfo> AllSkills;
#endif //__G_LEVEL_H__

View file

@ -11,6 +11,7 @@
#include "d_event.h"
#include "a_keys.h"
#include "c_console.h"
#include "templates.h"
// Degnin Ore ---------------------------------------------------------------
@ -461,7 +462,8 @@ bool AHealthFillup::TryPickup (AActor *toucher)
{
static const int skillhealths[5] = { -100, -75, -50, -50, -100 };
if (!P_GiveBody (toucher, skillhealths[gameskill]))
int index = clamp<int>(gameskill, 0,4);
if (!P_GiveBody (toucher, skillhealths[index]))
{
return false;
}

View file

@ -377,66 +377,80 @@ static oldmenu_t FilesMenu =
//
// DOOM SKILL SELECT
//
static oldmenuitem_t NewGameMenu[]=
{
{1,0,'i',"M_JKILL",M_ChooseSkill},
{1,0,'h',"M_ROUGH",M_ChooseSkill},
{1,0,'h',"M_HURT",M_ChooseSkill},
{1,0,'u',"M_ULTRA",M_ChooseSkill},
{1,0,'n',"M_NMARE",M_ChooseSkill}
static oldmenuitem_t SkillSelectMenu[]={
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
{ 1, 0, 0, "", M_ChooseSkill},
};
static oldmenu_t NewDef =
static oldmenu_t SkillDef =
{
countof(NewGameMenu),
NewGameMenu, // oldmenuitem_t ->
0,
SkillSelectMenu, // oldmenuitem_t ->
M_DrawNewGame, // drawing routine ->
48,63, // x,y
2 // lastOn
};
//
// HERETIC SKILL SELECT
//
static oldmenuitem_t HereticSkillItems[] =
{
{1,1,'t',"MNU_WETNURSE",M_ChooseSkill},
{1,1,'y',"MNU_YELLOWBELLIES",M_ChooseSkill},
{1,1,'b',"MNU_BRINGEST",M_ChooseSkill},
{1,1,'t',"MNU_SMITE",M_ChooseSkill},
{1,1,'b',"MNU_BLACKPLAGUE",M_ChooseSkill}
};
static oldmenu_t HereticSkillMenu =
{
countof(HereticSkillItems),
HereticSkillItems,
M_DrawNewGame,
38, 30,
2
};
//
// HEXEN SKILL SELECT
//
static oldmenuitem_t HexenSkillItems[] =
{
{ 1,1, '1', NULL, M_ChooseSkill },
{ 1,1, '2', NULL, M_ChooseSkill },
{ 1,1, '3', NULL, M_ChooseSkill },
{ 1,1, '4', NULL, M_ChooseSkill },
{ 1,1, '5', NULL, M_ChooseSkill }
};
static oldmenu_t HexenSkillMenu =
{
5, HexenSkillItems,
0,
SkillSelectMenu, // oldmenuitem_t ->
DrawHexenSkillMenu,
120, 44,
2
};
void M_StartupSkillMenu(const char *playerclass)
{
if (gameinfo.gametype & GAME_Raven)
{
SkillDef.x = 38;
SkillDef.y = 30;
}
SkillDef.numitems = HexenSkillMenu.numitems = 0;
for(int i=0;i<AllSkills.Size() && i<8;i++)
{
FSkillInfo &skill = AllSkills[i];
SkillSelectMenu[i].name = skill.MenuName;
SkillSelectMenu[i].fulltext = !skill.MenuNameIsLump;
SkillSelectMenu[i].alphaKey = skill.MenuNameIsLump? skill.shortcut : tolower(SkillSelectMenu[i].name[0]);
if (playerclass != NULL)
{
FString * pmnm = skill.MenuNamesForPlayerClass.CheckKey(playerclass);
if (pmnm != NULL)
{
SkillSelectMenu[i].name = *pmnm;
SkillSelectMenu[i].fulltext = true;
SkillSelectMenu[i].alphaKey = tolower(pmnm->GetChars()[0]);
}
}
SkillDef.numitems++;
HexenSkillMenu.numitems++;
}
// Hexen needs some manual coordinate adjustments based on player class
if (gameinfo.gametype == GAME_Hexen)
{
if (!stricmp(playerclass, "fighter")) HexenSkillMenu.x = 120;
else if (!stricmp(playerclass, "cleric")) HexenSkillMenu.x = 116;
else if (!stricmp(playerclass, "mage")) HexenSkillMenu.x = 112;
else HexenSkillMenu.x = 38;
M_SetupNextMenu(&HexenSkillMenu);
}
else
M_SetupNextMenu(&SkillDef);
}
//
// [RH] Player Setup Menu
//
@ -1579,14 +1593,11 @@ void M_NewGame(int choice)
{
M_ChooseSkill(2);
}
else if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
{
M_SetupNextMenu (&NewDef);
}
else
{
M_SetupNextMenu (&HereticSkillMenu);
M_StartupSkillMenu(NULL);
}
}
else
{
@ -1719,7 +1730,7 @@ void M_VerifyNightmare (int ch)
void M_ChooseSkill (int choice)
{
if (gameinfo.gametype == GAME_Doom && choice == NewDef.numitems - 1)
if (gameinfo.gametype == GAME_Doom && AllSkills[choice].MustConfirm)
{
M_StartMessage (GStrings("NIGHTMARE"), M_VerifyNightmare, true);
return;
@ -1758,59 +1769,7 @@ void M_Episode (int choice)
return;
}
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
M_SetupNextMenu (&NewDef);
else if (gameinfo.gametype == GAME_Hexen)
M_SetupNextMenu (&HexenSkillMenu);
else
M_SetupNextMenu (&HereticSkillMenu);
}
//==========================================================================
//
// Sets Hexen's skill menu according to player class
//
//==========================================================================
static void SetHexenSkillMenu (const char * pclass)
{
if (!stricmp(pclass, "fighter"))
{
HexenSkillMenu.x = 120;
HexenSkillItems[0].name = "MNU_SQUIRE";
HexenSkillItems[1].name = "MNU_KNIGHT";
HexenSkillItems[2].name = "MNU_WARRIOR";
HexenSkillItems[3].name = "MNU_BERSERKER";
HexenSkillItems[4].name = "MNU_TITAN";
}
else if (!stricmp(pclass, "cleric"))
{
HexenSkillMenu.x = 116;
HexenSkillItems[0].name = "MNU_ALTARBOY";
HexenSkillItems[1].name = "MNU_ACOLYTE";
HexenSkillItems[2].name = "MNU_PRIEST";
HexenSkillItems[3].name = "MNU_CARDINAL";
HexenSkillItems[4].name = "MNU_POPE";
}
else if (!stricmp(pclass, "mage"))
{
HexenSkillMenu.x = 112;
HexenSkillItems[0].name = "MNU_APPRENTICE";
HexenSkillItems[1].name = "MNU_ENCHANTER";
HexenSkillItems[2].name = "MNU_SORCERER";
HexenSkillItems[3].name = "MNU_WARLOCK";
HexenSkillItems[4].name = "MNU_ARCHMAGE";
}
else
{
// Use Heretic's menu titles as default
HexenSkillMenu.x = HereticSkillMenu.x;
HexenSkillItems[0].name = HereticSkillItems[0].name;
HexenSkillItems[1].name = HereticSkillItems[1].name;
HexenSkillItems[2].name = HereticSkillItems[2].name;
HexenSkillItems[3].name = HereticSkillItems[3].name;
HexenSkillItems[4].name = HereticSkillItems[4].name;
}
M_StartupSkillMenu(NULL);
}
//==========================================================================
@ -1832,15 +1791,13 @@ static void SCClass (int option)
else
playerclass = PlayerClasses[option].Type->Meta.GetMetaString (APMETA_DisplayName);
SetHexenSkillMenu(playerclass);
if (EpiDef.numitems > 1)
{
M_SetupNextMenu (&EpiDef);
}
else if (!EpisodeNoSkill[0])
{
M_SetupNextMenu (&HexenSkillMenu);
M_StartupSkillMenu(playerclass);
}
else
{
@ -1858,7 +1815,6 @@ static void M_ChooseClass (int choice)
}
playerclass = (choice < ClassMenuDef.numitems-1) ? ClassMenuItems[choice].name : "Random";
SetHexenSkillMenu(playerclass);
if (EpiDef.numitems > 1)
{
@ -1868,17 +1824,9 @@ static void M_ChooseClass (int choice)
{
M_ChooseSkill(2);
}
else if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
else
{
M_SetupNextMenu (&NewDef);
}
else if (gameinfo.gametype == GAME_Hexen)
{
M_SetupNextMenu (&HexenSkillMenu);
}
else
{
M_SetupNextMenu (&HereticSkillMenu);
M_StartupSkillMenu(playerclass);
}
}
@ -3375,7 +3323,7 @@ void M_Init (void)
if (gameinfo.gametype == GAME_Strife)
{
MainDef.y = 45;
NewDef.lastOn = 1;
//NewDef.lastOn = 1;
}
}
else

View file

@ -3923,7 +3923,7 @@ int DLevelScript::RunScript ()
break;
case PCD_GAMESKILL:
PushToStack (gameskill);
PushToStack (G_SkillProperty(SKILLP_ACSReturn));
break;
// [BC] Start ST PCD's

View file

@ -2516,7 +2516,7 @@ FUNC(LS_Autosave)
FUNC(LS_ChangeSkill)
{
if (arg0 < sk_baby || arg0 > sk_nightmare)
if (arg0 < 0 || arg0 > AllSkills.Size())
{
NextSkill = -1;
}

View file

@ -1608,7 +1608,7 @@ void P_MovePlayer (player_t *player)
fprintf (debugfile, "]\n");
}
if (!(player->cheats & CF_PREDICTING))
if (!(player->cheats & CF_PREDICTING) && (forwardmove|sidemove))
{
player->mo->PlayRunning ();
}