L4D2 Level Design/Custom Finale: Difference between revisions
ThaiGrocer (talk | contribs) m (→Map) |
ThaiGrocer (talk | contribs) No edit summary |
||
Line 1: | Line 1: | ||
{{L4D2 level intro menu}} | {{L4D2 level intro menu}}__toc__ | ||
A custom [[L4D Level Design/Finale Events Part 1|finale]] reads automatically off of a [[VScript|vscript]] containing a list of stages, <map name>_finale.nut. The system features the ability to increment finale stages with arbitrary conditions (mainly the onslaught stage type). Something elaborate as a custom boss is possible, for example, where a certain amount of damage advances the finale to the next stage. Once the stages listed are finished, [[trigger_finale]] fires a FinaleEscapeStarted output. | A custom [[L4D Level Design/Finale Events Part 1|finale]] reads automatically off of a [[VScript|vscript]] containing a list of stages, <map name>_finale.nut. The system features the ability to increment finale stages with arbitrary conditions (mainly the onslaught stage type). Something elaborate as a custom boss is possible, for example, where a certain amount of damage advances the finale to the next stage. Once the stages listed are finished, [[trigger_finale]] fires a FinaleEscapeStarted output. | ||
Line 7: | Line 7: | ||
=== VScript === | === VScript === | ||
As discussed in the [[L4D2_Vscripts#Finale_Specific.2FRelated|L4D2 vscript article]], there are four stage types, additional custom finale-specific director options, and special functions available. | As discussed in the [[L4D2_Vscripts#Finale_Specific.2FRelated|L4D2 vscript article]], there are four stage types, additional custom finale-specific director options, and special functions available. | ||
The following are custom finale vscripts with additional comments: | |||
==== c2m5_concert_finale.nut ==== | |||
{{ScrollBox|<source lang=lua> | |||
//----------------------------------------------------------------------------- | |||
// Enumerations of stage types | |||
PANIC <- 0 | |||
TANK <- 1 | |||
DELAY <- 2 | |||
ONSLAUGHT <- 3 | |||
//----------------------------------------------------------------------------- | |||
// Initialization of tables that will be fed to DirectorOptions | |||
SharedOptions <- | |||
{ | |||
A_CustomFinale_StageCount = 9 //Number of stages. Used by director VS scoring, as well?? | |||
A_CustomFinale1 = PANIC | |||
A_CustomFinaleValue1 = 1 //1 PANIC waves | |||
A_CustomFinale2 = PANIC | |||
A_CustomFinaleValue2 = 1 | |||
A_CustomFinale3 = DELAY | |||
A_CustomFinaleValue3 = 15 //15 seconds of DELAY | |||
A_CustomFinale4 = TANK | |||
A_CustomFinaleValue4 = 1 //1 TANK | |||
A_CustomFinaleMusic4 = "" //Custom music entry is off in script, played in-game | |||
A_CustomFinale5 = DELAY | |||
A_CustomFinaleValue5 = 15 | |||
A_CustomFinale6 = PANIC | |||
A_CustomFinaleValue6 = 2 | |||
A_CustomFinale7 = DELAY | |||
A_CustomFinaleValue7 = 10 | |||
A_CustomFinale8 = TANK | |||
A_CustomFinaleValue8 = 1 | |||
A_CustomFinaleMusic8 = "" | |||
A_CustomFinale9 = DELAY | |||
A_CustomFinaleValue9 = RandomInt( 5, 10 ) //Random DELAY between 5-10 seconds | |||
// Additional Director options | |||
PreferredMobDirection = SPAWN_LARGE_VOLUME | |||
PreferredSpecialDirection = SPAWN_LARGE_VOLUME | |||
ShouldConstrainLargeVolumeSpawn = false | |||
ZombieSpawnRange = 3000 | |||
SpecialRespawnInterval = 20 | |||
} | |||
InitialPanicOptions <- //Table separate from SharedOptions for stage 1 | |||
{ | |||
ShouldConstrainLargeVolumeSpawn = true | |||
} | |||
PanicOptions <- //General panic options | |||
{ | |||
CommonLimit = 25 | |||
} | |||
TankOptions <- //Another separate table used when TANK in play | |||
{ | |||
ShouldAllowSpecialsWithTank = true | |||
SpecialRespawnInterval = 30 | |||
} | |||
DirectorOptions <- clone SharedOptions //DirectorOptions starts off with SharedOptions | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
// Used frequently to copy table to another one | |||
function AddTableToTable( dest, src ) | |||
{ | |||
foreach( key, val in src ) | |||
{ | |||
dest[key] <- val | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
// Manipulation of DirectorOptions with custom logic | |||
// In this case, DirectorOptions only changes when a new stage starts | |||
function OnBeginCustomFinaleStage( num, type ) //Special func, when every new finale stage begins | |||
{ | |||
if ( developer() > 0 ) //If developer mode is on, -dev | |||
{ | |||
printl("========================================================"); | |||
printl( "Beginning custom finale stage " + num + " of type " + type ); | |||
} | |||
//Setting up / determining WAVEOPTIONS | |||
local waveOptions = null | |||
if ( num == 1 ) //If first stage (assumed to be PANIC) | |||
{ | |||
waveOptions = InitialPanicOptions | |||
} | |||
else if ( type == PANIC ) //General PANIC | |||
{ | |||
waveOptions = PanicOptions | |||
/* Change MegaMobSize if MegaMobMinSize is available in PanicOptions is available. | |||
Was this ever used?? */ | |||
if ( "MegaMobMinSize" in PanicOptions ) | |||
{ | |||
waveOptions.MegaMobSize <- RandomInt( PanicOptions.MegaMobMinSize, MegaMobMaxSize ) | |||
} | |||
} | |||
else if ( type == TANK ) //TANK time! | |||
{ | |||
waveOptions = TankOptions // | |||
} | |||
//--------------------------------- | |||
// Done determining WAVEOPTIONS. Now, actually move to DirectorOptions | |||
MapScript.DirectorOptions.clear() //Clear all DirectorOptions | |||
AddTableToTable( MapScript.DirectorOptions, SharedOptions ); //Bring back SharedOptions | |||
if ( waveOptions != null ) //Finally add the stage-dependent options | |||
{ | |||
AddTableToTable( MapScript.DirectorOptions, waveOptions ); | |||
} | |||
//--------------------------------- | |||
if ( developer() > 0 ) //More dev outputs (-dev) | |||
{ | |||
Msg( "\n*****\nMapScript.DirectorOptions:\n" ); | |||
foreach( key, value in MapScript.DirectorOptions ) | |||
{ | |||
Msg( " " + key + " = " + value + "\n" ); | |||
} | |||
if ( LocalScript.rawin( "DirectorOptions" ) ) | |||
{ | |||
Msg( "\n*****\nLocalScript.DirectorOptions:\n" ); | |||
foreach( key, value in LocalScript.DirectorOptions ) | |||
{ | |||
Msg( " " + key + " = " + value + "\n" ); | |||
} | |||
} | |||
printl("========================================================"); | |||
} | |||
}</source>}} | |||
=== Map === | === Map === | ||
At the very least, all that needs to be changed is trigger_finale Finale Type, from <code>Standard</code> to <code>Custom</code>. There are other options and details you should consider: | At the very least, all that needs to be changed is trigger_finale Finale Type, from <code>Standard</code> to <code>Custom</code>. There are other options and details you should consider: | ||
* The onslaught stage type does end unless the [[info_director|director]] is given the input EndCustomScriptedStage via script or | * The onslaught stage type does not end unless the [[info_director|director]] is given the input EndCustomScriptedStage via script EntFire (direct or indirect) or simply in-game I/O. | ||
* info_director: OnCustomPanicStageFinished, OnPanicEventFinished (maybe just for crescendo), and OnUserDefinedScriptEvent(1-4) outputs are available, linked to vscript stage states or methods such as .UserDefinedEvent1()-.UserDefinedEvent4(). | * info_director: OnCustomPanicStageFinished, OnPanicEventFinished (maybe just for crescendo), and OnUserDefinedScriptEvent(1-4) outputs are available, linked to vscript stage states or methods such as .UserDefinedEvent1()-.UserDefinedEvent4(). | ||
* trigger_finale: AdvanceFinaleState input is available. | * trigger_finale: AdvanceFinaleState input is available. |
Revision as of 09:20, 5 October 2011
A custom finale reads automatically off of a vscript containing a list of stages, <map name>_finale.nut. The system features the ability to increment finale stages with arbitrary conditions (mainly the onslaught stage type). Something elaborate as a custom boss is possible, for example, where a certain amount of damage advances the finale to the next stage. Once the stages listed are finished, trigger_finale fires a FinaleEscapeStarted output.
None of the official L4D2 maps use the Standard
finale option. Custom finale maps include c2m5_concert, c3m4_plantation, c4m5_milltown_escape, c7m3_port, and it is assumed that L4D1 finales do the same (No Mercy is confirmed to use custom).
Components
VScript
As discussed in the L4D2 vscript article, there are four stage types, additional custom finale-specific director options, and special functions available.
The following are custom finale vscripts with additional comments:
c2m5_concert_finale.nut
//-----------------------------------------------------------------------------
// Enumerations of stage types
PANIC <- 0
TANK <- 1
DELAY <- 2
ONSLAUGHT <- 3
//-----------------------------------------------------------------------------
// Initialization of tables that will be fed to DirectorOptions
SharedOptions <-
{
A_CustomFinale_StageCount = 9 //Number of stages. Used by director VS scoring, as well??
A_CustomFinale1 = PANIC
A_CustomFinaleValue1 = 1 //1 PANIC waves
A_CustomFinale2 = PANIC
A_CustomFinaleValue2 = 1
A_CustomFinale3 = DELAY
A_CustomFinaleValue3 = 15 //15 seconds of DELAY
A_CustomFinale4 = TANK
A_CustomFinaleValue4 = 1 //1 TANK
A_CustomFinaleMusic4 = "" //Custom music entry is off in script, played in-game
A_CustomFinale5 = DELAY
A_CustomFinaleValue5 = 15
A_CustomFinale6 = PANIC
A_CustomFinaleValue6 = 2
A_CustomFinale7 = DELAY
A_CustomFinaleValue7 = 10
A_CustomFinale8 = TANK
A_CustomFinaleValue8 = 1
A_CustomFinaleMusic8 = ""
A_CustomFinale9 = DELAY
A_CustomFinaleValue9 = RandomInt( 5, 10 ) //Random DELAY between 5-10 seconds
// Additional Director options
PreferredMobDirection = SPAWN_LARGE_VOLUME
PreferredSpecialDirection = SPAWN_LARGE_VOLUME
ShouldConstrainLargeVolumeSpawn = false
ZombieSpawnRange = 3000
SpecialRespawnInterval = 20
}
InitialPanicOptions <- //Table separate from SharedOptions for stage 1
{
ShouldConstrainLargeVolumeSpawn = true
}
PanicOptions <- //General panic options
{
CommonLimit = 25
}
TankOptions <- //Another separate table used when TANK in play
{
ShouldAllowSpecialsWithTank = true
SpecialRespawnInterval = 30
}
DirectorOptions <- clone SharedOptions //DirectorOptions starts off with SharedOptions
{
}
//-----------------------------------------------------------------------------
// Used frequently to copy table to another one
function AddTableToTable( dest, src )
{
foreach( key, val in src )
{
dest[key] <- val
}
}
//-----------------------------------------------------------------------------
// Manipulation of DirectorOptions with custom logic
// In this case, DirectorOptions only changes when a new stage starts
function OnBeginCustomFinaleStage( num, type ) //Special func, when every new finale stage begins
{
if ( developer() > 0 ) //If developer mode is on, -dev
{
printl("========================================================");
printl( "Beginning custom finale stage " + num + " of type " + type );
}
//Setting up / determining WAVEOPTIONS
local waveOptions = null
if ( num == 1 ) //If first stage (assumed to be PANIC)
{
waveOptions = InitialPanicOptions
}
else if ( type == PANIC ) //General PANIC
{
waveOptions = PanicOptions
/* Change MegaMobSize if MegaMobMinSize is available in PanicOptions is available.
Was this ever used?? */
if ( "MegaMobMinSize" in PanicOptions )
{
waveOptions.MegaMobSize <- RandomInt( PanicOptions.MegaMobMinSize, MegaMobMaxSize )
}
}
else if ( type == TANK ) //TANK time!
{
waveOptions = TankOptions //
}
//---------------------------------
// Done determining WAVEOPTIONS. Now, actually move to DirectorOptions
MapScript.DirectorOptions.clear() //Clear all DirectorOptions
AddTableToTable( MapScript.DirectorOptions, SharedOptions ); //Bring back SharedOptions
if ( waveOptions != null ) //Finally add the stage-dependent options
{
AddTableToTable( MapScript.DirectorOptions, waveOptions );
}
//---------------------------------
if ( developer() > 0 ) //More dev outputs (-dev)
{
Msg( "\n*****\nMapScript.DirectorOptions:\n" );
foreach( key, value in MapScript.DirectorOptions )
{
Msg( " " + key + " = " + value + "\n" );
}
if ( LocalScript.rawin( "DirectorOptions" ) )
{
Msg( "\n*****\nLocalScript.DirectorOptions:\n" );
foreach( key, value in LocalScript.DirectorOptions )
{
Msg( " " + key + " = " + value + "\n" );
}
}
printl("========================================================");
}
}
Map
At the very least, all that needs to be changed is trigger_finale Finale Type, from Standard
to Custom
. There are other options and details you should consider:
- The onslaught stage type does not end unless the director is given the input EndCustomScriptedStage via script EntFire (direct or indirect) or simply in-game I/O.
- info_director: OnCustomPanicStageFinished, OnPanicEventFinished (maybe just for crescendo), and OnUserDefinedScriptEvent(1-4) outputs are available, linked to vscript stage states or methods such as .UserDefinedEvent1()-.UserDefinedEvent4().
- trigger_finale: AdvanceFinaleState input is available.
Sacrifice finale
The sacrifice finale is based off of custom finale with additional hard-coded modifications introduced in The Sacrifice update.
← L4D2 Level Design/Gauntlet Finale | Return to L4D2 Level Design |