diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 81ba0113..308d5361 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -132,10 +132,10 @@ FBaseCVar::~FBaseCVar () } } -void FBaseCVar::ForceSet (UCVarValue value, ECVarType type) +void FBaseCVar::ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend) { DoSet (value, type); - if ((Flags & CVAR_USERINFO) && !(Flags & CVAR_NOSEND)) + if ((Flags & CVAR_USERINFO) && !nouserinfosend && !(Flags & CVAR_IGNORE)) D_UserInfoChanged (this); if (m_UseCallback) Callback (); @@ -1275,7 +1275,7 @@ void FilterCompactCVars (TArray &cvars, DWORD filter) // Accumulate all cvars that match the filter flags. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_NOSEND)) + if ((cvar->Flags & filter) && !(cvar->Flags & CVAR_IGNORE)) cvars.Push(cvar); } // Now sort them, so they're in a deterministic order and not whatever @@ -1314,7 +1314,7 @@ FString C_GetMassCVarString (DWORD filter, bool compact) { for (cvar = CVars; cvar != NULL; cvar = cvar->m_Next) { - if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_NOSEND))) + if ((cvar->Flags & filter) && !(cvar->Flags & (CVAR_NOSAVE|CVAR_IGNORE))) { UCVarValue val = cvar->GetGenericRep(CVAR_String); dump << '\\' << cvar->GetName() << '\\' << val.String; @@ -1539,7 +1539,7 @@ void C_ArchiveCVars (FConfigFile *f, uint32 filter) while (cvar) { if ((cvar->Flags & - (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) + (CVAR_GLOBALCONFIG|CVAR_ARCHIVE|CVAR_MOD|CVAR_AUTO|CVAR_USERINFO|CVAR_SERVERINFO|CVAR_NOSAVE)) == filter) { UCVarValue val; @@ -1670,16 +1670,16 @@ void FBaseCVar::ListVars (const char *filter, bool plain) else { ++count; - Printf ("%c%c%c%c %s = %s\n", - flags & CVAR_ARCHIVE ? 'A' : - flags & CVAR_MODARCHIVE ? 'M' : ' ', + Printf ("%c%c%c%c%c %s = %s\n", + flags & CVAR_ARCHIVE ? 'A' : ' ', flags & CVAR_USERINFO ? 'U' : flags & CVAR_SERVERINFO ? 'S' : flags & CVAR_AUTO ? 'C' : ' ', flags & CVAR_NOSET ? '-' : flags & CVAR_LATCH ? 'L' : flags & CVAR_UNSETTABLE ? '*' : ' ', - flags & CVAR_NOSEND ? 'X' : ' ', + flags & CVAR_MOD ? 'M' : ' ', + flags & CVAR_IGNORE ? 'X' : ' ', var->GetName(), var->GetGenericRep (CVAR_String).String); } diff --git a/src/c_cvars.h b/src/c_cvars.h index 744643d8..f1bf254b 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -61,8 +61,8 @@ enum CVAR_GLOBALCONFIG = 1024, // cvar is saved to global config section CVAR_VIDEOCONFIG = 2048, // cvar is saved to video config section (not implemented) CVAR_NOSAVE = 4096, // when used with CVAR_SERVERINFO, do not save var to savegame - CVAR_MODARCHIVE = 8192, // cvar will be saved to a mod-specific section of the ini - CVAR_NOSEND = 16384,// do not send cvar across the network (dummy mod cvar) + CVAR_MOD = 8192, // cvar was defined by a mod + CVAR_IGNORE = 16384,// do not send cvar across the network/inaccesible from ACS (dummy mod cvar) }; union UCVarValue @@ -101,7 +101,7 @@ public: inline FBaseCVar *GetNext() const { return m_Next; } void CmdSet (const char *newval); - void ForceSet (UCVarValue value, ECVarType type); + void ForceSet (UCVarValue value, ECVarType type, bool nouserinfosend=false); void SetGenericRep (UCVarValue value, ECVarType type); void ResetToDefault (); void SetArchiveBit () { Flags |= CVAR_ARCHIVE; } diff --git a/src/d_main.cpp b/src/d_main.cpp index 0f66f68a..6c92babe 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1379,7 +1379,7 @@ void ParseCVarInfo() FString cvarname; char *cvardefault = NULL; ECVarType cvartype = CVAR_Dummy; - int cvarflags = CVAR_MODARCHIVE; + int cvarflags = CVAR_MOD|CVAR_ARCHIVE; FBaseCVar *cvar; // Check for flag tokens. @@ -1395,7 +1395,7 @@ void ParseCVarInfo() } else if (stricmp(sc.String, "noarchive") == 0) { - cvarflags &= ~CVAR_MODARCHIVE; + cvarflags &= ~CVAR_ARCHIVE; } else { diff --git a/src/d_net.cpp b/src/d_net.cpp index 902d912b..0ea8e58c 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -108,6 +108,8 @@ int resendcount[MAXNETNODES]; unsigned int lastrecvtime[MAXPLAYERS]; // [RH] Used for pings unsigned int currrecvtime[MAXPLAYERS]; +unsigned int lastglobalrecvtime; // Identify the last time a packet was recieved. +bool hadlate; int nodeforplayer[MAXPLAYERS]; int playerfornode[MAXNETNODES]; @@ -311,6 +313,8 @@ void Net_ClearBuffers () oldentertics = entertic; gametic = 0; maketic = 0; + + lastglobalrecvtime = 0; } // @@ -700,6 +704,8 @@ void GetPackets (void) } continue; // extra setup packet } + + lastglobalrecvtime = I_GetTime (false); //Update the last time a packet was recieved netnode = doomcom.remotenode; netconsole = playerfornode[netnode] & ~PL_DRONE; @@ -1820,6 +1826,33 @@ void TryRunTics (void) if (lowtic < gametic) I_Error ("TryRunTics: lowtic < gametic"); + // [Ed850] Check to see the last time a packet was recieved. + // If it's longer then 3 seconds, a node has likely stalled. Check which one and re-request its last packet. + if(I_GetTime(false) - lastglobalrecvtime >= TICRATE*3) + { + int latenode = 0; // Node 0 is the local player, and should always be the highest + lastglobalrecvtime = I_GetTime(false); //Bump the count + + if(NetMode == NET_PeerToPeer || consoleplayer == Net_Arbitrator) + { + for (i = 0; i < doomcom.numnodes; i++) + if (nodeingame[i] && nettics[i] < nettics[latenode]) + latenode = i; + } + else if (nodeingame[nodeforplayer[Net_Arbitrator]] && + nettics[nodeforplayer[Net_Arbitrator]] < nettics[0]) + { // Likely a packet server game. Only check the packet host. + latenode = Net_Arbitrator; + } + + if (debugfile) + fprintf (debugfile, "lost tics from %i (%i to %i)\n", + latenode, nettics[latenode], gametic); + + if(latenode != 0) // Send resend request to late node (if not yourself... somehow). Also mark the node as waiting to display it in the hud. + remoteresend[latenode] = players[playerfornode[latenode]].waiting = hadlate = true; + } + // don't stay in here forever -- give the menu a chance to work if (I_GetTime (false) - entertic >= TICRATE/3) { @@ -1829,6 +1862,13 @@ void TryRunTics (void) } } + if (hadlate) + { + hadlate = false; + for (i = 0; i < MAXPLAYERS; i++) + players[i].waiting = false; + } + // run the count tics if (counts > 0) { diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 2f75d837..7f94ef68 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -378,7 +378,7 @@ void D_SetupUserInfo () for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { FBaseCVar **newcvar; FName cvarname(cvar->GetName()); @@ -416,7 +416,7 @@ void userinfo_t::Reset() // Create userinfo vars for this player, initialized to their defaults. for (FBaseCVar *cvar = CVars; cvar != NULL; cvar = cvar->GetNext()) { - if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_NOSEND)) == CVAR_USERINFO) + if ((cvar->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO) { ECVarType type; FName cvarname(cvar->GetName()); @@ -430,7 +430,7 @@ void userinfo_t::Reset() case NAME_PlayerClass: type = CVAR_Int; break; default: type = cvar->GetRealType(); break; } - newcvar = C_CreateCVar(NULL, type, 0); + newcvar = C_CreateCVar(NULL, type, cvar->GetFlags() & CVAR_MOD); newcvar->SetGenericRepDefault(cvar->GetGenericRepDefault(CVAR_String), CVAR_String); Insert(cvarname, newcvar); } diff --git a/src/d_player.h b/src/d_player.h index e8c18314..6169dceb 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -404,6 +404,7 @@ public: int timefreezer; // Player has an active time freezer short refire; // refired shots are less accurate short inconsistant; + bool waiting; int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing int hazardcount; // for delayed Strife damage diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 230e457d..3d8c6200 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -424,6 +424,7 @@ private: bool RepositionCoords (int &x, int &y, int xo, int yo, const int w, const int h) const; void DrawMessages (int layer, int bottom); void DrawConsistancy () const; + void DrawWaiting () const; TObjPtr Messages[NUM_HUDMSGLAYERS]; bool ShowLog; diff --git a/src/g_shared/shared_sbar.cpp b/src/g_shared/shared_sbar.cpp index fd543f19..0ceea11a 100644 --- a/src/g_shared/shared_sbar.cpp +++ b/src/g_shared/shared_sbar.cpp @@ -1511,6 +1511,7 @@ void DBaseStatusBar::DrawTopStuff (EHudState state) } DrawMessages (HUDMSGLayer_OverHUD, (state == HUD_StatusBar) ? ::ST_Y : SCREENHEIGHT); DrawConsistancy (); + DrawWaiting (); if (ShowLog && MustDrawLog(state)) DrawLog (); if (noisedebug) @@ -1612,6 +1613,39 @@ void DBaseStatusBar::DrawConsistancy () const } } +void DBaseStatusBar::DrawWaiting () const +{ + int i; + char conbuff[64], *buff_p; + + if (!netgame) + return; + + buff_p = NULL; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && players[i].waiting) + { + if (buff_p == NULL) + { + strcpy (conbuff, "Waiting for:"); + buff_p = conbuff + 12; + } + *buff_p++ = ' '; + *buff_p++ = '1' + i; + *buff_p = 0; + } + } + + if (buff_p != NULL) + { + screen->DrawText (SmallFont, CR_ORANGE, + (screen->GetWidth() - SmallFont->StringWidth (conbuff)*CleanXfac) / 2, + SmallFont->GetHeight()*CleanYfac, conbuff, DTA_CleanNoMove, true, TAG_DONE); + BorderTopRefresh = screen->GetPageCount (); + } +} + void DBaseStatusBar::FlashItem (const PClass *itemtype) { } diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index ddb331cf..2b97bf4b 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -453,12 +453,12 @@ void FGameConfigFile::DoModSetup(const char *gamename) mysnprintf(section, countof(section), "%s.Player.Mod", gamename); if (SetSection(section)) { - ReadCVars(CVAR_MODARCHIVE|CVAR_USERINFO|CVAR_NOSEND); + ReadCVars(CVAR_MOD|CVAR_USERINFO|CVAR_IGNORE); } mysnprintf(section, countof(section), "%s.LocalServerInfo.Mod", gamename); if (SetSection (section)) { - ReadCVars (CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + ReadCVars (CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE); } // Signal that these sections should be rewritten when saving the config. bModSetup = true; @@ -476,7 +476,7 @@ void FGameConfigFile::ReadNetVars () mysnprintf(subsection, sublen, "NetServerInfo.Mod"); if (SetSection(section)) { - ReadCVars(CVAR_MODARCHIVE|CVAR_SERVERINFO|CVAR_NOSEND); + ReadCVars(CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE); } } } @@ -489,11 +489,7 @@ void FGameConfigFile::ReadCVars (DWORD flags) FBaseCVar *cvar; UCVarValue val; - if (!(flags & CVAR_MODARCHIVE)) - { - flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE; - } - flags |= CVAR_AUTO; + flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE|CVAR_AUTO; while (NextInSection (key, value)) { cvar = FindCVar (key, NULL); @@ -523,7 +519,7 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strncpy (subsection + 6, ".Mod", sublen - 6); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_USERINFO); + C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_USERINFO); } strncpy (subsection, "ConsoleVariables", sublen); @@ -545,7 +541,7 @@ void FGameConfigFile::ArchiveGameData (const char *gamename) strncpy (subsection, netgame ? "NetServerInfo.Mod" : "LocalServerInfo.Mod", sublen); SetSection (section, true); ClearCurrentSection (); - C_ArchiveCVars (this, CVAR_MODARCHIVE|CVAR_AUTO|CVAR_SERVERINFO); + C_ArchiveCVars (this, CVAR_MOD|CVAR_ARCHIVE|CVAR_AUTO|CVAR_SERVERINFO); } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index a8469f46..f251ab2e 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3474,6 +3474,9 @@ enum EACSFunctions ACSF_VectorLength, ACSF_SetHUDClipRect, ACSF_SetHUDWrapWidth, + ACSF_SetCVar, + ACSF_GetUserCVar, + ACSF_SetUserCVar, // ZDaemon ACSF_GetTeamScore = 19620, // (int team) @@ -3573,6 +3576,145 @@ static int GetUserVariable(AActor *self, FName varname, int index) return 0; } +// Converts fixed- to floating-point as required. +static void DoSetCVar(FBaseCVar *cvar, int value, bool force=false) +{ + UCVarValue val; + ECVarType type; + + // For serverinfo variables, only the arbitrator should set it. + // The actual change to this cvar will not show up until it's + // been replicated to all peers. + if ((cvar->GetFlags() & CVAR_SERVERINFO) && consoleplayer != Net_Arbitrator) + { + return; + } + if (cvar->GetRealType() == CVAR_Float) + { + val.Float = FIXED2FLOAT(value); + type = CVAR_Float; + } + else + { + val.Int = value; + type = CVAR_Int; + } + if (force) + { + cvar->ForceSet(val, type, true); + } + else + { + cvar->SetGenericRep(val, type); + } +} + +// Converts floating- to fixed-point as required. +static int DoGetCVar(FBaseCVar *cvar) +{ + UCVarValue val; + + if (cvar->GetRealType() == CVAR_Float) + { + val = cvar->GetGenericRep(CVAR_Float); + return FLOAT2FIXED(val.Float); + } + else + { + val = cvar->GetGenericRep(CVAR_Int); + return val.Int; + } +} + +static int GetUserCVar(int playernum, const char *cvarname) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return 0; + } + FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar *cvar; + if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE)) + { + return 0; + } + return DoGetCVar(cvar); +} + +static int GetCVar(AActor *activator, const char *cvarname) +{ + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. + if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE)) + { + return 0; + } + else + { + // For userinfo cvars, redirect to GetUserCVar + if (cvar->GetFlags() & CVAR_USERINFO) + { + if (activator == NULL || activator->player == NULL) + { + return 0; + } + return GetUserCVar(int(activator->player - players), cvarname); + } + return DoGetCVar(cvar); + } +} + +static int SetUserCVar(int playernum, const char *cvarname, int value) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return 0; + } + FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar *cvar; + // Only mod-created cvars may be set. + if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE) || !(cvar->GetFlags() & CVAR_MOD)) + { + return 0; + } + DoSetCVar(cvar, value); + + // If we are this player, then also reflect this change in the local version of this cvar. + if (playernum == consoleplayer) + { + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // If we can find it in the userinfo, then we should also be able to find it in the normal cvar list, + // but check just to be safe. + if (cvar != NULL) + { + DoSetCVar(cvar, value, true); + } + } + + return 1; +} + +static int SetCVar(AActor *activator, const char *cvarname, int value) +{ + FBaseCVar *cvar = FindCVar(cvarname, NULL); + // Only mod-created cvars may be set. + if (cvar == NULL || (cvar->GetFlags() & (CVAR_IGNORE|CVAR_NOSET)) || !(cvar->GetFlags() & CVAR_MOD)) + { + return 0; + } + // For userinfo cvars, redirect to SetUserCVar + if (cvar->GetFlags() & CVAR_USERINFO) + { + if (activator == NULL || activator->player == NULL) + { + return 0; + } + return SetUserCVar(int(activator->player - players), cvarname, value); + } + DoSetCVar(cvar, value); + return 1; +} + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) { AActor *actor; @@ -4017,6 +4159,27 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) WrapWidth = argCount > 0 ? args[0] : 0; break; + case ACSF_GetUserCVar: + if (argCount == 2) + { + return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])); + } + break; + + case ACSF_SetUserCVar: + if (argCount == 3) + { + return SetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), args[2]); + } + break; + + case ACSF_SetCVar: + if (argCount == 2) + { + return SetCVar(activator, FBehavior::StaticLookupString(args[0]), args[1]); + } + break; + default: break; } @@ -6883,19 +7046,7 @@ scriptwait: break; case PCD_GETCVAR: - { - FBaseCVar *cvar = FindCVar (FBehavior::StaticLookupString (STACK(1)), NULL); - // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. - if (cvar == NULL || (cvar->GetFlags() & CVAR_NOSEND)) - { - STACK(1) = 0; - } - else - { - UCVarValue val = cvar->GetGenericRep (CVAR_Int); - STACK(1) = val.Int; - } - } + STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1))); break; case PCD_SETHUDSIZE: diff --git a/src/svnrevision.h b/src/svnrevision.h index 7fc60272..c3423b7e 100644 --- a/src/svnrevision.h +++ b/src/svnrevision.h @@ -3,5 +3,5 @@ // This file was automatically generated by the // updaterevision tool. Do not edit by hand. -#define ZD_SVN_REVISION_STRING "4280" -#define ZD_SVN_REVISION_NUMBER 4280 +#define ZD_SVN_REVISION_STRING "4285" +#define ZD_SVN_REVISION_NUMBER 4285 diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index d1c952ea..b0f4024f 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -366,7 +366,7 @@ ACTOR PillarAlienPower 227 { Spawn: APOW A 4 A_LoopActiveSound - Stop + Loop } }