Raised This Month: $42 Target: $400
 10% 

[L4D2] How to scale the gas can goal in scavenge finales to number of survivors?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Proaxel
Member
Join Date: Oct 2014
Old 03-17-2021 , 13:19   [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #1

I've seen other servers like Points Reloaded change the gas can goal in Dead Center Atrium to something like 40, but I can't seem to find any sufficient documentation on how to do it.

The closest other forum thread that I could find on the matter is this one which was over a decade ago, but it never seemed to get any definitive answer on how to do this despite the bump last year.

There was this plugin here which seems to do it, but it goes by a fixed amount, with the gas can goal only determined by the amount of gas can spawns you add with the plugin. It also seems to use modified director vscripts via vpk files. Since this was also made nearly a decade ago, I'm wondering if anyone here has found a better method since then, preferably using only Sourcemod.

My current plan as of now is to figure out how to go about changing the gas can goal to the number of survivors, and then use ScavengeRemixDS to set up the extra gas can spawns, and then modify said plugin to determine how many gas cans to spawn using the number of players instead of a using a fixed amount set by its cfg file. Though I highly doubt this is how some other servers did it; if anyone has any idea on how exactly they do it please do share.

Also I came across this in the list of L4D2 netprops, "m_nScavengeItemsGoal" as a netprop of CTerrorGameRulesProxy. Could it have something to do with that?
https://wiki.alliedmods.net/Left_4_D...ameRulesProxy:
Proaxel is offline
Zynda
Member
Join Date: Jul 2011
Old 03-18-2021 , 00:06   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #2

m_nScavengeItemsGoal is probably for the scavenge gamemode only.

Scavenge in coop is purely Director VScripts with the HUD element controlled by a game_scavenge_progress_display.

On the atrium level there are two main scripts:

c1m4_atrium.nut sets up the HUD counter when the round starts.
c1m4_atrium_finale.nut then gets loaded when the finale starts, it has the logic for counting cans when they are poured and holds the value for number of cans needed (separate from the HUD).

You probably could use some tricks to execute VScript from a plugin and override the number of cans needed after the finale has started, but in my testing every time the finale stage was increased the value for the numbers of cans was also reloaded by the script.

You can test this yourself on a localhost server by executing
Code:
script DirectorScript.MapScript.LocalScript.NumCansNeeded <- 3
after exiting the elevator and the music starts.

Then read the value to see what is stored:
Code:
script print(DirectorScript.MapScript.LocalScript.NumCansNeeded)
Now wait for the stage to increase (you will see a lot of debug spew in blue) and then read the value again.

I'm thinking your best bet is to use VScript File Replacer.
You can, for example, make some presets for the amount of cans and choose which preset gets loaded in the OnVScriptExecuted forward depending on amount of players.
Or perhaps write some VScript that reads the amount of cans from a ConVar that you set in your plugin and inject that into the director script instead.

Remember to update the HUD counter in your plugin also, in the c1m4_atrium.nut script they simply use ent_fire on the SetTotalItems input of the progress_display entity. This should probably happen before the finale is started (and the counter is activated).
Zynda is offline
Proaxel
Member
Join Date: Oct 2014
Old 03-18-2021 , 04:51   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #3

Okay, thanks! I think I'll just go the VScript preset method for now since I am still unfamiliar when it comes to everything about VScripts, unless you or someone else here would be willing to walk me through how to do the inject method you mentioned.

So in this preset method I presume I need to do the following:
In the server's Vscripts folder, Make a bunch of copies of the c1m4_atrium_finale.nut, name them according to the preset like finalet1.nut, finalet2.nut, and so on
In each copy change the following line to whatever goal it needs to be for that tier
Code:
// number of cans needed to escape.
NumCansNeeded <- 13 //< change this number to the new goal

Then in my sourcemod plugin it would go something like
PHP Code:
public Action OnVScriptExecuted(const char[] sScriptchar sOverride[PLATFORM_MAX_PATH], bool bOverride)
{
 
    if( 
strcmp(sScript"c1m4_atrium_finale") == || (bOverride && strcmp(sOverride"c1m4_atrium_finale") == 0) )
    {
        
int totalSurvivors GetSurvivorCount();
        if(
totalSurvivors && totalSurvivors <= 8)
        {
            
//Set new scavenge goal of 17 cans
            
PrintToServer("Increase to 17");
            
sOverride "c1m4_atrium_finalet1";
            
Ent_Fire("progress_display""SetTotalItems"17); 
            return 
Plugin_Changed;
        }
        else if(
totalSurvivors && totalSurvivors <= 12)
        {
            
//Set new scavenge goal of 21 cans
            
PrintToServer("Increase to 21");
            
sOverride "c1m4_atrium_finalet2";
            
Ent_Fire("progress_display""SetTotalItems"21); 
            return 
Plugin_Changed;
        }
        
//And so on
    
}
    return 
Plugin_Continue;

For changing the progress display is it simply a matter of using disawar's method in their plugin, or has Sourcemod added a better way of doing this since then (with SetEntProp perhaps?)

PHP Code:
Ent_Fire(const String:sName[], const String:sInput[], Params = -1)
{
    
decl String:sEntName[64];

    for (new 
04096i++){
    
        if (
IsValidEntity(i)){
        
            
GetEntPropString(iProp_Data"m_iName"sEntNamesizeof(sEntName));
            
            if (
StrEqual(sEntNamesName)){
                    
                
#if debug
                    
PrintToChatAll("[GS] ent_fire (%s %d, %s, %d)"sNameisInputParams);
                
#endif
                
                
if (Params != -1)
                    
SetVariantInt(Params);

                
AcceptEntityInput(isInput);
                break;
            }
        }
    }
}

Ent_Fire("game_scavenge_progress_display""SetTotalItems"newTotalCans); 
One last thing, is L4D2 smart enough to respawn gas cans in the same spawn points if it sees that there aren't enough cans to reach the goal, or does a plugin also have to tell it to do that? And/Or do I still have to make use of ScavengeRemixDS to make sure sufficient gas cans are spawned?
Proaxel is offline
Marttt
Veteran Member
Join Date: Jan 2019
Location: Brazil
Old 03-18-2021 , 09:59   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #4

gascans from scavenge events have the "weapon_scavenge_item_spawn" classname. It somehow detects that a gascan (weapon_gascan) related to it was used to fill and then stop respawning, or respawn it when explode.

In your example, you should use "FindEntityByClassname" instead looping through all entities indexes as a good practice.
__________________
Marttt is online now
Zynda
Member
Join Date: Jul 2011
Old 03-18-2021 , 14:12   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #5

Since the entity we're targeting is most likely always a singleton it should be safe to skip checking the targetname anyway.

Something like this should suffice:

PHP Code:
int index = -1;

while ((
index FindEntityByClassname(index"game_scavenge_progress_display")) != -1)
{
    
SetVariantInt(newTotalCans);
    
AcceptEntityInput(index"SetTotalItems", -1, -1);

Zynda is offline
Zynda
Member
Join Date: Jul 2011
Old 03-18-2021 , 14:35   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #6

Here is a snippet I made for the VScript File Replacer that sets the cans required from the value of a ConVar (mine is named "l4d2_cans" in this case).

Code:
"c1m4_atrium"
{
	"c1m4_atrium_finale"
	{
		"NumCansNeeded <- 13"	"NumCansNeeded <- Convars.GetStr(\"l4d2_cans\").tointeger()"
	}
}
Zynda is offline
Proaxel
Member
Join Date: Oct 2014
Old 03-18-2021 , 15:11   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #7

Quote:
Originally Posted by Marttt View Post
gascans from scavenge events have the "weapon_scavenge_item_spawn" classname. It somehow detects that a gascan (weapon_gascan) related to it was used to fill and then stop respawning, or respawn it when explode.
According to its wiki entry the "weapon_scavenge_item_spawn" can take "SpawnItem" as input. In that case would it be feasible to have the plugin do the following

Add tracking for the original gas can event
PHP Code:
        int totalSurvivors GetSurvivorCount();
        
int g_currentGasCans 13;
        
int g_newGasCanGoal 13;
        if(
totalSurvivors && totalSurvivors <= 8)
        {
            
//Set new scavenge goal of 17 cans
            
g_newGasCanGoal 17;
//.... 
Then have the plugin do HookEvent("gascan_pour_completed")
And then in that event check if there is enough gas cans, and if there aren't force one of those entities to spawn one
PHP Code:
public Action Event_GasCanPourCompleted(Handle:eventString:event_name[], bool:dontBroadcast)
{
    
g_currentGasCans++;
    if (
g_currentGasCans g_newGasCanGoal){
        
Ent_Fire("weapon_scavenge_item_spawn""SpawnItem");
    }
    return 
Plugin_Continue;

OR...

The scavRemixDS plugin uses cvars to determine how many gas cans to spawn:
PHP Code:
CreateConVar("l4d2_scramble_can_count""16""Value = How many Gas Cans to spawn from the pool."FCVAR_PLUGIN); 
So would it be feasible to instead set the convar when the finale Vscript executes on finale start? Or would that be too late?
PHP Code:
        if(totalSurvivors && totalSurvivors <= 8)
        {
            
//Set new scavenge goal of 17 cans
            
FindConVar("l4d2_scramble_can_count").IntValue 17
Quote:
Since the entity we're targeting is most likely always a singleton it should be safe to skip checking the targetname anyway.

Something like this should suffice:
Wouldn't the plugin hang if this was run inside a scavenge finale? Where would be the best place to put it in that case? I originally planned on having it update in the gas can pour completed event

Last edited by Proaxel; 03-19-2021 at 02:30.
Proaxel is offline
Gold Fish
Member
Join Date: Mar 2020
Old 03-19-2021 , 03:00   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #8

I have a problem when I reduce the number of canisters and start a forced rescue during this time the final tanks do not appear, maybe there is a way to manually activate the final stage of the map script so that panic starts and the tank starts spawning (if you understand what I mean)

Last edited by Gold Fish; 03-19-2021 at 03:01.
Gold Fish is offline
Marttt
Veteran Member
Join Date: Jan 2019
Location: Brazil
Old 03-19-2021 , 09:41   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #9

If you force the finale ending you may have to setup this on vscript too (based on c8m5_finale.nut)

PHP Code:
function EnableEscapeTanks()
{
    
printl"Chase Tanks Enabled!" );
    
    
MapScript.DirectorOptions.EscapeSpawnTanks <- true

__________________

Last edited by Marttt; 03-19-2021 at 09:41.
Marttt is online now
Proaxel
Member
Join Date: Oct 2014
Old 03-21-2021 , 19:55   Re: [L4D2] How to scale the gas can goal in scavenge finales to number of survivors?
Reply With Quote #10

I got it figured out and working, thanks to both of you! I changed my mind and went with having the VScript read a convar as suggested by Zynda, and went with having ScavengeRemixDS being responsible for setting up the extra can spawns.


PHP Code:
public Action OnVScriptExecuted(const char[] sScriptchar sOverride[PLATFORM_MAX_PATH], bool bOverride)
{
    if( 
strcmp(sScript"c1m4_atrium_finale") == || (bOverride && strcmp(sOverride"c1m4_atrium_finale") == 0) )
    {
        
//PrintToServer("[ScavengeBalancerDebug] Determining Can amount now.", g_numAtRoundStart);
        //PrintToChatAll("\x05[ScavengeBalancerDebug] \x01Determining Can amount now");
        
g_numAtRoundStart GetTotalSurvivorCount();
        
//PrintToServer("Survivors: %d", g_numAtRoundStart);
        
FindConVar("cans_goal_c1m4").IntValue CalculateGasCanGoal(13g_numAtRoundStart);
        
FindConVar("l4d2_scramble_can_count").IntValue FindConVar("cans_goal_c1m4").IntValue
        
g_overridenGoal true;
        
g_newGasCanGoal FindConVar("cans_goal_c1m4").IntValue;
        
Ent_Fire("game_scavenge_progress_display""SetTotalItems"g_newGasCanGoal);
        
//PrintToChatAll("\x05[ScavengeBalancerDebug] \x01Calculated new scavenge goal.", g_numAtRoundStart, FindConVar("l4d2_scramble_can_count").IntValue);
        //PrintToChatAll("13 + ((%d - 4) * 2) = %d", g_numAtRoundStart, FindConVar("l4d2_scramble_can_count").IntValue);
        //PrintToChatAll("\x05[ScavengeBalancerDebug] \x01%d gas cans SHOULD now be on the map. Ping Proaxel on Discord if this is not the case", FindConVar("l4d2_scramble_can_count").IntValue);
    
}
    return 
Plugin_Continue;

It is safe to run this right as the elevator opens, ScavengeRemixDS does see the convar change right away and spawns the right number of gas cans.

The only problem I ran into was that I found ScavengeRemixDS only scrambles the gas cans on the first finale attempt since map load. I found that if more players join between the time the finale starts the first time and the second time (due to survivors losing and restarting the round), my plugin sets the new goal to the number of players accordingly, but ScavengeRemixDS still spawns the number of cans determined from the first time, which can result in a softlocked finale due to not enough cans. Also, unlike vanilla it doesn't despawn the cans if survivors lose and retry again, so you can see all the gas cans as you're walking into the atrium for the second time again.

Thankfully the fix for these problems was simple, the code for said plugin is well organized enough that it was simply a matter of hooking the mission_lost event, and using it to call a couple of already made functions and changing a boolean to false to allow it to calculate and scramble gas cans again the next time the finale is triggered.

PHP Code:
public Action Event_MissionLost(Handle:event, const String:name[], bool:dontBroadcast)
{
    if(!
IsScavenge() && !IsSurvival() && ScrambleConfirmed)
    {
        
RemoveAllGasCanSpawns(); //Remove all current gas cans
        
RemoveAllGasCans(); //Remove all current gas can spawners
        
ScrambleConfirmed false;
        
PrintToChatAll("\x05[ScavengeRemixDS] \x01Gas Can Spawns Reset");
    }

Edit: I've since merged my plugin into the ScavengeRemixDS plugin itself. I thought it made more sense, so I just did it.

Last edited by Proaxel; 04-05-2021 at 04:40.
Proaxel is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 19:31.


Powered by vBulletin®
Copyright ©2000 - 2021, vBulletin Solutions, Inc.
Theme made by Freecode