aboutsummaryrefslogtreecommitdiff
path: root/Northstar.CustomServers/mod/scripts/vscripts
diff options
context:
space:
mode:
Diffstat (limited to 'Northstar.CustomServers/mod/scripts/vscripts')
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut8
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut9
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut3
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut7
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut8
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut20
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut8
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut169
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut23
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut29
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut29
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut15
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut220
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut105
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut180
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut56
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut9
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut18
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut294
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut7
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut26
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut17
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut2
-rw-r--r--Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut5
24 files changed, 1204 insertions, 63 deletions
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut
index 97ed959c..44836bc9 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_chat.gnut
@@ -25,26 +25,26 @@ void function Chat_PrivateMessage(entity fromPlayer, entity toPlayer, string tex
}
// Broadcasts a message from the server to all players.
-void function Chat_ServerBroadcast(string text)
+void function Chat_ServerBroadcast(string text, bool withServerTag = true)
{
NSBroadcastMessage(
-1,
-1,
text,
- false,
+ !withServerTag,
false,
eChatMessageType.CHAT
)
}
// Sends a message from the server to one player. Will be shown as a whisper if whisper is set.
-void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper)
+void function Chat_ServerPrivateMessage(entity toPlayer, string text, bool whisper, bool withServerTag = true)
{
NSBroadcastMessage(
-1,
toPlayer.GetPlayerIndex(),
text,
- false,
+ !withServerTag,
false,
whisper ? eChatMessageType.WHISPER : eChatMessageType.CHAT
)
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut
index 4a7f8189..ee21116d 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_custom_codecallbacks.gnut
@@ -1,7 +1,10 @@
untyped
global function AddCallback_OnReceivedSayTextMessage
-global function NSSetupChathooksServer
+
+// this is global due to squirrel bridge v3 making native not be able to find non-global funcs properly
+// temp fix (surely it will get replaced), do not use this function please
+global function CServerGameDLL_ProcessMessageStartThread
global struct ClServer_MessageStruct {
string message
@@ -53,7 +56,3 @@ void function AddCallback_OnReceivedSayTextMessage( ClServer_MessageStruct funct
{
NsCustomCallbacks.OnReceivedSayTextMessageCallbacks.append(callbackFunc)
}
-
-void function NSSetupChathooksServer() {
- getroottable().rawset("CServerGameDLL_ProcessMessageStartThread", CServerGameDLL_ProcessMessageStartThread)
-}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
index 3161237c..24dbb62d 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut
@@ -187,6 +187,8 @@ bool function ClientCommandCallback_SetPersistentLoadoutValue( entity player, ar
if ( args[0] == "pilot" )
SetPlayerLoadoutDirty( player )
+ UnlockAchievement( player, achievements.CUSTOMIZE_LOADOUT )
+
return true
}
@@ -230,7 +232,6 @@ bool function ClientCommandCallback_SetBurnCardPersistenceSlot( entity player, a
print( player + " SetBurnCardPersistenceSlot " + args[0] )
- // insecure, could be used to set invalid burnmeterslot potentially
if ( IsRefValidAndOfType( args[0], eItemTypes.BURN_METER_REWARD ) )
player.SetPersistentVar( "burnmeterSlot", BurnReward_GetByRef( args[0] ).id )
else
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut
index c0e69ba5..3546e3b7 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut
@@ -2127,8 +2127,13 @@ void function EntityDemigod_TryAdjustDamageInfo( entity ent, var damageInfo )
return
int bottomLimit = 5
+ // Set it up so that you at least take 1 damage, for hit indicators etc to trigger
if ( ent.GetHealth() <= bottomLimit )
- ent.SetHealth( bottomLimit + 1 ) //Set it up so that you at least take 1 damage, for hit indicators etc to trigger
+ {
+ // Prevent going over max health to avoid a server crash.
+ int newHealth = bottomLimit + 1
+ ent.SetHealth( ent.GetMaxHealth() < newHealth ? ent.GetMaxHealth() : newHealth )
+ }
int health = ent.GetHealth()
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
index a8def7b2..f193643c 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut
@@ -265,7 +265,7 @@ void function UseBurnCardWeapon( entity weapon, entity player )
if ( PlayerEarnMeter_IsRewardAvailable( player ) )
PlayerEarnMeter_SetRewardUsed( player )
- PlayerInventory_PopInventoryItem( player )
+ thread PlayerInventory_PopInventoryItem( player )
}
void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer )
@@ -295,10 +295,14 @@ void function InitBurnMeterPersistentData( entity player )
void function PlayerUsesAmpedWeaponsBurncard( entity player )
{
thread PlayerUsesAmpedWeaponsBurncardThreaded( player )
+
}
void function PlayerUsesAmpedWeaponsBurncardThreaded( entity player )
{
+ player.Signal( "StopAmpedWeapons" )
+ player.EndSignal("StopAmpedWeapons")
+
array<entity> weapons = player.GetMainWeapons()
//weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here
foreach ( entity weapon in weapons )
@@ -615,4 +619,4 @@ void function PlayerUsesReaperfallBurncard( entity player )
DispatchSpawn( reaper )
thread SuperSpectre_WarpFall( reaper )
-} \ No newline at end of file
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut b/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut
index b9f8f7eb..19c6b6df 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/class/cplayer.nut
@@ -328,6 +328,26 @@ function CodeCallback_RegisterClass_CPlayer()
}
}
}
+
+ function CPlayer::GetUserInfoString( key, defaultValue = "" )
+ {
+ return GetUserInfoKVString_Internal( this, key, defaultValue )
+ }
+
+ function CPlayer::GetUserInfoInt( key, defaultValue = 0 )
+ {
+ return GetUserInfoKVInt_Internal( this, key, defaultValue )
+ }
+
+ function CPlayer::GetUserInfoFloat( key, defaultValue = 0 )
+ {
+ return GetUserInfoKVFloat_Internal( this, key, defaultValue )
+ }
+
+ function CPlayer::GetUserInfoBool( key, defaultValue = false )
+ {
+ return GetUserInfoKVBool_Internal( this, key, defaultValue )
+ }
}
void function PlayerDropsScriptedItems( entity player )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut
index dda84976..b4e77375 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut
@@ -315,12 +315,12 @@ void function PlayerEarnMeter_Empty( entity player )
PlayerEarnMeter_SetRewardFrac( player, 0.0 )
}
-
void function EarnMeterDecayThink( entity player )
{
player.EndSignal( "OnDeath" )
player.Signal( "EarnMeterDecayThink" )
player.EndSignal( "EarnMeterDecayThink" )
+ thread OverDriveClearOnDeath( player )
if ( EarnMeter_DecayHold() < 0 )
return
@@ -348,6 +348,12 @@ void function EarnMeterDecayThink( entity player )
}
}
+void function OverDriveClearOnDeath( entity player )
+{
+ player.EndSignal( "OnDestroy" )
+ player.WaitSignal( "OnDeath" )
+ PlayerEarnMeter_SetEarnedFrac( player, PlayerEarnMeter_GetOwnedFrac( player ) )
+}
bool function PlayerEarnMeter_TryMakeGoalAvailable( entity player )
{
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
index b1d8f6bd..f23c841d 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut
@@ -69,11 +69,21 @@ struct {
entity evacIcon
} file
+struct EvacShipSetting
+{
+ asset shipModel
+ string flyinSound
+ string hoverSound
+ string flyoutSound
+}
+
void function Evac_Init()
{
EvacShared_Init()
RegisterSignal( "EvacShipLeaves" )
RegisterSignal( "EvacOver" )
+
+ PrecacheParticleSystem( FX_EVAC_MARKER )
}
void function AddEvacNode( entity evacNode )
@@ -100,7 +110,7 @@ void function EvacEpilogueSetup()
void function EvacEpilogue()
{
- int winner = GetWinningTeam()
+ int winner = GetWinningTeam()
// make sure we don't run evac if it won't be supported for current map/gamestate
bool canRunEvac = GetCurrentPlaylistVarInt( "max_teams", 2 ) == 2 &&
@@ -110,6 +120,10 @@ void function EvacEpilogue()
if ( canRunEvac )
{
thread SetRespawnAndWait( false )
+
+ // no players can evac? end match
+ thread CheckIfAnyPlayerLeft( GetOtherTeam( winner ) )
+
thread Evac( GetOtherTeam( winner ), EVAC_INITIAL_WAIT, EVAC_ARRIVAL_TIME, EVAC_WAIT_TIME, EvacEpiloguePlayerCanBoard, EvacEpilogueShouldLeaveEarly, EvacEpilogueCompleted )
}
else
@@ -139,6 +153,10 @@ void function SetRespawnAndWait( bool mode )
{
wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY
SetRespawnsEnabled( mode )
+
+ // clear any respawn availablity, or players are able to save there respawn for whenever they want
+ foreach( entity player in GetPlayerArray() )
+ ClearRespawnAvailable( player )
}
bool function EvacEpiloguePlayerCanBoard( entity dropship, entity player )
@@ -174,12 +192,16 @@ void function EvacEpilogueCompleted( entity dropship )
ScreenFadeToBlackForever( player, 2.0 )
wait 2.0
- SetGameState( eGameState.Postmatch )
+ if( GetGameState() != eGameState.Postmatch )
+ SetGameState( eGameState.Postmatch )
}
// global evac func, anything can call this, it's not necessarily an epilogue thing
void function Evac( int evacTeam, float initialWait, float arrivalTime, float waitTime, bool functionref( entity, entity ) canBoardCallback, bool functionref( entity ) shouldLeaveEarlyCallback, void functionref( entity ) completionCallback, entity customEvacNode = null )
{
+ // get evac ship sound and model for specific team
+ EvacShipSetting evacShip = GetEvacShipSettingByTeam( evacTeam )
+
wait initialWait
// setup evac nodes if not manually registered
@@ -212,6 +234,13 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
DispatchSpawn( file.evacIcon )
file.evacIcon.DisableHibernation()
+ // start evac beam
+ int index = GetParticleSystemIndex( FX_EVAC_MARKER )
+
+ entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, evacNode.GetOrigin(), < 0,0,0 > )
+ SetTeam( effectFriendly, evacTeam )
+ effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY
+
wait 0.5 // need to wait here, or the target won't appear on clients for some reason
// eta until arrive
SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon )
@@ -221,14 +250,20 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
wait arrivalTime - 4.33333
entity dropship = CreateDropship( evacTeam, evacNode.GetOrigin(), evacNode.GetAngles() )
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
- dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
+
+ thread DropShipTempHide( dropship ) // prevent showing model and health bar on spawn
+ dropship.SetModel( evacShip.shipModel )
+ dropship.SetValueForModelKey( evacShip.shipModel )
+
dropship.SetMaxHealth( EVAC_SHIP_HEALTH )
dropship.SetHealth( EVAC_SHIP_HEALTH )
dropship.SetShieldHealth( EVAC_SHIP_SHIELDS )
SetTargetName( dropship, "#NPC_EVAC_DROPSHIP" )
DispatchSpawn( dropship )
- dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" )
+
+ // reduce nuclear core's damage
+ AddEntityCallback_OnDamaged( dropship, EvacDropshipDamaged )
+
AddEntityCallback_OnKilled( dropship, EvacDropshipKilled )
dropship.s.evacSlots <- [ null, null, null, null, null, null, null, null ]
@@ -241,9 +276,12 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
dropship.s.evacTrigger.Destroy()
// this should be for both teams
- SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" )
- SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" )
-
+ if( !IsValid( dropship ) )
+ {
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" )
+ }
+
foreach ( entity player in dropship.s.evacSlots )
{
if ( !IsValid( player ) )
@@ -255,10 +293,14 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
// this is called whether dropship is destroyed or evac finishes, callback can handle this itself
thread completionCallback( dropship )
})
-
+
// flyin
Spectator_SetCustomSpectatorFunc( EvacSpectatorFunc )
thread PlayAnim( dropship, "cd_dropship_rescue_side_start", evacNode )
+
+ // fly in sound and effect
+ EmitSoundOnEntity( dropship, evacShip.flyinSound )
+ thread WarpInEffectEvacShip( dropship )
// calculate time until idle start
float sequenceDuration = dropship.GetSequenceDuration( "cd_dropship_rescue_side_start" )
@@ -266,11 +308,22 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
wait sequenceDuration * cycleFrac
thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", evacNode )
+
+ // hover sound
+ EmitSoundOnEntity( dropship, evacShip.hoverSound )
// eta until leave
SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + waitTime, file.evacIcon )
SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + waitTime, file.evacIcon )
+ // dialogue
+ PlayFactionDialogueToTeam( "mp_evacGo", evacTeam )
+ PlayFactionDialogueToTeam( "mp_evacStop", GetOtherTeam( evacTeam ) )
+
+ // stop evac beam
+ if( IsValid( effectFriendly ) )
+ EffectStop( effectFriendly )
+
// setup evac trigger
entity trigger = CreateEntity( "trigger_cylinder" )
trigger.SetRadius( 150 )
@@ -298,6 +351,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
WaitFrame()
}
+
+ // fly out sound
+ StopSoundOnEntity( dropship, evacShip.hoverSound )
+ EmitSoundOnEntity( dropship, evacShip.flyoutSound )
// holster all weapons
foreach ( entity player in dropship.s.evacSlots )
@@ -320,6 +377,12 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
Remote_CallFunction_NonReplay( player, "ServerCallback_PlayScreenFXWarpJump" )
wait WARPINFXTIME
+
+ dropship.kv.VisibilityFlags = 0 // prevent jetpack trails being like "dive" into ground
+ WaitFrame() // better wait because we are server
+ if( !IsValid( dropship ) )
+ return
+ thread __WarpOutEffectShared( dropship )
// go to space
@@ -345,6 +408,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa
}
SetPlayerActiveObjective( player, "EG_DropshipExtractSuccessfulEscape" )
+
+ // let evacing team able to see the ship again
+ dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY
// skybox
player.SetSkyCamera( GetEnt( SKYBOXSPACE ) )
@@ -428,3 +494,88 @@ void function EvacDropshipKilled( entity dropship, var damageInfo )
}
}
}
+
+// if there's no player left in evacing team, we end this match
+void function CheckIfAnyPlayerLeft( int evacTeam )
+{
+ wait GAME_EPILOGUE_PLAYER_RESPAWN_LEEWAY
+ float startTime = Time()
+
+ OnThreadEnd(
+ function() : ( evacTeam )
+ {
+ SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" )
+ SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" )
+ thread EvacEpilogueCompleted( null )
+ }
+ )
+ while( true )
+ {
+ if( GetPlayerArrayOfTeam_Alive( evacTeam ).len() == 0 )
+ break
+ if( GetGameState() == eGameState.Postmatch )
+ return
+ WaitFrame()
+ }
+}
+
+void function DropShipTempHide( entity dropship )
+{
+ dropship.kv.VisibilityFlags = 0 // or it will still shows the jetpack fxs
+ HideName( dropship )
+ wait 0.46
+ if( IsValid( dropship ) )
+ {
+ dropship.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE
+ ShowName( dropship )
+ }
+}
+
+EvacShipSetting function GetEvacShipSettingByTeam( int team )
+{
+ EvacShipSetting tempSetting
+ tempSetting.shipModel = $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl"
+ tempSetting.flyinSound = "Goblin_IMC_Evac_Flyin"
+ tempSetting.hoverSound = "Goblin_IMC_Evac_Hover"
+ tempSetting.flyoutSound = "Goblin_IMC_Evac_FlyOut"
+
+ if( team == TEAM_MILITIA )
+ {
+ tempSetting.shipModel = $"models/vehicle/crow_dropship/crow_dropship_hero.mdl"
+ tempSetting.flyinSound = "Crow_MCOR_Evac_Flyin"
+ tempSetting.hoverSound = "Crow_MCOR_Evac_Hover"
+ tempSetting.flyoutSound = "Crow_MCOR_Evac_Flyout"
+ }
+ return tempSetting
+}
+
+void function EvacDropshipDamaged( entity evacShip, var damageInfo )
+{
+ int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo )
+ if( damageSourceID == damagedef_nuclear_core )
+ DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) * EVAC_SHIP_DAMAGE_MULTIPLIER_AGAINST_NUCLEAR_CORE )
+}
+
+void function WarpInEffectEvacShip( entity dropship )
+{
+ dropship.EndSignal( "OnDestroy" )
+ float sfxWait = 0.1
+ float totalTime = WARPINFXTIME
+ float preWaitTime = 0.16 // give it some time so it's actually playing anim, and we can get it's "origin" attatch for playing warp in effect
+ string sfx = "dropship_warpin"
+
+ wait preWaitTime
+
+ int attach = dropship.LookupAttachment( "origin" )
+ vector origin = dropship.GetAttachmentOrigin( attach )
+ vector angles = dropship.GetAttachmentAngles( attach )
+
+ entity fx = PlayFX( FX_GUNSHIP_CRASH_EXPLOSION_ENTRANCE, origin, angles )
+ fx.FXEnableRenderAlways()
+ fx.DisableHibernation()
+
+ wait sfxWait
+ EmitSoundAtPosition( TEAM_UNASSIGNED, origin, sfx )
+
+ wait totalTime - sfxWait
+} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut
index 99f34164..9b05c3d4 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut
@@ -26,6 +26,8 @@ void function CaptureTheFlag_Init()
{
PrecacheModel( CTF_FLAG_MODEL )
PrecacheModel( CTF_FLAG_BASE_MODEL )
+ PrecacheParticleSystem( FLAG_FX_FRIENDLY )
+ PrecacheParticleSystem( FLAG_FX_ENEMY )
CaptureTheFlagShared_Init()
SetSwitchSidesBased( true )
@@ -164,6 +166,9 @@ void function CreateFlags()
flag.SetValueForModelKey( CTF_FLAG_MODEL )
SetTeam( flag, flagTeam )
flag.MarkAsNonMovingAttachment()
+ flag.Minimap_AlwaysShow( TEAM_IMC, null ) // show flag icon on minimap
+ flag.Minimap_AlwaysShow( TEAM_MILITIA, null )
+ flag.Minimap_SetAlignUpright( true )
DispatchSpawn( flag )
flag.SetModel( CTF_FLAG_MODEL )
flag.SetOrigin( spawn.GetOrigin() + < 0, 0, base.GetBoundingMaxs().z * 2 > ) // ensure flag doesn't spawn clipped into geometry
@@ -291,7 +296,7 @@ void function GiveFlag( entity player, entity flag )
PlayFactionDialogueToTeamExceptPlayer( "ctf_flagPickupFriendly", player.GetTeam(), player )
MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerHasFriendlyFlag, player, player )
- EmitSoundOnEntityToTeam( flag, "UI_CTF_EnemyGrabFlag", flag.GetTeam() )
+ EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyGrabFlag", flag.GetTeam() )
SetFlagStateForTeam( flag.GetTeam(), eFlagState.Away ) // used for held
}
@@ -339,14 +344,13 @@ void function DropFlag( entity player, bool realDrop = true )
file.imcCaptureAssistList.append( player )
else
file.militiaCaptureAssistList.append( player )
-
+
// do notifications
MessageToPlayer( player, eEventNotifications.YouDroppedTheEnemyFlag )
EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_FlagDrop" )
-
+
MessageToTeam( player.GetTeam(), eEventNotifications.PlayerDroppedEnemyFlag, player, player )
// todo need a sound here maybe
-
MessageToTeam( GetOtherTeam( player.GetTeam() ), eEventNotifications.PlayerDroppedFriendlyFlag, player, player )
// todo need a sound here maybe
}
@@ -421,7 +425,7 @@ void function CaptureFlag( entity player, entity flag )
AddPlayerScore( assistPlayer, "FlagCaptureAssist", player )
assistList.clear()
-
+
// notifs
MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag )
EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" )
@@ -430,7 +434,7 @@ void function CaptureFlag( entity player, entity flag )
EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player )
MessageToTeam( GetOtherTeam( team ), eEventNotifications.PlayerCapturedFriendlyFlag, player, player )
- EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScore", flag.GetTeam() )
+ EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_EnemyScores", flag.GetTeam() )
if ( GameRules_GetTeamScore( team ) == GameMode_GetRoundScoreLimit( GAMETYPE ) - 1 )
{
@@ -446,6 +450,9 @@ void function OnPlayerEntersFlagReturnTrigger( entity trigger, entity player )
flag = file.imcFlag
else
flag = file.militiaFlag
+
+ if( !IsValid( flag ) || !IsValid( player ) )
+ return
if ( !player.IsPlayer() || player.IsTitan() || player.GetTeam() != flag.GetTeam() || IsFlagHome( flag ) || flag.GetParent() != null )
return
@@ -481,6 +488,7 @@ void function TryReturnFlag( entity player, entity flag )
})
player.EndSignal( "FlagReturnEnded" )
+ flag.EndSignal( "FlagReturnEnded" ) // avoid multiple players to return one flag at once
player.EndSignal( "OnDeath" )
wait CTF_GetFlagReturnTime()
@@ -488,7 +496,8 @@ void function TryReturnFlag( entity player, entity flag )
// flag return succeeded
// return flag
ResetFlag( flag )
-
+ flag.Signal( "FlagReturnEnded" )
+
// do notifications for return
MessageToPlayer( player, eEventNotifications.YouReturnedFriendlyFlag )
AddPlayerScore( player, "FlagReturn", player )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut
index 496ebf84..7c08c036 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut
@@ -32,7 +32,7 @@ void function Sv_ItemInventory_OnPlayerGetsNewPilotLoadout( entity player, Pilot
if (playerInventoryStack.len() > 0) {
InventoryItem topInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1]
- PlayerInventory_GiveInventoryItem(player, topInventoryItem)
+ thread PlayerInventory_GiveInventoryItem(player, topInventoryItem)
}
return
@@ -68,13 +68,25 @@ int function PlayerInventory_CountBurnRef( entity player, string burnRef )
void function PlayerInventory_TakeInventoryItem( entity player )
{
+ player.EndSignal( "OnDestroy" )
entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY )
- if ( IsValid( preexistingWeapon ) )
- player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() )
+
+ if( !IsValid( preexistingWeapon ) )
+ return
+ preexistingWeapon.EndSignal( "OnDestroy" )
+ if( preexistingWeapon.GetWeaponClassName() == "mp_ability_burncardweapon" )
+ {
+ var fireTime = preexistingWeapon.GetWeaponInfoFileKeyField( "fire_anim_rate" )
+ if( fireTime )
+ wait fireTime
+ }
+ player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() )
}
void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem inventoryItem )
{
+ player.EndSignal( "OnDestroy" )
+
array<string> mods = []
if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) {
@@ -84,7 +96,10 @@ void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem in
}
// ensure inventory slot isn't full to avoid crash
- PlayerInventory_TakeInventoryItem( player )
+ waitthread PlayerInventory_TakeInventoryItem( player )
+ entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) // defensive fix
+ if( IsValid( preexistingWeapon ) )
+ player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() )
player.GiveOffhandWeapon( inventoryItem.weaponRef, OFFHAND_INVENTORY, mods )
if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) {
@@ -98,7 +113,7 @@ void function PlayerInventory_PushInventoryItem( entity player, InventoryItem in
file.playerInventoryStacks[ player ].append(inventoryItem)
player.SetPlayerNetInt( "itemInventoryCount", file.playerInventoryStacks[ player ].len() )
- PlayerInventory_GiveInventoryItem(player, inventoryItem)
+ thread PlayerInventory_GiveInventoryItem(player, inventoryItem)
}
void function PlayerInventory_PushInventoryItemByBurnRef( entity player, string burnRef )
@@ -121,9 +136,9 @@ void function PlayerInventory_PopInventoryItem( entity player )
if (playerInventoryStack.len() > 0) {
InventoryItem nextInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1]
- PlayerInventory_GiveInventoryItem(player, nextInventoryItem)
+ thread PlayerInventory_GiveInventoryItem( player, nextInventoryItem )
} else {
- PlayerInventory_TakeInventoryItem( player )
+ waitthread PlayerInventory_TakeInventoryItem( player )
}
}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut
index a4c6e187..362407b3 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype.gnut
@@ -1412,15 +1412,28 @@ void function CodeCallback_WeaponFireInCloak( entity player )
//player.SetCloakFlicker( 1.0, 2.0 )
DisableCloak( player, 0.5 )
- entity weapon = player.GetOffhandWeapon( OFFHAND_LEFT )
- //printt( "weapon", weapon.GetWeaponClassName() )
- // JFS; need code feature to properly reset next attack time/cooldown stuff
- if ( IsValid( weapon ) && weapon.GetWeaponClassName() == "mp_ability_cloak" )
+ entity cloakWeapon
+ int offhandSlot
+ for ( int i = 0; i <= OFFHAND_MELEE; i++ ) // OFFHAND_MELEE is the largest
{
- player.TakeOffhandWeapon( OFFHAND_LEFT )
- player.GiveOffhandWeapon( "mp_ability_cloak", OFFHAND_LEFT )
- weapon = player.GetOffhandWeapon( OFFHAND_LEFT )
- weapon.SetWeaponPrimaryClipCountAbsolute( 0 )
+ entity nowWeapon = player.GetOffhandWeapon( i )
+ if( IsValid( nowWeapon ))
+ {
+ if( nowWeapon.GetWeaponClassName() == "mp_ability_cloak" )
+ {
+ cloakWeapon = nowWeapon
+ offhandSlot = i
+ }
+ }
+ }
+ if( IsValid( cloakWeapon ) )
+ {
+ array<string> mods = cloakWeapon.GetMods()
+ // can't reset cooldown properly in script, let's give player a empty one
+ player.TakeWeapon( "mp_ability_cloak" ) // not using TakeWeaponNow() to fit vanilla behavior
+ player.GiveOffhandWeapon( "mp_ability_cloak", offhandSlot, mods )
+ cloakWeapon = player.GetOffhandWeapon( offhandSlot )
+ cloakWeapon.SetWeaponPrimaryClipCountAbsolute( 0 )
}
}
else
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
index ca8dc5f1..ec426754 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut
@@ -19,6 +19,8 @@ global function ShouldEntTakeDamage_SPMP
global function GetTitanBuildTime
global function TitanPlayerHotDropsIntoLevel
+global function SetRecalculateRespawnAsTitanStartPointCallback
+
struct {
bool killcamsEnabled = true
bool playerDeathsHidden = false
@@ -26,6 +28,8 @@ struct {
entity intermissionCamera
array<entity> specCams
+
+ entity functionref( entity player, entity basePoint ) recalculateRespawnAsTitanStartPointCallback
} file
void function BaseGametype_Init_MPSP()
@@ -443,6 +447,9 @@ void function RespawnAsTitan( entity player, bool manualPosition = false )
player.isSpawning = true
entity spawnpoint = FindSpawnPoint( player, true, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) && !IsFFAGame() )
+ if ( file.recalculateRespawnAsTitanStartPointCallback != null )
+ spawnpoint = file.recalculateRespawnAsTitanStartPointCallback( player, spawnpoint )
+
TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player )
asset model = GetPlayerSettingsAssetForClassName( titanLoadout.setFile, "bodymodel" )
@@ -500,7 +507,7 @@ void function RespawnAsTitan( entity player, bool manualPosition = false )
titan.Destroy() // pilotbecomestitan leaves an npc titan that we need to delete
else
RespawnAsPilot( player ) // this is 100% an edgecase, just avoid softlocking if we ever hit it in playable gamestates
-
+
camera.Fire( "Disable", "!activator", 0, player )
camera.Destroy()
})
@@ -509,6 +516,7 @@ void function RespawnAsTitan( entity player, bool manualPosition = false )
player.RespawnPlayer( null ) // spawn player as pilot so they get their pilot loadout on embark
player.SetOrigin( titan.GetOrigin() )
+ ClearTitanAvailable( player ) // titanfall succeed, clear titan availability
// don't make player titan when entity batteryContainer is not valid.
// This will prevent a servercrash that sometimes occur when evac is disabled and somebody is calling a titan in the defeat screen.
@@ -577,6 +585,11 @@ void function CheckForAutoTitanDeath( entity victim, entity attacker, var damage
}
}
+void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref( entity player, entity basePoint ) callbackFunc )
+{
+ file.recalculateRespawnAsTitanStartPointCallback = callbackFunc
+}
+
// stuff to change later
bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut
index 37b89169..ea88c1bc 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_battery_port.gnut
@@ -1 +1,219 @@
-//fuck \ No newline at end of file
+untyped
+global function InitTurretBatteryPort // only for fw turrets!
+
+void function InitTurretBatteryPort( entity batteryPort )
+{
+
+ batteryPort.s.beingUsed <- false // bool
+ batteryPort.s.hackAvaliable <- true // bool, for controlling hacking avaliablity
+
+ // SetUsableByGroup() updates is done in TurretStateWatcher()
+ batteryPort.SetUsableByGroup( "pilot" ) // show hind to any pilots
+ batteryPort.SetUsePrompts( "#RODEO_APPLY_BATTERY_HINT", "#RODEO_APPLY_BATTERY_HINT" ) // don't know what to use
+ AddCallback_OnUseEntity( batteryPort, OnUseTurretBatteryPort )
+}
+
+function OnUseTurretBatteryPort( entBeingUse, user )
+{
+ expect entity( entBeingUse )
+ expect entity( user )
+
+ //print( "try to use batteryPort" )
+ thread TryUseTurretBatteryPort( user, entBeingUse )
+}
+
+void function TryUseTurretBatteryPort( entity player, entity batteryPort )
+{
+ if( batteryPort.s.beingUsed ) // already being using
+ return
+
+ player.EndSignal( "OnDeath" )
+ player.EndSignal( "OnDestroy" )
+ player.EndSignal( "ScriptAnimStop" ) // so you can jump off animation
+ AddButtonPressedPlayerInputCallback( player, IN_JUMP, ForceStopUseBatteryPort )
+
+ OnThreadEnd(
+ function():( player )
+ {
+ RemoveButtonPressedPlayerInputCallback( player, IN_JUMP, ForceStopUseBatteryPort )
+ }
+ )
+
+
+ var BatteryPortUsable = batteryPort.s.isUsable
+
+ if( expect bool( BatteryPortUsable( batteryPort, player ) ) )
+ {
+ // friendly try to apply one, or enemy try to hack this turret
+ waitthread PlayerApplesBatteryPackToPort( player, batteryPort )
+ }
+}
+
+void function ForceStopUseBatteryPort( entity player )
+{
+ player.Signal( "ScriptAnimStop" )
+}
+
+void function PlayerApplesBatteryPackToPort( entity player, entity batteryPort )
+{
+ table result = {}
+ result.success <- false
+ batteryPort.s.beingUsed = true
+
+ BatteryPortSequenceStruct dataStruct = DisableCloakBeforeBatteryPortSequence( player )
+
+ // these are from _rodeo_titan.gnut
+ entity battery = GetBatteryOnBack( player )
+ battery.Hide() //Hide it because the animation has a battery model already
+ Battery_StopFX( battery )
+
+ entity tempBattery3p
+ tempBattery3p = CreatePropDynamic( RODEO_BATTERY_MODEL_FOR_RODEO_ANIMS )
+ tempBattery3p.SetParent( player, "R_HAND", false, 0.0 )
+ tempBattery3p.RemoveFromSpatialPartition()
+
+ entity tempBattery1p
+ tempBattery1p = CreatePropDynamic( RODEO_BATTERY_MODEL_FOR_RODEO_ANIMS )
+ tempBattery1p.SetParent( player.GetFirstPersonProxy(), "R_HAND", false, 0.0 )
+ tempBattery1p.RemoveFromSpatialPartition()
+
+ player.p.rodeoAnimTempProps.append( tempBattery3p )
+ player.p.rodeoAnimTempProps.append( tempBattery1p )
+
+ OnThreadEnd(
+ function() : ( battery, batteryPort, player, result, dataStruct )
+ {
+ if ( IsValid( battery ) ) // animation interrupted, otherwise the battery will be destroyed
+ {
+ battery.Show()
+ Battery_StartFX( battery )
+ }
+
+ if ( IsValid( batteryPort ) )
+ {
+ batteryPort.s.beingUsed = false
+ batteryPort.Anim_Stop()
+ }
+
+ if ( IsValid( player ) )
+ {
+ // restore control
+ DeployAndEnableWeapons( player )
+ //ViewConeFree( player ) // no need to lock viewcone
+
+ // clean up
+ ClearBatteryAnimTempProps( player )
+ PutEntityInSafeSpot( player, player, null, player.GetOrigin() + <0, 0, 32>, player.GetOrigin() )
+
+ CleanUpBatterySequenceForPlayer( player )
+ RestoreCloakAfterBatteryPortSequence( player, dataStruct )
+ }
+ }
+ )
+
+ FirstPersonSequenceStruct sequence
+ sequence.attachment = "REF" // only ref the batteryPort has
+
+ sequence.thirdPersonAnim = "pt_mp_battery_port_insert" //"pt_rodeo_ride_r_return_battery"
+ sequence.firstPersonAnim = "ptpov_mp_battery_port_insert" //"ptpov_rodeo_ride_r_return_battery"
+
+ // player stats
+ HolsterAndDisableWeapons( player )
+ //ViewConeZero( player ) // no need to lock viewcone
+
+ batteryPort.Anim_Play( "bp_mp_battery_port_insert" )
+
+ thread WaitForActivateBattery( player, battery, batteryPort )
+ waitthread FirstPersonSequence( sequence, player, batteryPort )
+}
+
+void function WaitForActivateBattery( entity player, entity battery, entity batteryPort )
+{
+ player.EndSignal( "OnDeath" )
+ player.EndSignal( "OnDestroy" )
+ player.EndSignal( "ScriptAnimStop" ) // so you can jump off animation
+ battery.EndSignal( "OnDestroy" )
+
+ player.WaitSignal( "BatteryActivate" ) // this is registered in _gamemode_fw.nut!
+ ApplyBatteryToBatteryPort( player, batteryPort )
+}
+
+void function ApplyBatteryToBatteryPort( entity player, entity batteryPort )
+{
+ if ( player.GetPlayerNetInt( "batteryCount" ) <= 0 ) // player actually not carrying a battery
+ return
+
+ entity battery = Rodeo_TakeBatteryAwayFromPilot( player )
+ if ( !IsValid( battery ) )
+ return
+
+ // player can apply battery
+
+ // disable hacking
+ batteryPort.s.hackAvaliable = false // can't be hacked again until completely killed
+
+
+ var useBatteryPort = batteryPort.s.useBattery
+ useBatteryPort( batteryPort, player )
+
+ // all things done, destroy this batt
+ battery.Destroy()
+}
+
+// for disabling cloak
+struct BatteryPortSequenceStruct
+{
+ bool wasCloaked = false
+ float cloakEndTime = 0.0
+}
+
+BatteryPortSequenceStruct function DisableCloakBeforeBatteryPortSequence( entity player )
+{
+ BatteryPortSequenceStruct dataStruct
+ if ( !IsCloaked( player ) )
+ return dataStruct // empty struct!
+
+ dataStruct.wasCloaked = true
+ dataStruct.cloakEndTime = player.GetCloakEndTime()
+ DisableCloak( player, 0.0 )
+
+ return dataStruct
+}
+
+bool function RestoreCloakAfterBatteryPortSequence( entity player, BatteryPortSequenceStruct dataStruct )
+{
+ if ( !IsAlive( player ) )
+ return false
+
+ if ( !dataStruct.wasCloaked )
+ return false
+
+ if ( dataStruct.cloakEndTime <= 0.0 )
+ return false
+
+ float remainingCloakDuration = max( 0.0, dataStruct.cloakEndTime - Time() )
+ if ( remainingCloakDuration <= CLOAK_FADE_IN ) //Has to be greater than 1.0 fade in duration, otherwise will cloak forever
+ return false
+
+ EnableCloak( player, remainingCloakDuration, CLOAK_FADE_IN )
+ return true
+}
+
+void function CleanUpBatterySequenceForPlayer( entity player )
+{
+ ClearPlayerAnimViewEntity( player )
+ player.AnimViewEntity_SetLerpOutTime( 0.4 ) // blend out the clear anim view entity
+ player.ClearParent()
+ player.Anim_Stop()
+}
+
+void function ClearBatteryAnimTempProps( entity player )
+{
+ foreach( tempProp in player.p.rodeoAnimTempProps )
+ {
+ if ( IsValid( tempProp ) )
+ tempProp.Destroy()
+ }
+
+ player.p.rodeoAnimTempProps.clear()
+} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
index 6cde4655..46b39ebc 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut
@@ -220,6 +220,8 @@ void function GameStateEnter_Playing_Threaded()
{
WaitFrame() // ensure timelimits are all properly set
+ thread DialoguePlayNormal() // runs dialogue play function
+
while ( GetGameState() == eGameState.Playing )
{
// could cache these, but what if we update it midgame?
@@ -268,6 +270,8 @@ void function GameStateEnter_WinnerDetermined_Threaded()
// do win announcement
int winningTeam = GetWinningTeamWithFFASupport()
+ DialoguePlayWinnerDetermined() // play a faction dialogue when winner is determined
+
foreach ( entity player in GetPlayerArray() )
{
int announcementSubstr
@@ -509,6 +513,20 @@ void function GameStateEnter_SuddenDeath()
{
// disable respawns, suddendeath calling is done on a kill callback
SetRespawnsEnabled( false )
+
+ // defensive fixes, so game won't stuck in SuddenDeath forever
+ bool mltElimited = false
+ bool imcElimited = false
+ if( GetPlayerArrayOfTeam_Alive( TEAM_MILITIA ).len() < 1 )
+ mltElimited = true
+ if( GetPlayerArrayOfTeam_Alive( TEAM_IMC ).len() < 1 )
+ imcElimited = true
+ if( mltElimited && imcElimited )
+ SetWinner( TEAM_UNASSIGNED )
+ else if( mltElimited )
+ SetWinner( TEAM_IMC )
+ else if( imcElimited )
+ SetWinner( TEAM_MILITIA )
}
@@ -874,3 +892,90 @@ float function GetTimeLimit_ForGameMode()
// default to 10 mins, because that seems reasonable
return GetCurrentPlaylistVarFloat( playlistString, 10 )
}
+
+// faction dialogue
+
+void function DialoguePlayNormal()
+{
+ int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() )
+ int winningTeam
+ int losingTeam
+ float diagIntervel = 71 // play a faction dailogue every 70 + 1s to prevent play together with winner dialogue
+
+ while( GetGameState() == eGameState.Playing )
+ {
+ wait diagIntervel
+ if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) )
+ {
+ winningTeam = TEAM_IMC
+ losingTeam = TEAM_MILITIA
+ }
+ if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) )
+ {
+ winningTeam = TEAM_MILITIA
+ losingTeam = TEAM_IMC
+ }
+ if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 )
+ {
+ PlayFactionDialogueToTeam( "scoring_winningLarge", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_losingLarge", losingTeam )
+ }
+ else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 )
+ {
+ PlayFactionDialogueToTeam( "scoring_winningClose", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_losingClose", losingTeam )
+ }
+ else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) )
+ {
+ continue
+ }
+ else
+ {
+ PlayFactionDialogueToTeam( "scoring_winning", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_losing", losingTeam )
+ }
+ }
+}
+
+void function DialoguePlayWinnerDetermined()
+{
+ int totalScore = GameMode_GetScoreLimit( GameRules_GetGameMode() )
+ int winningTeam
+ int losingTeam
+
+ if( GameRules_GetTeamScore( TEAM_MILITIA ) < GameRules_GetTeamScore( TEAM_IMC ) )
+ {
+ winningTeam = TEAM_IMC
+ losingTeam = TEAM_MILITIA
+ }
+ if( GameRules_GetTeamScore( TEAM_MILITIA ) > GameRules_GetTeamScore( TEAM_IMC ) )
+ {
+ winningTeam = TEAM_MILITIA
+ losingTeam = TEAM_IMC
+ }
+ if( IsRoundBased() ) // check for round based modes
+ {
+ if( GameRules_GetTeamScore( winningTeam ) != GameMode_GetRoundScoreLimit( GAMETYPE ) ) // no winner dialogue till game really ends
+ return
+ }
+ if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) >= totalScore * 0.4 )
+ {
+ PlayFactionDialogueToTeam( "scoring_wonMercy", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_lostMercy", losingTeam )
+ }
+ else if( GameRules_GetTeamScore( winningTeam ) - GameRules_GetTeamScore( losingTeam ) <= totalScore * 0.2 )
+ {
+ PlayFactionDialogueToTeam( "scoring_wonClose", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_lostClose", losingTeam )
+ }
+ else if( GameRules_GetTeamScore( winningTeam ) == GameRules_GetTeamScore( losingTeam ) )
+ {
+ PlayFactionDialogueToTeam( "scoring_tied", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_tied", losingTeam )
+ }
+ else
+ {
+ PlayFactionDialogueToTeam( "scoring_won", winningTeam )
+ PlayFactionDialogueToTeam( "scoring_lost", losingTeam )
+ }
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut
new file mode 100644
index 00000000..c33f4ef0
--- /dev/null
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut
@@ -0,0 +1,180 @@
+untyped
+
+
+global function ModelViewer_Init
+
+global function ToggleModelViewer
+
+global modelViewerModels = []
+
+#if DEV
+struct
+{
+ bool initialized
+ bool active
+ entity gameUIFreezeControls
+ array<string> playerWeapons
+ array<string> playerOffhands
+ bool dpadUpPressed = true
+ bool dpadDownPressed = true
+ var lastTitanAvailability
+} file
+#endif // DEV
+
+function ModelViewer_Init()
+{
+ #if DEV
+ if ( reloadingScripts )
+ return
+ AddClientCommandCallback( "ModelViewer", ClientCommand_ModelViewer )
+ #endif
+}
+
+function ToggleModelViewer()
+{
+ #if DEV
+ entity player = GetPlayerArray()[ 0 ]
+ if ( !file.active )
+ {
+ file.active = true
+
+ DisablePrecacheErrors()
+ wait 0.5
+
+ ModelViewerDisableConflicts()
+ Remote_CallFunction_NonReplay( player, "ServerCallback_ModelViewerDisableConflicts" )
+
+ ReloadShared()
+
+ if ( !file.initialized )
+ {
+ file.initialized = true
+ ControlsInit()
+ }
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_MVEnable" )
+
+ file.lastTitanAvailability = level.nv.titanAvailability
+ Riff_ForceTitanAvailability( eTitanAvailability.Never )
+
+ WeaponsRemove()
+ thread UpdateModelBounds()
+ }
+ else
+ {
+ file.active = false
+
+ Remote_CallFunction_NonReplay( player, "ServerCallback_MVDisable" )
+ RestorePrecacheErrors()
+
+ Riff_ForceTitanAvailability( file.lastTitanAvailability )
+
+ WeaponsRestore()
+ }
+ #endif
+}
+
+#if DEV
+function ModelViewerDisableConflicts()
+{
+ disable_npcs() //Just disable_npcs() for now, will probably add things later
+}
+
+function ReloadShared()
+{
+ modelViewerModels = GetModelViewerList()
+}
+
+function ControlsInit()
+{
+ file.gameUIFreezeControls = CreateEntity( "game_ui" )
+ file.gameUIFreezeControls.kv.spawnflags = 32
+ file.gameUIFreezeControls.kv.FieldOfView = -1.0
+
+ DispatchSpawn( file.gameUIFreezeControls )
+}
+
+bool function ClientCommand_ModelViewer( entity player, array<string> args )
+{
+ string command = args[ 0 ]
+ switch ( command )
+ {
+ case "freeze_player":
+ file.gameUIFreezeControls.Fire( "Activate", "!player", 0 )
+ break
+
+ case "unfreeze_player":
+ file.gameUIFreezeControls.Fire( "Deactivate", "!player", 0 )
+ break
+ }
+
+ return true
+}
+
+function UpdateModelBounds()
+{
+ wait( 0.3 )
+
+ foreach ( index, modelName in modelViewerModels )
+ {
+ entity model = CreatePropDynamic( expect asset( modelName ) )
+ local mins = model.GetBoundingMins()
+ local maxs = model.GetBoundingMaxs()
+
+ mins.x = min( -8.0, mins.x )
+ mins.y = min( -8.0, mins.y )
+ mins.z = min( -8.0, mins.z )
+
+ maxs.x = max( 8.0, maxs.x )
+ maxs.y = max( 8.0, maxs.y )
+ maxs.z = max( 8.0, maxs.z )
+
+ Remote_CallFunction_NonReplay( GetPlayerArray()[ 0 ], "ServerCallback_MVUpdateModelBounds", index, mins.x, mins.y, mins.z, maxs.x, maxs.y, maxs.z )
+ model.Destroy()
+ }
+}
+
+function WeaponsRemove()
+{
+ entity player = GetPlayerArray()[0]
+ if ( !IsValid( player ) )
+ return
+
+ file.playerWeapons.clear()
+ file.playerOffhands.clear()
+
+ array<entity> weapons = player.GetMainWeapons()
+ foreach ( weaponEnt in weapons )
+ {
+ string weapon = weaponEnt.GetWeaponClassName()
+ file.playerWeapons.append( weapon )
+ player.TakeWeapon( weapon )
+ }
+
+ array<entity> offhands = player.GetOffhandWeapons()
+ foreach ( index, offhandEnt in offhands )
+ {
+ string offhand = offhandEnt.GetWeaponClassName()
+ file.playerOffhands.append( offhand )
+ player.TakeOffhandWeapon( index )
+ }
+}
+
+function WeaponsRestore()
+{
+ entity player = GetPlayerArray()[0]
+ if ( !IsValid( player ) )
+ return
+
+ foreach ( weapon in file.playerWeapons )
+ {
+ player.GiveWeapon( weapon )
+ }
+
+ foreach ( index, offhand in file.playerOffhands )
+ {
+ player.GiveOffhandWeapon( offhand, index )
+ }
+}
+
+#endif // DEV
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
index 2d1ff074..dacd43b0 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut
@@ -187,9 +187,19 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage
return
if ( attacker.IsTitan() )
- AddPlayerScore( attacker, "TitanKillTitan", victim.GetTitanSoul().GetOwner() )
+ {
+ if( victim.GetBossPlayer() || victim.IsPlayer() ) // to confirm this is a pet titan or player titan
+ AddPlayerScore( attacker, "TitanKillTitan", attacker ) // this will show the "Titan Kill" callsign event
+ else
+ AddPlayerScore( attacker, "TitanKillTitan" )
+ }
else
- AddPlayerScore( attacker, "KillTitan", victim.GetTitanSoul().GetOwner() )
+ {
+ if( victim.GetBossPlayer() || victim.IsPlayer() )
+ AddPlayerScore( attacker, "KillTitan", attacker )
+ else
+ AddPlayerScore( attacker, "KillTitan" )
+ }
table<int, bool> alreadyAssisted
foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory )
@@ -205,6 +215,9 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage
Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), attackerInfo.time )
}
}
+
+ if( !victim.IsNPC() ) // don't let killing a npc titan plays dialogue
+ KilledPlayerTitanDialogue( attacker, victim )
}
void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageInfo )
@@ -251,3 +264,42 @@ void function ScoreEvent_SetupEarnMeterValuesForTitanModes()
{
// relatively sure we don't have to do anything here but leaving this function for consistency
}
+
+// faction dialogue
+void function KilledPlayerTitanDialogue( entity attacker, entity victim )
+{
+ if( !attacker.IsPlayer() )
+ return
+ entity titan
+ if ( victim.IsTitan() )
+ titan = victim
+
+ if( !IsValid( titan ) )
+ return
+ string titanCharacterName = GetTitanCharacterName( titan )
+
+ switch( titanCharacterName )
+ {
+ case "ion":
+ PlayFactionDialogueToPlayer( "kc_pilotkillIon", attacker )
+ return
+ case "tone":
+ PlayFactionDialogueToPlayer( "kc_pilotkillTone", attacker )
+ return
+ case "legion":
+ PlayFactionDialogueToPlayer( "kc_pilotkillLegion", attacker )
+ return
+ case "scorch":
+ PlayFactionDialogueToPlayer( "kc_pilotkillScorch", attacker )
+ return
+ case "ronin":
+ PlayFactionDialogueToPlayer( "kc_pilotkillRonin", attacker )
+ return
+ case "northstar":
+ PlayFactionDialogueToPlayer( "kc_pilotkillNorthstar", attacker )
+ return
+ default:
+ PlayFactionDialogueToPlayer( "kc_pilotkilltitan", attacker )
+ return
+ }
+}
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut
index 0984eaa8..153be7cd 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut
@@ -42,6 +42,9 @@ global function Battery_StopFXAndHideIconForPlayer
global function RemovePlayerAirControl //This function should really be in a server only SP & MP utility script file. No such file exists as of right now.
global function RestorePlayerAirControl //This function should really be in a server only SP & MP utility script file. No such file exists as of right now.
+// needs these
+global function Rodeo_TakeBatteryAwayFromPilot
+
#if DEV
global function SetDebugRodeoPrint
global function GetDebugRodeoPrint
@@ -338,7 +341,7 @@ void function RodeoBatteryRemoval( entity pilot )
if ( !playerHadBattery )
{
- AddPlayerScore( pilot, "PilotBatteryStolen" )
+ AddPlayerScore( pilot, "PilotBatteryStolen", pilot )
entity battery = Rodeo_CreateBatteryPack( titan )
Rodeo_PilotPicksUpBattery( pilot, battery )
thread BatteryThiefHighlight( pilot )
@@ -1868,7 +1871,7 @@ void function Rodeo_OnTouchBatteryPack_Internal( entity player, entity batteryPa
Battery_StopFX( batteryPack ) //Will be turned on again when player loses cloak
Rodeo_PilotPicksUpBattery( player, batteryPack )
- AddPlayerScore( player, "PilotBatteryPickup" )
+ AddPlayerScore( player, "PilotBatteryPickup", player )
// MessageToPlayer( player, eEventNotifications.Rodeo_PilotPickedUpBattery )
return
}
@@ -1893,7 +1896,7 @@ void function Rodeo_PilotAddsBatteryToFriendlyTitan( entity rider, entity titan
Rodeo_ApplyBatteryToTitan( battery, titan ) //This destroys the battery
- AddPlayerScore( rider, "PilotBatteryApplied" )
+ AddPlayerScore( rider, "PilotBatteryApplied", rider )
EmitSoundOnEntityOnlyToPlayer( rider, rider, PILOT_APPLIES_BATTERY_TO_TITAN_HEALTH_RESTORED_SOUND )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
index fbaf9e02..85f5aa05 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut
@@ -3263,6 +3263,24 @@ string function Loadouts_GetSetFileForRequestedClass( entity player )
return loadout.race
}
+ #if DEV
+ // these are #if DEV'd until they work as their function names describe they should
+ // atm these only exist to allow the #if DEV'd calls to them for bot code in this file to compile on retail
+ // bots don't work in retail at all, so this doesn't matter for us really, but these should be unDEV'd and api'd properly once they are functional
+
+ PilotLoadoutDef function GetRandomPilotLoadout()
+ {
+ PilotLoadoutDef loadout
+ return loadout
+ }
+
+ TitanLoadoutDef function GetRandomTitanLoadout( string setFile )
+ {
+ TitanLoadoutDef loadout
+ return loadout
+ }
+ #endif
+
bool function Loadouts_TryGivePilotLoadout( entity player )
{
if ( !Loadouts_CanGivePilotLoadout( player ) )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut
new file mode 100644
index 00000000..c390b5f5
--- /dev/null
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut
@@ -0,0 +1,294 @@
+global function SH_PowerUp_Init
+global function GetPowerUpFromIndex
+global function GetPowerUpFromItemRef
+
+//Proto Use Functions
+global function PowerUp_Func_GiveEPG
+global function PowerUp_Func_GiveHELL
+global function PowerUp_Func_GiveLSTAR
+global function PowerUp_Func_GiveSHOTGUN
+global function PowerUp_Func_GiveArmorSmall
+global function PowerUp_Func_GiveArmorMedium
+global function PowerUp_Func_GiveArmorLarge
+global function PowerUp_Func_TitanBuildTime
+global function PowerUp_Func_PilotUpgrade
+global function PowerUp_Func_GiveTicks
+
+global struct PowerUp
+{
+ int index
+ string name
+ asset icon
+ asset model
+ asset baseModel
+ string itemRef
+ vector modelOffset
+ vector modelAngles
+ float respawnDelay
+ vector glowColor
+ bool titanPickup
+ int maxInWorld
+ void functionref( entity ) destroyFunc
+ bool functionref() spawnFunc
+}
+
+const bool TITAN_PICKUP = true
+const bool PILOT_PICKUP = false
+
+struct
+{
+ array<PowerUp> powerUps
+}file
+
+const TEST_MODEL = $"models/communication/terminal_com_station.mdl"
+const TEST_ICON = $"vgui/HUD/coop/minimap_coop_nuke_titan"
+
+void function SH_PowerUp_Init()
+{
+ #if SERVER || CLIENT
+ PrecacheWeapon( "mp_weapon_epg" )
+ PrecacheWeapon( "mp_weapon_arena1" )
+ PrecacheWeapon( "mp_weapon_arena2" )
+ PrecacheWeapon( "mp_weapon_arena3" )
+ PrecacheWeapon( "mp_weapon_lstar" )
+ PrecacheWeapon( "mp_weapon_shotgun_doublebarrel" )
+ PrecacheWeapon( "mp_weapon_frag_drone" )
+ #endif
+
+ file.powerUps.resize( ePowerUps.count )
+ CreatePowerUp( ePowerUps.weaponEPG, "mp_weapon_epg", "EPG", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveEPG, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/auto_rocket_launcher_ARL/w_ARL.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.weaponHELL, "mp_weapon_arena3", "HELL", 90.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveHELL, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/defender/w_defender.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.weaponLSTAR, "mp_weapon_lstar", "LSTAR", 45.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveLSTAR, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/lstar/w_lstar.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.weaponSHOTGUN, "mp_weapon_shotgun_doublebarrel", "Shrapnel Shotgun", 30.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveSHOTGUN, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/weapons/mastiff_stgn/w_mastiff.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.armorSmall, "mp_loot_armor_small", "Armor +5", 30.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorSmall, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_small.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.armorMedium, "mp_loot_armor_medium", "Armor +25", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorMedium, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_small.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.armorLarge, "mp_loot_armor_large", "Armor +50", 120.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveArmorLarge, <0,0,255>, PILOT_PICKUP, $"vgui/HUD/op_health_mini", $"models/gameplay/health_pickup_large.mdl", $"models/containers/plastic_pallet_01.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.titanTimeReduction, "mp_loot_titan_build_credit", "Titan Build Time", 20.0, 2, FRAShouldSpawnPowerUp, PowerUp_Func_TitanBuildTime, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/titans/medium/titan_medium_battery_static.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.LTS_TitanTimeReduction, "mp_loot_titan_build_credit_lts", "Titan Build Time", 60.0, 0, LTSShouldSpawnPowerUp, PowerUp_Func_TitanBuildTime, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/titans/medium/titan_medium_battery_static.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.pilotUpgrade, "mp_loot_pilot_upgrade", "Can of Spinach", 120.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_PilotUpgrade, <0,255,0>, PILOT_PICKUP, $"vgui/HUD/op_drone_mini", $"models/humans/pilots/pilot_light_ged_m.mdl", $"models/communication/flag_base.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+ CreatePowerUp( ePowerUps.ticks, "mp_weapon_frag_drone", "Ticks", 60.0, 0, DefaultShouldSpawnPowerUp, PowerUp_Func_GiveTicks, <255,0,0>, PILOT_PICKUP, $"vgui/HUD/op_ammo_mini", $"models/robots/drone_frag/frag_drone_proj.mdl", $"models/robots/drone_frag/frag_drone_proj.mdl", < 0, 0, 32 >, < 0, 0, 0 > )
+}
+
+bool function FRAShouldSpawnPowerUp()
+{
+ return GAMETYPE == FREE_AGENCY
+}
+
+bool function LTSShouldSpawnPowerUp()
+{
+ if ( HasIronRules() )
+ return false
+
+ // modified for fw
+ //return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB )
+ return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB || GAMETYPE == FORT_WAR )
+}
+
+bool function DefaultShouldSpawnPowerUp()
+{
+ return GetCurrentPlaylistVarInt( "power_ups_enabled", 0 ) == 1
+}
+
+void function CreatePowerUp( int enumIndex, string item, string displayName, float respawnTime, int worldLimit, bool functionref() shouldSpawnFunction, void functionref( entity ) destroyFunction, vector color, bool canTitanPickup, asset worldIcon, asset worldModel, asset worldBase, vector worldModelOffset, vector worldModelAngle )
+{
+ PowerUp power
+ power.index = enumIndex
+ power.name = displayName
+ power.icon = worldIcon
+ power.model = worldModel
+ power.baseModel = worldBase
+ power.itemRef = item
+ power.modelOffset = worldModelOffset
+ power.modelAngles = worldModelAngle
+ power.respawnDelay = respawnTime
+ power.destroyFunc = destroyFunction
+ power.spawnFunc = shouldSpawnFunction
+ power.glowColor = color
+ power.titanPickup = canTitanPickup
+ power.maxInWorld = worldLimit
+ file.powerUps[enumIndex] = power
+
+ #if CLIENT
+ PrecacheHUDMaterial( worldIcon )
+ #else
+ PrecacheModel( worldModel )
+ PrecacheModel( worldBase )
+ #if R1_VGUI_MINIMAP
+ Minimap_PrecacheMaterial( worldIcon )
+ #endif
+ #endif
+}
+
+PowerUp function GetPowerUpFromIndex( int index )
+{
+ return file.powerUps[index]
+}
+
+PowerUp function GetPowerUpFromItemRef( string ref )
+{
+ foreach( power in file.powerUps )
+ {
+ if ( power.itemRef == ref )
+ return power
+ }
+
+ Assert( false, "Power Up not found")
+ unreachable
+}
+
+//////////////////////////////////////////////
+// PROTO USE FUNCTIONS - Maybe should be a bunch of new item_ classes with their own healthkit callbacks?
+//////////////////////////////////////////////
+void function PowerUp_Func_GiveEPG( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ GiveWeaponPowerUp( player, "mp_weapon_arena2" )
+ #endif
+}
+
+void function PowerUp_Func_GiveHELL( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ GiveWeaponPowerUp( player, "mp_weapon_arena3" )
+ #endif
+}
+
+void function PowerUp_Func_GiveLSTAR( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ GiveWeaponPowerUp( player, "mp_weapon_arena1" )
+ #endif
+}
+
+void function PowerUp_Func_GiveSHOTGUN( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ GiveWeaponPowerUp( player, "mp_weapon_shotgun_doublebarrel" )
+ #endif
+}
+
+void function PowerUp_Func_GiveTicks( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ player.TakeOffhandWeapon( OFFHAND_ORDNANCE )
+ player.GiveOffhandWeapon( "mp_weapon_frag_drone", OFFHAND_ORDNANCE )
+ thread RestoreDefaultOffhandWeapon( player )
+ #endif
+}
+
+#if SERVER
+void function RestoreDefaultOffhandWeapon( entity player )
+{
+ player.EndSignal( "OnDeath" )
+ player.EndSignal( "OnDestroy" )
+
+ while( true )
+ {
+ player.WaitSignal( "ThrowGrenade" )
+
+ if ( player.IsTitan() )
+ continue
+
+ entity weapon = player.GetOffhandWeapon( OFFHAND_ORDNANCE )
+ if ( weapon.GetWeaponPrimaryClipCount() == 0 )
+ {
+ player.TakeOffhandWeapon( OFFHAND_ORDNANCE )
+ int loadoutIndex = GetActivePilotLoadoutIndex( player )
+ PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, loadoutIndex )
+ player.GiveOffhandWeapon( loadout.ordnance, OFFHAND_ORDNANCE )
+ return
+ }
+ }
+}
+
+void function GiveWeaponPowerUp( entity player, string newWeapon )
+{
+ array<entity> weapons = player.GetMainWeapons()
+ string weaponToSwitch = player.GetLatestPrimaryWeapon().GetWeaponClassName()
+
+ if ( player.GetActiveWeapon() != player.GetAntiTitanWeapon() )
+ {
+ foreach ( weapon in weapons )
+ {
+ string weaponClassName = weapon.GetWeaponClassName()
+ if ( weaponClassName == newWeapon )
+ {
+ weaponToSwitch = weaponClassName
+ break
+ }
+ }
+ }
+
+ player.TakeWeaponNow( weaponToSwitch )
+ player.GiveWeapon( newWeapon )
+ player.SetActiveWeaponByName( newWeapon )
+}
+#endif
+
+void function PowerUp_Func_GiveArmorSmall( entity player )
+{
+ GiveArmor( player, 5 )
+}
+
+void function PowerUp_Func_GiveArmorMedium( entity player )
+{
+ GiveArmor( player, 25 )
+}
+
+void function PowerUp_Func_GiveArmorLarge( entity player )
+{
+ GiveArmor( player, 50 )
+}
+
+void function GiveArmor( entity player, int amount )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+ int currentShieldHealth = player.GetShieldHealth()
+ int currentMaxShieldHealth = player.GetShieldHealthMax()
+ player.SetShieldHealth( min( 200, amount + currentShieldHealth ) )
+ player.SetShieldHealthMax( min( 200, amount + currentMaxShieldHealth ) )
+ #endif
+}
+
+void function PowerUp_Func_TitanBuildTime( entity player )
+{
+ #if SERVER
+ entity battery = Rodeo_CreateBatteryPack()
+ battery.SetOrigin( player.GetOrigin() )
+ #endif
+}
+
+
+
+void function PowerUp_Func_PilotUpgrade( entity player )
+{
+ #if SERVER
+ if ( player.IsTitan() )
+ return
+
+ int loadoutIndex = GetPersistentSpawnLoadoutIndex( player, "pilot" )
+
+ PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, loadoutIndex )
+
+ loadout.primary = "mp_weapon_arena2"
+ loadout.secondary = "mp_weapon_mgl"
+ loadout.ordnance = "mp_weapon_grenade_emp"
+
+ UpdateDerivedPilotLoadoutData( loadout )
+
+ GivePilotLoadout( player, loadout )
+ SetActivePilotLoadoutIndex( player, loadoutIndex )
+ #endif
+} \ No newline at end of file
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut
index a51e528f..18df6a6f 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_server_to_client_stringcommands.gnut
@@ -1,6 +1,4 @@
#if CLIENT
-global function ServerToClientStringCommands_Init
-
global function AddServerToClientStringCommandCallback
global function NSClientCodeCallback_RecievedServerToClientStringCommand
#endif
@@ -14,11 +12,6 @@ struct {
table< string, array< void functionref( array<string> args ) > > callbacks
} file
-void function ServerToClientStringCommands_Init()
-{
- getroottable().rawset( "NSClientCodeCallback_RecievedServerToClientStringCommand", NSClientCodeCallback_RecievedServerToClientStringCommand )
-}
-
void function AddServerToClientStringCommandCallback( string command, void functionref( array<string> args ) callback )
{
if ( !( command in file.callbacks ) )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut
index c9d986bc..57361362 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut
@@ -21,7 +21,6 @@ global function ReplacementTitan
global function TryAnnounceTitanfallWarningToEnemyTeam
global function GetTitanForPlayer
-
global function ShouldSetTitanRespawnTimer
global function PauseTitanTimers
@@ -33,6 +32,7 @@ global function SetReplacementTitanGamemodeRules
global function SetRequestTitanGamemodeRules
global function CreateTitanForPlayerAndHotdrop
+global function SetRequestTitanAllowedCallback
struct {
array<int> ETATimeThresholds = [ 120, 60, 30, 15 ]
@@ -53,6 +53,8 @@ struct {
bool functionref( entity ) ReplacementTitanGamemodeRules
bool functionref( entity, vector ) RequestTitanGamemodeRules
+ bool functionref( entity player, array< string > args ) RequestTitanAllowedCallback
+
} file
const nagInterval = 40
@@ -87,6 +89,10 @@ function ReplacementTitans_Init()
FlagInit( "LevelHasRoof" )
}
+void function SetRequestTitanAllowedCallback( bool functionref( entity player, array<string> args ) RequestTitanAllowedCallback )
+{
+ file.RequestTitanAllowedCallback = RequestTitanAllowedCallback
+}
void function ReplacementTitan_InitPlayer( entity player )
{
@@ -424,6 +430,7 @@ function TryETATitanReadyAnnouncement( entity player )
TryReplacementTitanReadyAnnouncement( player )
return
}
+
//This entire loop is probably too complicated now for what it's doing. Simplify next game!
//Loop might be pretty hard to read, a particular iteration of the loop is written in comments below
@@ -524,6 +531,9 @@ function req()
bool function ClientCommand_RequestTitan( entity player, array<string> args )
{
+ if( file.RequestTitanAllowedCallback != null && !file.RequestTitanAllowedCallback( player, args ) )
+ return true
+
ReplacementTitan( player ) //Separate function because other functions will call ReplacementTitan
return true
}
@@ -877,6 +887,20 @@ void function CreateTitanForPlayerAndHotdrop( entity player, Point spawnPoint, T
player.Signal( "titan_impact" )
thread TitanNPC_WaitForBubbleShield_StartAutoTitanBehavior( titan )
+ thread PlayerEarnMeter_ReplacementTitanThink( player, titan )
+}
+
+void function PlayerEarnMeter_ReplacementTitanThink( entity player, entity titan )
+{
+ player.EndSignal( "OnDestroy" )
+ OnThreadEnd(
+ function(): ( player )
+ {
+ if( IsValid( player ) )
+ PlayerEarnMeter_Reset( player )
+ }
+ )
+ titan.WaitSignal( "OnDestroy" )
}
void function CleanupTitanFallDisablingEntity( entity titanFallDisablingEntity, entity titan )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut
index 933e9988..6972d5ff 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans_drop.gnut
@@ -4,6 +4,7 @@ global function HullTraceDropPoint
global function DebugTitanfall
global function TitanFindDropNodes
global function TitanHulldropSpawnpoint
+global function SetRecalculateTitanReplacementPointCallback
global const TITANDROP_LOS_DIST = 2000 // 2D distance at which we do the line of sight check to see where the player wants to call in the titan
global const TITANDROP_MIN_FOV = 10
@@ -19,8 +20,15 @@ global const TITANDROP_FALLBACK_DIST = 150 // if the ground search hits, we go t
struct
{
int replacementSpawnpointsID
+ Point functionref(Point originalPoint, entity player) recalculateTitanReplacementPointCallback
} file
+
+void function SetRecalculateTitanReplacementPointCallback(Point functionref(Point originalPoint, entity player) recalculateTitanReplacementPointCallback)
+{
+ file.recalculateTitanReplacementPointCallback = recalculateTitanReplacementPointCallback
+}
+
void function ReplacementTitansDrop_Init()
{
AddSpawnCallback( "info_spawnpoint_titan", AddDroppoint )
@@ -117,7 +125,10 @@ Point function GetTitanReplacementPoint( entity player, bool forDebugging = fals
vector playerEyeAngles = player.EyeAngles()
vector playerOrg = player.GetOrigin()
- return CalculateTitanReplacementPoint( playerOrg, playerEyePos, playerEyeAngles, forDebugging )
+ Point tempPoint = CalculateTitanReplacementPoint( playerOrg, playerEyePos, playerEyeAngles, forDebugging)
+ if( file.recalculateTitanReplacementPointCallback != null )
+ tempPoint = file.recalculateTitanReplacementPointCallback( tempPoint, player )
+ return tempPoint
}
Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEyePos, vector playerEyeAngles, bool forDebugging = false )
@@ -165,6 +176,7 @@ Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEy
Point point
point.origin = dropPoint
point.angles = yawAngles
+
return point
}
}
@@ -215,7 +227,8 @@ Point function CalculateTitanReplacementPoint( vector playerOrg, vector playerEy
Point point
point.origin = nodeOrigin
point.angles = Vector( 0, yaw, 0 )
- return point
+
+ return point
}
vector function GetPathNodeSearchPosWithLookPos( vector playerOrg, vector playerEyePos, vector playerEyeForward, vector playerLookPos, bool debug )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut
index d600cb03..396d5624 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_titan_health.gnut
@@ -1010,7 +1010,7 @@ void function AddCreditToTitanCoreBuilder( entity titan, float credit )
if ( IsValid( bossPlayer ) && !coreWasAvailable && IsCoreChargeAvailable( bossPlayer, soul ) )
{
- AddPlayerScore( bossPlayer, "TitanCoreEarned" )
+ AddPlayerScore( bossPlayer, "TitanCoreEarned", bossPlayer ) // this will show the "Core Earned" callsign event
#if MP
UpdateTitanCoreEarnedStat( bossPlayer, titan )
PIN_PlayerAbilityReady( bossPlayer, "core" )
diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut
index 5f72385e..d0a2d5e4 100644
--- a/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut
+++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut
@@ -68,6 +68,11 @@ bool function ClientCommand_TitanEject( entity player, array<string> args )
if ( !PlayerCanEject( player ) )
return true
+ // check array length before accessing index to avoid oob access
+ // prevents crashing a server by just calling `TitanEject` without arguments
+ if( args.len() < 1 )
+ return true
+
int ejectPressCount = args[ 0 ].tointeger()
if ( ejectPressCount < 3 )
return true