From d585bac7d294e715ccd6a3fe48e43b43a56565b7 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 20 Jul 2022 16:42:04 +0200 Subject: Mention reproducing bugs and feature usage desc. (#436) --- .github/pull_request_template.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 871b946e..8cda06a3 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,6 +3,9 @@ WHEN OPENING A PULL REQUEST KEEP IN MIND: -> If the changes you made can be summarised in a screenshot, add one (e.g. you changed the layout of an in-game menu) -> If the changes you made can be summarised in a screenrecording, add one (e.g. proof that you fixed a certain bug) +-> For fixes, description on how to reproduce the bug are appreciated and help your PR get merged faster +-> For features, description on how to use or a sample mod that makes use of the feature is appreciated and will help your PR get merged faster + -> Please use a sensible title for your pull request -> Please describe the changes you made. The easier it is to understand what you changed, the higher the chances of your PR being merged (in a timely manner). -- cgit v1.2.3 From ef30d11ccada0a708366245ab9aa87e6c4fbede9 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Thu, 21 Jul 2022 08:20:28 +0800 Subject: Fix TFFA from crashing when a player leaves during the intro sequence (#434) * Fix TFFA from crashing when a player leaves during the intro sequence * Fix Formatting --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut index 30aacad5..3b75e725 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_tffa.gnut @@ -63,6 +63,9 @@ void function PlayerWatchesTFFAIntroIntermissionCam( entity player ) wait TFFAIntroLength + if ( !IsValid( player ) ) // if player leaves during the intro sequence + return + RespawnAsTitan( player, false ) TryGameModeAnnouncement( player ) } @@ -75,4 +78,4 @@ void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var d // why isn't this PGS_SCORE? odd game attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) } -} \ No newline at end of file +} -- cgit v1.2.3 From a7df0676bfc21eb9471aa4f486b0383b533a1317 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Thu, 21 Jul 2022 08:30:10 +0800 Subject: Prevent crashing when an NPC titan kills a player or tries to earn score in Attrition (#425) * Small Fix towards Attrition * Update again after having more thoughts --- .../mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index 9a94b848..fae778d6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -78,6 +78,10 @@ void function HandleScoreEvent( entity victim, entity attacker, var damageInfo ) // Hacked spectre filter if ( victim.GetOwner() == attacker ) return + + // NPC titans without an owner player will not count towards any team's score + if ( attacker.IsNPC() && attacker.IsTitan() && !IsValid( GetPetTitanOwner( attacker ) ) ) + return // Split score so we can check if we are over the score max // without showing the wrong value on client @@ -507,4 +511,4 @@ void function AITdm_CleanupBoredNPCThread( entity guy ) print( "cleaning up bored npc: " + guy + " from team " + guy.GetTeam() ) guy.Destroy() -} \ No newline at end of file +} -- cgit v1.2.3 From fdc38f3867a3727edf097ec0241efc0b59d75395 Mon Sep 17 00:00:00 2001 From: Kyle Gospodnetich Date: Thu, 21 Jul 2022 15:38:16 -0700 Subject: Fix missing fonts under Linux (#437) * Replace Arial and Lucidia fonts with Lato and Fira Code respectively, this fixes Linux users needing to install proprietary fonts to use the in-game console. * Clean up gitattributes and encoding.yml to be more specific about the txt files it checks against. UTF-16LE-BOM will crash the game with a division by zero error if it's not expecting the file to be encoded as such. * Replace Fira Code with Northstar Mono (Modified Fira Mono Regular) --- .gitattributes | 2 +- .github/workflows/encoding.yml | 2 +- Northstar.Client/mod/resource/Lato-Regular.ttf | Bin 0 -> 657212 bytes Northstar.Client/mod/resource/NorthstarMono.ttf | Bin 0 -> 170600 bytes Northstar.Client/mod/resource/fontfiletable.txt | 40 ++++++++++++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 Northstar.Client/mod/resource/Lato-Regular.ttf create mode 100644 Northstar.Client/mod/resource/NorthstarMono.ttf create mode 100644 Northstar.Client/mod/resource/fontfiletable.txt diff --git a/.gitattributes b/.gitattributes index f18a3db7..c6a941df 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1 @@ -/Northstar.Client/mod/resource/*.txt text diff working-tree-encoding=UTF-16LE-BOM \ No newline at end of file +/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM \ No newline at end of file diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index 0b54639e..ac63e784 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -9,5 +9,5 @@ jobs: uses: actions/checkout@v2 - name: Check localization files encoding run: | - files=$(ls Northstar.Client/mod/resource/*.txt) + files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) IFS=$'\n'; files=($files); unset IFS; ! file --mime "${files[@]}" | grep -v "charset=utf-16le" diff --git a/Northstar.Client/mod/resource/Lato-Regular.ttf b/Northstar.Client/mod/resource/Lato-Regular.ttf new file mode 100644 index 00000000..adbfc467 Binary files /dev/null and b/Northstar.Client/mod/resource/Lato-Regular.ttf differ diff --git a/Northstar.Client/mod/resource/NorthstarMono.ttf b/Northstar.Client/mod/resource/NorthstarMono.ttf new file mode 100644 index 00000000..2814eee6 Binary files /dev/null and b/Northstar.Client/mod/resource/NorthstarMono.ttf differ diff --git a/Northstar.Client/mod/resource/fontfiletable.txt b/Northstar.Client/mod/resource/fontfiletable.txt new file mode 100644 index 00000000..b4238134 --- /dev/null +++ b/Northstar.Client/mod/resource/fontfiletable.txt @@ -0,0 +1,40 @@ +FontFileTable +{ + "Default" "resource/MetronicPro-Regular.vfont" [!$JAPANESE && !$TCHINESE] + "Default" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "Default" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + + "DefaultBold" "resource/MetronicPro-SemiBold.vfont" [!$JAPANESE && !$TCHINESE] + "DefaultBold" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "DefaultBold" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + + "Titanfall" "resource/Titanfall-Regular.vfont" [!$JAPANESE && !$TCHINESE && !$RUSSIAN] + "Titanfall" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] + "Titanfall" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] + "Titanfall" "resource/MetronicPro-SemiBold.vfont" [$RUSSIAN] + + "marlett" "vgui/fonts/marlett.ttf" + + // Everything below is DONOTSHIP / Dev only + + "arial unicode ms" "resource/Lato-Regular.ttf" + + "lucida console" "resource/NorthstarMono.ttf" [$PC] + "lucida console" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] + + "tahoma" "fonts\\tahoma.ttf" [$PC] + "tahoma" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] + + "tahoma bold" "fonts\\tahomabd.ttf" [$PC] + "tahoma bold" "resource/MetronicPro-SemiBold.vfont" [$GAMECONSOLE] + + "courier new" "fonts\\cour.ttf" [$PC] + "courier new" "vgui/fonts/cour.ttf" [$GAMECONSOLE] + + "times new roman" "fonts\\times.ttf" [$PC] + "times new roman" "vgui/fonts/times.ttf" [$GAMECONSOLE] + + "arial" "resource/Lato-Regular.ttf" + "arial bold" "resource/Lato-Regular.ttf" + "arial narrow" "resource/Lato-Regular.ttf" +} -- cgit v1.2.3 From 2cbdc1f6338a77ef64927e07ae356b64d15d6e4d Mon Sep 17 00:00:00 2001 From: Maya Date: Fri, 22 Jul 2022 01:21:11 +0200 Subject: Prevent effect hibernation for dome shields (#415) --- Northstar.CustomServers/mod/scripts/vscripts/_bubble_shield.gnut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_bubble_shield.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_bubble_shield.gnut index 30758bec..f09ef957 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_bubble_shield.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_bubble_shield.gnut @@ -223,6 +223,7 @@ entity function CreateBubbleShieldWithSettings( int team, vector origin, vector entity neutralColoredFX = StartParticleEffectInWorld_ReturnEntity( BUBBLE_SHIELD_FX_PARTICLE_SYSTEM_INDEX, coloredFXOrigin, <0, 0, 0> ) SetTeam( neutralColoredFX, team ) bubbleShieldDotS.neutralColoredFX <- neutralColoredFX + neutralColoredFX.DisableHibernation() bubbleShieldFXs.append( neutralColoredFX ) } else @@ -232,11 +233,13 @@ entity function CreateBubbleShieldWithSettings( int team, vector origin, vector SetTeam( friendlyColoredFX, team ) friendlyColoredFX.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY EffectSetControlPointVector( friendlyColoredFX, 1, FRIENDLY_COLOR_FX ) + friendlyColoredFX.DisableHibernation() entity enemyColoredFX = StartParticleEffectInWorld_ReturnEntity( BUBBLE_SHIELD_FX_PARTICLE_SYSTEM_INDEX, coloredFXOrigin, <0, 0, 0> ) SetTeam( enemyColoredFX, team ) enemyColoredFX.kv.VisibilityFlags = ENTITY_VISIBLE_TO_ENEMY EffectSetControlPointVector( enemyColoredFX, 1, ENEMY_COLOR_FX ) + enemyColoredFX.DisableHibernation() bubbleShieldDotS.friendlyColoredFX <- friendlyColoredFX bubbleShieldDotS.enemyColoredFX <- enemyColoredFX -- cgit v1.2.3 From 235e9bdd9be2c338d9a068fea018d41eb3881016 Mon Sep 17 00:00:00 2001 From: H0L0theBard Date: Tue, 26 Jul 2022 00:59:03 +1000 Subject: Removal of live fire map from titan tag (#453) Closes #386 --- Northstar.Custom/keyvalues/playlists_v2.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index bd2a58fe..a47cc07e 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -357,7 +357,6 @@ playlists mp_angel_city 1 mp_colony02 1 mp_glitch 1 - mp_lf_stacks 1 mp_relic02 1 mp_wargames 1 mp_rise 1 -- cgit v1.2.3 From e591885e0336f33facbcf2b15c9cd99f9b217e70 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Tue, 26 Jul 2022 17:16:32 +0200 Subject: Serverside RUI, but it doesn't stink ( hopefully ) (#435) * Serverside polls * reset table so mods can wait for response * large message * popup message * announcement * info * status * fix uniboi crash * no need to return id * among * typo * Formatting * bruh * takyon doesn't know how to finish a review * Formatting * Do you not know how to finish a review or what * You should look at gamemode_aitdm for some funky formatting :) * Formatting * Formatting * Finally a good suggestion * fix client misinterpreting assets --- Northstar.Client/mod/scripts/kb_act.lst | 11 +- Northstar.Custom/mod.json | 10 + .../mod/scripts/vscripts/sh_message_utils.gnut | 505 +++++++++++++++++++++ 3 files changed, 525 insertions(+), 1 deletion(-) create mode 100644 Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut diff --git a/Northstar.Client/mod/scripts/kb_act.lst b/Northstar.Client/mod/scripts/kb_act.lst index ace98222..238d7eef 100644 --- a/Northstar.Client/mod/scripts/kb_act.lst +++ b/Northstar.Client/mod/scripts/kb_act.lst @@ -1,7 +1,16 @@ "blank" "==========================" "blank" "NORTHSTAR" "blank" "==========================" -"toggleconsole" "Toggle Developer Console" +"toggleconsole" "Toggle Developer Console" +"vote 1" "Vote 1" +"vote 2" "Vote 2" +"vote 3" "Vote 3" +"vote 4" "Vote 4" +"vote 5" "Vote 5" +"vote 6" "Vote 6" +"vote 7" "Vote 7" +"vote 8" "Vote 8" +"vote 9" "Vote 9" "blank" "==========================" "blank" "#KEY_BINDINGS_HEADER_ACTIONS" "blank" "==========================" diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 46b5ab7f..28825a58 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -407,6 +407,16 @@ "ServerCallback": { "After": "CustomPilotCollision_InitPlaylistVars" } + }, + { + "Path": "sh_message_utils.gnut", + "RunOn": "( CLIENT || SERVER ) && MP", + "ClientCallback": { + "Before": "MessageUtils_ClientInit" + }, + "ServerCallback": { + "Before": "MessageUtils_ServerInit" + } } ], diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut new file mode 100644 index 00000000..6bbf77bd --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut @@ -0,0 +1,505 @@ +#if SERVER +global function MessageUtils_ServerInit + +global function NSCreatePollOnPlayer +global function NSGetPlayerResponse + +global function NSSendLargeMessageToPlayer +global function NSSendPopUpMessageToPlayer +global function NSSendAnnouncementMessageToPlayer +global function NSSendInfoMessageToPlayer + +global function NSCreateStatusMessageOnPlayer +global function NSEditStatusMessageOnPlayer +global function NSDeleteStatusMessageOnPlayer + +struct +{ + table playerPollResponses +} server +#endif // SERVER + + +#if CLIENT +global function MessageUtils_ClientInit + +vector ColorSelected = < 0.9, 0.8, 0.5 > +vector ColorBase = < 0.9, 0.5, 0.1 > + +struct tempMessage +{ + string title + string description + float duration + string image + int priority + int style + vector color +} + + +// Nested structs look funny, but are pretty helpful when reading code so I'm keeping them :) +struct +{ + struct + { + string header + array options + float duration + bool pollActive + array ruis + } poll + + string id + tempMessage temp + + array largeMessageQueue + array popupMessageQueue + array announcementQueue + array infoMessageQueue + + // table + table statusMessageList +} client +#endif // CLIENT + + +const int STATUS_MESSAGES_MAX = 4 + + +enum eMessageType +{ + POLL, + LARGE, + POPUP, + ANNOUNCEMENT, + INFO, + CREATE_STATUS, + EDIT_STATUS, + DELETE_STATUS +} + +enum eDataType +{ + POLL_HEADER, + POLL_OPTION, + POLL_DURATION, + POLL_SELECT, + TITLE, + DESC, + DURATION, + ASSET, + COLOR, + PRIORITY, + STYLE, + ID +} + +#if SERVER +void function MessageUtils_ServerInit() +{ + AddClientCommandCallback( "vote", ClientCommand_Vote ) + AddClientCommandCallback( "poll_respond", ClientCommand_PollRespond ) +} + +bool function ClientCommand_Vote( entity player, array args ) +{ + if( args.len() == 0 ) + return false + + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_SELECT + " " + args[0] ) + return true +} + +bool function ClientCommand_PollRespond( entity player, array args ) +{ + if( args.len() == 0 ) + return false + + server.playerPollResponses[player] <- args[0].tointeger() + return true +} + +void function NSCreateStatusMessageOnPlayer( entity player, string title, string description, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.CREATE_STATUS ) +} + +void function NSEditStatusMessageOnPlayer( entity player, string title, string description, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.EDIT_STATUS ) +} + +void function NSDeleteStatusMessageOnPlayer( entity player, string id ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ID + " " + id ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.DELETE_STATUS ) +} + +void function NSCreatePollOnPlayer( entity player, string header, array options, float duration ) +{ + foreach ( string option in options ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_OPTION + " " + option ) + + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_DURATION + " " + duration ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.POLL_HEADER + " " + header ) + + server.playerPollResponses[player] <- -1 // Reset poll response table + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.POLL ) +} + +int function NSGetPlayerResponse( entity player ) +{ + if( !( player in server.playerPollResponses ) ) + return -1 + + if( server.playerPollResponses[ player ] == -1 ) + return -1 + + return server.playerPollResponses[ player ] - 1 +} + +void function NSSendLargeMessageToPlayer( entity player, string title, string description, float duration, string image ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DURATION + " " + duration ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.ASSET + " " + image ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.LARGE ) +} + +void function NSSendPopUpMessageToPlayer( entity player, string text ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + text ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.POPUP ) +} + +void function NSSendAnnouncementMessageToPlayer( entity player, string title, string description, vector color, int priority, int style ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.TITLE + " " + title ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + description ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.COLOR + " " + color.x + " " + color.y + " " + color.z ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.PRIORITY + " " + priority ) + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.STYLE + " " + style ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.ANNOUNCEMENT ) +} + +void function NSSendInfoMessageToPlayer( entity player, string text ) +{ + ServerToClientStringCommand( player, "ServerHUDMessagePut " + eDataType.DESC + " " + text ) + + ServerToClientStringCommand( player, "ServerHUDMessageShow " + eMessageType.INFO ) +} + +#endif // SERVER + +#if CLIENT +void function MessageUtils_ClientInit() +{ + // ServerHUDMessageRequest + AddServerToClientStringCommandCallback( "ServerHUDMessageShow", ServerCallback_CreateServerHUDMessage ) + // ServerHUDMessageRequest + AddServerToClientStringCommandCallback( "ServerHUDMessagePut", ServerCallback_UpdateServerHUDMessage ) + + thread LargeMessageHandler_Threaded() + thread PopUpMessageHandler_Threaded() + thread AnnouncementMessageHandler_Threaded() + thread InfoMessageHandler_Threaded() +} + +string function CombineArgsIntoString( array args ) +{ + string result + + // Ignore the first argument + for( int i = 1; i < args.len(); i++ ) + result += args[i] + " " + + return result +} + +void function ServerCallback_UpdateServerHUDMessage ( array args ) +{ + switch ( args[0].tointeger() ) + { + case eDataType.POLL_HEADER: + client.poll.header = CombineArgsIntoString( args ) + break + case eDataType.POLL_OPTION: + client.poll.options.append( CombineArgsIntoString( args ) ) + break + case eDataType.POLL_DURATION: + client.poll.duration = args[1].tofloat() + break + case eDataType.POLL_SELECT: + thread SelectPollOption_Threaded( args[1].tointeger() ) + break + case eDataType.TITLE: + client.temp.title = CombineArgsIntoString( args ) + break + case eDataType.DESC: + client.temp.description = CombineArgsIntoString( args ) + break + case eDataType.DURATION: + client.temp.duration = args[1].tofloat() + break + case eDataType.ASSET: + client.temp.image = CombineArgsIntoString( args ) + break + case eDataType.COLOR: + client.temp.color = Vector( args[1].tofloat(), args[2].tofloat(), args[3].tofloat()) + break + case eDataType.PRIORITY: + client.temp.priority = args[1].tointeger() + break + case eDataType.STYLE: + client.temp.style = args[1].tointeger() + break + case eDataType.ID: + client.id = args[1] + break + } +} + +void function ServerCallback_CreateServerHUDMessage ( array args ) +{ + switch ( args[0].tointeger() ) + { + case eMessageType.POLL: + thread ShowPollMessage_Threaded() + break + case eMessageType.LARGE: + client.largeMessageQueue.append( client.temp ) + break + case eMessageType.POPUP: + client.popupMessageQueue.append( client.temp ) + break + case eMessageType.ANNOUNCEMENT: + client.announcementQueue.append( client.temp ) + break + case eMessageType.INFO: + client.infoMessageQueue.append( client.temp ) + break + case eMessageType.CREATE_STATUS: + CreateStatusMessage( client.id ) + break + case eMessageType.EDIT_STATUS: + EditStatusMessage( client.id ) + break + case eMessageType.DELETE_STATUS: + thread DeleteStatusMessage( client.id ) + break + } +} + +void function DeleteStatusMessage( string id ) +{ + if ( id in client.statusMessageList ) + { + var rui = client.statusMessageList[ id ] + RuiSetGameTime( rui, "startFadeOutTime", Time() ) + + // Remove it from table + delete client.statusMessageList[ id ] + + // Wait for animation + wait 0.6 + + RuiDestroyIfAlive( rui ) + + int i = 0 + foreach( _id, _rui in client.statusMessageList ) + { + RuiSetInt( _rui, "listPos", i ) + i++ + } + } +} + +void function EditStatusMessage( string id ) +{ + if( id in client.statusMessageList ) + { + var rui = client.statusMessageList[ id ] + RuiSetString( rui, "titleText", client.temp.title ) + RuiSetString( rui, "itemText", client.temp.description ) + } +} + +void function CreateStatusMessage( string id ) +{ + // Cap at 4 messages at a time + if( client.statusMessageList.len() == STATUS_MESSAGES_MAX ) + return + + var rui = CreatePermanentCockpitRui( $"ui/at_wave_intro.rpak" ) + RuiSetInt( rui, "listPos", client.statusMessageList.len() ) + RuiSetGameTime( rui, "startFadeInTime", Time() ) + RuiSetString( rui, "titleText", client.temp.title ) + RuiSetString( rui, "itemText", client.temp.description ) + RuiSetFloat2( rui, "offset", < 0, -250, 0 > ) + + client.statusMessageList[ id ] <- rui +} + +void function SelectPollOption_Threaded( int index ) +{ + if ( index >= client.poll.ruis.len() || index <= 0 ) + return + + RuiSetFloat3( client.poll.ruis[ index ], "msgColor", ColorSelected ) + EmitSoundOnEntity( GetLocalClientPlayer(), "menu_accept" ) + + float endTime = 1 + client.poll.duration + while( endTime > Time() && client.poll.pollActive ) + WaitFrame() + + GetLocalClientPlayer().ClientCommand( "poll_respond " + index ) + + foreach( var rui in client.poll.ruis ) + RuiDestroyIfAlive( rui ) + + client.poll.ruis.clear() + client.poll.pollActive = false +} + +void function ShowPollMessage_Threaded() +{ + if( client.poll.pollActive ) + return + + client.poll.pollActive = true + + for( int i = 0; i < client.poll.options.len() + 1; i++ ) + { + var rui = CreateCockpitRui( $"ui/cockpit_console_text_top_left.rpak" ) + // This makes it fade and me no likey >:( + RuiSetFloat2( rui, "msgPos", < 0, 0.4 + i * 0.025, 0 > ) + if( i == 0 ) + { + RuiSetFloat3( rui, "msgColor", ColorSelected ) + RuiSetString( rui, "msgText", client.poll.header ) + } + else + { + RuiSetFloat3( rui, "msgColor", ColorBase ) + RuiSetString( rui, "msgText", i + ". " + client.poll.options[i - 1] ) + } + + RuiSetFloat( rui, "msgFontSize", 30.0 ) + RuiSetFloat( rui, "msgAlpha", 0.9 ) + RuiSetFloat( rui, "thicken", 0.0 ) + + client.poll.ruis.append( rui ) + } + + client.poll.options.clear() + + float endTime = Time() + client.poll.duration + while( endTime > Time() && client.poll.pollActive ) + WaitFrame() + + + foreach( var rui in client.poll.ruis ) + RuiDestroyIfAlive( rui ) + + client.poll.ruis.clear() + client.poll.pollActive = false +} + +void function InfoMessageHandler_Threaded() +{ + while( true ) + { + while( client.infoMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreatePermanentCockpitRui( $"ui/death_hint_mp.rpak" ) + RuiSetString( rui, "hintText", client.infoMessageQueue[0].description ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat3( rui, "bgColor", < 0, 0, 0 > ) + RuiSetFloat( rui, "bgAlpha", 0.5 ) + + wait 7 + + client.infoMessageQueue.remove( 0 ) + RuiDestroyIfAlive( rui ) + } +} + +void function AnnouncementMessageHandler_Threaded() +{ + while( true ) + { + while( client.announcementQueue.len() == 0 ) + WaitFrame() + + AnnouncementData announcement = Announcement_Create( client.announcementQueue[0].title ) + Announcement_SetSubText( announcement, client.announcementQueue[0].description ) + Announcement_SetTitleColor( announcement, client.announcementQueue[0].color ) + Announcement_SetPurge( announcement, true ) + Announcement_SetPriority( announcement, client.announcementQueue[0].priority ) + Announcement_SetSoundAlias( announcement, SFX_HUD_ANNOUNCE_QUICK ) + Announcement_SetStyle( announcement, client.announcementQueue[0].style ) + AnnouncementFromClass( GetLocalViewPlayer(), announcement ) + + wait 5 + + client.announcementQueue.remove(0) + } +} + +void function LargeMessageHandler_Threaded() +{ + while( true ) + { + while( client.largeMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreatePermanentCockpitRui( $"ui/fd_tutorial_tip.rpak" ) + RuiSetImage( rui, "backgroundImage", StringToAsset( strip( client.largeMessageQueue[0].image ) ) ) + RuiSetString( rui, "titleText", client.largeMessageQueue[0].title ) + RuiSetString( rui, "descriptionText", client.largeMessageQueue[0].description ) + RuiSetGameTime( rui, "updateTime", Time() ) + RuiSetFloat( rui, "duration", client.largeMessageQueue[0].duration ) + + wait client.largeMessageQueue[0].duration + + client.largeMessageQueue.remove(0) + RuiDestroyIfAlive( rui ) + } +} + +void function PopUpMessageHandler_Threaded() +{ + while( true ) + { + while( client.popupMessageQueue.len() == 0 ) + WaitFrame() + + var rui = CreateCockpitRui( $"ui/killdeath_info.rpak" ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat( rui, "duration", 20 ) // It has a weird end animation + RuiSetString( rui, "messageText", client.popupMessageQueue[0].description ) + RuiSetBool( rui, "isBigText", true ) + + wait 2.4 + + client.popupMessageQueue.remove(0) + RuiDestroyIfAlive( rui ) + } +} + +#endif // CLIENT \ No newline at end of file -- cgit v1.2.3 From d9fed6e461c6e19ee488568951bee7064a62baa0 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 27 Jul 2022 11:02:41 +0200 Subject: Fix RespawnAsTitan not triggering FirstToFall (#427) Co-authored-by: x3Karma --- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) 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 1c53167f..05537435 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -447,7 +447,20 @@ void function RespawnAsTitan( entity player, bool manualPosition = false ) AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) // hide hud // do titanfall scoreevent - AddPlayerScore( player, "Titanfall", player ) + if ( !level.firstTitanfall ) + { + AddPlayerScore( player, "FirstTitanfall", player ) + + #if HAS_STATS + UpdatePlayerStat( player, "misc_stats", "titanFallsFirst" ) + #endif + + level.firstTitanfall = true + } + else + { + AddPlayerScore( player, "Titanfall", player ) + } entity camera = CreateTitanDropCamera( spawnpoint.GetAngles(), < 90, titan.GetAngles().y, 0 > ) camera.SetParent( titan ) -- cgit v1.2.3 From f66c631e7746fefe12e690bcbc8cd15b8d26130b Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Wed, 3 Aug 2022 05:24:18 +0800 Subject: Added Killer Outline (#470) * Added Killer Outline Added killer outline: highlight the killer after being killed * Changed to _base_gametype_mp.gnut Not using a single script right now * Removed IsNPC() Check Moved inside the if ( IsValid ( attacker ) ) check and removed the attacker.IsNPC() --- Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 3 +++ 1 file changed, 3 insertions(+) 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 05537435..b453286c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -298,6 +298,9 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga attackerInfo.attacker.AddToPlayerGameStat( PGS_ASSISTS, 1 ) } } + + if( attacker.IsPlayer() ) + Highlight_SetDeathRecapHighlight( attacker, "killer_outline" ) } player.p.rematchOrigin = player.p.deathOrigin -- cgit v1.2.3 From a9bd92ea64f3a99539d6ea734ec0fb05597b83a6 Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Sat, 6 Aug 2022 17:55:03 -0400 Subject: allow custom maps to set fasbtall panels (#475) --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut index 019bcc7d..5ce11eb3 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut @@ -1,5 +1,6 @@ untyped global function GamemodeFastball_Init +global function FastballAddPanelSpawnsForLevel struct { // first panel is a, second is b, third is c -- cgit v1.2.3 From aad66d78924569a5974297355635ee8606a039af Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sun, 7 Aug 2022 06:03:35 +0800 Subject: Fixed Turret Visual (#467) Run _ai_turret_sentry.gnut on ServerSide so that turret will spawn with it's lase --- Northstar.CustomServers/mod.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 14e1ff63..79663feb 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -149,6 +149,13 @@ "ServerCallback": { "Before": "RespawnProtection_Init" } + }, + { + "Path": "/ai/_ai_turret_sentry.gnut", + "RunOn": "SERVER && MP", + "ServerCallback": { + "After": "AiTurretSentry_Init" + } } ] } -- cgit v1.2.3 From eeb653546c25282a4c40799d6e4a5da466fc919c Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Sun, 7 Aug 2022 12:52:44 -0400 Subject: fix DelayedGamemodeAnnouncement (#471) --- Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut index 341493ba..8d859ba6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/levels/mp_wargames.nut @@ -339,7 +339,8 @@ void function PlayerWatchesWargamesIntro( entity player ) void function DelayedGamemodeAnnouncement( entity player ) { wait 1.0 - TryGameModeAnnouncement( player ) + if ( IsValid( player ) && IsAlive( player ) ) + TryGameModeAnnouncement( player ) } void function PlaySound_SimPod_DoorShut( entity playerFirstPersonProxy ) // stolen from sp_training -- cgit v1.2.3 From 853429f771adac08ebfc07fd2665d865fce46e86 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Aug 2022 18:54:35 +0200 Subject: Fix race condition crash when boarding dropship as it explodes (#438) Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index bce8b4c7..4a21e697 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -356,7 +356,6 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa foreach ( entity otherPlayer in GetPlayerArray() ) Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() ) } - } void function AddPlayerToEvacDropship( entity dropship, entity player ) @@ -376,7 +375,10 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) // no slots available if ( !PlayerInDropship( player, dropship ) ) return - + + // need to cancel if the dropship dies + dropship.EndSignal( "OnDeath", "OnDestroy" ) + player.SetInvulnerable() player.UnforceCrouch() player.ForceStand() @@ -391,7 +393,7 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) EmitSoundOnEntityOnlyToPlayer( player, player, SHIFTER_START_SOUND_3P ) // should play SHIFTER_START_SOUND_1P when they actually arrive in the ship i think, unsure how this is supposed to be done PlayPhaseShiftDisappearFX( player ) - waitthread FirstPersonSequence( fp, player, dropship ) + FirstPersonSequence( fp, player, dropship ) FirstPersonSequenceStruct idleFp idleFp.firstPersonAnimIdle = EVAC_IDLE_ANIMS_1P[ slot ] -- cgit v1.2.3 From 4a316c5c0055ffcf407dc2411b76438723187290 Mon Sep 17 00:00:00 2001 From: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Date: Mon, 8 Aug 2022 01:22:47 +0800 Subject: Support to input other languages in the search box (#477) Support to input other languages in the search box --- Northstar.Client/mod/resource/ui/menus/server_browser.menu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index 89fb951d..d25d1219 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -2197,7 +2197,7 @@ resource/ui/menus/mods_browse.menu font Default_21 allowRightClickMenu 0 allowSpecialCharacters 0 - unicode 0 + unicode 1 pin_to_sibling BtnSearchLabel pin_corner_to_sibling TOP_LEFT -- cgit v1.2.3 From 7b9ba2486eff78b17ff52a92d27dc62a3a17553b Mon Sep 17 00:00:00 2001 From: x3Karma Date: Mon, 8 Aug 2022 04:59:30 +0800 Subject: Update "The Hidden" to make use of Serverside RUI (#455) * Small update to Hidden utilizing Serverside RUI * Added EndSignals to end threads if player disconnects * Fix formatting * Fix formatting --- .../vscripts/gamemodes/_gamemode_hidden.nut | 79 ++++++++++++++++------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut index 4d52835b..6729ff97 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_hidden.nut @@ -1,5 +1,9 @@ global function GamemodeHidden_Init +struct { + bool isVisible = false + array hiddens +} file void function GamemodeHidden_Init() { @@ -20,8 +24,7 @@ void function GamemodeHidden_Init() AddCallback_GameStateEnter( eGameState.Postmatch, RemoveHidden ) SetTimeoutWinnerDecisionFunc( TimeoutCheckSurvivors ) - thread PredatorMain() - + RegisterSignal( "VisibleNotification" ) } void function HiddenInitPlayer( entity player ) @@ -78,7 +81,10 @@ void function MakePlayerHidden(entity player) SetTeam( player, TEAM_IMC ) player.SetPlayerGameStat( PGS_ASSAULT_SCORE, 0 ) // reset kills + file.hiddens.append( player ) RespawnHidden( player ) + thread PredatorMain( player ) + thread VisibleNotification( player ) Remote_CallFunction_NonReplay( player, "ServerCallback_YouAreHidden" ) } @@ -153,35 +159,66 @@ void function RemoveHidden() } } -void function PredatorMain() +void function PredatorMain( entity player ) { + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + float playerVel + while (true) { WaitFrame() if(!IsLobby()) { - foreach (entity player in GetPlayerArray()) + if ( !IsValid( player ) || !IsAlive( player ) || player.GetTeam() != TEAM_IMC ) + continue + + vector playerVelV = player.GetVelocity() + playerVel = sqrt( playerVelV.x * playerVelV.x + playerVelV.y * playerVelV.y + playerVelV.z * playerVelV.z ) + + if ( playerVel/300 < 1.3 ) { - if (player == null || !IsValid(player) || !IsAlive(player) || player.GetTeam() != TEAM_IMC) - continue - vector playerVelV = player.GetVelocity() - float playerVel - playerVel = sqrt(playerVelV.x * playerVelV.x + playerVelV.y * playerVelV.y + playerVelV.z * playerVelV.z) - float playerVelNormal = playerVel * 0.068544 - if (playerVel/300 < 1.3) + player.SetCloakFlicker( 0, 0 ) + player.kv.VisibilityFlags = 0 + wait 0.5 + if ( file.isVisible ) { - player.SetCloakFlicker(0, 0) - player.kv.VisibilityFlags = 0 - } - else - { - player.SetCloakFlicker(0.2 , 1 ) - player.kv.VisibilityFlags = 0 - float waittime = RandomFloat(0.5) - wait waittime - player.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + file.isVisible = false + player.Signal( "VisibleNotification" ) } } + else + { + player.SetCloakFlicker( 0.2 , 1 ) + player.kv.VisibilityFlags = 0 + float waittime = RandomFloat( 0.5 ) + wait waittime + player.kv.VisibilityFlags = ENTITY_VISIBLE_TO_EVERYONE + file.isVisible = true + } + } + } +} + +void function VisibleNotification( entity player ) +{ + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + while (IsAlive(player)) + { + WaitFrame() + if (!file.isVisible) + { + NSDeleteStatusMessageOnPlayer( player, "visibleTitle" ) + NSDeleteStatusMessageOnPlayer( player, "visibleDesc" ) + continue + } + else + { + NSCreateStatusMessageOnPlayer( player, "You are visible!", "", "visibleTitle" ) + NSCreateStatusMessageOnPlayer( player, "Note:", "Slow down to remain invisible!", "visibleDesc" ) + player.WaitSignal( "VisibleNotification" ) + continue } } } -- cgit v1.2.3 From fcdbedd671e8c824f626b39a75538df9aff762c0 Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Thu, 11 Aug 2022 08:15:18 -0400 Subject: adding win achievement (#481) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index bfcd23e0..4108d0d9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -278,6 +278,9 @@ void function GameStateEnter_WinnerDetermined_Threaded() Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceRoundWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME, GameRules_GetTeamScore2( TEAM_MILITIA ), GameRules_GetTeamScore2( TEAM_IMC ) ) else Remote_CallFunction_NonReplay( player, "ServerCallback_AnnounceWinner", winningTeam, announcementSubstr, ROUND_WINNING_KILL_REPLAY_SCREEN_FADE_TIME ) + + if ( player.GetTeam() == winningTeam ) + UnlockAchievement( player, achievements.MP_WIN ) } WaitFrame() // wait a frame so other scripts can setup killreplay stuff -- cgit v1.2.3 From 1bb3dafd123a4c4df987ac5077f1cec202858be9 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Thu, 11 Aug 2022 21:09:02 +0800 Subject: Swap EVAC_WAIT_TIME to waitTime in _evac.gnut (#482) --- Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index 4a21e697..b1d8f6bd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -268,8 +268,8 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa thread PlayAnim( dropship, "cd_dropship_rescue_side_idle", evacNode ) // eta until leave - SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon ) - SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + EVAC_WAIT_TIME, file.evacIcon ) + SetTeamActiveObjective( evacTeam, "EG_DropshipExtract2", Time() + waitTime, file.evacIcon ) + SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract2", Time() + waitTime, file.evacIcon ) // setup evac trigger entity trigger = CreateEntity( "trigger_cylinder" ) -- cgit v1.2.3 From 2c2ab93a2ad9c8626e3e5b98dbed5630bf6b95df Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Fri, 12 Aug 2022 09:28:09 -0400 Subject: Add functions to allow for custom damage source IDs (#311) * Add compatability for modded weapon damage * Formatting adjustments * Stinky space indent changed to tabs * Change to allow serverside-only source creation * Fix formatting As per suggestions in code review. --- .../mod/scripts/vscripts/sh_damage_types.nut | 776 +++++++++++++++++++++ 1 file changed, 776 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut new file mode 100644 index 00000000..c66fc857 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut @@ -0,0 +1,776 @@ +global function DamageTypes_Init +global function RegisterWeaponDamageSourceName +global function GetObitFromDamageSourceID +global function DamageSourceIDToString +global function DamageSourceIDHasString + +#if SERVER +global function RegisterWeaponDamageSource +global function RegisterWeaponDamageSources +#endif + +struct +{ + table damageSourceIDToName + table damageSourceIDToString + + // For new, modded damageSourceIDs. + // Holds triplets of [id, enum_name, display name]. Stored with no separation for ease of string conversion. + array customDamageSourceIDList +} file + +// For sending custom damage source IDs to clients +const int SOURCE_ID_MAX_MESSAGE_LENGTH = 200 // JFS - Used to break messages sent to client into chunks in case it would hit the limitation on command argument length +const string MESSAGE_SPACE_PADDING = "\xA6" // The "broken pipe" character. Trash character used to replace spaces in display name to allow sending via commands (args are separated by spaces). + +global enum eDamageSourceId +{ + invalid = -1 // used in code + + //--------------------------- + // defined in damageDef.txt. This will go away ( you can use damagedef_nuclear_core instead of eDamageSourceId.[enum id] and get rid of it from here ) + // once this list has only damagedef_*, then we can remove eDamageSourceId + code_reserved // may be merged with invalid -1 above + damagedef_unknown // must start at 1 and order must match what's in damageDefs.txt + damagedef_unknownBugIt + damagedef_suicide + damagedef_despawn + damagedef_titan_step + damagedef_crush + damagedef_nuclear_core + damagedef_titan_fall + damagedef_titan_hotdrop + damagedef_reaper_fall + damagedef_trip_wire + damagedef_reaper_groundslam + damagedef_reaper_nuke + damagedef_frag_drone_explode + damagedef_frag_drone_explode_FD + damagedef_frag_drone_throwable_PLAYER + damagedef_frag_drone_throwable_NPC + damagedef_stalker_powersupply_explosion_small + damagedef_stalker_powersupply_explosion_large + damagedef_stalker_powersupply_explosion_large_at + damagedef_shield_captain_arc_shield + damagedef_fd_explosive_barrel + damagedef_fd_tether_trap + + //--------------------------- + + // Titan Weapons + mp_titanweapon_40mm + mp_titanweapon_arc_cannon + mp_titanweapon_arc_wave + mp_titanweapon_arc_ball + mp_titanweapon_arc_pylon + mp_titanweapon_emp_volley + mp_titanweapon_rocket_launcher + mp_titanweapon_rocketeer_missile + mp_titanweapon_rocketeer_rocketstream + mp_titanweapon_shoulder_rockets + mp_titanweapon_shoulder_grenade + mp_titanweapon_orbital_strike + mp_titanweapon_tether_shot + mp_titanweapon_homing_rockets + mp_titanweapon_dumbfire_rockets + mp_titanweapon_multi_cluster + mp_titanweapon_meteor + mp_titanweapon_meteor_thermite + mp_titanweapon_meteor_thermite_charged + mp_titanweapon_salvo_rockets + mp_titanweapon_tracker_rockets + mp_titanweapon_sniper + mp_titanweapon_triple_threat + mp_titanweapon_vortex_shield + mp_titanweapon_vortex_shield_ion + mp_titanweapon_xo16 + mp_titanweapon_xo16_shorty + mp_titanweapon_xopistol + mp_titanweapon_at_mine + mp_titanweapon_leadwall + mp_titanweapon_jackhammer + mp_titanweapon_electric_fist + mp_titanweapon_cabertoss + mp_titanweapon_flame_wall + mp_titanweapon_flame_ring + mp_titanweapon_smash + mp_titanweapon_particle_accelerator + mp_titanweapon_sticky_40mm + mp_titanweapon_predator_cannon + mp_titanweapon_predator_cannon_siege + mp_titanability_laser_trip + mp_titanweapon_laser_lite + mp_titanweapon_stun_laser + mp_titanability_smoke + mp_titanability_arc_field + mp_titanweapon_arc_minefield + mp_titanability_hover + mp_titanability_cloak + mp_titanability_tether_trap + + mp_titancore_amp_core + mp_titancore_emp + mp_titancore_flame_wave + mp_titancore_flame_wave_secondary + mp_titancore_laser_cannon + mp_titancore_nuke_core + mp_titancore_nuke_missile + mp_titanweapon_berserker + mp_titancore_shift_core + mp_titanweapon_flightcore_rockets + mp_titancore_salvo_core + mp_titancore_siege_mode + + //SP weapons + mp_weapon_grenade_electric_smoke + proto_titanweapon_deathblossom + + // Pilot Weapons + mp_weapon_hemlok + mp_weapon_lmg + mp_weapon_rspn101 + mp_weapon_vinson + mp_weapon_lstar + mp_weapon_g2 + mp_weapon_smart_pistol + mp_weapon_r97 + mp_weapon_car + mp_weapon_hemlok_smg + mp_weapon_dmr + mp_weapon_wingman + mp_weapon_wingman_n + mp_weapon_semipistol + mp_weapon_autopistol + mp_weapon_mgl + mp_weapon_sniper + mp_weapon_shotgun + mp_weapon_mastiff + mp_weapon_frag_drone + mp_weapon_frag_grenade + mp_weapon_grenade_emp + mp_weapon_arc_blast + mp_weapon_thermite_grenade + mp_weapon_grenade_sonar + mp_weapon_grenade_gravity + mp_weapon_satchel + mp_weapon_nuke_satchel + mp_weapon_proximity_mine + mp_weapon_smr + mp_weapon_rocket_launcher + mp_weapon_arc_launcher + mp_weapon_defender + mp_weapon_dash_melee + mp_weapon_tether + mp_weapon_tripwire + mp_weapon_flak_rifle + mp_extreme_environment + mp_weapon_shotgun_pistol + mp_weapon_pulse_lmg + mp_weapon_sword + mp_weapon_softball + mp_weapon_shotgun_doublebarrel + mp_weapon_doubletake + mp_weapon_arc_rifle + mp_weapon_gibber_pistol + mp_weapon_alternator_smg + mp_weapon_esaw + mp_weapon_epg + mp_weapon_arena1 + mp_weapon_arena2 + mp_weapon_arena3 + mp_weapon_rspn101_og + + // + melee_pilot_emptyhanded + melee_pilot_arena + melee_pilot_sword + melee_titan_punch + melee_titan_punch_ion + melee_titan_punch_tone + melee_titan_punch_legion + melee_titan_punch_scorch + melee_titan_punch_northstar + melee_titan_punch_fighter + melee_titan_punch_vanguard + melee_titan_sword + melee_titan_sword_aoe + + mp_weapon_engineer_turret + + // Turret Weapons + mp_weapon_yh803 + mp_weapon_yh803_bullet + mp_weapon_yh803_bullet_overcharged + mp_weapon_mega_turret + mp_weapon_mega_turret_aa + mp_turretweapon_rockets + mp_turretweapon_blaster + mp_turretweapon_plasma + mp_turretweapon_sentry + + // AI only Weapons + mp_weapon_super_spectre + mp_weapon_dronebeam + mp_weapon_dronerocket + mp_weapon_droneplasma + mp_weapon_turretplasma + mp_weapon_turretrockets + mp_weapon_turretplasma_mega + mp_weapon_gunship_launcher + mp_weapon_gunship_turret + mp_weapon_gunship_missile + + // Misc + rodeo + rodeo_forced_titan_eject //For awarding points when you force a pilot to eject via rodeo + rodeo_execution + human_melee + auto_titan_melee + berserker_melee + mind_crime + charge_ball + grunt_melee + spectre_melee + prowler_melee + super_spectre_melee + titan_execution + human_execution + eviscerate + wall_smash + ai_turret + team_switch + rocket + titan_explosion + flash_surge + molotov + sticky_time_bomb + vortex_grenade + droppod_impact + ai_turret_explosion + rodeo_trap + round_end + bubble_shield + evac_dropship_explosion + sticky_explosive + titan_grapple + + // streaks + satellite_strike + + // Environmental + fall + splat + crushed + burn + lasergrid + outOfBounds + indoor_inferno + submerged + switchback_trap + floor_is_lava + suicideSpectreAoE + titanEmpField + stuck + deadly_fog + exploding_barrel + electric_conduit + turbine + harvester_beam + toxic_sludge + + mp_weapon_spectre_spawner + + // development + weapon_cubemap + + // Prototype + mp_weapon_zipline + mp_ability_ground_slam + sp_weapon_arc_tool + sp_weapon_proto_battery_charger_offhand + at_turret_override + rodeo_battery_removal + phase_shift + gamemode_bomb_detonation + nuclear_turret + proto_viewmodel_test + mp_titanweapon_heat_shield + mp_titanability_slow_trap + mp_titanability_gun_shield + mp_titanability_power_shot + mp_titanability_ammo_swap + mp_titanability_sonar_pulse + mp_titanability_rearm + mp_titancore_upgrade + mp_titanweapon_xo16_vanguard + mp_weapon_arc_trap + core_overload + + bombardment + bleedout + //damageSourceId=eDamageSourceId.xxxxx + //fireteam + //marvin + //rocketstrike + //orbitallaser + //explosion +} + +//When adding new mods, they need to be added below and to persistent_player_data_version_N.pdef in r1/cfg/server. +//Then when updating that file, save a new one and increment N. + +global enum eModSourceId +{ + accelerator + afterburners + arc_triple_threat + aog + burn_mod_autopistol + burn_mod_car + burn_mod_defender + burn_mod_dmr + burn_mod_emp_grenade + burn_mod_frag_grenade + burn_mod_grenade_electric_smoke + burn_mod_grenade_gravity + burn_mod_thermite_grenade + burn_mod_g2 + burn_mod_hemlok + burn_mod_lmg + burn_mod_mgl + burn_mod_r97 + burn_mod_rspn101 + burn_mod_satchel + burn_mod_semipistol + burn_mod_smart_pistol + burn_mod_smr + burn_mod_sniper + burn_mod_rocket_launcher + burn_mod_titan_40mm + burn_mod_titan_arc_cannon + burn_mod_titan_rocket_launcher + burn_mod_titan_sniper + burn_mod_titan_triple_threat + burn_mod_titan_xo16 + burn_mod_titan_dumbfire_rockets + burn_mod_titan_homing_rockets + burn_mod_titan_salvo_rockets + burn_mod_titan_shoulder_rockets + burn_mod_titan_vortex_shield + burn_mod_titan_smoke + burn_mod_titan_particle_wall + burst + capacitor + enhanced_targeting + extended_ammo + fast_lock + fast_reload + guided_missile + hcog + holosight + instant_shot + iron_sights + overcharge + quick_shot + rapid_fire_missiles + scope_4x + scope_6x + scope_8x + scope_10x + scope_12x + burn_mod_shotgun + silencer + slammer + spread_increase_ttt + stabilizer + titanhammer + burn_mod_wingman + burn_mod_lstar + burn_mod_mastiff + burn_mod_vinson + ricochet + ar_trajectory + redline_sight + threat_scope + smart_lock + pro_screen + rocket_arena +} + +//Attachments intentionally left off. This prevents them from displaying in kill cards. +// modNameStrings should be defined when the mods are created, not in a separate table -Mackey +global const modNameStrings = { + [ eModSourceId.accelerator ] = "#MOD_ACCELERATOR_NAME", + [ eModSourceId.afterburners ] = "#MOD_AFTERBURNERS_NAME", + [ eModSourceId.arc_triple_threat ] = "#MOD_ARC_TRIPLE_THREAT_NAME", + [ eModSourceId.burn_mod_autopistol ] = "#BC_AUTOPISTOL_M2", + [ eModSourceId.burn_mod_car ] = "#BC_CAR_M2", + [ eModSourceId.burn_mod_defender ] = "#BC_DEFENDER_M2", + [ eModSourceId.burn_mod_dmr ] = "#BC_DMR_M2", + [ eModSourceId.burn_mod_emp_grenade ] = "#BC_EMP_GRENADE_M2", + [ eModSourceId.burn_mod_frag_grenade ] = "#BC_FRAG_GRENADE_M2", + [ eModSourceId.burn_mod_grenade_electric_smoke ] = "#BC_GRENADE_ELECTRIC_SMOKE_M2", + [ eModSourceId.burn_mod_grenade_gravity ] = "#BC_GRENADE_ELECTRIC_SMOKE_M2", + [ eModSourceId.burn_mod_thermite_grenade ] = "#BC_GRENADE_ELECTRIC_SMOKE_M2", + [ eModSourceId.burn_mod_g2 ] = "#BC_G2_M2", + [ eModSourceId.burn_mod_hemlok ] = "#BC_HEMLOK_M2", + [ eModSourceId.burn_mod_lmg ] = "#BC_LMG_M2", + [ eModSourceId.burn_mod_mgl ] = "#BC_MGL_M2", + [ eModSourceId.burn_mod_r97 ] = "#BC_R97_M2", + [ eModSourceId.burn_mod_rspn101 ] = "#BC_RSPN101_M2", + [ eModSourceId.burn_mod_satchel ] = "#BC_SATCHEL_M2", + [ eModSourceId.burn_mod_semipistol ] = "#BC_SEMIPISTOL_M2", + [ eModSourceId.burn_mod_smr ] = "#BC_SMR_M2", + [ eModSourceId.burn_mod_smart_pistol ] = "#BC_SMART_PISTOL_M2", + [ eModSourceId.burn_mod_sniper ] = "#BC_SNIPER_M2", + [ eModSourceId.burn_mod_rocket_launcher ] = "#BC_ROCKET_LAUNCHER_M2", + [ eModSourceId.burn_mod_titan_40mm ] = "#BC_TITAN_40MM_M2", + [ eModSourceId.burn_mod_titan_arc_cannon ] = "#BC_TITAN_ARC_CANNON_M2", + [ eModSourceId.burn_mod_titan_rocket_launcher ] = "#BC_TITAN_ROCKET_LAUNCHER_M2", + [ eModSourceId.burn_mod_titan_sniper ] = "#BC_TITAN_SNIPER_M2", + [ eModSourceId.burn_mod_titan_triple_threat ] = "#BC_TITAN_TRIPLE_THREAT_M2", + [ eModSourceId.burn_mod_titan_xo16 ] = "#BC_TITAN_XO16_M2", + [ eModSourceId.burn_mod_titan_dumbfire_rockets ] = "#BC_TITAN_DUMBFIRE_MISSILE_M2", + [ eModSourceId.burn_mod_titan_homing_rockets ] = "#BC_TITAN_HOMING_ROCKETS_M2", + [ eModSourceId.burn_mod_titan_salvo_rockets ] = "#BC_TITAN_SALVO_ROCKETS_M2", + [ eModSourceId.burn_mod_titan_shoulder_rockets ] = "#BC_TITAN_SHOULDER_ROCKETS_M2", + [ eModSourceId.burn_mod_titan_vortex_shield ] = "#BC_TITAN_VORTEX_SHIELD_M2", + [ eModSourceId.burn_mod_titan_smoke ] = "#BC_TITAN_ELECTRIC_SMOKE_M2", + [ eModSourceId.burn_mod_titan_particle_wall ] = "#BC_TITAN_SHIELD_WALL_M2", + [ eModSourceId.burst ] = "#MOD_BURST_NAME", + [ eModSourceId.capacitor ] = "#MOD_CAPACITOR_NAME", + [ eModSourceId.enhanced_targeting ] = "#MOD_ENHANCED_TARGETING_NAME", + [ eModSourceId.extended_ammo ] = "#MOD_EXTENDED_MAG_NAME", + [ eModSourceId.fast_reload ] = "#MOD_FAST_RELOAD_NAME", + [ eModSourceId.instant_shot ] = "#MOD_INSTANT_SHOT_NAME", + [ eModSourceId.overcharge ] = "#MOD_OVERCHARGE_NAME", + [ eModSourceId.quick_shot ] = "#MOD_QUICK_SHOT_NAME", + [ eModSourceId.rapid_fire_missiles ] = "#MOD_RAPID_FIRE_MISSILES_NAME", + [ eModSourceId.burn_mod_shotgun ] = "#BC_SHOTGUN_M2", + [ eModSourceId.silencer ] = "#MOD_SILENCER_NAME", + [ eModSourceId.slammer ] = "#MOD_SLAMMER_NAME", + [ eModSourceId.spread_increase_ttt ] = "#MOD_SPREAD_INCREASE_TTT_NAME", + [ eModSourceId.stabilizer ] = "#MOD_STABILIZER_NAME", + [ eModSourceId.titanhammer ] = "#MOD_TITANHAMMER_NAME", + [ eModSourceId.burn_mod_wingman ] = "#BC_WINGMAN_M2", + [ eModSourceId.burn_mod_lstar ] = "#BC_LSTAR_M2", + [ eModSourceId.burn_mod_mastiff ] = "#BC_MASTIFF_M2", + [ eModSourceId.burn_mod_vinson ] = "#BC_VINSON_M2", + [ eModSourceId.ricochet ] = "Ricochet", + [ eModSourceId.ar_trajectory ] = "AR Trajectory", + [ eModSourceId.smart_lock ] = "Smart Lock", + [ eModSourceId.pro_screen ] = "Pro Screen", + [ eModSourceId.rocket_arena ] = "Rocket Arena", +} + +void function DamageTypes_Init() +{ + #if SERVER + AddCallback_OnClientConnected( SendNewDamageSourceIDsConnected ) + #else + AddServerToClientStringCommandCallback( "register_damage_source_ids", ReceiveNewDamageSourceIDs ) + #endif + + foreach ( name, number in eDamageSourceId ) + { + file.damageSourceIDToString[ number ] <- name + } + + PrecacheWeapon( "mp_weapon_rspn101" ) // used by npc_soldier >< + +#if DEV + + int numDamageDefs = DamageDef_GetCount() + table damageSourceIdEnum = expect table( getconsttable().eDamageSourceId ) + foreach ( name, id in damageSourceIdEnum ) + { + expect int( id ) + if ( id <= eDamageSourceId.code_reserved || id >= numDamageDefs ) + continue + + string damageDefName = DamageDef_GetName( id ) + Assert( damageDefName == name, "damage def (" + id + ") name: '" + damageDefName + "' doesn't match damage source id '" + name + "'" ) + } +#endif + + file.damageSourceIDToName = + { + //sp + [ eDamageSourceId.mp_weapon_grenade_electric_smoke ] = "#DEATH_ELECTRIC_SMOKE_SCREEN", + [ eDamageSourceId.proto_titanweapon_deathblossom ] = "#WPN_TITAN_ROCKET_LAUNCHER", + + //mp + [ eDamageSourceId.mp_extreme_environment ] = "#DAMAGE_EXTREME_ENVIRONMENT", + + [ eDamageSourceId.mp_weapon_engineer_turret ] = "#WPN_ENGINEER_TURRET", + + [ eDamageSourceId.mp_weapon_yh803 ] = "#WPN_LIGHT_TURRET", + [ eDamageSourceId.mp_weapon_yh803_bullet ] = "#WPN_LIGHT_TURRET", + [ eDamageSourceId.mp_weapon_yh803_bullet_overcharged ] = "#WPN_LIGHT_TURRET", + [ eDamageSourceId.mp_weapon_mega_turret ] = "#WPN_MEGA_TURRET", + [ eDamageSourceId.mp_weapon_mega_turret_aa ] = "#WPN_MEGA_TURRET", + [ eDamageSourceId.mp_turretweapon_rockets ] = "#WPN_TURRET_ROCKETS", + [ eDamageSourceId.mp_weapon_super_spectre ] = "#WPN_SUPERSPECTRE_ROCKETS", + [ eDamageSourceId.mp_weapon_dronebeam ] = "#WPN_DRONERBEAM", + [ eDamageSourceId.mp_weapon_dronerocket ] = "#WPN_DRONEROCKET", + [ eDamageSourceId.mp_weapon_droneplasma ] = "#WPN_DRONEPLASMA", + [ eDamageSourceId.mp_weapon_turretplasma ] = "#WPN_TURRETPLASMA", + [ eDamageSourceId.mp_weapon_turretrockets ] = "#WPN_TURRETROCKETS", + [ eDamageSourceId.mp_weapon_turretplasma_mega ] = "#WPN_TURRETPLASMA_MEGA", + [ eDamageSourceId.mp_weapon_gunship_launcher ] = "#WPN_GUNSHIP_LAUNCHER", + [ eDamageSourceId.mp_weapon_gunship_turret ] = "#WPN_GUNSHIP_TURRET", + [ eDamageSourceId.mp_weapon_gunship_turret ] = "#WPN_GUNSHIP_MISSILE", + + [ eDamageSourceId.mp_titanability_smoke ] = "#DEATH_ELECTRIC_SMOKE_SCREEN", + [ eDamageSourceId.mp_titanability_laser_trip ] = "#DEATH_LASER_TRIPWIRE", + [ eDamageSourceId.mp_titanability_slow_trap ] = "#DEATH_SLOW_TRAP", + [ eDamageSourceId.mp_titanability_tether_trap ] = "#DEATH_TETHER_TRAP", + + [ eDamageSourceId.rodeo ] = "#DEATH_TITAN_RODEO", + [ eDamageSourceId.rodeo_forced_titan_eject ] = "#DEATH_TITAN_RODEO", + [ eDamageSourceId.rodeo_execution ] = "#DEATH_RODEO_EXECUTION", + [ eDamageSourceId.nuclear_turret ] = "#DEATH_NUCLEAR_TURRET", + [ eDamageSourceId.mp_titanweapon_flightcore_rockets ] = "#WPN_TITAN_FLIGHT_ROCKET", + [ eDamageSourceId.mp_titancore_amp_core ] = "#TITANCORE_AMP_CORE", + [ eDamageSourceId.mp_titancore_emp ] = "#TITANCORE_EMP", + [ eDamageSourceId.mp_titancore_siege_mode ] = "#TITANCORE_SIEGE_MODE", + [ eDamageSourceId.mp_titancore_flame_wave ] = "#TITANCORE_FLAME_WAVE", + [ eDamageSourceId.mp_titancore_flame_wave_secondary ] = "#GEAR_SCORCH_FLAMECORE", + [ eDamageSourceId.mp_titancore_nuke_core ] = "#TITANCORE_NUKE", + [ eDamageSourceId.mp_titancore_nuke_missile ] = "#TITANCORE_NUKE_MISSILE", + [ eDamageSourceId.mp_titancore_shift_core ] = "#TITANCORE_SWORD", + [ eDamageSourceId.berserker_melee ] = "#DEATH_BERSERKER_MELEE", + [ eDamageSourceId.human_melee ] = "#DEATH_HUMAN_MELEE", + [ eDamageSourceId.auto_titan_melee ] = "#DEATH_AUTO_TITAN_MELEE", + + [ eDamageSourceId.prowler_melee ] = "#DEATH_PROWLER_MELEE", + [ eDamageSourceId.super_spectre_melee ] = "#DEATH_SUPER_SPECTRE", + [ eDamageSourceId.grunt_melee ] = "#DEATH_GRUNT_MELEE", + [ eDamageSourceId.spectre_melee ] = "#DEATH_SPECTRE_MELEE", + [ eDamageSourceId.eviscerate ] = "#DEATH_EVISCERATE", + [ eDamageSourceId.wall_smash ] = "#DEATH_WALL_SMASH", + [ eDamageSourceId.ai_turret ] = "#DEATH_TURRET", + [ eDamageSourceId.team_switch ] = "#DEATH_TEAM_CHANGE", + [ eDamageSourceId.rocket ] = "#DEATH_ROCKET", + [ eDamageSourceId.titan_explosion ] = "#DEATH_TITAN_EXPLOSION", + [ eDamageSourceId.evac_dropship_explosion ] = "#DEATH_EVAC_DROPSHIP_EXPLOSION", + [ eDamageSourceId.flash_surge ] = "#DEATH_FLASH_SURGE", + [ eDamageSourceId.molotov ] = "#DEATH_MOLOTOV", + [ eDamageSourceId.sticky_time_bomb ] = "#DEATH_STICKY_TIME_BOMB", + [ eDamageSourceId.vortex_grenade ] = "#DEATH_VORTEX_GRENADE", + [ eDamageSourceId.droppod_impact ] = "#DEATH_DROPPOD_CRUSH", + [ eDamageSourceId.ai_turret_explosion ] = "#DEATH_TURRET_EXPLOSION", + [ eDamageSourceId.rodeo_trap ] = "#DEATH_RODEO_TRAP", + [ eDamageSourceId.round_end ] = "#DEATH_ROUND_END", + [ eDamageSourceId.burn ] = "#DEATH_BURN", + [ eDamageSourceId.mind_crime ] = "Mind Crime", + [ eDamageSourceId.charge_ball ] = "Charge Ball", + [ eDamageSourceId.mp_titanweapon_rocketeer_missile ] = "Rocketeer Missile", + [ eDamageSourceId.core_overload ] = "#DEATH_CORE_OVERLOAD", + [ eDamageSourceId.mp_weapon_arc_trap ] = "#WPN_ARC_TRAP", + + + [ eDamageSourceId.mp_turretweapon_sentry ] = "#WPN_SENTRY_TURRET", + [ eDamageSourceId.mp_turretweapon_blaster ] = "#WPN_BLASTER_TURRET", + [ eDamageSourceId.mp_turretweapon_rockets ] = "#WPN_ROCKET_TURRET", + [ eDamageSourceId.mp_turretweapon_plasma ] = "#WPN_PLASMA_TURRET", + + [ eDamageSourceId.bubble_shield ] = "#DEATH_BUBBLE_SHIELD", + [ eDamageSourceId.sticky_explosive ] = "#DEATH_STICKY_EXPLOSIVE", + [ eDamageSourceId.titan_grapple ] = "#DEATH_TITAN_GRAPPLE", + + [ eDamageSourceId.satellite_strike ] = "#DEATH_SATELLITE_STRIKE", + + [ eDamageSourceId.mp_titanweapon_meteor ] = "#WPN_TITAN_METEOR", + [ eDamageSourceId.mp_titanweapon_meteor_thermite ] = "#WPN_TITAN_METEOR", + [ eDamageSourceId.mp_titanweapon_meteor_thermite_charged ] = "Thermite Meteor", + [ eDamageSourceId.mp_titanweapon_flame_ring ] = "Flame Wreath", + + // Instant death. Show no percentages on death recap. + [ eDamageSourceId.fall ] = "#DEATH_FALL", + //Todo: Rename eDamageSourceId.splat with a more appropriate name. This damage type was used for enviornmental damage, but it was for eject killing pilots if they were near a ceiling. I've changed the localized string to "Enviornment Damage", but this will cause confusion in the future. + [ eDamageSourceId.splat ] = "#DEATH_SPLAT", + [ eDamageSourceId.titan_execution ] = "#DEATH_TITAN_EXECUTION", + [ eDamageSourceId.human_execution ] = "#DEATH_HUMAN_EXECUTION", + [ eDamageSourceId.outOfBounds ] = "#DEATH_OUT_OF_BOUNDS", + [ eDamageSourceId.indoor_inferno ] = "#DEATH_INDOOR_INFERNO", + [ eDamageSourceId.submerged ] = "#DEATH_SUBMERGED", + [ eDamageSourceId.switchback_trap ] = "#DEATH_ELECTROCUTION", // Damages teammates and opposing team + [ eDamageSourceId.floor_is_lava ] = "#DEATH_ELECTROCUTION", + [ eDamageSourceId.suicideSpectreAoE ] = "#DEATH_SUICIDE_SPECTRE", // Used for distinguishing the initial spectre from allies. + [ eDamageSourceId.titanEmpField ] = "#DEATH_TITAN_EMP_FIELD", + [ eDamageSourceId.deadly_fog ] = "#DEATH_DEADLY_FOG", + + + // Prototype + [ eDamageSourceId.mp_weapon_zipline ] = "Zipline", + [ eDamageSourceId.mp_ability_ground_slam ] = "Ground Slam", + [ eDamageSourceId.sp_weapon_arc_tool ] = "#WPN_ARC_TOOL", + [ eDamageSourceId.sp_weapon_proto_battery_charger_offhand ] = "Battery Charger", + [ eDamageSourceId.at_turret_override ] = "AT Turret", + [ eDamageSourceId.phase_shift ] = "#WPN_SHIFTER", + [ eDamageSourceId.gamemode_bomb_detonation ] = "Bomb Detonation", + [ eDamageSourceId.bleedout ] = "#DEATH_BLEEDOUT", + + [ eDamageSourceId.damagedef_unknownBugIt ] = "#DEATH_GENERIC_KILLED", + [ eDamageSourceId.damagedef_unknown ] = "#DEATH_GENERIC_KILLED", + [ eDamageSourceId.weapon_cubemap ] = "#DEATH_GENERIC_KILLED", + [ eDamageSourceId.stuck ] = "#DEATH_GENERIC_KILLED", + [ eDamageSourceId.rodeo_battery_removal ] = "#DEATH_RODEO_BATTERY_REMOVAL", + + [ eDamageSourceId.melee_pilot_emptyhanded ] = "#DEATH_MELEE", + [ eDamageSourceId.melee_pilot_arena ] = "#DEATH_MELEE", + [ eDamageSourceId.melee_pilot_sword ] = "#DEATH_SWORD", + [ eDamageSourceId.melee_titan_punch ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_ion ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_tone ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_northstar ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_scorch ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_legion ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_fighter ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_punch_vanguard ] = "#DEATH_TITAN_MELEE", + [ eDamageSourceId.melee_titan_sword ] = "#DEATH_TITAN_SWORD", + [ eDamageSourceId.melee_titan_sword_aoe ] = "#DEATH_TITAN_SWORD" + } + + #if DEV + //development, with retail versions incase a rare bug happens we dont want to show developer text + file.damageSourceIDToName[ eDamageSourceId.damagedef_unknownBugIt ] = "UNKNOWN! BUG IT!" + file.damageSourceIDToName[ eDamageSourceId.damagedef_unknown ] = "Unknown" + file.damageSourceIDToName[ eDamageSourceId.weapon_cubemap ] = "Cubemap" + //file.damageSourceIDToName[ eDamageSourceId.invalid ] = "INVALID (BUG IT!)" + file.damageSourceIDToName[ eDamageSourceId.stuck ] = "NPC got Stuck (Don't Bug it!)" + #endif +} + +void function RegisterWeaponDamageSourceName( string weaponRef, string damageSourceName ) +{ + int sourceID = eDamageSourceId[weaponRef] + file.damageSourceIDToName[ sourceID ] <- damageSourceName +} + +bool function DamageSourceIDHasString( int index ) +{ + return (index in file.damageSourceIDToString) +} + +string function DamageSourceIDToString( int index ) +{ + return file.damageSourceIDToString[ index ] +} + +string function GetObitFromDamageSourceID( int damageSourceID ) +{ + if ( damageSourceID > 0 && damageSourceID < DamageDef_GetCount() ) + { + return DamageDef_GetObituary( damageSourceID ) + } + + if ( damageSourceID in file.damageSourceIDToName ) + return file.damageSourceIDToName[ damageSourceID ] + + table damageSourceIdEnum = expect table( getconsttable().eDamageSourceId ) + foreach ( name, id in damageSourceIdEnum ) + { + if ( id == damageSourceID ) + return expect string( name ) + } + + return "" +} + +#if SERVER +void function RegisterWeaponDamageSource( string weaponRef, string damageSourceName ) +{ + // Have to do this since squirrel table initialization only supports literals for string keys + table< string, string > temp + temp[ weaponRef ] <- damageSourceName + RegisterWeaponDamageSources( temp ) +} + +/* Values are expected to be in a table containing the enum variable name and the string name, e.g. + {"mp_titanweapon_sniper" : "Plasma Railgun", "mp_titanweapon_meteor" : "T203 Thermite Launcher"} + Only works properly if used after the match starts, e.g. called in "after" callbacks. +*/ +void function RegisterWeaponDamageSources( table< string, string > newValueTable ) +{ + int trgt = file.damageSourceIDToString.len() - 1 // -1 accounts for invalid. + int lastCustomSize = file.customDamageSourceIDList.len() // Used to only send new IDs to clients if any are added during runtime. + + foreach ( newVal, stringVal in newValueTable ) + { + // Don't replace existing enum values + while ( trgt in file.damageSourceIDToString ) + trgt++ + + // Only move insertion point if insertion succeeded + if ( RegisterWeaponDamageSourceInternal( trgt, newVal, stringVal ) ) + trgt++; + } + + // Send IDs created during match runtime. IDs made on inits get sent through client connected callback. + foreach( player in GetPlayerArray() ) + SendNewDamageSourceIDs( player, lastCustomSize ) +} +#endif + +bool function RegisterWeaponDamageSourceInternal( int id, string newVal, string stringVal ) +{ + table damageSourceID = expect table( getconsttable()[ "eDamageSourceId" ] ) + + // Fail invalid new source IDs (already exists or cannot be sent via string commands). Length condition has loose padding to account for ID string length. + if ( newVal in damageSourceID || newVal.len() + stringVal.len() > SOURCE_ID_MAX_MESSAGE_LENGTH - 15 || id in file.damageSourceIDToString ) + return false + + damageSourceID[ newVal ] <- id + file.damageSourceIDToString[ id ] <- newVal + file.damageSourceIDToName[ id ] <- stringVal + file.customDamageSourceIDList.extend( [ id.tostring(), newVal, StringReplace( stringVal, " ", MESSAGE_SPACE_PADDING ) ] ) + return true +} + +#if SERVER +void function SendNewDamageSourceIDsConnected( entity player ) +{ + SendNewDamageSourceIDs( player ) +} + +void function SendNewDamageSourceIDs( entity player, int index = 0 ) +{ + while ( index < file.customDamageSourceIDList.len() ) + { + int curSize = 0 + int curIndex = index + + // Figure out how many sources to send in this message chunk + while ( curIndex < file.customDamageSourceIDList.len() ) + { + // Sources are inserted to the custom list in triplets, so we can trust these indices exist. + curSize += file.customDamageSourceIDList[ curIndex ].len() + curSize += file.customDamageSourceIDList[ curIndex + 1 ].len() + curSize += file.customDamageSourceIDList[ curIndex + 2 ].len() + + // Stop before including strings in current message if it exceeds max message length. + // This will never stall on a singular source that exceeds the size since new sources are size limited. + if ( curSize > SOURCE_ID_MAX_MESSAGE_LENGTH ) + break + + curIndex += 3 + } + + // Create the string to pass to client + string message = "" + while ( index < curIndex ) + message += file.customDamageSourceIDList[ index++ ] + " " + + ServerToClientStringCommand( player, "register_damage_source_ids " + message ) + } +} +#else +void function ReceiveNewDamageSourceIDs( array args ) +{ + // IDs are inserted to the custom list in triplets, so we can trust these indices exist and the loop will end properly + for ( int i = 0; i < args.len(); i += 3 ) + RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " " ) ) +} +#endif \ No newline at end of file -- cgit v1.2.3 From 052e45547536ed139a5729498461ee242951a4c2 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Sat, 27 Aug 2022 00:39:25 +0100 Subject: Remove bad loadout validation properties for pilot and titan (#493) --- Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut | 3 --- 1 file changed, 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut index d15220e4..fbaf9e02 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut @@ -2379,10 +2379,8 @@ bool function IsValidPilotLoadoutProperty( string propertyName ) case "weapon3Mod2": case "weapon3Mod3": case "ordnance": - case "special": case "passive1": case "passive2": - case "melee": case "skinIndex": case "camoIndex": case "primarySkinIndex": @@ -2403,7 +2401,6 @@ bool function IsValidTitanLoadoutProperty( string propertyName ) { case "name": case "titanClass": - case "setFile": case "primaryMod": case "special": case "antirodeo": -- cgit v1.2.3 From 57c9f05a5fd4f901bd8622829dbee4809990e71a Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sat, 27 Aug 2022 01:41:47 +0200 Subject: Add alive checks (#491) hotfixes respawn crash exploit Co-authored-by: ScureX --- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 6 ++++++ 1 file changed, 6 insertions(+) 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 b453286c..ca8dc5f1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -427,11 +427,17 @@ void function DecideRespawnPlayer( entity player ) void function RespawnAsPilot( entity player ) { + // respawn crash exploit hotfix + if(IsAlive( player )) return + player.RespawnPlayer( FindSpawnPoint( player, false, ( ShouldStartSpawn( player ) || Flag( "ForceStartSpawn" ) ) && !IsFFAGame() ) ) } void function RespawnAsTitan( entity player, bool manualPosition = false ) { + // respawn crash exploit hotfix + if(IsAlive( player )) return + player.Signal( "PlayerRespawnStarted" ) player.isSpawning = true -- cgit v1.2.3 From ecd37edc3f833526518cf6a6abb2bd128fd0a51c Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Wed, 21 Sep 2022 21:44:20 +0000 Subject: Change modlist interface (#401) * Change modlist interface * add the settings file * new current mod enabled indicator * Only show requiredOnClient warning when required * filter by required on client status * fix ONLY_REQUIRED instead of ONLY_NOT_REQUIRED * update list slider position when reopening * colorblind colors * convar for reversed list and allow unicode search * better colors for the blind * Update filtered modlist after changing mod status * fix some things * mod enabled color blind icon * move enabled icon --- Northstar.Client/mod.json | 10 + .../northstar_client_localisation_english.txt | 2 + .../mod/resource/ui/menus/modlist.menu | 1003 +++++++++++--------- .../resource/ui/menus/panels/modlist_settings.res | 79 ++ .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 679 ++++++++----- 5 files changed, 1110 insertions(+), 663 deletions(-) create mode 100644 Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 17b01543..7dcfcd21 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -31,6 +31,16 @@ { "Name": "filter_map_hide_locked", "DefaultValue": "0" + }, + { + "Name": "modlist_show_convars", + "DefaultValue": "0", + "Flags": 16777216 + }, + { + "Name": "modlist_reverse", + "DefaultValue": "0", + "Flags": 16777216 } ], "Scripts": [ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 8c6cadcf..3382e5b1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -301,6 +301,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "SHOW_ALL" "All" "SHOW_ONLY_ENABLED" "Only Enabled" "SHOW_ONLY_DISABLED" "Only Disabled" + "SHOW_ONLY_NOT_REQUIRED" "Only Optional Mods" + "SHOW_ONLY_REQUIRED" "Only Required Mods" // Maps menu "HIDE_LOCKED" "Hide locked" diff --git a/Northstar.Client/mod/resource/ui/menus/modlist.menu b/Northstar.Client/mod/resource/ui/menus/modlist.menu index ffe9a257..da59bcdd 100644 --- a/Northstar.Client/mod/resource/ui/menus/modlist.menu +++ b/Northstar.Client/mod/resource/ui/menus/modlist.menu @@ -1,4 +1,4 @@ -resource/ui/menus/mods_browse.menu +resource/ui/menus/modlist.menu { menu { @@ -18,497 +18,654 @@ resource/ui/menus/mods_browse.menu Vignette { - ControlName ImagePanel - InheritProperties MenuVignette + ControlName ImagePanel + InheritProperties MenuVignette } Title { - ControlName Label - InheritProperties MenuTitle - labelText "#MENU_TITLE_MODS" + ControlName Label + InheritProperties MenuTitle + labelText "#MENU_TITLE_MODS" } ImgTopBar { - ControlName ImagePanel - InheritProperties MenuTopBar + ControlName ImagePanel + InheritProperties MenuTopBar } - + ButtonRowAnchor { - ControlName Label - labelText "" + ControlName Label + labelText "" - xpos 120 - ypos 160 + xpos 120 + ypos 160 } - + FilterButtonsRowAnchor { - ControlName Label - labelText "" + ControlName Label + labelText "" - xpos 90 - ypos 848 + xpos 90 + ypos 848 } - + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// PANELS //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - BtnMod1 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 0 - navUp BtnMod15 - navDown BtnMod2 - - pin_to_sibling ButtonRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - BtnMod2 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 1 - pin_to_sibling BtnMod1 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod1 - navDown BtnMod3 - } - BtnMod3 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 2 - pin_to_sibling BtnMod2 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod2 - navDown BtnMod4 - } - BtnMod4 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 3 - pin_to_sibling BtnMod3 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - //ypos 11 - navUp BtnMod3 - navDown BtnMod5 - } - BtnMod5 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 4 - pin_to_sibling BtnMod4 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod4 - navDown BtnMod6 - } - BtnMod6 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 5 - pin_to_sibling BtnMod5 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod5 - navDown BtnMod7 - } - BtnMod7 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 6 - pin_to_sibling BtnMod6 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod6 - navDown BtnMod8 - } - BtnMod8 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 7 - pin_to_sibling BtnMod7 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod7 - navDown BtnMod9 - } - BtnMod9 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 8 - pin_to_sibling BtnMod8 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod8 - navDown BtnMod10 - } - BtnMod10 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 9 - pin_to_sibling BtnMod9 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod9 - navDown BtnMod11 - } - BtnMod11 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 10 - pin_to_sibling BtnMod10 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod10 - navDown BtnMod12 - } - BtnMod12 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 11 - pin_to_sibling BtnMod11 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod11 - navDown BtnMod13 - } - BtnMod13 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 12 - pin_to_sibling BtnMod12 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod12 - navDown BtnMod14 - } - BtnMod14 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 13 - pin_to_sibling BtnMod13 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod13 - navDown BtnMod15 - } - BtnMod15 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 14 - pin_to_sibling BtnMod14 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod14 - navDown BtnMod1 - } - BtnMod16 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 15 - pin_to_sibling BtnMod15 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod15 - navDown BtnMod17 - } - BtnMod17 - { - ControlName RuiButton - InheritProperties RuiSmallButton - classname ModButton - scriptID 16 - pin_to_sibling BtnMod16 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - navUp BtnMod16 - navDown BtnMod18 + Panel1 + { + ControlName CNestedPanel + classname ModSelectorPanel + scriptID 1 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling ButtonRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel2 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 2 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel1 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel3 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 3 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel2 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel4 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 4 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel3 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel5 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 5 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel4 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel6 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 6 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel5 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel7 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 7 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel6 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel8 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 8 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel7 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel9 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 9 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel8 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel10 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 10 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel9 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel11 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 11 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel10 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel12 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 12 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel11 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT } + Panel13 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 13 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel12 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel14 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 14 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel13 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + Panel15 + { + ControlName "CNestedPanel" + classname ModSelectorPanel + scriptID 15 + + controlSettingsFile "resource/ui/menus/panels/modlist_settings.res" + wide %100 + tall 45 + + pin_to_sibling Panel14 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +// FILTERS +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + FilterPanel { - ControlName RuiPanel - wide 800 - tall 112 - xpos -8 - classname FilterPanelChild - - rui "ui/knowledgebase_panel.rpak" + ControlName RuiPanel + classname FilterPanelChild + + wide 800 + tall 112 + xpos -8 + zpos -1 - visible 1 - zpos -1 + rui "ui/knowledgebase_panel.rpak" + visible 1 - pin_to_sibling FilterButtonsRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT + pin_to_sibling FilterButtonsRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT } - + BtnSearchLabel { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#SEARCHBAR_LABEL" - textAlignment west - classname FilterPanelChild - - wide 500 - xpos -23 - ypos -16 - - wrap 1 - visible 1 - zpos 0 - - pin_to_sibling FilterButtonsRowAnchor - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + classname FilterPanelChild + + labelText #SEARCHBAR_LABEL + textAlignment west + + wide 500 + xpos -23 + ypos -16 + zpos 0 + wrap 1 + visible 1 + + + + pin_to_sibling FilterButtonsRowAnchor + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + BtnModsSearch { - ControlName TextEntry - classname FilterPanelChild - zpos 100 // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. - xpos -400 - ypos -5 - wide 390 - tall 30 - textHidden 0 - editable 1 - font Default_21 - allowRightClickMenu 0 - allowSpecialCharacters 0 - unicode 0 - - pin_to_sibling BtnSearchLabel - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_RIGHT + ControlName TextEntry + classname FilterPanelChild + + zpos 100 // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + xpos -400 + ypos -5 + wide 390 + tall 30 + + textHidden 0 // Why? + editable 1 + font Default_21 + + allowRightClickMenu 0 + allowSpecialCharacters 0 + unicode 1 + + pin_to_sibling BtnSearchLabel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_RIGHT } - + SwtBtnShowFilter { - ControlName RuiButton - InheritProperties SwitchButton - labelText "#SHOW" - ConVar "filter_mods" - classname FilterPanelChild + ControlName RuiButton + InheritProperties SwitchButton + classname FilterPanelChild + + labelText "#SHOW" + ConVar "filter_mods" wide 500 - + list { - "#SHOW_ALL" 0 - "#SHOW_ONLY_ENABLED" 1 - "#SHOW_ONLY_DISABLED" 2 + "#SHOW_ALL" 0 + "#SHOW_ONLY_ENABLED" 1 + "#SHOW_ONLY_DISABLED" 2 + "#SHOW_ONLY_NOT_REQUIRED" 3 + "#SHOW_ONLY_REQUIRED" 4 } - - pin_to_sibling BtnSearchLabel - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + + pin_to_sibling BtnSearchLabel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT } - + + BtnListReverse + { + ControlName RuiButton + InheritProperties SwitchButton + classname FilterPanelChild + + xpos -15 + ypos -15 + + labelText "Reverse" + ConVar "modlist_reverse" + wide 260 + + list + { + "low first" 0 + "high first" 1 + } + + pin_to_sibling FilterPanel + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_RIGHT + } + BtnFiltersClear { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#CLEAR_FILTERS" - classname FilterPanelChild - wide 100 - xpos -15 - ypos -55 - zpos 90 - - scriptID 999 - - pin_to_sibling FilterPanel - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner BOTTOM_RIGHT + ControlName RuiButton + InheritProperties RuiSmallButton + classname FilterPanelChild + + labelText "#CLEAR_FILTERS" + wide 100 + xpos -15 + ypos -55 + zpos 90 + + pin_to_sibling FilterPanel + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner BOTTOM_RIGHT } - + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// MOD INFO +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + ModButtonsPanel + { + ControlName RuiPanel + classname FilterPanelChild + + wide 950 + tall 112 + + rui "ui/knowledgebase_panel.rpak" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP + pin_to_sibling_corner BOTTOM + } + + HideCVButton + { + ControlName RuiButton + InheritProperties SwitchButton + + labelText "ConVars" + ConVar "modlist_show_convars" + wide 300 + + list + { + "Hidden" 0 + "Shown" 1 + } + + pin_to_sibling ModButtonsPanel + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + + ModPageButton + { + ControlName RuiButton + InheritProperties RuiSmallButton + + textAlignment west + visible 0 + + pin_to_sibling HideCVButton + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningLegendImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + xpos -10 + ypos -5 + visible 0 + + pin_to_sibling ModButtonsPanel + pin_corner_to_sibling BOTTOM_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningLegendLabel + { + ControlName Label + + labelText " : This mod gets (un)loaded automatically" + wide 500 + tall 50 + visible 0 + + pin_to_sibling WarningLegendImage + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + LabelDetails { - ControlName RuiPanel - xpos 900 - ypos 160 - tall 800 - wide 950 - rui "ui/knowledgebase_panel.rpak" - wrap 1 - visible 1 - zpos 1 + ControlName RuiPanel + + xpos 900 + ypos 160 + zpos 1 + + tall 688 + wide 950 + rui "ui/knowledgebase_panel.rpak" + wrap 1 + visible 1 } - + + ModEnabledBar + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 950 + tall 7 + zpos 2 + visible 0 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_LEFT + } + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SLIDER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + BtnModListUpArrow { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "A" - wide 40 - tall 40 - xpos 2 - ypos 2 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 40 + xpos 2 + ypos 2 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListUpArrowPanel { - ControlName RuiPanel - wide 40 - tall 40 - xpos 2 - ypos 2 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 40 + xpos 2 + ypos 2 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + zpos -1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListDownArrow { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "V" - wide 40 - tall 40 - xpos 2 - ypos -646 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 40 + xpos 2 + ypos -646 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListDownArrowPanel { - ControlName RuiPanel - wide 40 - tall 40 - xpos 2 - ypos -646 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 40 + xpos 2 + ypos -646 + zpos -1 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListSlider { - ControlName RuiButton - InheritProperties RuiSmallButton - //labelText "V" - wide 40 - tall 604 - xpos 2 - ypos -40 - zpos 0 - - image "vgui/hud/white" - drawColor "255 255 255 128" - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiButton + InheritProperties RuiSmallButton + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos 0 + + image "vgui/hud/white" + drawColor "255 255 255 128" + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + BtnModListSliderPanel { - ControlName RuiPanel - wide 40 - tall 604 - xpos 2 - ypos -40 - - rui "ui/knowledgebase_panel.rpak" - - visible 1 - zpos -1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT - } - + ControlName RuiPanel + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos -1 + + rui "ui/knowledgebase_panel.rpak" + visible 1 + + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT + } + // sh_menu_models.gnut has a global function which gets called when // left mouse button gets called while hovering and has mouse // deltaX; deltaY which we can yoink for ourselfes MouseMovementCapture { - ControlName CMouseMovementCapturePanel - wide 40 - tall 604 - xpos 2 - ypos -40 - zpos 1 - - pin_to_sibling LabelDetails - pin_corner_to_sibling TOP_RIGHT - pin_to_sibling_corner TOP_LEFT + ControlName CMouseMovementCapturePanel + + wide 40 + tall 604 + xpos 2 + ypos -40 + zpos 1 + + pin_to_sibling LabelDetails + pin_corner_to_sibling TOP_RIGHT + pin_to_sibling_corner TOP_LEFT } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FooterButtons { - ControlName CNestedPanel - InheritProperties FooterButtons + ControlName CNestedPanel + InheritProperties FooterButtons } } } diff --git a/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res b/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res new file mode 100644 index 00000000..cd596238 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/panels/modlist_settings.res @@ -0,0 +1,79 @@ +resource/ui/menus/panels/modlist_setting.res +{ + BtnMod + { + ControlName RuiButton + InheritProperties RuiSmallButton + classname ModButton + labelText "please show up" + + pin_to_sibling ControlBox + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + Header + { + ControlName Label + wide 400 + labelText "labelText" + + pin_to_sibling ControlBox + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + ControlBox + { + ControlName RuiPanel + classname ControlBox + + tall 30 + wide 5 + ypos 5 + rui "ui/basic_image.rpak" + + pin_corner_to_sibling LEFT + pin_to_sibling_corner LEFT + } + + BottomLine + { + ControlName ImagePanel + InheritProperties MenuTopBar + ypos 0 + wide %50 + + pin_to_sibling BtnMod + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + + WarningImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + visible 0 + + pin_to_sibling BtnMod + pin_corner_to_sibling LEFT + pin_to_sibling_corner RIGHT + } + + EnabledImage + { + ControlName RuiPanel + + rui ui/basic_image.rpak + wide 30 + tall 30 + visible 0 + + pin_to_sibling BtnMod + pin_corner_to_sibling RIGHT + pin_to_sibling_corner LEFT + } +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 15d78025..01149bb0 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -5,18 +5,26 @@ global function AddNorthstarModMenu_MainMenuFooter global function ReloadMods -const int BUTTONS_PER_PAGE = 17 - +struct modData { + string name = "" + string version = "" + string link = "" + int loadPriority = 0 + bool enabled = false + array conVars = [] +} -struct modStruct { - int modIndex - string modName +struct panelContent { + modData& mod + bool isHeader = false } enum filterShow { ALL = 0, ONLY_ENABLED = 1, ONLY_DISABLED = 2 + ONLY_NOT_REQUIRED = 3, + ONLY_REQUIRED = 4 } struct { @@ -25,16 +33,19 @@ struct { } mouseDeltaBuffer struct { - bool shouldReloadModsOnEnd - string currentMod - var currentButton - int scrollOffset = 0 - - array modsArrayFiltered - + array mods var menu + array panels + int scrollOffset = 0 + array enabledMods + var currentButton + string searchTerm + modData& lastMod } file +const int PANELS_LEN = 15 +const string[3] CORE_MODS = ["Northstar.Client", "Northstar.Coop", "Northstar.CustomServers"] // Shows a warning if you try to disable these + void function AddNorthstarModMenu() { AddMenu( "ModListMenu", $"resource/ui/menus/modlist.menu", InitModMenu ) @@ -54,11 +65,46 @@ void function AdvanceToModListMenu( var button ) void function InitModMenu() { file.menu = GetMenu( "ModListMenu" ) - + file.panels = GetElementsByClassname( file.menu, "ModSelectorPanel" ) + + var rui = Hud_GetRui( Hud_GetChild( file.menu, "WarningLegendImage" ) ) + RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) + + RuiSetFloat( Hud_GetRui( Hud_GetChild( file.menu, "ModEnabledBar" ) ), "basicImageAlpha", 0.8 ) + + // Mod buttons + foreach ( var panel in file.panels ) + { + var button = Hud_GetChild( panel, "BtnMod" ) + AddButtonEventHandler( button, UIE_GET_FOCUS, OnModButtonFocused ) + AddButtonEventHandler( button, UIE_CLICK, OnModButtonPressed ) + + var rui = Hud_GetRui( Hud_GetChild( panel, "WarningImage" ) ) + RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) + } + AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + // UI Events AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnModMenuClosed ) + + // up / down buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListUpArrow" ), UIE_CLICK, OnUpArrowSelected ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListDownArrow" ), UIE_CLICK, OnDownArrowSelected ) + + // Mod info buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "ModPageButton" ), UIE_CLICK, OnModLinkButtonPressed ) + + // Filter buttons + AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnShowFilter"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModsSearch"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnListReverse"), UIE_CHANGE, OnFiltersChange ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear"), UIE_CLICK, OnBtnFiltersClear_Activate ) + + AddButtonEventHandler( Hud_GetChild( file.menu, "HideCVButton"), UIE_CHANGE, OnHideConVarsChange ) + + // Footers AddMenuFooterOption( file.menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) AddMenuFooterOption( file.menu, @@ -74,37 +120,25 @@ void function InitModMenu() "#AUTHENTICATION_AGREEMENT", OnAuthenticationAgreementButtonPressed ) - - foreach ( var button in GetElementsByClassname( file.menu, "ModButton" ) ) - { - AddButtonEventHandler( button, UIE_GET_FOCUS, OnModMenuButtonFocused ) - AddButtonEventHandler( button, UIE_CLICK, OnModMenuButtonPressed ) - } - - AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnShowFilter"), UIE_CHANGE, OnFiltersChange ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModsSearch"), UIE_CHANGE, OnFiltersChange ) - - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListUpArrow"), UIE_CLICK, OnUpArrowSelected ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnModListDownArrow"), UIE_CLICK, OnDownArrowSelected ) - - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear"), UIE_CLICK, OnBtnFiltersClear_Activate ) - + // Nuke weird rui on filter switch RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnShowFilter")), "buttonText", "") + RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "HideCVButton")), "buttonText", "") + RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "BtnListReverse")), "buttonText", "") } +// EVENTS + void function OnModMenuOpened() { - file.shouldReloadModsOnEnd = false - file.scrollOffset = 0 - - RegisterButtonPressedCallback(MOUSE_WHEEL_UP , OnScrollUp) - RegisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) + file.enabledMods = GetEnabledModsArray() // used to check if mods should be reloaded - Hud_SetText( Hud_GetChild( file.menu, "Title" ), "#MENU_TITLE_MODS" ) + UpdateList() + UpdateListSliderHeight() + UpdateListSliderPosition() - - OnFiltersChange(0) + RegisterButtonPressedCallback(MOUSE_WHEEL_UP , OnScrollUp) + RegisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) } void function OnModMenuClosed() @@ -115,120 +149,118 @@ void function OnModMenuClosed() DeregisterButtonPressedCallback(MOUSE_WHEEL_DOWN , OnScrollDown) } catch ( ex ) {} - - if ( file.shouldReloadModsOnEnd ) - ReloadMods() -} - -void function OnFiltersChange( var n ) -{ - file.scrollOffset = 0 - - HideAllButtons() - - RefreshModsArray() - - UpdateList() - - UpdateListSliderHeight() -} -void function RefreshModsArray() -{ - string searchTerm = Hud_GetUTF8Text( Hud_GetChild( file.menu, "BtnModsSearch" ) ).tolower() - - file.modsArrayFiltered.clear() - - - bool useSearch = searchTerm != "" - - - array modNames = NSGetModNames() - int modCount = modNames.len() - - foreach ( int index_, mod in modNames ) { - modStruct tempMod - tempMod.modIndex = index_ - tempMod.modName = mod - - int filter = GetConVarInt( "filter_mods" ) - bool enabled = NSIsModEnabled( tempMod.modName ) - - bool containsTerm = tempMod.modName.tolower().find(searchTerm) != null - - if ( filter == filterShow.ALL && (useSearch == true ? containsTerm : true ) ) - { - file.modsArrayFiltered.append( tempMod ) - } - else if ( filter == filterShow.ONLY_ENABLED && enabled && (useSearch == true ? containsTerm : true )) - { - file.modsArrayFiltered.append( tempMod ) - } - else if ( filter == filterShow.ONLY_DISABLED && !enabled && (useSearch == true ? containsTerm : true )) + array current = GetEnabledModsArray() + bool reload + foreach ( string mod in current ) + { + if ( file.enabledMods.find(mod) == -1 ) { - file.modsArrayFiltered.append( tempMod ) + reload = true + break } } + if ( current.len() != file.enabledMods.len() || reload ) // Only reload if we have to + ReloadMods() } -void function HideAllButtons() +void function OnModButtonFocused( var button ) { - array buttons = GetElementsByClassname( file.menu, "ModButton" ) - - // disable all buttons, we'll enable the ones we need later - foreach ( var button in buttons ) + file.currentButton = button + file.lastMod = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod + string modName = file.lastMod.name + var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) + + RuiSetGameTime( rui, "startTime", -99999.99 ) // make sure it skips the whole animation for showing this + RuiSetString( rui, "headerText", modName ) + RuiSetString( rui, "messageText", FormatModDescription( modName ) ) + + // Add a button to open the link with if required + string link = NSGetModDownloadLinkByModName( modName ) + var linkButton = Hud_GetChild( file.menu, "ModPageButton" ) + if ( link.len() ) { - Hud_SetEnabled( button, false ) - Hud_SetVisible( button, false ) + Hud_SetEnabled( linkButton, true ) + Hud_SetVisible( linkButton, true ) + Hud_SetText( linkButton, link ) } + else + { + Hud_SetEnabled( linkButton, false ) + Hud_SetVisible( linkButton, false ) + } + + SetControlBarColor( modName ) + + bool required = NSIsModRequiredOnClient( modName ) + Hud_SetVisible( Hud_GetChild( file.menu, "WarningLegendLabel" ), required ) + Hud_SetVisible( Hud_GetChild( file.menu, "WarningLegendImage" ), required ) } -void function UpdateList() +void function OnModButtonPressed( var button ) { - array buttons = GetElementsByClassname( file.menu, "ModButton" ) - - - int j = file.modsArrayFiltered.len() > 17 ? 17 : file.modsArrayFiltered.len() - - for ( int i = 0; i < j; i++ ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod.name + if ( StaticFind( modName ) && NSIsModEnabled( modName ) ) + CoreModToggleDialog( modName ) + else { - Hud_SetEnabled( buttons[ i ], true ) - Hud_SetVisible( buttons[ i ], true ) - - SetModMenuNameText( buttons[ i ] ) + NSSetModEnabled( modName, !NSIsModEnabled( modName ) ) + var panel = file.panels[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) - 1 ] + SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) + SetControlBarColor( modName ) + SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) + RefreshMods() } } -void function SetModMenuNameText( var button ) +void function OnReloadModsButtonPressed( var button ) { - modStruct mod = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ] + ReloadMods() +} - // should be localisation at some point - if ( NSIsModEnabled( mod.modName ) ) - SetButtonRuiText( button, mod.modName + " v" + NSGetModVersionByModName( mod.modName ) ) - else - SetButtonRuiText( button, mod.modName + " (DISABLED)" ) +void function OnAuthenticationAgreementButtonPressed( var button ) +{ + NorthstarMasterServerAuthDialog() } -void function OnModMenuButtonPressed( var button ) +void function OnModLinkButtonPressed( var button ) { - string modName = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ].modName - if ( ( modName == "Northstar.Client" || modName == "Northstar.Coop" || modName == "Northstar.CustomServers") && NSIsModEnabled( modName ) ) - { - file.currentMod = modName - file.currentButton = button - CoreModToggleDialog( modName ) - } - else - { - NSSetModEnabled( modName, !NSIsModEnabled( modName ) ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) + file.scrollOffset - 1 ].mod.name + string link = NSGetModDownloadLinkByModName( modName ) + if ( link.find("http://") != 0 && link.find("https://") != 0 ) + link = "http://" + link // links without the http or https protocol get opened in the internal browser + LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL ) +} + +void function OnFiltersChange( var n ) +{ + file.scrollOffset = 0 - SetModMenuNameText( button ) + UpdateList() + UpdateListSliderHeight() + UpdateListSliderPosition() +} - file.shouldReloadModsOnEnd = true - } +void function OnBtnFiltersClear_Activate( var button ) +{ + Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) + + SetConVarInt( "filter_mods", 0 ) + + OnFiltersChange( null ) +} + +void function OnHideConVarsChange( var n ) +{ + string modName = file.lastMod.name + if ( modName == "" ) + return + var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) + RuiSetString( rui, "messageText", FormatModDescription( modName ) ) } +// LIST LOGIC + void function CoreModToggleDialog( string mod ) { DialogData dialogData @@ -247,46 +279,235 @@ void function CoreModToggleDialog( string mod ) void function DisableMod() { - NSSetModEnabled( file.currentMod, false ) + string modName = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) + file.scrollOffset - 1 ].mod.name + NSSetModEnabled( modName, false ) - SetModMenuNameText( file.currentButton ) + var panel = file.panels[ int ( Hud_GetScriptID( Hud_GetParent( file.currentButton ) ) ) - 1] + SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) + SetControlBarColor( modName ) + SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) - file.shouldReloadModsOnEnd = true + RefreshMods() } -void function OnModMenuButtonFocused( var button ) +array function GetEnabledModsArray() { - string modName = file.modsArrayFiltered[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ].modName + array enabledMods + foreach ( string mod in NSGetModNames() ) + { + if ( NSIsModEnabled( mod ) ) + enabledMods.append( mod ) + } + return enabledMods +} - var rui = Hud_GetRui( Hud_GetChild( file.menu, "LabelDetails" ) ) - - RuiSetGameTime( rui, "startTime", -99999.99 ) // make sure it skips the whole animation for showing this - RuiSetString( rui, "headerText", modName ) - RuiSetString( rui, "messageText", FormatModDescription( modName ) ) +void function HideAllPanels() +{ + foreach ( var panel in file.panels ) + { + Hud_SetEnabled( panel, false ) + Hud_SetVisible( panel, false ) + } +} + +void function UpdateList() +{ + HideAllPanels() + RefreshMods() + DisplayModPanels() +} + +void function RefreshMods() +{ + array modNames = NSGetModNames() + file.mods.clear() + + bool reverse = GetConVarBool( "modlist_reverse" ) + + int lastLoadPriority = reverse ? NSGetModLoadPriority( modNames[ modNames.len() - 1 ] ) + 1 : -1 + string searchTerm = Hud_GetUTF8Text( Hud_GetChild( file.menu, "BtnModsSearch" ) ).tolower() + + for ( int i = reverse ? modNames.len() - 1 : 0; + reverse ? ( i >= 0 ) : ( i < modNames.len() ); + i += ( reverse ? -1 : 1) ) + { + string mod = modNames[i] + + if ( searchTerm.len() && mod.tolower().find( searchTerm ) == null ) + continue + + bool enabled = NSIsModEnabled( mod ) + bool required = NSIsModRequiredOnClient( mod ) + switch ( GetConVarInt( "filter_mods" ) ) + { + case filterShow.ONLY_ENABLED: + if ( !enabled ) + continue + break + case filterShow.ONLY_DISABLED: + if ( enabled ) + continue + break + case filterShow.ONLY_REQUIRED: + if ( !required ) + continue + break + case filterShow.ONLY_NOT_REQUIRED: + if( required ) + continue + break + } + + int pr = NSGetModLoadPriority( mod ) + + if ( reverse ? pr < lastLoadPriority : pr > lastLoadPriority ) + { + modData m + m.name = pr.tostring() + + panelContent c + c.mod = m + c.isHeader = true + file.mods.append( c ) + lastLoadPriority = pr + } + + modData m + m.name = mod + m.version = NSGetModVersionByModName( mod ) + m.link = NSGetModDownloadLinkByModName( mod ) + m.loadPriority = NSGetModLoadPriority( mod ) + m.enabled = enabled + m.conVars = NSGetModConvarsByModName( mod ) + + panelContent c + c.mod = m + + file.mods.append( c ) + } +} + +void function DisplayModPanels() +{ + foreach ( int i, var panel in file.panels) + { + if ( i >= file.mods.len() ) // don't try to show more panels than needed + break + + panelContent c = file.mods[ file.scrollOffset + i ] + modData mod = c.mod + var btn = Hud_GetChild( panel, "BtnMod" ) + var headerLabel = Hud_GetChild( panel, "Header" ) + var box = Hud_GetChild( panel, "ControlBox" ) + var line = Hud_GetChild( panel, "BottomLine" ) + var warning = Hud_GetChild( panel, "WarningImage" ) + var enabledImage = Hud_GetChild( panel, "EnabledImage" ) + + if ( c.isHeader ) + { + Hud_SetEnabled( btn, false ) + Hud_SetVisible( btn, false ) + + Hud_SetText( headerLabel, "Load Priority: " + mod.name ) + Hud_SetVisible( headerLabel, true ) + + Hud_SetVisible( box, false ) + Hud_SetVisible( line, true ) + + Hud_SetVisible( warning, false ) + Hud_SetVisible( enabledImage, false ) + } + else + { + Hud_SetEnabled( btn, true ) + Hud_SetVisible( btn, true ) + Hud_SetText( btn, mod.name ) + + Hud_SetVisible( headerLabel, false ) + + SetControlBoxColor( box, mod.name ) + Hud_SetVisible( box, true ) + Hud_SetVisible( line, false ) + + Hud_SetVisible( warning, NSIsModRequiredOnClient( c.mod.name ) ) + + SetModEnabledHelperImageAsset( enabledImage, c.mod.name ) + } + Hud_SetVisible( panel, true ) + } +} + +void function SetModEnabledHelperImageAsset( var panel, string modName ) +{ + if( NSIsModEnabled( modName ) ) + RuiSetImage( Hud_GetRui( panel ), "basicImage", $"rui/menu/common/merit_state_success" ) + else + RuiSetImage( Hud_GetRui( panel ), "basicImage", $"rui/menu/common/merit_state_failure" ) + RuiSetFloat3(Hud_GetRui( panel ), "basicImageColor", GetControlColorForMod( modName ) ) + Hud_SetVisible( panel, true ) +} + +void function SetControlBoxColor( var box, string modName ) +{ + var rui = Hud_GetRui( box ) + // if ( NSIsModEnabled( modName ) ) + // RuiSetFloat3(rui, "basicImageColor", <0,1,0>) + // else + // RuiSetFloat3(rui, "basicImageColor", <1,0,0>) + RuiSetFloat3(rui, "basicImageColor", GetControlColorForMod( modName ) ) +} + +void function SetControlBarColor( string modName ) +{ + var bar_element = Hud_GetChild( file.menu, "ModEnabledBar" ) + var bar = Hud_GetRui( bar_element ) + // if ( NSIsModEnabled( modName ) ) + // RuiSetFloat3(bar, "basicImageColor", <0,1,0>) + // else + // RuiSetFloat3(bar, "basicImageColor", <1,0,0>) + RuiSetFloat3(bar, "basicImageColor", GetControlColorForMod( modName ) ) + Hud_SetVisible( bar_element, true ) +} + +vector function GetControlColorForMod( string modName ) +{ + if ( NSIsModEnabled( modName ) ) + switch ( GetConVarInt( "colorblind_mode" ) ) + { + case 1: + case 2: + case 3: + default: + return <0,1,0> + } + else + switch ( GetConVarInt( "colorblind_mode" ) ) + { + case 1: + case 2: + return <0.29,0,0.57> + case 3: + default: + return <1,0,0> + } + unreachable } string function FormatModDescription( string modName ) { string ret // version - ret += format( "Version %s\n", NSGetModVersionByModName( modName ) ) - - // download link - string modLink = NSGetModDownloadLinkByModName( modName ) - if ( modLink.len() != 0 ) - ret += format( "Download link: \"%s\"\n", modLink ) - + ret += format( "Version %s\n", NSGetModVersionByModName( modName ) ) + // load priority ret += format( "Load Priority: %i\n", NSGetModLoadPriority( modName ) ) - - // todo: add ClientRequired here - + // convars array modCvars = NSGetModConvarsByModName( modName ) - if ( modCvars.len() != 0 ) + if ( modCvars.len() != 0 && GetConVarBool( "modlist_show_convars" ) ) { ret += "ConVars: " - + for ( int i = 0; i < modCvars.len(); i++ ) { if ( i != modCvars.len() - 1 ) @@ -294,76 +515,33 @@ string function FormatModDescription( string modName ) else ret += format( "\"%s\"", modCvars[ i ] ) } - + ret += "\n" } - + // description ret += format( "\n%s\n", NSGetModDescriptionByModName( modName ) ) - - return ret -} - -void function OnReloadModsButtonPressed( var button ) -{ - ReloadMods() -} - -void function ReloadMods() -{ - NSReloadMods() - ClientCommand( "reload_localization" ) - ClientCommand( "loadPlaylists" ) - - bool svCheatsOriginal = GetConVarBool( "sv_cheats" ) - SetConVarBool( "sv_cheats", true ) - ClientCommand( "weapon_reparse" ) // weapon_reparse only works if a server is running and sv_cheats is 1, gotta figure this out eventually - SetConVarBool( "sv_cheats", svCheatsOriginal ) - - // note: the logic for this seems really odd, unsure why it doesn't seem to update, since the same code seems to get run irregardless of whether we've read weapon data before - ClientCommand( "uiscript_reset" ) -} -void function OnAuthenticationAgreementButtonPressed( var button ) -{ - NorthstarMasterServerAuthDialog() + return ret } +//////////// +// SLIDER +//////////// -void function OnBtnFiltersClear_Activate( var button ) -{ - Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) - - SetConVarInt( "filter_mods", 0 ) - - OnFiltersChange(0) -} - -////////////////////////////// -// Slider -////////////////////////////// void function UpdateMouseDeltaBuffer(int x, int y) { - mouseDeltaBuffer.deltaX += x - mouseDeltaBuffer.deltaY += y + mouseDeltaBuffer.deltaX = x + mouseDeltaBuffer.deltaY = y SliderBarUpdate() } -void function FlushMouseDeltaBuffer() -{ - mouseDeltaBuffer.deltaX = 0 - mouseDeltaBuffer.deltaY = 0 -} - void function SliderBarUpdate() { - if ( file.modsArrayFiltered.len() <= 17 ) - { - FlushMouseDeltaBuffer() + if ( file.mods.len() <= 15 ) return - } var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) @@ -376,12 +554,11 @@ void function SliderBarUpdate() float maxYPos = minYPos - (maxHeight - Hud_GetHeight( sliderPanel )) float useableSpace = (maxHeight - Hud_GetHeight( sliderPanel )) - float jump = minYPos - (useableSpace / ( float( file.modsArrayFiltered.len()))) + float jump = minYPos - (useableSpace / ( float( file.mods.len()))) // got local from official respaw scripts, without untyped throws an error local pos = Hud_GetPos(sliderButton)[1] local newPos = pos - mouseDeltaBuffer.deltaY - FlushMouseDeltaBuffer() if ( newPos < maxYPos ) newPos = maxYPos if ( newPos > minYPos ) newPos = minYPos @@ -390,69 +567,65 @@ void function SliderBarUpdate() Hud_SetPos( sliderPanel , 2, newPos ) Hud_SetPos( movementCapture , 2, newPos ) - file.scrollOffset = -int( ( (newPos - minYPos) / useableSpace ) * ( file.modsArrayFiltered.len() - BUTTONS_PER_PAGE) ) + file.scrollOffset = -int( ( (newPos - minYPos) / useableSpace ) * ( file.mods.len() - PANELS_LEN) ) UpdateList() } -void function UpdateListSliderHeight() +void function UpdateListSliderPosition() { var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) - - float mods = float ( file.modsArrayFiltered.len() ) - float maxHeight = 604.0 * (GetScreenSize()[1] / 1080.0) - float minHeight = 80.0 * (GetScreenSize()[1] / 1080.0) + float mods = float ( file.mods.len() ) - float height = maxHeight * ( float( BUTTONS_PER_PAGE ) / mods ) + float minYPos = -40.0 * (GetScreenSize()[1] / 1080.0) + float useableSpace = (604.0 * (GetScreenSize()[1] / 1080.0) - Hud_GetHeight( sliderPanel )) - if ( height > maxHeight ) height = maxHeight - if ( height < minHeight ) height = minHeight + float jump = minYPos - (useableSpace / ( mods - float( PANELS_LEN ) ) * file.scrollOffset) - Hud_SetHeight( sliderButton , height ) - Hud_SetHeight( sliderPanel , height ) - Hud_SetHeight( movementCapture , height ) -} + if ( jump > minYPos ) jump = minYPos + Hud_SetPos( sliderButton , 2, jump ) + Hud_SetPos( sliderPanel , 2, jump ) + Hud_SetPos( movementCapture , 2, jump ) +} -void function UpdateListSliderPosition() +void function UpdateListSliderHeight() { var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) - - float mods = float ( file.modsArrayFiltered.len() ) - float minYPos = -40.0 * (GetScreenSize()[1] / 1080.0) - float useableSpace = (604.0 * (GetScreenSize()[1] / 1080.0) - Hud_GetHeight( sliderPanel )) + float mods = float ( file.mods.len() ) - float jump = minYPos - (useableSpace / ( mods - float( BUTTONS_PER_PAGE ) ) * file.scrollOffset) + float maxHeight = 604.0 * (GetScreenSize()[1] / 1080.0) + float minHeight = 80.0 * (GetScreenSize()[1] / 1080.0) - //jump = jump * (GetScreenSize()[1] / 1080.0) + float height = maxHeight * ( float( PANELS_LEN ) / mods ) - if ( jump > minYPos ) jump = minYPos + if ( height > maxHeight ) height = maxHeight + if ( height < minHeight ) height = minHeight - Hud_SetPos( sliderButton , 2, jump ) - Hud_SetPos( sliderPanel , 2, jump ) - Hud_SetPos( movementCapture , 2, jump ) + Hud_SetHeight( sliderButton , height ) + Hud_SetHeight( sliderPanel , height ) + Hud_SetHeight( movementCapture , height ) } -void function OnDownArrowSelected( var button ) +void function OnScrollDown( var button ) { - if ( file.modsArrayFiltered.len() <= BUTTONS_PER_PAGE ) return - file.scrollOffset += 1 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.modsArrayFiltered.len()) { - file.scrollOffset = file.modsArrayFiltered.len() - BUTTONS_PER_PAGE + if ( file.mods.len() <= PANELS_LEN ) return + file.scrollOffset += 5 + if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + file.scrollOffset = file.mods.len() - PANELS_LEN } UpdateList() UpdateListSliderPosition() } - -void function OnUpArrowSelected( var button ) +void function OnScrollUp( var button ) { - file.scrollOffset -= 1 + file.scrollOffset -= 5 if (file.scrollOffset < 0) { file.scrollOffset = 0 } @@ -460,23 +633,49 @@ void function OnUpArrowSelected( var button ) UpdateListSliderPosition() } -void function OnScrollDown( var button ) +void function OnDownArrowSelected( var button ) { - if ( file.modsArrayFiltered.len() <= BUTTONS_PER_PAGE ) return - file.scrollOffset += 5 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.modsArrayFiltered.len()) { - file.scrollOffset = file.modsArrayFiltered.len() - BUTTONS_PER_PAGE + if ( file.mods.len() <= PANELS_LEN ) return + file.scrollOffset += 1 + if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + file.scrollOffset = file.mods.len() - PANELS_LEN } UpdateList() UpdateListSliderPosition() } -void function OnScrollUp( var button ) +void function OnUpArrowSelected( var button ) { - file.scrollOffset -= 5 + file.scrollOffset -= 1 if (file.scrollOffset < 0) { file.scrollOffset = 0 } UpdateList() UpdateListSliderPosition() +} + +// + +// Static arrays don't have the .find method for some reason +bool function StaticFind( string mod ) +{ + foreach( string smod in CORE_MODS ) + if ( mod == smod ) + return true + return false +} + +void function ReloadMods() +{ + NSReloadMods() + ClientCommand( "reload_localization" ) + ClientCommand( "loadPlaylists" ) + + bool svCheatsOriginal = GetConVarBool( "sv_cheats" ) + SetConVarBool( "sv_cheats", true ) + ClientCommand( "weapon_reparse" ) // weapon_reparse only works if a server is running and sv_cheats is 1, gotta figure this out eventually + SetConVarBool( "sv_cheats", svCheatsOriginal ) + + // note: the logic for this seems really odd, unsure why it doesn't seem to update, since the same code seems to get run irregardless of whether we've read weapon data before + ClientCommand( "uiscript_reset" ) } \ No newline at end of file -- cgit v1.2.3 From 7f819ca53f7dea47e7d51f43329a911d4327cecf Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sun, 25 Sep 2022 07:48:07 +0800 Subject: Refuse noclipping while player is setparented (#487) * Update _northstar_cheatcommands.nut * Cleaner Check * Apply suggestions --- .../mod/scripts/vscripts/_northstar_cheatcommands.nut | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_northstar_cheatcommands.nut b/Northstar.CustomServers/mod/scripts/vscripts/_northstar_cheatcommands.nut index c79265ac..af3dfea5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_northstar_cheatcommands.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_northstar_cheatcommands.nut @@ -14,6 +14,11 @@ bool function ClientCommandCallbackToggleNoclip( entity player, array ar { if ( !GetConVarBool( "sv_cheats" ) ) return true + if( player.GetParent() ) // change movetype while setparented will crash the server + { + print( player + " failed noclipping because the entity is parented" ) + return true + } print( player + " TOGGLED NOCLIP" ) -- cgit v1.2.3 From 6c2b576ce8379163d812f364079f761734815917 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Mon, 26 Sep 2022 13:31:57 +0200 Subject: Add some missing translations (#508) * feat: add missing spanish entries * feat: add missing french entry * feat: add missing chinese entry * feat: add missing italian entries * feat: add missing german entries --- .../northstar_client_localisation_french.txt | 2 + .../northstar_client_localisation_german.txt | 30 ++++++++++++++ .../northstar_client_localisation_italian.txt | 48 ++++++++++++++++++++++ .../northstar_client_localisation_mspanish.txt | 2 + .../northstar_client_localisation_spanish.txt | 2 + .../northstar_client_localisation_tchinese.txt | 2 + 6 files changed, 86 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 0d4786a0..276698a0 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -82,6 +82,8 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "cp_amped_capture_points" "Points de capture améliorés" "coliseum_loadouts_enabled" "Equipements du Colisée" + "aitdm_archer_grunts" "Soldats (Archer)" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Bac à sable" "PL_sbox_lobby" "Lobby: Bac à sable" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 0eded5bc..9077fac0 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -8,6 +8,9 @@ "MENU_LAUNCH_NORTHSTAR" "Northstar starten" "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Mods neu laden" + "WARNING" "Warnung" + "CORE_MOD_DISABLE_WARNING" "Das Deaktivieren von essentiellen Mods kann die Funktion deines Clients beeinträchtigen!" + "DISABLE" "Deaktiviere" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Danke, dass du Northstar installiert hast!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Damit Northstar funktionieren kann, muss es mithilfe des Northstar Masterservers authentifizieren. Dies setzt ein Weitergeben deines Origin Tokens an den Masterserver voraus, er wird nicht gespeichert oder für andere Zwecke verwendet. @@ -16,6 +19,9 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "AUTHENTICATION_AGREEMENT" "Authentifizierungs-Einwilligung" "AUTHENTICATION_AGREEMENT_RESTART" "Ein Neustart ist notwendig, um diese Änderung zu übernehmen" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Authentifizierung mit Master Server" + "AUTHENTICATIONAGREEMENT_NO" "Du hast dich gegen die Authentifizierung mit Northstar entschieden. Du kannst die Authentifizierungs-Einwilligung im Modmenü ansehen." + "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Keine Server gefunden" "NS_SERVERBROWSER_UNKNOWNMODE" "Unbekannter Modus" @@ -75,6 +81,8 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "cp_amped_capture_points" "Verstärkte Hardpoints" "coliseum_loadouts_enabled" "Coliseum Loadouts" + "aitdm_archer_grunts" "Archer Frontsoldaten" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" @@ -88,6 +96,8 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "PL_gg_hint" "Erhalte einen Kill mit jeder Waffe um zu siegen." "PL_gg_abbr" "GG" "GAMEMODE_GG" "Gun Game" + "gg_kill_reward" "Killprozentbelohnung" + "gg_execution_reward" "Exekutierungsprozentbelohnung" "PL_tt" "Titan Tag" "PL_tt_lobby" "Titan Tag Lobby" @@ -113,6 +123,17 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "HIDDEN_KILL_SURVIVORS" "Töte alle Überlebenden" "HIDDEN_FIRST_HIDDEN" "%s1 ist the The Hidden." + "PL_sns" "Stock und Stein" + "PL_sns_lobby" "Stock und Stein Lobby" + "PL_sns_desc" "Frei für Alle. Erziele Kills mit Impulsklingen und Exekutierungen um die Punktzahl des Gegners zurückzusetzen" + "PL_sns_abbr" "SuS" + "GAMEMODE_SNS" "Stock und Stein" + "sns_wme_kill_value" "Wingman Elite Killwert" + "sns_softball_kill_value" "Softball Killwert" + "sns_reset_kill_value" "Pulseklinge/Exekutierung Killwert" + "sns_melee_kill_value" "Nahkampfkill Killwert" + "sns_softball_enabled" "Softball aktiviert" + "PL_inf" "Infektion" "PL_inf_lobby" "Infektion-Lobby" "PL_inf_desc" "Überlebe die Infektion. Überlebende werden nach dem Tod infiziert." @@ -266,6 +287,15 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "INGAME_PLAYERS" "Spieler: ^6BA6C400%s1" "TOTAL_SERVERS" "Server: ^C46C6C00%s1" + // Mods menu + "SHOW" "Anzeigen" + "SHOW_ALL" "Alle anzeigen" + "SHOW_ONLY_ENABLED" "Nur aktivierte" + "SHOW_ONLY_DISABLED" "Nur deaktivierte" + + // Maps menu + "HIDE_LOCKED" "Verstecke gesperrte" + // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index b8253ad9..b0bc348f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -6,6 +6,9 @@ "MENU_LAUNCH_NORTHSTAR" "Avvia Northstar" "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Ricarica Mods" + "WARNING", "Attenzione" + "CORE_MOD_DISABLE_WARNING", "Disattivare Mods Principali può rompere il tuo Client!" + "DISABLE", "Disattiva" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Grazie per aver installato Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Affinché Northstar funzioni, è necessario autenticarsi utilizzando il server principale di Northstar. Ciò richiederà l'invio del tuo token di Origin al server principale, non verrà archiviato o utilizzato per altri scopi. @@ -14,8 +17,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT_RESTART" "Dovrai riavviare Titanfall 2 affinché questa scelta abbia effetto." + "DIALOG_AUTHENTICATING_MASTERSERVER", "Autenticazione Sul Master Server in corso" + "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu Mods" + "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Nessun server trovato" + "NS_SERVERBROWSER_UNKNOWNMODE", "Modalità Sconosciuta" "NS_SERVERBROWSER_WAITINGFORSERVERS" "In attesa dei server..." "NS_SERVERBROWSER_CONNECTIONFAILED" "Connessione fallita!" "REFRESH_SERVERS" "Aggiorna" @@ -46,6 +53,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "roundscorelimit" "Limite Punteggio (per round)" "timelimit" "Limite di Tempo" "roundtimelimit" "Limite di Tempo (per round)" + "respawnprotection", "Tempo Protezione di Respawn" "pilot_health_multiplier" "Moltiplicatore di Salute" "respawn_delay" "Tempo di Respawn" @@ -72,6 +80,8 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "cp_amped_capture_points" "Hardpoints Amplificati" "coliseum_loadouts_enabled" "Equipaggiamento Colosseo" + "aitdm_archer_grunts", "Schagniozzi Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" @@ -85,6 +95,10 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_gg_hint" "Ottieni una nuova arma ogni uccisione." "PL_gg_abbr" "GG" "GAMEMODE_GG" "Gioco d'Armi" + "aitdm_archer_grunts", "Schagniozzi Archer" + "gg_kill_reward", "Punteggio Riconpensa Uccisione" + "gg_assist_reward", "Punteggio Ricompensa Assist" + "gg_execution_reward", "Punteggio Ricompensa Esecuzione" "PL_tt" "Titan Tag" "PL_tt_lobby" "Lobby: Titan Tag" @@ -110,6 +124,24 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDDEN_KILL_SURVIVORS" "Uccidi tutti i giocatori." "HIDDEN_FIRST_HIDDEN" "%s1 è il Cacciatore." + "PL_sns", "Sticks and Stones" + "PL_sns_lobby", "Sticks and Stones Lobby" + "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e Esecuzioni per Resettare il Puntegio Nemico" + "PL_sns_abbr", "SNS" + "GAMEMODE_SNS", "Sticks and Stones" + "SCOREBOARD_BANKRUPTS", "Uccisioni Bancarotta" + "SNS_LEADER_BANKRUPT", "Leader Punteggio andato in Bancarotta!" + "SNS_LEADER_BANKRUPT_SUB", "%s1 è stato Resettato da %s2" + "SNS_BANKRUPT", "Bancarotta!" + "SNS_BANKRUPT_SUB", "Il Tuo Punteggio è stato Resettato da %s1" + "sns_wme_kill_value", "Valore Uccisione Wingman d'Elite" + "sns_softball_kill_value", "Valore Uccisione Softball" + "sns_offhand_kill_value", "Valore Uccisione Improvvisa" + "sns_reset_kill_value", "Valore Uccisione Pulse/Esecuzione" + "sns_melee_kill_value", "Valore Uccisione Corpo a Corpo" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill", "Reset Cooldown Uccisione" + "sns_softball_enabled", "Softball Attivato" + "PL_inf" "Infetto" "PL_inf_lobby" "Lobby: Infetto" "PL_inf_desc" "Sopravvivi all'infezione. I sopravvissuti vengono infettati quando uccisi." @@ -124,6 +156,13 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INFECTION_YOU_ARE_LAST_SURVIVOR" "Sei l'Ultimo Sopravvissuto!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sopravvivi." + "PL_tffa", "Titan Free for All" + "PL_tffa_lobby", "Titan Free for All Lobby" + "PL_tffa_desc", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." + "PL_tffa_hint", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." + "PL_tffa_abbr", "TFFA" + "GAMEMODE_TFFA", "Titan Free for All" + "PL_hs" "Nascondino" "PL_hs_lobby" "Lobby: Nascondino" "PL_hs_desc" "Nasconditi oppure trova gli avversari." @@ -257,6 +296,15 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INGAME_PLAYERS" "Players: ^6BA6C400%s1" "TOTAL_SERVERS" "Server: ^C46C6C00%s1" + // Mods menu + "SHOW", "Mostra" + "SHOW_ALL", "Mostra Tutti" + "SHOW_ONLY_ENABLED", "Mostra solo Attivi" + "SHOW_ONLY_DISABLED", "Mostra solo Inattivi" + + // Maps menu + "HIDE_LOCKED" "Nascondi bloccati" + // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index ea62415e..208747f9 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -82,6 +82,8 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "cp_amped_capture_points" "Fortalezas amplificadas" "coliseum_loadouts_enabled" "Equipamientos de coliseo" + "aitdm_archer_grunts" "Soldado Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Lobby sandbox" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 8d2df53b..fa732b63 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -82,6 +82,8 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "cp_amped_capture_points" "Fortines cargados" "coliseum_loadouts_enabled" "Arsenales de coliseo" + "aitdm_archer_grunts" "Soldado Archer" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Vestíbulo de Sandbox" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 5e6721a9..276a192d 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -82,6 +82,8 @@ "cp_amped_capture_points" "強化據點" "coliseum_loadouts_enabled" "競技場裝備" + "aitdm_archer_grunts" "射手飛彈步兵" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "沙盒" "PL_sbox_lobby" "沙盒大廳" -- cgit v1.2.3 From 189a7cd05caa65cfde716e2c8e39da0635735cb2 Mon Sep 17 00:00:00 2001 From: CYakigasi <65476384+castella-cake@users.noreply.github.com> Date: Tue, 27 Sep 2022 08:39:57 +0900 Subject: Update Japanese Translation (#499) Translated the untranslated text (game modes, UI, error messages, etc.) --- .../northstar_client_localisation_japanese.txt | 105 +++++++++++++++++++-- 1 file changed, 96 insertions(+), 9 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index 08772933..b35c9fb8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -3,9 +3,15 @@ "Language" "japanese" "Tokens" { + // ファイルはUTF-16 LEでエンコードしてください、メモ帳なら"名前を付けて保存"から + "MENU_LAUNCH_NORTHSTAR" "Northstarを起動" "MENU_TITLE_MODS" "Modの管理" "RELOAD_MODS" "Modをリロード" + "WARNING" "警告" + "CORE_MOD_DISABLE_WARNING" "コアModを無効化すると、クライアントが破損する可能性があります!" + // 多分ボタンに使われると思うので「無効化」としたが、今後変更する必要があるかもしれない + "DISABLE" "無効化" "MENU_MAIN_AUTHENTICATING" "認証中..." "MENU_MAIN_CONNECTING" "ローカルサーバーへの接続" @@ -17,8 +23,12 @@ "AUTHENTICATION_AGREEMENT" "認証への同意" "AUTHENTICATION_AGREEMENT_RESTART" "変更を適用するには、一度Titanfall 2を再起動する必要があります。" + "DIALOG_AUTHENTICATING_MASTERSERVER" "マスターサーバーへ認証中..." + "AUTHENTICATIONAGREEMENT_NO" "Northstarの認証を行わないことを選択しました。Modメニューから再度このダイアログを開くことができます。" + "MENU_TITLE_SERVER_BROWSER" "サーバーブラウザー" "NS_SERVERBROWSER_NOSERVERS" "サーバーが見つかりませんでした。" + "NS_SERVERBROWSER_UNKNOWNMODE" "不明なモード" "NS_SERVERBROWSER_WAITINGFORSERVERS" "サーバーを待っています..." "NS_SERVERBROWSER_CONNECTIONFAILED" "接続に失敗しました!" // 要議論 @@ -60,6 +70,7 @@ // 要議論: "時間制限"のままか、"マッチ時間"、"タイム上限"、それ以外への差し替え "timelimit" "時間制限" "roundtimelimit" "時間制限 (ラウンドベース)" + "respawnprotection" "リスポーン保護時間" "pilot_health_multiplier" "ヘルス倍率" // 要議論: "リスポーン遅延" のままか、"リスポーンまでの時間"、それ以外への差し替え @@ -89,29 +100,76 @@ "cp_amped_capture_points" "拠点増幅" "coliseum_loadouts_enabled" "コロシアムロードアウト" + // そのまま「グラント」よりも、Respawn翻訳で使われている + //「ミニオン」のほうが伝わりやすいかもしれないのでこっちにする + // 「アーチャーを持ったミニオン」とかだと流石によくなさそうなのでとりあえずそのまま日本語に。 + "aitdm_archer_grunts" "アーチャー持ちミニオン" + // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "サンドボックス" - "PL_sbox_lobby" "サンドボックスロビー" + "PL_sbox_lobby" "サンドボックス ロビー" "PL_sbox_desc" "サンドボックス" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" "PL_gg" "ガン・ゲーム" - "PL_gg_lobby" "ガン・ゲームロビー" + "PL_gg_lobby" "ガン・ゲーム ロビー" "PL_gg_desc" "全ての銃でキルを取って勝利しろ。" "PL_gg_hint" "全ての銃でキルを取って勝利しろ。" "PL_gg_abbr" "GG" "GAMEMODE_GG" "ガン・ゲーム" + "gg_kill_reward" "キルリワード倍率" + "gg_assist_reward" "アシストリワード倍率" + "gg_execution_reward" "処刑リワード倍率" "PL_tt" "タイタン・タグ" - "PL_tt_lobby" "タイタン・タグロビー" + "PL_tt_lobby" "タイタン・タグ ロビー" "PL_tt_desc" "タイタンとしてポイントを稼げ。敵のタイタンを破壊し自分のタイタンを確保しろ。" "PL_tt_hint" "タイタンとしてポイントを稼げ。敵のタイタンを破壊し自分のタイタンを確保しろ。" "PL_tt_abbr" "TT" "GAMEMODE_TT" "タイタン・タグ" + "PL_chamber" "ワン・イン・ザ・チャンバー" + "PL_chamber_lobby" "ワン・イン・ザ・チャンバー ロビー" + "PL_chamber_desc" "ワンショット・ワンキル。敵をキルして、弾倉に新たな弾丸を込めろ。" + "PL_chamber_hint" "ワンショット・ワンキル。敵をキルして、弾倉に新たな弾丸を込めろ。" + "PL_chamber_abbr" "CHAMBER" + "GAMEMODE_CHAMBER" "ワン・イン・ザ・チャンバー" + + "PL_hidden" "ザ・ヒデゥン" + "PL_hidden_lobby" "ザ・ヒデゥン ロビー" + "PL_hidden_desc" "透明化しているプレイヤーが一人潜んでいる。ヒデゥンを撃破せよ。" + "PL_hidden_hint" "透明化しているプレイヤーが一人潜んでいる。ヒデゥンを撃破せよ。" + "PL_hidden_abbr" "HIDDEN" + "GAMEMODE_HIDDEN" "ザ・ヒデゥン" + "HIDDEN_YOU_ARE_HIDDEN" "ヒデゥンになった!" + "HIDDEN_KILL_SURVIVORS" "すべてのサバイバーを撃破せよ。" + "HIDDEN_FIRST_HIDDEN" "%s1 はヒデゥンになった。" + + "PL_sns" "スティック・アンド・ストーン" + "PL_sns_lobby" "スティック・アンド・ストーン ロビー" + "PL_sns_desc" "フリー・フォー・オール。パルスブレードか、処刑を使用して敵のスコアをリセットできる。" + "PL_sns_abbr" "SNS" + "GAMEMODE_SNS" "スティック・アンド・ストーン" + // 要変更: 破産以外の言葉に置き換える + "SCOREBOARD_BANKRUPTS" "破産キル" + "SNS_LEADER_BANKRUPT" "スコアリーダーが破産した!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 は %s2 にスコアをリセットされた" + "SNS_BANKRUPT" "破産!" + "SNS_BANKRUPT_SUB" "あなたのスコアは %s1 によってリセットされた" + // 要議論: value -> "数"?それとも"値"? + "sns_wme_kill_value" "ウィングマン・エリートキル数" + "sns_softball_kill_value" "ソフトボールキル数" + "sns_offhand_kill_value" "オフハンドキル数" + "sns_reset_kill_value" "パルスブレード/処刑キル数" + "sns_melee_kill_value" "格闘キル数" + // 要変更: 「キルリセットまでのクールダウンを有効化するかどうか」なのか、「キルによってクールダウンをリセットするかどうか」なのか。 + // ひとまずそのまま日本語に直したが、わかりにくいので変更するべき。 + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "キルクールダウンリセット" + "sns_softball_enabled" "ソフトボールを有効化" + "PL_inf" "インフェクション" - "PL_inf_lobby" "インフェクションロビー" + "PL_inf_lobby" "インフェクション ロビー" "PL_inf_desc" "生き残りは死亡するとインフェクターになる。" "PL_inf_hint" "生き残りは死亡するとインフェクターになる。" "PL_inf_abbr" "INF" @@ -125,8 +183,15 @@ "INFECTION_YOU_ARE_LAST_SURVIVOR" "お前が最後の生き残りだ!" "INFECTION_SURVIVE_LAST_SURVIVOR" "生きろ" + "PL_tffa" "タイタン フリー・フォー・オール" + "PL_tffa_lobby" "タイタン フリー・フォー・オール ロビー" + "PL_tffa_desc" "すべてのパイロットはタイタンに搭乗している。すべての敵タイタンを撃破せよ。" + "PL_tffa_hint" "すべてのパイロットはタイタンに搭乗している。すべての敵タイタンを撃破せよ。" + "PL_tffa_abbr" "TFFA" + "GAMEMODE_TFFA" "タイタン フリー・フォー・オール" + "PL_hs" "ハイド・アンド・シーク" - "PL_hs_lobby" "ハイド・アンド・シークロビー" + "PL_hs_lobby" "ハイド・アンド・シーク ロビー" "PL_hs_desc" "ハイダーは隠れ、シーカーはハイダーを探せ!" "PL_hs_hint" "ハイダーは隠れ、シーカーはハイダーを探せ!" "PL_hs_abbr" "HS" @@ -145,13 +210,13 @@ "GAMEMODE_fw" "フロンティア戦争" "PL_fw" "フロンティア戦争" - "PL_fw_lobby" "フロンティア戦争ロビー" + "PL_fw_lobby" "フロンティア戦争 ロビー" "PL_fw_desc" "敵のハーベスターを破壊し、自分のを守れ!" "PL_fw_abbr" "FW" "GAMEMODE_kr" "強化キルレース" "PL_kr" "強化キルレース" - "PL_kr_lobby" "強化キルレースロビー" + "PL_kr_lobby" "強化キルレース ロビー" "PL_kr_desc" "旗を拾い、キルレースを開始しろ。キルでポイントを上げ、キルレースの時間を延ばせ。最高ポイント記録が一番高い者が勝利する" "PL_kr_hint" "旗を拾い、キルレースを開始しろ。キルでポイントを上げ、キルレースの時間を延ばせ。最高ポイント記録が一番高い者が勝利する" "PL_kr_abbr" "KR" @@ -167,7 +232,7 @@ "GAMEMODE_fastball" "ファストボール" "PL_fastball" "ファストボール" - "PL_fastball_lobby" "ファストボールロビー" + "PL_fastball_lobby" "ファストボール ロビー" "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる" "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる" "PL_fastball_abbr" "FB" @@ -182,6 +247,7 @@ "MODE_SETTING_CATEGORY_BLEEDOUT" "パイロットのダウン" "custom_air_accel_pilot" "空中加速度" + "no_pilot_collision" "パイロット同士の当たり判定" "promode_enable" "Proモードの武器" "fp_embark_enabled" "搭乗と処刑の一人称視点" "classic_rodeo" "クラシックロデオ" @@ -257,10 +323,31 @@ "CONNECTING" "接続中..." "INGAME_PLAYERS" "プレイヤー数: ^6BA6C400%s1" "TOTAL_SERVERS" "サーバー数: ^C46C6C00%s1" - // Translation done by Zetryox and CYakigasi + + // Mods menu + "SHOW" "表示" + "SHOW_ALL" "全て" + "SHOW_ONLY_ENABLED" "有効のみ" + "SHOW_ONLY_DISABLED" "無効のみ" + + // Maps menu + "HIDE_LOCKED" "ロック中を隠す" // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + + "NO_GAMESERVER_RESPONSE" "ゲームサーバーに接続できません\n(Couldn't reach game server)" + "BAD_GAMESERVER_RESPONSE" "ゲームサーバーが不明なレスポンスを返しました\n(Game server gave an invalid response)" + "UNAUTHORIZED_GAMESERVER" "ゲームサーバーにそのリクエストを作成する許可がありません\n(Game server is not authorized to make that request)" + "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\nStryder couldn't confirm that this account owns Titanfall 2" + "UNAUTHORIZED_PWD" "パスワードが間違っています\n(Wrong password)" + "STRYDER_RESPONSE" "Stryderからのレスポンスの処理に失敗しました\n(Couldn't parse stryder response)" + "PLAYER_NOT_FOUND" "プレイヤーのアカウントが見つかりません\n(Couldn't find player account)" + "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです\n(Invalid or expired masterserver token)" + "JSON_PARSE_ERROR" "JSONレスポンスの処理に失敗しました\n(Error parsing json response)" + "UNSUPPORTED_VERSION" "現在使用しているバージョンはサポートされていません\n(The version you are using is no longer supported)" + + // Translation done by Zetryox and CYakigasi } } -- cgit v1.2.3 From 5ac11bd422a7c65b167633197642106755fd1e68 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Wed, 28 Sep 2022 04:12:04 +0800 Subject: Fixed Phase Rewind not Behaving Well (#505) * Fixed Phase Rewind not Behaving Well Phase Rewind will now have a longer distance and mostly won't stuck as It be like in vanilla Map Hack won't show sonar pulse to other players anymore, also be like in vanilla * No need to make last node Specific * Compared vanilla and nearfed vanilla phase rewind don't works so well, I found this one is better * Apply suggestions from code review * little fix for my next pr * Make rewind smoother --- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 72 ++++++++++++++++++---- 1 file changed, 61 insertions(+), 11 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 056f0313..0d189017 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -15,8 +15,10 @@ global function InitBurnMeterPersistentData const float PHASE_REWIND_LENGTH = 2.0 // taken from wraith portal in apex, assuming it's the same as tf2's -const float PHASE_REWIND_PATH_SNAPSHOT_INTERVAL = 0.1 -const int PHASE_REWIND_MAX_SNAPSHOTS = int( PHASE_REWIND_LENGTH / PHASE_REWIND_PATH_SNAPSHOT_INTERVAL ) +// 0.1 can be too fast for ttf2 scripts +const float PHASE_REWIND_PATH_SNAPSHOT_INTERVAL = 0.2 // mainly controlled by this const, the higher the rewind path will be longer, assuming this one is like vanilla's +const int PHASE_REWIND_MAX_SNAPSHOTS = int( PHASE_REWIND_LENGTH / PHASE_REWIND_PATH_SNAPSHOT_INTERVAL ) - 1 +const int PHASE_REWIND_DATA_MAX_POSITIONS = int( PHASE_REWIND_LENGTH * 10 ) + 1 // hardcoded but maybe good const float AMPED_WEAPONS_LENGTH = 30.0 @@ -221,18 +223,18 @@ void function PhaseRewindLifetime( entity player ) { PhaseRewindData rewindData rewindData.origin = player.GetOrigin() - rewindData.angles = player.GetAngles() + rewindData.angles = < 0, player.EyeAngles().y, 0 > rewindData.velocity = player.GetVelocity() rewindData.wasInContextAction = player.ContextAction_IsActive() rewindData.wasCrouched = player.IsCrouched() - if ( player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.len() >= PHASE_REWIND_MAX_SNAPSHOTS ) + if ( player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.len() >= PHASE_REWIND_DATA_MAX_POSITIONS ) { // shift all snapshots left - for ( int i = 0; i < PHASE_REWIND_MAX_SNAPSHOTS - 1; i++ ) + for ( int i = 0; i < PHASE_REWIND_DATA_MAX_POSITIONS - 1; i++ ) player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ i ] = player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ i + 1 ] - player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ PHASE_REWIND_MAX_SNAPSHOTS - 1 ] = rewindData + player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions[ PHASE_REWIND_DATA_MAX_POSITIONS - 1 ] = rewindData } else player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions.append( rewindData ) @@ -407,6 +409,10 @@ void function PlayerUsesMaphackBurncardThreaded( entity player ) entities.extend( GetPlayerDecoyArray() ) IncrementSonarPerTeam( playerTeam ) + + if ( IsAlive( player ) ) // only owner can see the pulse + Remote_CallFunction_Replay( player, "ServerCallback_SonarPulseFromPosition", player.GetOrigin().x, player.GetOrigin().y, player.GetOrigin().z, SONAR_GRENADE_RADIUS ) + foreach ( entity ent in entities ) { if ( !IsValid( ent ) ) // Not sure why we can get invalid entities at this point @@ -414,9 +420,6 @@ void function PlayerUsesMaphackBurncardThreaded( entity player ) if ( ent.IsPlayer() ) { - if ( IsAlive( player ) ) - Remote_CallFunction_Replay( ent, "ServerCallback_SonarPulseFromPosition", player.GetOrigin().x, player.GetOrigin().y, player.GetOrigin().z, SONAR_GRENADE_RADIUS ) - // Map Hack also gives radar on enemies for longer than the sonar duration. if ( ent.GetTeam() == playerTeam ) thread ScanMinimap( ent, false, MAPHACK_PULSE_DELAY - 0.2 ) @@ -470,18 +473,65 @@ void function PlayerUsesPhaseRewindBurncardThreaded( entity player ) array positions = clone player.p.burnCardPhaseRewindStruct.phaseRetreatSavedPositions + array tempArray + int segment = positions.len() / PHASE_REWIND_MAX_SNAPSHOTS + for( int i = 0; i < PHASE_REWIND_MAX_SNAPSHOTS; i++ ) + { + if( positions.len() <= segment * i ) + break + tempArray.append( positions[ segment * i ] ) + } + positions = tempArray + + vector startOrigin = player.GetOrigin() ViewConeZero( player ) player.HolsterWeapon() player.SetPredictionEnabled( false ) PhaseShift( player, 0.0, positions.len() * PHASE_REWIND_PATH_SNAPSHOT_INTERVAL * 1.5 ) + EmitSoundOnEntityOnlyToPlayer( player, player, "pilot_phaserewind_1p" ) + EmitSoundOnEntityExceptToPlayer( player, player, "pilot_phaserewind_3p" ) for ( int i = positions.len() - 1; i > -1; i-- ) { - mover.NonPhysicsMoveTo( positions[ i ].origin, PHASE_REWIND_PATH_SNAPSHOT_INTERVAL, 0, 0 ) - mover.NonPhysicsRotateTo( positions[ i ].angles, PHASE_REWIND_PATH_SNAPSHOT_INTERVAL, 0, 0 ) + // should looks better? + float moveTime = PHASE_REWIND_PATH_SNAPSHOT_INTERVAL + 0.1 + player.SetVelocity( -positions[ i ].velocity ) + mover.NonPhysicsMoveTo( positions[ i ].origin, moveTime, 0, 0 ) + mover.NonPhysicsRotateTo( positions[ i ].angles, moveTime, 0, 0 ) wait PHASE_REWIND_PATH_SNAPSHOT_INTERVAL } player.SetVelocity( <0, 0, 0> ) + if( positions[0].wasCrouched ) + player.SetOrigin( player.GetOrigin() + < 0, 0, 20 > ) + + // fix position after rewind + PutPhaseRewindedPlayerInSafeSpot( player, 1 ) +} + +void function PutPhaseRewindedPlayerInSafeSpot( entity player, int severity ) +{ + vector baseOrigin = player.GetOrigin() + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y + severity, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y - severity, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x + severity, baseOrigin.y, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x - severity, baseOrigin.y, baseOrigin.z >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y, baseOrigin.z + severity >, baseOrigin ) ) + return + + if ( PutEntityInSafeSpot( player, player, null, < baseOrigin.x, baseOrigin.y, baseOrigin.z - severity >, baseOrigin ) ) + return + + return PutPhaseRewindedPlayerInSafeSpot( player, severity + 5 ) + } void function PlayerUsesNukeTitanBurncard( entity player ) -- cgit v1.2.3 From bcb6b30db6b051776e2585c3d162856b4e9481b3 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Fri, 7 Oct 2022 21:34:03 -0400 Subject: Fix crash when final killcam entity becomes invalid (#516) --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 4108d0d9..6cde4655 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -387,11 +387,14 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLe player.SetPredictionEnabled( false ) // prediction fucks with replays entity attacker = file.roundWinningKillReplayAttacker - player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) - player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() ) - player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) - player.SetViewIndex( attacker.GetIndexForEntity() ) - player.SetIsReplayRoundWinning( true ) + if ( IsValid( attacker ) ) + { + player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) + player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() ) + player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) + player.SetViewIndex( attacker.GetIndexForEntity() ) + player.SetIsReplayRoundWinning( true ) + } if ( replayLength >= ROUND_WINNING_KILL_REPLAY_LENGTH_OF_REPLAY - 0.5 ) // only do fade if close to full length replay { -- cgit v1.2.3 From 5edc1b0c98aed20cbd3b3bc429db9c5d17939945 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:22:29 +0800 Subject: Added ReaperFall Marks and Reapers' Outlines (#468) * Added ReaperFall Marks and Reapers' Outlines Added red mark for reaperfall points and outline after landing * Fixed RoundEndCleanUp Crash * Better Outline Function --- .../scripts/vscripts/gamemodes/_ai_gamemodes.gnut | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut index d6d578bb..0fad768c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut @@ -111,7 +111,16 @@ void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string aiSettings = "", void functionref( entity reaper ) reaperHandler = null ) { + thread Reaper_Spawnpoint( pos, team, 11.2 ) + + wait 10 + // spawn reapers right before it warpfalls, or round_end clean up will crash the game entity reaper = CreateSuperSpectre( team, pos, rot ) + // reaper highlight + Highlight_SetFriendlyHighlight( reaper, "sp_enemy_pilot" ) + reaper.Highlight_SetParam( 1, 0, < 3,3,3 > ) + Highlight_SetEnemyHighlight( reaper, "enemy_titan" ) + SetSpawnOption_Titanfall( reaper ) SetSpawnOption_Warpfall( reaper ) @@ -125,6 +134,38 @@ void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string thread reaperHandler( reaper ) } +// copied from cl_replacement_titan_hud.gnut +void function Reaper_Spawnpoint( vector origin, int team, float impactTime, bool hasFriendlyWarning = false ) +{ + array targetEffects = [] + vector surfaceNormal = < 0, 0, 1 > + + int index = GetParticleSystemIndex( $"P_ar_titan_droppoint" ) + + if( hasFriendlyWarning ) + { + entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) + SetTeam( effectFriendly, team ) + EffectSetControlPointVector( effectFriendly, 1, < 128,188,255 > ) + effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY + targetEffects.append( effectFriendly ) + } + + entity effectEnemy = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) + SetTeam( effectEnemy, team ) + EffectSetControlPointVector( effectEnemy, 1, < 255,99,0 > ) + effectEnemy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_ENEMY + targetEffects.append( effectEnemy ) + + wait impactTime + + foreach( entity targetEffect in targetEffects ) + { + if ( IsValid( targetEffect ) ) + EffectStop( targetEffect ) + } +} + // including aisettings stuff specifically for at bounty titans void function AiGameModes_SpawnTitan( vector pos, vector rot, int team, string setFile, string aiSettings = "", void functionref( entity titan ) titanHandler = null ) { -- cgit v1.2.3 From 1804b784eee053a1031a9f095955de88b0179e1e Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Sat, 8 Oct 2022 10:30:22 +0000 Subject: Modlist Hotfixes (#510) * fix mod list overflow * better offset validation --- .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 49 +++++++++++++--------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 01149bb0..329ea73f 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -166,6 +166,9 @@ void function OnModMenuClosed() void function OnModButtonFocused( var button ) { + if( int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) > file.mods.len() ) + return + file.currentButton = button file.lastMod = file.mods[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset - 1 ].mod string modName = file.lastMod.name @@ -209,7 +212,9 @@ void function OnModButtonPressed( var button ) SetControlBoxColor( Hud_GetChild( panel, "ControlBox" ), modName ) SetControlBarColor( modName ) SetModEnabledHelperImageAsset( Hud_GetChild( panel, "EnabledImage" ), modName ) - RefreshMods() + // RefreshMods() + UpdateListSliderPosition() + UpdateListSliderHeight() } } @@ -391,7 +396,7 @@ void function DisplayModPanels() { foreach ( int i, var panel in file.panels) { - if ( i >= file.mods.len() ) // don't try to show more panels than needed + if ( i >= file.mods.len() || file.scrollOffset + i >= file.mods.len() ) // don't try to show more panels than needed break panelContent c = file.mods[ file.scrollOffset + i ] @@ -534,6 +539,7 @@ void function UpdateMouseDeltaBuffer(int x, int y) mouseDeltaBuffer.deltaX = x mouseDeltaBuffer.deltaY = y + UpdateListSliderHeight() SliderBarUpdate() } @@ -616,45 +622,50 @@ void function OnScrollDown( var button ) { if ( file.mods.len() <= PANELS_LEN ) return file.scrollOffset += 5 - if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + if (file.scrollOffset + PANELS_LEN > file.mods.len()) file.scrollOffset = file.mods.len() - PANELS_LEN - } - UpdateList() - UpdateListSliderPosition() + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModListSlider" ) ) + ValidateScrollOffset() } void function OnScrollUp( var button ) { file.scrollOffset -= 5 - if (file.scrollOffset < 0) { + if (file.scrollOffset < 0) file.scrollOffset = 0 - } - UpdateList() - UpdateListSliderPosition() + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModListSlider" ) ) + ValidateScrollOffset() } void function OnDownArrowSelected( var button ) { if ( file.mods.len() <= PANELS_LEN ) return file.scrollOffset += 1 - if (file.scrollOffset + PANELS_LEN > file.mods.len()) { + if (file.scrollOffset + PANELS_LEN > file.mods.len()) file.scrollOffset = file.mods.len() - PANELS_LEN - } - UpdateList() - UpdateListSliderPosition() + ValidateScrollOffset() } void function OnUpArrowSelected( var button ) { file.scrollOffset -= 1 - if (file.scrollOffset < 0) { + if (file.scrollOffset < 0) file.scrollOffset = 0 - } - UpdateList() - UpdateListSliderPosition() + ValidateScrollOffset() } -// +void function ValidateScrollOffset() +{ + RefreshMods() + if( file.scrollOffset + 15 > file.mods.len() ) + file.scrollOffset = file.mods.len() - 15 + if( file.scrollOffset < 0 ) + file.scrollOffset = 0 + HideAllPanels() + DisplayModPanels() + UpdateListSliderHeight() + UpdateListSliderPosition() +} // Static arrays don't have the .find method for some reason bool function StaticFind( string mod ) -- cgit v1.2.3 From 118f9414326b0af067ee2a925d052c3ee17e4bef Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 17 Oct 2022 21:06:48 +0100 Subject: Use refactor's updated miscserverscript defs (#519) --- .../mod/scripts/vscripts/_menu_callbacks.gnut | 6 ++-- .../mod/scripts/vscripts/lobby/_private_lobby.gnut | 36 ++++++++++------------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut index 02be47a4..1092bf2d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut @@ -9,7 +9,7 @@ void function MenuCallbacks_Init() bool function ClientCommandCallback_LeaveMatch( entity player, array args ) { // note: this is imperfect if we have multiple people of the same uid on a server, but that's only a thing in testing - if ( NSIsPlayerIndexLocalPlayer( player.GetPlayerIndex() ) ) + if ( NSIsPlayerLocalPlayer( player ) ) { if ( GetConVarBool( "ns_should_return_to_lobby" ) && GetMapName() != "mp_lobby" ) { @@ -41,9 +41,11 @@ void function WritePersistenceAndLeaveForLocalPlayerOnly( entity player ) void function WritePersistenceAndLeave( entity player ) { + player.EndSignal( "OnDestroy" ) + // write player persistence before we leave, since leaving player might load local lobby before server writes persistence, so they won't get newest // not super essential, but a nice qol thing - NSEarlyWritePlayerIndexPersistenceForLeave( player.GetPlayerIndex() ) + NSEarlyWritePlayerPersistenceForLeave( player ) while ( NSIsWritingPlayerPersistence() ) WaitFrame() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut index c410869e..0a28031a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_private_lobby.gnut @@ -38,14 +38,14 @@ void function SetupPrivateMatchUIVarsWhenReady() bool function ClientCommandCallback_PrivateMatchLaunch( entity player, array args ) { if ( GetConVarBool( "ns_private_match_only_host_can_start" ) ) - if ( !NSIsPlayerIndexLocalPlayer( player.GetPlayerIndex() ) ) + if ( !NSIsPlayerLocalPlayer( player ) ) return true - PlayerChangedTheGame( player , " changed the game state." , args ) + LogPrivateMatchChange( player , " changed the game state." , args ) if ( file.startState == ePrivateMatchStartState.STARTING ) { - PlayerChangedTheGame( player , " canceled the game countdown." , args ) + LogPrivateMatchChange( player , " canceled the game countdown." , args ) // cancel start if we're already mid-countdown file.startState = ePrivateMatchStartState.READY @@ -54,7 +54,7 @@ bool function ClientCommandCallback_PrivateMatchLaunch( entity player, array a return true if ( GetConVarInt( "ns_private_match_only_host_can_change_settings" ) == 2 ) - if ( !NSIsPlayerIndexLocalPlayer( player.GetPlayerIndex() ) ) + if ( !NSIsPlayerLocalPlayer( player ) ) return true - PlayerChangedTheGame( player , " changed the map to " , args ) + LogPrivateMatchChange( player , " changed the map to " , args ) // todo: need to verify this value file.map = args[0] @@ -217,10 +217,10 @@ bool function ClientCommandCallback_PrivateMatchSetPlaylistVarOverride( entity p return true if ( GetConVarInt( "ns_private_match_only_host_can_change_settings" ) >= 1 ) - if ( !NSIsPlayerIndexLocalPlayer( player.GetPlayerIndex() ) ) + if ( !NSIsPlayerLocalPlayer( player ) ) return true - PlayerChangedTheGame( player , " override the setting " , args ) + LogPrivateMatchChange( player , " override the setting " , args ) bool found = false foreach ( string category in GetPrivateMatchSettingCategories() ) @@ -244,23 +244,21 @@ bool function ClientCommandCallback_PrivateMatchSetPlaylistVarOverride( entity p bool function ClientCommandCallback_ResetMatchSettingsToDefault( entity player, array args ) { if ( GetConVarInt( "ns_private_match_only_host_can_change_settings" ) >= 1 ) - if ( !NSIsPlayerIndexLocalPlayer( player.GetPlayerIndex() ) ) + if ( !NSIsPlayerLocalPlayer( player ) ) return true - PlayerChangedTheGame( player , " reset to default" , args ) + LogPrivateMatchChange( player , " reset to default" , args ) ClearPlaylistVarOverrides() return true } -void function PlayerChangedTheGame( entity player , string step , array args ){ - if( step.find( "mode" ) || step.find( "map" )){ +void function LogPrivateMatchChange( entity player , string step , array args ) +{ + if( step.find( "mode" ) || step.find( "map" ) ) print( player.GetPlayerName() + step + args[ 0 ] + ".---" + "UID:" +player.GetUID() ) - } - else if(step.find("setting")){ + else if ( step.find( "setting" ) ) print( player.GetPlayerName() + step + args[ 0 ] + " to "+ args[ 1 ] + ".---" + "UID:" +player.GetUID() ) - } - else{ + else print( player.GetPlayerName() + step + ".---" + "UID:" + player.GetUID()) - } } \ No newline at end of file -- cgit v1.2.3 From 74093a1afcf85ac6c66329d47b30f0d9cdadb50b Mon Sep 17 00:00:00 2001 From: Erlite Date: Fri, 21 Oct 2022 20:42:36 +0200 Subject: Fix server crash from demigod setting health over max health. (#509) * Fix server crash from demigod set health > max health * Add the incredible optimization. :^) Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA. Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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() -- cgit v1.2.3 From 1dc1986a7ab58a212be42ce557f5407029723f01 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:44:20 +0800 Subject: Fixed SuddenDeath Based Modes Stuck (#496) * Fixed SuddenDeath Based Modes Stuck Added checks so sudden death based gamemodes won't stuck if there ain't any players in server * Make scripts able to run --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 6cde4655..a44d7590 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -509,6 +509,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 ) } -- cgit v1.2.3 From 66d6613e679647e6395b21e8b6fe5f64312a8dd2 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Fri, 21 Oct 2022 19:44:43 +0100 Subject: allow server scripts to compile with -dev or developer 1 (#492) --- .../mod/scripts/vscripts/_loadouts_mp.gnut | 1 - .../mod/scripts/vscripts/mp/_model_viewer.nut | 180 +++++++++++++++++++++ .../mod/scripts/vscripts/sh_loadouts.nut | 18 +++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/mp/_model_viewer.nut diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 3e8ac9ea..068a785f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -222,7 +222,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/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 playerWeapons + array 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 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 weapons = player.GetMainWeapons() + foreach ( weaponEnt in weapons ) + { + string weapon = weaponEnt.GetWeaponClassName() + file.playerWeapons.append( weapon ) + player.TakeWeapon( weapon ) + } + + array 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/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 ) ) -- cgit v1.2.3 From 3c03047f9a0e3d06004cc5fe008e457396fccbf7 Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:46:58 -0400 Subject: add CUSTOMIZE_LOADOUT achievement (#489) --- Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 068a785f..76cb4ac4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -179,6 +179,8 @@ bool function ClientCommandCallback_SetPersistentLoadoutValue( entity player, ar if ( args[0] == "pilot" ) SetPlayerLoadoutDirty( player ) + UnlockAchievement( player, achievements.CUSTOMIZE_LOADOUT ) + return true } -- cgit v1.2.3 From 89814b24cbdc7cd9a9ba07acae08570b4d188dfe Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:48:43 +0800 Subject: Hide and seek crash fix (#488) * Fixed Hide and Seek droppod respawn crash Added EndSignal() and IsValid() check * Added IsValid() --- .../mod/scripts/vscripts/_droppod_spawn.gnut | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/_droppod_spawn.gnut b/Northstar.Custom/mod/scripts/vscripts/_droppod_spawn.gnut index 7447fc59..5bc75db2 100644 --- a/Northstar.Custom/mod/scripts/vscripts/_droppod_spawn.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/_droppod_spawn.gnut @@ -14,7 +14,10 @@ void function DropPodSpawn_Init() void function CleanupSpawningDropPods() { foreach ( entity pod in file.droppods ) - pod.Destroy() + { + if( IsValid( pod ) ) + pod.Destroy() + } file.droppods.clear() } @@ -22,6 +25,7 @@ void function CleanupSpawningDropPods() void function SpawnPlayersInDropPod( array< entity > players, vector targetOrigin, vector angles, float destructionTime = -1 ) { entity pod = CreateDropPod( targetOrigin, angles ) + pod.EndSignal( "OnDestroy" ) file.droppods.append( pod ) svGlobal.levelEnt.EndSignal( "CleanUpEntitiesForRoundEnd" ) @@ -35,9 +39,11 @@ void function SpawnPlayersInDropPod( array< entity > players, vector targetOrigi foreach ( entity player in players ) { + if( !IsValid( player ) ) + continue if ( !IsAlive( player ) ) player.RespawnPlayer( null ) - + player.SetOrigin( pod.GetOrigin() ) player.SetAngles( pod.GetAngles() ) player.SetParent( pod ) @@ -49,8 +55,12 @@ void function SpawnPlayersInDropPod( array< entity > players, vector targetOrigi // wait for this LaunchAnimDropPod( pod, "pod_testpath", targetOrigin, angles ) + if( !GamePlaying() ) + return foreach ( entity player in players ) { + if( !IsValid( player ) ) + continue player.ClearParent() player.ClearViewEntity() player.UnfreezeControlsOnServer() @@ -61,8 +71,12 @@ void function SpawnPlayersInDropPod( array< entity > players, vector targetOrigi WaitFrame() vector doorPos = pod.GetAttachmentOrigin( pod.LookupAttachment( "hatch" ) ) + if( !GamePlaying() ) + return foreach ( entity player in players ) { + if( !IsValid( player ) ) + continue vector viewAngles = doorPos - player.GetOrigin() viewAngles.x = 3.0 -- cgit v1.2.3 From 133aa4c4d1559b680cc043fdfe9c4dafb5d486f8 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:49:23 +0800 Subject: Added Callsign Event for Core Earned And Titan Kill (#495) * Added Callsign Event to Core Earned and Titan Kill Callsign event from vanilla * No Associate Entity for NPC Titan Kill * Added Check to Player Titans --- Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut | 14 ++++++++++++-- .../mod/scripts/vscripts/titan/_titan_health.gnut | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index 2d1ff074..457b2c9f 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 alreadyAssisted foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) 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" ) -- cgit v1.2.3 From ee0613f81248335191170ffccada19af0e85524c Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:51:19 +0800 Subject: Added Music and Dialogue Event (#469) * Added Music and Dialogue Event Added Music based on score event and time. Added Dialogue event based on score comparation and after killing a player's titan * Changed Filter Type to Only DM Gamemodes Only vanilla gamemodes those have unlimited respawns will automatically plays music * Added a ! omg * Removed Music Event Removed Music Event, Moved Dialogue Event to _gamestate_mp.nut * Changed mods.json * Changed RoundBased Gamemodes Check not hardcoded right now * Moved Killing Titan Dialogue to _score.nut dialogue is now together with scoreevent --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 91 ++++++++++++++++++++++ .../mod/scripts/vscripts/mp/_score.nut | 42 ++++++++++ 2 files changed, 133 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index a44d7590..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 @@ -888,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/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index 457b2c9f..dacd43b0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -215,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 ) @@ -261,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 + } +} -- cgit v1.2.3 From 1714d2d329bef4f970715b12133d1d676b7046ac Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 02:51:48 +0800 Subject: Fixed EarnMeter OverDrive not reset after player died (#486) --- .../mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 ) { -- cgit v1.2.3 From a758993e51bcc83a9982d313900d19fe36223383 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 22 Oct 2022 06:33:31 +0800 Subject: Fixed Evac Visual and Sound (#466) * Fixed Evac Visual and Sound Fix evac intro visual, flying sound and leaving visual * Removed Unnecessary comments Added better comments * Added IsValid() Check Added IsValid() check after a wait * Added EndSignal and Default Situation for ShipSetting --- .../mod/scripts/vscripts/evac/_evac.gnut | 169 +++++++++++++++++++-- 1 file changed, 160 insertions(+), 9 deletions(-) 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 -- cgit v1.2.3 From e9beee8d500f1729b6c051fba17beb493da43c24 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Fri, 21 Oct 2022 22:39:16 -0400 Subject: Fix invalid titan soul crash on arm badge (#361) --- Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut index 92b4924b..814e4430 100644 --- a/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/titan/sh_titan.gnut @@ -219,7 +219,7 @@ void function AddArmBadgeToTitan( entity soul ) void function AddArmBadgeToTitan_Internal( entity soul ) { - soul.EndSignal( "OnDeath" ) + soul.EndSignal( "OnDestroy" ) // wait until the end of the frame to allow the soul to become owned by a boss player WaitEndFrame() -- cgit v1.2.3 From dae4a32f1c4b0f04a50fa462d00ce6ebee92b2ee Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Sat, 22 Oct 2022 03:43:16 +0100 Subject: Halfway decent fix to allow changing of minimap size and zoom midgame (#265) * Add files via upload * Added Getter functions * typo lol * Update cl_minimap.gnut * Mode select updated RegisterPlaylistBannerImage and GetPlaylistBannerImage had initially been in another file but that file is not present in r2northstar/client, not much point adding the entirety of menu_playlist here since for a few lines, this also wont modify mixtape but i don't think mixtape menu is used anywhere in northstar * Added rui since basic image cant handle callsigns added ``` NextModeImageCallsign //For calling card icons { ControlName RuiPanel // xpos -12 ypos -12 wide 480 tall 240 visible 1 scaleImage 1 zpos 2 pin_to_sibling NextModeImageFrame pin_corner_to_sibling BOTTOM pin_to_sibling_corner BOTTOM rui "ui/callsign_icon_button.rpak" //For callsign mode images } ``` * Revert "Added rui since basic image cant handle callsigns" This reverts commit b2623ec41ca944fc0ac3386ae0346464da07a8b3. * Revert "Mode select updated" This reverts commit 2c6f430775c84ef252402b6b447b01fd394459a9. --- .../mod/scripts/vscripts/client/cl_minimap.gnut | 942 +++++++++++++++++++++ 1 file changed, 942 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut new file mode 100644 index 00000000..4237a0be --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_minimap.gnut @@ -0,0 +1,942 @@ +global function ClMinimap_Init + +global function ClientCodeCallback_MinimapEntitySpawned + +global function Minimap_AddLayer +global function Minimap_AddCustomLayer + +global function RegisterMinimapPackage + +global function Minimap_SetZoomScale +global function Minimap_SetSizeScale +global function Minimap_GetZoomScale +global function Minimap_GetSizeScale +global function Minimap_IsUsingLargeMinimap + +global function Minimap_Ping +global function ServerCallback_PingMinimap + +global function Minimap_EnableDraw +global function Minimap_DisableDraw + +#if DEV +global function DumpMinimapHandles +#endif + +struct { + var minimap_base + var minimap_wedges + + int activeMinimapObjectCount + + var minimap_you + var minimap_jammed_layer + + var minimap_indicator + + #if DEV + table< int, entity > minimapHandles + #endif + + array minimapOtherRuis + + float threatMaxDist + + float minimapZoomScale = 1 + float minimapSizeScale = 1 + + bool minimapEnabled = true +} file + + +struct MinmapPackage +{ + asset minimapAsset = $"" + void functionref( entity, var ) initFunction +} + +table< string, array > minimapAssetMap = {} + +const int OF_IS_VISIBLE = 1 << 0 +const int OF_TEAM_SAME = 1 << 1 +const int OF_TEAM_ENEMY = 1 << 2 +const int OF_IN_OUR_PARTY = 1 << 3 +const int OF_IS_OWNED_BY_US = 1 << 4 +const int OF_IS_PLAYER = 1 << 5 +const int OF_IS_NPC = 1 << 6 +const int OF_IS_TITAN = 1 << 7 +const int OF_ORIENT_UP = 1 << 8 +const int OF_NO_TEAM_COLOR = 1 << 9 + + +void function RegisterMinimapPackage( string entityClassname, int customStateIndex, asset minimapAsset, void functionref( entity, var ) initFunction ) +{ + Assert ( (entityClassname in minimapAssetMap), "minimap is not currently setup to handle this type of entity: " + entityClassname ) + + MinmapPackage minimapPackage + minimapPackage.minimapAsset = minimapAsset + minimapPackage.initFunction = initFunction + + switch ( entityClassname ) + { + case "npc_soldier": + case "npc_spectre": + case "npc_stalker": + case "npc_drone": + case "npc_frag_drone": + case "npc_super_spectre": + case "npc_turret_sentry": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_npc.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_npc.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + case "npc_titan": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_npc_titan.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_npc_titan.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + case "prop_script": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_prop_script.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_prop_script.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + case "info_hardpoint": + Assert( customStateIndex > 0 && customStateIndex < eMinimapObject_info_hardpoint.COUNT ) + minimapAssetMap[entityClassname].resize( eMinimapObject_info_hardpoint.COUNT ) + minimapAssetMap[entityClassname][customStateIndex] = minimapPackage + break + + default: + Assert( false, "minimap is not currently setup to handle this type of entity: " + entityClassname ) + } +} + +void function RegisterDefaultMinimapPackage( string entityClassname, asset minimapAsset, void functionref( entity, var ) initFunction ) +{ + Assert ( !(entityClassname in minimapAssetMap) ) + + MinmapPackage minimapPackage + minimapPackage.minimapAsset = minimapAsset + minimapPackage.initFunction = initFunction + + minimapAssetMap[entityClassname] <- [minimapPackage] +} + +void function ClMinimap_Init() +{ + RegisterDefaultMinimapPackage( "player", $"ui/minimap_player.rpak", MinimapPackage_PlayerInit ) + RegisterDefaultMinimapPackage( "npc_titan", $"ui/minimap_object.rpak", MinimapPackage_NPCTitanInit ) + RegisterDefaultMinimapPackage( "npc_soldier", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_spectre", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_stalker", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_super_spectre", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_drone_rocket", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_frag_drone", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_drone", $"ui/minimap_object.rpak", MinimapPackage_NPCHumanSizedInit ) + RegisterDefaultMinimapPackage( "npc_dropship", $"ui/minimap_object.rpak", MinimapPackage_NPCDropShipInit ) + RegisterDefaultMinimapPackage( "npc_turret_sentry", $"ui/minimap_object.rpak", MinimapPackage_NPCSentryTurretInit ) + RegisterDefaultMinimapPackage( "prop_script", $"", MinimapPackage_DummyInit ) + RegisterDefaultMinimapPackage( "item_titan_battery", $"ui/minimap_fw_battery.rpak", MinimapPackage_BatteryInit ) + RegisterDefaultMinimapPackage( "item_flag", $"ui/minimap_object.rpak", MinimapPackage_FlagInit ) + RegisterDefaultMinimapPackage( "item_bomb", $"ui/minimap_object.rpak", MinimapPackage_LTSBomb ) + RegisterDefaultMinimapPackage( "info_hardpoint", $"", MinimapPackage_DummyInit ) + RegisterDefaultMinimapPackage( "item_powerup", $"ui/minimap_object.rpak", MinimapPackage_PowerUp ) + + RegisterMinimapPackage( "npc_titan", eMinimapObject_npc_titan.AT_BOUNTY_BOSS, $"ui/minimap_object.rpak", MinimapPackage_BossTitanInit ) + + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_A, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_B, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_DROPZONE_C, $"ui/minimap_obj_area.rpak", MinimapPackage_ATAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.AT_BANK, $"ui/minimap_object.rpak", MinimapPackage_ATBank ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE_TURRET, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_BUILDSITE_SHIELDED, $"ui/minimap_fw_build_site.rpak", MinimapPackage_FWBuildSite ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_HARVESTER, $"ui/minimap_obj_area.rpak", MinimapPackage_FDHarvester ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_LOADOUT_CHEST, $"ui/minimap_obj_area.rpak", MinimapPackage_FDLoadoutChest ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_BATTERY_EXCHANGE, $"ui/minimap_obj_area.rpak", MinimapPackage_FDBatteryExchange ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.BOOST_STORE, $"ui/minimap_obj_area.rpak", MinimapPackage_BoostStore ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FD_MORTAR_POSITION, $"ui/minimap_mortar_spectre.rpak", MinimapPackage_MortarPosition ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.ARC_TRAP, $"ui/minimap_obj_area.rpak", MinimapPackage_ArcTrap ) + + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_A, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampA ) + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_B, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampB ) + //RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.FW_CAMP_C, $"ui/minimap_fw_camp.rpak", MinimapPackage_FWCampC ) + + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_A, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointA ) + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_B, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointB ) + RegisterMinimapPackage( "info_hardpoint", eMinimapObject_info_hardpoint.HARDPOINT_C, $"ui/minimap_obj_area.rpak", MinimapPackage_HardpointC ) + + //if ( IsPlayingDemo() ) + { + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_IMC, $"ui/minimap_obj_area.rpak", MinimapPackage_SpawnZoneAreaInit ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_MIL, $"ui/minimap_obj_area.rpak", MinimapPackage_SpawnZoneAreaInit ) + } + //else + //{ + // RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_IMC, $"", MinimapPackage_SpawnZoneAreaInit ) + // RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.SPAWNZONE_MIL, $"", MinimapPackage_SpawnZoneAreaInit ) + //} + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.LTS_SITE_A, $"ui/minimap_object.rpak", MinimapPackage_LTSBombSiteA ) + RegisterMinimapPackage( "prop_script", eMinimapObject_prop_script.LTS_SITE_B, $"ui/minimap_object.rpak", MinimapPackage_LTSBombSiteB ) + /* + { + MinmapPackage atAreaPacakage + atAreaPacakage.minimapAsset = $"ui/minimap_obj_area.rpak" + atAreaPacakage.initFunction = MinimapPackage_ATAreaInit + MinmapPackage spawnZonePacakage + spawnZonePacakage.minimapAsset = $"ui/minimap_obj_area.rpak" + spawnZonePacakage.initFunction = MinimapPackage_SpawnZoneAreaInit + MinmapPackage fwBuildSitePackage + fwBuildSitePackage.minimapAsset = $"ui/minimap_fw_build_site.rpak" + fwBuildSitePackage.initFunction = MinimapPackage_FWBuildSite + MinmapPackage fwCampAPackage + fwCampAPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampAPackage.initFunction = MinimapPackage_FWCampA + MinmapPackage fwCampBPackage + fwCampBPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampBPackage.initFunction = MinimapPackage_FWCampB + MinmapPackage fwCampCPackage + fwCampCPackage.minimapAsset = $"ui/minimap_fw_camp.rpak" + fwCampCPackage.initFunction = MinimapPackage_FWCampC + minimapAssetMap["prop_script"] <-[blankPackage, atAreaPacakage, atAreaPacakage, atAreaPacakage, spawnZonePacakage, spawnZonePacakage, + fwCampAPackage, fwCampBPackage, fwCampCPackage, + fwBuildSitePackage, fwBuildSitePackage, fwBuildSitePackage ] + } +*/ + + AddCreateCallback( "player", OnPlayerCreate ) + + float threatMaxDist = Minimap_GetFloatForKey( "threatMaxDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + if ( GameRules_GetGameMode() == FORT_WAR ) + file.threatMaxDist = max( threatMaxDist, 2200 ) + else + file.threatMaxDist = max( threatMaxDist, 1800 ) + + file.minimap_base = CreateCockpitRui( $"ui/minimap_base.rpak", MINIMAP_Z_BASE ) + + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + + file.minimap_wedges = CreateCockpitRui( $"ui/minimap_wedges.rpak", MINIMAP_Z_THREAT_WEDGES ) + + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + + file.minimap_you = CreateCockpitRui( $"ui/minimap_you.rpak", MINIMAP_Z_YOU ) + + RuiSetFloat( file.minimap_you, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_you, "minimapSizeScale", file.minimapSizeScale ) + + file.minimap_jammed_layer = null + + file.minimap_indicator = CreateCockpitRui( $"ui/minimap_indicator.rpak", -1 ) + + RuiSetFloat( file.minimap_indicator, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_indicator, "minimapSizeScale", file.minimapSizeScale ) + + StatusEffect_RegisterEnabledCallback( eStatusEffect.minimap_jammed, MinimapJammed_Enabled ) + StatusEffect_RegisterDisabledCallback( eStatusEffect.minimap_jammed, MinimapJammed_Disabled ) + RegisterSignal( "LoopRadarJammerSounds" ) +} + +#if DEV +void function DumpMinimapHandles() +{ + int index = 0 + foreach ( handle, ent in file.minimapHandles ) + { + printt( index, handle, ent ) + ++index + } +} +#endif + + +void function Minimap_DisableDraw() +{ + file.minimapEnabled = false + + RuiSetDrawGroup( file.minimap_base, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_wedges, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_you, RUI_DRAW_NONE ) + RuiSetDrawGroup( file.minimap_indicator, RUI_DRAW_NONE ) + + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetDrawGroup( rui, RUI_DRAW_NONE ) + } +} + +void function Minimap_EnableDraw() +{ + file.minimapEnabled = true + + RuiSetDrawGroup( file.minimap_base, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_wedges, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_you, RUI_DRAW_COCKPIT ) + RuiSetDrawGroup( file.minimap_indicator, RUI_DRAW_COCKPIT ) + + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetDrawGroup( rui, RUI_DRAW_COCKPIT ) + } +} + + +void function ClientCodeCallback_MinimapEntitySpawned( entity ent ) +{ + foreach ( callbackFunc in clGlobal.onMinimapEntSpawnedCallbacks ) + { + callbackFunc( ent ) + } + + if ( ent == GetLocalViewPlayer() ) + return + + thread AddMinimapObject( ent ) +} + + +asset function GetMinimapAsset( string className, int customState ) +{ + if ( !(className in minimapAssetMap) ) + return $"" + + if ( customState > minimapAssetMap[className].len() - 1 ) + return $"" + + return minimapAssetMap[className][customState].minimapAsset +} + + +void function AddMinimapObject( entity ent ) //TODO: If we want radar jammer boost to hide friendly players we need to be able to get the rui handles back. +{ + Assert( IsValid( ent ) ) + + string className = expect string( ent.GetSignifierName() ) + int customState = ent.Minimap_GetCustomState() + + asset minimapAsset = GetMinimapAsset( className, customState ) + if ( minimapAsset == $"" ) + { + return + } + + int zOrder = ent.Minimap_GetZOrder() + entity viewPlayer = GetLocalViewPlayer() + + ent.SetDoDestroyCallback( true ) + + #if DEV + int eHandle = ent.Dev_GetEncodedEHandle() + + { + array< int > eHandlesToRemove + foreach ( eHandleIter, entIter in file.minimapHandles ) + { + if ( !IsValid( entIter ) ) + { + eHandlesToRemove.append( eHandleIter ) + } + } + + foreach ( eHandleIter in eHandlesToRemove ) + { + delete file.minimapHandles[eHandleIter] + } + } + + if ( eHandle in file.minimapHandles ) + { + // Should have been removed in above loop + Assert( IsValid( file.minimapHandles[eHandle] ) ) + + DumpMinimapHandles() + Assert( false, "Duplicate minimap entity added - " + ent ) + } + + file.minimapHandles[eHandle] <- ent + #endif + + var rui = CreateCockpitRui( minimapAsset, MINIMAP_Z_BASE + zOrder ) + + //RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + + RuiTrackFloat3( rui, "playerPos", viewPlayer, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", viewPlayer, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiTrackFloat3( rui, "objectPos", ent, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "objectAngles", ent, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackInt( rui, "objectFlags", ent, RUI_TRACK_MINIMAP_FLAGS ) + RuiTrackInt( rui, "customState", ent, RUI_TRACK_MINIMAP_CUSTOM_STATE ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + minimapAssetMap[className][customState].initFunction( ent, rui ) + + file.minimapOtherRuis.append( rui ) + + RuiSetDrawGroup( rui, file.minimapEnabled ? RUI_DRAW_COCKPIT : RUI_DRAW_NONE ) + OnThreadEnd( + function() : ( rui ) + { + file.minimapOtherRuis.removebyvalue( rui ) + RuiDestroy( rui ) + } + ) + + ent.EndSignal( "OnDestroy" ) + + if ( ent.IsPlayer() ) + { + while ( IsValid( ent ) ) + { + WaitSignal( ent, "SettingsChanged", "OnDeath" ) + } + } + else + { + ent.WaitSignal( "OnDestroy" ) + } +} + + +void function Minimap_PingCount( vector origin, float radius, float duration, vector color, int count, bool reverse = false ) +{ + float delay = duration / count + + while ( count ) + { + count-- + + Minimap_Ping( origin, radius, delay + (delay * 0.25), color, reverse ) + wait delay + } +} + + +void function Minimap_Ping( vector origin, float radius, float duration, vector color, bool reverse = false ) +{ + entity viewPlayer = GetLocalViewPlayer() + int zOrder = viewPlayer.Minimap_GetZOrder() + + if ( !file.minimapEnabled ) + return + + var rui = CreateCockpitRui( $"ui/minimap_ping.rpak", MINIMAP_Z_BASE + zOrder ) + + RuiTrackFloat3( rui, "playerPos", viewPlayer, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", viewPlayer, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiSetFloat3( rui, "objColor", color ) + RuiSetFloat3( rui, "objectPos", origin ) + RuiSetFloat3( rui, "objectAngles", <0,0,0> ) + + RuiSetFloat( rui, "objectRadius", radius / ( file.threatMaxDist * file.minimapZoomScale ) ) + + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetGameTime( rui, "endTime", Time() + duration ) + + RuiSetBool( rui, "reverse", reverse ) +} + + + +var function Minimap_AddLayer( asset layerImage, bool isFriendly ) +{ + entity player = GetLocalViewPlayer() + + var rui = CreateCockpitRui( $"ui/minimap_layer.rpak", MINIMAP_Z_LAYER ) + + RuiTrackFloat3( rui, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetImage( rui, "layerImage", layerImage ) + RuiSetFloat3( rui, "mapCorner", ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "mapScale", mapScale ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetBool( rui, "isFriendly", isFriendly ) + + return rui +} + +var function Minimap_AddCustomLayer( asset ruiAsset, int sortKey = MINIMAP_Z_LAYER ) +{ + entity player = GetLocalViewPlayer() + + var rui = CreateCockpitRui( ruiAsset, sortKey ) + + RuiTrackFloat3( rui, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( rui, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetFloat3( rui, "mapCorner", ) + RuiSetFloat( rui, "displayDist", file.threatMaxDist ) + RuiSetFloat( rui, "mapScale", mapScale ) + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + + return rui +} + + +void function OnPlayerCreate( entity player ) +{ + if ( player != GetLocalViewPlayer() ) + return + + RuiTrackFloat3( file.minimap_base, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.minimap_base, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + RuiTrackInt( file.minimap_indicator, "indicatorId", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "indicatorId" ) ) + + asset mapImage = Minimap_GetAssetForKey( "minimap" ) + float mapCornerX = Minimap_GetFloatForKey( "pos_x" ) + float mapCornerY = Minimap_GetFloatForKey( "pos_y" ) + float displayDist = Minimap_GetFloatForKey( "displayDist" ) + float threatDistNear = Minimap_GetFloatForKey( "threatNearDist" ) + float threatDistFar = Minimap_GetFloatForKey( "threatFarDist" ) + + float mapScale = Minimap_GetFloatForKey( "scale" ) + + RuiSetImage( file.minimap_base, "mapImage", mapImage ) + RuiSetFloat3( file.minimap_base, "mapCorner", ) + RuiSetFloat( file.minimap_base, "displayDist", file.threatMaxDist ) + RuiSetFloat( file.minimap_base, "mapScale", mapScale ) + + RuiTrackFloat3( file.minimap_wedges, "playerPos", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.minimap_wedges, "playerAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiSetFloat3( file.minimap_wedges, "distances", ) + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeCenter", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_CENTER ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid0", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_N ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid1", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_NE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid2", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_E ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid3", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_SE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid4", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_S ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid5", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_SW ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid6", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_W ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeMid7", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_NEAR_NW ) + + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter0", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_N ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter1", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_NE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter2", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_E ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter3", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_SE ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter4", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_S ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter5", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_SW ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter6", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_W ) + RuiTrackGameTime( file.minimap_wedges, "lastFireTimeOuter7", player, RUI_TRACK_MINIMAP_THREAT_SECTOR, MOTS_FAR_NW ) + + + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + + RuiTrackInt( file.minimap_you, "objectFlags", player, RUI_TRACK_MINIMAP_FLAGS ) + RuiTrackInt( file.minimap_you, "customState", player, RUI_TRACK_MINIMAP_CUSTOM_STATE ) + +} + + +void function MinimapPackage_DummyInit( entity ent, var rui ) +{ + +} + +void function MinimapPackage_PlayerInit( entity ent, var rui ) +{ + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + { + RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) + RuiTrackFloat( rui, "maphackDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.maphack_detected ) + } +} + +void function MinimapPackage_NPCTitanInit( entity ent, var rui ) +{ + entity player = GetLocalClientPlayer() + + RuiSetBool( rui, "useTeamColor", false ) + + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) +} + +void function MinimapPackage_NPCHumanSizedInit( entity ent, var rui ) +{ + entity player = GetLocalClientPlayer() + + RuiSetImage( rui, "defaultIcon", $"rui/hud/minimap/compass_icon_small_dot" ) + RuiSetImage( rui, "clampedDefaultIcon", $"" ) + + //if ( ent == GetLocalClientPlayer().GetPetTitan() ) + //{ + // RuiSetBool( rui, "useTeamColor", false ) + // RuiSetFloat3( rui, "iconColor", TEAM_COLOR_YOU / 255.0 ) + //} + RuiTrackGameTime( rui, "lastFireTime", ent, RUI_TRACK_LAST_FIRED_TIME ) + //if ( !IsFFAGame() ) //JFS: Too much work to get FFA to work correctly with Minimap logic, so disabling it for FFA + // RuiTrackFloat( rui, "sonarDetectedFrac", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.sonar_detected ) +} + +void function MinimapPackage_NPCDropShipInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/scoreboard/status_evac" ) +} + +void function MinimapPackage_NPCSentryTurretInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"" ) + RuiSetImage( rui, "clampedDefaultIcon", $"" ) +} + +void function MinimapPackage_BossTitanInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_titan" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_titan" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_BatteryInit( entity ent, var rui ) +{ + entity player = GetLocalViewPlayer() + RuiTrackInt( rui, "batteryCount", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "batteryCount" ) ) + RuiSetBool( rui, "useTeamColor", false ) + RuiTrackFloat( rui, "batteryCarried", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.battery_carried ) +} + +void function MinimapPackage_ATAreaInit( entity ent, var rui ) +{ + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_ATBank( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_SpawnZoneAreaInit( entity ent, var rui ) +{ + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) + if ( !IsPlayingDemo() ) + { + RuiSetImage( rui, "centerImage", $"" ) // hide diamond + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/obj_foreground_diamond" ) + } +} + +void function MinimapPackage_FWBuildSite( entity ent, var rui ) +{ + entity player = GetLocalViewPlayer() + RuiTrackInt( rui, "batteryCount", player, RUI_TRACK_SCRIPT_NETWORK_VAR_INT, GetNetworkedVariableIndex( "batteryCount" ) ) + //RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_HardpointA( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_HardpointB( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_HardpointC( entity ent, var rui ) +{ + RuiSetFloat( rui, "objectRadius", 0.001 ) +} + +void function MinimapPackage_FDHarvester( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/coop_harvester" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/coop_harvester" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_FDLoadoutChest( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/coop_ammo_locker_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/coop_ammo_locker_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_FDBatteryExchange( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bank_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_BoostStore( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bonus_icon" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/bounty_hunt/bh_bonus_icon" ) + RuiSetFloat( rui, "objectRadius", 0.01 ) + RuiSetBool( rui, "useOverrideColor", true ) + RuiSetColorAlpha( rui, "overrideColor", <1.0,1.0,1.0>, 1.0 ) +} + +void function MinimapPackage_MortarPosition( entity ent, var rui ) +{ + RuiSetImage( rui, "bgImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar_bg" ) + RuiSetImage( rui, "centerImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar" ) + RuiSetImage( rui, "clampedImage", $"rui/hud/gametype_icons/fd/fd_icon_spectre_mortar" ) + RuiTrackFloat( rui, "arcPercent", ent, RUI_TRACK_SHIELD_FRACTION ) +} + +void function MinimapPackage_ArcTrap( entity ent, var rui ) +{ + RuiSetImage( rui, "centerImage", $"rui/hud/minimap/compass_icon_arc_trap" ) + RuiSetImage( rui, "clampedImage", $"" ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampA( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertA" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampB( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertB" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_FWCampC( entity ent, var rui ) +{ + RuiTrackInt( rui, "alertLevel", null, RUI_TRACK_SCRIPT_NETWORK_VAR_GLOBAL_INT, GetNetworkedVariableIndex( "fwCampAlertC" ) ) + RuiTrackFloat( rui, "objectRadius", ent, RUI_TRACK_MINIMAP_SCALE ) +} + +void function MinimapPackage_LTSBombSiteA( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_a_attacking" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_a_attacking" ) +} + +void function MinimapPackage_LTSBombSiteB( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_b_attacking" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_site_b_attacking" ) +} + +void function MinimapPackage_LTSBomb( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_neutral" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/last_titan_standing/bomb_neutral" ) + RuiSetBool( rui, "useTeamColor", false ) +} + +void function MinimapPackage_FlagInit( entity ent, var rui ) +{ + RuiSetImage( rui, "defaultIcon", $"rui/hud/gametype_icons/ctf/ctf_flag_neutral" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/gametype_icons/ctf/ctf_flag_neutral" ) + RuiSetBool( rui, "useTeamColor", true ) +} + +void function MinimapPackage_PowerUp( entity ent, var rui ) +{ + //Battery spawners are the only power ups in use atm. This would need to be updated if we use them differently. + RuiSetImage( rui, "defaultIcon", $"rui/hud/battery/battery_capture_friendly" ) + RuiSetImage( rui, "clampedDefaultIcon", $"rui/hud/battery/battery_capture_friendly" ) + RuiSetBool( rui, "useTeamColor", false ) +} + + +void function MinimapJammed_Enabled( entity ent, int statusEffect, bool actuallyChanged ) +{ + if ( !actuallyChanged ) + return + + if ( ent != GetLocalClientPlayer() ) + return + + thread LoopRadarJammerSounds( ent ) + thread FadeOutStaticSoundAfterDelay( ent, BURN_METER_RADAR_JAMMER_PULSE_DURATION - BURN_METER_RADAR_JAMMER_EASE_OFF_TIME ) + + if ( file.minimap_jammed_layer != null ) + RuiDestroy( file.minimap_jammed_layer ) + + file.minimap_jammed_layer = Minimap_AddCustomLayer( $"ui/minimap_jammer_layer.rpak", MINIMAP_Z_YOU + 1 ) + if ( actuallyChanged ) + RuiSetGameTime( file.minimap_jammed_layer, "startTime", Time() ) + + RuiSetFloat( file.minimap_jammed_layer, "minimapZoomScale", file.minimapZoomScale ) + RuiSetFloat( file.minimap_jammed_layer, "minimapSizeScale", file.minimapSizeScale ) + RuiTrackFloat( file.minimap_jammed_layer, "scriptAlphaVar", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, statusEffect ) + + RuiTrackFloat( file.minimap_wedges, "scriptInverseAlphaVar", ent, RUI_TRACK_STATUS_EFFECT_SEVERITY, statusEffect ) + +} + +void function MinimapJammed_Disabled( entity ent, int statusEffect, bool actuallyChanged ) +{ + if ( !actuallyChanged ) + return + + if ( ent != GetLocalClientPlayer() ) + return + + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) + + if ( file.minimap_jammed_layer != null ) + { + RuiDestroy( file.minimap_jammed_layer ) + file.minimap_jammed_layer = null + } +} + +void function LoopRadarJammerSounds( entity ent ) +{ + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) + clGlobal.levelEnt.EndSignal( "LoopRadarJammerSounds" ) + ent.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( ent ) + { + StopSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_RedTextBeep_1P" ) + } + ) + + float currentTime = Time() + float fractionalComponent = currentTime - floor( currentTime ) + float timeToWait + if ( fractionalComponent <= 0.5 ) + timeToWait = 0.5 - fractionalComponent + else + timeToWait = 1.5 - fractionalComponent + + wait ( timeToWait ) //Red text flashes in with regards to game time, so we need to wait till the appropriate time (0.5) to play the next sound + + while( true ) + { + if ( IsValid( ent ) ) + EmitSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_RedTextBeep_1P" ) + + wait 1.0 //This is dependent on the rui logic, and will need to be changed if the rui logic changes + } +} + +void function FadeOutStaticSoundAfterDelay( entity ent, float delay ) +{ + EmitSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_Signal_Static_1P" ) + + ent.EndSignal( "OnDeath" ) + + OnThreadEnd( + function() : ( ent ) + { + clGlobal.levelEnt.Signal( "LoopRadarJammerSounds" ) //stop red text beeping sounds + if ( IsValid( ent ) ) + StopSoundOnEntity( ent, "HUD_Boost_Card_Radar_Jammer_Signal_Static_1P" ) + + } + ) + wait delay +} +void function Minimap_SetZoomScale( float scale ) +{ + file.minimapZoomScale = scale + if(file.minimap_you != null) + RuiSetFloat( file.minimap_you, "minimapZoomScale", file.minimapZoomScale ) + if(file.minimap_indicator != null) + RuiSetFloat( file.minimap_indicator, "minimapZoomScale", file.minimapZoomScale ) + if(file.minimap_base != null) + RuiSetFloat( file.minimap_base, "minimapZoomScale", file.minimapZoomScale ) + + if ( file.minimap_wedges != null ) + { + RuiSetBool( file.minimap_wedges, "isVisible", file.minimapZoomScale == 1.0 ) + RuiSetFloat( file.minimap_wedges, "minimapZoomScale", file.minimapZoomScale ) + } + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetFloat( rui, "minimapZoomScale", file.minimapZoomScale ) + } +} + +void function Minimap_SetSizeScale( float scale ) +{ + file.minimapSizeScale = scale + if(file.minimap_base != null) + RuiSetFloat( file.minimap_base, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_indicator != null) + RuiSetFloat( file.minimap_indicator, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_you != null) + RuiSetFloat( file.minimap_you, "minimapSizeScale", file.minimapSizeScale ) + if(file.minimap_wedges != null) + RuiSetFloat( file.minimap_wedges, "minimapSizeScale", file.minimapSizeScale ) + foreach ( var rui in file.minimapOtherRuis ) + { + RuiSetFloat( rui, "minimapSizeScale", file.minimapSizeScale ) + } + +} +float function Minimap_GetZoomScale() +{ + return file.minimapZoomScale +} +float function Minimap_GetSizeScale() +{ + return file.minimapSizeScale +} +bool function Minimap_IsUsingLargeMinimap() +{ + return file.minimapSizeScale > 1.0 +} + +void function ServerCallback_PingMinimap( float originX, float originY, float originZ, float radius, float duration, float colorR, float colorG, float colorB, int count, bool reverse ) +{ + if ( count > 1 ) + thread Minimap_PingCount( , radius, duration, , count, reverse ) + else + Minimap_Ping( , radius, duration, , reverse ) +} -- cgit v1.2.3 From ef8a419edea010f39c35b913626c35900f052e2b Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:16:58 +0000 Subject: restore hud_takesshots functionality to automatically take screenshots of scoreboard (#522) * restore hud_takesshots functionality to take screenshots of scoreboard automatically * fixup some formatting --- Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut b/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut index 93be01ea..1baeae9f 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_gamestate.gnut @@ -1105,8 +1105,16 @@ void function DisplayPostMatchTop3() RuiSetBool( rui, "isFriendly" + i, localTeam == players[i].GetTeam() ) } } + + if ( GetConVarBool( "hud_takesshots" ) ) + thread TakeScoreboardScreenshot_Delayed() } +void function TakeScoreboardScreenshot_Delayed() +{ + wait 1.5 + GetLocalClientPlayer().ClientCommand( "jpeg" ) +} float function GetGameStartTime() { -- cgit v1.2.3 From 0c388032acabebd89d2b28e52e97be6f6446b144 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Tue, 1 Nov 2022 07:17:13 +0800 Subject: Fixed ctf Sound Events and Flag Icon (#515) * Fixed ctf Sound Events and Flag Icon Norshtar before using a wrong sound name that causes enemy picking up/ capture flag have no sounds, also there's not a icon in minimap for flags * commit fix --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) 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 ) -- cgit v1.2.3 From c5166f21fef4796d3066c59f4b2f2bdb7c1c4d74 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 31 Oct 2022 23:17:24 +0000 Subject: add datatables (dumped from rpak) (#517) * add datatables (dumped from rpak) * add datatables that accidentally weren't included --- .../mod/scripts/datatable/battle_chatter.csv | 24 + .../scripts/datatable/battle_chatter_voices.csv | 19 + .../mod/scripts/datatable/burn_meter_rewards.csv | 21 + .../mod/scripts/datatable/burn_meter_store.csv | 21 + .../mod/scripts/datatable/caller_ids_mp.csv | 2 + .../mod/scripts/datatable/calling_cards.csv | 491 ++++++++++ .../mod/scripts/datatable/callsign_icons.csv | 193 ++++ .../mod/scripts/datatable/camo_skins.csv | 161 ++++ .../mod/scripts/datatable/community_entries.csv | 22 + .../mod/scripts/datatable/death_hints_mp.csv | 381 ++++++++ .../scripts/datatable/default_pilot_loadouts.csv | 11 + .../scripts/datatable/default_titan_loadouts.csv | 8 + .../mod/scripts/datatable/earn_meter_mp.csv | 31 + .../mod/scripts/datatable/faction_dialogue.csv | 273 ++++++ .../mod/scripts/datatable/faction_leaders.csv | 8 + .../datatable/faction_leaders_dropship_anims.csv | 23 + .../mod/scripts/datatable/fd_awards.csv | 15 + .../mod/scripts/datatable/features_mp.csv | 21 + .../mod/scripts/datatable/flightpath_assets.csv | 8 + .../mod/scripts/datatable/grunt_chatter_mp.csv | 47 + .../mod/scripts/datatable/non_loadout_weapons.csv | 29 + .../mod/scripts/datatable/pain_death_sounds.csv | 53 ++ .../mod/scripts/datatable/pilot_abilities.csv | 16 + .../mod/scripts/datatable/pilot_executions.csv | 14 + .../mod/scripts/datatable/pilot_passives.csv | 10 + .../mod/scripts/datatable/pilot_properties.csv | 8 + .../scripts/datatable/pilot_weapon_features.csv | 5 + .../mod/scripts/datatable/pilot_weapon_mods.csv | 250 ++++++ .../scripts/datatable/pilot_weapon_mods_common.csv | 27 + .../mod/scripts/datatable/pilot_weapons.csv | 33 + .../mod/scripts/datatable/playlist_items.csv | 27 + .../mod/scripts/datatable/score_events.csv | 221 +++++ .../mod/scripts/datatable/sp_levels.csv | 17 + .../mod/scripts/datatable/spectre_chatter_mp.csv | 8 + .../mod/scripts/datatable/spotlight_images.csv | 30 + .../mod/scripts/datatable/startpoints.csv | 313 +++++++ .../mod/scripts/datatable/titan_abilities.csv | 36 + .../mod/scripts/datatable/titan_executions.csv | 26 + .../mod/scripts/datatable/titan_fd_upgrades.csv | 50 ++ .../mod/scripts/datatable/titan_nose_art.csv | 191 ++++ .../scripts/datatable/titan_os_conversations.csv | 67 ++ .../mod/scripts/datatable/titan_passives.csv | 52 ++ .../mod/scripts/datatable/titan_primary_mods.csv | 1 + .../datatable/titan_primary_mods_common.csv | 1 + .../scripts/datatable/titan_primary_weapons.csv | 10 + .../mod/scripts/datatable/titan_properties.csv | 10 + .../mod/scripts/datatable/titan_skins.csv | 56 ++ .../mod/scripts/datatable/titan_voices.csv | 9 + .../mod/scripts/datatable/titans_mp.csv | 8 + .../scripts/datatable/unlocks_faction_level.csv | 82 ++ .../scripts/datatable/unlocks_fd_titan_level.csv | 26 + .../mod/scripts/datatable/unlocks_player_level.csv | 996 +++++++++++++++++++++ .../mod/scripts/datatable/unlocks_random.csv | 359 ++++++++ .../mod/scripts/datatable/unlocks_titan_level.csv | 402 +++++++++ .../datatable/unlocks_weapon_level_pilot.csv | 383 ++++++++ .../mod/scripts/datatable/weapon_skins.csv | 35 + .../mod/scripts/datatable/xp_per_faction_level.csv | 6 + .../scripts/datatable/xp_per_fd_titan_level.csv | 25 + .../mod/scripts/datatable/xp_per_player_level.csv | 51 ++ .../mod/scripts/datatable/xp_per_titan_level.csv | 21 + .../mod/scripts/datatable/xp_per_weapon_level.csv | 21 + 61 files changed, 5765 insertions(+) create mode 100644 Northstar.CustomServers/mod/scripts/datatable/battle_chatter.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/battle_chatter_voices.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/burn_meter_rewards.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/burn_meter_store.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/caller_ids_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/calling_cards.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/callsign_icons.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/camo_skins.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/community_entries.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/death_hints_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/default_pilot_loadouts.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/default_titan_loadouts.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/earn_meter_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/faction_dialogue.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/faction_leaders.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/faction_leaders_dropship_anims.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/fd_awards.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/features_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/flightpath_assets.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/grunt_chatter_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/non_loadout_weapons.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pain_death_sounds.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_abilities.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_executions.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_passives.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_properties.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_features.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods_common.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/pilot_weapons.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/playlist_items.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/score_events.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/sp_levels.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/spectre_chatter_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/spotlight_images.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/startpoints.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_abilities.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_executions.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_fd_upgrades.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_nose_art.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_os_conversations.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_passives.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods_common.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_primary_weapons.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_properties.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_skins.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titan_voices.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/titans_mp.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_faction_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_fd_titan_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_player_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_random.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_titan_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/unlocks_weapon_level_pilot.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/weapon_skins.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/xp_per_faction_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/xp_per_fd_titan_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/xp_per_player_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/xp_per_titan_level.csv create mode 100644 Northstar.CustomServers/mod/scripts/datatable/xp_per_weapon_level.csv diff --git a/Northstar.CustomServers/mod/scripts/datatable/battle_chatter.csv b/Northstar.CustomServers/mod/scripts/datatable/battle_chatter.csv new file mode 100644 index 00000000..74d4c1d9 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/battle_chatter.csv @@ -0,0 +1,24 @@ +conversationname,priority,debounce +"bc_pReload",500,45.000000 +"bc_pHardcover",500,10.000000 +"bc_pPulse",500,10.000000 +"bc_pGrapple",500,10.000000 +"bc_pHolo",500,10.000000 +"bc_pCloak",500,10.000000 +"bc_pAmp",500,10.000000 +"bc_pStim",500,10.000000 +"bc_pPhase",500,10.000000 +"bc_pFrag",500,10.000000 +"bc_pSmoke",500,10.000000 +"bc_pArc",500,10.000000 +"bc_pGrav",500,10.000000 +"bc_pSatchel",500,10.000000 +"bc_pFirestar",500,10.000000 +"bc_pGravStar",500,10.000000 +"bc_pAmpedWall",500,10.000000 +"bc_fKilledEnemy",500,10.000000 +"bc_pPulseBladeSpotEnemy",500,10.000000 +"bc_fNearEnemyDmg",500,10.000000 +"bc_fCongratsKill",500,10.000000 +"bc_pBatteryOffer",500,5.000000 +"bc_pIntroChat",500,5.000000 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/battle_chatter_voices.csv b/Northstar.CustomServers/mod/scripts/datatable/battle_chatter_voices.csv new file mode 100644 index 00000000..32450513 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/battle_chatter_voices.csv @@ -0,0 +1,19 @@ +isMale,isAndroid,ref +1,0,"M1" +1,0,"M2" +1,0,"M3" +1,0,"M4" +1,0,"M5" +1,0,"M6" +1,0,"M7" +1,0,"M8" +1,0,"M9" +0,0,"F1" +0,0,"F2" +0,0,"F3" +0,0,"F4" +0,0,"F5" +1,1,"MA1" +1,1,"MA2" +0,1,"FA1" +0,1,"FA2" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/burn_meter_rewards.csv b/Northstar.CustomServers/mod/scripts/datatable/burn_meter_rewards.csv new file mode 100644 index 00000000..41e8376d --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/burn_meter_rewards.csv @@ -0,0 +1,21 @@ +itemRef,selectable,name,description,image,model,skinIndex,activationCost,rewardAvailableFor,weaponName,extraWeaponMod,activationText,cost +"burnmeter_maphack",1,"#BURNMETER_MAP_HACK","#BURNMETER_MAP_HACK_DESC","rui/menu/boosts/boost_map_hack","models/weapons_r2/burn_card/burn_card.mdl",9,0.700000,"PILOT_AND_TITAN","mp_ability_burncardweapon","burnmeter_maphack","#BURNMETER_MAP_HACK_DESC",125 +"burnmeter_amped_weapons",1,"#BURNMETER_AMPED_WEAPONS","#BURNMETER_AMPED_WEAPONS_DESC","rui/menu/boosts/boost_amped_weapons","models/weapons_r2/burn_card/burn_card.mdl",0,0.800000,"PILOT_AND_TITAN","mp_ability_burncardweapon","burnmeter_amped_weapons","#BURNMETER_AMPED_WEAPONS_DESC",125 +"burnmeter_ticks",1,"#BURNMETER_TICKS","#BURNMETER_TICKS_DESC","rui/menu/boosts/boost_ticks","models/weapons_r2/burn_card/burn_card.mdl",5,0.650000,"PILOT_ONLY","mp_weapon_frag_drone","","#WPN_FRAG_DRONE_LONGDESC",125 +"burnmeter_random_foil",1,"#BURNMETER_RANDOM_FOIL","#BURNMETER_RANDOM_FOIL_DESC","rui/menu/boosts/boost_random","models/weapons_r2/burn_card/burn_card.mdl",11,0.500000,"PILOT_AND_TITAN","mp_ability_burncardweapon","burnmeter_random_foil","#BURNMETER_RANDOM_FOIL_DESC",125 +"burnmeter_ap_turret_weapon",1,"#BURNMETER_AP_TURRETWEAPON","#BURNMETER_AP_TURRETWEAPON_DESC","rui/menu/boosts/boost_antipersonnel_sentry","models/weapons_r2/burn_card/burn_card.mdl",6,0.720000,"PILOT_ONLY","mp_ability_turretweapon","burnmeter_ap_turret_weapon","#BURNMETER_AP_TURRETWEAPON_DESC_BOOST_ACTIVATION_TEXT",125 +"burnmeter_phase_rewind",1,"#WPN_REWIND","#WPN_REWIND_LONGDESC","rui/menu/boosts/boost_phase_rewind","models/weapons_r2/burn_card/burn_card.mdl",8,0.250000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_phase_rewind","#WPN_REWIND_LONGDESC",125 +"burnmeter_at_turret_weapon",1,"#BURNMETER_AT_TURRETWEAPON","#BURNMETER_AT_TURRETWEAPON_DESC","rui/menu/boosts/boost_antititan_sentry","models/weapons_r2/burn_card/burn_card.mdl",7,0.350000,"PILOT_ONLY","mp_ability_turretweapon","burnmeter_at_turret_weapon","#BURNMETER_AT_TURRETWEAPON_DESC_BOOST_ACTIVATION_TEXT",125 +"burnmeter_holopilot_nova",1,"#WPN_HOLOPILOT_NOVA","#WPN_HOLOPILOT_NOVA_DESC_BOOST_ACTIVATION_TEXT","rui/menu/boosts/boost_holo_pilots","models/weapons_r2/burn_card/burn_card.mdl",10,0.400000,"PILOT_ONLY","mp_ability_holopilot_nova","","#WPN_HOLOPILOT_NOVA_DESC",125 +"burnmeter_emergency_battery",1,"#BURNMETER_EMERGENCY_BATTERY","#BURNMETER_EMERGENCY_BATTERY_DESC","rui/menu/boosts/boost_battery","models/weapons_r2/burn_card/burn_card.mdl",1,0.800000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_emergency_battery","#BURNMETER_AT_BATTERY_BOOST_ACTIVATION_TEXT",125 +"burnmeter_smart_pistol",1,"#WPN_SMART_PISTOL","#WPN_SMART_PISTOL_LONGDESC","rui/menu/boosts/boost_smart_pistol","models/weapons_r2/burn_card/burn_card.mdl",2,0.600000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_smart_pistol","#WPN_SMART_PISTOL_BOOST_ACTIVATION_TEXT",125 +"burnmeter_radar_jammer",1,"#BURNMETER_RADAR_JAMMER","#BURNMETER_RADAR_JAMMER_DESC","rui/menu/boosts/boost_radar_jammer","models/weapons_r2/burn_card/burn_card.mdl",3,0.400000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_radar_jammer","#BURNMETER_RADAR_JAMMER_DESC",125 +"burnmeter_hard_cover",1,"#WPN_HARD_COVER","#WPN_HARD_COVER_DESC","rui/menu/boosts/boost_shield","models/weapons_r2/burn_card/burn_card.mdl",4,0.200000,"PILOT_ONLY","mp_weapon_hard_cover","","#WPN_HARD_COVER_DESC",125 +"burnmeter_nuke_titan",0,"#WPN_NUKE_TITAN","#WPN_NUKE_TITAN_DESC","rui/menu/boosts/boost_nuke","models/weapons_r2/burn_card/burn_card.mdl",9,0.200000,"SPECIAL_PLAYERS_ONLY","mp_ability_burncardweapon","burnmeter_nuke_titan","#WPN_NUKE_TITAN_DESC",125 +"burnmeter_harvester_shield",0,"#BURNMETER_HARVESTER_SHIELD","#BURNMETER_HARVESTER_SHIELD_DESC","rui/menu/boosts/boost_harvester","models/weapons_r2/burn_card/burn_card.mdl",9,0.200000,"SPECIAL_PLAYERS_ONLY","mp_ability_burncardweapon","burnmeter_harvester_shield","#BURNMETER_HARVESTER_SHIELD_DESC",125 +"burnmeter_arc_trap",0,"#WPN_ARC_TRAP","#WPN_ARC_TRAP_DESC","rui/menu/boosts/boost_arc_trap","models/weapons_r2/burn_card/burn_card.mdl",9,0.200000,"PILOT_ONLY","mp_weapon_arc_trap","","#WPN_ARC_TRAP_DESC",125 +"burnmeter_ap_turret_weapon_infinite",0,"#BURNMETER_AP_TURRETWEAPON_INF","#BURNMETER_AP_TURRETWEAPON_INF_DESC","rui/menu/boosts/boost_antipersonnel_sentry","models/weapons_r2/burn_card/burn_card.mdl",6,0.720000,"PILOT_ONLY","mp_ability_turretweapon","burnmeter_ap_turret_weapon_inf","#BURNMETER_AP_TURRETWEAPON_INF_DESC",125 +"burnmeter_at_turret_weapon_infinite",0,"#BURNMETER_AT_TURRETWEAPON_INF","#BURNMETER_AT_TURRETWEAPON_INF_DESC","rui/menu/boosts/boost_antititan_sentry","models/weapons_r2/burn_card/burn_card.mdl",7,0.350000,"PILOT_ONLY","mp_ability_turretweapon","burnmeter_at_turret_weapon_inf","#BURNMETER_AT_TURRETWEAPON_INF_DESC",125 +"burnmeter_rodeo_grenade",0,"#BURNMETER_SUPER_RODEO","#BURNMETER_SUPER_RODEO_DESC","rui/menu/boosts/boost_core_grenade","models/weapons_r2/burn_card/burn_card.mdl",9,0.350000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_rodeo_grenade","#BURNMETER_SUPER_RODEO_DESC",125 +"burnmeter_instant_battery",0,"#BURNMETER_INSTANT_BATTERY","#BURNMETER_INSTANT_BATTERY_DESC","rui/menu/boosts/boost_battery","models/weapons_r2/burn_card/burn_card.mdl",1,0.800000,"PILOT_ONLY","mp_ability_burncardweapon","burnmeter_emergency_battery","#BURNMETER_INSTANT_BATTERY_DESC",125 +"burnmeter_amped_weapons_permanent",0,"#BURNMETER_AMPED_WEAPONS_PERMANENT","#BURNMETER_AMPED_WEAPONS_PERMANENT_DESC","rui/menu/boosts/boost_amped_weapons","models/weapons_r2/burn_card/burn_card.mdl",0,0.800000,"PILOT_AND_TITAN","mp_ability_burncardweapon","burnmeter_amped_weapons","#BURNMETER_AMPED_WEAPONS_PERMANENT_DESC",125 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/burn_meter_store.csv b/Northstar.CustomServers/mod/scripts/datatable/burn_meter_store.csv new file mode 100644 index 00000000..2f05bfc8 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/burn_meter_store.csv @@ -0,0 +1,21 @@ +itemRef,modes,cost,extraDesc,autoActivate,storeIcon,lockedStoreIcon,extraDescFail +"burnmeter_maphack","",0,"",0,"rui/menu/boosts/boost_icon_map_hack","rui/menu/boosts/boost_icon_map_hack","" +"burnmeter_amped_weapons","",100,"#BOOST_STORE_INSTANT",1,"rui/menu/boosts/boost_icon_amped","rui/menu/boosts/boost_icon_amped","#BOOST_STORE_AMPED_FAIL" +"burnmeter_ticks","",50,"",0,"rui/menu/boosts/boost_icon_tick","rui/menu/boosts/boost_icon_tick","" +"burnmeter_random_foil","",0,"",0,"rui/menu/boosts/boost_icon_random","rui/menu/boosts/boost_icon_random","" +"burnmeter_ap_turret_weapon","",0,"",0,"rui/menu/boosts/boost_icon_personel_sentry","rui/menu/boosts/boost_icon_personel_sentry","" +"burnmeter_phase_rewind","",0,"",0,"rui/menu/boosts/boost_icon_phase_rewind","rui/menu/boosts/boost_icon_phase_rewind","" +"burnmeter_at_turret_weapon","",0,"",0,"rui/menu/boosts/boost_icon_titan_sentry","rui/menu/boosts/boost_icon_titan_sentry","" +"burnmeter_holopilot_nova","",0,"",0,"rui/menu/boosts/boost_icon_holopilot","rui/menu/boosts/boost_icon_holopilot","" +"burnmeter_emergency_battery","",0,"",0,"rui/menu/boosts/boost_icon_battery","rui/menu/boosts/boost_icon_battery","" +"burnmeter_smart_pistol","",0,"",1,"rui/menu/boosts/boost_icon_smart_pistol","rui/menu/boosts/boost_icon_smart_pistol","" +"burnmeter_radar_jammer","",0,"",0,"rui/menu/boosts/boost_icon_radar_jam","rui/menu/boosts/boost_icon_radar_jam","" +"burnmeter_hard_cover","",0,"",0,"rui/menu/boosts/boost_icon_shield","rui/menu/boosts/boost_icon_shield","" +"burnmeter_nuke_titan","",0,"",0,"rui/menu/boosts/boost_icon_nuke","rui/menu/boosts/boost_icon_nuke","" +"burnmeter_harvester_shield","fd",1200,"",1,"rui/menu/boosts/boost_icon_harvester_shield","rui/menu/boosts/locked/boost_icon_harvester_shield","#BOOST_STORE_HARVESTER_SHIELD_FAIL" +"burnmeter_arc_trap","fd",650,"",0,"rui/menu/boosts/boost_icon_arc_trap","rui/menu/boosts/locked/boost_icon_arc_trap","#BOOST_STORE_ARC_TRAP_FAIL" +"burnmeter_at_turret_weapon_infinite","",1200,"#BOOST_STORE_TURRET_LIMIT",0,"rui/menu/boosts/boost_icon_titan_sentry","rui/menu/boosts/boost_icon_titan_sentry","" +"burnmeter_ap_turret_weapon_infinite","fd",1200,"#BOOST_STORE_TURRET_LIMIT",0,"rui/menu/boosts/boost_icon_personel_sentry","rui/menu/boosts/locked/boost_icon_personel_sentry","#BOOST_STORE_TURRET_FAIL" +"burnmeter_rodeo_grenade","fd",500,"",1,"rui/menu/boosts/boost_icon_core_overload","rui/menu/boosts/locked/boost_icon_core_overload","#BOOST_STORE_RODEO_GRENADE_FAIL" +"burnmeter_instant_battery","fd",400,"#BOOST_STORE_INSTANT",1,"rui/menu/boosts/boost_icon_battery_amped","rui/menu/boosts/locked/boost_icon_battery_amped","#BOOST_STORE_BATTERY_FAIL" +"burnmeter_amped_weapons_permanent","fd",100,"#BOOST_STORE_INSTANT",1,"rui/menu/boosts/boost_icon_amped","rui/menu/boosts/locked/boost_icon_amped","#BOOST_STORE_AMPED_FAIL" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/caller_ids_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/caller_ids_mp.csv new file mode 100644 index 00000000..dcb3f5ab --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/caller_ids_mp.csv @@ -0,0 +1,2 @@ +title,image +"#FACTION_LEADER_NAME_MARVIN","rui/hud/caller_ids/caller_id_36" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/calling_cards.csv b/Northstar.CustomServers/mod/scripts/datatable/calling_cards.csv new file mode 100644 index 00000000..998e644e --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/calling_cards.csv @@ -0,0 +1,491 @@ +itemRef,name,layoutType,image,cost +"callsign_01_col","#BANNER_CALLSIGN1",0,"rui/callsigns/callsign_01_col",0 +"callsign_02_col","#BANNER_CALLSIGN2",0,"rui/callsigns/callsign_02_col",100 +"callsign_03_col","#BANNER_CALLSIGN3",0,"rui/callsigns/callsign_03_col",0 +"callsign_04_col","#BANNER_CALLSIGN4",0,"rui/callsigns/callsign_04_col",0 +"callsign_05_col","#BANNER_CALLSIGN5",0,"rui/callsigns/callsign_05_col",0 +"callsign_06_col","#BANNER_CALLSIGN6",0,"rui/callsigns/callsign_06_col",0 +"callsign_07_col","#BANNER_CALLSIGN7",0,"rui/callsigns/callsign_07_col",0 +"callsign_08_col","#BANNER_CALLSIGN8",0,"rui/callsigns/callsign_08_col",100 +"callsign_09_col","#BANNER_CALLSIGN9",0,"rui/callsigns/callsign_09_col",0 +"callsign_10_col","#BANNER_CALLSIGN10",0,"rui/callsigns/callsign_10_col",100 +"callsign_11_col","#BANNER_CALLSIGN11",0,"rui/callsigns/callsign_11_col",0 +"callsign_12_col","#BANNER_CALLSIGN12",0,"rui/callsigns/callsign_12_col",100 +"callsign_13_col","#BANNER_CALLSIGN13",0,"rui/callsigns/callsign_13_col",0 +"callsign_14_col","#BANNER_CALLSIGN14",0,"rui/callsigns/callsign_14_col",0 +"callsign_15_col","#BANNER_CALLSIGN15",0,"rui/callsigns/callsign_15_col",0 +"callsign_16_col","#BANNER_CALLSIGN16",0,"rui/callsigns/callsign_16_col",0 +"callsign_17_col","#BANNER_CALLSIGN17",0,"rui/callsigns/callsign_17_col",100 +"callsign_18_col","#BANNER_CALLSIGN18",0,"rui/callsigns/callsign_18_col",0 +"callsign_19_col","#BANNER_CALLSIGN19",0,"rui/callsigns/callsign_19_col",0 +"callsign_20_col","#BANNER_CALLSIGN20",0,"rui/callsigns/callsign_20_col",100 +"callsign_21_col","#BANNER_CALLSIGN21",0,"rui/callsigns/callsign_21_col",0 +"callsign_22_col","#BANNER_CALLSIGN22",0,"rui/callsigns/callsign_22_col",0 +"callsign_23_col","#BANNER_CALLSIGN23",0,"rui/callsigns/callsign_23_col",0 +"callsign_24_col","#BANNER_CALLSIGN24",0,"rui/callsigns/callsign_24_col",0 +"callsign_25_col","#BANNER_CALLSIGN25",0,"rui/callsigns/callsign_25_col",100 +"callsign_26_col","#BANNER_CALLSIGN26",0,"rui/callsigns/callsign_26_col",0 +"callsign_27_col","#BANNER_CALLSIGN27",0,"rui/callsigns/callsign_27_col",0 +"callsign_28_col","#BANNER_CALLSIGN28",0,"rui/callsigns/callsign_28_col",100 +"callsign_29_col","#BANNER_CALLSIGN29",0,"rui/callsigns/callsign_29_col",0 +"callsign_30_col","#BANNER_CALLSIGN30",0,"rui/callsigns/callsign_30_col",0 +"callsign_31_col","#BANNER_CALLSIGN31",0,"rui/callsigns/callsign_31_col",0 +"callsign_32_col","#BANNER_CALLSIGN32",0,"rui/callsigns/callsign_32_col",100 +"callsign_34_col","#BANNER_CALLSIGN34",0,"rui/callsigns/callsign_34_col",0 +"callsign_35_col","#BANNER_CALLSIGN35",0,"rui/callsigns/callsign_35_col",0 +"callsign_36_col","#BANNER_CALLSIGN36",0,"rui/callsigns/callsign_36_col",0 +"callsign_37_col","#BANNER_CALLSIGN37",0,"rui/callsigns/callsign_37_col",0 +"callsign_39_col","#BANNER_CALLSIGN39",0,"rui/callsigns/callsign_39_col",0 +"callsign_40_col","#BANNER_CALLSIGN40",0,"rui/callsigns/callsign_40_col",0 +"callsign_41_col","#BANNER_CALLSIGN41",0,"rui/callsigns/callsign_41_col",0 +"callsign_42_col","#BANNER_CALLSIGN42",0,"rui/callsigns/callsign_42_col",0 +"callsign_43_col","#BANNER_CALLSIGN43",0,"rui/callsigns/callsign_43_col",100 +"callsign_44_col","#BANNER_CALLSIGN44",0,"rui/callsigns/callsign_44_col",100 +"callsign_45_col","#BANNER_CALLSIGN45",0,"rui/callsigns/callsign_45_col",0 +"callsign_46_col","#BANNER_CALLSIGN46",0,"rui/callsigns/callsign_46_col",0 +"callsign_47_col","#BANNER_CALLSIGN47",0,"rui/callsigns/callsign_47_col",0 +"callsign_48_col","#BANNER_CALLSIGN48",0,"rui/callsigns/callsign_48_col",0 +"callsign_49_col","#BANNER_CALLSIGN49",0,"rui/callsigns/callsign_49_col",100 +"callsign_50_col","#BANNER_CALLSIGN50",0,"rui/callsigns/callsign_50_col",100 +"callsign_51_col","#BANNER_CALLSIGN51",0,"rui/callsigns/callsign_51_col",0 +"callsign_52_col","#BANNER_CALLSIGN52",0,"rui/callsigns/callsign_52_col",100 +"callsign_53_col","#BANNER_CALLSIGN53",0,"rui/callsigns/callsign_53_col",0 +"callsign_54_col","#BANNER_CALLSIGN54",0,"rui/callsigns/callsign_54_col",100 +"callsign_55_col","#BANNER_CALLSIGN55",0,"rui/callsigns/callsign_55_col",0 +"callsign_56_col","#BANNER_CALLSIGN56",0,"rui/callsigns/callsign_56_col",100 +"callsign_57_col","#BANNER_CALLSIGN57",0,"rui/callsigns/callsign_57_col",0 +"callsign_58_col","#BANNER_CALLSIGN58",0,"rui/callsigns/callsign_58_col",100 +"callsign_59_col","#BANNER_CALLSIGN59",0,"rui/callsigns/callsign_59_col",0 +"callsign_60_col","#BANNER_CALLSIGN60",0,"rui/callsigns/callsign_60_col",100 +"callsign_61_col","#BANNER_CALLSIGN61",0,"rui/callsigns/callsign_61_col",100 +"callsign_62_col","#BANNER_CALLSIGN62",0,"rui/callsigns/callsign_62_col",100 +"callsign_63_col","#BANNER_CALLSIGN63",0,"rui/callsigns/callsign_63_col",100 +"callsign_64_col","#BANNER_CALLSIGN64",0,"rui/callsigns/callsign_64_col",100 +"callsign_66_col","#BANNER_CALLSIGN66",0,"rui/callsigns/callsign_66_col",0 +"callsign_67_col","#BANNER_CALLSIGN67",0,"rui/callsigns/callsign_67_col",0 +"callsign_68_col","#BANNER_CALLSIGN68",0,"rui/callsigns/callsign_68_col",0 +"callsign_69_col","#BANNER_CALLSIGN69",0,"rui/callsigns/callsign_69_col",0 +"callsign_70_col","#BANNER_CALLSIGN70",0,"rui/callsigns/callsign_70_col",0 +"callsign_71_col","#BANNER_CALLSIGN71",0,"rui/callsigns/callsign_71_col",100 +"callsign_72_col","#BANNER_CALLSIGN72",0,"rui/callsigns/callsign_72_col",100 +"callsign_73_col","#BANNER_CALLSIGN73",0,"rui/callsigns/callsign_73_col",100 +"callsign_74_col","#BANNER_CALLSIGN74",0,"rui/callsigns/callsign_74_col",100 +"callsign_75_col","#BANNER_CALLSIGN75",0,"rui/callsigns/callsign_75_col",0 +"callsign_76_col","#BANNER_CALLSIGN76",0,"rui/callsigns/callsign_76_col",0 +"callsign_77_col","#BANNER_CALLSIGN77",0,"rui/callsigns/callsign_77_col",100 +"callsign_78_col","#BANNER_CALLSIGN78",0,"rui/callsigns/callsign_78_col",0 +"callsign_79_col","#BANNER_CALLSIGN79",0,"rui/callsigns/callsign_79_col",0 +"callsign_80_col","#BANNER_CALLSIGN80",0,"rui/callsigns/callsign_80_col",100 +"callsign_81_col","#BANNER_CALLSIGN81",0,"rui/callsigns/callsign_81_col",100 +"callsign_82_col","#BANNER_CALLSIGN82",0,"rui/callsigns/callsign_82_col",100 +"callsign_83_col","#BANNER_CALLSIGN83",0,"rui/callsigns/callsign_83_col",100 +"callsign_84_col","#BANNER_CALLSIGN84",0,"rui/callsigns/callsign_84_col",100 +"callsign_85_col","#BANNER_CALLSIGN85",0,"rui/callsigns/callsign_85_col",100 +"callsign_86_col","#BANNER_CALLSIGN86",0,"rui/callsigns/callsign_86_col",100 +"callsign_87_col","#BANNER_CALLSIGN87",0,"rui/callsigns/callsign_87_col",100 +"callsign_88_col","#BANNER_CALLSIGN88",0,"rui/callsigns/callsign_88_col",100 +"callsign_89_col","#BANNER_CALLSIGN89",0,"rui/callsigns/callsign_89_col",100 +"callsign_90_col","#BANNER_CALLSIGN90",0,"rui/callsigns/callsign_90_col",100 +"callsign_91_col","#BANNER_CALLSIGN91",0,"rui/callsigns/callsign_91_col",100 +"callsign_92_col","#BANNER_CALLSIGN92",0,"rui/callsigns/callsign_92_col",0 +"callsign_93_col","#BANNER_CALLSIGN93",0,"rui/callsigns/callsign_93_col",100 +"callsign_94_col","#BANNER_CALLSIGN94",0,"rui/callsigns/callsign_94_col",0 +"callsign_95_col","#BANNER_CALLSIGN95",0,"rui/callsigns/callsign_95_col",100 +"callsign_96_col","#BANNER_CALLSIGN96",0,"rui/callsigns/callsign_96_col",0 +"callsign_97_col","#BANNER_CALLSIGN97",0,"rui/callsigns/callsign_97_col",0 +"callsign_98_col","#BANNER_CALLSIGN98",0,"rui/callsigns/callsign_98_col",100 +"callsign_99_col","#BANNER_CALLSIGN99",0,"rui/callsigns/callsign_99_col",0 +"callsign_100_col","#BANNER_CALLSIGN100",0,"rui/callsigns/callsign_100_col",0 +"callsign_101_col","#BANNER_CALLSIGN101",0,"rui/callsigns/callsign_101_col",100 +"callsign_102_col","#BANNER_CALLSIGN102",0,"rui/callsigns/callsign_102_col",100 +"callsign_103_col","#BANNER_CALLSIGN103",0,"rui/callsigns/callsign_103_col",0 +"callsign_104_col","#BANNER_CALLSIGN104",0,"rui/callsigns/callsign_104_col",0 +"callsign_02_col_prism","#BANNER_PRISM_CALLSIGN2",1,"rui/callsigns/callsign_02_col",250 +"callsign_08_col_prism","#BANNER_PRISM_CALLSIGN8",1,"rui/callsigns/callsign_08_col",250 +"callsign_10_col_prism","#BANNER_PRISM_CALLSIGN10",1,"rui/callsigns/callsign_10_col",250 +"callsign_12_col_prism","#BANNER_PRISM_CALLSIGN12",1,"rui/callsigns/callsign_12_col",250 +"callsign_17_col_prism","#BANNER_PRISM_CALLSIGN17",1,"rui/callsigns/callsign_17_col",250 +"callsign_20_col_prism","#BANNER_PRISM_CALLSIGN20",1,"rui/callsigns/callsign_20_col",250 +"callsign_25_col_prism","#BANNER_PRISM_CALLSIGN25",1,"rui/callsigns/callsign_25_col",250 +"callsign_28_col_prism","#BANNER_PRISM_CALLSIGN28",1,"rui/callsigns/callsign_28_col",250 +"callsign_32_col_prism","#BANNER_PRISM_CALLSIGN32",1,"rui/callsigns/callsign_32_col",250 +"callsign_43_col_prism","#BANNER_PRISM_CALLSIGN43",1,"rui/callsigns/callsign_43_col",250 +"callsign_44_col_prism","#BANNER_PRISM_CALLSIGN44",1,"rui/callsigns/callsign_44_col",250 +"callsign_49_col_prism","#BANNER_PRISM_CALLSIGN49",1,"rui/callsigns/callsign_49_col",250 +"callsign_50_col_prism","#BANNER_PRISM_CALLSIGN50",1,"rui/callsigns/callsign_50_col",250 +"callsign_52_col_prism","#BANNER_PRISM_CALLSIGN52",1,"rui/callsigns/callsign_52_col",250 +"callsign_54_col_prism","#BANNER_PRISM_CALLSIGN54",1,"rui/callsigns/callsign_54_col",250 +"callsign_56_col_prism","#BANNER_PRISM_CALLSIGN56",1,"rui/callsigns/callsign_56_col",250 +"callsign_58_col_prism","#BANNER_PRISM_CALLSIGN58",1,"rui/callsigns/callsign_58_col",250 +"callsign_60_col_prism","#BANNER_PRISM_CALLSIGN60",1,"rui/callsigns/callsign_60_col",250 +"callsign_61_col_prism","#BANNER_PRISM_CALLSIGN61",1,"rui/callsigns/callsign_61_col",250 +"callsign_62_col_prism","#BANNER_PRISM_CALLSIGN62",1,"rui/callsigns/callsign_62_col",250 +"callsign_63_col_prism","#BANNER_PRISM_CALLSIGN63",1,"rui/callsigns/callsign_63_col",250 +"callsign_64_col_prism","#BANNER_PRISM_CALLSIGN64",1,"rui/callsigns/callsign_64_col",250 +"callsign_71_col_prism","#BANNER_PRISM_CALLSIGN71",1,"rui/callsigns/callsign_71_col",250 +"callsign_72_col_prism","#BANNER_PRISM_CALLSIGN72",1,"rui/callsigns/callsign_72_col",250 +"callsign_73_col_prism","#BANNER_PRISM_CALLSIGN73",1,"rui/callsigns/callsign_73_col",250 +"callsign_74_col_prism","#BANNER_PRISM_CALLSIGN74",1,"rui/callsigns/callsign_74_col",250 +"callsign_77_col_prism","#BANNER_PRISM_CALLSIGN77",1,"rui/callsigns/callsign_77_col",250 +"callsign_80_col_prism","#BANNER_PRISM_CALLSIGN80",1,"rui/callsigns/callsign_80_col",250 +"callsign_81_col_prism","#BANNER_PRISM_CALLSIGN81",1,"rui/callsigns/callsign_81_col",250 +"callsign_82_col_prism","#BANNER_PRISM_CALLSIGN82",1,"rui/callsigns/callsign_82_col",250 +"callsign_83_col_prism","#BANNER_PRISM_CALLSIGN83",1,"rui/callsigns/callsign_83_col",250 +"callsign_84_col_prism","#BANNER_PRISM_CALLSIGN84",1,"rui/callsigns/callsign_84_col",250 +"callsign_85_col_prism","#BANNER_PRISM_CALLSIGN85",1,"rui/callsigns/callsign_85_col",250 +"callsign_86_col_prism","#BANNER_PRISM_CALLSIGN86",1,"rui/callsigns/callsign_86_col",250 +"callsign_87_col_prism","#BANNER_PRISM_CALLSIGN87",1,"rui/callsigns/callsign_87_col",250 +"callsign_88_col_prism","#BANNER_PRISM_CALLSIGN88",1,"rui/callsigns/callsign_88_col",250 +"callsign_89_col_prism","#BANNER_PRISM_CALLSIGN89",1,"rui/callsigns/callsign_89_col",250 +"callsign_90_col_prism","#BANNER_PRISM_CALLSIGN90",1,"rui/callsigns/callsign_90_col",250 +"callsign_91_col_prism","#BANNER_PRISM_CALLSIGN91",1,"rui/callsigns/callsign_91_col",250 +"callsign_93_col_prism","#BANNER_PRISM_CALLSIGN93",1,"rui/callsigns/callsign_93_col",250 +"callsign_95_col_prism","#BANNER_PRISM_CALLSIGN95",1,"rui/callsigns/callsign_95_col",250 +"callsign_98_col_prism","#BANNER_PRISM_CALLSIGN98",1,"rui/callsigns/callsign_98_col",250 +"callsign_101_col_prism","#BANNER_PRISM_CALLSIGN101",1,"rui/callsigns/callsign_101_col",250 +"callsign_102_col_prism","#BANNER_PRISM_CALLSIGN102",1,"rui/callsigns/callsign_102_col",250 +"callsign_16_col_gold","#BANNER_GOLD_CALLSIGN16",2,"rui/callsigns/callsign_16_col",0 +"callsign_01_col_gold","#BANNER_GOLD_CALLSIGN1",2,"rui/callsigns/callsign_01_col",0 +"callsign_03_col_gold","#BANNER_GOLD_CALLSIGN3",2,"rui/callsigns/callsign_03_col",0 +"callsign_04_col_gold","#BANNER_GOLD_CALLSIGN4",2,"rui/callsigns/callsign_04_col",0 +"callsign_05_col_gold","#BANNER_GOLD_CALLSIGN5",2,"rui/callsigns/callsign_05_col",0 +"callsign_06_col_gold","#BANNER_GOLD_CALLSIGN6",2,"rui/callsigns/callsign_06_col",0 +"callsign_07_col_gold","#BANNER_GOLD_CALLSIGN7",2,"rui/callsigns/callsign_07_col",0 +"callsign_09_col_gold","#BANNER_GOLD_CALLSIGN9",2,"rui/callsigns/callsign_09_col",0 +"callsign_11_col_gold","#BANNER_GOLD_CALLSIGN11",2,"rui/callsigns/callsign_11_col",0 +"callsign_13_col_gold","#BANNER_GOLD_CALLSIGN13",2,"rui/callsigns/callsign_13_col",0 +"callsign_14_col_gold","#BANNER_GOLD_CALLSIGN14",2,"rui/callsigns/callsign_14_col",0 +"callsign_15_col_gold","#BANNER_GOLD_CALLSIGN15",2,"rui/callsigns/callsign_15_col",0 +"callsign_18_col_gold","#BANNER_GOLD_CALLSIGN18",2,"rui/callsigns/callsign_18_col",0 +"callsign_19_col_gold","#BANNER_GOLD_CALLSIGN19",2,"rui/callsigns/callsign_19_col",0 +"callsign_21_col_gold","#BANNER_GOLD_CALLSIGN21",2,"rui/callsigns/callsign_21_col",0 +"callsign_22_col_gold","#BANNER_GOLD_CALLSIGN22",2,"rui/callsigns/callsign_22_col",0 +"callsign_23_col_gold","#BANNER_GOLD_CALLSIGN23",2,"rui/callsigns/callsign_23_col",0 +"callsign_24_col_gold","#BANNER_GOLD_CALLSIGN24",2,"rui/callsigns/callsign_24_col",0 +"callsign_26_col_gold","#BANNER_GOLD_CALLSIGN26",2,"rui/callsigns/callsign_26_col",0 +"callsign_27_col_gold","#BANNER_GOLD_CALLSIGN27",2,"rui/callsigns/callsign_27_col",0 +"callsign_29_col_gold","#BANNER_GOLD_CALLSIGN29",2,"rui/callsigns/callsign_29_col",0 +"callsign_30_col_gold","#BANNER_GOLD_CALLSIGN30",2,"rui/callsigns/callsign_30_col",0 +"callsign_31_col_gold","#BANNER_GOLD_CALLSIGN31",2,"rui/callsigns/callsign_31_col",0 +"callsign_33_col_gold","#BANNER_GOLD_CALLSIGN33",2,"rui/callsigns/callsign_33_col",0 +"callsign_34_col_gold","#BANNER_GOLD_CALLSIGN34",2,"rui/callsigns/callsign_34_col",0 +"callsign_35_col_gold","#BANNER_GOLD_CALLSIGN35",2,"rui/callsigns/callsign_35_col",0 +"callsign_36_col_gold","#BANNER_GOLD_CALLSIGN36",2,"rui/callsigns/callsign_36_col",0 +"callsign_37_col_gold","#BANNER_GOLD_CALLSIGN37",2,"rui/callsigns/callsign_37_col",0 +"callsign_38_col_gold","#BANNER_GOLD_CALLSIGN38",2,"rui/callsigns/callsign_38_col",0 +"callsign_39_col_gold","#BANNER_GOLD_CALLSIGN39",2,"rui/callsigns/callsign_39_col",0 +"callsign_40_col_gold","#BANNER_GOLD_CALLSIGN40",2,"rui/callsigns/callsign_40_col",0 +"callsign_41_col_gold","#BANNER_GOLD_CALLSIGN41",2,"rui/callsigns/callsign_41_col",0 +"callsign_42_col_gold","#BANNER_GOLD_CALLSIGN42",2,"rui/callsigns/callsign_42_col",0 +"callsign_45_col_gold","#BANNER_GOLD_CALLSIGN45",2,"rui/callsigns/callsign_45_col",0 +"callsign_46_col_gold","#BANNER_GOLD_CALLSIGN46",2,"rui/callsigns/callsign_46_col",0 +"callsign_47_col_gold","#BANNER_GOLD_CALLSIGN47",2,"rui/callsigns/callsign_47_col",0 +"callsign_48_col_gold","#BANNER_GOLD_CALLSIGN48",2,"rui/callsigns/callsign_48_col",0 +"callsign_51_col_gold","#BANNER_GOLD_CALLSIGN51",2,"rui/callsigns/callsign_51_col",0 +"callsign_53_col_gold","#BANNER_GOLD_CALLSIGN53",2,"rui/callsigns/callsign_53_col",0 +"callsign_55_col_gold","#BANNER_GOLD_CALLSIGN55",2,"rui/callsigns/callsign_55_col",0 +"callsign_57_col_gold","#BANNER_GOLD_CALLSIGN57",2,"rui/callsigns/callsign_57_col",0 +"callsign_59_col_gold","#BANNER_GOLD_CALLSIGN59",2,"rui/callsigns/callsign_59_col",0 +"callsign_65_col_gold","#BANNER_GOLD_CALLSIGN65",2,"rui/callsigns/callsign_65_col",0 +"callsign_66_col_gold","#BANNER_GOLD_CALLSIGN66",2,"rui/callsigns/callsign_66_col",0 +"callsign_67_col_gold","#BANNER_GOLD_CALLSIGN67",2,"rui/callsigns/callsign_67_col",0 +"callsign_68_col_gold","#BANNER_GOLD_CALLSIGN68",2,"rui/callsigns/callsign_68_col",0 +"callsign_69_col_gold","#BANNER_GOLD_CALLSIGN69",2,"rui/callsigns/callsign_69_col",0 +"callsign_70_col_gold","#BANNER_GOLD_CALLSIGN70",2,"rui/callsigns/callsign_70_col",0 +"callsign_71_col_gold","#BANNER_GOLD_CALLSIGN71",2,"rui/callsigns/callsign_71_col",0 +"callsign_75_col_gold","#BANNER_GOLD_CALLSIGN75",2,"rui/callsigns/callsign_75_col",0 +"callsign_76_col_gold","#BANNER_GOLD_CALLSIGN76",2,"rui/callsigns/callsign_76_col",0 +"callsign_78_col_gold","#BANNER_GOLD_CALLSIGN78",2,"rui/callsigns/callsign_78_col",0 +"callsign_79_col_gold","#BANNER_GOLD_CALLSIGN79",2,"rui/callsigns/callsign_79_col",0 +"callsign_92_col_gold","#BANNER_GOLD_CALLSIGN92",2,"rui/callsigns/callsign_92_col",0 +"callsign_94_col_gold","#BANNER_GOLD_CALLSIGN94",2,"rui/callsigns/callsign_94_col",0 +"callsign_96_col_gold","#BANNER_GOLD_CALLSIGN96",2,"rui/callsigns/callsign_96_col",0 +"callsign_97_col_gold","#BANNER_GOLD_CALLSIGN97",2,"rui/callsigns/callsign_97_col",0 +"callsign_99_col_gold","#BANNER_GOLD_CALLSIGN99",2,"rui/callsigns/callsign_99_col",0 +"callsign_100_col_gold","#BANNER_GOLD_CALLSIGN100",2,"rui/callsigns/callsign_100_col",0 +"callsign_103_col_gold","#BANNER_GOLD_CALLSIGN103",2,"rui/callsigns/callsign_103_col",0 +"callsign_104_col_gold","#BANNER_GOLD_CALLSIGN104",2,"rui/callsigns/callsign_104_col",0 +"callsign_105_col_gold","#BANNER_GOLD_CALLSIGN105",2,"rui/callsigns/callsign_105_col",0 +"callsign_16_col_fire","#BANNER_FIRE_CALLSIGN16",3,"rui/callsigns/callsign_16_col",0 +"callsign_01_col_fire","#BANNER_FIRE_CALLSIGN1",3,"rui/callsigns/callsign_01_col",0 +"callsign_03_col_fire","#BANNER_FIRE_CALLSIGN3",3,"rui/callsigns/callsign_03_col",0 +"callsign_04_col_fire","#BANNER_FIRE_CALLSIGN4",3,"rui/callsigns/callsign_04_col",0 +"callsign_05_col_fire","#BANNER_FIRE_CALLSIGN5",3,"rui/callsigns/callsign_05_col",0 +"callsign_06_col_fire","#BANNER_FIRE_CALLSIGN6",3,"rui/callsigns/callsign_06_col",0 +"callsign_07_col_fire","#BANNER_FIRE_CALLSIGN7",3,"rui/callsigns/callsign_07_col",0 +"callsign_09_col_fire","#BANNER_FIRE_CALLSIGN9",3,"rui/callsigns/callsign_09_col",0 +"callsign_11_col_fire","#BANNER_FIRE_CALLSIGN11",3,"rui/callsigns/callsign_11_col",0 +"callsign_13_col_fire","#BANNER_FIRE_CALLSIGN13",3,"rui/callsigns/callsign_13_col",0 +"callsign_14_col_fire","#BANNER_FIRE_CALLSIGN14",3,"rui/callsigns/callsign_14_col",0 +"callsign_15_col_fire","#BANNER_FIRE_CALLSIGN15",3,"rui/callsigns/callsign_15_col",0 +"callsign_18_col_fire","#BANNER_FIRE_CALLSIGN18",3,"rui/callsigns/callsign_18_col",0 +"callsign_19_col_fire","#BANNER_FIRE_CALLSIGN19",3,"rui/callsigns/callsign_19_col",0 +"callsign_21_col_fire","#BANNER_FIRE_CALLSIGN21",3,"rui/callsigns/callsign_21_col",0 +"callsign_22_col_fire","#BANNER_FIRE_CALLSIGN22",3,"rui/callsigns/callsign_22_col",0 +"callsign_23_col_fire","#BANNER_FIRE_CALLSIGN23",3,"rui/callsigns/callsign_23_col",0 +"callsign_24_col_fire","#BANNER_FIRE_CALLSIGN24",3,"rui/callsigns/callsign_24_col",0 +"callsign_26_col_fire","#BANNER_FIRE_CALLSIGN26",3,"rui/callsigns/callsign_26_col",0 +"callsign_27_col_fire","#BANNER_FIRE_CALLSIGN27",3,"rui/callsigns/callsign_27_col",0 +"callsign_29_col_fire","#BANNER_FIRE_CALLSIGN29",3,"rui/callsigns/callsign_29_col",0 +"callsign_30_col_fire","#BANNER_FIRE_CALLSIGN30",3,"rui/callsigns/callsign_30_col",0 +"callsign_31_col_fire","#BANNER_FIRE_CALLSIGN31",3,"rui/callsigns/callsign_31_col",0 +"callsign_34_col_fire","#BANNER_FIRE_CALLSIGN34",3,"rui/callsigns/callsign_34_col",0 +"callsign_35_col_fire","#BANNER_FIRE_CALLSIGN35",3,"rui/callsigns/callsign_35_col",0 +"callsign_36_col_fire","#BANNER_FIRE_CALLSIGN36",3,"rui/callsigns/callsign_36_col",0 +"callsign_37_col_fire","#BANNER_FIRE_CALLSIGN37",3,"rui/callsigns/callsign_37_col",0 +"callsign_39_col_fire","#BANNER_FIRE_CALLSIGN39",3,"rui/callsigns/callsign_39_col",0 +"callsign_40_col_fire","#BANNER_FIRE_CALLSIGN40",3,"rui/callsigns/callsign_40_col",0 +"callsign_41_col_fire","#BANNER_FIRE_CALLSIGN41",3,"rui/callsigns/callsign_41_col",0 +"callsign_42_col_fire","#BANNER_FIRE_CALLSIGN42",3,"rui/callsigns/callsign_42_col",0 +"callsign_45_col_fire","#BANNER_FIRE_CALLSIGN45",3,"rui/callsigns/callsign_45_col",0 +"callsign_46_col_fire","#BANNER_FIRE_CALLSIGN46",3,"rui/callsigns/callsign_46_col",0 +"callsign_47_col_fire","#BANNER_FIRE_CALLSIGN47",3,"rui/callsigns/callsign_47_col",0 +"callsign_48_col_fire","#BANNER_FIRE_CALLSIGN48",3,"rui/callsigns/callsign_48_col",0 +"callsign_51_col_fire","#BANNER_FIRE_CALLSIGN51",3,"rui/callsigns/callsign_51_col",0 +"callsign_53_col_fire","#BANNER_FIRE_CALLSIGN53",3,"rui/callsigns/callsign_53_col",0 +"callsign_55_col_fire","#BANNER_FIRE_CALLSIGN55",3,"rui/callsigns/callsign_55_col",0 +"callsign_57_col_fire","#BANNER_FIRE_CALLSIGN57",3,"rui/callsigns/callsign_57_col",0 +"callsign_59_col_fire","#BANNER_FIRE_CALLSIGN59",3,"rui/callsigns/callsign_59_col",0 +"callsign_66_col_fire","#BANNER_FIRE_CALLSIGN66",3,"rui/callsigns/callsign_66_col",0 +"callsign_67_col_fire","#BANNER_FIRE_CALLSIGN67",3,"rui/callsigns/callsign_67_col",0 +"callsign_68_col_fire","#BANNER_FIRE_CALLSIGN68",3,"rui/callsigns/callsign_68_col",0 +"callsign_69_col_fire","#BANNER_FIRE_CALLSIGN69",3,"rui/callsigns/callsign_69_col",0 +"callsign_70_col_fire","#BANNER_FIRE_CALLSIGN70",3,"rui/callsigns/callsign_70_col",0 +"callsign_75_col_fire","#BANNER_FIRE_CALLSIGN75",3,"rui/callsigns/callsign_75_col",0 +"callsign_76_col_fire","#BANNER_FIRE_CALLSIGN76",3,"rui/callsigns/callsign_76_col",0 +"callsign_78_col_fire","#BANNER_FIRE_CALLSIGN78",3,"rui/callsigns/callsign_78_col",0 +"callsign_79_col_fire","#BANNER_FIRE_CALLSIGN79",3,"rui/callsigns/callsign_79_col",0 +"callsign_92_col_fire","#BANNER_FIRE_CALLSIGN92",3,"rui/callsigns/callsign_92_col",0 +"callsign_94_col_fire","#BANNER_FIRE_CALLSIGN94",3,"rui/callsigns/callsign_94_col",0 +"callsign_96_col_fire","#BANNER_FIRE_CALLSIGN96",3,"rui/callsigns/callsign_96_col",0 +"callsign_97_col_fire","#BANNER_FIRE_CALLSIGN97",3,"rui/callsigns/callsign_97_col",0 +"callsign_99_col_fire","#BANNER_FIRE_CALLSIGN99",3,"rui/callsigns/callsign_99_col",0 +"callsign_100_col_fire","#BANNER_FIRE_CALLSIGN100",3,"rui/callsigns/callsign_100_col",0 +"callsign_103_col_fire","#BANNER_FIRE_CALLSIGN103",3,"rui/callsigns/callsign_103_col",0 +"callsign_104_col_fire","#BANNER_FIRE_CALLSIGN104",3,"rui/callsigns/callsign_104_col",0 +"callsign_106_col","#BANNER_CALLSIGN106",0,"rui/callsigns/callsign_106_col",0 +"callsign_107_col","#BANNER_CALLSIGN107",0,"rui/callsigns/callsign_107_col",0 +"callsign_108_col","#BANNER_CALLSIGN108",0,"rui/callsigns/callsign_108_col",0 +"callsign_109_col","#BANNER_CALLSIGN109",0,"rui/callsigns/callsign_109_col",0 +"callsign_110_col","#BANNER_CALLSIGN110",0,"rui/callsigns/callsign_110_col",0 +"callsign_111_col","#BANNER_CALLSIGN111",0,"rui/callsigns/callsign_111_col",0 +"callsign_112_col","#BANNER_CALLSIGN112",0,"rui/callsigns/callsign_112_col",0 +"callsign_113_col","#BANNER_CALLSIGN113",0,"rui/callsigns/callsign_113_col",0 +"callsign_114_col","#BANNER_CALLSIGN114",0,"rui/callsigns/callsign_114_col",0 +"callsign_115_col","#BANNER_CALLSIGN115",0,"rui/callsigns/callsign_115_col",0 +"callsign_116_col","#BANNER_CALLSIGN116",0,"rui/callsigns/callsign_116_col",0 +"callsign_117_col","#BANNER_CALLSIGN117",0,"rui/callsigns/callsign_117_col",0 +"callsign_118_col","#BANNER_CALLSIGN118",0,"rui/callsigns/callsign_118_col",0 +"callsign_119_col","#BANNER_CALLSIGN119",0,"rui/callsigns/callsign_119_col",0 +"callsign_120_col","#BANNER_CALLSIGN120",0,"rui/callsigns/callsign_120_col",0 +"callsign_121_col","#BANNER_CALLSIGN121",0,"rui/callsigns/callsign_121_col",0 +"callsign_122_col","#BANNER_CALLSIGN122",0,"rui/callsigns/callsign_122_col",0 +"callsign_123_col","#BANNER_CALLSIGN123",0,"rui/callsigns/callsign_123_col",0 +"callsign_124_col","#BANNER_CALLSIGN124",0,"rui/callsigns/callsign_124_col",0 +"callsign_125_col","#BANNER_CALLSIGN125",0,"rui/callsigns/callsign_125_col",0 +"callsign_139_col","#BANNER_CALLSIGN139",0,"rui/callsigns/callsign_139_col",0 +"callsign_139_col_fire","#BANNER_FIRE_CALLSIGN139",3,"rui/callsigns/callsign_139_col",0 +"callsign_139_col_gold","#BANNER_GOLD_CALLSIGN139",2,"rui/callsigns/callsign_139_col",0 +"callsign_126_col","#BANNER_CALLSIGN126",0,"rui/callsigns/callsign_126_col",0 +"callsign_127_col","#BANNER_CALLSIGN127",0,"rui/callsigns/callsign_127_col",0 +"callsign_128_col","#BANNER_CALLSIGN128",0,"rui/callsigns/callsign_128_col",0 +"callsign_129_col","#BANNER_CALLSIGN129",0,"rui/callsigns/callsign_129_col",0 +"callsign_130_col","#BANNER_CALLSIGN130",0,"rui/callsigns/callsign_130_col",0 +"callsign_131_col","#BANNER_CALLSIGN131",0,"rui/callsigns/callsign_131_col",0 +"callsign_132_col","#BANNER_CALLSIGN132",0,"rui/callsigns/callsign_132_col",0 +"callsign_133_col","#BANNER_CALLSIGN133",0,"rui/callsigns/callsign_133_col",0 +"callsign_134_col","#BANNER_CALLSIGN134",0,"rui/callsigns/callsign_134_col",0 +"callsign_135_col","#BANNER_CALLSIGN135",0,"rui/callsigns/callsign_135_col",0 +"callsign_136_col","#BANNER_CALLSIGN136",0,"rui/callsigns/callsign_136_col",0 +"callsign_137_col","#BANNER_CALLSIGN137",0,"rui/callsigns/callsign_137_col",0 +"callsign_138_col","#BANNER_CALLSIGN138",0,"rui/callsigns/callsign_138_col",0 +"callsign_125_col_fire","#BANNER_FIRE_CALLSIGN125",3,"rui/callsigns/callsign_125_col",0 +"callsign_126_col_fire","#BANNER_FIRE_CALLSIGN126",3,"rui/callsigns/callsign_126_col",0 +"callsign_127_col_fire","#BANNER_FIRE_CALLSIGN127",3,"rui/callsigns/callsign_127_col",0 +"callsign_128_col_fire","#BANNER_FIRE_CALLSIGN128",3,"rui/callsigns/callsign_128_col",0 +"callsign_129_col_fire","#BANNER_FIRE_CALLSIGN129",3,"rui/callsigns/callsign_129_col",0 +"callsign_130_col_fire","#BANNER_FIRE_CALLSIGN130",3,"rui/callsigns/callsign_130_col",0 +"callsign_131_col_fire","#BANNER_FIRE_CALLSIGN131",3,"rui/callsigns/callsign_131_col",0 +"callsign_132_col_fire","#BANNER_FIRE_CALLSIGN132",3,"rui/callsigns/callsign_132_col",0 +"callsign_133_col_fire","#BANNER_FIRE_CALLSIGN133",3,"rui/callsigns/callsign_133_col",0 +"callsign_134_col_fire","#BANNER_FIRE_CALLSIGN134",3,"rui/callsigns/callsign_134_col",0 +"callsign_135_col_fire","#BANNER_FIRE_CALLSIGN135",3,"rui/callsigns/callsign_135_col",0 +"callsign_136_col_fire","#BANNER_FIRE_CALLSIGN136",3,"rui/callsigns/callsign_136_col",0 +"callsign_137_col_fire","#BANNER_FIRE_CALLSIGN137",3,"rui/callsigns/callsign_137_col",0 +"callsign_138_col_fire","#BANNER_FIRE_CALLSIGN138",3,"rui/callsigns/callsign_138_col",0 +"callsign_125_col_gold","#BANNER_GOLD_CALLSIGN125",2,"rui/callsigns/callsign_125_col",0 +"callsign_126_col_gold","#BANNER_GOLD_CALLSIGN126",2,"rui/callsigns/callsign_126_col",0 +"callsign_127_col_gold","#BANNER_GOLD_CALLSIGN127",2,"rui/callsigns/callsign_127_col",0 +"callsign_128_col_gold","#BANNER_GOLD_CALLSIGN128",2,"rui/callsigns/callsign_128_col",0 +"callsign_129_col_gold","#BANNER_GOLD_CALLSIGN129",2,"rui/callsigns/callsign_129_col",0 +"callsign_130_col_gold","#BANNER_GOLD_CALLSIGN130",2,"rui/callsigns/callsign_130_col",0 +"callsign_131_col_gold","#BANNER_GOLD_CALLSIGN131",2,"rui/callsigns/callsign_131_col",0 +"callsign_132_col_gold","#BANNER_GOLD_CALLSIGN132",2,"rui/callsigns/callsign_132_col",0 +"callsign_133_col_gold","#BANNER_GOLD_CALLSIGN133",2,"rui/callsigns/callsign_133_col",0 +"callsign_134_col_gold","#BANNER_GOLD_CALLSIGN134",2,"rui/callsigns/callsign_134_col",0 +"callsign_135_col_gold","#BANNER_GOLD_CALLSIGN135",2,"rui/callsigns/callsign_135_col",0 +"callsign_136_col_gold","#BANNER_GOLD_CALLSIGN136",2,"rui/callsigns/callsign_136_col",0 +"callsign_137_col_gold","#BANNER_GOLD_CALLSIGN137",2,"rui/callsigns/callsign_137_col",0 +"callsign_138_col_gold","#BANNER_GOLD_CALLSIGN138",2,"rui/callsigns/callsign_138_col",0 +"callsign_125_col_prism","#BANNER_PRISM_CALLSIGN125",1,"rui/callsigns/callsign_125_col",0 +"callsign_126_col_prism","#BANNER_PRISM_CALLSIGN126",1,"rui/callsigns/callsign_126_col",1500 +"callsign_127_col_prism","#BANNER_PRISM_CALLSIGN127",1,"rui/callsigns/callsign_127_col",1500 +"callsign_128_col_prism","#BANNER_PRISM_CALLSIGN128",1,"rui/callsigns/callsign_128_col",0 +"callsign_129_col_prism","#BANNER_PRISM_CALLSIGN129",1,"rui/callsigns/callsign_129_col",0 +"callsign_130_col_prism","#BANNER_PRISM_CALLSIGN130",1,"rui/callsigns/callsign_130_col",1500 +"callsign_131_col_prism","#BANNER_PRISM_CALLSIGN131",1,"rui/callsigns/callsign_131_col",1500 +"callsign_132_col_prism","#BANNER_PRISM_CALLSIGN132",1,"rui/callsigns/callsign_132_col",0 +"callsign_133_col_prism","#BANNER_PRISM_CALLSIGN133",1,"rui/callsigns/callsign_133_col",0 +"callsign_134_col_prism","#BANNER_PRISM_CALLSIGN134",1,"rui/callsigns/callsign_134_col",0 +"callsign_135_col_prism","#BANNER_PRISM_CALLSIGN135",1,"rui/callsigns/callsign_135_col",0 +"callsign_136_col_prism","#BANNER_PRISM_CALLSIGN136",1,"rui/callsigns/callsign_136_col",0 +"callsign_137_col_prism","#BANNER_PRISM_CALLSIGN137",1,"rui/callsigns/callsign_137_col",0 +"callsign_138_col_prism","#BANNER_PRISM_CALLSIGN138",1,"rui/callsigns/callsign_138_col",0 +"callsign_140_col","#BANNER_CALLSIGN140",0,"rui/callsigns/callsign_140_col",0 +"callsign_141_col","#BANNER_CALLSIGN141",0,"rui/callsigns/callsign_141_col",0 +"callsign_142_col","#BANNER_CALLSIGN142",0,"rui/callsigns/callsign_142_col",0 +"callsign_140_col_fire","#BANNER_FIRE_CALLSIGN140",3,"rui/callsigns/callsign_140_col",0 +"callsign_141_col_fire","#BANNER_FIRE_CALLSIGN141",3,"rui/callsigns/callsign_141_col",0 +"callsign_142_col_fire","#BANNER_FIRE_CALLSIGN142",3,"rui/callsigns/callsign_142_col",0 +"callsign_140_col_gold","#BANNER_GOLD_CALLSIGN140",2,"rui/callsigns/callsign_140_col",0 +"callsign_141_col_gold","#BANNER_GOLD_CALLSIGN141",2,"rui/callsigns/callsign_141_col",0 +"callsign_142_col_gold","#BANNER_GOLD_CALLSIGN142",2,"rui/callsigns/callsign_142_col",0 +"callsign_143_col","#BANNER_CALLSIGN143",0,"rui/callsigns/callsign_143_col",0 +"callsign_144_col","#BANNER_CALLSIGN144",0,"rui/callsigns/callsign_144_col",0 +"callsign_145_col","#BANNER_CALLSIGN145",0,"rui/callsigns/callsign_145_col",0 +"callsign_146_col","#BANNER_CALLSIGN146",0,"rui/callsigns/callsign_146_col",0 +"callsign_147_col","#BANNER_CALLSIGN147",0,"rui/callsigns/callsign_147_col",0 +"callsign_148_col","#BANNER_CALLSIGN148",0,"rui/callsigns/callsign_148_col",0 +"callsign_149_col","#BANNER_CALLSIGN149",0,"rui/callsigns/callsign_149_col",0 +"callsign_150_col","#BANNER_CALLSIGN150",0,"rui/callsigns/callsign_150_col",0 +"callsign_151_col","#BANNER_CALLSIGN151",0,"rui/callsigns/callsign_151_col",0 +"callsign_152_col","#BANNER_CALLSIGN152",0,"rui/callsigns/callsign_152_col",0 +"callsign_153_col","#BANNER_CALLSIGN153",0,"rui/callsigns/callsign_153_col",0 +"callsign_154_col","#BANNER_CALLSIGN154",0,"rui/callsigns/callsign_154_col",0 +"callsign_155_col","#BANNER_CALLSIGN155",0,"rui/callsigns/callsign_155_col",0 +"callsign_156_col","#BANNER_CALLSIGN156",0,"rui/callsigns/callsign_156_col",0 +"callsign_157_col","#BANNER_CALLSIGN157",0,"rui/callsigns/callsign_157_col",0 +"callsign_158_col","#BANNER_CALLSIGN158",0,"rui/callsigns/callsign_158_col",0 +"callsign_159_col","#BANNER_CALLSIGN159",0,"rui/callsigns/callsign_159_col",0 +"callsign_160_col","#BANNER_CALLSIGN160",0,"rui/callsigns/callsign_160_col",0 +"callsign_161_col","#BANNER_CALLSIGN161",0,"rui/callsigns/callsign_161_col",0 +"callsign_162_col","#BANNER_CALLSIGN162",0,"rui/callsigns/callsign_162_col",0 +"callsign_163_col","#BANNER_CALLSIGN163",0,"rui/callsigns/callsign_163_col",0 +"callsign_164_col","#BANNER_CALLSIGN164",0,"rui/callsigns/callsign_164_col",0 +"callsign_163_col_prism","#BANNER_PRISM_CALLSIGN163",1,"rui/callsigns/callsign_163_col",0 +"callsign_164_col_prism","#BANNER_PRISM_CALLSIGN164",1,"rui/callsigns/callsign_164_col",0 +"callsign_163_col_gold","#BANNER_GOLD_CALLSIGN163",2,"rui/callsigns/callsign_163_col",0 +"callsign_164_col_gold","#BANNER_GOLD_CALLSIGN164",2,"rui/callsigns/callsign_164_col",0 +"callsign_163_col_fire","#BANNER_FIRE_CALLSIGN163",3,"rui/callsigns/callsign_163_col",0 +"callsign_164_col_fire","#BANNER_FIRE_CALLSIGN164",3,"rui/callsigns/callsign_164_col",0 +"callsign_regen_10_col","#BANNER_REGEN_10",0,"rui/callsigns/callsign_regen_10_col",0 +"callsign_regen_20_col","#BANNER_REGEN_20",0,"rui/callsigns/callsign_regen_20_col",0 +"callsign_regen_30_col","#BANNER_REGEN_30",0,"rui/callsigns/callsign_regen_30_col",0 +"callsign_regen_40_col","#BANNER_REGEN_40",0,"rui/callsigns/callsign_regen_40_col",0 +"callsign_regen_50_col","#BANNER_REGEN_50",0,"rui/callsigns/callsign_regen_50_col",0 +"callsign_regen_60_col","#BANNER_REGEN_60",0,"rui/callsigns/callsign_regen_60_col",0 +"callsign_regen_70_col","#BANNER_REGEN_70",0,"rui/callsigns/callsign_regen_70_col",0 +"callsign_regen_80_col","#BANNER_REGEN_80",0,"rui/callsigns/callsign_regen_80_col",0 +"callsign_regen_90_col","#BANNER_REGEN_90",0,"rui/callsigns/callsign_regen_90_col",0 +"callsign_regen_100_col","#BANNER_REGEN_100",0,"rui/callsigns/callsign_regen_100_col",0 +"callsign_regen_10_col_prism","#BANNER_PRISM_REGEN_10",1,"rui/callsigns/callsign_regen_10_col",0 +"callsign_regen_20_col_prism","#BANNER_PRISM_REGEN_20",1,"rui/callsigns/callsign_regen_20_col",0 +"callsign_regen_30_col_prism","#BANNER_PRISM_REGEN_30",1,"rui/callsigns/callsign_regen_30_col",0 +"callsign_regen_40_col_prism","#BANNER_PRISM_REGEN_40",1,"rui/callsigns/callsign_regen_40_col",0 +"callsign_regen_50_col_prism","#BANNER_PRISM_REGEN_50",1,"rui/callsigns/callsign_regen_50_col",0 +"callsign_regen_60_col_prism","#BANNER_PRISM_REGEN_60",1,"rui/callsigns/callsign_regen_60_col",0 +"callsign_regen_70_col_prism","#BANNER_PRISM_REGEN_70",1,"rui/callsigns/callsign_regen_70_col",0 +"callsign_regen_80_col_prism","#BANNER_PRISM_REGEN_80",1,"rui/callsigns/callsign_regen_80_col",0 +"callsign_regen_90_col_prism","#BANNER_PRISM_REGEN_90",1,"rui/callsigns/callsign_regen_90_col",0 +"callsign_regen_100_col_prism","#BANNER_PRISM_REGEN_100",1,"rui/callsigns/callsign_regen_100_col",0 +"callsign_165_col","#BANNER_CALLSIGN165",0,"rui/callsigns/callsign_165_col",0 +"callsign_166_col","#BANNER_CALLSIGN166",0,"rui/callsigns/callsign_166_col",0 +"callsign_167_col","#BANNER_CALLSIGN167",0,"rui/callsigns/callsign_167_col",0 +"callsign_168_col","#BANNER_CALLSIGN168",0,"rui/callsigns/callsign_168_col",0 +"callsign_169_col","#BANNER_CALLSIGN169",0,"rui/callsigns/callsign_169_col",0 +"callsign_170_col","#BANNER_CALLSIGN170",0,"rui/callsigns/callsign_170_col",0 +"callsign_171_col","#BANNER_CALLSIGN171",0,"rui/callsigns/callsign_171_col",0 +"callsign_172_col","#BANNER_CALLSIGN172",0,"rui/callsigns/callsign_172_col",0 +"callsign_173_col","#BANNER_CALLSIGN173",0,"rui/callsigns/callsign_173_col",0 +"callsign_174_col","#BANNER_CALLSIGN174",0,"rui/callsigns/callsign_174_col",0 +"callsign_175_col","#BANNER_CALLSIGN175",0,"rui/callsigns/callsign_175_col",0 +"callsign_176_col","#BANNER_CALLSIGN176",0,"rui/callsigns/callsign_176_col",0 +"callsign_177_col","#BANNER_CALLSIGN177",0,"rui/callsigns/callsign_177_col",0 +"callsign_178_col","#BANNER_CALLSIGN178",0,"rui/callsigns/callsign_178_col",0 +"callsign_179_col","#BANNER_CALLSIGN179",0,"rui/callsigns/callsign_179_col",0 +"callsign_180_col","#BANNER_CALLSIGN180",0,"rui/callsigns/callsign_180_col",0 +"callsign_181_col","#BANNER_CALLSIGN181",0,"rui/callsigns/callsign_181_col",0 +"callsign_182_col","#BANNER_CALLSIGN182",0,"rui/callsigns/callsign_182_col",0 +"callsign_183_col","#BANNER_CALLSIGN183",0,"rui/callsigns/callsign_183_col",0 +"callsign_184_col","#BANNER_CALLSIGN184",0,"rui/callsigns/callsign_184_col",0 +"callsign_185_col","#BANNER_CALLSIGN185",0,"rui/callsigns/callsign_185_col",0 +"callsign_165_col_fire","#BANNER_FIRE_CALLSIGN165",3,"rui/callsigns/callsign_165_col",0 +"callsign_165_col_gold","#BANNER_GOLD_CALLSIGN165",2,"rui/callsigns/callsign_165_col",0 +"callsign_24_col_prism","#BANNER_PRISM_CALLSIGN24",1,"rui/callsigns/callsign_24_col",0 +"callsign_47_col_prism","#BANNER_PRISM_CALLSIGN47",1,"rui/callsigns/callsign_47_col",0 +"callsign_36_col_prism","#BANNER_PRISM_CALLSIGN36",1,"rui/callsigns/callsign_36_col",0 +"callsign_45_col_prism","#BANNER_PRISM_CALLSIGN45",1,"rui/callsigns/callsign_45_col",0 +"callsign_68_col_prism","#BANNER_PRISM_CALLSIGN68",1,"rui/callsigns/callsign_68_col",0 +"callsign_26_col_prism","#BANNER_PRISM_CALLSIGN26",1,"rui/callsigns/callsign_26_col",0 +"callsign_165_col_prism","#BANNER_PRISM_CALLSIGN165",1,"rui/callsigns/callsign_165_col",0 +"callsign_fd_ion_dynamic","#BANNER_CALLSIGN_FD_ION",0,"rui/callsigns/callsign_fd_ion_dynamic",0 +"callsign_fd_tone_dynamic","#BANNER_CALLSIGN_FD_TONE",0,"rui/callsigns/callsign_fd_tone_dynamic",0 +"callsign_fd_scorch_dynamic","#BANNER_CALLSIGN_FD_SCORCH",0,"rui/callsigns/callsign_fd_scorch_dynamic",0 +"callsign_fd_legion_dynamic","#BANNER_CALLSIGN_FD_LEGION",0,"rui/callsigns/callsign_fd_legion_dynamic",0 +"callsign_fd_ronin_dynamic","#BANNER_CALLSIGN_FD_RONIN",0,"rui/callsigns/callsign_fd_ronin_dynamic",0 +"callsign_fd_northstar_dynamic","#BANNER_CALLSIGN_FD_NORTHSTAR",0,"rui/callsigns/callsign_fd_northstar_dynamic",0 +"callsign_fd_monarch_dynamic","#BANNER_CALLSIGN_FD_MONARCH",0,"rui/callsigns/callsign_fd_monarch_dynamic",0 +"callsign_fd_ion_hard","#BANNER_CALLSIGN_FD_ION",1,"rui/callsigns/callsign_fd_ion_hard",0 +"callsign_fd_ion_master","#BANNER_CALLSIGN_FD_ION",1,"rui/callsigns/callsign_fd_ion_master",0 +"callsign_fd_ion_insane","#BANNER_CALLSIGN_FD_ION",2,"rui/callsigns/callsign_fd_ion_insane",0 +"callsign_fd_tone_hard","#BANNER_CALLSIGN_FD_TONE",1,"rui/callsigns/callsign_fd_tone_hard",0 +"callsign_fd_tone_master","#BANNER_CALLSIGN_FD_TONE",1,"rui/callsigns/callsign_fd_tone_master",0 +"callsign_fd_tone_insane","#BANNER_CALLSIGN_FD_TONE",2,"rui/callsigns/callsign_fd_tone_insane",0 +"callsign_fd_scorch_hard","#BANNER_CALLSIGN_FD_SCORCH",1,"rui/callsigns/callsign_fd_scorch_hard",0 +"callsign_fd_scorch_master","#BANNER_CALLSIGN_FD_SCORCH",1,"rui/callsigns/callsign_fd_scorch_master",0 +"callsign_fd_scorch_insane","#BANNER_CALLSIGN_FD_SCORCH",2,"rui/callsigns/callsign_fd_scorch_insane",0 +"callsign_fd_legion_hard","#BANNER_CALLSIGN_FD_LEGION",1,"rui/callsigns/callsign_fd_legion_hard",0 +"callsign_fd_legion_master","#BANNER_CALLSIGN_FD_LEGION",1,"rui/callsigns/callsign_fd_legion_master",0 +"callsign_fd_legion_insane","#BANNER_CALLSIGN_FD_LEGION",2,"rui/callsigns/callsign_fd_legion_insane",0 +"callsign_fd_ronin_hard","#BANNER_CALLSIGN_FD_RONIN",1,"rui/callsigns/callsign_fd_ronin_hard",0 +"callsign_fd_ronin_master","#BANNER_CALLSIGN_FD_RONIN",1,"rui/callsigns/callsign_fd_ronin_master",0 +"callsign_fd_ronin_insane","#BANNER_CALLSIGN_FD_RONIN",2,"rui/callsigns/callsign_fd_ronin_insane",0 +"callsign_fd_northstar_hard","#BANNER_CALLSIGN_FD_NORTHSTAR",1,"rui/callsigns/callsign_fd_northstar_hard",0 +"callsign_fd_northstar_master","#BANNER_CALLSIGN_FD_NORTHSTAR",1,"rui/callsigns/callsign_fd_northstar_master",0 +"callsign_fd_northstar_insane","#BANNER_CALLSIGN_FD_NORTHSTAR",2,"rui/callsigns/callsign_fd_northstar_insane",0 +"callsign_fd_monarch_hard","#BANNER_CALLSIGN_FD_MONARCH",1,"rui/callsigns/callsign_fd_monarch_hard",0 +"callsign_fd_monarch_master","#BANNER_CALLSIGN_FD_MONARCH",1,"rui/callsigns/callsign_fd_monarch_master",0 +"callsign_fd_monarch_insane","#BANNER_CALLSIGN_FD_MONARCH",2,"rui/callsigns/callsign_fd_monarch_insane",0 +"callsign_tt_gameover","#BANNER_CALLSIGN_TT_GAMEOVER",0,"rui/callsigns/callsign_tt_gameover",1500 +"callsign_tt_gameover_prism","#BANNER_PRISM_TT_GAMEOVER",1,"rui/callsigns/callsign_tt_gameover",3000 +"callsign_tt_guardtheflag","#BANNER_CALLSIGN_TT_GUARDTHEFLAG",0,"rui/callsigns/callsign_tt_guardtheflag",1500 +"callsign_tt_guardtheflag_prism","#BANNER_PRISM_TT_GUARDTHEFLAG",1,"rui/callsigns/callsign_tt_guardtheflag",3000 +"callsign_tt_megamarvin","#BANNER_CALLSIGN_TT_MEGAMARVIN",0,"rui/callsigns/callsign_tt_megamarvin",1500 +"callsign_tt_megamarvin_prism","#BANNER_PRISM_TT_MEGAMARVIN",1,"rui/callsigns/callsign_tt_megamarvin",3000 +"callsign_tt_nessievault","#BANNER_CALLSIGN_TT_NESSIEVAULT",0,"rui/callsigns/callsign_tt_nessievault",1500 +"callsign_tt_nessievault_prism","#BANNER_PRISM_TT_NESSIEVAULT",1,"rui/callsigns/callsign_tt_nessievault",3000 +"callsign_tt_nsbt","#BANNER_CALLSIGN_TT_NSBT",0,"rui/callsigns/callsign_tt_nsbt",1500 +"callsign_tt_nsbt_prism","#BANNER_PRISM_TT_NSBT",1,"rui/callsigns/callsign_tt_nsbt",3000 +"callsign_tt_protocol2","#BANNER_CALLSIGN_TT_PROTOCOL2",0,"rui/callsigns/callsign_tt_protocol2",1500 +"callsign_tt_protocol2_prism","#BANNER_PRISM_TT_PROTOCOL2",1,"rui/callsigns/callsign_tt_protocol2",3000 +"callsign_tt_rekt","#BANNER_CALLSIGN_TT_REKT",0,"rui/callsigns/callsign_tt_rekt",1500 +"callsign_tt_rekt_prism","#BANNER_PRISM_TT_REKT",1,"rui/callsigns/callsign_tt_rekt",3000 +"callsign_tt_titantoons","#BANNER_CALLSIGN_TT_TITANTOONS",0,"rui/callsigns/callsign_tt_titantoons",1500 +"callsign_tt_titantoons_prism","#BANNER_PRISM_TT_TITANTOONS",1,"rui/callsigns/callsign_tt_titantoons",3000 +"callsign_eat_ion","#BANNER_EAT_ION",0,"rui/callsigns/callsign_eat_ion",1500 +"callsign_eat_legion","#BANNER_EAT_LEGION",0,"rui/callsigns/callsign_eat_legion",1500 +"callsign_eat_northstar","#BANNER_EAT_NORTHSTAR",0,"rui/callsigns/callsign_eat_northstar",1500 +"callsign_eat_ronin","#BANNER_EAT_RONIN",0,"rui/callsigns/callsign_eat_ronin",1500 +"callsign_eat_scorch","#BANNER_EAT_SCORCH",0,"rui/callsigns/callsign_eat_scorch",1500 +"callsign_eat_tone","#BANNER_EAT_TONE",0,"rui/callsigns/callsign_eat_tone",1500 +"callsign_goodboy","#BANNER_GOODBOY",0,"rui/callsigns/callsign_goodboy",0 +"callsign_contest_01","#BANNER_CONTEST_01",0,"rui/callsigns/callsign_contest_01",0 +"callsign_contest_02","#BANNER_CONTEST_02",0,"rui/callsigns/callsign_contest_02",0 +"callsign_contest_03","#BANNER_CONTEST_03",0,"rui/callsigns/callsign_contest_03",0 +"callsign_contest_04","#BANNER_CONTEST_04",0,"rui/callsigns/callsign_contest_04",0 +"callsign_contest_05","#BANNER_CONTEST_05",0,"rui/callsigns/callsign_contest_05",0 +"callsign_contest_06","#BANNER_CONTEST_06",0,"rui/callsigns/callsign_contest_06",0 +"callsign_contest_07","#BANNER_CONTEST_07",0,"rui/callsigns/callsign_contest_07",0 +"callsign_contest_08","#BANNER_CONTEST_08",0,"rui/callsigns/callsign_contest_08",0 +"callsign_contest_09","#BANNER_CONTEST_09",0,"rui/callsigns/callsign_contest_09",0 +"callsign_contest_10","#BANNER_CONTEST_10",0,"rui/callsigns/callsign_contest_10",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/callsign_icons.csv b/Northstar.CustomServers/mod/scripts/datatable/callsign_icons.csv new file mode 100644 index 00000000..61840c68 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/callsign_icons.csv @@ -0,0 +1,193 @@ +itemRef,name,image,smallImage,cost +"gc_icon_5star","#PATCH_GC_ICON_5STAR","rui/gencard_icons/gc_icon_5star","rui/gencard_icons/gc_icon_5star_small",50 +"gc_icon_8ball","#PATCH_8BALL","rui/gencard_icons/gc_icon_8ball","rui/gencard_icons/gc_icon_8ball_small",0 +"gc_icon_ace","#PATCH_ACE","rui/gencard_icons/gc_icon_ace","rui/gencard_icons/gc_icon_ace_small",0 +"gc_icon_angryface","#PATCH_ANGRYFACE","rui/gencard_icons/gc_icon_angryface","rui/gencard_icons/gc_icon_angryface_small",50 +"gc_icon_apostrophe","#PATCH_APOSTROPHE","rui/gencard_icons/gc_icon_apostrophe","rui/gencard_icons/gc_icon_apostrophe_small",0 +"gc_icon_atom","#PATCH_ATOM","rui/gencard_icons/gc_icon_atom","rui/gencard_icons/gc_icon_atom_small",0 +"gc_icon_balloon","#PATCH_BALLOON","rui/gencard_icons/gc_icon_balloon","rui/gencard_icons/gc_icon_balloon_small",0 +"gc_icon_bear","#PATCH_BEAR","rui/gencard_icons/gc_icon_bear","rui/gencard_icons/gc_icon_bear_small",50 +"gc_icon_bird","#PATCH_BIRD","rui/gencard_icons/gc_icon_bird","rui/gencard_icons/gc_icon_bird_small",50 +"gc_icon_bomb_01","#PATCH_BOMB_01","rui/gencard_icons/gc_icon_bomb_01","rui/gencard_icons/gc_icon_bomb_01_small",0 +"gc_icon_bomb_02","#PATCH_BOMB_02","rui/gencard_icons/gc_icon_bomb_02","rui/gencard_icons/gc_icon_bomb_02_small",0 +"gc_icon_bullet","#PATCH_BULLET","rui/gencard_icons/gc_icon_bullet","rui/gencard_icons/gc_icon_bullet_small",0 +"gc_icon_bullseye","#PATCH_BULLSEYE","rui/gencard_icons/gc_icon_bullseye","rui/gencard_icons/gc_icon_bullseye_small",0 +"gc_icon_cateye","#PATCH_CATEYE","rui/gencard_icons/gc_icon_cateye","rui/gencard_icons/gc_icon_cateye_small",0 +"gc_icon_chicken","#PATCH_CHICKEN","rui/gencard_icons/gc_icon_chicken","rui/gencard_icons/gc_icon_chicken_small",50 +"gc_icon_clawmark","#PATCH_CLAWMARK","rui/gencard_icons/gc_icon_clawmark","rui/gencard_icons/gc_icon_clawmark_small",0 +"gc_icon_club","#PATCH_CLUB","rui/gencard_icons/gc_icon_club","rui/gencard_icons/gc_icon_club_small",50 +"gc_icon_comet","#PATCH_COMET","rui/gencard_icons/gc_icon_comet","rui/gencard_icons/gc_icon_comet_small",0 +"gc_icon_cow","#PATCH_COW","rui/gencard_icons/gc_icon_cow","rui/gencard_icons/gc_icon_cow_small",50 +"gc_icon_cowboy_hat","#PATCH_COWBOY_HAT","rui/gencard_icons/gc_icon_cowboy_hat","rui/gencard_icons/gc_icon_cowboy_hat_small",0 +"gc_icon_crosshair","#PATCH_CROSSHAIR","rui/gencard_icons/gc_icon_crosshair","rui/gencard_icons/gc_icon_crosshair_small",0 +"gc_icon_cupcake","#PATCH_CUPCAKE","rui/gencard_icons/gc_icon_cupcake","rui/gencard_icons/gc_icon_cupcake_small",50 +"gc_icon_diamond","#PATCH_DIAMOND","rui/gencard_icons/gc_icon_diamond","rui/gencard_icons/gc_icon_diamond_small",0 +"gc_icon_dice","#PATCH_DICE","rui/gencard_icons/gc_icon_dice","rui/gencard_icons/gc_icon_dice_small",0 +"gc_icon_dollarsign","#PATCH_DOLLARSIGN","rui/gencard_icons/gc_icon_dollarsign","rui/gencard_icons/gc_icon_dollarsign_small",0 +"gc_icon_doublerainbow","#PATCH_DOUBLERAINBOW","rui/gencard_icons/gc_icon_doublerainbow","rui/gencard_icons/gc_icon_doublerainbow_small",50 +"gc_icon_fingerprint","#PATCH_FINGERPRINT","rui/gencard_icons/gc_icon_fingerprint","rui/gencard_icons/gc_icon_fingerprint_small",50 +"gc_icon_fireball","#PATCH_FIREBALL","rui/gencard_icons/gc_icon_fireball","rui/gencard_icons/gc_icon_fireball_small",0 +"gc_icon_frag","#PATCH_FRAG","rui/gencard_icons/gc_icon_frag","rui/gencard_icons/gc_icon_frag_small",0 +"gc_icon_gear","#PATCH_GEAR","rui/gencard_icons/gc_icon_gear","rui/gencard_icons/gc_icon_gear_small",0 +"gc_icon_ghostface","#PATCH_GHOSTFACE","rui/gencard_icons/gc_icon_ghostface","rui/gencard_icons/gc_icon_ghostface_small",50 +"gc_icon_hamburger","#PATCH_HAMBURGER","rui/gencard_icons/gc_icon_hamburger","rui/gencard_icons/gc_icon_hamburger_small",50 +"gc_icon_handprint","#PATCH_HANDPRINT","rui/gencard_icons/gc_icon_handprint","rui/gencard_icons/gc_icon_handprint_small",50 +"gc_icon_happyface","#PATCH_HAPPYFACE","rui/gencard_icons/gc_icon_happyface","rui/gencard_icons/gc_icon_happyface_small",0 +"gc_icon_heart","#PATCH_HEART","rui/gencard_icons/gc_icon_heart","rui/gencard_icons/gc_icon_heart_small",0 +"gc_icon_hvt","#PATCH_HVT","rui/gencard_icons/gc_icon_hvt","rui/gencard_icons/gc_icon_hvt_small",50 +"gc_icon_jollyrgr","#PATCH_JOLLYRGR","rui/gencard_icons/gc_icon_jollyrgr","rui/gencard_icons/gc_icon_jollyrgr_small",50 +"gc_icon_lightning","#PATCH_LIGHTNING","rui/gencard_icons/gc_icon_lightning","rui/gencard_icons/gc_icon_lightning_small",0 +"gc_icon_lol","#PATCH_LOL","rui/gencard_icons/gc_icon_lol","rui/gencard_icons/gc_icon_lol_small",50 +"gc_icon_mad_hat","#PATCH_MAD_HAT","rui/gencard_icons/gc_icon_mad_hat","rui/gencard_icons/gc_icon_mad_hat_small",50 +"gc_icon_medic","#PATCH_MEDIC","rui/gencard_icons/gc_icon_medic","rui/gencard_icons/gc_icon_medic_small",0 +"gc_icon_moon","#PATCH_MOON","rui/gencard_icons/gc_icon_moon","rui/gencard_icons/gc_icon_moon_small",0 +"gc_icon_omg","#PATCH_OMG","rui/gencard_icons/gc_icon_omg","rui/gencard_icons/gc_icon_omg_small",50 +"gc_icon_paw","#PATCH_PAW","rui/gencard_icons/gc_icon_paw","rui/gencard_icons/gc_icon_paw_small",0 +"gc_icon_pizza","#PATCH_PIZZA","rui/gencard_icons/gc_icon_pizza","rui/gencard_icons/gc_icon_pizza_small",50 +"gc_icon_pro","#PATCH_PRO","rui/gencard_icons/gc_icon_pro","rui/gencard_icons/gc_icon_pro_small",0 +"gc_icon_question","#PATCH_QUESTION","rui/gencard_icons/gc_icon_question","rui/gencard_icons/gc_icon_question_small",50 +"gc_icon_rainbow","#PATCH_RAINBOW","rui/gencard_icons/gc_icon_rainbow","rui/gencard_icons/gc_icon_rainbow_small",50 +"gc_icon_raincloud","#PATCH_RAINCLOUD","rui/gencard_icons/gc_icon_raincloud","rui/gencard_icons/gc_icon_raincloud_small",0 +"gc_icon_rocket","#PATCH_ROCKET","rui/gencard_icons/gc_icon_rocket","rui/gencard_icons/gc_icon_rocket_small",0 +"gc_icon_saturn","#PATCH_SATURN","rui/gencard_icons/gc_icon_saturn","rui/gencard_icons/gc_icon_saturn_small",50 +"gc_icon_skull","#PATCH_SKULL","rui/gencard_icons/gc_icon_skull","rui/gencard_icons/gc_icon_skull_small",50 +"gc_icon_spade","#PATCH_SPADE","rui/gencard_icons/gc_icon_spade","rui/gencard_icons/gc_icon_spade_small",0 +"gc_icon_star","#PATCH_STAR","rui/gencard_icons/gc_icon_star","rui/gencard_icons/gc_icon_star_small",0 +"gc_icon_sword","#PATCH_SWORD","rui/gencard_icons/gc_icon_sword","rui/gencard_icons/gc_icon_sword_small",0 +"gc_icon_teabage","#PATCH_TEABAGE","rui/gencard_icons/gc_icon_teabage","rui/gencard_icons/gc_icon_teabage_small",50 +"gc_icon_titanfall","#PATCH_TITANFALL","rui/gencard_icons/gc_icon_titanfall","rui/gencard_icons/gc_icon_titanfall_small",0 +"gc_icon_vip","#PATCH_VIP","rui/gencard_icons/gc_icon_vip","rui/gencard_icons/gc_icon_vip_small",0 +"gc_icon_witch_hat","#PATCH_WITCH_HAT","rui/gencard_icons/gc_icon_witch_hat","rui/gencard_icons/gc_icon_witch_hat_small",50 +"gc_icon_wizard_hat","#PATCH_WIZARD_HAT","rui/gencard_icons/gc_icon_wizard_hat","rui/gencard_icons/gc_icon_wizard_hat_small",50 +"gc_icon_wtf","#PATCH_WTF","rui/gencard_icons/gc_icon_wtf","rui/gencard_icons/gc_icon_wtf_small",50 +"gc_icon_yuckface","#PATCH_YUCKFACE","rui/gencard_icons/gc_icon_yuckface","rui/gencard_icons/gc_icon_yuckface_small",0 +"gc_icon_respawn","#PATCH_RESPAWN","rui/gencard_icons/gc_icon_respawn","rui/gencard_icons/gc_icon_respawn_small",50 +"gc_icon_fair_warning","#PATCH_FAIR_WARNING","rui/gencard_icons/gc_icon_fair_warning","rui/gencard_icons/gc_icon_fair_warning_small",50 +"gc_icon_hawk","#PATCH_HAWK","rui/gencard_icons/gc_icon_hawk","rui/gencard_icons/gc_icon_hawk_small",0 +"gc_icon_ram","#PATCH_RAM","rui/gencard_icons/gc_icon_ram","rui/gencard_icons/gc_icon_ram_small",50 +"gc_icon_stab","#PATCH_STAB","rui/gencard_icons/gc_icon_stab","rui/gencard_icons/gc_icon_stab_small",50 +"gc_icon_bigcat","#PATCH_BIGCAT","rui/gencard_icons/gc_icon_bigcat","rui/gencard_icons/gc_icon_bigcat_small",50 +"gc_icon_wraith","#PATCH_WRAITH","rui/gencard_icons/gc_icon_wraith","rui/gencard_icons/gc_icon_wraith_small",50 +"gc_icon_stinger","#PATCH_STINGER","rui/gencard_icons/gc_icon_stinger","rui/gencard_icons/gc_icon_stinger_small",0 +"gc_icon_heartless","#PATCH_HEARTLESS","rui/gencard_icons/gc_icon_heartless","rui/gencard_icons/gc_icon_heartless_small",50 +"gc_icon_earthworm","#PATCH_EARTHWORM","rui/gencard_icons/gc_icon_earthworm","rui/gencard_icons/gc_icon_earthworm_small",50 +"gc_icon_prowler","#PATCH_PROWLER","rui/gencard_icons/gc_icon_prowler","rui/gencard_icons/gc_icon_prowler_small",0 +"gc_icon_ordnance","#PATCH_ORDNANCE","rui/gencard_icons/gc_icon_ordnance","rui/gencard_icons/gc_icon_ordnance_small",50 +"gc_icon_radar","#PATCH_RADAR","rui/gencard_icons/gc_icon_radar","rui/gencard_icons/gc_icon_radar_small",0 +"gc_icon_ramskull","#PATCH_RAMSKULL","rui/gencard_icons/gc_icon_ramskull","rui/gencard_icons/gc_icon_ramskull_small",0 +"gc_icon_hawkmoth","#PATCH_HAWKMOTH","rui/gencard_icons/gc_icon_hawkmoth","rui/gencard_icons/gc_icon_hawkmoth_small",50 +"gc_icon_fox","#PATCH_FOX","rui/gencard_icons/gc_icon_fox","rui/gencard_icons/gc_icon_fox_small",0 +"gc_icon_marksman","#PATCH_MARKSMAN","rui/gencard_icons/gc_icon_marksman","rui/gencard_icons/gc_icon_marksman_small",50 +"gc_icon_bunnyskull","#PATCH_BUNNYSKULL","rui/gencard_icons/gc_icon_bunnyskull","rui/gencard_icons/gc_icon_bunnyskull_small",50 +"gc_icon_falcon","#PATCH_FALCON","rui/gencard_icons/gc_icon_falcon","rui/gencard_icons/gc_icon_falcon_small",50 +"gc_icon_assault","#PATCH_ASSAULT","rui/gencard_icons/gc_icon_assault","rui/gencard_icons/gc_icon_assault_small",0 +"gc_icon_flying_skull","#PATCH_FLYING_SKULL","rui/gencard_icons/gc_icon_flying_skull","rui/gencard_icons/gc_icon_flying_skull_small",50 +"gc_icon_hammer","#PATCH_HAMMER","rui/gencard_icons/gc_icon_hammer","rui/gencard_icons/gc_icon_hammer_small",50 +"gc_icon_dragonfly","#PATCH_DRAGONFLY","rui/gencard_icons/gc_icon_dragonfly","rui/gencard_icons/gc_icon_dragonfly_small",0 +"gc_icon_striketwice","#PATCH_STRIKETWICE","rui/gencard_icons/gc_icon_striketwice","rui/gencard_icons/gc_icon_striketwice_small",0 +"gc_icon_waves","#PATCH_WAVES","rui/gencard_icons/gc_icon_waves","rui/gencard_icons/gc_icon_waves_small",0 +"gc_icon_fin","#PATCH_FIN","rui/gencard_icons/gc_icon_fin","rui/gencard_icons/gc_icon_fin_small",0 +"gc_icon_bee","#PATCH_BEE","rui/gencard_icons/gc_icon_bee","rui/gencard_icons/gc_icon_bee_small",50 +"gc_icon_wasp","#PATCH_WASP","rui/gencard_icons/gc_icon_wasp","rui/gencard_icons/gc_icon_wasp_small",0 +"gc_icon_bat","#PATCH_BAT","rui/gencard_icons/gc_icon_bat","rui/gencard_icons/gc_icon_bat_small",0 +"gc_icon_dataknife","#PATCH_DATAKNIFE","rui/gencard_icons/gc_icon_dataknife","rui/gencard_icons/gc_icon_dataknife_small",50 +"gc_icon_knife","#PATCH_KNIFE","rui/gencard_icons/gc_icon_knife","rui/gencard_icons/gc_icon_knife_small",50 +"gc_icon_widow","#PATCH_WIDOW","rui/gencard_icons/gc_icon_widow","rui/gencard_icons/gc_icon_widow_small",50 +"gc_icon_snake","#PATCH_SNAKE","rui/gencard_icons/gc_icon_snake","rui/gencard_icons/gc_icon_snake_small",50 +"gc_icon_scorpion","#PATCH_SCORPION","rui/gencard_icons/gc_icon_scorpion","rui/gencard_icons/gc_icon_scorpion_small",50 +"gc_icon_dragon","#PATCH_DRAGON","rui/gencard_icons/gc_icon_dragon","rui/gencard_icons/gc_icon_dragon_small",50 +"gc_icon_sgt_major","#PATCH_SGT_MAJOR","rui/gencard_icons/gc_icon_sgt_major","rui/gencard_icons/gc_icon_sgt_major_small",0 +"gc_icon_senior_sgt_e6","#PATCH_SENIOR_SGT_E6","rui/gencard_icons/gc_icon_senior_sgt_e6","rui/gencard_icons/gc_icon_senior_sgt_e6_small",50 +"gc_icon_senior_sgt","#PATCH_SENIOR_SGT","rui/gencard_icons/gc_icon_senior_sgt","rui/gencard_icons/gc_icon_senior_sgt_small",50 +"gc_icon_sgt","#PATCH_SGT","rui/gencard_icons/gc_icon_sgt","rui/gencard_icons/gc_icon_sgt_small",50 +"gc_icon_corporal","#PATCH_CORPORAL","rui/gencard_icons/gc_icon_corporal","rui/gencard_icons/gc_icon_corporal_small",50 +"gc_icon_pvt","#PATCH_PVT","rui/gencard_icons/gc_icon_private","rui/gencard_icons/gc_icon_private_small",50 +"gc_icon_gen0","#PATCH_GEN0","rui/gencard_icons/gc_icon_gen0","rui/gencard_icons/gc_icon_gen0_small",0 +"gc_icon_gen1","#PATCH_GEN1","rui/gencard_icons/gc_icon_gen1","rui/gencard_icons/gc_icon_gen1_small",0 +"gc_icon_gen2","#PATCH_GEN2","rui/gencard_icons/gc_icon_gen2","rui/gencard_icons/gc_icon_gen2_small",0 +"gc_icon_gen3","#PATCH_GEN3","rui/gencard_icons/gc_icon_gen3","rui/gencard_icons/gc_icon_gen3_small",0 +"gc_icon_gen4","#PATCH_GEN4","rui/gencard_icons/gc_icon_gen4","rui/gencard_icons/gc_icon_gen4_small",0 +"gc_icon_gen5","#PATCH_GEN5","rui/gencard_icons/gc_icon_gen5","rui/gencard_icons/gc_icon_gen5_small",0 +"gc_icon_gen6","#PATCH_GEN6","rui/gencard_icons/gc_icon_gen6","rui/gencard_icons/gc_icon_gen6_small",0 +"gc_icon_gen7","#PATCH_GEN7","rui/gencard_icons/gc_icon_gen7","rui/gencard_icons/gc_icon_gen7_small",0 +"gc_icon_gen8","#PATCH_GEN8","rui/gencard_icons/gc_icon_gen8","rui/gencard_icons/gc_icon_gen8_small",0 +"gc_icon_gen9","#PATCH_GEN9","rui/gencard_icons/gc_icon_gen9","rui/gencard_icons/gc_icon_gen9_small",0 +"gc_icon_respawn_dev","#PATCH_DEV","rui/gencard_icons/gc_icon_respawn_dev","rui/gencard_icons/gc_icon_respawn_dev_small",0 +"gc_icon_64","#PATCH_64","rui/gencard_icons/dlc1/gc_icon_64","rui/gencard_icons/dlc1/gc_icon_64_small",0 +"gc_icon_aces","#PATCH_ACES","rui/gencard_icons/dlc1/gc_icon_aces","rui/gencard_icons/dlc1/gc_icon_aces_small",0 +"gc_icon_alien","#PATCH_ALIEN","rui/gencard_icons/dlc1/gc_icon_alien","rui/gencard_icons/dlc1/gc_icon_alien_small",0 +"gc_icon_apex","#PATCH_APEX","rui/gencard_icons/dlc1/gc_icon_apex","rui/gencard_icons/dlc1/gc_icon_apex_small",0 +"gc_icon_ares","#PATCH_ARES","rui/gencard_icons/dlc1/gc_icon_ares","rui/gencard_icons/dlc1/gc_icon_ares_small",0 +"gc_icon_controller","#PATCH_CONTROLLER","rui/gencard_icons/dlc1/gc_icon_controller","rui/gencard_icons/dlc1/gc_icon_controller_small",0 +"gc_icon_drone","#PATCH_DRONE","rui/gencard_icons/dlc1/gc_icon_drone","rui/gencard_icons/dlc1/gc_icon_drone_small",0 +"gc_icon_heartbreaker","#PATCH_HEARTBREAKER","rui/gencard_icons/dlc1/gc_icon_heartbreaker","rui/gencard_icons/dlc1/gc_icon_heartbreaker_small",0 +"gc_icon_hexes","#PATCH_HEXES","rui/gencard_icons/dlc1/gc_icon_hexes","rui/gencard_icons/dlc1/gc_icon_hexes_small",0 +"gc_icon_kodai","#PATCH_KODAI","rui/gencard_icons/dlc1/gc_icon_kodai","rui/gencard_icons/dlc1/gc_icon_kodai_small",0 +"gc_icon_lastimosa","#PATCH_LASTIMOSA","rui/gencard_icons/dlc1/gc_icon_lastimosa","rui/gencard_icons/dlc1/gc_icon_lastimosa_small",0 +"gc_icon_lawai","#PATCH_LAWAI","rui/gencard_icons/dlc1/gc_icon_lawai","rui/gencard_icons/dlc1/gc_icon_lawai_small",0 +"gc_icon_mcor","#PATCH_MCOR","rui/gencard_icons/dlc1/gc_icon_mcor","rui/gencard_icons/dlc1/gc_icon_mcor_small",0 +"gc_icon_phoenix","#PATCH_PHOENIX","rui/gencard_icons/dlc1/gc_icon_phoenix","rui/gencard_icons/dlc1/gc_icon_phoenix_small",0 +"gc_icon_pilot","#PATCH_PILOT","rui/gencard_icons/dlc1/gc_icon_pilot","rui/gencard_icons/dlc1/gc_icon_pilot_small",0 +"gc_icon_robot","#PATCH_ROBOT","rui/gencard_icons/dlc1/gc_icon_robot","rui/gencard_icons/dlc1/gc_icon_robot_small",0 +"gc_icon_sentry","#PATCH_SENTRY","rui/gencard_icons/dlc1/gc_icon_sentry","rui/gencard_icons/dlc1/gc_icon_sentry_small",0 +"gc_icon_super_spectre","#PATCH_SUPER_SPECTRE","rui/gencard_icons/dlc1/gc_icon_super_spectre","rui/gencard_icons/dlc1/gc_icon_super_spectre_small",0 +"gc_icon_vinson","#PATCH_VINSON","rui/gencard_icons/dlc1/gc_icon_vinson","rui/gencard_icons/dlc1/gc_icon_vinson_small",0 +"gc_icon_wonyeon","#PATCH_WONYEON","rui/gencard_icons/dlc1/gc_icon_wonyeon","rui/gencard_icons/dlc1/gc_icon_wonyeon_small",0 +"gc_icon_b3_wing","#PATCH_B3_WING","rui/gencard_icons/gc_icon_b3_wing","rui/gencard_icons/gc_icon_b3_wing_small",0 +"gc_icon_balance","#PATCH_BALANCE","rui/gencard_icons/dlc3/gc_icon_balance","rui/gencard_icons/dlc3/gc_icon_balance_small",0 +"gc_icon_boot","#PATCH_BOOT","rui/gencard_icons/dlc3/gc_icon_boot","rui/gencard_icons/dlc3/gc_icon_boot_small",0 +"gc_icon_bt_eye","#PATCH_BT_EYE","rui/gencard_icons/dlc3/gc_icon_bt_eye","rui/gencard_icons/dlc3/gc_icon_bt_eye_small",0 +"gc_icon_peace","#PATCH_PEACE","rui/gencard_icons/dlc3/gc_icon_peace","rui/gencard_icons/dlc3/gc_icon_peace_small",0 +"gc_icon_pilot2","#PATCH_PILOT2","rui/gencard_icons/dlc3/gc_icon_pilot","rui/gencard_icons/dlc3/gc_icon_pilot_small",0 +"gc_icon_srs","#PATCH_SRS","rui/gencard_icons/dlc3/gc_icon_srs","rui/gencard_icons/dlc3/gc_icon_srs_small",0 +"gc_icon_starline","#PATCH_STARLINE","rui/gencard_icons/dlc3/gc_icon_starline","rui/gencard_icons/dlc3/gc_icon_starline_small",0 +"gc_icon_thumbdown","#PATCH_THUMBDOWN","rui/gencard_icons/dlc3/gc_icon_thumbdown","rui/gencard_icons/dlc3/gc_icon_thumbdown_small",0 +"gc_icon_thumbup","#PATCH_THUMBUP","rui/gencard_icons/dlc3/gc_icon_thumbup","rui/gencard_icons/dlc3/gc_icon_thumbup_small",0 +"gc_icon_vanguard","#PATCH_VANGUARD","rui/gencard_icons/dlc3/gc_icon_vanguard","rui/gencard_icons/dlc3/gc_icon_vanguard_small",0 +"gc_icon_deuce","#PATCH_DEUCE","rui/gencard_icons/dlc2/gc_icon_deuce","rui/gencard_icons/dlc2/gc_icon_deuce_small",0 +"gc_icon_down","#PATCH_DOWN","rui/gencard_icons/dlc2/gc_icon_down","rui/gencard_icons/dlc2/gc_icon_down_small",50 +"gc_icon_joy","#PATCH_JOY","rui/gencard_icons/dlc2/gc_icon_joy","rui/gencard_icons/dlc2/gc_icon_joy_small",50 +"gc_icon_mushroom","#PATCH_MUSHROOM","rui/gencard_icons/dlc2/gc_icon_mushroom","rui/gencard_icons/dlc2/gc_icon_mushroom_small",0 +"gc_icon_prowlerhead","#PATCH_PROWLERHEAD","rui/gencard_icons/dlc2/gc_icon_prowlerhead","rui/gencard_icons/dlc2/gc_icon_prowlerhead_small",0 +"gc_icon_scythe","#PATCH_SCYTHE","rui/gencard_icons/dlc2/gc_icon_scythe","rui/gencard_icons/dlc2/gc_icon_scythe_small",0 +"gc_icon_shuriken","#PATCH_SHURIKEN","rui/gencard_icons/dlc2/gc_icon_shuriken","rui/gencard_icons/dlc2/gc_icon_shuriken_small",0 +"gc_icon_squid","#PATCH_SQUID","rui/gencard_icons/dlc2/gc_icon_squid","rui/gencard_icons/dlc2/gc_icon_squid_small",0 +"gc_icon_threebullets","#PATCH_THREEBULLETS","rui/gencard_icons/dlc2/gc_icon_threebullets","rui/gencard_icons/dlc2/gc_icon_threebullets_small",0 +"gc_icon_tick","#PATCH_TICK","rui/gencard_icons/dlc2/gc_icon_tick","rui/gencard_icons/dlc2/gc_icon_tick_small",0 +"gc_icon_buzzsaw","#PATCH_BUZZSAW","rui/gencard_icons/dlc3/gc_icon_buzzsaw","rui/gencard_icons/dlc3/gc_icon_buzzsaw_small",0 +"gc_icon_crossed_lighting","#PATCH_CROSSED_LIGHTING","rui/gencard_icons/dlc3/gc_icon_crossed_lighting","rui/gencard_icons/dlc3/gc_icon_crossed_lighting_small",0 +"gc_icon_flying_bullet","#PATCH_FLYING_BULLET","rui/gencard_icons/dlc3/gc_icon_flying_bullet","rui/gencard_icons/dlc3/gc_icon_flying_bullet_small",0 +"gc_icon_hammer2","#PATCH_HAMMER2","rui/gencard_icons/dlc3/gc_icon_hammer","rui/gencard_icons/dlc3/gc_icon_hammer_small",0 +"gc_icon_keyboard","#PATCH_KEYBOARD","rui/gencard_icons/dlc3/gc_icon_keyboard","rui/gencard_icons/dlc3/gc_icon_keyboard_small",0 +"gc_icon_lightbulb","#PATCH_LIGHTBULB","rui/gencard_icons/dlc3/gc_icon_lightbulb","rui/gencard_icons/dlc3/gc_icon_lightbulb_small",0 +"gc_icon_narwhal","#PATCH_NARWHAL","rui/gencard_icons/dlc3/gc_icon_narwhal","rui/gencard_icons/dlc3/gc_icon_narwhal_small",0 +"gc_icon_robot_eye","#PATCH_ROBOT_EYE","rui/gencard_icons/dlc3/gc_icon_robot_eye","rui/gencard_icons/dlc3/gc_icon_robot_eye_small",0 +"gc_icon_taco","#PATCH_TACO","rui/gencard_icons/dlc3/gc_icon_taco","rui/gencard_icons/dlc3/gc_icon_taco_small",0 +"gc_icon_treble","#PATCH_TREBLE","rui/gencard_icons/dlc3/gc_icon_treble","rui/gencard_icons/dlc3/gc_icon_treble_small",0 +"gc_icon_monarch","#PATCH_MONARCH","rui/gencard_icons/dlc4/gc_icon_monarch","rui/gencard_icons/dlc4/gc_icon_monarch_small",0 +"gc_icon_mrvn","#PATCH_MRVN","rui/gencard_icons/dlc4/gc_icon_mrvn","rui/gencard_icons/dlc4/gc_icon_mrvn_small",0 +"gc_icon_blank","#PATCH_BLANK","rui/gencard_icons/gc_icon_blank","rui/gencard_icons/gc_icon_blank_small",0 +"gc_icon_monarch_dlc5","#PATCH_MONARCH_DLC5","rui/gencard_icons/dlc5/gc_icon_monarch","rui/gencard_icons/dlc5/gc_icon_monarch_small",0 +"gc_icon_militia","#PATCH_MILITIA","rui/gencard_icons/dlc5/gc_icon_militia","rui/gencard_icons/dlc5/gc_icon_militia_small",0 +"gc_icon_militia_alt","#PATCH_MILITIA_ALT","rui/gencard_icons/dlc5/gc_icon_militia_alt","rui/gencard_icons/dlc5/gc_icon_militia_alt_small",0 +"gc_icon_imc","#PATCH_IMC","rui/gencard_icons/dlc5/gc_icon_imc","rui/gencard_icons/dlc5/gc_icon_imc_small",0 +"gc_icon_hammond","#PATCH_HAMMOND","rui/gencard_icons/dlc5/gc_icon_hammond","rui/gencard_icons/dlc5/gc_icon_hammond_small",0 +"gc_icon_tri_chevron","#PATCH_TRI_CHEVRON","rui/gencard_icons/dlc5/gc_icon_tri_chevron","rui/gencard_icons/dlc5/gc_icon_tri_chevron_small",0 +"gc_icon_pilot_circle","#PATCH_PILOT_CIRCLE","rui/gencard_icons/dlc5/gc_icon_pilot_circle","rui/gencard_icons/dlc5/gc_icon_pilot_circle_small",0 +"gc_icon_x","#PATCH_X","rui/gencard_icons/dlc5/gc_icon_x","rui/gencard_icons/dlc5/gc_icon_x_small",0 +"gc_icon_nessie","#PATCH_NESSIE","rui/gencard_icons/dlc5/gc_icon_nessie","rui/gencard_icons/dlc5/gc_icon_nessie_small",0 +"gc_icon_spicy","#PATCH_SPICY","rui/gencard_icons/dlc5/gc_icon_spicy","rui/gencard_icons/dlc5/gc_icon_spicy_small",0 +"gc_icon_crown","#PATCH_CROWN","rui/gencard_icons/dlc5/gc_icon_crown","rui/gencard_icons/dlc5/gc_icon_crown_small",0 +"gc_icon_pawn","#PATCH_PAWN","rui/gencard_icons/dlc5/gc_icon_pawn","rui/gencard_icons/dlc5/gc_icon_pawn_small",0 +"gc_icon_excite","#PATCH_EXCITE","rui/gencard_icons/dlc5/gc_icon_excite","rui/gencard_icons/dlc5/gc_icon_excite_small",0 +"gc_icon_duck","#PATCH_DUCK","rui/gencard_icons/dlc5/gc_icon_duck","rui/gencard_icons/dlc5/gc_icon_duck_small",0 +"gc_icon_sock","#PATCH_SOCK","rui/gencard_icons/dlc5/gc_icon_sock","rui/gencard_icons/dlc5/gc_icon_sock_small",0 +"gc_icon_rabbit","#PATCH_RABBIT","rui/gencard_icons/dlc5/gc_icon_rabbit","rui/gencard_icons/dlc5/gc_icon_rabbit_small",0 +"gc_icon_peanut","#PATCH_PEANUT","rui/gencard_icons/dlc5/gc_icon_peanut","rui/gencard_icons/dlc5/gc_icon_peanut_small",0 +"gc_icon_clock","#PATCH_CLOCK","rui/gencard_icons/dlc5/gc_icon_clock","rui/gencard_icons/dlc5/gc_icon_clock_small",0 +"gc_icon_shamrock","#PATCH_SHAMROCK","rui/gencard_icons/dlc5/gc_icon_shamrock","rui/gencard_icons/dlc5/gc_icon_shamrock_small",0 +"gc_icon_trident","#PATCH_TRIDENT","rui/gencard_icons/dlc5/gc_icon_trident","rui/gencard_icons/dlc5/gc_icon_trident_small",0 +"gc_icon_fd_normal","#PATCH_FD_NORMAL","rui/gencard_icons/fd/gc_icon_fd_normal","rui/gencard_icons/fd/gc_icon_fd_normal_small",0 +"gc_icon_fd_hard","#PATCH_FD_HARD","rui/gencard_icons/fd/gc_icon_fd_hard","rui/gencard_icons/fd/gc_icon_fd_hard_small",0 +"gc_icon_fd_master","#PATCH_FD_MASTER","rui/gencard_icons/fd/gc_icon_fd_master","rui/gencard_icons/fd/gc_icon_fd_master_small",0 +"gc_icon_fd_insane","#PATCH_FD_INSANE","rui/gencard_icons/fd/gc_icon_fd_insane","rui/gencard_icons/fd/gc_icon_fd_insane_small",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/camo_skins.csv b/Northstar.CustomServers/mod/scripts/datatable/camo_skins.csv new file mode 100644 index 00000000..2773f4b6 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/camo_skins.csv @@ -0,0 +1,161 @@ +itemRef,pilotRef,titanRef,type,image,name,description,pilotCost,titanCost,pilotWeaponCost,titanWeaponCost,category +"camo_skin00","pilot_camo_skin00","titan_camo_skin00","CAMO","rui/menu/common/no_art","#CAMO_DEFAULT","#DEFAULT_DESC",0,0,0,0,1 +"camo_skin01","pilot_camo_skin01","titan_camo_skin01","CAMO","models/camo_skins/camo_skin01_col","#CAMO_SKIN_01","#CAMO_SKIN_01_DESC",0,0,0,0,1 +"camo_skin02","pilot_camo_skin02","titan_camo_skin02","CAMO","models/camo_skins/camo_skin02_col","#CAMO_SKIN_02","#CAMO_SKIN_02_DESC",0,0,0,0,1 +"camo_skin03","pilot_camo_skin03","titan_camo_skin03","CAMO","models/camo_skins/camo_skin03_col","#CAMO_SKIN_03","#CAMO_SKIN_03_DESC",0,0,0,0,1 +"camo_skin04","pilot_camo_skin04","titan_camo_skin04","CAMO","models/camo_skins/camo_skin04_col","#CAMO_SKIN_04","#CAMO_SKIN_04_DESC",150,100,75,50,3 +"camo_skin05","pilot_camo_skin05","titan_camo_skin05","CAMO","models/camo_skins/camo_skin05_col","#CAMO_SKIN_05","#CAMO_SKIN_05_DESC",150,100,75,50,3 +"camo_skin06","pilot_camo_skin06","titan_camo_skin06","CAMO","models/camo_skins/camo_skin06_col","#CAMO_SKIN_06","#CAMO_SKIN_06_DESC",150,100,75,50,4 +"camo_skin07","pilot_camo_skin07","titan_camo_skin07","CAMO","models/camo_skins/camo_skin07_col","#CAMO_SKIN_07","#CAMO_SKIN_07_DESC",0,0,0,0,2 +"camo_skin08","pilot_camo_skin08","titan_camo_skin08","CAMO","models/camo_skins/camo_skin08_col","#CAMO_SKIN_08","#CAMO_SKIN_08_DESC",150,100,75,50,4 +"camo_skin09","pilot_camo_skin09","titan_camo_skin09","CAMO","models/camo_skins/camo_skin09_col","#CAMO_SKIN_09","#CAMO_SKIN_09_DESC",0,0,0,0,1 +"camo_skin10","pilot_camo_skin10","titan_camo_skin10","CAMO","models/camo_skins/camo_skin10_col","#CAMO_SKIN_10","#CAMO_SKIN_10_DESC",0,0,0,0,1 +"camo_skin11","pilot_camo_skin11","titan_camo_skin11","CAMO","models/camo_skins/camo_skin11_col","#CAMO_SKIN_11","#CAMO_SKIN_11_DESC",150,100,75,50,4 +"camo_skin12","pilot_camo_skin12","titan_camo_skin12","CAMO","models/camo_skins/camo_skin12_col","#CAMO_SKIN_12","#CAMO_SKIN_12_DESC",150,100,75,50,4 +"camo_skin13","pilot_camo_skin13","titan_camo_skin13","CAMO","models/camo_skins/camo_skin13_col","#CAMO_SKIN_13","#CAMO_SKIN_13_DESC",0,0,0,0,2 +"camo_skin14","pilot_camo_skin14","titan_camo_skin14","CAMO","models/camo_skins/camo_skin14_col","#CAMO_SKIN_14","#CAMO_SKIN_14_DESC",0,0,0,0,1 +"camo_skin15","pilot_camo_skin15","titan_camo_skin15","CAMO","models/camo_skins/camo_skin15_col","#CAMO_SKIN_15","#CAMO_SKIN_15_DESC",0,0,0,0,1 +"camo_skin16","pilot_camo_skin16","titan_camo_skin16","CAMO","models/camo_skins/camo_skin16_col","#CAMO_SKIN_16","#CAMO_SKIN_16_DESC",0,0,0,0,1 +"camo_skin17","pilot_camo_skin17","titan_camo_skin17","CAMO","models/camo_skins/camo_skin17_col","#CAMO_SKIN_17","#CAMO_SKIN_17_DESC",0,0,0,0,1 +"camo_skin18","pilot_camo_skin18","titan_camo_skin18","CAMO","models/camo_skins/camo_skin18_col","#CAMO_SKIN_18","#CAMO_SKIN_18_DESC",0,0,0,0,1 +"camo_skin19","pilot_camo_skin19","titan_camo_skin19","CAMO","models/camo_skins/camo_skin19_col","#CAMO_SKIN_19","#CAMO_SKIN_19_DESC",0,0,0,0,1 +"camo_skin20","pilot_camo_skin20","titan_camo_skin20","CAMO","models/camo_skins/camo_skin20_col","#CAMO_SKIN_20","#CAMO_SKIN_20_DESC",150,100,75,50,3 +"camo_skin21","pilot_camo_skin21","titan_camo_skin21","CAMO","models/camo_skins/camo_skin21_col","#CAMO_SKIN_21","#CAMO_SKIN_21_DESC",150,100,75,50,3 +"camo_skin22","pilot_camo_skin22","titan_camo_skin22","CAMO","models/camo_skins/camo_skin22_col","#CAMO_SKIN_22","#CAMO_SKIN_22_DESC",150,100,75,50,3 +"camo_skin23","pilot_camo_skin23","titan_camo_skin23","CAMO","models/camo_skins/camo_skin23_col","#CAMO_SKIN_23","#CAMO_SKIN_23_DESC",150,100,75,50,3 +"camo_skin24","pilot_camo_skin24","titan_camo_skin24","CAMO","models/camo_skins/camo_skin24_col","#CAMO_SKIN_24","#CAMO_SKIN_24_DESC",0,0,0,0,1 +"camo_skin25","pilot_camo_skin25","titan_camo_skin25","CAMO","models/camo_skins/camo_skin25_col","#CAMO_SKIN_25","#CAMO_SKIN_25_DESC",0,0,0,0,1 +"camo_skin26","pilot_camo_skin26","titan_camo_skin26","CAMO","models/camo_skins/camo_skin26_col","#CAMO_SKIN_26","#CAMO_SKIN_26_DESC",0,0,0,0,1 +"camo_skin27","pilot_camo_skin27","titan_camo_skin27","CAMO","models/camo_skins/camo_skin27_col","#CAMO_SKIN_27","#CAMO_SKIN_27_DESC",0,0,0,0,1 +"camo_skin28","pilot_camo_skin28","titan_camo_skin28","CAMO","models/camo_skins/camo_skin28_col","#CAMO_SKIN_28","#CAMO_SKIN_28_DESC",150,100,75,50,4 +"camo_skin29","pilot_camo_skin29","titan_camo_skin29","CAMO","models/camo_skins/camo_skin29_col","#CAMO_SKIN_29","#CAMO_SKIN_29_DESC",150,100,75,50,4 +"camo_skin30","pilot_camo_skin30","titan_camo_skin30","CAMO","models/camo_skins/camo_skin30_col","#CAMO_SKIN_30","#CAMO_SKIN_30_DESC",0,0,0,0,1 +"camo_skin31","pilot_camo_skin31","titan_camo_skin31","CAMO","models/camo_skins/camo_skin31_col","#CAMO_SKIN_31","#CAMO_SKIN_31_DESC",0,0,0,0,1 +"camo_skin32","pilot_camo_skin32","titan_camo_skin32","CAMO","models/camo_skins/camo_skin32_col","#CAMO_SKIN_32","#CAMO_SKIN_32_DESC",150,100,75,50,4 +"camo_skin33","pilot_camo_skin33","titan_camo_skin33","CAMO","models/camo_skins/camo_skin33_col","#CAMO_SKIN_33","#CAMO_SKIN_33_DESC",150,100,75,50,4 +"camo_skin34","pilot_camo_skin34","titan_camo_skin34","CAMO","models/camo_skins/camo_skin34_col","#CAMO_SKIN_34","#CAMO_SKIN_34_DESC",150,100,75,50,4 +"camo_skin35","pilot_camo_skin35","titan_camo_skin35","CAMO","models/camo_skins/camo_skin35_col","#CAMO_SKIN_35","#CAMO_SKIN_35_DESC",150,100,75,50,3 +"camo_skin36","pilot_camo_skin36","titan_camo_skin36","CAMO","models/camo_skins/camo_skin36_col","#CAMO_SKIN_36","#CAMO_SKIN_36_DESC",150,100,75,50,3 +"camo_skin37","pilot_camo_skin37","titan_camo_skin37","CAMO","models/camo_skins/camo_skin37_col","#CAMO_SKIN_37","#CAMO_SKIN_37_DESC",150,100,75,50,4 +"camo_skin38","pilot_camo_skin38","titan_camo_skin38","CAMO","models/camo_skins/camo_skin38_col","#CAMO_SKIN_38","#CAMO_SKIN_38_DESC",150,100,75,50,4 +"camo_skin39","pilot_camo_skin39","titan_camo_skin39","CAMO","models/camo_skins/camo_skin39_col","#CAMO_SKIN_39","#CAMO_SKIN_39_DESC",150,100,75,50,4 +"camo_skin40","pilot_camo_skin40","titan_camo_skin40","CAMO","models/camo_skins/camo_skin40_col","#CAMO_SKIN_40","#CAMO_SKIN_40_DESC",150,100,75,50,3 +"camo_skin41","pilot_camo_skin41","titan_camo_skin41","CAMO","models/camo_skins/camo_skin41_col","#CAMO_SKIN_41","#CAMO_SKIN_41_DESC",150,100,75,50,3 +"camo_skin42","pilot_camo_skin42","titan_camo_skin42","CAMO","models/camo_skins/camo_skin42_col","#CAMO_SKIN_42","#CAMO_SKIN_42_DESC",150,100,75,50,3 +"camo_skin43","pilot_camo_skin43","titan_camo_skin43","CAMO","models/camo_skins/camo_skin43_col","#CAMO_SKIN_43","#CAMO_SKIN_43_DESC",150,100,75,50,3 +"camo_skin44","pilot_camo_skin44","titan_camo_skin44","CAMO","models/camo_skins/camo_skin44_col","#CAMO_SKIN_44","#CAMO_SKIN_44_DESC",150,100,75,50,3 +"camo_skin45","pilot_camo_skin45","titan_camo_skin45","CAMO","models/camo_skins/camo_skin45_col","#CAMO_SKIN_45","#CAMO_SKIN_45_DESC",150,100,75,50,3 +"camo_skin46","pilot_camo_skin46","titan_camo_skin46","CAMO","models/camo_skins/camo_skin46_col","#CAMO_SKIN_46","#CAMO_SKIN_46_DESC",150,100,75,50,3 +"camo_skin47","pilot_camo_skin47","titan_camo_skin47","CAMO","models/camo_skins/camo_skin47_col","#CAMO_SKIN_47","#CAMO_SKIN_47_DESC",150,100,75,50,4 +"camo_skin48","pilot_camo_skin48","titan_camo_skin48","CAMO","models/camo_skins/camo_skin48_col","#CAMO_SKIN_48","#CAMO_SKIN_48_DESC",150,100,75,50,4 +"camo_skin49","pilot_camo_skin49","titan_camo_skin49","CAMO","models/camo_skins/camo_skin49_col","#CAMO_SKIN_49","#CAMO_SKIN_49_DESC",150,100,75,50,4 +"camo_skin50","pilot_camo_skin50","titan_camo_skin50","CAMO","models/camo_skins/camo_skin50_col","#CAMO_SKIN_50","#CAMO_SKIN_50_DESC",150,100,75,50,4 +"camo_skin51","pilot_camo_skin51","titan_camo_skin51","CAMO","models/camo_skins/camo_skin51_col","#CAMO_SKIN_51","#CAMO_SKIN_51_DESC",150,100,75,50,4 +"camo_skin52","pilot_camo_skin52","titan_camo_skin52","CAMO","models/camo_skins/camo_skin52_col","#CAMO_SKIN_52","#CAMO_SKIN_52_DESC",150,100,75,50,4 +"camo_skin53","pilot_camo_skin53","titan_camo_skin53","CAMO","models/camo_skins/camo_skin53_col","#CAMO_SKIN_53","#CAMO_SKIN_53_DESC",150,100,75,50,4 +"camo_skin54","pilot_camo_skin54","titan_camo_skin54","CAMO","models/camo_skins/camo_skin54_col","#CAMO_SKIN_54","#CAMO_SKIN_54_DESC",150,100,75,50,4 +"camo_skin55","pilot_camo_skin55","titan_camo_skin55","CAMO","models/camo_skins/camo_skin55_col","#CAMO_SKIN_55","#CAMO_SKIN_55_DESC",0,0,0,0,2 +"camo_skin56","pilot_camo_skin56","titan_camo_skin56","CAMO","models/camo_skins/camo_skin56_col","#CAMO_SKIN_56","#CAMO_SKIN_56_DESC",0,0,0,0,2 +"camo_skin57","pilot_camo_skin57","titan_camo_skin57","CAMO","models/camo_skins/camo_skin57_col","#CAMO_SKIN_57","#CAMO_SKIN_57_DESC",0,0,0,0,2 +"camo_skin58","pilot_camo_skin58","titan_camo_skin58","CAMO","models/camo_skins/camo_skin58_col","#CAMO_SKIN_58","#CAMO_SKIN_58_DESC",0,0,0,0,2 +"camo_skin59","pilot_camo_skin59","titan_camo_skin59","CAMO","models/camo_skins/camo_skin59_col","#CAMO_SKIN_59","#CAMO_SKIN_59_DESC",0,0,0,0,2 +"camo_skin60","pilot_camo_skin60","titan_camo_skin60","CAMO","models/camo_skins/camo_skin60_col","#CAMO_SKIN_60","#CAMO_SKIN_60_DESC",0,0,0,0,2 +"camo_skin61","pilot_camo_skin61","titan_camo_skin61","CAMO","models/camo_skins/camo_skin61_col","#CAMO_SKIN_61","#CAMO_SKIN_61_DESC",0,0,0,0,2 +"camo_skin62","pilot_camo_skin62","titan_camo_skin62","CAMO","models/camo_skins/camo_skin62_col","#CAMO_SKIN_62","#CAMO_SKIN_62_DESC",0,0,0,0,2 +"camo_skin63","pilot_camo_skin63","titan_camo_skin63","CAMO","models/camo_skins/camo_skin63_col","#CAMO_SKIN_63","#CAMO_SKIN_63_DESC",0,0,0,0,2 +"camo_skin64","pilot_camo_skin64","titan_camo_skin64","CAMO","models/camo_skins/camo_skin64_col","#CAMO_SKIN_64","#CAMO_SKIN_64_DESC",0,0,0,0,2 +"camo_skin65","pilot_camo_skin65","titan_camo_skin65","CAMO","models/camo_skins/camo_skin65_col","#CAMO_SKIN_65","#CAMO_SKIN_65_DESC",0,0,0,0,2 +"camo_skin66","pilot_camo_skin66","titan_camo_skin66","CAMO","models/camo_skins/camo_skin66_col","#CAMO_SKIN_66","#CAMO_SKIN_66_DESC",0,0,0,0,2 +"camo_skin67","pilot_camo_skin67","titan_camo_skin67","CAMO","models/camo_skins/camo_skin67_col","#CAMO_SKIN_67","#CAMO_SKIN_67_DESC",0,0,0,0,2 +"camo_skin68","pilot_camo_skin68","titan_camo_skin68","CAMO","models/camo_skins/camo_skin68_col","#CAMO_SKIN_68","#CAMO_SKIN_68_DESC",150,100,75,50,4 +"camo_skin69","pilot_camo_skin69","titan_camo_skin69","CAMO","models/camo_skins/camo_skin69_col","#CAMO_SKIN_69","#CAMO_SKIN_69_DESC",150,100,75,50,4 +"camo_skin70","pilot_camo_skin70","titan_camo_skin70","CAMO","models/camo_skins/camo_skin70_col","#CAMO_SKIN_70","#CAMO_SKIN_70_DESC",150,100,75,50,4 +"camo_skin71","pilot_camo_skin71","titan_camo_skin71","CAMO","models/camo_skins/camo_skin71_col","#CAMO_SKIN_71","#CAMO_SKIN_71_DESC",150,100,75,50,4 +"camo_skin72","pilot_camo_skin72","titan_camo_skin72","CAMO","models/camo_skins/camo_skin72_col","#CAMO_SKIN_72","#CAMO_SKIN_72_DESC",150,100,75,50,4 +"camo_skin73","pilot_camo_skin73","titan_camo_skin73","CAMO","models/camo_skins/camo_skin73_col","#CAMO_SKIN_73","#CAMO_SKIN_73_DESC",150,100,75,50,4 +"camo_skin74","pilot_camo_skin74","titan_camo_skin74","CAMO","models/camo_skins/camo_skin74_col","#CAMO_SKIN_74","#CAMO_SKIN_74_DESC",150,100,75,50,4 +"camo_skin75","pilot_camo_skin75","titan_camo_skin75","CAMO","models/camo_skins/camo_skin75_col","#CAMO_SKIN_75","#CAMO_SKIN_75_DESC",150,100,75,50,4 +"camo_skin76","pilot_camo_skin76","titan_camo_skin76","CAMO","models/camo_skins/camo_skin76_col","#CAMO_SKIN_76","#CAMO_SKIN_76_DESC",150,100,75,50,3 +"camo_skin77","pilot_camo_skin77","titan_camo_skin77","CAMO","models/camo_skins/camo_skin77_col","#CAMO_SKIN_77","#CAMO_SKIN_77_DESC",150,100,75,50,3 +"camo_skin78","pilot_camo_skin78","titan_camo_skin78","CAMO","models/camo_skins/camo_skin78_col","#CAMO_SKIN_78","#CAMO_SKIN_78_DESC",150,100,75,50,3 +"camo_skin79","pilot_camo_skin79","titan_camo_skin79","CAMO","models/camo_skins/camo_skin79_col","#CAMO_SKIN_79","#CAMO_SKIN_79_DESC",150,100,75,50,3 +"camo_skin80","pilot_camo_skin80","titan_camo_skin80","CAMO","models/camo_skins/camo_skin80_col","#CAMO_SKIN_80","#CAMO_SKIN_80_DESC",150,100,75,50,3 +"camo_skin81","pilot_camo_skin81","titan_camo_skin81","CAMO","models/camo_skins/camo_skin81_col","#CAMO_SKIN_81","#CAMO_SKIN_81_DESC",0,0,0,0,1 +"camo_skin82","pilot_camo_skin82","titan_camo_skin82","CAMO","models/camo_skins/camo_skin82_col","#CAMO_SKIN_82","#CAMO_SKIN_82_DESC",0,0,0,0,1 +"camo_skin83","pilot_camo_skin83","titan_camo_skin83","CAMO","models/camo_skins/camo_skin83_col","#CAMO_SKIN_83","#CAMO_SKIN_83_DESC",0,0,0,0,1 +"camo_skin84","pilot_camo_skin84","titan_camo_skin84","CAMO","models/camo_skins/camo_skin84_col","#CAMO_SKIN_84","#CAMO_SKIN_84_DESC",150,100,75,50,4 +"camo_skin85","pilot_camo_skin85","titan_camo_skin85","CAMO","models/camo_skins/camo_skin85_col","#CAMO_SKIN_85","#CAMO_SKIN_85_DESC",0,0,0,0,2 +"camo_skin86","pilot_camo_skin86","titan_camo_skin86","CAMO","models/camo_skins/camo_skin86_col","#CAMO_SKIN_86","#CAMO_SKIN_86_DESC",150,100,75,50,4 +"camo_skin87","pilot_camo_skin87","titan_camo_skin87","CAMO","models/camo_skins/camo_skin87_col","#CAMO_SKIN_87","#CAMO_SKIN_87_DESC",0,0,0,0,2 +"camo_skin88","pilot_camo_skin88","titan_camo_skin88","CAMO","models/camo_skins/camo_skin88_col","#CAMO_SKIN_88","#CAMO_SKIN_88_DESC",150,100,75,50,4 +"camo_skin89","pilot_camo_skin89","titan_camo_skin89","CAMO","models/camo_skins/camo_skin89_col","#CAMO_SKIN_89","#CAMO_SKIN_89_DESC",150,100,75,50,4 +"camo_skin90","pilot_camo_skin90","titan_camo_skin90","CAMO","models/camo_skins/camo_skin90_col","#CAMO_SKIN_90","#CAMO_SKIN_90_DESC",150,100,75,50,4 +"camo_skin91","pilot_camo_skin91","titan_camo_skin91","CAMO","models/camo_skins/camo_skin91_col","#CAMO_SKIN_91","#CAMO_SKIN_91_DESC",0,0,0,0,2 +"camo_skin92","pilot_camo_skin92","titan_camo_skin92","CAMO","models/camo_skins/camo_skin92_col","#CAMO_SKIN_92","#CAMO_SKIN_92_DESC",0,0,0,0,1 +"camo_skin93","pilot_camo_skin93","titan_camo_skin93","CAMO","models/camo_skins/camo_skin93_col","#CAMO_SKIN_93","#CAMO_SKIN_93_DESC",0,0,0,0,2 +"camo_skin94","pilot_camo_skin94","titan_camo_skin94","CAMO","models/camo_skins/camo_skin94_col","#CAMO_SKIN_94","#CAMO_SKIN_94_DESC",0,0,0,0,2 +"camo_skin95","pilot_camo_skin95","titan_camo_skin95","CAMO","models/camo_skins/camo_skin95_col","#CAMO_SKIN_95","#CAMO_SKIN_95_DESC",150,100,75,50,4 +"camo_skin96","pilot_camo_skin96","titan_camo_skin96","CAMO","models/camo_skins/camo_skin96_col","#CAMO_SKIN_96","#CAMO_SKIN_96_DESC",150,100,75,50,4 +"camo_skin97","pilot_camo_skin97","titan_camo_skin97","CAMO","models/camo_skins/camo_skin97_col","#CAMO_SKIN_97","#CAMO_SKIN_97_DESC",0,0,0,0,1 +"camo_skin98","pilot_camo_skin98","titan_camo_skin98","CAMO","models/camo_skins/camo_skin98_col","#CAMO_SKIN_98","#CAMO_SKIN_98_DESC",150,100,75,50,4 +"camo_skin99","pilot_camo_skin99","titan_camo_skin99","CAMO","models/camo_skins/camo_skin99_col","#CAMO_SKIN_99","#CAMO_SKIN_99_DESC",150,100,75,50,4 +"camo_skin101","pilot_camo_skin101","titan_camo_skin101","CAMO","models/camo_skins/camo_skin101_col","#CAMO_SKIN_101","#CAMO_SKIN_101_DESC",0,0,0,0,5 +"camo_skin102","pilot_camo_skin102","titan_camo_skin102","CAMO","models/camo_skins/camo_skin102_col","#CAMO_SKIN_102","#CAMO_SKIN_102_DESC",0,0,0,0,5 +"camo_skin103","pilot_camo_skin103","titan_camo_skin103","CAMO","models/camo_skins/camo_skin103_col","#CAMO_SKIN_103","#CAMO_SKIN_103_DESC",0,0,0,0,5 +"camo_skin104","pilot_camo_skin104","titan_camo_skin104","CAMO","models/camo_skins/camo_skin104_col","#CAMO_SKIN_104","#CAMO_SKIN_104_DESC",0,0,0,0,5 +"camo_skin105","pilot_camo_skin105","titan_camo_skin105","CAMO","models/camo_skins/camo_skin105_col","#CAMO_SKIN_105","#CAMO_SKIN_105_DESC",0,0,0,0,5 +"camo_skin106","pilot_camo_skin106","titan_camo_skin106","CAMO","models/camo_skins/camo_skin106_col","#CAMO_SKIN_106","#CAMO_SKIN_106_DESC",0,0,0,0,5 +"camo_skin107","pilot_camo_skin107","titan_camo_skin107","CAMO","models/camo_skins/camo_skin107_col","#CAMO_SKIN_107","#CAMO_SKIN_107_DESC",0,0,0,0,5 +"camo_skin108","pilot_camo_skin108","titan_camo_skin108","CAMO","models/camo_skins/camo_skin108_col","#CAMO_SKIN_108","#CAMO_SKIN_108_DESC",0,0,0,0,5 +"camo_skin109","pilot_camo_skin109","titan_camo_skin109","CAMO","models/camo_skins/camo_skin109_col","#CAMO_SKIN_109","#CAMO_SKIN_109_DESC",0,0,0,0,5 +"camo_skin110","pilot_camo_skin110","titan_camo_skin110","CAMO","models/camo_skins/camo_skin110_col","#CAMO_SKIN_110","#CAMO_SKIN_110_DESC",0,0,0,0,5 +"camo_skin111","pilot_camo_skin111","titan_camo_skin111","CAMO","models/camo_skins/camo_skin111_col","#CAMO_SKIN_111","#CAMO_SKIN_111_DESC",0,0,0,0,5 +"camo_skin112","pilot_camo_skin112","titan_camo_skin112","CAMO","models/camo_skins/camo_skin112_col","#CAMO_SKIN_112","#CAMO_SKIN_112_DESC",0,0,0,0,5 +"camo_skin113","pilot_camo_skin113","titan_camo_skin113","CAMO","models/camo_skins/camo_skin113_col","#CAMO_SKIN_113","#CAMO_SKIN_113_DESC",0,0,0,0,5 +"camo_skin114","pilot_camo_skin114","titan_camo_skin114","CAMO","models/camo_skins/camo_skin114_col","#CAMO_SKIN_114","#CAMO_SKIN_114_DESC",0,0,0,0,5 +"camo_skin115","pilot_camo_skin115","titan_camo_skin115","CAMO","models/camo_skins/camo_skin115_col","#CAMO_SKIN_115","#CAMO_SKIN_115_DESC",0,0,0,0,5 +"camo_skin116","pilot_camo_skin116","titan_camo_skin116","CAMO","models/camo_skins/camo_skin116_col","#CAMO_SKIN_116","#CAMO_SKIN_116_DESC",0,0,0,0,5 +"camo_skin117","pilot_camo_skin117","titan_camo_skin117","CAMO","models/camo_skins/camo_skin117_col","#CAMO_SKIN_117","#CAMO_SKIN_117_DESC",0,0,0,0,5 +"camo_skin118","pilot_camo_skin118","titan_camo_skin118","CAMO","models/camo_skins/camo_skin118_col","#CAMO_SKIN_118","#CAMO_SKIN_118_DESC",0,0,0,0,5 +"camo_skin119","pilot_camo_skin119","titan_camo_skin119","CAMO","models/camo_skins/camo_skin119_col","#CAMO_SKIN_119","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin120","pilot_camo_skin120","titan_camo_skin120","CAMO","models/camo_skins/camo_skin120_col","#CAMO_SKIN_120","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin121","pilot_camo_skin121","titan_camo_skin121","CAMO","models/camo_skins/camo_skin121_col","#CAMO_SKIN_121","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin122","pilot_camo_skin122","titan_camo_skin122","CAMO","models/camo_skins/camo_skin122_col","#CAMO_SKIN_122","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin123","pilot_camo_skin123","titan_camo_skin123","CAMO","models/camo_skins/camo_skin123_col","#CAMO_SKIN_123","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin124","pilot_camo_skin124","titan_camo_skin124","CAMO","models/camo_skins/camo_skin124_col","#CAMO_SKIN_124","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin125","pilot_camo_skin125","titan_camo_skin125","CAMO","models/camo_skins/camo_skin125_col","#CAMO_SKIN_125","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin126","pilot_camo_skin126","titan_camo_skin126","CAMO","models/camo_skins/camo_skin126_col","#CAMO_SKIN_126","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin127","pilot_camo_skin127","titan_camo_skin127","CAMO","models/camo_skins/camo_skin127_col","#CAMO_SKIN_127","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin128","pilot_camo_skin128","titan_camo_skin128","CAMO","models/camo_skins/camo_skin128_col","#CAMO_SKIN_128","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin129","pilot_camo_skin129","titan_camo_skin129","CAMO","models/camo_skins/camo_skin129_col","#CAMO_SKIN_129","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin130","pilot_camo_skin130","titan_camo_skin130","CAMO","models/camo_skins/camo_skin130_col","#CAMO_SKIN_130","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin131","pilot_camo_skin131","titan_camo_skin131","CAMO","models/camo_skins/camo_skin131_col","#CAMO_SKIN_131","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin132","pilot_camo_skin132","titan_camo_skin132","CAMO","models/camo_skins/camo_skin132_col","#CAMO_SKIN_132","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin133","pilot_camo_skin133","titan_camo_skin133","CAMO","models/camo_skins/camo_skin133_col","#CAMO_SKIN_133","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin134","pilot_camo_skin134","titan_camo_skin134","CAMO","models/camo_skins/camo_skin134_col","#CAMO_SKIN_134","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin135","pilot_camo_skin135","titan_camo_skin135","CAMO","models/camo_skins/camo_skin135_col","#CAMO_SKIN_135","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin136","pilot_camo_skin136","titan_camo_skin136","CAMO","models/camo_skins/camo_skin136_col","#CAMO_SKIN_136","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin137","pilot_camo_skin137","titan_camo_skin137","CAMO","models/camo_skins/camo_skin137_col","#CAMO_SKIN_137","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin138","pilot_camo_skin138","titan_camo_skin138","CAMO","models/camo_skins/camo_skin138_col","#CAMO_SKIN_138","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin139","pilot_camo_skin139","titan_camo_skin139","CAMO","models/camo_skins/camo_skin139_col","#CAMO_SKIN_139","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin140","pilot_camo_skin140","titan_camo_skin140","CAMO","models/camo_skins/camo_skin140_col","#CAMO_SKIN_140","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin141","pilot_camo_skin141","titan_camo_skin141","CAMO","models/camo_skins/camo_skin141_col","#CAMO_SKIN_141","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin142","pilot_camo_skin142","titan_camo_skin142","CAMO","models/camo_skins/camo_skin142_col","#CAMO_SKIN_142","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin143","pilot_camo_skin143","titan_camo_skin143","CAMO","models/camo_skins/camo_skin143_col","#CAMO_SKIN_143","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin144","pilot_camo_skin144","titan_camo_skin144","CAMO","models/camo_skins/camo_skin144_col","#CAMO_SKIN_144","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin145","pilot_camo_skin145","titan_camo_skin145","CAMO","models/camo_skins/camo_skin145_col","#CAMO_SKIN_145","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin146","pilot_camo_skin146","titan_camo_skin146","CAMO","models/camo_skins/camo_skin146_col","#CAMO_SKIN_146","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin147","pilot_camo_skin147","titan_camo_skin147","CAMO","models/camo_skins/camo_skin147_col","#CAMO_SKIN_147","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin148","pilot_camo_skin148","titan_camo_skin148","CAMO","models/camo_skins/camo_skin148_col","#CAMO_SKIN_148","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin149","pilot_camo_skin149","titan_camo_skin149","CAMO","models/camo_skins/camo_skin149_col","#CAMO_SKIN_149","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin150","pilot_camo_skin150","titan_camo_skin150","CAMO","models/camo_skins/camo_skin150_col","#CAMO_SKIN_150","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin151","pilot_camo_skin151","titan_camo_skin151","CAMO","models/camo_skins/camo_skin151_col","#CAMO_SKIN_151","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin152","pilot_camo_skin152","titan_camo_skin152","CAMO","models/camo_skins/camo_skin152_col","#CAMO_SKIN_152","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin153","pilot_camo_skin153","titan_camo_skin153","CAMO","models/camo_skins/camo_skin153_col","#CAMO_SKIN_153","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin154","pilot_camo_skin154","titan_camo_skin154","CAMO","models/camo_skins/camo_skin154_col","#CAMO_SKIN_154","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin155","pilot_camo_skin155","titan_camo_skin155","CAMO","models/camo_skins/camo_skin155_col","#CAMO_SKIN_155","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin156","pilot_camo_skin156","titan_camo_skin156","CAMO","models/camo_skins/camo_skin156_col","#CAMO_SKIN_156","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin157","pilot_camo_skin157","titan_camo_skin157","CAMO","models/camo_skins/camo_skin157_col","#CAMO_SKIN_157","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin158","pilot_camo_skin158","titan_camo_skin158","CAMO","models/camo_skins/camo_skin158_col","#CAMO_SKIN_158","#CAMO_SKIN_120_DESC",0,0,0,0,5 +"camo_skin159","pilot_camo_skin159","titan_camo_skin159","CAMO","models/camo_skins/camo_skin159_col","#CAMO_SKIN_159","#CAMO_SKIN_119_DESC",0,0,0,0,5 +"camo_skin160","pilot_camo_skin160","titan_camo_skin160","CAMO","models/camo_skins/camo_skin160_col","#CAMO_SKIN_160","#CAMO_SKIN_120_DESC",0,0,0,0,5 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/community_entries.csv b/Northstar.CustomServers/mod/scripts/datatable/community_entries.csv new file mode 100644 index 00000000..0616f131 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/community_entries.csv @@ -0,0 +1,22 @@ +category,key,locString +"categories","gaming","#COMMUNITY_CATEGORY_GAMING" +"categories","lifestyle","#COMMUNITY_CATEGORY_LIFESTYLE" +"categories","geography","#COMMUNITY_CATEGORY_GEOGRAPHY" +"categories","tech","#COMMUNITY_CATEGORY_TECH" +"categories","other","#COMMUNITY_CATEGORY_OTHER" +"regions","North America","#COMMUNITY_REGION_NORTHAMERICA" +"regions","Europe","#COMMUNITY_REGION_EUROPE" +"regions","South America","#COMMUNITY_REGION_SOUTHAMERICA" +"regions","Asia","#COMMUNITY_REGION_ASIA" +"regions","Oceania","#COMMUNITY_REGION_AUSTRALIA" +"languages","English","#COMMUNITY_LANGUAGE_ENGLISH" +"languages","French","#COMMUNITY_LANGUAGE_FRENCH" +"languages","Italian","#COMMUNITY_LANGUAGE_ITALIAN" +"languages","German","#COMMUNITY_LANGUAGE_GERMAN" +"languages","Spanish","#COMMUNITY_LANGUAGE_SPANISH" +"languages","MSpanish","#COMMUNITY_LANGUAGE_MSPANISH" +"languages","Japanese","#COMMUNITY_LANGUAGE_JAPANESE" +"languages","TChinese","#COMMUNITY_LANGUAGE_TCHINESE" +"languages","Russian","#COMMUNITY_LANGUAGE_RUSSIAN" +"languages","Portuguese","#COMMUNITY_LANGUAGE_PORTUGUESE" +"languages","Polish","#COMMUNITY_LANGUAGE_POLISH" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/death_hints_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/death_hints_mp.csv new file mode 100644 index 00000000..4388ab0f --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/death_hints_mp.csv @@ -0,0 +1,381 @@ +source,className,locString,mapName,gameMode +"titan_class","ion","#DEATH_HINT_ION_001","","" +"titan_class","ion","#DEATH_HINT_ION_002","","" +"titan_class","ion","#DEATH_HINT_ION_003","","" +"titan_class","ion","#DEATH_HINT_ION_004","","" +"titan_class","ion","#DEATH_HINT_ION_005","","" +"titan_class","ion","#DEATH_HINT_ION_006","","" +"titan_class","legion","#DEATH_HINT_LEGION_001","","" +"titan_class","legion","#DEATH_HINT_LEGION_002","","" +"titan_class","legion","#DEATH_HINT_LEGION_003","","" +"titan_class","legion","#DEATH_HINT_LEGION_004","","" +"titan_class","legion","#DEATH_HINT_LEGION_005","","" +"titan_class","legion","#DEATH_HINT_LEGION_006","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_001","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_002","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_003","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_004","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_005","","" +"titan_class","northstar","#DEATH_HINT_NORTHSTAR_006","","" +"titan_class","ronin","#DEATH_HINT_RONIN_001","","" +"titan_class","ronin","#DEATH_HINT_RONIN_002","","" +"titan_class","ronin","#DEATH_HINT_RONIN_003","","" +"titan_class","ronin","#DEATH_HINT_RONIN_004","","" +"titan_class","ronin","#DEATH_HINT_RONIN_005","","" +"titan_class","ronin","#DEATH_HINT_RONIN_006","","" +"titan_class","ronin","#DEATH_HINT_RONIN_007","","" +"titan_class","ronin","#DEATH_HINT_RONIN_008","","" +"titan_class","ronin","#DEATH_HINT_RONIN_009","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_001","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_002","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_003","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_004","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_005","","" +"titan_class","scorch","#DEATH_HINT_SCORCH_006","","" +"titan_class","tone","#DEATH_HINT_TONE_001","","" +"titan_class","tone","#DEATH_HINT_TONE_002","","" +"titan_class","tone","#DEATH_HINT_TONE_003","","" +"titan_class","tone","#DEATH_HINT_TONE_004","","" +"titan_class","tone","#DEATH_HINT_TONE_005","","" +"titan_class","tone","#DEATH_HINT_TONE_006","","" +"weapon","mp_ability_cloak","#DEATH_HINT_CLOAK_001","","" +"weapon","mp_ability_cloak","#DEATH_HINT_CLOAK_002","","" +"weapon","mp_ability_cloak","#DEATH_HINT_CLOAK_003","","" +"weapon","mp_ability_grapple","#DEATH_HINT_GRAPPLE_001","","" +"weapon","mp_ability_heal","#DEATH_HINT_STIM_001","","" +"weapon","mp_ability_heal","#DEATH_HINT_STIM_002","","" +"weapon","mp_ability_heal","#DEATH_HINT_STIM_003","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_001","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_002","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_003","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_004","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_005","","" +"weapon","mp_ability_holopilot","#DEATH_HINT_HOLOPILOT_006","","" +"weapon","mp_ability_phase_rewind","#DEATH_HINT_PHASE_REWIND_001","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_001","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_002","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_003","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_004","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_005","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_006","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_007","","" +"weapon","mp_ability_shifter","#DEATH_HINT_PHASESHIFT_008","","" +"weapon","mp_ability_sonar","#DEATH_HINT_SONAR_001","","" +"weapon","mp_titanability_ammo_swap","#DEATH_HINT_AMMO_SWAP_001_MP","","" +"weapon","mp_titanability_basic_block","#DEATH_HINT_SWORD_BLOCK_001_MP","","" +"weapon","mp_titanability_gun_shield","#DEATH_HINT_GUN_SHIELD_001_MP","","" +"weapon","mp_titanability_hover","#DEATH_HINT_TITAN_HOVER_001","","" +"weapon","mp_titanability_laser_trip","#DEATH_HINT_LASER_TRIPWIRE_001","","" +"weapon","mp_titanability_particle_wall","#DEATH_HINT_PARTICLE_WALL_001_MP","","" +"weapon","mp_titanability_particle_wall","#DEATH_HINT_PARTICLE_WALL_002_MP","","" +"weapon","mp_titanability_particle_wall","#DEATH_HINT_PARTICLE_WALL_003_MP","","" +"weapon","mp_titanability_phase_dash","#DEATH_HINT_PHASE_DASH_001_MP","","" +"weapon","mp_titanability_phase_dash","#DEATH_HINT_PHASE_DASH_002_MP","","" +"weapon","mp_titanability_power_shot","#DEATH_HINT_POWER_SHOT_001_MP","","" +"weapon","mp_titanability_power_shot","#DEATH_HINT_POWER_SHOT_002_MP","","" +"weapon","mp_titanability_slow_trap","#DEATH_HINT_INCENDIARY_TRAP_001","","" +"weapon","mp_titanability_tether_trap","#DEATH_HINT_TETHER_TRAP_001_MP","","" +"weapon","mp_titancore_flame_wave","#DEATH_HINT_FLAME_CORE_001_MP","","" +"weapon","mp_titancore_flight_core","#DEATH_HINT_FLIGHT_CORE_001_MP","","" +"weapon","mp_titancore_laser_cannon","#DEATH_HINT_LASER_CANNON_001_MP","","" +"weapon","mp_titancore_salvo_core","#DEATH_HINT_SALVO_CORE_001_MP","","" +"weapon","mp_titancore_shift_core","#DEATH_HINT_SHIFT_CORE_001","","" +"weapon","mp_titancore_siege_mode","#DEATH_HINT_SMART_CORE_001_MP","","" +"weapon","mp_titanweapon_arc_wave","#DEATH_HINT_ARC_WAVE_001","","" +"weapon","mp_titanweapon_flame_wall","#DEATH_HINT_FIREWALL_001_MP","","" +"weapon","mp_titanweapon_heat_shield","#DEATH_HINT_HEAT_SHIELD_001_MP","","" +"weapon","mp_titanweapon_laser_lite","#DEATH_HINT_LASER_SHOT_001_MP","","" +"weapon","mp_titanweapon_leadwall","#DEATH_HINT_LEADWALL_001","","" +"weapon","mp_titanweapon_leadwall","#DEATH_HINT_LEADWALL_002","","" +"weapon","mp_titanweapon_leadwall","#DEATH_HINT_LEADWALL_003","","" +"weapon","mp_titanweapon_leadwall","#DEATH_HINT_LEADWALL_004","","" +"weapon","mp_titanweapon_meteor","#DEATH_HINT_THERMITE_LAUNCHER_001","","" +"weapon","mp_titanweapon_meteor","#DEATH_HINT_THERMITE_LAUNCHER_002","","" +"weapon","mp_titanweapon_meteor","#DEATH_HINT_THERMITE_LAUNCHER_003","","" +"weapon","mp_titanweapon_meteor","#DEATH_HINT_THERMITE_LAUNCHER_004","","" +"weapon","mp_titanweapon_meteor","#DEATH_HINT_THERMITE_LAUNCHER_005","","" +"weapon","mp_titanweapon_particle_accelerator","#DEATH_HINT_SPLITTER_RIFLE_001","","" +"weapon","mp_titanweapon_particle_accelerator","#DEATH_HINT_SPLITTER_RIFLE_002","","" +"weapon","mp_titanweapon_particle_accelerator","#DEATH_HINT_SPLITTER_RIFLE_003","","" +"weapon","mp_titanweapon_particle_accelerator","#DEATH_HINT_SPLITTER_RIFLE_004","","" +"weapon","mp_titanweapon_predator_cannon","#DEATH_HINT_PREDATOR_CANNON_001","","" +"weapon","mp_titanweapon_predator_cannon","#DEATH_HINT_PREDATOR_CANNON_002","","" +"weapon","mp_titanweapon_predator_cannon","#DEATH_HINT_PREDATOR_CANNON_003","","" +"weapon","mp_titanweapon_predator_cannon","#DEATH_HINT_PREDATOR_CANNON_004","","" +"weapon","mp_titanweapon_predator_cannon","#DEATH_HINT_PREDATOR_CANNON_005","","" +"weapon","mp_titanweapon_sniper","#DEATH_HINT_PLASMA_RAILGUN_001","","" +"weapon","mp_titanweapon_sniper","#DEATH_HINT_PLASMA_RAILGUN_002","","" +"weapon","mp_titanweapon_sniper","#DEATH_HINT_PLASMA_RAILGUN_003","","" +"weapon","mp_titanweapon_sniper","#DEATH_HINT_PLASMA_RAILGUN_004","","" +"weapon","mp_titanweapon_sniper","#DEATH_HINT_PLASMA_RAILGUN_005","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_001","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_002","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_003","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_004","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_005","","" +"weapon","mp_titanweapon_sticky_40mm","#DEATH_HINT_40MM_TRACKER_006","","" +"weapon","mp_titanweapon_tracker_rockets","#DEATH_HINT_TRACKING_ROCKETS_001_MP","","" +"weapon","mp_titanweapon_tracker_rockets","#DEATH_HINT_TRACKING_ROCKETS_002_MP","","" +"weapon","mp_titanweapon_tracker_rockets","#DEATH_HINT_TRACKING_ROCKETS_003","","" +"weapon","mp_titanweapon_vortex_shield","#DEATH_HINT_VORTEX_SHIELD_001","","" +"weapon","mp_titanweapon_vortex_shield","#DEATH_HINT_VORTEX_SHIELD_002_MP","","" +"weapon","mp_weapon_alternator_smg","#DEATH_HINT_ALTERNATOR_001","","" +"weapon","mp_weapon_alternator_smg","#DEATH_HINT_ALTERNATOR_002","","" +"weapon","mp_weapon_arc_launcher","#DEATH_HINT_ARCLAUNCHER_001","","" +"weapon","mp_weapon_arc_launcher","#DEATH_HINT_ARCLAUNCHER_002","","" +"weapon","mp_weapon_arc_launcher","#DEATH_HINT_ARCLAUNCHER_003","","" +"weapon","mp_weapon_arc_launcher","#DEATH_HINT_ARCLAUNCHER_004","","" +"weapon","mp_weapon_autopistol","#DEATH_HINT_RE45_001","","" +"weapon","mp_weapon_autopistol","#DEATH_HINT_RE45_002","","" +"weapon","mp_weapon_autopistol","#DEATH_HINT_RE45_003","","" +"weapon","mp_weapon_car","#DEATH_HINT_CAR_001","","" +"weapon","mp_weapon_car","#DEATH_HINT_CAR_002","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_001","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_002","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_003","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_004","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_005","","" +"weapon","mp_weapon_defender","#DEATH_HINT_CHARGERIFLE_006","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_001","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_002","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_003","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_004","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_005","","" +"weapon","mp_weapon_deployable_cover","#DEATH_HINT_AWALL_006","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_001","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_002","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_003","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_004","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_005","","" +"weapon","mp_weapon_dmr","#DEATH_HINT_DMR_006","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_001","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_002","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_003","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_004","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_005","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_006","","" +"weapon","mp_weapon_doubletake","#DEATH_HINT_DOUBLETAKE_007","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_001","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_002","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_003","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_004","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_005","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_006","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_007","","" +"weapon","mp_weapon_epg","#DEATH_HINT_EPG1_008","","" +"weapon","mp_weapon_esaw","#DEATH_HINT_DEVOTION_001","","" +"weapon","mp_weapon_esaw","#DEATH_HINT_DEVOTION_002","","" +"weapon","mp_weapon_esaw","#DEATH_HINT_DEVOTION_003","","" +"weapon","mp_weapon_esaw","#DEATH_HINT_DEVOTION_004","","" +"weapon","mp_weapon_frag_drone","#DEATH_HINT_FRAG_DRONE_001","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_001","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_002","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_003","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_004","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_005","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_006","","" +"weapon","mp_weapon_frag_grenade","#DEATH_HINT_GRENADE_FRAG_007","","" +"weapon","mp_weapon_g2","#DEATH_HINT_G2_001","","" +"weapon","mp_weapon_g3","#DEATH_HINT_G2_002","","" +"weapon","mp_weapon_g4","#DEATH_HINT_G2_003","","" +"weapon","mp_weapon_g5","#DEATH_HINT_G2_004","","" +"weapon","mp_weapon_grenade_electric_smoke","#DEATH_HINT_GRENADE_ELECTRIC_SMOKE_001","","" +"weapon","mp_weapon_grenade_electric_smoke","#DEATH_HINT_GRENADE_ELECTRIC_SMOKE_002","","" +"weapon","mp_weapon_grenade_electric_smoke","#DEATH_HINT_GRENADE_ELECTRIC_SMOKE_003","","" +"weapon","mp_weapon_grenade_electric_smoke","#DEATH_HINT_GRENADE_ELECTRIC_SMOKE_004","","" +"weapon","mp_weapon_grenade_emp","#DEATH_HINT_GRENADE_EMP_001","","" +"weapon","mp_weapon_grenade_emp","#DEATH_HINT_GRENADE_EMP_002","","" +"weapon","mp_weapon_grenade_emp","#DEATH_HINT_GRENADE_EMP_003","","" +"weapon","mp_weapon_grenade_emp","#DEATH_HINT_GRENADE_EMP_004","","" +"weapon","mp_weapon_grenade_emp","#DEATH_HINT_GRENADE_EMP_005","","" +"weapon","mp_weapon_grenade_gravity","#DEATH_HINT_GRENADE_GRAVITY_001","","" +"weapon","mp_weapon_grenade_gravity","#DEATH_HINT_GRENADE_GRAVITY_002","","" +"weapon","mp_weapon_grenade_gravity","#DEATH_HINT_GRENADE_GRAVITY_003","","" +"weapon","mp_weapon_grenade_gravity","#DEATH_HINT_GRENADE_GRAVITY_004","","" +"weapon","mp_weapon_grenade_gravity","#DEATH_HINT_GRENADE_GRAVITY_005","","" +"weapon","mp_weapon_grenade_sonar","#DEATH_HINT_GRENADE_SONAR_001","","" +"weapon","mp_weapon_grenade_sonar","#DEATH_HINT_GRENADE_SONAR_002","","" +"weapon","mp_weapon_grenade_sonar","#DEATH_HINT_GRENADE_SONAR_003","","" +"weapon","mp_weapon_grenade_sonar","#DEATH_HINT_GRENADE_SONAR_004","","" +"weapon","mp_weapon_hemlok","#DEATH_HINT_HEMLOK_001","","" +"weapon","mp_weapon_hemlok","#DEATH_HINT_HEMLOK_002","","" +"weapon","mp_weapon_hemlok_smg","#DEATH_HINT_VOLT_001","","" +"weapon","mp_weapon_hemlok_smg","#DEATH_HINT_VOLT_002","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_001","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_002","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_003","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_004","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_005","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_006","","" +"weapon","mp_weapon_lmg","#DEATH_HINT_SPITFIRE_007","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_001","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_002","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_003","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_004","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_005","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_006","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_007","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_008","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_009","","" +"weapon","mp_weapon_lstar","#DEATH_HINT_LSTAR_010","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_001","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_002","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_003","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_004","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_005","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_006","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_007","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_008","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_009","","" +"weapon","mp_weapon_mastiff","#DEATH_HINT_MASTIFF_010","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_001","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_002","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_003","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_004","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_005","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_006","","" +"weapon","mp_weapon_mgl","#DEATH_HINT_MGL_007","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_001","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_002","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_003","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_004","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_005","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_006","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_007","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_008","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_009","","" +"weapon","mp_weapon_pulse_lmg","#DEATH_HINT_COLDWAR_010","","" +"weapon","mp_weapon_r97","#DEATH_HINT_97_001","","" +"weapon","mp_weapon_r97","#DEATH_HINT_97_002","","" +"weapon","mp_weapon_r97","#DEATH_HINT_97_003","","" +"weapon","mp_weapon_r97","#DEATH_HINT_97_004","","" +"weapon","mp_weapon_rocket_launcher","#DEATH_HINT_ARCHER_001","","" +"weapon","mp_weapon_rocket_launcher","#DEATH_HINT_ARCHER_002","","" +"weapon","mp_weapon_rocket_launcher","#DEATH_HINT_ARCHER_003","","" +"weapon","mp_weapon_rocket_launcher","#DEATH_HINT_ARCHER_004","","" +"weapon","mp_weapon_rocket_launcher","#DEATH_HINT_ARCHER_005","","" +"weapon","mp_weapon_rspn101","#DEATH_HINT_102_001","","" +"weapon","mp_weapon_rspn102","#DEATH_HINT_102_002","","" +"weapon","mp_weapon_satchel","#DEATH_HINT_SATCHEL_001","","" +"weapon","mp_weapon_satchel","#DEATH_HINT_SATCHEL_002","","" +"weapon","mp_weapon_satchel","#DEATH_HINT_SATCHEL_003","","" +"weapon","mp_weapon_semipistol","#DEATH_HINT_P2011_001","","" +"weapon","mp_weapon_semipistol","#DEATH_HINT_P2011_002","","" +"weapon","mp_weapon_semipistol","#DEATH_HINT_P2011_003","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_001","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_002","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_003","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_004","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_005","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_006","","" +"weapon","mp_weapon_shotgun","#DEATH_HINT_EVA8_007","","" +"weapon","mp_weapon_shotgun_pistol","#DEATH_HINT_MOZAMBIQUE_001","","" +"weapon","mp_weapon_shotgun_pistol","#DEATH_HINT_MOZAMBIQUE_002","","" +"weapon","mp_weapon_shotgun_pistol","#DEATH_HINT_MOZAMBIQUE_003","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_001","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_002","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_003","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_004","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_005","","" +"weapon","mp_weapon_smart_pistol","#DEATH_HINT_SMARTPISTOL_006","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_001","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_002","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_003","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_004","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_005","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_006","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_007","","" +"weapon","mp_weapon_smr","#DEATH_HINT_SMR_008","","" +"weapon","mp_weapon_sniper","#DEATH_HINT_KRABER_001","","" +"weapon","mp_weapon_sniper","#DEATH_HINT_KRABER_002","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_001","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_002","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_003","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_004","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_005","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_006","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_007","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_008","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_009","","" +"weapon","mp_weapon_softball","#DEATH_HINT_SOFTBALL_010","","" +"weapon","mp_weapon_thermite_grenade","#DEATH_HINT_GRENADE_THERMITE_001","","" +"weapon","mp_weapon_thermite_grenade","#DEATH_HINT_GRENADE_THERMITE_002","","" +"weapon","mp_weapon_thermite_grenade","#DEATH_HINT_GRENADE_THERMITE_003","","" +"weapon","mp_weapon_thermite_grenade","#DEATH_HINT_GRENADE_THERMITE_004","","" +"weapon","mp_weapon_vinson","#DEATH_HINT_VINSON_001","","" +"weapon","mp_weapon_vinson","#DEATH_HINT_VINSON_002","","" +"weapon","mp_weapon_vinson","#DEATH_HINT_VINSON_003","","" +"weapon","mp_weapon_wingman","#DEATH_HINT_WINGMAN_001","","" +"weapon","mp_weapon_wingman","#DEATH_HINT_WINGMAN_002","","" +"weapon","mp_weapon_wingman","#DEATH_HINT_WINGMAN_003","","" +"weapon","mp_weapon_wingman","#DEATH_HINT_WINGMAN_004","","" +"weapon","mp_weapon_wingman_n","#DEATH_HINT_WINGMAN_N_001","","" +"weapon","pas_power_cell","#DEATH_HINT_POWER_CELL_001","","" +"weapon","pas_fast_health_regen","#DEATH_HINT_FAST_REGEN_001","","" +"weapon","pas_ordnance_pack","#DEATH_HINT_ORDNANCE_EXPERT_001","","" +"weapon","pas_ordnance_pack","#DEATH_HINT_ORDNANCE_EXPERT_002","","" +"weapon","pas_ordnance_pack","#DEATH_HINT_ORDNANCE_EXPERT_003","","" +"weapon","pas_ordnance_pack","#DEATH_HINT_ORDNANCE_EXPERT_004","","" +"weapon","pas_fast_embark","#DEATH_HINT_PHASE_EMBARK_001","","" +"weapon","pas_fast_embark","#DEATH_HINT_PHASE_EMBARK_002","","" +"weapon","pas_fast_embark","#DEATH_HINT_PHASE_EMBARK_003","","" +"weapon","pas_enemy_death_icons","#DEATH_HINT_KILL_REPORT_001","","" +"weapon","pas_enemy_death_icons","#DEATH_HINT_KILL_REPORT_002","","" +"weapon","pas_enemy_death_icons","#DEATH_HINT_KILL_REPORT_003","","" +"weapon","pas_wallhang","#DEATH_HINT_WALLHANG_001","","" +"weapon","pas_wallhang","#DEATH_HINT_WALLHANG_002","","" +"weapon","pas_ads_hover","#DEATH_HINT_HOVER_001","","" +"weapon","pas_ads_hover","#DEATH_HINT_HOVER_002","","" +"weapon","pas_ads_hover","#DEATH_HINT_HOVER_003","","" +"weapon","pas_ads_hover","#DEATH_HINT_HOVER_004","","" +"weapon","pas_ads_hover","#DEATH_HINT_HOVER_005","","" +"weapon","pas_stealth_movement","#DEATH_HINT_LOW_PROFILE_001","","" +"weapon","pas_enhanced_titan_ai","#DEATH_HINT_ASSAULT_CHIP_001","","" +"weapon","pas_enhanced_titan_ai","#DEATH_HINT_ASSAULT_CHIP_002","","" +"weapon","pas_auto_eject","#DEATH_HINT_AUTO_EJECT_001","","" +"weapon","pas_auto_eject","#DEATH_HINT_AUTO_EJECT_002","","" +"weapon","pas_auto_eject","#DEATH_HINT_AUTO_EJECT_003","","" +"weapon","pas_auto_eject","#DEATH_HINT_AUTO_EJECT_004","","" +"weapon","pas_mobility_dash_capacity","#DEATH_HINT_TURBO_ENGINE_001","","" +"weapon","pas_mobility_dash_capacity","#DEATH_HINT_TURBO_ENGINE_002","","" +"weapon","pas_mobility_dash_capacity","#DEATH_HINT_TURBO_ENGINE_003","","" +"weapon","pas_hyper_core","#DEATH_HINT_OVERCORE_001","","" +"weapon","pas_build_up_nuclear_core","#DEATH_HINT_NUKE_EJECT_001","","" +"weapon","pas_build_up_nuclear_core","#DEATH_HINT_NUKE_EJECT_002","","" +"weapon","pas_anti_rodeo","#DEATH_HINT_COUNTER_READY_001","","" +"weapon","pas_anti_rodeo","#DEATH_HINT_COUNTER_READY_002","","" +"weapon","pas_warpfall","#DEATH_HINT_WARPFALL_001","","" +"weapon","pas_bubbleshield","#DEATH_HINT_DOME_SHIELD_001","","" +"weapon","pas_bubbleshield","#DEATH_HINT_DOME_SHIELD_002","","" +"npc_title","#NPC_TITAN_AUTO_NUKE","#HINT_FD_TITAN_AUTO_NUKE","","fd" +"npc_title","#NPC_TITAN_AUTO_NUKE","#HINT_FD_TITAN_AUTO_NUKE2","","fd" +"npc_title","#NPC_TITAN_ARC","#HINT_FD_TITAN_ARC","","fd" +"npc_title","#NPC_TITAN_ARC","#HINT_FD_TITAN_ARC2","","fd" +"npc_title","#NPC_TITAN_MORTAR","#HINT_FD_TITAN_MORTAR","","fd" +"npc_title","#NPC_TITAN_MORTAR","#HINT_FD_TITAN_MORTAR2","","fd" +"npc_title","#NPC_SOLDIER","#HINT_FD_SOLDIER","","fd" +"npc_title","#NPC_SPECTRE","#HINT_FD_SPECTRE","","fd" +"npc_title","#NPC_SPECTRE_MORTAR","#HINT_FD_SPECTRE_MORTAR","","fd" +"npc_title","#NPC_SPECTRE_MORTAR","#HINT_FD_SPECTRE_MORTAR2","","fd" +"npc_title","#NPC_STALKER","#HINT_FD_STALKER","","fd" +"npc_title","#NPC_SUPER_SPECTRE","#HINT_FD_SUPER_SPECTRE","","fd" +"npc_title","#NPC_SUPER_SPECTRE","#HINT_FD_SUPER_SPECTRE2","","fd" +"npc_title","#NPC_SPECTRE_SUICIDE","#HINT_FD_SPECTRE_SUICIDE","","fd" +"npc_title","#NPC_DRONE_PLASMA","#HINT_FD_DRONE_PLASMA","","fd" +"npc_title","#NPC_DRONE_CLOAKED","#HINT_FD_DRONE_CLOAKED","","fd" +"npc_title","#NPC_TITAN_STRYDER_LEADWALL","#HINT_FD_TITAN_STRYDER_LEADWALL","","fd" +"npc_title","#NPC_TITAN_STRYDER_SNIPER","#HINT_FD_TITAN_STRYDER_SNIPER","","fd" +"npc_title","#NPC_TITAN_OGRE_METEOR","#HINT_FD_TITAN_OGRE_METEOR","","fd" +"npc_title","#NPC_TITAN_OGRE_MINIGUN","#HINT_FD_TITAN_OGRE_MINIGUN","","fd" +"npc_title","#NPC_TITAN_ATLAS_TRACKER","#HINT_FD_TITAN_ATLAS_TRACKER","","fd" +"npc_title","#NPC_TITAN_ATLAS_STICKYBOMB","#HINT_FD_TITAN_ATLAS_STICKYBOMB","","fd" +"npc_title","#NPC_TITAN_ATLAS_VANGUARD","#HINT_FD_TITAN_ATLAS_VANGUARD","","fd" +"npc_title","#NPC_TITAN_SNIPER_FD","#HINT_FD_TITAN_STRYDER_SNIPER","","fd" +"npc_title","#NPC_TITAN_SNIPER_FD","#HINT_FD_TITAN_STRYDER_SNIPER2","","fd" +"npc_title","#NPC_TITAN_SNIPER_FD","#HINT_FD_TITAN_STRYDER_SNIPER3","","fd" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_001","","" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_002","","" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_003","","" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_004","","" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_005","","" +"titan_class","vanguard","#DEATH_HINT_VANGUARD_006","","" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/default_pilot_loadouts.csv b/Northstar.CustomServers/mod/scripts/datatable/default_pilot_loadouts.csv new file mode 100644 index 00000000..e0fbbcd9 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/default_pilot_loadouts.csv @@ -0,0 +1,11 @@ +name,suit,race,primary,primaryAttachment,primaryMod1,primaryMod2,primaryMod3,secondary,secondaryMod1,secondaryMod2,secondaryMod3,weapon3,weapon3Mod1,weapon3Mod2,weapon3Mod3,ordnance,passive1,passive2 +"#DEFAULT_PILOT_1","grapple","race_human_male","mp_weapon_rspn101","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_frag_grenade","pas_power_cell","pas_enemy_death_icons" +"#DEFAULT_PILOT_2","medium","race_human_female","mp_weapon_car","","","","","mp_weapon_mgl","","","","mp_weapon_autopistol","","","","mp_weapon_grenade_emp","pas_fast_health_regen","pas_wallhang" +"#DEFAULT_PILOT_3","grapple","race_human_female","mp_weapon_lmg","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_thermite_grenade","pas_fast_health_regen","pas_enemy_death_icons" +"#DEFAULT_PILOT_4","medium","race_human_male","mp_weapon_shotgun","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_frag_grenade","pas_power_cell","pas_wallhang" +"#DEFAULT_PILOT_5","geist","race_human_female","mp_weapon_sniper","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_grenade_emp","pas_power_cell","pas_enemy_death_icons" +"#DEFAULT_PILOT_6","grapple","race_human_female","mp_weapon_smr","","","","","mp_weapon_defender","","","","mp_weapon_semipistol","","","","mp_weapon_thermite_grenade","pas_fast_health_regen","pas_wallhang" +"#DEFAULT_PILOT_7","medium","race_human_female","mp_weapon_rspn101","","","","","mp_weapon_mgl","","","","mp_weapon_autopistol","","","","mp_weapon_grenade_emp","pas_power_cell","pas_enemy_death_icons" +"#DEFAULT_PILOT_8","grapple","race_human_male","mp_weapon_car","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_thermite_grenade","pas_fast_health_regen","pas_wallhang" +"#DEFAULT_PILOT_9","grapple","race_human_male","mp_weapon_sniper","","","","","mp_weapon_defender","","","","mp_weapon_semipistol","","","","mp_weapon_frag_grenade","pas_power_cell","pas_enemy_death_icons" +"#DEFAULT_PILOT_10","geist","race_human_male","mp_weapon_smr","","","","","mp_weapon_defender","","","","mp_weapon_autopistol","","","","mp_weapon_grenade_emp","pas_fast_health_regen","pas_wallhang" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/default_titan_loadouts.csv b/Northstar.CustomServers/mod/scripts/datatable/default_titan_loadouts.csv new file mode 100644 index 00000000..b19ef636 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/default_titan_loadouts.csv @@ -0,0 +1,8 @@ +name,primeName,setFile,titanRef,primaryMod,special,antirodeo,passive1,passive2,passive3,passive4,passive5,passive6,voice +"#DEFAULT_TITAN_5","#DEFAULT_TITAN_5_PRIME","titan_atlas_stickybomb","ion","","mp_titanweapon_vortex_shield_ion","mp_titanability_laser_trip","pas_enhanced_titan_ai","pas_ion_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_ion" +"#DEFAULT_TITAN_7","#DEFAULT_TITAN_7_PRIME","titan_ogre_meteor","scorch","","mp_titanweapon_heat_shield","mp_titanability_slow_trap","pas_enhanced_titan_ai","pas_scorch_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_scorch" +"#DEFAULT_TITAN_3","#DEFAULT_TITAN_3_PRIME","titan_stryder_sniper","northstar","","mp_titanability_tether_trap","mp_titanability_hover","pas_enhanced_titan_ai","pas_northstar_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_northstar" +"#DEFAULT_TITAN_2","#DEFAULT_TITAN_2_PRIME","titan_stryder_leadwall","ronin","","mp_titanability_basic_block","mp_titanability_phase_dash","pas_enhanced_titan_ai","pas_ronin_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_ronin" +"#DEFAULT_TITAN_4","#DEFAULT_TITAN_4_PRIME","titan_atlas_tracker","tone","","mp_titanability_particle_wall","mp_titanability_sonar_pulse","pas_enhanced_titan_ai","pas_tone_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_tone" +"#DEFAULT_TITAN_8","#DEFAULT_TITAN_8_PRIME","titan_ogre_minigun","legion","","mp_titanability_gun_shield","mp_titanability_ammo_swap","pas_enhanced_titan_ai","pas_legion_weapon","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_legion" +"#DEFAULT_TITAN_10","#DEFAULT_TITAN_10_PRIME","titan_atlas_vanguard","vanguard","","mp_titanweapon_stun_laser","mp_titanability_rearm","pas_enhanced_titan_ai","pas_vanguard_shield","pas_bubbleshield","pas_vanguard_core1","pas_vanguard_core4","pas_vanguard_core7","titanos_vanguard" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/earn_meter_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/earn_meter_mp.csv new file mode 100644 index 00000000..1c766181 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/earn_meter_mp.csv @@ -0,0 +1,31 @@ +itemRef,earnType,buildingImage,readyImage,nameText +"titan_ronin","GOAL","rui/hud/earn_meter/ajax_building","rui/hud/earn_meter/titan_ready","#RONIN" +"titan","GOAL","rui/hud/earn_meter/ajax_building","rui/hud/earn_meter/titan_ready","#TITAN" +"ion","GOAL","rui/hud/earn_meter/ajax_building","rui/hud/earn_meter/titan_ready","#ION" +"tone","GOAL","rui/hud/earn_meter/ajax_building","rui/hud/earn_meter/titan_ready","#TONE" +"scorch","GOAL","rui/hud/earn_meter/ogre_building","rui/hud/earn_meter/titan_ready","#SCORCH" +"legion","GOAL","rui/hud/earn_meter/ogre_building","rui/hud/earn_meter/titan_ready","#LEGION" +"ronin","GOAL","rui/hud/earn_meter/stryder_building","rui/hud/earn_meter/titan_ready","#RONIN" +"northstar","GOAL","rui/hud/earn_meter/stryder_building","rui/hud/earn_meter/titan_ready","#NORTHSTAR" +"vanguard","GOAL","rui/hud/earn_meter/ajax_building","rui/hud/earn_meter/titan_ready","#VANGUARD" +"core_electric_smoke","REWARD","rui/menu/boosts/boost_icon_electric_smoke","rui/menu/boosts/boost_icon_electric_smoke","#WPN_TITAN_ELECTRIC_SMOKE" +"burnmeter_maphack","REWARD","rui/menu/boosts/boost_icon_map_hack","rui/menu/boosts/boost_icon_map_hack","#BURNMETER_MAP_HACK" +"burnmeter_amped_weapons","REWARD","rui/menu/boosts/boost_icon_amped","rui/menu/boosts/boost_icon_amped","#BURNMETER_AMPED_WEAPONS" +"burnmeter_ticks","REWARD","rui/menu/boosts/boost_icon_tick","rui/menu/boosts/boost_icon_tick","#BURNMETER_TICKS" +"burnmeter_emergency_titan","REWARD","ui/temp","ui/temp","#BURNMETER_EMERGENCY_TITAN" +"burnmeter_random_foil","REWARD","rui/menu/boosts/boost_icon_random","rui/menu/boosts/boost_icon_random","#BURNMETER_RANDOM_FOIL" +"burnmeter_double_agent","REWARD","rui/menu/boosts/burncard_icon","rui/menu/boosts/burncard_icon","#BURNMETER_DOUBLE_AGENT" +"burnmeter_phase_rewind","REWARD","rui/menu/boosts/boost_icon_phase_rewind","rui/menu/boosts/boost_icon_phase_rewind","#WPN_REWIND" +"burnmeter_at_turret_weapon","REWARD","rui/menu/boosts/boost_icon_titan_sentry","rui/menu/boosts/boost_icon_titan_sentry","#BURNMETER_AT_TURRETWEAPON" +"burnmeter_ap_turret_weapon","REWARD","rui/menu/boosts/boost_icon_personel_sentry","rui/menu/boosts/boost_icon_personel_sentry","#BURNMETER_AP_TURRETWEAPON" +"burnmeter_holopilot_nova","REWARD","rui/menu/boosts/boost_icon_holopilot","rui/menu/boosts/boost_icon_holopilot","#WPN_HOLOPILOT_NOVA" +"burnmeter_emergency_battery","REWARD","rui/menu/boosts/boost_icon_battery","rui/menu/boosts/boost_icon_battery","#BURNMETER_EMERGENCY_BATTERY" +"burnmeter_smart_pistol","REWARD","rui/menu/boosts/boost_icon_smart_pistol","rui/menu/boosts/boost_icon_smart_pistol","#WPN_SMART_PISTOL" +"burnmeter_radar_jammer","REWARD","rui/menu/boosts/boost_icon_radar_jam","rui/menu/boosts/boost_icon_radar_jam","#BURNMETER_RADAR_JAMMER" +"burnmeter_hard_cover","REWARD","rui/menu/boosts/boost_icon_shield","rui/menu/boosts/boost_icon_shield","#WPN_HARD_COVER" +"burnmeter_nuke_titan","REWARD","rui/menu/boosts/boost_icon_nuke","rui/menu/boosts/boost_icon_nuke","#WPN_NUKE_TITAN" +"burnmeter_harvester_shield","REWARD","rui/menu/boosts/boost_icon_harvester_shield","rui/menu/boosts/boost_icon_harvester_shield","#BURNMETER_HARVESTER_SHIELD" +"burnmeter_arc_trap","REWARD","rui/menu/boosts/boost_icon_arc_trap","rui/menu/boosts/boost_icon_arc_trap","#WPN_ARC_TRAP" +"burnmeter_at_turret_weapon_infinite","REWARD","rui/menu/boosts/boost_icon_titan_sentry","rui/menu/boosts/boost_icon_titan_sentry","#BURNMETER_AT_TURRETWEAPON" +"burnmeter_ap_turret_weapon_infinite","REWARD","rui/menu/boosts/boost_icon_personel_sentry","rui/menu/boosts/boost_icon_personel_sentry","#BURNMETER_AP_TURRETWEAPON" +"burnmeter_rodeo_grenade","REWARD","rui/menu/boosts/boost_icon_core_overload","rui/menu/boosts/boost_icon_core_overload","#BURNMETER_SUPER_RODEO" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/faction_dialogue.csv b/Northstar.CustomServers/mod/scripts/datatable/faction_dialogue.csv new file mode 100644 index 00000000..8e9673d1 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/faction_dialogue.csv @@ -0,0 +1,273 @@ +conversationname,priority,debounce,disabledForFaction,inheritedDebounceConversations +"scoring_won",3000,10.000000,"","" +"scoring_lost",3000,10.000000,"","" +"scoring_tied",3000,10.000000,"","" +"scoring_wonClose",3000,10.000000,"","" +"scoring_lostClose",3000,10.000000,"","" +"scoring_winning",3000,10.000000,"faction_marvin","" +"scoring_losing",3000,10.000000,"faction_marvin","" +"scoring_winningClose",3000,10.000000,"faction_marvin","" +"scoring_losingClose",3000,10.000000,"faction_marvin","" +"scoring_winningLarge",3000,10.000000,"faction_marvin","" +"scoring_losingLarge",3000,10.000000,"faction_marvin","" +"scoring_lostMercy",3000,10.000000,"","" +"scoring_wonMercy",3000,10.000000,"","" +"fortwar_matchLoss",3000,10.000000,"","" +"scoring_flavor",1500,10.000000,"","" +"scoring_gotMailAlert",1500,10.000000,"","" +"amphp_modeName",1500,10.000000,"","" +"mtitan_modeName",1500,10.000000,"","" +"ffa_modeName",2500,10.000000,"","" +"freea_modeName",2500,10.000000,"","" +"at_modeName",2500,10.000000,"","" +"hp_modeName",2500,10.000000,"","" +"cp_modeName",2500,10.000000,"","" +"phunt_modeName",2500,10.000000,"","" +"fortwar_modeName",2500,10.000000,"","" +"tw_modeName",2500,10.000000,"","" +"ctf_modeName",2500,10.000000,"","" +"bh_modeName",2500,10.000000,"","" +"front_modeName",2500,10.000000,"","" +"frontdef_modeName",2500,10.000000,"","" +"frontatk_modeName",2500,10.000000,"","" +"lts_modeName",2500,10.000000,"","" +"mfd_modeName",2500,10.000000,"","" +"tmfd_modeName",2500,10.000000,"","" +"extract_modeName",2500,10.000000,"","" +"mw_modeName",2500,10.000000,"","" +"pvp_modeName",2500,10.000000,"","" +"raid_modeName",2500,10.000000,"","" +"aslt_modeName",2500,10.000000,"","" +"gnrc_modeDesc",2500,10.000000,"","" +"ffa_modeDesc",2500,10.000000,"","" +"ctf_modeDesc",2500,10.000000,"","" +"lts_modeDesc",2500,10.000000,"","" +"mfd_modeDesc",2500,10.000000,"","" +"ltsd_modeDesc",2500,10.000000,"","" +"ltsa_modeDesc",2500,10.000000,"","" +"hp_modeDesc",2500,10.000000,"","" +"mtitan_modeDesc",2500,10.000000,"","" +"pvp_modeDesc",2500,10.000000,"","" +"phunt_modeDesc",2500,10.000000,"","" +"freea_modeDesc",2500,10.000000,"","" +"grnc_modeDesc",2500,10.000000,"","" +"mp_titanReady",1200,30.000000,"","" +"mp_titanSoon",1200,45.000000,"faction_marvin","" +"mp_titanInbound",1200,10.000000,"","" +"mp_titanEmergency",1200,10.000000,"faction_marvin","" +"mp_evacGo",1500,10.000000,"faction_marvin","" +"mp_evacStop",1500,10.000000,"faction_marvin","" +"mp_evacGoNag",1500,10.000000,"faction_marvin","" +"mp_evacStopNag",1500,10.000000,"faction_marvin","" +"mp_halftime",1500,10.000000,"","" +"mp_sideSwitching",1500,10.000000,"","" +"bh_modeDesc",1500,10.000000,"","" +"bh_incoming",1500,10.000000,"","" +"bh_collect",1500,10.000000,"faction_marvin","" +"bh_decrypt",1500,10.000000,"faction_marvin","" +"bh_collectSuccess",1500,10.000000,"faction_marvin","" +"bh_collectFail",1500,10.000000,"faction_marvin","" +"bh_mvp",1500,10.000000,"faction_marvin","" +"bh_clearedA",1500,10.000000,"","" +"bh_clearedB",1500,10.000000,"","" +"bh_clearedC",1500,10.000000,"","" +"bh_newWave",1500,10.000000,"","" +"bh_bountyClaimedByEnemy",1500,10.000000,"","" +"bh_bountyClaimedByFriendly",1500,10.000000,"","" +"bh_playerKilledBounty",1500,10.000000,"faction_marvin","" +"lts_atk60",1500,10.000000,"faction_marvin","" +"lts_atk30",1500,10.000000,"faction_marvin","" +"lts_def60",1500,10.000000,"faction_marvin","" +"lts_def30",1500,10.000000,"faction_marvin","" +"lts_bombDown",1500,10.000000,"faction_marvin","" +"lts_bombDownAtk",1500,10.000000,"faction_marvin","" +"lts_bombDownDef",1500,10.000000,"faction_marvin","" +"lts_bombPickup",1500,10.000000,"faction_marvin","" +"lts_bombPlanted",1500,10.000000,"faction_marvin","" +"lts_bombDefusedAtk",1500,10.000000,"faction_marvin","" +"lts_bombDefusedDef",1500,10.000000,"faction_marvin","" +"lts_bombPlantedAtk",1500,10.000000,"faction_marvin","" +"lts_bombPlantedDef",1500,10.000000,"faction_marvin","" +"fortwar_turretDeployFriendly",1500,10.000000,"faction_marvin","" +"fortwar_turretDestroyedFriendly",1500,10.000000,"faction_marvin","" +"fortwar_baseShieldDownFriendly",1500,10.000000,"faction_marvin","" +"fortwar_baseShieldDownEnemy",1500,10.000000,"faction_marvin","" +"fortwar_baseShieldUpFriendly",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgFriendly",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgFriendly75",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgFriendly50",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgFriendly25",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgEnemy75",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgEnemy50",1500,10.000000,"faction_marvin","" +"fortwar_baseDmgEnemy25",1500,10.000000,"faction_marvin","" +"fortwar_baseEnemyAllyAttacking",1500,30.000000,"faction_marvin","" +"fortwar_awayTurretsUnderAttack",1450,30.000000,"faction_marvin","" +"fortwar_baseTurretsUnderAttack",1470,30.000000,"faction_marvin","" +"fortwar_turretShieldedByFriendlyPilot",1400,10.000000,"faction_marvin","" +"tw_territoryNag",1500,10.000000,"faction_marvin","" +"fortwar_terEnemyExpelled",1500,60.000000,"faction_marvin","" +"fortwar_terFriendlyExpelled",1450,60.000000,"faction_marvin","" +"fortwar_terEnteredEnemyPilot",1400,60.000000,"faction_marvin","" +"fortwar_terEnteredEnemyTitan",1450,60.000000,"faction_marvin","" +"fortwar_terPresentEnemyTitans",1470,60.000000,"faction_marvin","" +"fortwar_terEnteredEnemyForce",1500,60.000000,"faction_marvin","" +"amphp_friendlyCappingA",1500,30.000000,"","" +"amphp_friendlyCappingB",1500,30.000000,"","" +"amphp_friendlyCappingC",1500,30.000000,"","" +"amphp_friendlyCappedA",1500,10.000000,"faction_marvin","" +"amphp_friendlyCappedB",1500,10.000000,"faction_marvin","" +"amphp_friendlyCappedC",1500,10.000000,"faction_marvin","" +"amphp_friendlyAmpedA",1500,10.000000,"faction_marvin","" +"amphp_friendlyAmpedB",1500,10.000000,"faction_marvin","" +"amphp_friendlyAmpedC",1500,10.000000,"faction_marvin","" +"amphp_enemyCappedA",1500,10.000000,"","" +"amphp_enemyCappedB",1500,10.000000,"","" +"amphp_enemyCappedC",1500,10.000000,"","" +"amphp_enemyAmpedA",1500,10.000000,"","" +"amphp_enemyAmpedB",1500,10.000000,"","" +"amphp_enemyAmpedC",1500,10.000000,"","" +"amphp_friendlyCapAll",2000,10.000000,"","" +"amphp_enemyCapAll",2000,10.000000,"","" +"amphp_youAmpedA",1500,10.000000,"","" +"amphp_youAmpedB",1500,10.000000,"","" +"amphp_youAmpedC",1500,10.000000,"","" +"ctf_flagPickupFriendly",1500,10.000000,"","" +"ctf_flagPickupYou",1500,10.000000,"","" +"ctf_flagReturnedFriendly",1500,10.000000,"","" +"ctf_flagReturnedEnemy",1500,10.000000,"","" +"ctf_notifyWin1more",1500,10.000000,"faction_marvin","" +"ctf_notifyLose1more",1500,10.000000,"faction_marvin","" +"kc_pilotkillLegion",1400,0.100000,"faction_marvin","" +"kc_pilotkillScorch",1400,0.100000,"faction_marvin","" +"kc_pilotkillTone",1400,0.100000,"faction_marvin","" +"kc_pilotkillIon",1400,0.100000,"faction_marvin","" +"kc_pilotkillRonin",1400,0.100000,"faction_marvin","" +"kc_pilotkillNorthstar",1400,0.100000,"faction_marvin","" +"kc_bullseye",1350,0.100000,"faction_marvin","" +"kc_rodeo",1350,10.000000,"faction_marvin","" +"kc_rakerodeoguy",1400,10.000000,"faction_marvin","" +"kc_pilotkilltitan",1400,0.100000,"faction_marvin","" +"kc_hitandrun",1350,0.100000,"faction_marvin","" +"kc_firstblood",2100,0.100000,"faction_marvin","" +"kc_megakill",2100,0.100000,"","" +"kc_triplekill",2100,0.100000,"","" +"kc_doublekill",1350,0.100000,"faction_marvin","" +"kc_iced",1350,0.100000,"faction_marvin","" +"kc_rampage",1350,0.100000,"faction_marvin","" +"kc_killingspree",1350,0.100000,"faction_marvin","" +"kc_dominating",1350,0.100000,"faction_marvin","" +"kc_retribution",1350,0.100000,"faction_marvin","" +"kc_comeback",1350,0.100000,"faction_marvin","" +"mfd_youAreMarked",1500,0.100000,"","" +"mfd_youKilledMark",1500,0.100000,"","" +"mfd_markDownEnemy",1500,0.100000,"","" +"mfd_markDownFriendly",1500,0.100000,"","" +"mfd_targetsMarkedLong",1500,0.100000,"","" +"mfd_targetsMarkedShort",1500,0.100000,"","" +"mfd_youOutlastedEnemy",1500,0.100000,"","" +"mfd_markCountdown",1500,0.100000,"","" +"lts_playerLastTitanOnTeam",1500,0.100000,"","" +"fd_modeDesc",2500,10.000000,"","" +"fd_firstWaveStartPrefix",2500,10.000000,"","" +"fd_newWaveStartPrefix",2500,10.000000,"","" +"fd_finalWaveStartPrefix",2500,10.000000,"","" +"fd_waveVictory",3000,10.000000,"","" +"fd_waveRestart",3000,10.000000,"","" +"fd_waveRedoTwo",3000,10.000000,"","" +"fd_waveRedoFinal",3000,10.000000,"","" +"fd_titanReadyNag",1500,10.000000,"","" +"fd_minimapTip",1500,10.000000,"","" +"fd_waveNoTitanDrops",1500,10.000000,"","" +"fd_waveTypeInfantry",1500,10.000000,"","" +"fd_waveTypeCloakDrone",1500,10.000000,"","" +"fd_waveTypeTitanReg",1500,10.000000,"","" +"fd_waveTypeTitanMortar",1500,10.000000,"","" +"fd_waveTypeTitanNuke",1500,10.000000,"","" +"fd_waveTypeTitanArc",1500,10.000000,"","" +"fd_waveComboNukeMortar",1500,10.000000,"","" +"fd_waveComboArcMortar",1500,10.000000,"","" +"fd_waveComboArcNuke",1500,10.000000,"","" +"fd_waveComboNukeCloak",1500,10.000000,"","" +"fd_waveComboNukeTrain",1500,10.000000,"","" +"fd_waveComboMultiMix",1500,10.000000,"","" +"fd_waveTypeReapers",1500,10.000000,"","" +"fd_waveTypeTicks",1500,10.000000,"","" +"fd_waveTypeStalkers",1500,10.000000,"","" +"fd_waveTypeMortarSpectre",1500,10.000000,"","" +"fd_waveTypeReaperTicks",1500,10.000000,"","" +"fd_waveTypeEliteTitan",1500,10.000000,"","" +"fd_waveTypeFlyers",1500,10.000000,"","" +"fd_baseDeath",3000,10.000000,"","" +"fd_waveRecapLowHealth",25000,10.000000,"","" +"fd_waveRecapNearPerfect",2500,10.000000,"","" +"fd_waveRecapPerfect",2500,10.000000,"","" +"fd_bigWaveInc",1500,10.000000,"","" +"fd_finalWaveStartGeneric",1500,10.000000,"","" +"fd_baseHealthRecharge",2500,10.000000,"","" +"fd_matchVictory",3000,10.000000,"","" +"fd_matchDefeat",3000,10.000000,"","" +"fd_waveCleanup",1500,10.000000,"","" +"fd_singlePilotDown",2000,10.000000,"","" +"fd_multiPilotDown",2000,10.000000,"","" +"fd_onlyPlayerIsAlive",2000,10.000000,"","" +"fd_pilotRespawn",2000,10.000000,"","" +"fd_nukeTitanNearBase",1750,10.000000,"","" +"fd_waveCleanup5",1500,20.000000,"","" +"fd_waveCleanup4",1500,20.000000,"","" +"fd_waveCleanup3",1500,20.000000,"","" +"fd_waveCleanup2",1500,20.000000,"","" +"fd_waveCleanup1",1500,20.000000,"","" +"fd_baseShieldTakingDmg",1900,30.000000,"","" +"fd_baseShieldLow",1910,10.000000,"","fd_baseShieldTakingDmg" +"fd_baseShieldDown",1930,10.000000,"","" +"fd_baseShieldUp",1810,8.000000,"","fd_baseShieldTakingDmg fd_baseShieldRecharging" +"fd_baseShieldRecharging",1800,30.000000,"","fd_baseShieldTakingDmg" +"fd_baseShieldRechargingShort",1800,30.000000,"","" +"fd_baseBatteryNagLow",1920,10.000000,"","" +"fd_baseBatteryNagDown",2000,10.000000,"","" +"fd_baseShieldLowHolding",2000,10.000000,"","" +"fd_waveNoTitans",1500,10.000000,"","" +"fd_incTitansNukeClump",1500,10.000000,"","" +"fd_incTitansMortarClump",1500,10.000000,"","" +"fd_incArcTitanClump",1500,10.000000,"","" +"fd_incCloakDroneClump",1500,10.000000,"","" +"fd_incReaperClump",1500,10.000000,"","" +"fd_nagKillTitansMortar",2020,45.000000,"","" +"fd_nagKillInfantry",1500,45.000000,"","" +"fd_nagKillStalkers",1000,45.000000,"","" +"fd_nagKillMortarSpectres",2020,45.000000,"","" +"fd_nagKillTitanEMP",1500,45.000000,"","" +"fd_nagTitanArcAtBase",1500,10.000000,"","" +"fd_baseHealth75",2000,15.000000,"","" +"fd_baseHealth50",2010,15.000000,"","fd_baseHealth75" +"fd_baseHealth25",2020,15.000000,"","fd_baseHealth75 fd_baseHealth50" +"fd_baseLowHealth",2030,15.000000,"","fd_baseHealth75 fd_baseHealth50 fd_baseHealth25" +"fd_baseHealth50nag",2010,10.000000,"","" +"fd_baseHealth25nag",2020,10.000000,"","" +"fd_playerCashNagSurplus",1500,10.000000,"","" +"fd_playerCashNagReg",1500,10.000000,"","" +"fd_wavePayoutAddtnl",1500,10.000000,"","" +"fd_wavePayoutFirst",1500,10.000000,"","" +"fd_introEasy",1500,10.000000,"","" +"fd_introMedium",1500,10.000000,"","" +"fd_introHard",1500,10.000000,"","" +"fd_turretOffline",1500,10.000000,"","" +"fd_turretOnline",1500,10.000000,"","" +"turretKillsLow",1500,10.000000,"","" +"turretKillsMedium",1500,10.000000,"","" +"turretKillsHigh",1500,10.000000,"","" +"turretKillsMega",1500,10.000000,"","" +"fd_boughtSentryTurret",1500,10.000000,"","" +"fd_boughtArcTrap",1500,10.000000,"","" +"fd_boughtCoreOverload",1500,10.000000,"","" +"fd_playerNeedsToReadyUp",1500,10.000000,"","" +"fd_boughtAmpedWeapons",1500,10.000000,"","" +"fd_boughtHarvesterShield",1500,10.000000,"","" +"fd_boughtBattery",1500,10.000000,"","" +"matchRecapNoDeaths",1500,10.000000,"","" +"matchRecapNoPlayerDeath",1500,10.000000,"","" +"matchRecapPlayerMVP",1500,10.000000,"","" +"fd_soonNukeTitans",1500,10.000000,"","" +"fd_soonArcTitans",1500,10.000000,"","" +"fd_soonMortarTitans",1500,10.000000,"","" +"fd_stalkerExploNag",1000,300.000000,"","" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/faction_leaders.csv b/Northstar.CustomServers/mod/scripts/datatable/faction_leaders.csv new file mode 100644 index 00000000..22fb3e45 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/faction_leaders.csv @@ -0,0 +1,8 @@ +persistenceRef,factionDialoguePrefix,logo,image,name,description,factionName,usesWaveform,modelName,skinIndex,menuIdleAnim,propModelName,propAttachment,cost +"faction_marauder","mcor_sarah","rui/faction/faction_logo_marauder","rui/faction/faction_button_marauder","#FACTION_LEADER_NAME_SARAH","#FACTION_LEADER_DESC_SARAH","#FACTION_MARAUDER",0,"models/humans/heroes/mlt_hero_sarah.mdl",0,"Sarah_menu_pose","models/Weapons/p2011/w_p2011.mdl","KNIFE",100 +"faction_apex","imc_blisk","rui/faction/faction_logo_apex","rui/faction/faction_button_apex","#FACTION_LEADER_NAME_BLISK","#FACTION_LEADER_DESC_BLISK","#FACTION_APEX",0,"models/humans/heroes/imc_hero_blisk.mdl",0,"Blisk_menu_pose","models/Weapons/combat_knife/w_combat_knife.mdl","KNIFE",100 +"faction_vinson","imc_ash","rui/faction/faction_logo_vinson","rui/faction/faction_button_vinson","#FACTION_LEADER_NAME_ASH","#FACTION_LEADER_DESC_ASH","#FACTION_VINSON",0,"models/humans/heroes/imc_hero_ash.mdl",0,"Ash_menu_pose","","",100 +"faction_aces","mcor_barker","rui/faction/faction_logo_aces","rui/faction/faction_button_aces","#FACTION_LEADER_NAME_BARKER","#FACTION_LEADER_DESC_BARKER","#FACTION_ACES",0,"models/humans/heroes/mlt_hero_barker.mdl",0,"Barker_menu_pose","models/props/flask/prop_flask_animated.mdl","PROPGUN",100 +"faction_64","mcor_gates","rui/faction/faction_logo_64","rui/faction/faction_button_64","#FACTION_LEADER_NAME_GATES","#FACTION_LEADER_DESC_GATES","#FACTION_64",0,"models/humans/pilots/sp_medium_geist_f.mdl",0,"Gates_menu_pose","models/Weapons/p2011/w_p2011.mdl","KNIFE",100 +"faction_ares","imc_marder","rui/faction/faction_logo_ares","rui/faction/faction_button_ares","#FACTION_LEADER_NAME_MARDER","#FACTION_LEADER_DESC_MARDER","#FACTION_ARES",0,"models/humans/heroes/imc_hero_marder.mdl",0,"Marder_menu_pose","","",100 +"faction_marvin","mcor_marvin","rui/faction/faction_logo_mrvn","rui/faction/faction_button_mrvn","#FACTION_LEADER_NAME_MARVIN","#FACTION_LEADER_DESC_MARVIN","#FACTION_MARVIN",1,"models/Robots/marvin/marvin.mdl",1,"commander_MP_flyin_marvin_idle","","",100 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/faction_leaders_dropship_anims.csv b/Northstar.CustomServers/mod/scripts/datatable/faction_leaders_dropship_anims.csv new file mode 100644 index 00000000..0d759d93 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/faction_leaders_dropship_anims.csv @@ -0,0 +1,23 @@ +persistenceRef,dropshipAnimName,isEasterEgg +"faction_marauder","commander_MP_flyin_sarah",0 +"faction_marauder","commander_MP_flyin_sarah_alt",0 +"faction_marauder","commander_MP_flyin_sarah_silent",0 +"faction_apex","commander_MP_flyin_blisk_betta",0 +"faction_apex","commander_MP_flyin_blisk_born",0 +"faction_apex","commander_MP_flyin_blisk_silent",0 +"faction_vinson","commander_MP_flyin_ash_focus",0 +"faction_vinson","commander_MP_flyin_ash_grateful",0 +"faction_vinson","commander_MP_flyin_ash_silent",0 +"faction_aces","commander_MP_flyin_barker",0 +"faction_aces","commander_MP_flyin_barker_victory",0 +"faction_aces","commander_MP_flyin_barker_conductor",0 +"faction_64","commander_MP_flyin_gates_family",0 +"faction_64","commander_MP_flyin_gates_sixfour",0 +"faction_64","commander_MP_flyin_gates_silent",0 +"faction_ares","commander_MP_flyin_marder",0 +"faction_ares","commander_MP_flyin_marder_alt1",0 +"faction_ares","commander_MP_flyin_marder_alt2",0 +"faction_marvin","commander_MP_flyin_marvin_salute",0 +"faction_marvin","commander_MP_flyin_marvin_highfive",0 +"faction_marvin","commander_MP_flyin_marvin_greeter",0 +"faction_marvin","commander_MP_flyin_marvin_freestyle",1 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/fd_awards.csv b/Northstar.CustomServers/mod/scripts/datatable/fd_awards.csv new file mode 100644 index 00000000..01c6254b --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/fd_awards.csv @@ -0,0 +1,15 @@ +ref,priority,displayString,subText,awardDisplayString,displayStyle,image,validityCheck,validityCheckValue,comparisonCheck,needsToBeBest +"harvesterHeals",5,"#FD_AWARD_0","#FD_AWARD_SUBTEXT_0","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/shielded_harvester","greater_than",1.000000,"highest",1 +"mortarUnitsKilled",3,"#FD_AWARD_1","#FD_AWARD_SUBTEXT_1","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/mortar_units","greater_than",1.000000,"highest",1 +"moneySpent",4,"#FD_AWARD_2","#FD_AWARD_SUBTEXT_2","#FD_AWARD_VALUE_DISPLAY_MONEY","FD_DISPLAY_STYLE_NUMBER","rui/medals/cash_spent","greater_than",2000.000000,"highest",1 +"coresUsed",8,"#FD_AWARD_3","#FD_AWARD_SUBTEXT_3","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/titan_core","greater_than",1.000000,"highest",1 +"longestTitanLife",9,"#FD_AWARD_4","#FD_AWARD_SUBTEXT_4","#FD_AWARD_VALUE_DISPLAY_SECONDS","FD_DISPLAY_STYLE_TIME","rui/medals/least_lost","greater_than",100.000000,"highest",1 +"turretsRepaired",7,"#FD_AWARD_5","#FD_AWARD_SUBTEXT_5","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/turrets_healed","greater_than",5.000000,"highest",1 +"moneyShared",6,"#FD_AWARD_6","#FD_AWARD_SUBTEXT_6","#FD_AWARD_VALUE_DISPLAY_MONEY","FD_DISPLAY_STYLE_NUMBER","rui/medals/cash_shared","greater_than",100.000000,"highest",1 +"damageDealt",1,"#FD_AWARD_7","#FD_AWARD_SUBTEXT_7","#FD_AWARD_VALUE_DISPLAY_POINTS","FD_DISPLAY_STYLE_NUMBER","rui/medals/most_damage","greater_than",-1.000000,"highest",0 +"timeNearHarvester",2,"#FD_AWARD_8","#FD_AWARD_SUBTEXT_8","#FD_AWARD_VALUE_DISPLAY_SECONDS","FD_DISPLAY_STYLE_TIME","rui/medals/harvester_protect","greater_than",200.000000,"highest",1 +"longestLife",0,"#FD_AWARD_9","#FD_AWARD_SUBTEXT_9","#FD_AWARD_VALUE_DISPLAY_SECONDS","FD_DISPLAY_STYLE_TIME","rui/medals/long_life","greater_than",200.000000,"highest",1 +"heals",11,"#FD_AWARD_10","#FD_AWARD_SUBTEXT_10","#FD_AWARD_VALUE_DISPLAY_POINTS","FD_DISPLAY_STYLE_NUMBER","rui/medals/heal","greater_than",5000.000000,"highest",1 +"turretKills",10,"#FD_AWARD_11","#FD_AWARD_SUBTEXT_11","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/turret_damage","greater_than",10.000000,"highest",1 +"mvp",13,"#FD_AWARD_12","#FD_AWARD_SUBTEXT_12","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/mvp","greater_than",2.000000,"highest",1 +"titanKills",12,"#FD_AWARD_13","#FD_AWARD_SUBTEXT_13","#FD_AWARD_VALUE_DISPLAY_BLANK","FD_DISPLAY_STYLE_NUMBER","rui/medals/titans_killed","greater_than",30.000000,"highest",1 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/features_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/features_mp.csv new file mode 100644 index 00000000..8f1b39b3 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/features_mp.csv @@ -0,0 +1,21 @@ +featureRef,featureName,featureDesc,featureIcon,specificType,cost +"communities","#FEATURE_COMMUNITIES","","rui/hud/common/feature_icon","#ITEM_TYPE_FEATURE",0 +"happy_hour","#FEATURE_HAPPY_HOUR","","rui/hud/common/feature_icon","#ITEM_TYPE_FEATURE",0 +"pilot_loadout_1","#DEFAULT_PILOT_1","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_2","#DEFAULT_PILOT_2","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_3","#DEFAULT_PILOT_3","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_4","#DEFAULT_PILOT_4","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_5","#DEFAULT_PILOT_5","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_6","#DEFAULT_PILOT_6","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",15 +"pilot_loadout_7","#DEFAULT_PILOT_7","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",100 +"pilot_loadout_8","#DEFAULT_PILOT_8","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",100 +"pilot_loadout_9","#DEFAULT_PILOT_9","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",100 +"pilot_loadout_10","#DEFAULT_PILOT_10","","rui/hud/common/feature_icon","#ITEM_TYPE_LOADOUT",100 +"coliseum_ticket","#ITEM_COLISEUM","#ITEM_COLISEUM_DESC","rui/menu/common/ticket_icon","#ITEM_TYPE_PLAYLIST",10 +"double_xp","#DOUBLE_XP","#DOUBLE_XP_DESC","rui/menu/common/dbl_xp_icon","#ITEM_TYPE_DOUBLEXP",0 +"credit_award","#CREDIT_AWARD","#CREDIT_AWARD_DESC","rui/menu/common/credit_symbol_large_color","#ITEM_TYPE_CREDITS",0 +"credit_award_5x","#CREDIT_AWARD_5X","","rui/menu/common/credit_symbol_large_color","#ITEM_TYPE_CREDITS",0 +"advocate_gift","#RANDOM","","rui\menu\common\unlock_random","#UNLOCK_RANDOM",0 +"mp_angel_city","#MP_ANGEL_CITY","","rui/hud/common/feature_icon","#UNLOCK_RANDOM",0 +"random","#RANDOM","","rui\menu\common\unlock_random","#UNLOCK_RANDOM",0 +"classic_music","#CLASSIC_MUSIC","","rui/hud/common/feature_icon","#UNLOCK_CLASSIC_MUSIC",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/flightpath_assets.csv b/Northstar.CustomServers/mod/scripts/datatable/flightpath_assets.csv new file mode 100644 index 00000000..d14566f1 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/flightpath_assets.csv @@ -0,0 +1,8 @@ +name,mp_model,sp_model +"fp_dropship_model","models/vehicle/goblin_dropship/goblin_dropship.mdl","models/vehicle/goblin_dropship/goblin_dropship.mdl" +"fp_dropship_hero_model","models/vehicle/goblin_dropship/goblin_dropship_hero.mdl","models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" +"fp_crow_model","models/vehicle/crow_dropship/crow_dropship.mdl","models/vehicle/crow_dropship/crow_dropship.mdl" +"fp_crow_hero_model","models/vehicle/crow_dropship/crow_dropship_hero.mdl","models/vehicle/crow_dropship/crow_dropship_hero.mdl" +"fp_titan_model","models/titans/medium/titan_medium_ajax.mdl","models/titans/medium/sp_titan_medium_ajax.mdl" +"fp_straton_model","models/vehicle/straton/straton_imc_gunship_01.mdl","models/vehicle/straton/straton_imc_gunship_01.mdl" +"fp_hornet_model","models/vehicle/hornet/hornet_fighter.mdl","models/vehicle/hornet/hornet_fighter.mdl" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/grunt_chatter_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/grunt_chatter_mp.csv new file mode 100644 index 00000000..c3c15f19 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/grunt_chatter_mp.csv @@ -0,0 +1,47 @@ +conversationname,alias,priority,debounce +"bc_allygruntdown","bc_allygruntdown",250,20.000000 +"bc_enemytitandown","bc_enemytitandown",250,20.000000 +"bc_enemytitanspotcall","bc_enemytitanspotcall",250,20.000000 +"bc_engageenemycloakedpilot","bc_engageenemycloakedpilot",250,20.000000 +"bc_engagepilotenemy","bc_engagepilotenemy",250,20.000000 +"bc_grenadecall","bc_grenadecall",250,20.000000 +"bc_gruntkillstitan","bc_gruntkillstitan",250,20.000000 +"bc_killenemypilot","bc_killenemypilot",250,20.000000 +"bc_spotenemypilot","bc_spotenemypilot",250,20.000000 +"bc_squaddeplete","bc_squaddeplete",250,20.000000 +"bc_reactGrenadeArc","bc_reactGrenadeArc",250,20.000000 +"bc_reactGrenadeThermite","bc_reactGrenadeThermite",250,20.000000 +"bc_reactGrenadeGravity","bc_reactGrenadeGravity",250,20.000000 +"bc_reactGrenadeElecSmoke","bc_reactGrenadeElecSmoke",250,20.000000 +"bc_grenadeOutCall","bc_grenadeOutCall",250,20.000000 +"bc_fleePlayerTitanCall","bc_spotclosetitancall_01",250,20.000000 +"bc_fleePlayerTitanCall","bc_fleePlayerTitanCall",250,20.000000 +"bc_reactTickSpawnFriendly","bc_reactTickSpawnFriendly_01",250,20.000000 +"bc_reactTickSpawnFriendly","bc_reactTickSpawnFriendly_02",250,20.000000 +"bc_reactTickSpawnFriendly","bc_reactTickSpawnFriendly_03",250,20.000000 +"bc_reactTitanfallFriendlyArrives","bc_reactTitanfallFriendlyArrives_01",250,40.000000 +"bc_reactTitanfallFriendlyArrives","bc_titancheer_01",250,40.000000 +"bc_reactEnemySpotted","bc_engagepilotenemy_01",250,20.000000 +"bc_reactEnemySpotted","bc_engagepilotenemy_02",250,20.000000 +"bc_reactEnemySpotted","bc_engagepilotenemy_06",250,20.000000 +"bc_reactEnemyReaper","diag_sp_ReaperTown_BM102_15_01_mcor_grunt3",250,20.000000 +"bc_reactEnemyReaper","diag_sp_ReaperTown_BM102_16_01_mcor_grunt2",250,20.000000 +"bc_reactReaperFriendlyArrives","bc_reactReaperFriendlyArrives_01",250,40.000000 +"bc_reactFriendlyPilot","diag_sp_ReaperTown_BM103_01a_01_mcor_grunt2",250,180.000000 +"TEMP_bc_reactFriendlyPilot","diag_sp_corkscrew_SE131_02_01_mcor_grunt1",250,180.000000 +"bc_reactFriendlyPilot","diag_sp_corkscrew_SE131_19_01_mcor_grunt1",250,180.000000 +"bc_generalCombat","diag_sp_corkscrew_SE131_21_01_mcor_grunt1",250,20.000000 +"bc_generalCombat","diag_sp_corkscrew_SE131_12_01_mcor_grunt1",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_29_01_mcor_grunt6",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_24_01_mcor_grunt1",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD103_02_01_mcor_grunt2",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_25_01_mcor_grunt2",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_26_01_mcor_grunt3",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_27_01_mcor_grunt4",250,20.000000 +"bc_generalCombat","diag_sp_intro_WD104_28_01_mcor_grunt5",250,20.000000 +"TEMP_bc_generalNonCombat","diag_sp_ReaperTown_BM102_29a_01_imc_gcaptain",250,100.000000 +"bc_generalNonCombat","diag_sp_ReaperTown_BM103_02a_01_mcor_grunt1",250,100.000000 +"bc_generalCombatTitan","diag_sp_sewerArena_SE151_09_01_imc_grunt1",250,20.000000 +"bc_generalCombatTitan","diag_sp_sewerArena_SE152_01_01_imc_grunt1",250,20.000000 +"bc_generalCombatTitan","diag_sp_intro_WD103_07_01_mcor_grunt1",250,20.000000 +"bc_generalCombatTitan","diag_sp_bigCharge_TD111_06_01_mcor_pilot3",250,20.000000 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/non_loadout_weapons.csv b/Northstar.CustomServers/mod/scripts/datatable/non_loadout_weapons.csv new file mode 100644 index 00000000..8816fd8f --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/non_loadout_weapons.csv @@ -0,0 +1,29 @@ +weapon +"melee_titan_punch" +"melee_titan_punch_fighter" +"melee_titan_punch_ion" +"melee_titan_punch_tone" +"melee_titan_punch_northstar" +"melee_titan_punch_scorch" +"melee_titan_punch_legion" +"melee_titan_sword" +"melee_titan_sword_aoe" +"mp_titanweapon_flightcore_rockets" +"mp_titanweapon_orbital_strike" +"mp_titanweapon_predator_cannon_siege" +"mp_weapon_spectre_spawner" +"proto_viewmodel_test" +"mp_turretweapon_blaster" +"mp_turretweapon_plasma" +"mp_turretweapon_sentry" +"mp_ability_arc_blast" +"mp_ability_burncardweapon" +"mp_ability_holopilot_nova" +"mp_weapon_smart_pistol" +"mp_weapon_hard_cover" +"melee_titan_punch_vanguard" +"mp_titanweapon_rocketeer_rocketstream" +"mp_titanweapon_shoulder_rockets" +"mp_ability_swordblock" +"mp_titanability_nuke_eject" +"mp_weapon_arc_trap" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pain_death_sounds.csv b/Northstar.CustomServers/mod/scripts/datatable/pain_death_sounds.csv new file mode 100644 index 00000000..00d5e595 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pain_death_sounds.csv @@ -0,0 +1,53 @@ +event,priority,blocksNextPriority,method,bodyType,alias_1p_victim_only,alias_3p_except_victim,alias_3p_attacker_only,alias_3p_except_attacker,spmp +"death",105,0,"SE_GIB","NPC_GRUNT","","death.pinkmist","","","spmp" +"death",105,0,"SE_GIB","NPC_MARVIN","","","","","spmp" +"death",105,0,"SE_GIB","NPC_PROWLER","","","","","spmp" +"death",105,0,"SE_GIB","NPC_SPECTRE","","","","","spmp" +"death",105,0,"SE_GIB","NPC_STALKER","","","","","spmp" +"death",110,1,"SE_HEADSHOT_BULLET","NPC_GRUNT","","","","Flesh.Light.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_BULLET","NPC_MARVIN","","","","Android.Light.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_BULLET","NPC_SPECTRE","","","","Android.Light.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_BULLET","NPC_STALKER","","","","Android.Light.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_SHOTGUN","NPC_GRUNT","","","","Flesh.Shotgun.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_SHOTGUN","NPC_MARVIN","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_SHOTGUN","NPC_SPECTRE","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_SHOTGUN","NPC_STALKER","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_TITAN","NPC_GRUNT","","","","Flesh.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_TITAN","NPC_MARVIN","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_TITAN","NPC_SPECTRE","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",110,1,"SE_HEADSHOT_TITAN","NPC_STALKER","","","","Android.Heavy.BulletImpact_Headshot_3P_vs_3P","spmp" +"death",120,1,"SE_NECK_SNAP","NPC_GRUNT","","diag_efforts_DeathNeck_gl_grunt_3p","","","spmp" +"death",140,1,"SE_DISSOLVE","NPC_GRUNT","","diag_efforts_DeathBurn_gl_grunt_3p","","","spmp" +"death",160,1,"SE_ELECTRICAL","NPC_GRUNT","","diag_efforts_DeathElec_gl_grunt_3p","","","spmp" +"death",180,1,"SE_EXPLOSION","NPC_GRUNT","","diag_efforts_DeathExplo_gl_grunt_3p","","","spmp" +"death",200,1,"SE_FALL","NPC_GRUNT","","diag_efforts_DeathFall_gl_grunt_3p","","","spmp" +"death",220,1,"SE_PROWLER","NPC_GRUNT","","diag_efforts_DeathProwler_gl_grunt_3p","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_GRUNT","","titan_grunt_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_MARVIN","","titan_spectre_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_SPECTRE","","titan_spectre_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_STALKER","","titan_spectre_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_PROWLER","","titan_grunt_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_MALE","","titan_grunt_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_MALE","","titan_grunt_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_ANDROID_MALE","","titan_spectre_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_FEMALE","","titan_grunt_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_ANDROID_FEMALE","","titan_spectre_squish","","","spmp" +"death",290,1,"SE_TITAN_STEP","NPC_GRUNT","","diag_efforts_DeathCrush_gl_grunt_3p","","","spmp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_MALE","diag_efforts_DeathCrush_sp_cooper_3p_vs_1p","diag_efforts_DeathCrush_mp_maleHuman_3p","","","sp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_MALE","diag_efforts_DeathCrush_mp_maleHuman_3p_vs_1p","diag_efforts_DeathCrush_mp_maleHuman_3p","","","mp" +"death",290,1,"SE_TITAN_STEP","PLAYER_ANDROID_MALE","diag_efforts_DeathCrush_mp_maleRobot_3p_vs_1p","diag_efforts_DeathCrush_mp_maleRobot_3p","","","mp" +"death",290,1,"SE_TITAN_STEP","PLAYER_HUMAN_FEMALE","diag_efforts_DeathCrush_mp_femaleHuman_3p_vs_1p","diag_efforts_DeathCrush_mp_femaleHuman_3p","","","mp" +"death",400,1,"SE_ANY","NPC_MARVIN","","marvin_death","","","spmp" +"death",400,1,"SE_TITAN_STEP","PLAYER_ANDROID_FEMALE","diag_efforts_DeathCrush_mp_femaleRobot_3p_vs_1p","diag_efforts_DeathCrush_mp_femaleRobot_3p","","","mp" +"death",500,1,"SE_ANY","NPC_GRUNT","","diag_efforts_DeathQuick_gl_grunt_3p","","","spmp" +"death",500,1,"SE_ANY","TITAN","titan_death_explode","titan_death_explode","","","spmp" +"pain",300,1,"SE_ELECTRICAL","NPC_GRUNT","","diag_efforts_hitByArc_gl_grunt_3p","","","spmp" +"pain",300,1,"SE_THERMITE_GRENADE","NPC_GRUNT","","diag_efforts_burns_gl_grunt_3p","","","spmp" +"pain",400,0,"SE_PROWLER","NPC_GRUNT","","diag_efforts_hitByProwler_gl_grunt_3p","","","spmp" +"pain",400,0,"SE_SMOKE","NPC_GRUNT","","diag_efforts_cough_gl_grunt_3p","","","spmp" +"pain",400,0,"SE_ANY","NPC_GRUNT","","diag_efforts_hits_gl_grunt_3p","","","spmp" +"pain",400,0,"SE_ANY","PLAYER_ANDROID_FEMALE","diag_efforts_hits_mp_femaleRobot_3p_vs_1p","","","","mp" +"pain",400,0,"SE_ANY","PLAYER_ANDROID_MALE","diag_efforts_hits_mp_maleRobot_3p_vs_1p","","","","mp" +"pain",400,0,"SE_ANY","PLAYER_HUMAN_FEMALE","diag_efforts_hits_mp_femaleHuman_3p_vs_1p","","","","mp" +"pain",400,0,"SE_ANY","PLAYER_HUMAN_MALE","diag_efforts_hits_mp_maleHuman_3p_vs_1p","","","","mp" +"pain",400,0,"SE_ANY","PLAYER_HUMAN_MALE","diag_efforts_hits_sp_cooper_3p_vs_1p","","","","sp" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_abilities.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_abilities.csv new file mode 100644 index 00000000..e9949479 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_abilities.csv @@ -0,0 +1,16 @@ +itemRef,type,damageSource,hidden,cost +"mp_ability_grapple","PILOT_SPECIAL",0,0,180 +"mp_ability_heal","PILOT_SPECIAL",0,0,180 +"mp_ability_holopilot","PILOT_SPECIAL",0,0,180 +"mp_weapon_grenade_sonar","PILOT_SPECIAL",1,0,180 +"mp_ability_shifter","PILOT_SPECIAL",0,0,180 +"mp_weapon_deployable_cover","PILOT_SPECIAL",0,0,180 +"mp_ability_cloak","PILOT_SPECIAL",0,0,180 +"mp_weapon_frag_grenade","PILOT_ORDNANCE",1,0,220 +"mp_weapon_grenade_emp","PILOT_ORDNANCE",1,0,220 +"mp_weapon_grenade_gravity","PILOT_ORDNANCE",1,0,220 +"mp_weapon_grenade_electric_smoke","PILOT_ORDNANCE",1,0,220 +"mp_weapon_thermite_grenade","PILOT_ORDNANCE",1,0,220 +"mp_weapon_satchel","PILOT_ORDNANCE",1,0,220 +"melee_pilot_sword","NOT_LOADOUT",1,1,220 +"mp_ability_shifter_super","PILOT_SPECIAL",0,1,220 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_executions.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_executions.csv new file mode 100644 index 00000000..faae9db7 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_executions.csv @@ -0,0 +1,14 @@ +ref,name,description,image,hidden,cost +"execution_neck_snap","#PILOT_EXECUTION_NECK_SNAP","#PILOT_EXECUTION_NECK_SNAP_DESC","rui/pilot_loadout/execution/execution_neck_snap",0,0 +"execution_face_stab","#PILOT_EXECUTION_FACE_STAB","#PILOT_EXECUTION_FACE_STAB_DESC","rui/pilot_loadout/execution/execution_face_stab",0,300 +"execution_backshot","#PILOT_EXECUTION_BACK_SHOT","#PILOT_EXECUTION_BACK_SHOT_DESC","rui/pilot_loadout/execution/execution_backshot",0,300 +"execution_combo","#PILOT_EXECUTION_COMBO","#PILOT_EXECUTION_COMBO_DESC","rui/pilot_loadout/execution/execution_combo",0,300 +"execution_knockout","#PILOT_EXECUTION_KNOCKOUT","#PILOT_EXECUTION_KNOCKOUT_DESC","rui/pilot_loadout/execution/execution_knockout",0,300 +"execution_telefrag","#PILOT_EXECUTION_TELEFRAG","#PILOT_EXECUTION_TELEFRAG_DESC","rui/pilot_loadout/execution/execution_inner_pieces",0,0 +"execution_stim","#PILOT_EXECUTION_STIM","#PILOT_EXECUTION_STIM_DESC","rui/pilot_loadout/execution/execution_straight_blast",0,0 +"execution_grapple","#PILOT_EXECUTION_GRAPPLE","#PILOT_EXECUTION_GRAPPLE_DESC","rui/pilot_loadout/execution/execution_grapple",0,0 +"execution_pulseblade","#PILOT_EXECUTION_PULSEBLADE","#PILOT_EXECUTION_PULSEBLADE_DESC","rui/pilot_loadout/execution/execution_pulseblade",0,0 +"execution_random","#PILOT_EXECUTION_RANDOM","#PILOT_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0 +"execution_cloak","#PILOT_EXECUTION_CLOAK","#PILOT_EXECUTION_CLOAK_DESC","rui/pilot_loadout/execution/execution_now_you_see_me",0,0 +"execution_holopilot","#PILOT_EXECUTION_HOLOPILOT","#PILOT_EXECUTION_HOLOPILOT_DESC","rui/pilot_loadout/execution/execution_holopilot",0,0 +"execution_ampedwall","#PILOT_EXECUTION_AMPEDWALL","#PILOT_EXECUTION_AMPEDWALL_DESC","rui/pilot_loadout/execution/execution_amped_wall",0,0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_passives.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_passives.csv new file mode 100644 index 00000000..a13a98f2 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_passives.csv @@ -0,0 +1,10 @@ +passive,type,name,description,image,hidden,cost +"pas_enemy_death_icons","PILOT_PASSIVE2","#GEAR_ENEMY_DEATH_ICONS","#GEAR_ENEMY_DEATH_ICONS_DESC","rui/pilot_loadout/kit/kill_report_menu",0,25 +"pas_ordnance_pack","PILOT_PASSIVE1","#GEAR_EXPLOSIVES_PACK","#GEAR_EXPLOSIVES_PACK_DESC","rui/pilot_loadout/kit/ordnance_expert_menu",0,125 +"pas_power_cell","PILOT_PASSIVE1","#GEAR_POWER_CELL","#GEAR_POWER_CELL_DESC","rui/pilot_loadout/kit/power_cell_menu",0,25 +"pas_fast_embark","PILOT_PASSIVE1","#GEAR_FAST_EMBARK","#GEAR_FAST_EMBARK_DESC","rui/pilot_loadout/kit/phase_embark_menu",0,125 +"pas_ads_hover","PILOT_PASSIVE2","#GEAR_ADS_HOVER","#GEAR_ADS_HOVER_DESC","rui/pilot_loadout/kit/hover_menu",0,225 +"pas_wallhang","PILOT_PASSIVE2","#GEAR_WALLHANG","#GEAR_WALLHANG_DESC","rui/pilot_loadout/kit/wall_hang_menu",0,25 +"pas_fast_health_regen","PILOT_PASSIVE1","#GEAR_FAST_HEALTH_REGEN","#GEAR_FAST_HEALTH_REGEN_DESC","rui/pilot_loadout/kit/quick_regen_menu",0,25 +"pas_stealth_movement","PILOT_PASSIVE2","#GEAR_STEALTH_KIT","#GEAR_STEALTH_KIT_DESC","rui/pilot_loadout/kit/stealth_movement_menu",0,225 +"pas_at_hunter","PILOT_PASSIVE2","#GEAR_AT_HUNTER_KIT","#GEAR_AT_HUNTER_KIT_DESC","rui/pilot_loadout/kit/titan_hunter_menu",0,225 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_properties.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_properties.csv new file mode 100644 index 00000000..6e40e332 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_properties.csv @@ -0,0 +1,8 @@ +type,image,tactical,defaultPassive1,defaultPassive2,melee,cost +"nomad","rui/pilot_loadout/suit/nomad","mp_ability_heal","pas_power_cell","pas_enemy_death_icons","melee_pilot_emptyhanded",180 +"light","rui/pilot_loadout/suit/light","mp_ability_shifter","pas_fast_health_regen","pas_wallhang","melee_pilot_emptyhanded",180 +"geist","rui/pilot_loadout/suit/geist","mp_ability_cloak","pas_power_cell","pas_enemy_death_icons","melee_pilot_emptyhanded",180 +"medium","rui/pilot_loadout/suit/medium","mp_weapon_grenade_sonar","pas_fast_health_regen","pas_wallhang","melee_pilot_emptyhanded",180 +"grapple","rui/pilot_loadout/suit/grapple","mp_ability_grapple","pas_power_cell","pas_wallhang","melee_pilot_emptyhanded",180 +"heavy","rui/pilot_loadout/suit/heavy","mp_weapon_deployable_cover","pas_fast_health_regen","pas_enemy_death_icons","melee_pilot_emptyhanded",180 +"stalker","rui/pilot_loadout/suit/stalker","mp_ability_holopilot","pas_power_cell","pas_enemy_death_icons","melee_pilot_emptyhanded",180 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_features.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_features.csv new file mode 100644 index 00000000..2226eb79 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_features.csv @@ -0,0 +1,5 @@ +featureRef,featureName,featureDesc,featureIcon,cost +"primarymod2","#EXTRA_MOD","","rui/hud/common/feature_icon",0 +"secondarymod2","#EXTRA_MOD","","rui/hud/common/feature_icon",0 +"primarymod3","#MOD_PRO_SCREEN_NAME","","rui/hud/common/feature_icon",0 +"secondarymod3","#MOD_PRO_SCREEN_NAME","","rui/hud/common/feature_icon",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods.csv new file mode 100644 index 00000000..b59acb18 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods.csv @@ -0,0 +1,250 @@ +mod,weapon,statDamage,statAccuracy,statRange,statFireRate,statClipSize,hidden +"extended_ammo","mp_weapon_r97",0,0,0,0,10,0 +"extended_ammo","mp_weapon_shotgun",0,0,0,0,3,0 +"extended_ammo","mp_weapon_mastiff",0,0,0,0,3,0 +"extended_ammo","mp_weapon_car",0,0,0,0,10,0 +"extended_ammo","mp_weapon_rspn101",0,0,0,0,6,0 +"extended_ammo","mp_weapon_rspn101_og",0,0,0,0,6,0 +"extended_ammo","mp_weapon_hemlok",0,0,0,0,6,0 +"extended_ammo","mp_weapon_g2",0,0,0,0,4,0 +"extended_ammo","mp_weapon_vinson",0,0,0,0,6,0 +"extended_ammo","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"extended_ammo","mp_weapon_alternator_smg",0,0,0,0,0,0 +"extended_ammo","mp_weapon_wingman",0,0,0,0,0,0 +"extended_ammo","mp_weapon_wingman_n",0,0,0,0,0,0 +"extended_ammo","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"extended_ammo","mp_weapon_sniper",0,0,0,0,0,0 +"extended_ammo","mp_weapon_defender",0,0,0,0,0,0 +"extended_ammo","mp_weapon_dmr",0,0,0,0,0,0 +"extended_ammo","mp_weapon_doubletake",0,0,0,0,0,0 +"extended_ammo","mp_weapon_softball",0,0,0,0,0,0 +"extended_ammo","mp_weapon_epg",0,0,0,0,0,0 +"extended_ammo","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"extended_ammo","mp_weapon_smr",0,0,0,0,0,0 +"extended_ammo","mp_weapon_rocket_launcher",0,0,0,0,0,0 +"extended_ammo","mp_weapon_mgl",0,0,0,0,0,0 +"extended_ammo","mp_weapon_arc_launcher",0,0,0,0,0,0 +"extended_ammo","mp_weapon_semipistol",0,0,0,0,0,0 +"extended_ammo","mp_weapon_autopistol",0,0,0,0,0,0 +"extended_ammo","mp_weapon_lmg",0,0,0,0,0,0 +"extended_ammo","mp_weapon_lstar",0,0,0,0,0,0 +"extended_ammo","mp_weapon_esaw",0,0,0,0,0,0 +"silencer","mp_weapon_wingman",0,0,0,0,0,0 +"silencer","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"silencer","mp_weapon_autopistol",0,0,0,0,0,0 +"silencer","mp_weapon_semipistol",0,0,0,0,0,0 +"hcog","mp_weapon_rspn101",0,0,0,0,0,0 +"hcog","mp_weapon_rspn101_og",0,0,0,0,0,0 +"hcog","mp_weapon_hemlok",0,0,0,0,0,0 +"hcog","mp_weapon_g2",0,0,0,0,0,0 +"hcog","mp_weapon_vinson",0,0,0,0,0,0 +"hcog","mp_weapon_alternator_smg",0,0,0,0,0,0 +"redline_sight","mp_weapon_r97",0,0,0,0,0,0 +"redline_sight","mp_weapon_car",0,0,0,0,0,0 +"redline_sight","mp_weapon_rspn101",0,0,0,0,0,0 +"redline_sight","mp_weapon_rspn101_og",0,0,0,0,0,0 +"redline_sight","mp_weapon_hemlok",0,0,0,0,0,0 +"redline_sight","mp_weapon_g2",0,0,0,0,0,0 +"redline_sight","mp_weapon_lmg",0,0,0,0,0,0 +"redline_sight","mp_weapon_vinson",0,0,0,0,0,0 +"redline_sight","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"redline_sight","mp_weapon_alternator_smg",0,0,0,0,0,0 +"redline_sight","mp_weapon_lstar",0,0,0,0,0,0 +"redline_sight","mp_weapon_esaw",0,0,0,0,0,0 +"redline_sight","mp_weapon_shotgun",0,0,0,0,0,0 +"redline_sight","mp_weapon_mastiff",0,0,0,0,0,0 +"aog","mp_weapon_lstar",0,0,0,0,0,0 +"aog","mp_weapon_lmg",0,0,0,0,0,0 +"aog","mp_weapon_esaw",0,0,0,0,0,0 +"holosight","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"holosight","mp_weapon_car",0,0,0,0,0,0 +"holosight","mp_weapon_r97",0,0,0,0,0,0 +"holosight","mp_weapon_shotgun",0,0,0,0,0,0 +"holosight","mp_weapon_mastiff",0,0,0,0,0,0 +"scope_4x","mp_weapon_dmr",0,0,0,0,0,0 +"scope_4x","mp_weapon_sniper",0,0,0,0,0,0 +"scope_4x","mp_weapon_doubletake",0,0,0,0,0,0 +"ricochet","mp_weapon_sniper",0,0,0,0,0,0 +"ricochet","mp_weapon_doubletake",0,0,0,0,0,0 +"ricochet","mp_weapon_wingman_n",0,0,0,0,0,0 +"threat_scope","mp_weapon_rspn101",0,0,0,0,0,0 +"threat_scope","mp_weapon_rspn101_og",0,0,0,0,0,0 +"threat_scope","mp_weapon_vinson",0,0,0,0,0,0 +"threat_scope","mp_weapon_hemlok",0,0,0,0,0,0 +"threat_scope","mp_weapon_g2",0,0,0,0,0,0 +"threat_scope","mp_weapon_car",0,0,0,0,0,0 +"threat_scope","mp_weapon_r97",0,0,0,0,0,0 +"threat_scope","mp_weapon_alternator_smg",0,0,0,0,0,0 +"threat_scope","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"threat_scope","mp_weapon_sniper",0,0,0,0,0,0 +"threat_scope","mp_weapon_dmr",0,0,0,0,0,0 +"threat_scope","mp_weapon_doubletake",0,0,0,0,0,0 +"threat_scope","mp_weapon_lmg",0,0,0,0,0,0 +"threat_scope","mp_weapon_lstar",0,0,0,0,0,0 +"threat_scope","mp_weapon_esaw",0,0,0,0,0,0 +"threat_scope","mp_weapon_shotgun",0,0,0,0,0,0 +"threat_scope","mp_weapon_mastiff",0,0,0,0,0,0 +"quick_charge","mp_weapon_defender",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_rspn101",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_rspn101_og",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_vinson",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_hemlok",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_g2",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_car",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_r97",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_alternator_smg",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_lmg",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_lstar",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_esaw",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_sniper",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_dmr",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_doubletake",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_wingman",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_wingman_n",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_autopistol",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_semipistol",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_shotgun",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_mastiff",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_softball",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_epg",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"tactical_cdr_on_kill","mp_weapon_smr",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_rspn101",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_rspn101_og",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_vinson",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_hemlok",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_g2",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_car",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_r97",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_alternator_smg",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_lmg",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_lstar",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_esaw",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_sniper",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_dmr",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_doubletake",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_wingman",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_wingman_n",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_autopistol",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_semipistol",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_shotgun",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_mastiff",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_softball",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_epg",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_smr",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_defender",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_rocket_launcher",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_mgl",0,0,0,0,0,0 +"pas_fast_ads","mp_weapon_arc_launcher",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_rspn101",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_rspn101_og",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_vinson",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_hemlok",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_g2",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_car",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_r97",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_alternator_smg",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_lmg",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_lstar",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_esaw",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_sniper",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_dmr",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_doubletake",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_shotgun",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_mastiff",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_softball",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_epg",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_smr",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_defender",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_rocket_launcher",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_mgl",0,0,0,0,0,0 +"pas_fast_swap","mp_weapon_arc_launcher",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_rspn101",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_rspn101_og",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_vinson",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_hemlok",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_g2",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_car",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_r97",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_alternator_smg",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_lmg",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_lstar",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_esaw",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_sniper",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_dmr",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_doubletake",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_wingman",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_wingman_n",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_autopistol",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_semipistol",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_shotgun",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_mastiff",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_softball",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_epg",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_smr",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_rocket_launcher",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_mgl",0,0,0,0,0,0 +"pas_fast_reload","mp_weapon_arc_launcher",0,0,0,0,0,0 +"pro_screen","mp_weapon_r97",0,0,0,0,0,0 +"pro_screen","mp_weapon_shotgun",0,0,0,0,0,0 +"pro_screen","mp_weapon_mastiff",0,0,0,0,0,0 +"pro_screen","mp_weapon_car",0,0,0,0,0,0 +"pro_screen","mp_weapon_rspn101",0,0,0,0,0,0 +"pro_screen","mp_weapon_rspn101_og",0,0,0,0,0,0 +"pro_screen","mp_weapon_hemlok",0,0,0,0,0,0 +"pro_screen","mp_weapon_g2",0,0,0,0,0,0 +"pro_screen","mp_weapon_vinson",0,0,0,0,0,0 +"pro_screen","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"pro_screen","mp_weapon_alternator_smg",0,0,0,0,0,0 +"pro_screen","mp_weapon_wingman",0,0,0,0,0,0 +"pro_screen","mp_weapon_wingman_n",0,0,0,0,0,0 +"pro_screen","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"pro_screen","mp_weapon_sniper",0,0,0,0,0,0 +"pro_screen","mp_weapon_defender",0,0,0,0,0,0 +"pro_screen","mp_weapon_dmr",0,0,0,0,0,0 +"pro_screen","mp_weapon_doubletake",0,0,0,0,0,0 +"pro_screen","mp_weapon_softball",0,0,0,0,0,0 +"pro_screen","mp_weapon_epg",0,0,0,0,0,0 +"pro_screen","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"pro_screen","mp_weapon_smr",0,0,0,0,0,0 +"pro_screen","mp_weapon_rocket_launcher",0,0,0,0,0,0 +"pro_screen","mp_weapon_mgl",0,0,0,0,0,0 +"pro_screen","mp_weapon_arc_launcher",0,0,0,0,0,0 +"pro_screen","mp_weapon_semipistol",0,0,0,0,0,0 +"pro_screen","mp_weapon_autopistol",0,0,0,0,0,0 +"pro_screen","mp_weapon_lmg",0,0,0,0,0,0 +"pro_screen","mp_weapon_lstar",0,0,0,0,0,0 +"pro_screen","mp_weapon_esaw",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_r97",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_shotgun",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_mastiff",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_car",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_rspn101",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_rspn101_og",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_hemlok",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_g2",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_vinson",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_hemlok_smg",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_alternator_smg",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_wingman",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_wingman_n",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_shotgun_pistol",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_softball",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_epg",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_pulse_lmg",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_smr",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_semipistol",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_autopistol",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_lmg",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_lstar",0,0,0,0,0,0 +"pas_run_and_gun","mp_weapon_esaw",0,0,0,0,0,0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods_common.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods_common.csv new file mode 100644 index 00000000..4718c126 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapon_mods_common.csv @@ -0,0 +1,27 @@ +mod,type,name,shortName,description,image,cost,costSniper,costPistol,costAT +"iron_sights","attachment","#FACTORY_ISSUE_NAME","","#FACTORY_ISSUE_SIGHT_DESC","r2_ui/menus/loadout_icons/attachments/iron_sights",0,0,0,0 +"holosight","attachment","#MOD_HOLOSIGHT_NAME","","#MOD_HOLOSIGHT_DESC","r2_ui/menus/loadout_icons/attachments/holosight",0,0,0,0 +"hcog","attachment","#MOD_HCOG_NAME","HCOG","#MOD_HCOG_DESC","r2_ui/menus/loadout_icons/attachments/hcog_ranger",0,0,0,0 +"aog","attachment","#MOD_AOG_NAME","AOG","#MOD_AOG_DESC","r2_ui/menus/loadout_icons/attachments/aog",0,0,0,0 +"scope_4x","attachment","#MOD_SCOPE_4X_NAME","","#MOD_SCOPE_4X_DESC","r2_ui/menus/loadout_icons/attachments/variable_zoom",0,0,0,0 +"scope_6x","attachment","4x Zoom Scope","4x Zoom","#MOD_SCOPE_4X_DESC","ui/menu/items/attachment_icons/scope_6x",0,0,0,0 +"redline_sight","attachment","#MOD_ZOOM_SIGHT_NAME","#MOD_ZOOM_SIGHT_NAME","#MOD_ZOOM_SIGHT_DESC","r2_ui/menus/loadout_icons/attachments/hcog",0,0,0,0 +"threat_scope","attachment","#MOD_THREAT_SIGHT_NAME","T-Scope","#MOD_THREAT_SIGHT_DESC","r2_ui/menus/loadout_icons/attachments/threat_scope",0,0,0,0 +"extended_ammo","mod","#MOD_EXTENDED_AMMO_NAME","Ext. Mag","#MOD_EXTENDED_AMMO_DESC","rui/pilot_loadout/mods/extended_ammo",0,0,0,0 +"silencer","mod","#MOD_SILENCER_NAME","Suppressor","#MOD_SILENCER_DESC","r2_ui/menus/loadout_icons/attachments/suppressor",0,0,0,0 +"stabilizer","mod","Stabilizer","Stabilizer","Reduces sway when looking down scope","ui/menu/items/mod_icons/stabilizer",0,0,0,0 +"slammer","mod","Slammer","Slammer","Increases rodeo damage","ui/menu/items/mod_icons/slammer",0,0,0,0 +"enhanced_targeting","mod","Enhanced Targeting","E. Targeting","Enables multiple lock-on capability","ui/menu/items/mod_icons/enhanced_targeting",0,0,0,0 +"single_lock","mod","Single Lock","Single Lock","Single Lock on Pilots","ui/menu/items/mod_icons/enhanced_targeting",0,0,0,0 +"ricochet","mod","#MOD_RICOCHET_NAME","Ricochet","#MOD_RICOCHET_DESC","rui/pilot_loadout/mods/ricochet",0,0,0,0 +"ar_trajectory","mod","Ar Trajectory","Ar Trajectory","Displays estimated trajectory","rui/pilot_loadout/mods/ar_trajectory",0,0,0,0 +"alt_spread","mod","Alt Spread","Alt Spread","Alternate spread pattern","ui/temp",0,0,0,0 +"delayed_shot","mod","Soft Launch","Soft Launch","Delayed ignition with fast rockets","ui/temp",0,0,0,0 +"quick_charge","mod","#MOD_CHARGE_HACK_NAME","Charge Hack","#MOD_CHARGE_HACK_DESC","rui/pilot_loadout/mods/charge_hack",0,0,0,0 +"pas_run_and_gun","mod","#MOD_GUNRUNNER_NAME","Gunrunner","#MOD_GUNRUNNER_DESC","rui/pilot_loadout/mods/gunrunner",0,0,0,0 +"tactical_cdr_on_kill","mod","#MOD_TACTIKILL_NAME","Tactikill","#MOD_TACTIKILL_DESC","rui/pilot_loadout/mods/tactikill",0,0,0,0 +"pas_fast_ads","mod","#MOD_GUN_READY_NAME","Fast ADS","#MOD_GUN_READY_DESC","rui/pilot_loadout/mods/gun_ready",0,0,0,0 +"pas_fast_swap","mod","#MOD_SPEED_TRANSITION_NAME","Fast Swap","#MOD_SPEED_TRANSITION_DESC","rui/pilot_loadout/mods/speed_transition",0,0,0,0 +"pas_fast_reload","mod","#GEAR_QUICK_RELOAD","#GEAR_QUICK_RELOAD","#GEAR_QUICK_RELOAD_DESC","rui/pilot_loadout/kit/speed_loader",0,0,0,0 +"pro_screen","mod3","#MOD_PRO_SCREEN_NAME","Pro Screen","#MOD_PRO_SCREEN_DESC","rui/pilot_loadout/mods/pro_screen",0,0,0,0 +"rocket_arena","mod","#MOD_PRO_SCREEN_NAME","Pro Screen","#MOD_PRO_SCREEN_DESC","rui/pilot_loadout/mods/pro_screen",0,0,0,0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/pilot_weapons.csv b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapons.csv new file mode 100644 index 00000000..d8bbfb0a --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/pilot_weapons.csv @@ -0,0 +1,33 @@ +itemRef,type,defaultAttachment,defaultMod1,defaultMod2,defaultMod3,hidden,xpPerLevelType,cost +"mp_weapon_r97","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_alternator_smg","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_car","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_hemlok_smg","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_lmg","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_lstar","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_esaw","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_rspn101","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_vinson","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_hemlok","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_g2","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_shotgun","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_mastiff","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_dmr","PILOT_PRIMARY","","","","",0,"sniper",100 +"mp_weapon_doubletake","PILOT_PRIMARY","","","","",0,"sniper",100 +"mp_weapon_sniper","PILOT_PRIMARY","","","","",0,"sniper",100 +"mp_weapon_epg","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_smr","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_pulse_lmg","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_softball","PILOT_PRIMARY","","","","",0,"default",100 +"mp_weapon_autopistol","PILOT_SECONDARY","","","","",0,"pistol",50 +"mp_weapon_semipistol","PILOT_SECONDARY","","","","",0,"pistol",50 +"mp_weapon_wingman","PILOT_SECONDARY","","","","",0,"pistol",50 +"mp_weapon_shotgun_pistol","PILOT_PRIMARY","","","","",0,"default",50 +"mp_weapon_rocket_launcher","PILOT_SECONDARY","","","","",0,"antititan",50 +"mp_weapon_arc_launcher","PILOT_SECONDARY","","","","",0,"antititan",50 +"mp_weapon_defender","PILOT_SECONDARY","","","","",0,"antititan",50 +"mp_weapon_mgl","PILOT_SECONDARY","","","","",0,"antititan",50 +"melee_pilot_emptyhanded","PILOT_MELEE","","","","",0,"default",100 +"melee_pilot_arena","PILOT_MELEE","","","","",0,"default",100 +"mp_weapon_wingman_n","PILOT_PRIMARY","","","","",0,"default",50 +"mp_weapon_rspn101_og","PILOT_PRIMARY","","","","",0,"default",100 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/playlist_items.csv b/Northstar.CustomServers/mod/scripts/datatable/playlist_items.csv new file mode 100644 index 00000000..f485fe70 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/playlist_items.csv @@ -0,0 +1,27 @@ +playlist,name,image,thumbnail,cost +"at","#PL_attrition","rui/menu/gametype_select/bounty_hunt","rui/menu/gametype_select/playlist_bounty_hunt",5 +"aitdm","#PL_aitdm","rui/menu/gametype_select/attrition","rui/menu/gametype_select/playlist_attrition",5 +"cp","#PL_hardpoint","rui/menu/gametype_select/hardpoint","rui/menu/gametype_select/playlist_amped_hardpoint",5 +"ctf","#PL_capture_the_flag","rui/menu/gametype_select/capture_the_flag","rui/menu/gametype_select/playlist_ctf",5 +"lts","#PL_last_titan_standing","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_lts",5 +"tdm","#PL_pilot_hunter","rui/menu/gametype_select/pilot_hunter","rui/menu/gametype_select/playlist_skirmish",5 +"varietypack","Variety Pack","rui/menu/gametype_select/variety_pack","rui/menu/gametype_select/playlist_gen_weapon",5 +"coliseum","#PL_coliseum","rui/menu/gametype_select/colosseum","rui/menu/gametype_select/playlist_coliseum",0 +"fnf","Friday Night Fights","rui/menu/gametype_select/friday_night_fights","rui/menu/gametype_select/playlist_gen_star",5 +"ffa","#PL_ffa","rui/menu/gametype_select/free_for_all","rui/menu/gametype_select/playlist_free_for_all",5 +"ps","#PL_pilot_skirmish","rui/menu/gametype_select/pilot_v_pilot","rui/menu/gametype_select/playlist_pilot_vs_pilot",5 +"default","Default","rui/menu/gametype_select/bounty_hunt","rui/menu/gametype_select/playlist_gen_star",5 +"fw","#PL_titan_war","rui/menu/gametype_select/titan_war","rui/menu/gametype_select/playlist_gen_arrow",5 +"private_match","#PL_private_match","rui/menu/gametype_select/private_match","rui/menu/gametype_select/playlist_gen_star",0 +"lf","#PL_speedball","rui/menu/gametype_select/hardcore_pilot_hunter","rui/menu/gametype_select/playlist_live_fire",5 +"angel_city_247","#PL_angel_city","rui/menu/gametype_select/angel_city","rui/menu/gametype_select/playlist_gen_star",5 +"hunted","#PL_hunted","rui/menu/gametype_select/variety_pack","rui/menu/gametype_select/playlist_apex",5 +"mfd","#PL_mfd","rui/menu/gametype_select/pilot_hunter","rui/menu/gametype_select/playlist_marked_for_death",5 +"speedball","#PL_speedball","rui/menu/gametype_select/hardcore_pilot_hunter","rui/menu/gametype_select/playlist_live_fire",0 +"fd_easy","#PL_fd_easy","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_easy",0 +"fd","#PL_fd_normal","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_normal",0 +"fd_normal","#PL_fd_normal","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_normal",0 +"fd_hard","#PL_fd_hard","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_hard",0 +"fd_master","#PL_fd_master","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_master",0 +"fd_insane","#PL_fd_insane","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_fd_insane",0 +"ttdm","#PL_titan_brawl","rui/menu/gametype_select/last_titan_standing","rui/menu/gametype_select/playlist_titan_brawl",5 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/score_events.csv b/Northstar.CustomServers/mod/scripts/datatable/score_events.csv new file mode 100644 index 00000000..d71d3ac9 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/score_events.csv @@ -0,0 +1,221 @@ +name,splashText,medalText,pointValue,burnPointValue,pointType,xpValue,xpValueTitan,xpValueWeapon,xpValueFaction,xpType,displayType,medalIcon,conversation,scaleScoreForAutoTitan +"AttritionAirDroneKilled","#SCORE_EVENT_AT_AIR_DRONE_KILLED","#SCORE_EVENT_AT_AIR_DRONE_KILLED","ATTRITION_SCORE_AIR_DRONE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionBossKilled","#SCORE_EVENT_AT_BOSS_KILLED","#SCORE_EVENT_AT_BOSS_KILLED","ATTRITION_SCORE_BOSS","","ASSAULT","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionBountySurvived","#SCORE_EVENT_AT_BOUNTY_SURVIVED","#SCORE_EVENT_AT_BOUNTY_SURVIVED","ATTRITION_SCORE_BOUNTY_SURVIVAL","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/victory","",0 +"AttritionGruntKilled","#SCORE_EVENT_AT_GRUNT_KILLED","#SCORE_EVENT_AT_GRUNT_KILLED","ATTRITION_SCORE_GRUNT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"AttritionMegaTurretKilled","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","ATTRITION_SCORE_MEGATURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionSentryTurretKilled","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","ATTRITION_SCORE_SENTRYTURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionPilotKilled","#SCORE_EVENT_AT_PILOT_KILLED","#SCORE_EVENT_AT_PILOT_KILLED","ATTRITION_SCORE_PILOT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"AttritionProwlerKilled","#SCORE_EVENT_AT_PROWLER_KILLED","#SCORE_EVENT_AT_PROWLER_KILLED","ATTRITION_SCORE_PROWLER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"AttritionSpectreKilled","#SCORE_EVENT_AT_SPECTRE_KILLED","#SCORE_EVENT_AT_SPECTRE_KILLED","ATTRITION_SCORE_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionStalkerKilled","#SCORE_EVENT_AT_STALKER_KILLED","#SCORE_EVENT_AT_STALKER_KILLED","ATTRITION_SCORE_STALKER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionSuperSpectreKilled","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","ATTRITION_SCORE_SUPER_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionTitanDoomed","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","ATTRITION_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionTitanKilled","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","ATTRITION_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"AttritionCashedBonus","#SCORE_EVENT_AT_CASHED_BONUS","#SCORE_EVENT_AT_CASHED_BONUS","ATTRITION_SCORE_BONUS","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"AttritionBonusStolen","#SCORE_EVENT_AT_BONUS_STOLEN","#SCORE_EVENT_AT_BONUS_STOLEN","ATTRITION_SCORE_BONUS_STOLEN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"BombCarry","#SCORE_EVENT_BOMB_CARRY_POINTS","#SCORE_EVENT_BOMB_CARRY_POINTS","GAMEMODE_BOMB_SCORE_CARRY","","DISTANCE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/bomb","",0 +"BombPlant","#SCORE_EVENT_BOMB_PLANT_POINTS","#SCORE_EVENT_BOMB_PLANT_POINTS","GAMEMODE_BOMB_SCORE_PLANT","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/bomb","",0 +"BombDefuse","#SCORE_EVENT_BOMB_DEFUSE_POINTS","#SCORE_EVENT_BOMB_DEFUSE_POINTS","GAMEMODE_BOMB_SCORE_DEFUSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/bomb","",0 +"BombExplode","#SCORE_EVENT_BOMB_EXPLODE_POINTS","#SCORE_EVENT_BOMB_EXPLODE_POINTS","GAMEMODE_BOMB_SCORE_EXPLODE","","DETONATION","0","0","0","0","","MEDAL GAMEMODE","rui/medals/bomb","",0 +"ChallengeCompleted","#SCORE_EVENT_CHALLENGE_COMPLETED","#SCORE_EVENT_CHALLENGE_COMPLETED","0","","","0","0","0","0","","MEDAL","rui/medals/victory","",0 +"ChallengePVPKillCount","#SCORE_EVENT_CHALLENGE_PVP_KILLS","#SCORE_EVENT_CHALLENGE_PVP_KILLS","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeATAssault","#SCORE_EVENT_CHALLENGE_AT_ASSAULT","#SCORE_EVENT_CHALLENGE_AT_ASSAULT","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeCPAssault","#SCORE_EVENT_CHALLENGE_CP_ASSAULT","#SCORE_EVENT_CHALLENGE_CP_ASSAULT","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeCPDefense","#SCORE_EVENT_CHALLENGE_CP_DEFENSE","#SCORE_EVENT_CHALLENGE_CP_DEFENSE","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeCTFCapAssist","#SCORE_EVENT_ASSIST_WITH_FLAG_CAP","#SCORE_EVENT_ASSIST_WITH_FLAG_CAP","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeCTFRetAssist","#SCORE_EVENT_ASSIST_WITH_FLAG_RET","#SCORE_EVENT_ASSIST_WITH_FLAG_RET","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeFW","#SCORE_EVENT_USE_N_BATTERIES","#SCORE_EVENT_USE_N_BATTERIES","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeFFA","#SCORE_EVENT_KILL_N_PILOTS","#SCORE_EVENT_KILL_N_PILOTS","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeTDM","#SCORE_EVENT_KILL_N_IN_A_ROW","#SCORE_EVENT_KILL_N_IN_A_ROW","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeTTDM","#SCORE_EVENT_CHALLENGE_COMPLETED","#SCORE_EVENT_CHALLENGE_COMPLETED","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeLTS","#SCORE_EVENT_KILL_N_TITANS","#SCORE_EVENT_KILL_N_TITANS","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeSPEEDBALL","#SCORE_EVENT_KILL_N_PILOTS","#SCORE_EVENT_KILL_N_PILOTS","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeMFD","#SCORE_EVENT_CHALLENGE_COMPLETED","#SCORE_EVENT_CHALLENGE_COMPLETED","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"ChallengeFD","#SCORE_EVENT_CHALLENGE_FD","#SCORE_EVENT_CHALLENGE_FD","","","","1","0","0","0","SCORE_MILESTONE","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"Comeback","#SCORE_EVENT_COMEBACK","#SCORE_EVENT_COMEBACK","POINTVALUE_COMEBACK","","","0","0","0","0","","MEDAL","rui/medals/kill","kc_comeback",0 +"ControlPanelHeavyTurretActivate","#SCORE_EVENT_HEAVY_TURRET_ACTIVATED","#SCORE_EVENT_HEAVY_TURRET_ACTIVATED","POINTVALUE_CONTROL_PANEL_ACTIVATE","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"ControlPanelLightTurretActivate","#SCORE_EVENT_LIGHT_TURRETS_ACTIVATED","#SCORE_EVENT_LIGHT_TURRETS_ACTIVATED","POINTVALUE_CONTROL_PANEL_ACTIVATE_LIGHT","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"ControlPointCapture","#SCORE_EVENT_HARDPOINT_CAPTURED","#SCORE_EVENT_HARDPOINT_CAPTURED","POINTVALUE_HARDPOINT_CAPTURE","","ASSAULT","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointCaptureAssist","#SCORE_EVENT_HARDPOINT_CAPTURE_ASSIST","#SCORE_EVENT_HARDPOINT_CAPTURE_ASSIST","POINTVALUE_HARDPOINT_CAPTURE_ASSIST","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointHold","#SCORE_EVENT_HARDPOINT_HOLD","#SCORE_EVENT_HARDPOINT_HOLD","POINTVALUE_HARDPOINT_HOLD","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointTake","#SCORE_EVENT_HARDPOINT_TAKE","#SCORE_EVENT_HARDPOINT_TAKE","POINTVALUE_HARDPOINT_HOLD","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointAmped","#SCORE_EVENT_HARDPOINT_AMPED","#SCORE_EVENT_HARDPOINT_AMPED","POINTVALUE_HARDPOINT_AMPED","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointAmpedHold","#SCORE_EVENT_HARDPOINT_AMPED_HOLD","#SCORE_EVENT_HARDPOINT_AMPED_HOLD","POINTVALUE_HARDPOINT_AMPED_HOLD","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointNeutralize","#SCORE_EVENT_HARDPOINT_NEUTRALIZED","#SCORE_EVENT_HARDPOINT_NEUTRALIZED","POINTVALUE_HARDPOINT_NEUTRALIZE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"ControlPointNeutralizeAssist","#SCORE_EVENT_HARDPOINT_NEUTRALIZE_ASSIST","#SCORE_EVENT_HARDPOINT_NEUTRALIZE_ASSIST","POINTVALUE_HARDPOINT_NEUTRALIZE_ASSIST","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"Damage","#SCORE_EVENT_DAMAGE_GENERIC","#SCORE_EVENT_DAMAGE_GENERIC","0","","","0","0","0","0","","CENTER","rui/medals/kill","",0 +"DamageTitan","#SCORE_EVENT_DAMAGE_TITAN","#SCORE_EVENT_DAMAGE_TITAN","0","","","0","0","0","0","","CENTER","rui/medals/kill","",0 +"StealMeter","#SCORE_EVENT_STEAL_METER","#SCORE_EVENT_STEAL_METER","0","","","0","0","0","0","","CENTER","rui/medals/kill","",0 +"Destored_Proximity_Mine","#SCORE_EVENT_DESTROYED_PROXIMITY_CHARGE","#SCORE_EVENT_DESTROYED_PROXIMITY_CHARGE","POINTVALUE_DESTROYED_PROXIMITY_MINE","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"Destroyed_Satchel","#SCORE_EVENT_DESTROYED_SATCHEL_CHARGE","#SCORE_EVENT_DESTROYED_SATCHEL_CHARGE","POINTVALUE_DESTROYED_SATCHEL","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"Dominating","#SCORE_EVENT_DOMINATING","#SCORE_EVENT_DOMINATING","POINTVALUE_DOMINATING","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_dominating",0 +"DoomAutoTitan","#MEDAL_DOOMED_TITAN","#MEDAL_DOOMED_TITAN","100","BURN_METER_SMALL_POINT_VALUE","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"DoomTitan","#MEDAL_DOOMED_TITAN","#MEDAL_DOOMED_TITAN","100","BURN_METER_SMALL_POINT_VALUE","","0","0","0","0","","BIG MEDAL","rui/medals/kill_robot","",0 +"DoubleKill","#SCORE_EVENT_DOUBLE_KILL","#SCORE_EVENT_DOUBLE_KILL","POINTVALUE_DOUBLEKILL","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_doublekill",0 +"EliminatePilot","#SCORE_EVENT_ELIMINATED_PILOT","#MEDAL_ELIMINATED_PILOT","POINTVALUE_ELIMINATE_PILOT","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","KILL","BIG MEDAL CENTER","rui/medals/kill","",0 +"EliminateTitan","#MEDAL_ELIMINATED_TITAN","#MEDAL_ELIMINATED_TITAN","1","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","","CALLINGCARD MEDAL","rui/medals/kill_robot","",0 +"EliminateAutoTitan","#MEDAL_ELIMINATED_TITAN","#MEDAL_ELIMINATED_TITAN","1","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","","CALLINGCARD MEDAL","rui/medals/kill_robot","",0 +"FirstStrike","#SCORE_EVENT_FIRST_STRIKE","#SCORE_EVENT_FIRST_STRIKE","POINTVALUE_FIRST_STRIKE","","","0","0","0","0","","CALLINGCARD MEDAL","rui/medals/first_strike","kc_firstblood",0 +"FirstTitanfall","#SCORE_EVENT_FIRST_TITANFALL","#SCORE_EVENT_FIRST_TITANFALL","POINTVALUE_FIRST_TITANFALL","","","0","1","0","0","TITAN_FALL","CALLINGCARD MEDAL","rui/medals/titanfall","",0 +"FishInBarrel","#SCORE_EVENT_FISH_IN_A_BARREL","#SCORE_EVENT_FISH_IN_A_BARREL","POINTVALUE_FISHINBARREL","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"FlagCapture","#SCORE_EVENT_FLAG_CAPTURE","#SCORE_EVENT_FLAG_CAPTURE","POINTVALUE_FLAG_CAPTURE","","","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/ctf","",0 +"FlagTaken","#SCORE_EVENT_FLAG_TAKEN","#SCORE_EVENT_FLAG_TAKEN","POINTVALUE_FLAG_TAKEN","","","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/ctf","",0 +"FlagCaptureAssist","#SCORE_EVENT_FLAG_CAPTURE_ASSIST","#SCORE_EVENT_FLAG_CAPTURE_ASSIST","POINTVALUE_FLAG_CAPTURE_ASSIST","","","0","0","0","0","","MEDAL","rui/medals/ctf","",0 +"FlagCarrierKill","#SCORE_EVENT_KILLED_FLAG_CARRIER","#SCORE_EVENT_KILLED_FLAG_CARRIER","POINTVALUE_FLAG_CARRIER_KILL","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/ctf","",0 +"FlagReturn","#SCORE_EVENT_FLAG_RETURN","#SCORE_EVENT_FLAG_RETURN","POINTVALUE_FLAG_RETURN","","","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/ctf","",0 +"FlyerKill","#SCORE_EVENT_KILLED_FLYER","#MEDAL_KILLED_FLYER","POINTVALUE_KILL_FLYER","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"GetToChopper","#SCORE_EVENT_GET_TO_THE_CHOPPER","#SCORE_EVENT_GET_TO_THE_CHOPPER","POINTVALUE_GET_TO_CHOPPER","","","0","0","0","0","","MEDAL","rui/medals/extract","",0 +"GiveRide","#SCORE_EVENT_GIVE_A_FRIEND_A_LIFT","#SCORE_EVENT_GIVE_A_FRIEND_A_LIFT","POINTVALUE_FRIEND_RIDE","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"HappyHourBonus","#SCORE_EVENT_HAPPY_HOUR_BONUS","#SCORE_EVENT_HAPPY_HOUR_BONUS","","","","5","0","0","0","HAPPY_HOUR","MEDAL CHALLENGE GAMEMODE","rui/medals/victory","",0 +"HardpointAssault","#SCORE_EVENT_HARDPOINT_ASSAULT","#SCORE_EVENT_HARDPOINT_ASSAULT","POINTVALUE_HARDPOINT_ASSAULT","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"HardpointDefense","#SCORE_EVENT_HARDPOINT_DEFENSE","#SCORE_EVENT_HARDPOINT_DEFENSE","POINTVALUE_HARDPOINT_DEFENSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"HardpointPerimeterDefense","#SCORE_EVENT_HARDPOINT_PERIMETER_DEFENSE","#SCORE_EVENT_HARDPOINT_PERIMETER_DEFENSE","POINTVALUE_HARDPOINT_PERIMETER_DEFENSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"HardpointSiege","#SCORE_EVENT_HARDPOINT_SIEGE","#SCORE_EVENT_HARDPOINT_SIEGE","POINTVALUE_HARDPOINT_SIEGE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"HardpointSnipe","#SCORE_EVENT_HARDPOINT_RANGED_SUPPORT","#SCORE_EVENT_HARDPOINT_RANGED_SUPPORT","POINTVALUE_HARDPOINT_SNIPE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"Headshot","#MEDAL_HEADSHOT","#MEDAL_HEADSHOT","POINTVALUE_HEADSHOT","","","0","0","0","0","","MEDAL","rui/medals/headshot","",0 +"HitchRide","#SCORE_EVENT_HITCH_A_RIDE","#SCORE_EVENT_HITCH_A_RIDE","POINTVALUE_RODEOD_FRIEND","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"HotZoneExtract","#SCORE_EVENT_HOT_ZONE_EXTRACT","#SCORE_EVENT_HOT_ZONE_EXTRACT","POINTVALUE_HOTZONE_EXTRACT","","","1","0","0","1","EVAC","MEDAL","rui/medals/extract","",0 +"KillAutoTitan","#MEDAL_KILLED_TITAN","#MEDAL_KILLED_TITAN","POINTVALUE_KILL_TITAN","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","","CALLINGCARD MEDAL","rui/medals/kill_robot","",0 +"KillDrone","#SCORE_EVENT_KILLED_DRONE","#MEDAL_KILLED_DRONE","POINTVALUE_KILL_DRONE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"KillDropship","#SCORE_EVENT_EVAC_DENIED","#SCORE_EVENT_EVAC_DENIED","POINTVALUE_EVAC_DENIED","","","0","0","0","0","","MEDAL","rui/medals/extract","",0 +"KilledEscapee","#SCORE_EVENT_KILLED_EVACUATING_ENEMY","#MEDAL_KILLED_EVACUATING_ENEMY","POINTVALUE_KILLED_ESCAPEE","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"KilledMVP","#SCORE_EVENT_KILLED_MVP","#MEDAL_KILLED_MVP","POINTVALUE_KILLED_MVP","","","0","0","0","0","","MEDAL","rui/medals/kill","",0 +"KillGrunt","#SCORE_EVENT_KILLED_MILITIA","#SCORE_EVENT_KILLED_MILITIA","POINTVALUE_KILL_FIRETEAM_AI","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill","",0 +"KillHeavyTurret","#SCORE_EVENT_KILLED_HEAVY_TURRET","#SCORE_EVENT_KILLED_HEAVY_TURRET","POINTVALUE_KILL_HEAVY_TURRET","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"KillingSpree","#SCORE_EVENT_KILLING_SPREE","#SCORE_EVENT_KILLING_SPREE","POINTVALUE_KILLINGSPREE","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_killingspree",0 +"KillLightTurret","#SCORE_EVENT_KILLED_LIGHT_TURRET","#SCORE_EVENT_KILLED_LIGHT_TURRET","POINTVALUE_KILL_LIGHT_TURRET","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"KillPilot","#SCORE_EVENT_KILLED_PILOT","#MEDAL_KILLED_PILOT","1","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","KILL","BIG MEDAL CENTER","rui/medals/kill","",0 +"KillProwler","#SCORE_EVENT_KILLED_PROWLER","#MEDAL_KILLED_PROWLER","POINTVALUE_KILL_PROWLER","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"KillRescueShip","#SCORE_EVENT_EVAC_DENIED","#SCORE_EVENT_EVAC_DENIED","POINTVALUE_EVAC_DENIED","","","0","0","0","0","","MEDAL","rui/medals/extract","",0 +"KillSpectre","#SCORE_EVENT_KILLED_SPECTRE","#MEDAL_KILLED_SPECTRE","POINTVALUE_KILL_SPECTRE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"KillStalker","#SCORE_EVENT_KILLED_STALKER","#MEDAL_KILLED_STALKER","POINTVALUE_KILL_STALKER","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"KillHackedSpectre","#SCORE_EVENT_KILLED_HACKED_SPECTRE","#MEDAL_KILLED_SPECTRE","POINTVALUE_KILL_SPECTRE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"KillSuperSpectre","#SCORE_EVENT_KILLED_SUPER_SPECTRE","#MEDAL_KILLED_SUPER_SPECTRE","POINTVALUE_KILL_SUPER_SPECTRE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"KillTitan","#MEDAL_KILLED_TITAN","#MEDAL_KILLED_TITAN","POINTVALUE_KILL_TITAN","BURN_METER_SMALL_POINT_VALUE","","0","0","1","0","KILL","CALLINGCARD MEDAL CENTER","rui/medals/kill_robot","",0 +"TitanKillTitan","#MEDAL_KILLED_TITAN","#MEDAL_KILLED_TITAN","POINTVALUE_KILL_TITAN","BURN_METER_SMALL_POINT_VALUE","","0","1","1","0","KILL","CALLINGCARD MEDAL CENTER","rui/medals/kill_robot","",0 +"LeechDrone","#SCORE_EVENT_LEECHED_DRONE","#SCORE_EVENT_LEECHED_DRONE","POINTVALUE_LEECH_DRONE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"LeechSpectre","#SCORE_EVENT_LEECHED_SPECTRE","#SCORE_EVENT_LEECHED_SPECTRE","POINTVALUE_LEECH_SPECTRE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"LeechSuperSpectre","#SCORE_EVENT_LEECHED_SUPER_SPECTRE","#SCORE_EVENT_LEECHED_SUPER_SPECTRE","POINTVALUE_LEECH_SUPER_SPECTRE","","","0","0","0","0","","MEDAL","rui/medals/kill_robot","",0 +"MarkedEscort","#SCORE_EVENT_PROTECTED_MARKED_TARGET","#SCORE_EVENT_PROTECTED_MARKED_TARGET","POINTVALUE_MARKED_ESCORT","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill","",0 +"MarkedKilledMarked","#SCORE_EVENT_MARKED_KILLED_MARKED","#SCORE_EVENT_MARKED_KILLED_MARKED","POINTVALUE_MARKED_KILLED_MARKED","","","0","0","0","0","","MEDAL GAMEMODE","rui/hud/gametype_icons/mfd/mfd_enemy","",0 +"MarkedOutlastedEnemyMarked","#SCORE_EVENT_MARKED_OUTLASTED_ENEMY_MARK","#SCORE_EVENT_MARKED_OUTLASTED_ENEMY_MARK","POINTVALUE_MARKED_OUTLASTED_ENEMY_MARKED","","","0","0","0","0","","MEDAL GAMEMODE","rui/hud/gametype_icons/mfd/mfd_friendly","",0 +"MarkedSurvival","#SCORE_EVENT_MARKED_SURVIVAL","#SCORE_EVENT_MARKED_SURVIVAL","POINTVALUE_MARKED_SURVIVAL","","","0","0","0","0","","MEDAL GAMEMODE","rui/hud/gametype_icons/mfd/mfd_friendly","",0 +"MarkedTargetKilled","#SCORE_EVENT_KILLED_MARKED_TARGET","#SCORE_EVENT_KILLED_MARKED_TARGET","POINTVALUE_MARKED_TARGET_KILLED","","","0","0","0","0","","MEDAL GAMEMODE","rui/hud/gametype_icons/mfd/mfd_enemy","",0 +"MatchComplete","#SCORE_EVENT_COMPLETION","#SCORE_EVENT_COMPLETION","POINTVALUE_MATCH_COMPLETION","","","1","0","0","0","MATCH_COMPLETED","MEDAL","rui/medals/victory","",0 +"MatchVictory","#SCORE_EVENT_VICTORY","#SCORE_EVENT_VICTORY","POINTVALUE_MATCH_VICTORY","","","1","0","0","1","MATCH_VICTORY","MEDAL GAMEMODE","rui/medals/victory","",0 +"Mayhem","#SCORE_EVENT_MAYHEM","#SCORE_EVENT_MAYHEM","POINTVALUE_MAYHEM","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"MegaKill","#SCORE_EVENT_MEGA_KILL","#SCORE_EVENT_MEGA_KILL","POINTVALUE_MEGAKILL","","","0","0","0","0","","CALLINGCARD MEDAL","rui/medals/kill_multiple","kc_megakill",0 +"Nemesis","#SCORE_EVENT_NEMESIS","#SCORE_EVENT_NEMESIS","POINTVALUE_NEMESIS","","","0","0","0","0","","MEDAL","rui/medals/kill","kc_retribution",0 +"NewPlayerBonus","#SCORE_EVENT_NEW_PLAYER_BONUS","#SCORE_EVENT_NEW_PLAYER_BONUS","POINTVALUE_MATCH_VICTORY","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/victory","",0 +"NPCHeadshot","#SCORE_EVENT_HEADSHOT","#SCORE_EVENT_HEADSHOT","POINTVALUE_NPC_HEADSHOT","","","0","0","0","0","","MEDAL","rui/medals/headshot","",0 +"Onslaught","#SCORE_EVENT_ONSLAUGHT","#SCORE_EVENT_ONSLAUGHT","POINTVALUE_ONSLAUGHT","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"PilotAmmoPickup","Picked Up Ammo","Picked Up Ammo","50","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",1 +"PilotAssist","#MEDAL_ASSIST_PILOT","#MEDAL_ASSIST_PILOT","POINTVALUE_ASSIST","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill","",0 +"PilotBatteryApplied","#SCORE_EVENT_BATTERY_APPLY","#SCORE_EVENT_BATTERY_APPLY","50","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",1 +"PilotBatteryPickup","#SCORE_EVENT_BATTERY_PICKUP","#SCORE_EVENT_BATTERY_PICKUP","50","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",1 +"PilotBatteryStolen","#SCORE_EVENT_BATTERY_STEAL","#SCORE_EVENT_BATTERY_STEAL","50","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",1 +"QuickRevenge","#SCORE_EVENT_QUICK_REVENGE","#SCORE_EVENT_QUICK_REVENGE","POINTVALUE_REVENGE_QUICK","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"Rampage","#SCORE_EVENT_RAMPAGE","#SCORE_EVENT_RAMPAGE","POINTVALUE_RAMPAGE","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_rampage",0 +"Revenge","#SCORE_EVENT_REVENGE","#SCORE_EVENT_REVENGE","POINTVALUE_REVENGE","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"RodeoEnemyTitan","#SCORE_EVENT_RODEOED_ENEMY_TITAN","#SCORE_EVENT_RODEOED_ENEMY_TITAN","POINTVALUE_RODEOD","","","0","0","0","0","","MEDAL","rui/medals/medal_prototype","",0 +"RoundComplete","#SCORE_EVENT_ROUND_COMPLETION","#SCORE_EVENT_ROUND_COMPLETION","POINTVALUE_ROUND_COMPLETION","","","0","0","0","0","","MEDAL","rui/medals/victory","",0 +"RoundVictory","#SCORE_EVENT_ROUND_WIN","#SCORE_EVENT_ROUND_WIN","POINTVALUE_ROUND_WIN","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/victory","",0 +"SelfBonusKilledAll","#SCORE_EVENT_SOLO_KILLED_ALL_COMBATANTS","#SCORE_EVENT_SOLO_KILLED_ALL_COMBATANTS","POINTVALUE_FULL_TEAM_KILL_SOLO","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"Showstopper","#SCORE_EVENT_SHOWSTOPPER","#SCORE_EVENT_SHOWSTOPPER","POINTVALUE_SHOWSTOPPER","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_iced",0 +"SoleSurvivor","#SCORE_EVENT_SOLE_SURVIVOR","#SCORE_EVENT_SOLE_SURVIVOR","POINTVALUE_SOLE_SURVIVOR","","","0","0","0","0","","MEDAL","rui/medals/extract","",0 +"SpotAssist","#SCORE_EVENT_SPOT_ASSIST","#SCORE_EVENT_SPOT_ASSIST","POINTVALUE_ASSIST","","","0","0","0","0","","MEDAL","rui/medals/headshot","",0 +"TeamBonusFullEvac","#SCORE_EVENT_TEAM_BONUS_FULL_TEAM_EVAC","#SCORE_EVENT_TEAM_BONUS_FULL_TEAM_EVAC","POINTVALUE_FULL_TEAM_EVAC","","","0","0","0","0","","MEDAL","rui/medals/extract","",0 +"TeamBonusKilledAll","#SCORE_EVENT_TEAM_BONUS_KILLED_ALL_COMBATANTS","#SCORE_EVENT_TEAM_BONUS_KILLED_ALL_COMBATANTS","POINTVALUE_FULL_TEAM_KILL","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","",0 +"TitanAssist","#MEDAL_ASSIST_TITAN","#MEDAL_ASSIST_TITAN","POINTVALUE_ASSIST_TITAN","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"TitanCoreEarned","#SCORE_EVENT_CORE_EARNED","#SCORE_EVENT_CORE_EARNED","POINTVALUE_CALLED_IN_TITAN","","","0","1","0","0","TITAN_CORE_EARNED","CALLINGCARD MEDAL","rui/medals/titanfall","",0 +"Titanfall","#SCORE_EVENT_TITANFALL","#SCORE_EVENT_TITANFALL","POINTVALUE_CALLED_IN_TITAN","","","0","1","0","0","TITAN_FALL","CALLINGCARD MEDAL","rui/medals/titanfall","",0 +"TripleKill","#SCORE_EVENT_TRIPLE_KILL","#SCORE_EVENT_TRIPLE_KILL","POINTVALUE_TRIPLEKILL","","","0","0","0","0","","MEDAL","rui/medals/kill_multiple","kc_triplekill",0 +"VictoryKill","#SCORE_EVENT_VICTORY_KILL","#SCORE_EVENT_VICTORY_KILL","POINTVALUE_VICTORYKILL","BURN_METER_SMALL_POINT_VALUE","","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/kill","",0 +"FactionLevelUp","","","","","","1","0","0","0","FACTION_LEVELED","","","",0 +"TitanLevelUp","","","","","","1","0","0","0","TITAN_LEVELED","","","",0 +"WeaponLevelUp","","","","","","1","0","0","0","WEAPON_LEVELED","","","",0 +"FortWarAssault","#SCORE_EVENT_FW_ASSAULT","#SCORE_EVENT_FW_ASSAULT","POINTVALUE_FW_ASSAULT","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarDefense","#SCORE_EVENT_FW_DEFENSE","#SCORE_EVENT_FW_DEFENSE","POINTVALUE_FW_DEFENSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarPerimeterDefense","#SCORE_EVENT_FW_PERIMETER_DEFENSE","#SCORE_EVENT_FW_PERIMETER_DEFENSE","POINTVALUE_FW_PERIMETER_DEFENSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarSiege","#SCORE_EVENT_FW_SIEGE","#SCORE_EVENT_FW_SIEGE","POINTVALUE_FW_SIEGE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarSnipe","#SCORE_EVENT_FW_RANGED_SUPPORT","#SCORE_EVENT_FW_RANGED_SUPPORT","POINTVALUE_FW_SNIPE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarBaseConstruction","#SCORE_EVENT_FW_BASE_CONSTRUCTION","#SCORE_EVENT_FW_BASE_CONSTRUCTION","POINTVALUE_FW_BASE_CONSTRUCTION","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarForwardConstruction","#SCORE_EVENT_FW_FORWARD_CONSTRUCTION","#SCORE_EVENT_FW_FORWARD_CONSTRUCTION","POINTVALUE_FW_FORWARD_CONSTRUCTION","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarInvasiveConstruction","#SCORE_EVENT_FW_INVASIVE_CONSTRUCTION","#SCORE_EVENT_FW_INVASIVE_CONSTRUCTION","POINTVALUE_FW_INVASIVE_CONSTRUCTION","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarShieldConstruction","#SCORE_EVENT_FW_SHIELD_CONSTRUCTION","#SCORE_EVENT_FW_SHIELD_CONSTRUCTION","POINTVALUE_FW_SHIELD_CONSTRUCTION","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarResourceDenial","#SCORE_EVENT_FW_RESOURCE_DENIAL","#SCORE_EVENT_FW_RESOURCE_DENIAL","POINTVALUE_FW_RESOURCE_DENIAL","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarTowerDamage","#SCORE_EVENT_FW_TOWER_DAMAGE","#SCORE_EVENT_FW_TOWER_DAMAGE","POINTVALUE_FW_TOWER_DAMAGE","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarTowerDefense","#SCORE_EVENT_FW_TOWER_DEFENSE","#SCORE_EVENT_FW_TOWER_DEFENSE","POINTVALUE_FW_TOWER_DEFENSE","","DEFENSE","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_One","#SCORE_EVENT_FW_TURRET_CONTROL_ONE","#SCORE_EVENT_FW_TURRET_CONTROL_ONE","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_Two","#SCORE_EVENT_FW_TURRET_CONTROL_TWO","#SCORE_EVENT_FW_TURRET_CONTROL_TWO","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_Three","#SCORE_EVENT_FW_TURRET_CONTROL_THREE","#SCORE_EVENT_FW_TURRET_CONTROL_THREE","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_Four","#SCORE_EVENT_FW_TURRET_CONTROL_FOUR","#SCORE_EVENT_FW_TURRET_CONTROL_FOUR","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_Five","#SCORE_EVENT_FW_TURRET_CONTROL_FIVE","#SCORE_EVENT_FW_TURRET_CONTROL_FIVE","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarTeamTurretControlBonus_Six","#SCORE_EVENT_FW_TURRET_CONTROL_SIX","#SCORE_EVENT_FW_TURRET_CONTROL_SIX","POINTVALUE_FW_TEAM_TURRET_CONTROL","","DEFENSE","0","0","0","0","","MEDAL","rui/medals/hardpoint","",0 +"FortWarSecuringGatheredResources","#SCORE_EVENT_FW_SECURING_RESOURCES","#SCORE_EVENT_FW_SECURING_RESOURCES","POINTVALUE_FW_SECURING_RESOURCES","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"FortWarShieldDestroyed","#SCORE_EVENT_FW_DESTROYED_TURRET_SHIELD","#SCORE_EVENT_FW_DESTROYED_TURRET_SHIELD","POINTVALUE_FW_DESTROY_TURRET_SHIELD","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/hardpoint","",0 +"HuntedEliminatePilot","#SCORE_EVENT_HUNTED_HUNTER_KILLED","#SCORE_EVENT_HUNTED_HUNTER_KILLED","POINTVALUE_HUNTED_ELIMINATE_HUNTER","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"HuntedEliminateGrunt","#SCORE_EVENT_HUNTED_GRUNT_KILLED","#SCORE_EVENT_HUNTED_GRUNT_KILLED","POINTVALUE_HUNTED_ELIMINATE_GRUNT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"HuntedEliminateSquad","#SCORE_EVENT_HUNTED_SQUAD_KILLED","#SCORE_EVENT_HUNTED_SQUAD_KILLED","POINTVALUE_HUNTED_ELIMINATE_SQUAD","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_multiple","",0 +"HuntedAquireAsset","#SCORE_EVENT_HUNTED_AQUIRE_ASSET","#SCORE_EVENT_HUNTED_AQUIRE_ASSET","POINTVALUE_HUNTED_AQUIRE_ASSET","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"HuntedSecureAsset","#SCORE_EVENT_HUNTED_AQUIRE_SECURED","#SCORE_EVENT_HUNTED_AQUIRE_SECURED","POINTVALUE_HUNTED_SECURE_ASSET","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"HuntedExtractAsset","#SCORE_EVENT_HUNTED_AQUIRE_EXTRACTED","#SCORE_EVENT_HUNTED_AQUIRE_EXTRACTED","POINTVALUE_HUNTED_EXTRACT_ASSET","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"HuntedSurvival","#SCORE_EVENT_HUNTED_OBJECTIVE_SURVIVAL","#SCORE_EVENT_HUNTED_OBJECTIVE_SURVIVAL","POINTVALUE_HUNTED_OBJECTIVE_SURVIVAL","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"HuntedMissionSurvival","#SCORE_EVENT_HUNTED_MISSION_SURVIVAL","#SCORE_EVENT_HUNTED_MISSION_SURVIVAL","POINTVALUE_HUNTED_MISSION_SURVIVAL","","DEFENSE","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"MFDMarked","#SCORE_EVENT_MARKED_FOR_DEATH_TARGET","#SCORE_EVENT_MARKED_FOR_DEATH_TARGET","POINTVALUE_MARKED_TARGET","","","0","1","0","0","","CALLINGCARD MEDAL","rui/medals/titanfall","",0 +"BombPlantRaid","#SCORE_EVENT_BOMB_PLANT_POINTS","#SCORE_EVENT_BOMB_PLANT_POINTS","GAMEMODE_RAID_SCORE_PLANT","","ASSAULT","0","0","0","0","","MEDAL GAMEMODE","rui/medals/bomb","",0 +"ATCOOPAirDroneKilled","#SCORE_EVENT_AT_AIR_DRONE_KILLED","#SCORE_EVENT_AT_AIR_DRONE_KILLED","ATCOOP_SCORE_AIR_DRONE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPBossKilled","#SCORE_EVENT_AT_BOSS_KILLED","#SCORE_EVENT_AT_BOSS_KILLED","ATCOOP_SCORE_BOSS","","ASSAULT","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPBountySurvived","#SCORE_EVENT_AT_BOUNTY_SURVIVED","#SCORE_EVENT_AT_BOUNTY_SURVIVED","ATCOOP_SCORE_BOUNTY_SURVIVAL","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/victory","",0 +"ATCOOPGruntKilled","#SCORE_EVENT_AT_GRUNT_KILLED","#SCORE_EVENT_AT_GRUNT_KILLED","ATCOOP_SCORE_GRUNT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"ATCOOPMegaTurretKilled","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","ATCOOP_SCORE_MEGATURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPSentryTurretKilled","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","ATCOOP_SCORE_SENTRYTURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPPilotKilled","#SCORE_EVENT_AT_PILOT_KILLED","#SCORE_EVENT_AT_PILOT_KILLED","ATCOOP_SCORE_PILOT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"ATCOOPProwlerKilled","#SCORE_EVENT_AT_PROWLER_KILLED","#SCORE_EVENT_AT_PROWLER_KILLED","ATCOOP_SCORE_PROWLER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"ATCOOPSpectreKilled","#SCORE_EVENT_AT_SPECTRE_KILLED","#SCORE_EVENT_AT_SPECTRE_KILLED","ATCOOP_SCORE_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPStalkerKilled","#SCORE_EVENT_AT_STALKER_KILLED","#SCORE_EVENT_AT_STALKER_KILLED","ATCOOP_SCORE_STALKER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPSuperSpectreKilled","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","ATCOOP_SCORE_SUPER_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPTitanDoomed","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","ATCOOP_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPTitanKilled","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","ATCOOP_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"ATCOOPCashedBonus","#SCORE_EVENT_AT_CASHED_BONUS","#SCORE_EVENT_AT_CASHED_BONUS","ATCOOP_SCORE_BONUS","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"ATCOOPBonusStolen","#SCORE_EVENT_AT_BONUS_STOLEN","#SCORE_EVENT_AT_BONUS_STOLEN","ATCOOP_SCORE_BONUS_STOLEN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXAirDroneKilled","#SCORE_EVENT_AT_AIR_DRONE_KILLED","#SCORE_EVENT_AT_AIR_DRONE_KILLED","PVE_SANDBOX_SCORE_AIR_DRONE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXBossKilled","#SCORE_EVENT_AT_BOSS_KILLED","#SCORE_EVENT_AT_BOSS_KILLED","PVE_SANDBOX_SCORE_BOSS","","ASSAULT","0","0","0","0","","CALLINGCARD MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXBountySurvived","#SCORE_EVENT_AT_BOUNTY_SURVIVED","#SCORE_EVENT_AT_BOUNTY_SURVIVED","PVE_SANDBOX_SCORE_BOUNTY_SURVIVAL","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/victory","",0 +"PVESANDBOXGruntKilled","#SCORE_EVENT_AT_GRUNT_KILLED","#SCORE_EVENT_AT_GRUNT_KILLED","PVE_SANDBOX_SCORE_GRUNT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"PVESANDBOXMegaTurretKilled","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","#SCORE_EVENT_AT_MEGA_TURRET_KILLED","PVE_SANDBOX_SCORE_MEGATURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXSentryTurretKilled","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","#SCORE_EVENT_AT_SENTRY_TURRET_KILLED","PVE_SANDBOX_SCORE_SENTRYTURRET","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXPilotKilled","#SCORE_EVENT_AT_PILOT_KILLED","#SCORE_EVENT_AT_PILOT_KILLED","PVE_SANDBOX_SCORE_PILOT","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"PVESANDBOXProwlerKilled","#SCORE_EVENT_AT_PROWLER_KILLED","#SCORE_EVENT_AT_PROWLER_KILLED","PVE_SANDBOX_SCORE_PROWLER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"PVESANDBOXSpectreKilled","#SCORE_EVENT_AT_SPECTRE_KILLED","#SCORE_EVENT_AT_SPECTRE_KILLED","PVE_SANDBOX_SCORE_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXStalkerKilled","#SCORE_EVENT_AT_STALKER_KILLED","#SCORE_EVENT_AT_STALKER_KILLED","PVE_SANDBOX_SCORE_STALKER","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXSuperSpectreKilled","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","PVE_SANDBOX_SCORE_SUPER_SPECTRE","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXTitanDoomed","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","PVE_SANDBOX_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXTitanKilled","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","PVE_SANDBOX_SCORE_TITAN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"PVESANDBOXCashedBonus","#SCORE_EVENT_AT_CASHED_BONUS","#SCORE_EVENT_AT_CASHED_BONUS","PVE_SANDBOX_SCORE_BONUS","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"PVESANDBOXBonusStolen","#SCORE_EVENT_AT_BONUS_STOLEN","#SCORE_EVENT_AT_BONUS_STOLEN","PVE_SANDBOX_SCORE_BONUS_STOLEN","","ASSAULT","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDAirDroneKilled","#SCORE_EVENT_AT_AIR_DRONE_KILLED","#SCORE_EVENT_AT_AIR_DRONE_KILLED","FD_SCORE_AIR_DRONE","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDGruntKilled","#SCORE_EVENT_AT_GRUNT_KILLED","#SCORE_EVENT_AT_GRUNT_KILLED","FD_SCORE_GRUNT","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill","",0 +"FDSpectreKilled","#SCORE_EVENT_AT_SPECTRE_KILLED","#SCORE_EVENT_AT_SPECTRE_KILLED","FD_SCORE_SPECTRE","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDStalkerKilled","#SCORE_EVENT_AT_STALKER_KILLED","#SCORE_EVENT_AT_STALKER_KILLED","FD_SCORE_STALKER","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDSuperSpectreKilled","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","#SCORE_EVENT_AT_SUPER_SPECTRE_KILLED","FD_SCORE_SUPER_SPECTRE","","","0","0","0","0","","ATTRITION MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDTitanKilled","#SCORE_EVENT_AT_TITAN_DOOMED","#SCORE_EVENT_AT_TITAN_DOOMED","FD_SCORE_TITAN","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDEnemiesKilled","#SCORE_EVENT_FD_ENEMIES_KILLED","#SCORE_EVENT_FD_ENEMIES_KILLED","FD_SCORE_ENEMIES","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill","",0 +"FDWaveMVP","#SCORE_EVENT_FD_WAVE_MVP","#SCORE_EVENT_FD_WAVE_MVP","FD_SCORE_MVP","","","0","0","0","0","","MEDAL_FORCED GAMEMODE CALLINGCARD","rui/medals/mvp","",0 +"FDTeamFinalWave","#SCORE_EVENT_FD_TEAM_FINAL_WAVE","#SCORE_EVENT_FD_TEAM_FINAL_WAVE","FD_SCORE_TEAM_FINAL_WAVE","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"FDTeamWave","#SCORE_EVENT_FD_TEAM_WAVE","#SCORE_EVENT_FD_TEAM_WAVE","FD_SCORE_TEAM_WAVE","","","0","0","0","0","","MEDAL_FORCED GAMEMODE","rui/medals/harvester_protect","",0 +"FDTeamFlawlessWave","#SCORE_EVENT_FD_TEAM_FLAWLESS_WAVE","#SCORE_EVENT_FD_TEAM_FLAWLESS_WAVE","FD_SCORE_TEAM_FLAWLESS_WAVE","","","0","0","0","0","","MEDAL_FORCED GAMEMODE","rui/medals/shielded_harvester","",0 +"PasTitanHunter","#GEAR_AT_HUNTER_KIT","#GEAR_AT_HUNTER_KIT","","","","0","0","0","0","KILL","MEDAL","rui/medals/kill_robot","",0 +"Execution","#SCORE_EVENT_EXECUTION","#SCORE_EVENT_EXECUTION","0","BURN_METER_LARGE_POINT_VALUE","","0","0","0","0","","MEDAL","rui/medals/kill","",0 +"FDRepairTurret","#SCORE_EVENT_REPAIR_TURRET","#SCORE_EVENT_REPAIR_TURRET","FD_SCORE_REPAIR_TURRET","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"FDDidntDie","#SCORE_EVENT_DIDNT_DIE","#SCORE_EVENT_DIDNT_DIE","FD_SCORE_DIDNT_DIE","","","0","0","0","0","","MEDAL_FORCED GAMEMODE","rui/medals/heal","",0 +"FDShieldHarvester","#SCORE_EVENT_FD_SHIELD_HARVESTER","#SCORE_EVENT_FD_SHIELD_HARVESTER","FD_SCORE_SHIELD_HARVESTER","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/shielded_harvester","",0 +"FDSonarPulse","#SCORE_EVENT_FD_SONAR_PULSE","#SCORE_EVENT_FD_SONAR_PULSE","FD_SCORE_SONAR_PULSE","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"FDArcTrapTriggered","#SCORE_EVENT_FD_ARC_TRAP_TRIGGERED","#SCORE_EVENT_FD_ARC_TRAP_TRIGGERED","FD_SCORE_ARC_TRAP_TRIGGERED","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDTetherTriggered","#SCORE_EVENT_FD_TETHER_TRAP_TRIGGERED","#SCORE_EVENT_FD_TETHER_TRAP_TRIGGERED","FD_SCORE_TETHER_TRAP_TRIGGERED","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/kill_robot","",0 +"FDArcWave","#SCORE_EVENT_FD_ARC_WAVE","#SCORE_EVENT_FD_ARC_WAVE","FD_SCORE_ARC_WAVE","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/medal_prototype","",0 +"FDTeamHeal","#SCORE_EVENT_FD_TEAM_HEAL","#SCORE_EVENT_FD_TEAM_HEAL","FD_SCORE_TEAM_HEAL","","","0","0","0","0","","MEDAL GAMEMODE","rui/medals/heal","",0 +"FDDamageBonus","#SCORE_EVENT_FD_DAMAGE_BONUS","#SCORE_EVENT_FD_DAMAGE_BONUS","FD_SCORE_DAMAGE_BONUS","","","0","0","0","0","","MEDAL_FORCED GAMEMODE SHOW_SCORE","rui/medals/medal_prototype","",0 +"FDHealingBonus","#SCORE_EVENT_FD_HEALING_BONUS","#SCORE_EVENT_FD_HEALING_BONUS","FD_SCORE_HEALING_BONUS","","","0","0","0","0","","MEDAL_FORCED GAMEMODE SHOW_SCORE","rui/medals/heal","",0 +"FDSupportBonus","#SCORE_EVENT_FD_SUPPORT_BONUS","#SCORE_EVENT_FD_SUPPORT_BONUS","FD_SCORE_SUPPORT_BONUS","","","0","0","0","0","","MEDAL_FORCED GAMEMODE SHOW_SCORE","rui/medals/kill_robot","",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/sp_levels.csv b/Northstar.CustomServers/mod/scripts/datatable/sp_levels.csv new file mode 100644 index 00000000..f373d4ed --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/sp_levels.csv @@ -0,0 +1,17 @@ +levelNum,level,startPoint,levelId,mainEntry,showLions,title,desc,missionSelectImage +0,"sp_training","Pod Intro","sp_training",1,1,"#SP_TRAINING_CAMPAIGN_NAME","#SP_TRAINING_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image1" +0,"sp_training","Gauntlet Mode","training_gauntlet_mode",0,1,"","","" +1,"sp_crashsite","LevelStart","sp_crashsite",1,1,"#SP_CRASHSITE_CAMPAIGN_NAME","#SP_CRASHSITE_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image2" +2,"sp_sewers1","Channel Mortar Run","sp_sewers1",1,1,"#SP_SEWERS1_CAMPAIGN_NAME","#SP_SEWERS1_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image3" +3,"sp_boomtown_start","Intro","sp_boomtown_start",1,1,"#SP_BOOMTOWN_START_CAMPAIGN_NAME","#SP_BOOMTOWN_START_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image4" +3,"sp_boomtown","Start","sp_boomtown",0,1,"","","" +3,"sp_boomtown_end","Intro Caves","sp_boomtown_end",0,1,"","","" +4,"sp_hub_timeshift","LECTURE HALLS","sp_hub_timeshift",1,0,"#SP_HUB_TIMESHIFT_CAMPAIGN_NAME","#SP_HUB_TIMESHIFT_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image5" +4,"sp_timeshift_spoke02","Timeshift Device","sp_timeshift_spoke02",0,1,"","","" +4,"sp_hub_timeshift","PRISTINE CAMPUS","timeshift_pt3",0,1,"","","" +5,"sp_beacon","Level Start","sp_beacon",1,0,"#SP_BEACON_CAMPAIGN_NAME","#SP_BEACON_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image6" +5,"sp_beacon_spoke0","Level Start","sp_beacon_spoke0",0,1,"","","" +5,"sp_beacon","Spoke_0_Complete","beacon_pt3",0,1,"","","" +6,"sp_tday","Intro","sp_tday",1,1,"#SP_TDAY_CAMPAIGN_NAME","#SP_TDAY_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image7" +7,"sp_s2s","Level Start","sp_s2s",1,1,"#SP_S2S_CAMPAIGN_NAME","#SP_S2S_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image8" +8,"sp_skyway_v1","Level Start","sp_skyway_v1",1,1,"#SP_SKYWAY_V1_CAMPAIGN_NAME","#SP_SKYWAY_V1_CAMPAIGN_DESC_MILITIA","rui/menu/level_select/level_image9" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/spectre_chatter_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/spectre_chatter_mp.csv new file mode 100644 index 00000000..4194a938 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/spectre_chatter_mp.csv @@ -0,0 +1,8 @@ +conversationname,priority,debounce +"diag_imc_spectre_gs_spotclosetitancall_01",200,20.000000 +"diag_imc_spectre_gs_engagepilotenemy_01_1",200,20.000000 +"diag_imc_spectre_gs_grenadeout_01_1",200,20.000000 +"diag_imc_spectre_gs_killenemypilot_01_1",200,20.000000 +"diag_imc_spectre_gs_gruntkillstitan_02_1",200,20.000000 +"diag_imc_spectre_gs_squaddeplete_01_1",200,20.000000 +"diag_imc_spectre_gs_allygrundown_05_1",200,20.000000 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/spotlight_images.csv b/Northstar.CustomServers/mod/scripts/datatable/spotlight_images.csv new file mode 100644 index 00000000..1e6946c1 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/spotlight_images.csv @@ -0,0 +1,30 @@ +image +"rui/menu/main_menu/spotlight_01" +"rui/menu/main_menu/spotlight_02" +"rui/menu/main_menu/spotlight_03" +"rui/menu/main_menu/spotlight_04" +"rui/menu/main_menu/spotlight_05" +"rui/menu/main_menu/spotlight_06" +"rui/menu/main_menu/spotlight_07" +"rui/menu/main_menu/spotlight_08" +"rui/menu/main_menu/spotlight_09" +"rui/menu/main_menu/spotlight_10" +"rui/menu/main_menu/spotlight_11" +"rui/menu/main_menu/spotlight_12" +"rui/menu/main_menu/spotlight_13" +"rui/menu/main_menu/spotlight_14" +"rui/menu/main_menu/spotlight_15" +"rui/menu/main_menu/spotlight_16" +"rui/menu/main_menu/spotlight_17" +"rui/menu/main_menu/spotlight_18" +"rui/menu/main_menu/spotlight_19" +"rui/menu/main_menu/spotlight_20" +"rui/menu/main_menu/spotlight_21" +"rui/menu/main_menu/spotlight_22" +"rui/menu/main_menu/spotlight_23" +"rui/menu/main_menu/spotlight_24" +"rui/menu/main_menu/spotlight_25" +"rui/menu/main_menu/spotlight_26" +"rui/menu/main_menu/spotlight_27" +"rui/menu/main_menu/spotlight_28" +"rui/menu/main_menu/spotlight_29" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/startpoints.csv b/Northstar.CustomServers/mod/scripts/datatable/startpoints.csv new file mode 100644 index 00000000..a171cd8a --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/startpoints.csv @@ -0,0 +1,313 @@ +level,startpoint,loadScreenIndex,hasDetente,spLog,spLogTitle,isLeft +"sp_grunt_arena","Pilot vs 3 Grunts (Trial)",0,0,"","",0 +"sp_grunt_arena","Pilot and Leeched Spectre vs Grunts (Trial)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Spectre (Trial)",0,0,"","",0 +"sp_grunt_arena","Arc Grenades vs Spectres and Grunts (Trial)",0,0,"","",0 +"sp_grunt_arena","Learn to use Shield Drone (Trial)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Grunts (Small Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Grunts (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Shield Drone vs Turrets (Trial)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Captains (Trial)",0,0,"","",0 +"sp_grunt_arena","Use Turrets vs AI (Trial)",0,0,"","",0 +"sp_grunt_arena","Turret Maze Part 1 (Trial)",0,0,"","",0 +"sp_grunt_arena","Turret Maze Part 2 (Trial)",0,0,"","",0 +"sp_grunt_arena","Learn to use Suicide Spectres (Trial)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Mixed AI (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot and Titan vs Many AI (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Titan Wingman Arena (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Titan vs Many AI (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Super Spectre (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Super Spectres (Small Arena)",0,0,"","",0 +"sp_grunt_arena","Titan vs Super Spectres (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Spectres (Big Arena)",0,0,"","",0 +"sp_grunt_arena","Pilot vs Stalker progressive (Big Arena)",0,0,"","",0 +"sp_grunt_arena","The End!",0,0,"","",0 +"sp_ab_gym","gym_windmills",0,0,"","",0 +"sp_ab_gym","gym_bongo_board",0,0,"","",0 +"sp_ab_testfire2","room1",0,0,"","",0 +"sp_ab_testfire2","room2",0,0,"","",0 +"sp_ola_hub","topside",0,0,"","",0 +"sp_ola_hub","hub_intro",0,0,"","",0 +"sp_ola_hub","engine1_connect",0,0,"","",0 +"sp_ola_spoke1","sp_ola_spoke1",0,0,"","",0 +"sp_ola_spoke1","ola_spoke1_cleanroom",0,0,"","",0 +"sp_ola_spoke1","ola_spoke1_powerrod_factory",0,0,"","",0 +"sp_ola_spoke1","ola_spoke1_canyon",0,0,"","",0 +"sp_ola_sewers","ola_sewers_drain",0,0,"","",0 +"sp_ola_sewers","ola_sewers_sludge_test1",0,0,"","",0 +"sp_ola_sewers","ola_sewers_sludge_test2",0,0,"","",0 +"sp_ola_sewers","ola_sewers_sludge_test3",0,0,"","",0 +"sp_ola_sewers","ola_sewers_sludge_test4",0,0,"","",0 +"sp_ola_sewers","ola_sewers_sludge_bt_test1",0,0,"","",0 +"sp_ola_canyon_test","ola_canyontest1",0,0,"","",0 +"sp_ola_canyon_test","ola_canyontest2",0,0,"","",0 +"sp_ola_canyon_test","ola_canyontest3",0,0,"","",0 +"sp_ola_canyon_test","ola_canyontest4",0,0,"","",0 +"sp_ola_canyon_test","dish_array",0,0,"","",0 +"sp_ola_canyon_test","ledge_run",0,0,"","",0 +"sp_ab_canyon_prowler","prowler_canyon_1",0,0,"","",0 +"sp_ab_canyon_prowler","prowler_canyon_2",0,0,"","",0 +"sp_ab_canyon_prowler","prowler_canyon_3",0,0,"","",0 +"sp_hub_timeshift","LECTURE HALLS",0,1,"SP_MISSION_LOG_TIMESHIFT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_hub_timeshift","OVERGROWN CAMPUS",1,0,"SP_MISSION_LOG_TIMESHIFT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_hub_timeshift","Corpse Search",1,0,"SP_MISSION_LOG_TIMESHIFT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_hub_timeshift","BT EXPLAINS IT ALL",1,0,"SP_MISSION_LOG_TIMESHIFT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_hub_timeshift","Zipline",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_hub_timeshift","Security",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_hub_timeshift","Skybridge",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_hub_timeshift","PRISTINE CAMPUS",2,1,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_hub_timeshift","Hub Fight",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_hub_timeshift","Extended Bridge",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_hub_timeshift","REACTOR MELTDOWN",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_hub_timeshift","Core Scan",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_hub_timeshift","Level End",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG1","MENU_SP_LOG_TITLE_TIMESHIFT2",1 +"sp_timeshift_spoke02","Timeshift Device",1,1,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","WILDLIFE RESEARCH",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","First Timeshift Fight",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","Elevator Fight",1,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","HUMAN RESEARCH",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","Sphere Room",2,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",1 +"sp_timeshift_spoke02","Human Room",3,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",0 +"sp_timeshift_spoke02","CAMPUS RETURN",3,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",0 +"sp_timeshift_spoke02","Fan Drop",3,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",0 +"sp_timeshift_spoke02","Fan Drop End",3,0,"SP_MISSION_LOG_TIMESHIFT_SPLOG0","MENU_SP_LOG_TITLE_TIMESHIFT1",0 +"sp_beacon","Level Start",1,1,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon","Control Room",1,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke_0_Complete",2,1,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Power Relays Online",1,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Fastball to Spoke 1",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke 1 Start",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke 1 First Combat",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke 1 Second Combat",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke 1 Pillar Room",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Double Crane Puzzle",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Second Beacon",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Spoke 1 Arena",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Wallrun Panels",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Back at HUB",3,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Climb Dish",1,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon","Final Battle",4,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon","Send Signal",4,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon","Beacon Ending",4,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon_spoke0","Level Start",0,1,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon_spoke0","First Fight",1,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon_spoke0","Get Arc Tool",1,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon_spoke0","Got Arc Tool",2,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon_spoke0","Horizontal Fan",2,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon_spoke0","Horizontal Fan Complete",2,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon_spoke0","Fan Wallrun",2,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",0 +"sp_beacon_spoke2","Level Start",0,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon_spoke2","Fastball",0,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_beacon_spoke2","Loading Dock",0,0,"#SP_MISSION_LOG_BEACON","MENU_SP_OBJECTIVES_TITLE",1 +"sp_boomtown_ride","1 - Level Start",0,0,"","",0 +"sp_boomtown_ride","2 - Assembly Line",0,0,"","",0 +"sp_boomtown_ride","3 - First Fight",0,0,"","",0 +"sp_boomtown_ride","4 - First Ride",0,0,"","",0 +"sp_boomtown_ride","5 - Second Ride",0,0,"","",0 +"sp_ab_moving_geo_combat_1","1 - Moving Cover",0,0,"","",0 +"sp_ab_moving_geo_combat_1","2 - Moving Cover with High Ceiling",0,0,"","",0 +"sp_ab_moving_geo_combat_1","3 - Rotating Cover (CQC)",0,0,"","",0 +"sp_ab_moving_geo_combat_1","4 - Rotating Cover - Only Grunts",0,0,"","",0 +"sp_ab_moving_geo_combat_1","5 - Rotating Cover - Stationary Reaper",0,0,"","",0 +"sp_ab_moving_geo_combat_1","6 - Rotating Cover - Mobile Reaper",0,0,"","",0 +"sp_ab_moving_geo_combat_1","7 - Building Assembly Battle",0,0,"","",0 +"sp_training","Pod Intro",1,1,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Basic Movement",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Zen Garden",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Firing Range",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Gauntlet",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Gauntlet Challenge",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Titanfall",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Pod Outro",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Meet OG",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Gauntlet Mode",1,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_FIRSTRUN",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_WIP",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_01",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_02",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_03",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_04",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_05",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_06",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_07",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_08",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","DEV_GHOSTREC_GAUNTLET_CHAL_09",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Pod Intro DEV",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_training","Pod Outro DEV",0,0,"#SP_MISSION_LOG_TRAINING","MENU_SP_OBJECTIVES_TITLE",0 +"sp_wild","1 - Spoke 1: Escape Pod",0,0,"","",0 +"sp_wild","2 - Spoke 1: Basic Movement",0,0,"","",0 +"sp_wild","placeholder 3 - Spoke 1: Spectre Forest",0,0,"","",0 +"sp_wild","placeholder 4 - Spoke 1: Friend or Foe?",0,0,"","",0 +"sp_wild","placeholder 5 - Spoke 1: Grand Reveal",0,0,"","",0 +"sp_wild","placeholder 6 - Spoke 1: Checkpoint Zulu",0,0,"","",0 +"sp_wild","placeholder 7 - Spoke 1: Pistol Puzzle",0,0,"","",0 +"sp_wild","placeholder 8 - Spoke 1: Intruder",0,0,"","",0 +"sp_wild","placeholder 9 - HUB p-1: Gravity",0,0,"","",0 +"sp_wild","placeholder 10 - HUB p-1: Flirtation",0,0,"","",0 +"sp_wild","placeholder 11 - HUB p-1: Chase",0,0,"","",0 +"sp_wild","placeholder 12 - Spoke 2: Gorilla in the Mist",0,0,"","",0 +"sp_wild","13 - Spoke 2: Upgrades",0,0,"","",0 +"sp_wild","placeholder 14 - Spoke 2: A whole new world",0,0,"","",0 +"sp_wild","placeholder 15 - HUB p-2: Making Friends",0,0,"","",0 +"sp_wild","placeholder 16 - HUB p-2: Influencing People",0,0,"","",0 +"sp_wild","placeholder 17 - Spoke 3: Survivors",0,0,"","",0 +"sp_wild","placeholder 18 - Spoke 3: Prisoners",0,0,"","",0 +"sp_wild","placeholder 19 - HUB p-3: Snatch and Grab",0,0,"","",0 +"sp_wild","placeholder 20 - HUB p-3: Hero to Zero",0,0,"","",0 +"sp_wild","placeholder 21 - Spoke 4: Outpost Cherokee",0,0,"","",0 +"sp_wild","placeholder 22 - Spoke 4: Grenades",0,0,"","",0 +"sp_wild","placeholder 23 - Spoke 4: QRF",0,0,"","",0 +"sp_wild","placeholder 24 - Spoke 4: Those Eyes",0,0,"","",0 +"sp_wild","placeholder 25 - Spoke 5: Tree of Life",0,0,"","",0 +"sp_wild","26 - Spoke 5: Gift From the Gods",0,0,"","",0 +"sp_wild","placeholder 27 - HUB p-4: Energizer",0,0,"","",0 +"sp_wild","placeholder 28 - HUB p-4: One Man Army",0,0,"","",0 +"sp_wild","placeholder 29 - Spoke 5: p-2: Sleeping Beauty",0,0,"","",0 +"sp_wild","placeholder 30 - Spoke 5: p-2: Prowler Den",0,0,"","",0 +"sp_wild","placeholder 31 - Spoke 5: p-2: Common Ground",0,0,"","",0 +"sp_wild","placeholder 32 - Spoke 5: p-2: Dharma Hatch",0,0,"","",0 +"sp_crashsite","LevelStart",1,1,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","BT_Intro",1,0,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","Blisk_Intro",1,0,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","FamilyPhoto",1,0,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","Waking_Up",2,0,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","Field_Promotion",2,0,"SP_MISSION_LOG_WILDS_SPLOG0","MENU_SP_LOG_TITLE_WILDS",1 +"sp_crashsite","Grave",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery2_Path",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery2_Combat",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery2_Ship",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery3_Path",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery3_Combat",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","Battery3_Ship",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_crashsite","PilotLink",2,0,"SP_MISSION_LOG_WILDS_ALT","MENU_SP_OBJECTIVES_TITLE",0 +"sp_ship_01","S2S_GOBLIN",0,0,"","",0 +"sp_ship_01","Goblin Deploy",0,0,"","",0 +"sp_ship_01","Goblin Deploy Zip",0,0,"","",0 +"sp_ship_01","S2S_FASTBALL",0,0,"","",0 +"sp_ship_01","S2S_REDEYE",0,0,"","",0 +"sp_ship_01","S2S_SENTINEL",0,0,"","",0 +"sp_ship_01","Model Test [ solid ]",0,0,"","",0 +"sp_ship_01","Model Test [ notsolid ]",0,0,"","",0 +"sp_ship_01","Bug: Skycam Parent",0,0,"","",0 +"sp_ship_01","Bug: Skycam Move/Rotate",0,0,"","",0 +"sp_ship_01","Bug: Ents outside Bounds",0,0,"","",0 +"sp_ship_01","S2S_COMBAT1-p1",0,0,"","",0 +"sp_ship_01","S2S_COMBAT1-p2",0,0,"","",0 +"sp_ship_01","S2S_COMBAT1-p3",0,0,"","",0 +"sp_ship_01","S2S_COMBAT1-p4",0,0,"","",0 +"sp_ship_03","hull combat p1",0,0,"","",0 +"sp_ship_04","hull combat p1",0,0,"","",0 +"sp_ship_05","hull combat p1",0,0,"","",0 +"sp_s2s","Level Start",1,1,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Intro",1,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Gibraltar",1,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Boss Intro",1,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Widow Fall",1,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Barker Ship",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","FastBall 1",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Intro",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Drone Room",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Guns",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Widow Jump",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Hangar",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Breach",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Bridge",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Reunite with BT",2,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Malta Deck",3,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","BT Tackle",3,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Boss Fight",3,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Viper Dead",3,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",0 +"sp_s2s","Life Boats",4,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",1 +"sp_s2s","Core Room",4,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",1 +"sp_s2s","OLA Crash",4,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",1 +"sp_s2s","--------------",4,0,"SP_MISSION_LOG_S2S","MENU_SP_OBJECTIVES_TITLE",1 +"sp_s2s","TestBed",1,0,"","",0 +"sp_s2s","Dropship Combat Test",1,0,"","",0 +"sp_s2s","LightEdit Connect",1,0,"","",0 +"sp_s2s","TRAILER bridge",1,0,"","",0 +"sp_scrapyard_test","Arena 1",0,0,"","",0 +"sp_sewers1","Channel Mortar Run",1,1,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_sewers1","Sewer Split",2,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",0 +"sp_sewers1","Sludge Falls",3,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_sewers1","Corkscrew Room",4,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",0 +"sp_sewers1","Pipe Room Climb",5,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_sewers1","Sewer Arena",6,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_sewers1","Sewer Arena Defend",6,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_sewers1","Kane Arena",7,0,"SP_MISSION_LOG_SEWERS","MENU_SP_OBJECTIVES_TITLE",1 +"sp_davis_sewer_battle","Sneaky Section",0,0,"","",0 +"sp_davis_sewer_battle","Combat Arena",0,0,"","",0 +"sp_davis_sewer_battle","Cylinder Tick Tunnels",0,0,"","",0 +"sp_ab_titan_arena","TvT Linear w 1.5 Boss Titans",0,0,"","",0 +"sp_ab_titan_arena","TvT Arena",0,0,"","",0 +"sp_ab_titan_arena","1v1 Arena A",0,0,"","",0 +"sp_ab_titan_arena","1v1 Arena B",0,0,"","",0 +"sp_ab_titan_arena","1v1 Arena C",0,0,"","",0 +"sp_ab_titan_arena","1v1 Arena D",0,0,"","",0 +"sp_boomtown_townboot","Town Boot",0,0,"","",0 +"sp_boomtown_townboot","Town Delivery",0,0,"","",0 +"sp_boomtown_townboot","Spotlight",0,0,"","",0 +"sp_ab_wilds_combat_test","Battery2",0,0,"","",0 +"sp_ab_wilds_combat_test","Battery3",0,0,"","",0 +"sp_skyway_v1","Level Start",0,1,"","",0 +"sp_skyway_v1","Torture Room B",1,0,"","",0 +"sp_skyway_v1","Smart Pistol Run",1,0,"","",0 +"sp_skyway_v1","Bridge Fight",2,0,"","",0 +"sp_skyway_v1","BT Reunion",3,0,"","",0 +"sp_skyway_v1","Titan Hill",3,0,"","",0 +"sp_skyway_v1","Titan Smash Hallway",3,0,"","",0 +"sp_skyway_v1","Sculptor Climb",3,0,"","",0 +"sp_skyway_v1","Targeting Room",4,0,"","",0 +"sp_skyway_v1","Injector Room",4,0,"","",0 +"sp_skyway_v1","Blisk's Farewell",4,0,"","",0 +"sp_skyway_v1","BT Sacrifice",4,0,"","",0 +"sp_skyway_v1","Rising World Run",5,0,"","",0 +"sp_skyway_v1","Rising World Jump",5,0,"","",0 +"sp_skyway_v1","Exploding Planet",5,0,"","",0 +"sp_skyway_v1","Harmony",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","--- CREDITS ---",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","sarah intro",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","walk",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","hug",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","cheer",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor jack cooper",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor BT / OG",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor blisk",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor sarah",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor bosses",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor marder",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actors 6-4",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","actor barker",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","new BT",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","board ship",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_skyway_v1","final image",5,0,"SP_MISSION_LOG_SKYWAY_ALT","MENU_SP_OBJECTIVES_TITLE",1 +"sp_template","Level Start",0,0,"","",0 +"sp_template","Big Fight",0,0,"","",0 +"sp_template","Finale",0,0,"","",0 +"sp_tday","Intro",1,1,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",1 +"sp_tday","Wall Bombardment",1,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",1 +"sp_tday","Militia Big Charge",1,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",1 +"sp_tday","Underground Fuel Storage",2,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",1 +"sp_tday","Elevator",2,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",1 +"sp_tday","VTOL",3,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",0 +"sp_tday","Fire on the Runway",4,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",0 +"sp_tday","OLA Launch",4,0,"SP_MISSION_LOG_TDAY","MENU_SP_OBJECTIVES_TITLE",0 +"sp_boomtown_start","Intro",0,1,"SP_MISSION_LOG_BOOMTOWN_1","MENU_SP_OBJECTIVES_TITLE",0 +"sp_boomtown_start","Prop House",1,0,"SP_MISSION_LOG_BOOMTOWN_1","MENU_SP_OBJECTIVES_TITLE",1 +"sp_boomtown_start","Narrow Hallway",1,0,"SP_MISSION_LOG_BOOMTOWN_1","MENU_SP_OBJECTIVES_TITLE",1 +"sp_boomtown_start","Titan Arena",1,0,"SP_MISSION_LOG_BOOMTOWN_1","MENU_SP_OBJECTIVES_TITLE",1 +"sp_boomtown_start","Loading Dock",1,0,"SP_MISSION_LOG_BOOMTOWN_1","MENU_SP_OBJECTIVES_TITLE",1 +"sp_boomtown","Start",0,1,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Start",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Dirt",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Wallrun",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Furniture",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Walls",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Assembly_Highway",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","Town_Climb_Entry",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown","ReaperTown",2,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG0","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown_end","Intro Caves",0,1,"SP_MISSION_LOG_BOOMTOWN_SPLOG1","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown_end","Prowler Towers",0,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG1","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown_end","Above The Dome",1,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG1","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown_end","Pre Ash Fight",2,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG1","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"sp_boomtown_end","Ash Fight",3,0,"SP_MISSION_LOG_BOOMTOWN_SPLOG1","MENU_SP_LOG_TITLE_BOOMTOWN",1 +"eof","eof",0,0,"","",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_abilities.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_abilities.csv new file mode 100644 index 00000000..46164792 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_abilities.csv @@ -0,0 +1,36 @@ +itemRef,type,damageSource,hidden +"mp_titancore_flame_wave","TITAN_CORE_ABILITY",1,0 +"mp_titancore_flight_core","TITAN_CORE_ABILITY",0,0 +"mp_titancore_laser_cannon","TITAN_CORE_ABILITY",1,0 +"mp_titancore_salvo_core","TITAN_CORE_ABILITY",1,0 +"mp_titancore_shift_core","TITAN_CORE_ABILITY",0,0 +"mp_titancore_siege_mode","TITAN_CORE_ABILITY",0,0 +"mp_titancore_amp_core","TITAN_CORE_ABILITY",0,0 +"mp_titancore_dash_core","TITAN_CORE_ABILITY",0,0 +"mp_titanweapon_arc_wave","TITAN_ORDNANCE",1,0 +"mp_titanweapon_dumbfire_rockets","TITAN_ORDNANCE",1,0 +"mp_titanweapon_flame_wall","TITAN_ORDNANCE",1,0 +"mp_titanweapon_homing_rockets","TITAN_ORDNANCE",1,0 +"mp_titanweapon_laser_lite","TITAN_ORDNANCE",1,0 +"mp_titanweapon_salvo_rockets","TITAN_ORDNANCE",1,0 +"mp_titanweapon_shoulder_rockets","TITAN_ORDNANCE",1,0 +"mp_titanweapon_tracker_rockets","TITAN_ORDNANCE",1,0 +"mp_titanability_power_shot","TITAN_ORDNANCE",1,0 +"mp_titanability_tether_trap","TITAN_ORDNANCE",0,0 +"mp_titanability_basic_block","TITAN_SPECIAL",0,0 +"mp_titanability_particle_wall","TITAN_SPECIAL",0,0 +"mp_titanweapon_vortex_shield","TITAN_SPECIAL",1,0 +"mp_titanweapon_vortex_shield_ion","TITAN_SPECIAL",1,0 +"mp_titanweapon_heat_shield","TITAN_SPECIAL",1,0 +"mp_titanability_gun_shield","TITAN_SPECIAL",1,0 +"mp_titanability_smoke","TITAN_SPECIAL",0,0 +"mp_titanability_hover","TITAN_ANTIRODEO",0,0 +"mp_titanability_phase_dash","TITAN_ANTIRODEO",0,0 +"mp_titanability_laser_trip","TITAN_ANTIRODEO",0,0 +"mp_titanability_slow_trap","TITAN_ANTIRODEO",0,0 +"mp_titanability_ammo_swap","TITAN_ANTIRODEO",1,0 +"mp_titanability_sonar_pulse","TITAN_ANTIRODEO",1,0 +"mp_titanability_rocketeer_ammo_swap","TITAN_ANTIRODEO",0,0 +"mp_titanweapon_stun_laser","TITAN_SPECIAL",1,0 +"mp_titanability_rearm","TITAN_ANTIRODEO",1,0 +"mp_titancore_upgrade","TITAN_CORE_ABILITY",0,0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_executions.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_executions.csv new file mode 100644 index 00000000..09c4a4d1 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_executions.csv @@ -0,0 +1,26 @@ +ref,setfile,attackerAnim,attackerAnimVsAutoTitan,victimAnim_lt,victimAnim_md,victimAnim_hv,victimAnim_pt_lt,victimAnim_pt_md,victimAnim_pt_hv,attackerAnim_pt_lt,attackerAnim_pt_mt,attackerAnim_pt_ht,sound_1p,sound_3p,camAttach,type,name,description,image,hidden,cost,reqPrime,linkedExecutions +"execution_legion","titan_ogre_minigun","htPRED_MP_Sync_Execution_Attacker","htPRED_MP_Sync_Execution_Attacker","t_MeleeExecuted_By_htPred","t_MeleeExecuted_By_htPred","t_MeleeExecuted_By_htPred","","","","","","","Ogre_1p_Sync_Melee","Ogre_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_LEGION_EXECUTION","#TITAN_EXECUTION_LEGION","#TITAN_EXECUTION_LEGION_DESC","rui/titan_loadout/execution/titan_execution_legion",0,0,0,"" +"execution_legion_prime","titan_ogre_legion_prime","htLegionPrime_MP_Sync_Execution_attacker","htLegionPrime_MP_Sync_Execution_attacker","t_MeleeExecuted_By_htLegionPrime","t_MeleeExecuted_By_htLegionPrime","t_MeleeExecuted_By_htLegionPrime","","","","","","","Ogre_1p_Sync_Melee","Ogre_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_LEGION_EXECUTION","#TITAN_EXECUTION_LEGION_PRIME","#TITAN_EXECUTION_LEGION_PRIME_DESC","rui/titan_loadout/execution/titan_execution_legion_prime",0,0,1,"" +"execution_scorch","titan_ogre_meteor","htThermite_MP_Sync_Execution_Attacker","htThermite_MP_Sync_Execution_Attacker","t_MeleeExecuted_By_htThermite","t_MeleeExecuted_By_htThermite","t_MeleeExecuted_By_htThermite","","","","","","","Ogre_1p_Sync_Melee","Ogre_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_SCORCH_EXECUTION","#TITAN_EXECUTION_SCORCH","#TITAN_EXECUTION_SCORCH_DESC","rui/titan_loadout/execution/titan_execution_scorch",0,0,0,"" +"execution_scorch_prime","titan_ogre_scorch_prime","htScorchPrime_MP_Sync_Execution_attacker","htScorchPrime_MP_Sync_Execution_attacker","t_MeleeExecuted_By_htScorchPrime","t_MeleeExecuted_By_htScorchPrime","t_MeleeExecuted_By_htScorchPrime","","","","","","","Ogre_1p_Sync_Melee","Ogre_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_SCORCH_EXECUTION","#TITAN_EXECUTION_SCORCH_PRIME","#TITAN_EXECUTION_SCORCH_PRIME_DESC","rui/titan_loadout/execution/titan_execution_scorch_prime",0,0,1,"" +"execution_ronin","titan_stryder_leadwall","lt_execution_attacker_sword_01","lt_execution_attacker_sword_01","lt_execution_victim_sword_01","mt_execution_victim_sword_01","ht_execution_victim_sword_01","pt_lt_execution_victim_sword_01","pt_mt_execution_victim_sword_01","pt_ht_execution_victim_sword_01","","","","Stryder_1p_Sync_Melee","Stryder_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_RONIN_EXECUTION","#TITAN_EXECUTION_RONIN","#TITAN_EXECUTION_RONIN_DESC","rui/titan_loadout/execution/titan_execution_ronin",0,0,0,"" +"execution_ronin_prime","titan_stryder_ronin_prime","lt_execution_attacker_sword_02_prime","lt_execution_attacker_sword_02_prime","lt_execution_victim_sword_02","mt_execution_victim_sword_02","ht_execution_victim_sword_02","pt_lt_execution_victim_sword_02","pt_mt_execution_victim_sword_02","pt_ht_execution_victim_sword_02","","","","Stryder_1p_Sync_Melee","Stryder_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_RONIN_EXECUTION","#TITAN_EXECUTION_RONIN_PRIME","#TITAN_EXECUTION_RONIN_PRIME_DESC","rui/titan_loadout/execution/titan_execution_ronin_prime",0,0,1,"" +"execution_ion","titan_atlas_stickybomb","mt_execution_attacker_laser","mt_execution_attacker_laser","lt_execution_victim_laser","mt_execution_victim_laser","ht_execution_victim_laser","pt_execution_victim_laser","pt_execution_victim_laser","pt_execution_victim_laser","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_ION_EXECUTION","#TITAN_EXECUTION_ION","#TITAN_EXECUTION_ION_DESC","rui/titan_loadout/execution/titan_execution_ion",0,0,0,"" +"execution_ion_prime","titan_atlas_ion_prime","mt_execution_attacker_ion_prime","mt_execution_attacker_ion_prime","lt_execution_victim_ion_prime","mt_execution_victim_ion_prime","ht_execution_victim_ion_prime","pt_execution_victim_ion_prime","pt_execution_victim_ion_prime","pt_execution_victim_ion_prime","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_ION_EXECUTION","#TITAN_EXECUTION_ION_PRIME","#TITAN_EXECUTION_ION_PRIME_DESC","rui/titan_loadout/execution/titan_execution_ion_prime",0,0,1,"" +"execution_bt","titan_buddy","bt_synced_titan_execute_flip_takedown_A","bt_synced_titan_execute_flip_takedown_A","titan_synced_bt_execute_flip_takedown_V","titan_synced_bt_execute_flip_takedown_V","titan_synced_bt_execute_flip_takedown_V","","","","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","","","","",1,0,0,"" +"execution_tone","titan_atlas_tracker","mt_execution_attacker_tone","mt_execution_attacker_tone_auto","lt_execution_victim_tone","mt_execution_victim_tone","ht_execution_victim_tone","pt_execution_victim_tone","pt_execution_victim_tone","pt_execution_victim_tone","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_TONE_EXECUTION","#TITAN_EXECUTION_TONE","#TITAN_EXECUTION_TONE_DESC","rui/titan_loadout/execution/titan_execution_tone",0,0,0,"" +"execution_tone_prime","titan_atlas_tone_prime","mt_execution_attacker_tone_prime","mt_execution_attacker_tone_prime","lt_execution_victim_tone_prime","mt_execution_victim_tone_prime","ht_execution_victim_tone_prime","","","","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_TONE_EXECUTION","#TITAN_EXECUTION_TONE_PRIME","#TITAN_EXECUTION_TONE_PRIME_DESC","rui/titan_loadout/execution/titan_execution_tone_prime",0,0,1,"" +"execution_northstar","titan_stryder_sniper","lt_execution_attacker_sweep_01","lt_execution_attacker_sweep_01","lt_execution_victim_sweep_01","mt_execution_victim_sweep_01","ht_execution_victim_sweep_01","","","","","","","Stryder_1p_Sync_Melee","Stryder_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_NORTHSTAR_EXECUTION","#TITAN_EXECUTION_NORTHSTAR","#TITAN_EXECUTION_NORTHSTAR_DESC","rui/titan_loadout/execution/titan_execution_northstar",0,0,0,"" +"execution_northstar_prime","titan_stryder_northstar_prime","lt_execution_attacker_armsrip","lt_execution_attacker_armsrip","lt_execution_victim_armsrip","mt_execution_victim_armsrip","ht_execution_victim_armsrip","","","","","","","Stryder_1p_Sync_Melee","Stryder_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_NORTHSTAR_EXECUTION","#TITAN_EXECUTION_NORTHSTAR_PRIME","#TITAN_EXECUTION_NORTHSTAR_PRIME_DESC","rui/titan_loadout/execution/titan_execution_northstar_prime",0,0,1,"" +"execution_vanguard","titan_atlas_vanguard","mt_execution_attacker_vanguard","mt_execution_autoTitan_attacker_vanguard","lt_execution_victim_vanguard","mt_execution_victim_vanguard","ht_execution_victim_vanguard","pt_lt_execution_victim_vanguard","pt_mt_execution_victim_vanguard","pt_ht_execution_victim_vanguard","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","TITAN_VANGUARD_EXECUTION","#TITAN_EXECUTION_VANGUARD","#TITAN_EXECUTION_VANGUARD_DESC","rui/titan_loadout/execution/titan_execution_monarch",0,0,0,"" +"execution_vanguard_kit","titan_atlas_vanguard_kit","mt_execution_battery_attacker_vanguard","mt_execution_battery_attacker_vanguard","lt_execution_battery_victim_vanguard","mt_execution_battery_victim_vanguard","ht_execution_battery_victim_vanguard","pt_lt_execution_battery_victim_vanguard","pt_mt_execution_battery_victim_vanguard","pt_ht_execution_battery_victim_vanguard","pt_lt_execution_battery_attacker_vanguard","pt_mt_execution_battery_attacker_vanguard","pt_ht_execution_battery_attacker_vanguard","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","","","","",1,0,0,"" +"execution_random_0","","","","","","","","","","","","","","","","TITAN_ION_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_ion,execution_ion_prime" +"execution_random_1","","","","","","","","","","","","","","","","TITAN_SCORCH_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_scorch,execution_scorch_prime" +"execution_random_2","","","","","","","","","","","","","","","","TITAN_NORTHSTAR_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_northstar,execution_northstar_prime" +"execution_random_3","","","","","","","","","","","","","","","","TITAN_RONIN_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_ronin,execution_ronin_prime" +"execution_random_4","","","","","","","","","","","","","","","","TITAN_TONE_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_tone,execution_tone_prime" +"execution_random_5","","","","","","","","","","","","","","","","TITAN_LEGION_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_legion,execution_legion_prime" +"execution_random_6","","","","","","","","","","","","","","","","TITAN_VANGUARD_EXECUTION","#TITAN_EXECUTION_RANDOM","#TITAN_EXECUTION_RANDOM_DESC","rui/pilot_loadout/execution/execution_random",0,0,0,"execution_vanguard" +"execution_bt_flip","titan_buddy","bt_synced_titan_execute_flip_takedown_A","bt_synced_titan_execute_flip_takedown_A","titan_synced_bt_execute_flip_takedown_V","titan_synced_bt_execute_flip_takedown_V","titan_synced_bt_execute_flip_takedown_V","","","","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","","","","",1,0,0,"" +"execution_bt_kickshoot","titan_buddy","bt_synced_titan_execute_kickshoot_A","bt_synced_titan_execute_kickshoot_A","titan_synced_bt_execute_kickshoot_V","titan_synced_bt_execute_kickshoot_V","titan_synced_bt_execute_kickshoot_V","pt_lt_synced_bt_execute_kickshoot_V","pt_mt_synced_bt_execute_kickshoot_V","pt_ht_synced_bt_execute_kickshoot_V","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","","","","",1,0,0,"" +"execution_bt_pilotrip","titan_buddy","bt_synced_titan_execute_pilot_rip_A","bt_synced_titan_execute_pilot_rip_A","titan_synced_bt_execute_pilot_rip_V","titan_synced_bt_execute_pilot_rip_V","titan_synced_bt_execute_pilot_rip_V","pt_lt_synced_bt_execute_pilot_rip_V","pt_mt_synced_bt_execute_pilot_rip_V","pt_ht_synced_bt_execute_pilot_rip_V","","","","Atlas_1p_Sync_Melee","Atlas_3p_Sync_Melee","vehicle_driver_eyes camera_2 camera_3","","","","",1,0,0,"" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_fd_upgrades.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_fd_upgrades.csv new file mode 100644 index 00000000..aab61afb --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_fd_upgrades.csv @@ -0,0 +1,50 @@ +ref,parentref,upgradeType,name,description,image,lockedImage,cost,slot,unlockLevel +"fd_upgrade_tone_utility_tier_1","tone","utility","#FD_UPGRADE_TONE_UTILITY_TIER_1","#FD_UPGRADE_TONE_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_tone_signal_strength","rui/menu/fd_menu/disabled/upgrade_tone_signal_strength",1,2,12 +"fd_upgrade_tone_utility_tier_2","tone","utility","#FD_UPGRADE_TONE_UTILITY_TIER_2","#FD_UPGRADE_TONE_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_tone_weak_points","rui/menu/fd_menu/disabled/upgrade_tone_weak_points",2,3,6 +"fd_upgrade_tone_defense_tier_1","tone","defensive","#FD_UPGRADE_TONE_DEFENSE_TIER_1","#FD_UPGRADE_TONE_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_tone_chassis","rui/menu/fd_menu/disabled/upgrade_tone_chassis",1,0,4 +"fd_upgrade_tone_defense_tier_2","tone","defensive","#FD_UPGRADE_TONE_DEFENSE_TIER_2","#FD_UPGRADE_TONE_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_tone_shield","rui/menu/fd_menu/disabled/upgrade_tone_shield",2,1,10 +"fd_upgrade_tone_weapon_tier_1","tone","weapon","#FD_UPGRADE_TONE_WEAPON_TIER_1","#FD_UPGRADE_TONE_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_tone_splasher_rounds","rui/menu/fd_menu/disabled/upgrade_tone_splasher_rounds",1,4,8 +"fd_upgrade_tone_weapon_tier_2","tone","weapon","#FD_UPGRADE_TONE_WEAPON_TIER_2","#FD_UPGRADE_TONE_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_tone_extended_ammo","rui/menu/fd_menu/disabled/upgrade_tone_extended_ammo",2,5,2 +"fd_upgrade_tone_ultimate","tone","ultimate","#FD_UPGRADE_TONE_ULTIMATE","#FD_UPGRADE_TONE_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_tone_salvo_core","rui/menu/fd_menu/disabled/upgrade_tone_salvo_core",3,6,14 +"fd_upgrade_ion_utility_tier_1","ion","utility","#FD_UPGRADE_ION_UTILITY_TIER_1","#FD_UPGRADE_ION_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_ion_energy_master","rui/menu/fd_menu/disabled/upgrade_ion_energy_master",1,2,12 +"fd_upgrade_ion_utility_tier_2","ion","utility","#FD_UPGRADE_ION_UTILITY_TIER_2","#FD_UPGRADE_ION_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_ion_energy_storage","rui/menu/fd_menu/disabled/upgrade_ion_energy_storage",2,3,6 +"fd_upgrade_ion_defense_tier_1","ion","defensive","#FD_UPGRADE_ION_DEFENSE_TIER_1","#FD_UPGRADE_ION_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_ion_chassis","rui/menu/fd_menu/disabled/upgrade_ion_chassis",1,0,4 +"fd_upgrade_ion_defense_tier_2","ion","defensive","#FD_UPGRADE_ION_DEFENSE_TIER_2","#FD_UPGRADE_ION_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_ion_shield","rui/menu/fd_menu/disabled/upgrade_ion_shield",2,1,10 +"fd_upgrade_ion_weapon_tier_1","ion","weapon","#FD_UPGRADE_ION_WEAPON_TIER_1","#FD_UPGRADE_ION_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_ion_split_shot","rui/menu/fd_menu/disabled/upgrade_ion_split_shot",1,4,2 +"fd_upgrade_ion_weapon_tier_2","ion","weapon","#FD_UPGRADE_ION_WEAPON_TIER_2","#FD_UPGRADE_ION_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_ion_splitter_damage","rui/menu/fd_menu/disabled/upgrade_ion_splitter_damage",2,5,8 +"fd_upgrade_ion_ultimate","ion","ultimate","#FD_UPGRADE_ION_ULTIMATE","#FD_UPGRADE_ION_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_ion_laser_reset","rui/menu/fd_menu/disabled/upgrade_ion_laser_reset",3,6,14 +"fd_upgrade_vanguard_utility_tier_1","vanguard","utility","#FD_UPGRADE_VANGUARD_UTILITY_TIER_1","#FD_UPGRADE_VANGUARD_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_monarch_energize_smoke","rui/menu/fd_menu/disabled/upgrade_monarch_energize_smoke",1,2,2 +"fd_upgrade_vanguard_utility_tier_2","vanguard","utility","#FD_UPGRADE_VANGUARD_UTILITY_TIER_2","#FD_UPGRADE_VANGUARD_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_monarch_energize_smoke_2","rui/menu/fd_menu/disabled/upgrade_monarch_energize_smoke_2",2,3,8 +"fd_upgrade_vanguard_defense_tier_1","vanguard","defensive","#FD_UPGRADE_VANGUARD_DEFENSE_TIER_1","#FD_UPGRADE_VANGUARD_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_monarch_chassis","rui/menu/fd_menu/disabled/upgrade_monarch_chassis",1,0,4 +"fd_upgrade_vanguard_defense_tier_2","vanguard","defensive","#FD_UPGRADE_VANGUARD_DEFENSE_TIER_2","#FD_UPGRADE_VANGUARD_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_monarch_shield","rui/menu/fd_menu/disabled/upgrade_monarch_shield",2,1,10 +"fd_upgrade_vanguard_weapon_tier_1","vanguard","weapon","#FD_UPGRADE_VANGUARD_WEAPON_TIER_1","#FD_UPGRADE_VANGUARD_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_monarch_threat_optics","rui/menu/fd_menu/disabled/upgrade_monarch_threat_optics",1,4,6 +"fd_upgrade_vanguard_weapon_tier_2","vanguard","weapon","#FD_UPGRADE_VANGUARD_WEAPON_TIER_2","#FD_UPGRADE_VANGUARD_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_monarch_xo16_sniper","rui/menu/fd_menu/disabled/upgrade_monarch_xo16_sniper",2,5,12 +"fd_upgrade_vanguard_ultimate","vanguard","ultimate","#FD_UPGRADE_VANGUARD_ULTIMATE","#FD_UPGRADE_VANGUARD_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_monarch_apex_titan","rui/menu/fd_menu/disabled/upgrade_monarch_apex_titan",3,6,14 +"fd_upgrade_ronin_utility_tier_1","ronin","utility","#FD_UPGRADE_RONIN_UTILITY_TIER_1","#FD_UPGRADE_RONIN_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_ronin_ghost_machine","rui/menu/fd_menu/disabled/upgrade_ronin_ghost_machine",1,2,6 +"fd_upgrade_ronin_utility_tier_2","ronin","utility","#FD_UPGRADE_RONIN_UTILITY_TIER_2","#FD_UPGRADE_RONIN_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_ronin_wraith","rui/menu/fd_menu/disabled/upgrade_ronin_wraith",2,3,12 +"fd_upgrade_ronin_defense_tier_1","ronin","defensive","#FD_UPGRADE_RONIN_DEFENSE_TIER_1","#FD_UPGRADE_RONIN_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_ronin_chassis","rui/menu/fd_menu/disabled/upgrade_ronin_chassis",1,0,4 +"fd_upgrade_ronin_defense_tier_2","ronin","defensive","#FD_UPGRADE_RONIN_DEFENSE_TIER_2","#FD_UPGRADE_RONIN_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_ronin_shield","rui/menu/fd_menu/disabled/upgrade_ronin_shield",2,1,10 +"fd_upgrade_ronin_weapon_tier_1","ronin","weapon","#FD_UPGRADE_RONIN_WEAPON_TIER_1","#FD_UPGRADE_RONIN_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_ronin_sword_mastery","rui/menu/fd_menu/disabled/upgrade_ronin_sword_mastery",1,4,2 +"fd_upgrade_ronin_weapon_tier_2","ronin","weapon","#FD_UPGRADE_RONIN_WEAPON_TIER_2","#FD_UPGRADE_RONIN_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_ronin_kinetic_transfer","rui/menu/fd_menu/disabled/upgrade_ronin_kinetic_transfer",2,5,8 +"fd_upgrade_ronin_ultimate","ronin","ultimate","#FD_UPGRADE_RONIN_ULTIMATE","#FD_UPGRADE_RONIN_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_ronin_blade_master","rui/menu/fd_menu/disabled/upgrade_ronin_blade_master",3,6,14 +"fd_upgrade_northstar_utility_tier_1","northstar","utility","#FD_UPGRADE_NORTHSTAR_UTILITY_TIER_1","#FD_UPGRADE_NORTHSTAR_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_northstar_explosive_trap","rui/menu/fd_menu/disabled/upgrade_northstar_explosive_trap",1,2,2 +"fd_upgrade_northstar_utility_tier_2","northstar","utility","#FD_UPGRADE_NORTHSTAR_UTILITY_TIER_2","#FD_UPGRADE_NORTHSTAR_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_northstar_trap_master","rui/menu/fd_menu/disabled/upgrade_northstar_trap_master",2,3,8 +"fd_upgrade_northstar_defense_tier_1","northstar","defensive","#FD_UPGRADE_NORTHSTAR_DEFENSE_TIER_1","#FD_UPGRADE_NORTHSTAR_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_northstar_chassis","rui/menu/fd_menu/disabled/upgrade_northstar_chassis",1,0,4 +"fd_upgrade_northstar_defense_tier_2","northstar","defensive","#FD_UPGRADE_NORTHSTAR_DEFENSE_TIER_2","#FD_UPGRADE_NORTHSTAR_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_northstar_shield","rui/menu/fd_menu/disabled/upgrade_northstar_shield",2,1,10 +"fd_upgrade_northstar_weapon_tier_1","northstar","weapon","#FD_UPGRADE_NORTHSTAR_WEAPON_TIER_1","#FD_UPGRADE_NORTHSTAR_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_northstar_quick_charge","rui/menu/fd_menu/disabled/upgrade_northstar_quick_charge",1,4,6 +"fd_upgrade_northstar_weapon_tier_2","northstar","weapon","#FD_UPGRADE_NORTHSTAR_WEAPON_TIER_2","#FD_UPGRADE_NORTHSTAR_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_northstar_one_shot_kill","rui/menu/fd_menu/disabled/upgrade_northstar_one_shot_kill",2,5,12 +"fd_upgrade_northstar_ultimate","northstar","ultimate","#FD_UPGRADE_NORTHSTAR_ULTIMATE","#FD_UPGRADE_NORTHSTAR_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_northstar_twin_cluster","rui/menu/fd_menu/disabled/upgrade_northstar_twin_cluster",3,6,14 +"fd_upgrade_scorch_utility_tier_1","scorch","utility","#FD_UPGRADE_SCORCH_UTILITY_TIER_1","#FD_UPGRADE_SCORCH_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_scorch_hot_streak","rui/menu/fd_menu/disabled/upgrade_scorch_hot_streak",1,2,6 +"fd_upgrade_scorch_utility_tier_2","scorch","utility","#FD_UPGRADE_SCORCH_UTILITY_TIER_2","#FD_UPGRADE_SCORCH_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_scorch_roaring_flame","rui/menu/fd_menu/disabled/upgrade_scorch_roaring_flame",2,3,8 +"fd_upgrade_scorch_defense_tier_1","scorch","defensive","#FD_UPGRADE_SCORCH_DEFENSE_TIER_1","#FD_UPGRADE_SCORCH_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_scorch_chassis","rui/menu/fd_menu/disabled/upgrade_scorch_chassis",1,0,4 +"fd_upgrade_scorch_defense_tier_2","scorch","defensive","#FD_UPGRADE_SCORCH_DEFENSE_TIER_2","#FD_UPGRADE_SCORCH_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_scorch_shield","rui/menu/fd_menu/disabled/upgrade_scorch_shield",2,1,10 +"fd_upgrade_scorch_weapon_tier_1","scorch","weapon","#FD_UPGRADE_SCORCH_WEAPON_TIER_1","#FD_UPGRADE_SCORCH_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_scorch_double_threat","rui/menu/fd_menu/disabled/upgrade_scorch_double_threat",1,4,2 +"fd_upgrade_scorch_weapon_tier_2","scorch","weapon","#FD_UPGRADE_SCORCH_WEAPON_TIER_2","#FD_UPGRADE_SCORCH_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_scorch_triple_threat","rui/menu/fd_menu/disabled/upgrade_scorch_triple_threat",2,5,12 +"fd_upgrade_scorch_ultimate","scorch","ultimate","#FD_UPGRADE_SCORCH_ULTIMATE","#FD_UPGRADE_SCORCH_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_scorch_explosive_barrells","rui/menu/fd_menu/disabled/upgrade_scorch_explosive_barrells",3,6,14 +"fd_upgrade_legion_utility_tier_1","legion","utility","#FD_UPGRADE_LEGION_UTILITY_TIER_1","#FD_UPGRADE_LEGION_UTILITY_TIER_1_DESC","rui/menu/fd_menu/upgrade_legion_executioner","rui/menu/fd_menu/disabled/upgrade_legion_executioner",1,2,6 +"fd_upgrade_legion_utility_tier_2","legion","utility","#FD_UPGRADE_LEGION_UTILITY_TIER_2","#FD_UPGRADE_LEGION_UTILITY_TIER_2_DESC","rui/menu/fd_menu/upgrade_legion_drill_shot","rui/menu/fd_menu/disabled/upgrade_legion_drill_shot",2,3,12 +"fd_upgrade_legion_defense_tier_1","legion","defensive","#FD_UPGRADE_LEGION_DEFENSE_TIER_1","#FD_UPGRADE_LEGION_DEFENSE_TIER_1_DESC","rui/menu/fd_menu/upgrade_legion_chassis","rui/menu/fd_menu/disabled/upgrade_legion_chassis",1,0,4 +"fd_upgrade_legion_defense_tier_2","legion","defensive","#FD_UPGRADE_LEGION_DEFENSE_TIER_2","#FD_UPGRADE_LEGION_DEFENSE_TIER_2_DESC","rui/menu/fd_menu/upgrade_legion_shield","rui/menu/fd_menu/disabled/upgrade_legion_shield",2,1,10 +"fd_upgrade_legion_weapon_tier_1","legion","weapon","#FD_UPGRADE_LEGION_WEAPON_TIER_1","#FD_UPGRADE_LEGION_WEAPON_TIER_1_DESC","rui/menu/fd_menu/upgrade_legion_piercing_shot","rui/menu/fd_menu/disabled/upgrade_legion_piercing_shot",1,4,2 +"fd_upgrade_legion_weapon_tier_2","legion","weapon","#FD_UPGRADE_LEGION_WEAPON_TIER_2","#FD_UPGRADE_LEGION_WEAPON_TIER_2_DESC","rui/menu/fd_menu/upgrade_legion_redirect","rui/menu/fd_menu/disabled/upgrade_legion_redirect",2,5,8 +"fd_upgrade_legion_ultimate","legion","ultimate","#FD_UPGRADE_LEGION_ULTIMATE","#FD_UPGRADE_LEGION_ULTIMATE_DESC","rui/menu/fd_menu/upgrade_legion_double_down","rui/menu/fd_menu/disabled/upgrade_legion_double_down",3,6,14 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_nose_art.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_nose_art.csv new file mode 100644 index 00000000..56bcf556 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_nose_art.csv @@ -0,0 +1,191 @@ +ref,titanRef,image,name,cost +"ion_nose_art_none","ion","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"ion_nose_art_01","ion","rui/titan_loadout/nose_art/ion_nose_art_01","#ION_NOSE_ART_01",0 +"ion_nose_art_02","ion","rui/titan_loadout/nose_art/ion_nose_art_02","#ION_NOSE_ART_02",0 +"ion_nose_art_03","ion","rui/titan_loadout/nose_art/ion_nose_art_03","#ION_NOSE_ART_03",0 +"ion_nose_art_04","ion","rui/titan_loadout/nose_art/ion_nose_art_04","#ION_NOSE_ART_04",0 +"ion_nose_art_05","ion","rui/titan_loadout/nose_art/ion_nose_art_05","#ION_NOSE_ART_05",300 +"ion_nose_art_06","ion","rui/titan_loadout/nose_art/ion_nose_art_06","#ION_NOSE_ART_06",0 +"ion_nose_art_07","ion","rui/titan_loadout/nose_art/ion_nose_art_07","#ION_NOSE_ART_07",0 +"ion_nose_art_08","ion","rui/titan_loadout/nose_art/ion_nose_art_08","#ION_NOSE_ART_08",0 +"ion_nose_art_09","ion","rui/titan_loadout/nose_art/ion_nose_art_09","#ION_NOSE_ART_09",0 +"ion_nose_art_10","ion","rui/titan_loadout/nose_art/ion_nose_art_10","#ION_NOSE_ART_10",0 +"ion_nose_art_11","ion","rui/titan_loadout/nose_art/ion_nose_art_11","#ION_NOSE_ART_11",0 +"ion_nose_art_12","ion","rui/titan_loadout/nose_art/ion_nose_art_12","#ION_NOSE_ART_12",0 +"ion_nose_art_13","ion","rui/titan_loadout/nose_art/ion_nose_art_13","#ION_NOSE_ART_13",0 +"ion_nose_art_14","ion","rui/titan_loadout/nose_art/ion_nose_art_14","#ION_NOSE_ART_14",0 +"scorch_nose_art_none","scorch","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"scorch_nose_art_01","scorch","rui/titan_loadout/nose_art/scorch_nose_art_01","#SCORCH_NOSE_ART_01",0 +"scorch_nose_art_02","scorch","rui/titan_loadout/nose_art/scorch_nose_art_02","#SCORCH_NOSE_ART_02",0 +"scorch_nose_art_03","scorch","rui/titan_loadout/nose_art/scorch_nose_art_03","#SCORCH_NOSE_ART_03",0 +"scorch_nose_art_04","scorch","rui/titan_loadout/nose_art/scorch_nose_art_04","#SCORCH_NOSE_ART_04",0 +"scorch_nose_art_05","scorch","rui/titan_loadout/nose_art/scorch_nose_art_05","#SCORCH_NOSE_ART_05",0 +"scorch_nose_art_06","scorch","rui/titan_loadout/nose_art/scorch_nose_art_06","#SCORCH_NOSE_ART_06",0 +"scorch_nose_art_07","scorch","rui/titan_loadout/nose_art/scorch_nose_art_07","#SCORCH_NOSE_ART_07",0 +"scorch_nose_art_08","scorch","rui/titan_loadout/nose_art/scorch_nose_art_08","#SCORCH_NOSE_ART_08",0 +"scorch_nose_art_09","scorch","rui/titan_loadout/nose_art/scorch_nose_art_09","#SCORCH_NOSE_ART_09",0 +"scorch_nose_art_10","scorch","rui/titan_loadout/nose_art/scorch_nose_art_10","#SCORCH_NOSE_ART_10",0 +"scorch_nose_art_11","scorch","rui/titan_loadout/nose_art/scorch_nose_art_11","#SCORCH_NOSE_ART_11",0 +"scorch_nose_art_12","scorch","rui/titan_loadout/nose_art/scorch_nose_art_12","#SCORCH_NOSE_ART_12",300 +"scorch_nose_art_13","scorch","rui/titan_loadout/nose_art/scorch_nose_art_13","#SCORCH_NOSE_ART_13",0 +"scorch_nose_art_14","scorch","rui/titan_loadout/nose_art/scorch_nose_art_14","#SCORCH_NOSE_ART_14",0 +"ronin_nose_art_none","ronin","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"ronin_nose_art_01","ronin","rui/titan_loadout/nose_art/ronin_nose_art_01","#RONIN_NOSE_ART_01",0 +"ronin_nose_art_02","ronin","rui/titan_loadout/nose_art/ronin_nose_art_02","#RONIN_NOSE_ART_02",0 +"ronin_nose_art_03","ronin","rui/titan_loadout/nose_art/ronin_nose_art_03","#RONIN_NOSE_ART_03",0 +"ronin_nose_art_04","ronin","rui/titan_loadout/nose_art/ronin_nose_art_04","#RONIN_NOSE_ART_04",0 +"ronin_nose_art_05","ronin","rui/titan_loadout/nose_art/ronin_nose_art_05","#RONIN_NOSE_ART_05",0 +"ronin_nose_art_06","ronin","rui/titan_loadout/nose_art/ronin_nose_art_06","#RONIN_NOSE_ART_06",0 +"ronin_nose_art_07","ronin","rui/titan_loadout/nose_art/ronin_nose_art_07","#RONIN_NOSE_ART_07",0 +"ronin_nose_art_08","ronin","rui/titan_loadout/nose_art/ronin_nose_art_08","#RONIN_NOSE_ART_08",300 +"ronin_nose_art_09","ronin","rui/titan_loadout/nose_art/ronin_nose_art_09","#RONIN_NOSE_ART_09",0 +"ronin_nose_art_10","ronin","rui/titan_loadout/nose_art/ronin_nose_art_10","#RONIN_NOSE_ART_10",0 +"ronin_nose_art_11","ronin","rui/titan_loadout/nose_art/ronin_nose_art_11","#RONIN_NOSE_ART_11",0 +"ronin_nose_art_12","ronin","rui/titan_loadout/nose_art/ronin_nose_art_12","#RONIN_NOSE_ART_12",300 +"ronin_nose_art_13","ronin","rui/titan_loadout/nose_art/ronin_nose_art_13","#RONIN_NOSE_ART_13",0 +"ronin_nose_art_14","ronin","rui/titan_loadout/nose_art/ronin_nose_art_14","#RONIN_NOSE_ART_14",0 +"tone_nose_art_none","tone","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"tone_nose_art_01","tone","rui/titan_loadout/nose_art/tone_nose_art_01","#TONE_NOSE_ART_01",0 +"tone_nose_art_02","tone","rui/titan_loadout/nose_art/tone_nose_art_02","#TONE_NOSE_ART_02",0 +"tone_nose_art_03","tone","rui/titan_loadout/nose_art/tone_nose_art_03","#TONE_NOSE_ART_03",0 +"tone_nose_art_04","tone","rui/titan_loadout/nose_art/tone_nose_art_04","#TONE_NOSE_ART_04",0 +"tone_nose_art_05","tone","rui/titan_loadout/nose_art/tone_nose_art_05","#TONE_NOSE_ART_05",0 +"tone_nose_art_06","tone","rui/titan_loadout/nose_art/tone_nose_art_06","#TONE_NOSE_ART_06",0 +"tone_nose_art_07","tone","rui/titan_loadout/nose_art/tone_nose_art_07","#TONE_NOSE_ART_07",0 +"tone_nose_art_08","tone","rui/titan_loadout/nose_art/tone_nose_art_08","#TONE_NOSE_ART_08",0 +"tone_nose_art_09","tone","rui/titan_loadout/nose_art/tone_nose_art_09","#TONE_NOSE_ART_09",0 +"tone_nose_art_10","tone","rui/titan_loadout/nose_art/tone_nose_art_10","#TONE_NOSE_ART_10",0 +"tone_nose_art_11","tone","rui/titan_loadout/nose_art/tone_nose_art_11","#TONE_NOSE_ART_11",300 +"tone_nose_art_12","tone","rui/titan_loadout/nose_art/tone_nose_art_12","#TONE_NOSE_ART_12",300 +"tone_nose_art_13","tone","rui/titan_loadout/nose_art/tone_nose_art_13","#TONE_NOSE_ART_13",0 +"tone_nose_art_14","tone","rui/titan_loadout/nose_art/tone_nose_art_14","#TONE_NOSE_ART_14",0 +"northstar_nose_art_none","northstar","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"northstar_nose_art_01","northstar","rui/titan_loadout/nose_art/northstar_nose_art_01","#NORTHSTAR_NOSE_ART_01",0 +"northstar_nose_art_02","northstar","rui/titan_loadout/nose_art/northstar_nose_art_02","#NORTHSTAR_NOSE_ART_02",0 +"northstar_nose_art_03","northstar","rui/titan_loadout/nose_art/northstar_nose_art_03","#NORTHSTAR_NOSE_ART_03",0 +"northstar_nose_art_04","northstar","rui/titan_loadout/nose_art/northstar_nose_art_04","#NORTHSTAR_NOSE_ART_04",0 +"northstar_nose_art_05","northstar","rui/titan_loadout/nose_art/northstar_nose_art_05","#NORTHSTAR_NOSE_ART_05",0 +"northstar_nose_art_06","northstar","rui/titan_loadout/nose_art/northstar_nose_art_06","#NORTHSTAR_NOSE_ART_06",0 +"northstar_nose_art_07","northstar","rui/titan_loadout/nose_art/northstar_nose_art_07","#NORTHSTAR_NOSE_ART_07",0 +"northstar_nose_art_08","northstar","rui/titan_loadout/nose_art/northstar_nose_art_08","#NORTHSTAR_NOSE_ART_08",0 +"northstar_nose_art_09","northstar","rui/titan_loadout/nose_art/northstar_nose_art_09","#NORTHSTAR_NOSE_ART_09",0 +"northstar_nose_art_10","northstar","rui/titan_loadout/nose_art/northstar_nose_art_10","#NORTHSTAR_NOSE_ART_10",0 +"northstar_nose_art_11","northstar","rui/titan_loadout/nose_art/northstar_nose_art_11","#NORTHSTAR_NOSE_ART_11",0 +"northstar_nose_art_12","northstar","rui/titan_loadout/nose_art/northstar_nose_art_12","#NORTHSTAR_NOSE_ART_12",300 +"northstar_nose_art_13","northstar","rui/titan_loadout/nose_art/northstar_nose_art_13","#NORTHSTAR_NOSE_ART_13",300 +"northstar_nose_art_14","northstar","rui/titan_loadout/nose_art/northstar_nose_art_14","#NORTHSTAR_NOSE_ART_14",0 +"legion_nose_art_none","legion","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"legion_nose_art_01","legion","rui/titan_loadout/nose_art/legion_nose_art_01","#LEGION_NOSE_ART_01",0 +"legion_nose_art_02","legion","rui/titan_loadout/nose_art/legion_nose_art_02","#LEGION_NOSE_ART_02",0 +"legion_nose_art_03","legion","rui/titan_loadout/nose_art/legion_nose_art_03","#LEGION_NOSE_ART_03",0 +"legion_nose_art_04","legion","rui/titan_loadout/nose_art/legion_nose_art_04","#LEGION_NOSE_ART_04",0 +"legion_nose_art_05","legion","rui/titan_loadout/nose_art/legion_nose_art_05","#LEGION_NOSE_ART_05",0 +"legion_nose_art_06","legion","rui/titan_loadout/nose_art/legion_nose_art_06","#LEGION_NOSE_ART_06",0 +"legion_nose_art_07","legion","rui/titan_loadout/nose_art/legion_nose_art_07","#LEGION_NOSE_ART_07",0 +"legion_nose_art_08","legion","rui/titan_loadout/nose_art/legion_nose_art_08","#LEGION_NOSE_ART_08",0 +"legion_nose_art_09","legion","rui/titan_loadout/nose_art/legion_nose_art_09","#LEGION_NOSE_ART_09",0 +"legion_nose_art_10","legion","rui/titan_loadout/nose_art/legion_nose_art_10","#LEGION_NOSE_ART_10",0 +"legion_nose_art_11","legion","rui/titan_loadout/nose_art/legion_nose_art_11","#LEGION_NOSE_ART_11",0 +"legion_nose_art_12","legion","rui/titan_loadout/nose_art/legion_nose_art_12","#LEGION_NOSE_ART_12",300 +"legion_nose_art_13","legion","rui/titan_loadout/nose_art/legion_nose_art_13","#LEGION_NOSE_ART_13",0 +"legion_nose_art_14","legion","rui/titan_loadout/nose_art/legion_nose_art_14","#LEGION_NOSE_ART_14",300 +"ion_nose_art_17","ion","rui/titan_loadout/nose_art/ion_nose_art_17","#ION_NOSE_ART_17",0 +"ion_nose_art_18","ion","rui/titan_loadout/nose_art/ion_nose_art_18","#ION_NOSE_ART_18",0 +"ion_nose_art_19","ion","rui/titan_loadout/nose_art/ion_nose_art_19","#ION_NOSE_ART_19",0 +"ion_nose_art_20","ion","rui/titan_loadout/nose_art/ion_nose_art_20","#ION_NOSE_ART_20",0 +"ion_nose_art_21","ion","rui/titan_loadout/nose_art/ion_nose_art_21","#ION_NOSE_ART_21",0 +"scorch_nose_art_15","scorch","rui/titan_loadout/nose_art/scorch_nose_art_15","#SCORCH_NOSE_ART_15",0 +"scorch_nose_art_16","scorch","rui/titan_loadout/nose_art/scorch_nose_art_16","#SCORCH_NOSE_ART_16",0 +"scorch_nose_art_17","scorch","rui/titan_loadout/nose_art/scorch_nose_art_17","#SCORCH_NOSE_ART_17",0 +"scorch_nose_art_18","scorch","rui/titan_loadout/nose_art/scorch_nose_art_18","#SCORCH_NOSE_ART_18",0 +"scorch_nose_art_19","scorch","rui/titan_loadout/nose_art/scorch_nose_art_19","#SCORCH_NOSE_ART_19",0 +"ronin_nose_art_16","ronin","rui/titan_loadout/nose_art/ronin_nose_art_16","#RONIN_NOSE_ART_16",0 +"ronin_nose_art_17","ronin","rui/titan_loadout/nose_art/ronin_nose_art_17","#RONIN_NOSE_ART_17",0 +"ronin_nose_art_18","ronin","rui/titan_loadout/nose_art/ronin_nose_art_18","#RONIN_NOSE_ART_18",0 +"ronin_nose_art_19","ronin","rui/titan_loadout/nose_art/ronin_nose_art_19","#RONIN_NOSE_ART_19",0 +"ronin_nose_art_20","ronin","rui/titan_loadout/nose_art/ronin_nose_art_20","#RONIN_NOSE_ART_20",0 +"tone_nose_art_17","tone","rui/titan_loadout/nose_art/tone_nose_art_17","#TONE_NOSE_ART_17",0 +"tone_nose_art_18","tone","rui/titan_loadout/nose_art/tone_nose_art_18","#TONE_NOSE_ART_18",0 +"tone_nose_art_19","tone","rui/titan_loadout/nose_art/tone_nose_art_19","#TONE_NOSE_ART_19",0 +"tone_nose_art_20","tone","rui/titan_loadout/nose_art/tone_nose_art_20","#TONE_NOSE_ART_20",0 +"tone_nose_art_21","tone","rui/titan_loadout/nose_art/tone_nose_art_21","#TONE_NOSE_ART_21",0 +"northstar_nose_art_18","northstar","rui/titan_loadout/nose_art/northstar_nose_art_18","#NORTHSTAR_NOSE_ART_18",0 +"northstar_nose_art_19","northstar","rui/titan_loadout/nose_art/northstar_nose_art_19","#NORTHSTAR_NOSE_ART_19",0 +"northstar_nose_art_20","northstar","rui/titan_loadout/nose_art/northstar_nose_art_20","#NORTHSTAR_NOSE_ART_20",0 +"northstar_nose_art_21","northstar","rui/titan_loadout/nose_art/northstar_nose_art_21","#NORTHSTAR_NOSE_ART_21",0 +"northstar_nose_art_22","northstar","rui/titan_loadout/nose_art/northstar_nose_art_22","#NORTHSTAR_NOSE_ART_22",0 +"legion_nose_art_17","legion","rui/titan_loadout/nose_art/legion_nose_art_17","#LEGION_NOSE_ART_17",0 +"legion_nose_art_18","legion","rui/titan_loadout/nose_art/legion_nose_art_18","#LEGION_NOSE_ART_18",0 +"legion_nose_art_19","legion","rui/titan_loadout/nose_art/legion_nose_art_19","#LEGION_NOSE_ART_19",0 +"legion_nose_art_20","legion","rui/titan_loadout/nose_art/legion_nose_art_20","#LEGION_NOSE_ART_20",0 +"legion_nose_art_21","legion","rui/titan_loadout/nose_art/legion_nose_art_21","#LEGION_NOSE_ART_21",0 +"ion_nose_art_22","ion","rui/titan_loadout/nose_art/ion_nose_art_22","#ION_NOSE_ART_22",0 +"ion_nose_art_23","ion","rui/titan_loadout/nose_art/ion_nose_art_23","#ION_NOSE_ART_23",0 +"ion_nose_art_24","ion","rui/titan_loadout/nose_art/ion_nose_art_24","#ION_NOSE_ART_24",0 +"ion_nose_art_25","ion","rui/titan_loadout/nose_art/ion_nose_art_25","#ION_NOSE_ART_25",0 +"ion_nose_art_26","ion","rui/titan_loadout/nose_art/ion_nose_art_26","#ION_NOSE_ART_26",0 +"scorch_nose_art_20","scorch","rui/titan_loadout/nose_art/scorch_nose_art_20","#SCORCH_NOSE_ART_20",0 +"scorch_nose_art_21","scorch","rui/titan_loadout/nose_art/scorch_nose_art_21","#SCORCH_NOSE_ART_21",0 +"scorch_nose_art_22","scorch","rui/titan_loadout/nose_art/scorch_nose_art_22","#SCORCH_NOSE_ART_22",0 +"scorch_nose_art_23","scorch","rui/titan_loadout/nose_art/scorch_nose_art_23","#SCORCH_NOSE_ART_23",0 +"scorch_nose_art_24","scorch","rui/titan_loadout/nose_art/scorch_nose_art_24","#SCORCH_NOSE_ART_24",0 +"ronin_nose_art_21","ronin","rui/titan_loadout/nose_art/ronin_nose_art_21","#RONIN_NOSE_ART_21",0 +"ronin_nose_art_22","ronin","rui/titan_loadout/nose_art/ronin_nose_art_22","#RONIN_NOSE_ART_22",0 +"ronin_nose_art_23","ronin","rui/titan_loadout/nose_art/ronin_nose_art_23","#RONIN_NOSE_ART_23",0 +"ronin_nose_art_24","ronin","rui/titan_loadout/nose_art/ronin_nose_art_24","#RONIN_NOSE_ART_24",0 +"ronin_nose_art_25","ronin","rui/titan_loadout/nose_art/ronin_nose_art_25","#RONIN_NOSE_ART_25",0 +"tone_nose_art_22","tone","rui/titan_loadout/nose_art/tone_nose_art_22","#TONE_NOSE_ART_22",0 +"tone_nose_art_23","tone","rui/titan_loadout/nose_art/tone_nose_art_23","#TONE_NOSE_ART_23",0 +"tone_nose_art_24","tone","rui/titan_loadout/nose_art/tone_nose_art_24","#TONE_NOSE_ART_24",0 +"tone_nose_art_25","tone","rui/titan_loadout/nose_art/tone_nose_art_25","#TONE_NOSE_ART_25",0 +"tone_nose_art_26","tone","rui/titan_loadout/nose_art/tone_nose_art_26","#TONE_NOSE_ART_26",0 +"northstar_nose_art_23","northstar","rui/titan_loadout/nose_art/northstar_nose_art_23","#NORTHSTAR_NOSE_ART_23",0 +"northstar_nose_art_24","northstar","rui/titan_loadout/nose_art/northstar_nose_art_24","#NORTHSTAR_NOSE_ART_24",0 +"northstar_nose_art_25","northstar","rui/titan_loadout/nose_art/northstar_nose_art_25","#NORTHSTAR_NOSE_ART_25",0 +"northstar_nose_art_26","northstar","rui/titan_loadout/nose_art/northstar_nose_art_26","#NORTHSTAR_NOSE_ART_26",0 +"northstar_nose_art_27","northstar","rui/titan_loadout/nose_art/northstar_nose_art_27","#NORTHSTAR_NOSE_ART_27",0 +"legion_nose_art_22","legion","rui/titan_loadout/nose_art/legion_nose_art_22","#LEGION_NOSE_ART_22",0 +"legion_nose_art_23","legion","rui/titan_loadout/nose_art/legion_nose_art_23","#LEGION_NOSE_ART_23",0 +"legion_nose_art_24","legion","rui/titan_loadout/nose_art/legion_nose_art_24","#LEGION_NOSE_ART_24",0 +"legion_nose_art_25","legion","rui/titan_loadout/nose_art/legion_nose_art_25","#LEGION_NOSE_ART_25",0 +"legion_nose_art_26","legion","rui/titan_loadout/nose_art/legion_nose_art_26","#LEGION_NOSE_ART_26",0 +"vanguard_nose_art_none","vanguard","rui/menu/common/no_art","#FACTORY_ISSUE_NAME",0 +"vanguard_nose_art_01","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_02","#VANGUARD_NOSE_ART_01",0 +"vanguard_nose_art_02","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_03","#VANGUARD_NOSE_ART_02",0 +"vanguard_nose_art_03","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_04","#VANGUARD_NOSE_ART_03",0 +"vanguard_nose_art_04","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_05","#VANGUARD_NOSE_ART_04",0 +"vanguard_nose_art_05","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_06","#VANGUARD_NOSE_ART_05",0 +"vanguard_nose_art_06","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_07","#VANGUARD_NOSE_ART_06",0 +"vanguard_nose_art_07","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_08","#VANGUARD_NOSE_ART_07",0 +"vanguard_nose_art_08","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_09","#VANGUARD_NOSE_ART_08",0 +"vanguard_nose_art_09","vanguard","rui/titan_loadout/nose_art/monarch_nose_art_10","#VANGUARD_NOSE_ART_09",0 +"ion_nose_art_27","ion","rui/titan_loadout/nose_art/ion_nose_art_27","#ION_NOSE_ART_27",0 +"ion_nose_art_28","ion","rui/titan_loadout/nose_art/ion_nose_art_28","#ION_NOSE_ART_28",0 +"ion_nose_art_29","ion","rui/titan_loadout/nose_art/ion_nose_art_29","#ION_NOSE_ART_29",0 +"ion_nose_art_30","ion","rui/titan_loadout/nose_art/ion_nose_art_30","#ION_NOSE_ART_30",0 +"ion_nose_art_31","ion","rui/titan_loadout/nose_art/ion_nose_art_31","#ION_NOSE_ART_31",0 +"scorch_nose_art_25","scorch","rui/titan_loadout/nose_art/scorch_nose_art_25","#SCORCH_NOSE_ART_25",0 +"scorch_nose_art_26","scorch","rui/titan_loadout/nose_art/scorch_nose_art_26","#SCORCH_NOSE_ART_26",0 +"scorch_nose_art_27","scorch","rui/titan_loadout/nose_art/scorch_nose_art_27","#SCORCH_NOSE_ART_27",0 +"scorch_nose_art_28","scorch","rui/titan_loadout/nose_art/scorch_nose_art_28","#SCORCH_NOSE_ART_28",0 +"scorch_nose_art_29","scorch","rui/titan_loadout/nose_art/scorch_nose_art_29","#SCORCH_NOSE_ART_29",0 +"ronin_nose_art_26","ronin","rui/titan_loadout/nose_art/ronin_nose_art_26","#RONIN_NOSE_ART_26",0 +"ronin_nose_art_27","ronin","rui/titan_loadout/nose_art/ronin_nose_art_27","#RONIN_NOSE_ART_27",0 +"ronin_nose_art_28","ronin","rui/titan_loadout/nose_art/ronin_nose_art_28","#RONIN_NOSE_ART_28",0 +"ronin_nose_art_29","ronin","rui/titan_loadout/nose_art/ronin_nose_art_29","#RONIN_NOSE_ART_29",0 +"ronin_nose_art_30","ronin","rui/titan_loadout/nose_art/ronin_nose_art_30","#RONIN_NOSE_ART_30",0 +"tone_nose_art_27","tone","rui/titan_loadout/nose_art/tone_nose_art_27","#TONE_NOSE_ART_27",0 +"tone_nose_art_28","tone","rui/titan_loadout/nose_art/tone_nose_art_28","#TONE_NOSE_ART_28",0 +"tone_nose_art_29","tone","rui/titan_loadout/nose_art/tone_nose_art_29","#TONE_NOSE_ART_29",0 +"tone_nose_art_30","tone","rui/titan_loadout/nose_art/tone_nose_art_30","#TONE_NOSE_ART_30",0 +"tone_nose_art_31","tone","rui/titan_loadout/nose_art/tone_nose_art_31","#TONE_NOSE_ART_31",0 +"northstar_nose_art_28","northstar","rui/titan_loadout/nose_art/northstar_nose_art_28","#NORTHSTAR_NOSE_ART_28",0 +"northstar_nose_art_29","northstar","rui/titan_loadout/nose_art/northstar_nose_art_29","#NORTHSTAR_NOSE_ART_29",0 +"northstar_nose_art_30","northstar","rui/titan_loadout/nose_art/northstar_nose_art_30","#NORTHSTAR_NOSE_ART_30",0 +"northstar_nose_art_31","northstar","rui/titan_loadout/nose_art/northstar_nose_art_31","#NORTHSTAR_NOSE_ART_31",0 +"northstar_nose_art_32","northstar","rui/titan_loadout/nose_art/northstar_nose_art_32","#NORTHSTAR_NOSE_ART_32",0 +"legion_nose_art_27","legion","rui/titan_loadout/nose_art/legion_nose_art_27","#LEGION_NOSE_ART_27",0 +"legion_nose_art_28","legion","rui/titan_loadout/nose_art/legion_nose_art_28","#LEGION_NOSE_ART_28",0 +"legion_nose_art_29","legion","rui/titan_loadout/nose_art/legion_nose_art_29","#LEGION_NOSE_ART_29",0 +"legion_nose_art_30","legion","rui/titan_loadout/nose_art/legion_nose_art_30","#LEGION_NOSE_ART_30",0 +"legion_nose_art_31","legion","rui/titan_loadout/nose_art/legion_nose_art_31","#LEGION_NOSE_ART_31",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_os_conversations.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_os_conversations.csv new file mode 100644 index 00000000..6d7a8623 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_os_conversations.csv @@ -0,0 +1,67 @@ +conversationname,priority,debounce +"bettyAlarm",400,0.100000 +"warning",400,3.000000 +"caution",400,3.000000 +"multiTitanEngage",400,15.000000 +"outnumbered2to1",400,15.000000 +"outnumbered3to1",400,15.000000 +"outnumbered4to1",400,15.000000 +"embark",400,3.000000 +"disembark",400,3.000000 +"guard",2000,3.000000 +"follow",2000,3.000000 +"briefCriticalDamage",400,10.000000 +"manualEjectNotice",400,0.100000 +"autoEjectNotice",400,0.100000 +"doomState",400,0.100000 +"halfDoomState",400,0.100000 +"rodeoWarning",2000,3.000000 +"allyRodeoAttach",400,3.000000 +"allyRodeoDetach",400,3.000000 +"killEnemyRodeo",400,10.000000 +"warningEnemyPilot",400,10.000000 +"warningEnemyPilotMulti",400,10.000000 +"elimTarget",400,3.000000 +"elimEnemyPilot",400,3.000000 +"ejectedEnemy",400,3.000000 +"ejectedFriendly",400,3.000000 +"assistedByFriendlyTitan",400,10.000000 +"elimEnemyTitan",400,3.000000 +"elimFriendlyTitan",400,3.000000 +"assistedByFriendlyPilot",400,3.000000 +"hostileTitanInbound",2000,3.000000 +"friendlyRodeoOnEnemyTitan",400,3.000000 +"autoEngageGrunt",400,10.000000 +"autoEngagePilot",400,10.000000 +"autoEngageTitan",400,10.000000 +"autoEngageTitans",400,10.000000 +"killEnemyRodeoGnrc",400,10.000000 +"batteryGot",400,3.000000 +"predRangeLong",400,3.000000 +"predRangeShort",400,3.000000 +"smartCoreOnline",400,3.000000 +"smartCoreActivated",400,3.000000 +"smartCoreOffline",400,3.000000 +"flamewavecoreOnline",400,3.000000 +"flamewavecoreActivated",400,3.000000 +"hack_bt_workaround",400,3.000000 +"lasercoreOnline",400,3.000000 +"lasercoreActivated",400,3.000000 +"sonarPulse",400,3.000000 +"flightCoreOnline",400,3.000000 +"flightCoreActivated",400,3.000000 +"flightCoreOffline",400,3.000000 +"SalvocoreOnline",400,3.000000 +"SalvocoreActivated",400,3.000000 +"swordCoreOnline",400,3.000000 +"swordCoreActivated",400,3.000000 +"swordCoreOffline",400,3.000000 +"burstCoreOnline",400,3.000000 +"burstCoreActivated",400,3.000000 +"UpgradecoreOnline",400,3.000000 +"UpgradecoreActivated",400,3.000000 +"upgradeTo1",400,3.000000 +"upgradeTo2",400,3.000000 +"upgradeTo3",400,3.000000 +"upgradeToFin",400,3.000000 +"upgradeShieldReplenish",400,3.000000 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_passives.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_passives.csv new file mode 100644 index 00000000..79f093c2 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_passives.csv @@ -0,0 +1,52 @@ +passive,type,name,description,longdescription,image,hidden,cost +"pas_build_up_nuclear_core","TITAN_GENERAL_PASSIVE","#GEAR_NUCLEAR_CORE","#GEAR_NUCLEAR_CORE_DESC","#GEAR_NUCLEAR_CORE_LONGDESC","rui/titan_loadout/passive/nuke_eject",0,5 +"pas_enhanced_titan_ai","TITAN_GENERAL_PASSIVE","#GEAR_ASSAULT_CHIP","#GEAR_ASSAULT_CHIP_DESC","#GEAR_ASSAULT_CHIP_LONGDESC","rui/titan_loadout/passive/assault_chip",0,25 +"pas_auto_eject","TITAN_GENERAL_PASSIVE","#GEAR_AUTO_EJECT","#GEAR_AUTO_EJECT_DESC","#GEAR_AUTO_EJECT_LONGDESC","rui/titan_loadout/passive/auto_eject",0,25 +"pas_hyper_core","TITAN_GENERAL_PASSIVE","#GEAR_CORE_HEADSTART","#GEAR_CORE_HEADSTART_DESC","#GEAR_CORE_HEADSTART_LONGDESC","rui/titan_loadout/passive/overcore",0,5 +"pas_anti_rodeo","TITAN_GENERAL_PASSIVE","#GEAR_ANTI_RODEO","#GEAR_ANTI_RODEO_DESC","#GEAR_ANTI_RODEO_LONGDESC","rui/titan_loadout/passive/improved_anti_rodeo",0,5 +"pas_mobility_dash_capacity","TITAN_GENERAL_PASSIVE","#GEAR_DASH_CAPACITY","#GEAR_DASH_CAPACITY_DESC","#GEAR_DASH_CAPACITY_LONGDESC","rui/titan_loadout/passive/dash_plus",0,5 +"pas_warpfall","TITAN_TITANFALL_PASSIVE","#GEAR_WARPFALL","#GEAR_WARPFALL_DESC","#GEAR_WARPFALL_LONGDESC","rui/titan_loadout/passive/titanfall_kit_warpfall",0,25 +"pas_bubbleshield","TITAN_TITANFALL_PASSIVE","#GEAR_BUBBLESHIELD","#GEAR_BUBBLESHIELD_DESC","#GEAR_BUBBLESHIELD_LONGDESC","rui/titan_loadout/passive/titanfall_kit_bubbleshield",0,14 +"pas_ronin_weapon","TITAN_RONIN_PASSIVE","#GEAR_RONIN_WEAPON","#GEAR_RONIN_WEAPON_DESC","#GEAR_RONIN_WEAPON_LONGDESC","rui/titan_loadout/passive/ronin_ricochet_round",0,25 +"pas_northstar_weapon","TITAN_NORTHSTAR_PASSIVE","#GEAR_NORTHSTAR_WEAPON","#GEAR_NORTHSTAR_WEAPON_DESC","#GEAR_NORTHSTAR_WEAPON_LONGDESC","rui/titan_loadout/passive/northstar_piercing_shot",0,25 +"pas_ion_weapon","TITAN_ION_PASSIVE","#GEAR_ION_WEAPON","#GEAR_ION_WEAPON_DESC","#GEAR_ION_WEAPON_LONGDESC","rui/titan_loadout/passive/ion_entangled_energy",0,25 +"pas_tone_weapon","TITAN_TONE_PASSIVE","#GEAR_TONE_WEAPON","#GEAR_TONE_WEAPON_DESC","#GEAR_TONE_WEAPON_LONGDESC","rui/titan_loadout/passive/tone_enhanced_tracker",0,25 +"pas_scorch_weapon","TITAN_SCORCH_PASSIVE","#GEAR_SCORCH_WEAPON","#GEAR_SCORCH_WEAPON_DESC","#GEAR_SCORCH_WEAPON_LONGDESC","rui/titan_loadout/passive/scorch_wildfire_launcher",0,25 +"pas_legion_weapon","TITAN_LEGION_PASSIVE","#GEAR_LEGION_WEAPON","#GEAR_LEGION_WEAPON_DESC","#GEAR_LEGION_WEAPON_LONGDESC","rui/titan_loadout/passive/legion_enhanced_ammo",0,25 +"pas_ion_tripwire","TITAN_ION_PASSIVE","#GEAR_ION_TRIPWIRE","#GEAR_ION_TRIPWIRE_DESC","#GEAR_ION_TRIPWIRE_LONGDESC","rui/titan_loadout/passive/ion_zero_point_tripwire",0,24 +"pas_ion_vortex","TITAN_ION_PASSIVE","#GEAR_ION_VORTEX","#GEAR_ION_VORTEX_DESC","#GEAR_ION_VORTEX_LONGDESC","rui/titan_loadout/passive/ion_vortex_amp",0,24 +"pas_ion_lasercannon","TITAN_ION_PASSIVE","#GEAR_ION_LASERCANNON","#GEAR_ION_LASERCANNON_DESC","#GEAR_ION_LASERCANNON_LONGDESC","rui/titan_loadout/passive/ion_grand_canon",0,24 +"pas_tone_rockets","TITAN_TONE_PASSIVE","#GEAR_TONE_ROCKETS","#GEAR_TONE_ROCKETS_DESC","#GEAR_TONE_ROCKETS_LONGDESC","rui/titan_loadout/passive/tone_rocket_barrage",0,24 +"pas_tone_sonar","TITAN_TONE_PASSIVE","#GEAR_TONE_SONAR","#GEAR_TONE_SONAR_DESC","#GEAR_TONE_SONAR_LONGDESC","rui/titan_loadout/passive/tone_pulse_echo",0,24 +"pas_tone_wall","TITAN_TONE_PASSIVE","#GEAR_TONE_WALL","#GEAR_TONE_WALL_DESC","#GEAR_TONE_WALL_LONGDESC","rui/titan_loadout/passive/tone_reinforced_partical_wall",0,24 +"pas_ronin_arcwave","TITAN_RONIN_PASSIVE","#GEAR_RONIN_ARCWAVE","#GEAR_RONIN_ARCWAVE_DESC","#GEAR_RONIN_ARCWAVE_LONGDESC","rui/titan_loadout/passive/ronin_thunderstorm",0,24 +"pas_ronin_phase","TITAN_RONIN_PASSIVE","#GEAR_RONIN_PHASE","#GEAR_RONIN_PHASE_DESC","#GEAR_RONIN_PHASE_LONGDESC","rui/titan_loadout/passive/ronin_temporal_anomaly",0,24 +"pas_ronin_swordcore","TITAN_RONIN_PASSIVE","#GEAR_RONIN_SWORDCORE","#GEAR_RONIN_SWORDCORE_DESC","#GEAR_RONIN_SWORDCORE_LONGDESC","rui/titan_loadout/passive/ronin_highlander",0,24 +"pas_northstar_cluster","TITAN_NORTHSTAR_PASSIVE","#GEAR_NORTHSTAR_CLUSTER","#GEAR_NORTHSTAR_CLUSTER_DESC","#GEAR_NORTHSTAR_CLUSTER_LONGDESC","rui/titan_loadout/passive/northstar_enhanced_payload",0,24 +"pas_northstar_trap","TITAN_NORTHSTAR_PASSIVE","#GEAR_NORTHSTAR_TRAP","#GEAR_NORTHSTAR_TRAP_DESC","#GEAR_NORTHSTAR_TRAP_LONGDESC","rui/titan_loadout/passive/northstar_twin_trap",0,24 +"pas_northstar_flightcore","TITAN_NORTHSTAR_PASSIVE","#GEAR_NORTHSTAR_FLIGHTCORE","#GEAR_NORTHSTAR_FLIGHTCORE_DESC","#GEAR_NORTHSTAR_FLIGHTCORE_LONGDESC","rui/titan_loadout/passive/northstar_viper_thrusters",0,24 +"pas_scorch_firewall","TITAN_SCORCH_PASSIVE","#GEAR_SCORCH_FIREWALL","#GEAR_SCORCH_FIREWALL_DESC","#GEAR_SCORCH_FIREWALL_LONGDESC","rui/titan_loadout/passive/scorch_fuel",0,24 +"pas_scorch_shield","TITAN_SCORCH_PASSIVE","#GEAR_SCORCH_SHIELD","#GEAR_SCORCH_SHIELD_DESC","#GEAR_SCORCH_SHIELD_LONGDESC","rui/titan_loadout/passive/scorch_inferno_shield",0,24 +"pas_scorch_selfdmg","TITAN_SCORCH_PASSIVE","#GEAR_SCORCH_SELFDMG","#GEAR_SCORCH_SELFDMG_DESC","#GEAR_SCORCH_SELFDMG_LONGDESC","rui/titan_loadout/passive/scorch_tempered_plating",0,24 +"pas_legion_spinup","TITAN_LEGION_PASSIVE","#GEAR_LEGION_SPINUP","#GEAR_LEGION_SPINUP_DESC","#GEAR_LEGION_SPINUP_LONGDESC","rui/titan_loadout/passive/legion_lightweight_alloys",0,24 +"pas_legion_gunshield","TITAN_LEGION_PASSIVE","#GEAR_LEGION_GUNSHIELD","#GEAR_LEGION_GUNSHIELD_DESC","#GEAR_LEGION_GUNSHIELD_LONGDESC","rui/titan_loadout/passive/legion_bulwark",0,24 +"pas_legion_smartcore","TITAN_LEGION_PASSIVE","#GEAR_LEGION_SMARTCORE","#GEAR_LEGION_SMARTCORE_DESC","#GEAR_LEGION_SMARTCORE_LONGDESC","rui/titan_loadout/passive/legion_sensor_array",0,24 +"pas_ion_weapon_ads","TITAN_ION_PASSIVE","#GEAR_ION_SPLIT","#GEAR_ION_SPLIT_DESC","#GEAR_ION_SPLIT_LONGDESC","rui/titan_loadout/passive/ion_diffraction_lens",0,24 +"pas_tone_burst","TITAN_TONE_PASSIVE","#GEAR_TONE_BURST","#GEAR_TONE_BURST_DESC","#GEAR_TONE_BURST_LONGDESC","rui/titan_loadout/passive/tone_40mm_burst",0,24 +"pas_legion_chargeshot","TITAN_LEGION_PASSIVE","#GEAR_LEGION_CHARGESHOT","#GEAR_LEGION_CHARGESHOT_DESC","#GEAR_LEGION_CHARGESHOT_LONGDESC","rui/titan_loadout/passive/legion_siege_mode",0,24 +"pas_ronin_autoshift","TITAN_RONIN_PASSIVE","#GEAR_RONIN_AUTOSHIFT","#GEAR_RONIN_AUTOSHIFT_DESC","#GEAR_RONIN_AUTOSHIFT_LONGDESC","rui/titan_loadout/passive/ronin_auto_shift",0,24 +"pas_northstar_optics","TITAN_NORTHSTAR_PASSIVE","#GEAR_NORTHSTAR_OPTICS","#GEAR_NORTHSTAR_OPTICS_DESC","#GEAR_NORTHSTAR_OPTICS_LONGDESC","rui/titan_loadout/passive/northstar_threat_optics",0,24 +"pas_scorch_flamecore","TITAN_SCORCH_PASSIVE","#GEAR_SCORCH_FLAMECORE","#GEAR_SCORCH_FLAMECORE_DESC","#GEAR_SCORCH_FLAMECORE_LONGDESC","rui/titan_loadout/passive/scorch_scorched_earth",0,24 +"pas_vanguard_coremeter","TITAN_VANGUARD_PASSIVE","#GEAR_VANGUARD_COREMETER","#GEAR_VANGUARD_COREMETER_DESC","#GEAR_VANGUARD_COREMETER_LONGDESC","rui/titan_loadout/passive/vanguard_siphon",0,24 +"pas_vanguard_shield","TITAN_VANGUARD_PASSIVE","#GEAR_VANGUARD_SHIELD","#GEAR_VANGUARD_SHIELD_DESC","#GEAR_VANGUARD_SHIELD_LONGDESC","rui/titan_loadout/passive/vanguard_survivor",0,24 +"pas_vanguard_rearm","TITAN_VANGUARD_PASSIVE","#GEAR_VANGUARD_REARM","#GEAR_VANGUARD_REARM_DESC","#GEAR_VANGUARD_REARM_LONGDESC","rui/titan_loadout/passive/vanguard_rearm",0,24 +"pas_vanguard_doom","TITAN_VANGUARD_PASSIVE","#GEAR_VANGUARD_DOOM","#GEAR_VANGUARD_DOOM_DESC","#GEAR_VANGUARD_DOOM_LONGDESC","rui/titan_loadout/passive/vanguard_fittest",0,24 +"pas_vanguard_core1","TITAN_UPGRADE1_PASSIVE","#GEAR_VANGUARD_CORE1","#GEAR_VANGUARD_CORE1_DESC","#GEAR_VANGUARD_CORE1_LONGDESC","rui/titan_loadout/passive/monarch_core_arc_rounds",0,24 +"pas_vanguard_core2","TITAN_UPGRADE1_PASSIVE","#GEAR_VANGUARD_CORE2","#GEAR_VANGUARD_CORE2_DESC","#GEAR_VANGUARD_CORE2_LONGDESC","rui/titan_loadout/passive/monarch_core_missile_racks",0,24 +"pas_vanguard_core3","TITAN_UPGRADE1_PASSIVE","#GEAR_VANGUARD_CORE3","#GEAR_VANGUARD_CORE3_DESC","#GEAR_VANGUARD_CORE3_LONGDESC","rui/titan_loadout/passive/monarch_core_energy_field",0,24 +"pas_vanguard_core4","TITAN_UPGRADE2_PASSIVE","#GEAR_VANGUARD_CORE4","#GEAR_VANGUARD_CORE4_DESC","#GEAR_VANGUARD_CORE4_LONGDESC","rui/titan_loadout/passive/monarch_core_swift_rearm",0,24 +"pas_vanguard_core5","TITAN_UPGRADE2_PASSIVE","#GEAR_VANGUARD_CORE5","#GEAR_VANGUARD_CORE5_DESC","#GEAR_VANGUARD_CORE5_LONGDESC","rui/titan_loadout/passive/monarch_core_maelstrom",0,24 +"pas_vanguard_core6","TITAN_UPGRADE2_PASSIVE","#GEAR_VANGUARD_CORE6","#GEAR_VANGUARD_CORE6_DESC","#GEAR_VANGUARD_CORE6_LONGDESC","rui/titan_loadout/passive/monarch_core_energy_transfer",0,24 +"pas_vanguard_core7","TITAN_UPGRADE3_PASSIVE","#GEAR_VANGUARD_CORE7","#GEAR_VANGUARD_CORE7_DESC","#GEAR_VANGUARD_CORE7_LONGDESC","rui/titan_loadout/passive/monarch_core_multi_target",0,24 +"pas_vanguard_core8","TITAN_UPGRADE3_PASSIVE","#GEAR_VANGUARD_CORE8","#GEAR_VANGUARD_CORE8_DESC","#GEAR_VANGUARD_CORE8_LONGDESC","rui/titan_loadout/passive/monarch_core_superior_chassis",0,24 +"pas_vanguard_core9","TITAN_UPGRADE3_PASSIVE","#GEAR_VANGUARD_CORE9","#GEAR_VANGUARD_CORE9_DESC","#GEAR_VANGUARD_CORE9_LONGDESC","rui/titan_loadout/passive/monarch_core_xo16",0,24 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods.csv new file mode 100644 index 00000000..d25cc30d --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods.csv @@ -0,0 +1 @@ +mod,weapon,statDamage,statAccuracy,statRange,statFireRate,statClipSize,hidden \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods_common.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods_common.csv new file mode 100644 index 00000000..e4659a7e --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_mods_common.csv @@ -0,0 +1 @@ +mod,name,description,image \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_primary_weapons.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_weapons.csv new file mode 100644 index 00000000..c617d653 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_primary_weapons.csv @@ -0,0 +1,10 @@ +itemRef,hidden,defaultMod2,hidden +"mp_titanweapon_leadwall",0,"",0 +"mp_titanweapon_meteor",0,"",0 +"mp_titanweapon_particle_accelerator",0,"",0 +"mp_titanweapon_predator_cannon",0,"",0 +"mp_titanweapon_sniper",0,"",0 +"mp_titanweapon_sticky_40mm",0,"",0 +"mp_titanweapon_xo16_shorty",1,"",0 +"mp_titanweapon_rocketeer_rocketstream",1,"",0 +"mp_titanweapon_xo16_vanguard",0,"",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_properties.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_properties.csv new file mode 100644 index 00000000..4b9369ca --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_properties.csv @@ -0,0 +1,10 @@ +setFile,primeSetFile,titanRef,primeTitanRef,titanLoadoutInSP,mp_npcUseAllowed,difficulty,coreBuildingIcon,coreReadyIcon,hintIcon,loadoutIcon,loadoutIconFD,fdRole,desc,speedDisplay,damageDisplay,healthDisplay,dashDisplay,primary,melee,ordnance,special,antirodeo,coreAbility,passive1,passive2,passive3,passive4,passive5,passive6,titanExecution,bossCharacter,hidden,menuItem,menuTitle,menuSubTitle,menuLongDesc,menuFlavorText,dialogHint,weaponImage +"titan_buddy","","bt","",1,0,1,"rui\titan_loadout\core\titan_core_burst_core","rui\titan_loadout\core\titan_core_burst_core","rui\menu\common\bulb_hint_icon","rui/menu/postgame/vanguard_icon","rui/menu/fd_menu/fd_icon_monarch","#FD_ROLE_MONARCH","#MP_TITAN_LOADOUT_DESC_XO16",2,1,2,2,"mp_titanweapon_xo16_shorty","melee_titan_punch","mp_titanweapon_shoulder_rockets","mp_titanweapon_vortex_shield","mp_titanability_smoke","mp_titancore_amp_core","TITAN_GENERAL_PASSIVE","TITAN_GENERAL_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","","",1,"#SP_TITAN_LOADOUT_MENUITEM_XO16","#SP_TITAN_LOADOUT_TITLE_XO16","#SP_TITAN_LOADOUT_SUBTITLE_XO16","#SP_TITAN_LOADOUT_DESC_XO16","#SP_TITAN_LOADOUT_FLAVOR_XO16","diag_sp_extra_GB101_47_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_x016_shorty" +"titan_atlas_tracker","titan_atlas_tone_prime","tone","tone_prime",1,1,2,"rui\titan_loadout\core\titan_core_salvo","rui\titan_loadout\core\titan_core_salvo","rui\menu\common\bulb_hint_icon","rui/menu/postgame/tone_icon","rui/menu/fd_menu/fd_icon_tone","#FD_ROLE_TONE","#MP_TITAN_LOADOUT_DESC_TONE",2,2,2,1,"mp_titanweapon_sticky_40mm","melee_titan_punch_tone","mp_titanweapon_tracker_rockets","mp_titanability_particle_wall","mp_titanability_sonar_pulse","mp_titancore_salvo_core","TITAN_GENERAL_PASSIVE","TITAN_TONE_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_TONE_EXECUTION","Richter",0,"#SP_TITAN_LOADOUT_MENUITEM_TONE","#SP_TITAN_LOADOUT_TITLE_TONE","#SP_TITAN_LOADOUT_SUBTITLE_TONE","#SP_TITAN_LOADOUT_DESC_TONE","#SP_TITAN_LOADOUT_FLAVOR_TONE","diag_sp_extra_GB101_37_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_40mm" +"titan_ogre_meteor","titan_ogre_scorch_prime","scorch","scorch_prime",1,1,3,"rui\titan_loadout\core\titan_core_flame_wave","rui\titan_loadout\core\titan_core_flame_wave","rui\menu\common\bulb_hint_icon","rui/menu/postgame/scorch_icon","rui/menu/fd_menu/fd_icon_scorch","#FD_ROLE_SCORCH","#MP_TITAN_LOADOUT_DESC_SCORCH",1,3,3,0,"mp_titanweapon_meteor","melee_titan_punch_scorch","mp_titanweapon_flame_wall","mp_titanweapon_heat_shield","mp_titanability_slow_trap","mp_titancore_flame_wave","TITAN_GENERAL_PASSIVE","TITAN_SCORCH_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_SCORCH_EXECUTION","Kane",0,"#SP_TITAN_LOADOUT_MENUITEM_SCORCH","#SP_TITAN_LOADOUT_TITLE_SCORCH","#SP_TITAN_LOADOUT_SUBTITLE_SCORCH","#SP_TITAN_LOADOUT_DESC_SCORCH","#SP_TITAN_LOADOUT_FLAVOR_SCORCH","diag_sp_extra_GB101_33_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_meteor" +"titan_stryder_rocketeer","","brute4","",1,0,1,"rui\titan_loadout\core\titan_core_flight","rui\titan_loadout\core\titan_core_flight","rui\menu\common\bulb_hint_icon","rui/menu/postgame/northstar_icon","rui/menu/fd_menu/fd_icon_northstar","#FD_ROLE_NORTHSTAR","#MP_TITAN_LOADOUT_DESC_BRUTE",3,2,1,2,"mp_titanweapon_rocketeer_rocketstream","melee_titan_punch","mp_titanweapon_shoulder_rockets","mp_titanweapon_vortex_shield","mp_titanability_hover","mp_titancore_flight_core","TITAN_GENERAL_PASSIVE","TITAN_GENERAL_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","","",0,"#SP_TITAN_LOADOUT_MENUITEM_BRUTE","#SP_TITAN_LOADOUT_TITLE_BRUTE","#SP_TITAN_LOADOUT_SUBTITLE_BRUTE","#SP_TITAN_LOADOUT_DESC_BRUTE","#SP_TITAN_LOADOUT_FLAVOR_BRUTE","diag_sp_extra_GB101_47_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_rocketeer" +"titan_atlas_stickybomb","titan_atlas_ion_prime","ion","ion_prime",1,1,1,"rui\titan_loadout\core\titan_core_laser","rui\titan_loadout\core\titan_core_laser","rui\menu\common\bulb_hint_icon","rui/menu/postgame/ion_icon","rui/menu/fd_menu/fd_icon_ion","#FD_ROLE_ION","#MP_TITAN_LOADOUT_DESC_ION",2,1,2,1,"mp_titanweapon_particle_accelerator","melee_titan_punch_ion","mp_titanweapon_laser_lite","mp_titanweapon_vortex_shield_ion","mp_titanability_laser_trip","mp_titancore_laser_cannon","TITAN_GENERAL_PASSIVE","TITAN_ION_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_ION_EXECUTION","Slone",0,"#SP_TITAN_LOADOUT_MENUITEM_ION","#SP_TITAN_LOADOUT_TITLE_ION","#SP_TITAN_LOADOUT_SUBTITLE_ION","#SP_TITAN_LOADOUT_DESC_ION","#SP_TITAN_LOADOUT_FLAVOR_ION","diag_sp_extra_GB101_34_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_particle_accelerator" +"titan_stryder_leadwall","titan_stryder_ronin_prime","ronin","ronin_prime",1,1,3,"rui\titan_loadout\core\titan_core_sword","rui\titan_loadout\core\titan_core_sword","rui\menu\common\bulb_hint_icon","rui/menu/postgame/ronin_icon","rui/menu/fd_menu/fd_icon_ronin","#FD_ROLE_RONIN","#MP_TITAN_LOADOUT_DESC_RONIN",3,2,1,2,"mp_titanweapon_leadwall","melee_titan_sword","mp_titanweapon_arc_wave","mp_titanability_basic_block","mp_titanability_phase_dash","mp_titancore_shift_core","TITAN_GENERAL_PASSIVE","TITAN_RONIN_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_RONIN_EXECUTION","Ash",0,"#SP_TITAN_LOADOUT_MENUITEM_RONIN","#SP_TITAN_LOADOUT_TITLE_RONIN","#SP_TITAN_LOADOUT_SUBTITLE_RONIN","#SP_TITAN_LOADOUT_DESC_RONIN","#SP_TITAN_LOADOUT_FLAVOR_RONIN","diag_sp_extra_GB101_35_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_leadwall" +"titan_stryder_sniper","titan_stryder_northstar_prime","northstar","northstar_prime",1,1,2,"rui\titan_loadout\core\titan_core_flight","rui\titan_loadout\core\titan_core_flight","rui\menu\common\bulb_hint_icon","rui/menu/postgame/northstar_icon","rui/menu/fd_menu/fd_icon_northstar","#FD_ROLE_NORTHSTAR","#MP_TITAN_LOADOUT_DESC_NORTHSTAR",3,3,1,2,"mp_titanweapon_sniper","melee_titan_punch_northstar","mp_titanweapon_dumbfire_rockets","mp_titanability_tether_trap","mp_titanability_hover","mp_titancore_flight_core","TITAN_GENERAL_PASSIVE","TITAN_NORTHSTAR_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_NORTHSTAR_EXECUTION","Viper",0,"#SP_TITAN_LOADOUT_MENUITEM_NORTHSTAR","#SP_TITAN_LOADOUT_TITLE_NORTHSTAR","#SP_TITAN_LOADOUT_SUBTITLE_NORTHSTAR","#SP_TITAN_LOADOUT_DESC_NORTHSTAR","#SP_TITAN_LOADOUT_FLAVOR_NORTHSTAR","diag_sp_extra_GB101_36_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_sniper" +"titan_ogre_minigun","titan_ogre_legion_prime","legion","legion_prime",1,1,2,"rui\titan_loadout\core\titan_core_smart","rui\titan_loadout\core\titan_core_smart","rui\menu\common\bulb_hint_icon","rui/menu/postgame/legion_icon","rui/menu/fd_menu/fd_icon_legion","#FD_ROLE_LEGION","#MP_TITAN_LOADOUT_DESC_LEGION",1,3,3,0,"mp_titanweapon_predator_cannon","melee_titan_punch_legion","mp_titanability_power_shot","mp_titanability_gun_shield","mp_titanability_ammo_swap","mp_titancore_siege_mode","TITAN_GENERAL_PASSIVE","TITAN_LEGION_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_LEGION_EXECUTION","Blisk",0,"#SP_TITAN_LOADOUT_MENUITEM_LEGION","#SP_TITAN_LOADOUT_TITLE_LEGION","#SP_TITAN_LOADOUT_SUBTITLE_LEGION","#SP_TITAN_LOADOUT_DESC_LEGION","#SP_TITAN_LOADOUT_FLAVOR_LEGION","diag_sp_extra_GB101_32_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_predator" +"titan_atlas_vanguard","","vanguard","vanguard_prime",0,1,3,"rui\titan_loadout\core\titan_core_smart","rui\titan_loadout\core\titan_core_smart","rui\menu\common\bulb_hint_icon","rui/menu/postgame/vanguard_icon","rui/menu/fd_menu/fd_icon_monarch","#FD_ROLE_MONARCH","#MP_TITAN_LOADOUT_DESC_VANGUARD",2,2,2,1,"mp_titanweapon_xo16_vanguard","melee_titan_punch_vanguard","mp_titanweapon_salvo_rockets","mp_titanweapon_stun_laser","mp_titanability_rearm","mp_titancore_upgrade","TITAN_GENERAL_PASSIVE","TITAN_VANGUARD_PASSIVE","TITAN_TITANFALL_PASSIVE","TITAN_UPGRADE1_PASSIVE","TITAN_UPGRADE2_PASSIVE","TITAN_UPGRADE3_PASSIVE","TITAN_VANGUARD_EXECUTION","Richter",0,"#SP_TITAN_LOADOUT_MENUITEM_TONE","#SP_TITAN_LOADOUT_TITLE_TONE","#SP_TITAN_LOADOUT_SUBTITLE_TONE","#SP_TITAN_LOADOUT_DESC_TONE","#SP_TITAN_LOADOUT_FLAVOR_TONE","diag_sp_extra_GB101_37_01_mcor_bt","rui\titan_loadout\loadout_select\ls_wep_ttn_40mm" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_skins.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_skins.csv new file mode 100644 index 00000000..da8b3172 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_skins.csv @@ -0,0 +1,56 @@ +ref,titanRef,image,name,cost,skinIndex +"ion_skin_01","ion","rui/titan_loadout/skins/ion_skin_01","#ION_SKIN_01",0,1 +"ion_skin_02","ion","rui/titan_loadout/skins/ion_skin_02","#ION_SKIN_02",0,3 +"ion_skin_03","ion","rui/titan_loadout/skins/ion_skin_03","#ION_SKIN_03",500,4 +"ion_skin_04","ion","rui/titan_loadout/skins/ion_skin_04","#ION_SKIN_04",0,5 +"ion_skin_06","ion","rui/titan_loadout/skins/ion_skin_06","#ION_SKIN_06",0,6 +"scorch_skin_01","scorch","rui/titan_loadout/skins/scorch_skin_01","#SCORCH_SKIN_01",0,1 +"scorch_skin_02","scorch","rui/titan_loadout/skins/scorch_skin_02","#SCORCH_SKIN_02",0,3 +"scorch_skin_03","scorch","rui/titan_loadout/skins/scorch_skin_03","#SCORCH_SKIN_03",0,4 +"scorch_skin_04","scorch","rui/titan_loadout/skins/scorch_skin_04","#SCORCH_SKIN_04",0,5 +"ronin_skin_01","ronin","rui/titan_loadout/skins/ronin_skin_01","#RONIN_SKIN_01",0,1 +"ronin_skin_02","ronin","rui/titan_loadout/skins/ronin_skin_02","#RONIN_SKIN_02",0,3 +"ronin_skin_03","ronin","rui/titan_loadout/skins/ronin_skin_03","#RONIN_SKIN_03",0,4 +"ronin_skin_04","ronin","rui/titan_loadout/skins/ronin_skin_04","#RONIN_SKIN_04",0,5 +"tone_skin_01","tone","rui/titan_loadout/skins/tone_skin_01","#TONE_SKIN_01",0,1 +"tone_skin_02","tone","rui/titan_loadout/skins/tone_skin_02","#TONE_SKIN_02",0,3 +"tone_skin_03","tone","rui/titan_loadout/skins/tone_skin_03","#TONE_SKIN_03",0,4 +"tone_skin_04","tone","rui/titan_loadout/skins/tone_skin_04","#TONE_SKIN_04",0,5 +"northstar_skin_01","northstar","rui/titan_loadout/skins/northstar_skin_01","#NORTHSTAR_SKIN_01",0,1 +"northstar_skin_02","northstar","rui/titan_loadout/skins/northstar_skin_02","#NORTHSTAR_SKIN_02",0,3 +"northstar_skin_03","northstar","rui/titan_loadout/skins/northstar_skin_03","#NORTHSTAR_SKIN_03",0,4 +"northstar_skin_04","northstar","rui/titan_loadout/skins/northstar_skin_04","#NORTHSTAR_SKIN_04",0,5 +"legion_skin_01","legion","rui/titan_loadout/skins/legion_skin_01","#LEGION_SKIN_01",0,1 +"legion_skin_02","legion","rui/titan_loadout/skins/legion_skin_02","#LEGION_SKIN_02",0,3 +"legion_skin_03","legion","rui/titan_loadout/skins/legion_skin_03","#LEGION_SKIN_03",0,4 +"legion_skin_04","legion","rui/titan_loadout/skins/legion_skin_04","#LEGION_SKIN_04",0,5 +"ion_skin_10","ion","rui/titan_loadout/skins/ion_skin_10","#ION_SKIN_10",0,7 +"tone_skin_06","tone","rui/titan_loadout/skins/tone_skin_06","#TONE_SKIN_06",0,6 +"scorch_skin_07","scorch","rui/titan_loadout/skins/scorch_skin_07","#SCORCH_SKIN_07",0,6 +"ronin_skin_10","ronin","rui/titan_loadout/skins/ronin_skin_10","#RONIN_SKIN_10",0,6 +"northstar_skin_10","northstar","rui/titan_loadout/skins/northstar_skin_10","#NORTHSTAR_SKIN_10",0,6 +"legion_skin_07","legion","rui/titan_loadout/skins/legion_skin_07","#LEGION_SKIN_07",0,6 +"ion_skin_11","ion","rui/titan_loadout/skins/ion_skin_11","#ION_SKIN_11",0,8 +"tone_skin_07","tone","rui/titan_loadout/skins/tone_skin_07","#TONE_SKIN_07",0,7 +"scorch_skin_08","scorch","rui/titan_loadout/skins/scorch_skin_08","#SCORCH_SKIN_08",0,7 +"ronin_skin_11","ronin","rui/titan_loadout/skins/ronin_skin_11","#RONIN_SKIN_11",0,7 +"northstar_skin_11","northstar","rui/titan_loadout/skins/northstar_skin_11","#NORTHSTAR_SKIN_11",0,7 +"legion_skin_08","legion","rui/titan_loadout/skins/legion_skin_08","#LEGION_SKIN_08",0,7 +"vanguard_skin_01","vanguard","rui/titan_loadout/skins/legion_skin_01","#LEGION_SKIN_01",0,1 +"vanguard_skin_02","vanguard","rui/titan_loadout/skins/legion_skin_02","#LEGION_SKIN_02",0,3 +"vanguard_skin_03","vanguard","rui/titan_loadout/skins/legion_skin_03","#LEGION_SKIN_03",0,4 +"vanguard_skin_07","vanguard","rui/titan_loadout/skins/legion_skin_07","#LEGION_SKIN_07",0,6 +"vanguard_skin_08","vanguard","rui/titan_loadout/skins/legion_skin_08","#LEGION_SKIN_08",0,7 +"northstar_skin_06","northstar","rui/titan_loadout/skins/northstar_skin_06","#NORTHSTAR_SKIN_06",0,8 +"ronin_skin_07","ronin","rui/titan_loadout/skins/ronin_skin_07","#RONIN_SKIN_07",0,8 +"scorch_skin_06","scorch","rui/titan_loadout/skins/scorch_skin_06","#SCORCH_SKIN_06",0,8 +"ion_skin_07","ion","rui/titan_loadout/skins/ion_skin_07","#ION_SKIN_07",0,9 +"legion_skin_09","legion","rui/titan_loadout/skins/legion_skin_09","#LEGION_SKIN_09",0,8 +"tone_skin_08","tone","rui/titan_loadout/skins/tone_skin_08","#TONE_SKIN_08",0,8 +"northstar_skin_fd","northstar","rui/titan_loadout/skins/northstar_skin_fd","#NORTHSTAR_SKIN_FD",0,9 +"ronin_skin_fd","ronin","rui/titan_loadout/skins/ronin_skin_fd","#RONIN_SKIN_FD",0,9 +"scorch_skin_fd","scorch","rui/titan_loadout/skins/scorch_skin_fd","#SCORCH_SKIN_FD",0,9 +"ion_skin_fd","ion","rui/titan_loadout/skins/ion_skin_fd","#ION_SKIN_FD",0,10 +"legion_skin_fd","legion","rui/titan_loadout/skins/legion_skin_fd","#LEGION_SKIN_FD",0,9 +"tone_skin_fd","tone","rui/titan_loadout/skins/tone_skin_fd","#TONE_SKIN_FD",0,9 +"monarch_skin_fd","vanguard","rui/titan_loadout/skins/monarch_skin_fd","#MONARCH_SKIN_FD",0,3 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titan_voices.csv b/Northstar.CustomServers/mod/scripts/datatable/titan_voices.csv new file mode 100644 index 00000000..8a762f9b --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titan_voices.csv @@ -0,0 +1,9 @@ +weapon,name,description,image,hidden +"titanos_bt","#TITAN_OS_BT_NAME","#TITAN_OS_BT_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_legion","#TITAN_OS_LEGION_NAME","#TITAN_OS_LEGION_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_scorch","#TITAN_OS_SCORCH_NAME","#TITAN_OS_SCORCH_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_ronin","#TITAN_OS_RONIN_NAME","#TITAN_OS_RONIN_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_northstar","#TITAN_OS_NORTHSTAR_NAME","#TITAN_NORTHSTAR_BETTY_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_ion","#TITAN_OS_ION_NAME","#TITAN_OS_ION_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_tone","#TITAN_OS_TONE_NAME","#TITAN_OS_TONE_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 +"titanos_vanguard","#TITAN_OS_VANGUARD_NAME","#TITAN_OS_VANGUARD_LONGDESC","material/ui/menu/voice_personality_icons/betty_voice_icon_gen.rpak",0 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/titans_mp.csv b/Northstar.CustomServers/mod/scripts/datatable/titans_mp.csv new file mode 100644 index 00000000..a0873690 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/titans_mp.csv @@ -0,0 +1,8 @@ +titanRef,cost,coreIcon,image +"ion",5,"rui/titan_loadout/core/titan_core_laser","rui/menu/postgame/ion_icon" +"scorch",5,"rui/titan_loadout/core/titan_core_flame_wave","rui/menu/postgame/scorch_icon" +"northstar",5,"rui/titan_loadout/core/titan_core_flight","rui/menu/postgame/northstar_icon" +"ronin",10,"rui/titan_loadout/core/titan_core_sword","rui/menu/postgame/ronin_icon" +"tone",15,"rui/titan_loadout/core/titan_core_salvo","rui/menu/postgame/tone_icon" +"legion",20,"rui/titan_loadout/core/titan_core_smart","rui/menu/postgame/legion_icon" +"vanguard",200,"rui/titan_loadout/core/titan_core_vanguard","rui/menu/postgame/vanguard_icon" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_faction_level.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_faction_level.csv new file mode 100644 index 00000000..6f9fa4c1 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_faction_level.csv @@ -0,0 +1,82 @@ +factionLevel,faction_apex,faction_64,faction_vinson,faction_marauder,faction_aces,faction_ares,faction_marvin +0,"faction_apex","faction_64","faction_vinson","faction_marauder","faction_aces","faction_ares","faction_marvin" +1,"","","","","","","" +2,"gc_icon_dollarsign,random","gc_icon_fox,random ","gc_icon_gear,random ","gc_icon_prowler,random ","gc_icon_ace,random","gc_icon_radar,random","gc_icon_mrvn,random" +3,"random,callsign_06_col","random,callsign_96_col","random,callsign_05_col","random,callsign_46_col","random,callsign_01_col","random,callsign_41_col","random,callsign_163_col" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random,callsign_06_col_fire","random,callsign_96_col_fire","random,callsign_05_col_fire","random,callsign_46_col_fire","random,callsign_01_col_fire","random,callsign_41_col_fire","random,callsign_163_col_fire" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random,callsign_06_col_gold","random,callsign_96_col_gold","random,callsign_05_col_gold","random,callsign_46_col_gold","random,callsign_01_col_gold","random,callsign_41_col_gold","random,callsign_163_col_gold" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random,callsign_163_col_prism" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random,callsign_164_col" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random,callsign_164_col_fire" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random,callsign_164_col_gold" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random,callsign_164_col_prism" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" +1,"random","random","random","random","random","random","random" +2,"random","random","random","random","random","random","random" +3,"random","random","random","random","random","random","random" +4,"random","random","random","random","random","random","random" +5,"random","random","random","random","random","random","random" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_fd_titan_level.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_fd_titan_level.csv new file mode 100644 index 00000000..957af6d6 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_fd_titan_level.csv @@ -0,0 +1,26 @@ +titanLevel,ion,scorch,northstar,ronin,tone,legion,vanguard,end +"","ion","scorch","northstar","ronin","tone","legion","vanguard","END" +"1","","","","","","","","" +"2","fd_upgrade_ion_weapon_tier_2","fd_upgrade_scorch_weapon_tier_1","fd_upgrade_northstar_utility_tier_1","fd_upgrade_ronin_weapon_tier_1","fd_upgrade_tone_weapon_tier_1","fd_upgrade_legion_weapon_tier_1","fd_upgrade_vanguard_utility_tier_1","" +"3","random","random","random","random","random","random","random","" +"4","random","random","random","random","random","random","random","" +"5","fd_upgrade_ion_defense_tier_1","fd_upgrade_scorch_defense_tier_1","fd_upgrade_northstar_defense_tier_1","fd_upgrade_ronin_defense_tier_1","fd_upgrade_tone_defense_tier_1","fd_upgrade_legion_defense_tier_1","fd_upgrade_vanguard_defense_tier_1","" +"6","random","random","random","random","random","random","random","" +"7","random","random","random","random","random","random","random","" +"8","fd_upgrade_ion_utility_tier_2","fd_upgrade_scorch_utility_tier_1","fd_upgrade_northstar_weapon_tier_1","fd_upgrade_ronin_utility_tier_1","fd_upgrade_tone_utility_tier_2","fd_upgrade_legion_utility_tier_1","fd_upgrade_vanguard_weapon_tier_1","" +"9","random","random","random","random","random","random","random","" +"10","random","random","random","random","random","random","random","" +"11","fd_upgrade_ion_weapon_tier_1","fd_upgrade_scorch_utility_tier_2","fd_upgrade_northstar_utility_tier_2","fd_upgrade_ronin_weapon_tier_2","fd_upgrade_tone_weapon_tier_2","fd_upgrade_legion_weapon_tier_2","fd_upgrade_vanguard_utility_tier_2","" +"12","random","random","random","random","random","random","random","" +"13","random","random","random","random","random","random","random","" +"14","fd_upgrade_ion_defense_tier_2","fd_upgrade_scorch_defense_tier_2","fd_upgrade_northstar_defense_tier_2","fd_upgrade_ronin_defense_tier_2","fd_upgrade_tone_defense_tier_2","fd_upgrade_legion_defense_tier_2","fd_upgrade_vanguard_defense_tier_2","" +"15","random","random","random","random","random","random","random","" +"16","random","random","random","random","random","random","random","" +"17","fd_upgrade_ion_utility_tier_1","fd_upgrade_scorch_weapon_tier_2","fd_upgrade_northstar_weapon_tier_2","fd_upgrade_ronin_utility_tier_2","fd_upgrade_tone_utility_tier_1","fd_upgrade_legion_utility_tier_2","fd_upgrade_vanguard_weapon_tier_2","" +"18","random","random","random","random","random","random","random","" +"19","random","random","random","random","random","random","random","" +"20","fd_upgrade_ion_ultimate","fd_upgrade_scorch_ultimate","fd_upgrade_northstar_ultimate","fd_upgrade_ronin_ultimate","fd_upgrade_tone_ultimate","fd_upgrade_legion_ultimate","fd_upgrade_vanguard_ultimate","" +"21","random","random","random","random","random","random","random","" +"22","random","random","random","random","random","random","random","" +"23","random","random","random","random","random","random","random","" +"24","callsign_24_col_prism","callsign_47_col_prism","callsign_36_col_prism","callsign_45_col_prism","callsign_68_col_prism","callsign_26_col_prism","callsign_165_col_prism","" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_player_level.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_player_level.csv new file mode 100644 index 00000000..693bcc15 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_player_level.csv @@ -0,0 +1,996 @@ +playerLevel,pilotWeapons,pilotOffhands,pilotKits,pilotTactical,titanChassis,burnCard,feature,callSign,callsignIcon,pilotExecutions,pilotCamo,factions,random +1,"mp_weapon_rspn101_og, mp_weapon_rspn101,mp_weapon_car,mp_weapon_lmg,mp_weapon_shotgun,mp_weapon_sniper,mp_weapon_smr,mp_weapon_semipistol,mp_weapon_autopistol,mp_weapon_defender,mp_weapon_mgl,mp_weapon_wingman_n","mp_weapon_frag_grenade,mp_weapon_grenade_emp,mp_weapon_thermite_grenade","pas_enemy_death_icons,pas_wallhang,pas_fast_health_regen,pas_power_cell","mp_ability_grapple,mp_ability_cloak,mp_weapon_grenade_sonar,mp_ability_shifter_super,grapple,geist,medium","ion,scorch,northstar","burnmeter_amped_weapons","cp,ctf,lts,ffa,fw,ps,tdm,at,aitdm,lf,communities,happy_hour, pilot_loadout_1, pilot_loadout_2, pilot_loadout_3, pilot_loadout_4, pilot_loadout_5, pilot_loadout_6,hunted,mfd,fd_easy,fd_normal","callsign_16_col","gc_icon_titanfall","execution_neck_snap","pilot_camo_skin00","faction_marauder","" +2,"mp_weapon_lstar","","","","","","","","","","","","" +3,"","","","mp_ability_heal,nomad","","","","","","","","","" +4,"","","","","","","coliseum","","","","","","" +5,"mp_weapon_epg","","","","","","","callsign_53_col","","","","","" +6,"","","","","","burnmeter_ticks","","","","","","","" +7,"","","","","ronin","","","","","","","","" +8,"mp_weapon_alternator_smg","","","","","","","","","","","","" +9,"","mp_weapon_grenade_gravity","","","","","","","","","","","" +10,"mp_weapon_shotgun_pistol","","","","","","","","","","pilot_camo_skin01","","" +11,"","","","","tone","","","","","","","","" +12,"","","","","","","","","","","","faction_apex","" +13,"mp_weapon_hemlok","","","","","","","","","","","","" +14,"","","","mp_weapon_deployable_cover,heavy","","","","","","","","","" +15,"","","","","legion","","","callsign_67_col","","","","","" +16,"mp_weapon_doubletake","","","","","","","","","","","","" +17,"","","","","","burnmeter_ap_turret_weapon","","","","","","","" +18,"","","pas_ordnance_pack","","","","","","","","","","" +19,"mp_weapon_mastiff","","","","","","","","","","","","" +20,"","","","","vanguard","","pilot_loadout_7","","","","pilot_camo_skin03","faction_vinson","" +21,"mp_weapon_arc_launcher","","","","","","","","","","","","" +22,"","mp_weapon_grenade_electric_smoke","","","","","","","","","","","" +23,"","","","","","burnmeter_maphack","","","","","","","" +24,"mp_weapon_esaw","","","","","","","","","","","","" +25,"","","pas_ads_hover","","","","","callsign_100_col","","","","","" +26,"","","","mp_ability_shifter,light","","","","","","","","","" +27,"mp_weapon_hemlok_smg","","","","","","","","","","","","" +28,"","","","","","burnmeter_emergency_battery","","","","","","","" +29,"","","pas_fast_embark","","","","","","","","","","" +30,"mp_weapon_softball","","","","","","pilot_loadout_8","","","","pilot_camo_skin02","","" +31,"","","","","","burnmeter_radar_jammer","","","","","","","" +32,"mp_weapon_wingman","","","","","","","","","","","","" +33,"","","","","","","","","","","","faction_aces","" +34,"","","","","","burnmeter_at_turret_weapon","","","","","","","" +35,"mp_weapon_g2","","","","","","","callsign_09_col","","","","","" +36,"","","","mp_ability_holopilot,stalker","","","","","","","","","" +37,"","mp_weapon_satchel","","","","","","","","","","","" +38,"mp_weapon_dmr","","","","","","","","","","","","" +39,"","","","","","","","","","","","faction_64","" +40,"","","pas_stealth_movement","","","","pilot_loadout_9","","","","pilot_camo_skin97","","" +41,"mp_weapon_r97","","","","","","","","","","","","" +42,"","","","","","burnmeter_smart_pistol","","","","","","","" +43,"mp_weapon_rocket_launcher","","","","","","","","","","","","" +44,"","","","","","burnmeter_phase_rewind","","","","","","","" +45,"mp_weapon_pulse_lmg","","","","","","","callsign_70_col","","","","","" +46,"","","","","","burnmeter_hard_cover","","","","","","","" +47,"mp_weapon_vinson","","","","","","","","","","","","" +48,"","","","","","burnmeter_holopilot_nova","","","","","","","" +49,"","","pas_at_hunter","","","","","","","","","faction_ares","" +50,"","","","","","burnmeter_random_foil","pilot_loadout_10","","gc_icon_gen0","","pilot_camo_skin24","faction_marvin","" +1,"","","","","","","","callsign_35_col","gc_icon_gen1","","pilot_camo_skin16","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","callsign_53_col_fire","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","callsign_67_col_fire","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","callsign_100_col_fire","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","pilot_camo_skin25","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","callsign_09_col_fire","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","callsign_70_col_fire","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_07_col","gc_icon_gen2","","pilot_camo_skin14","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","callsign_53_col_gold","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","callsign_67_col_gold","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","callsign_100_col_gold","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","pilot_camo_skin26","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","callsign_09_col_gold","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","callsign_70_col_gold","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_34_col","gc_icon_gen3","","pilot_camo_skin83","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","pilot_camo_skin27","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_39_col","gc_icon_gen4","","pilot_camo_skin31","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","pilot_camo_skin19","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_16_col_fire","gc_icon_gen5","","pilot_camo_skin82","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_35_col_fire","gc_icon_sgt_major,gc_icon_gen6","","pilot_camo_skin15","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_07_col_fire","gc_icon_gen7","","pilot_camo_skin17","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_34_col_fire","gc_icon_gen8","","pilot_camo_skin81","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","callsign_39_col_fire","gc_icon_gen9","","pilot_camo_skin18","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","callsign_16_col_gold,callsign_35_col_gold,callsign_07_col_gold,callsign_34_col_gold,callsign_39_col_gold","","","pilot_camo_skin30","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" +46,"","","","","","","","","","","","","" +47,"","","","","","","","","","","","","" +48,"","","","","","","","","","","","","" +49,"","","","","","","","","","","","","" +50,"","","","","","","","","","","","","" +1,"","","","","","","","","","","","","" +2,"","","","","","","","","","","","","" +3,"","","","","","","","","","","","","" +4,"","","","","","","","","","","","","" +5,"","","","","","","","","","","","","random" +6,"","","","","","","","","","","","","" +7,"","","","","","","","","","","","","" +8,"","","","","","","","","","","","","" +9,"","","","","","","","","","","","","" +10,"","","","","","","","","","","","","" +11,"","","","","","","","","","","","","" +12,"","","","","","","","","","","","","" +13,"","","","","","","","","","","","","" +14,"","","","","","","","","","","","","" +15,"","","","","","","","","","","","","random" +16,"","","","","","","","","","","","","" +17,"","","","","","","","","","","","","" +18,"","","","","","","","","","","","","" +19,"","","","","","","","","","","","","" +20,"","","","","","","","","","","","","" +21,"","","","","","","","","","","","","" +22,"","","","","","","","","","","","","" +23,"","","","","","","","","","","","","" +24,"","","","","","","","","","","","","" +25,"","","","","","","","","","","","","random" +26,"","","","","","","","","","","","","" +27,"","","","","","","","","","","","","" +28,"","","","","","","","","","","","","" +29,"","","","","","","","","","","","","" +30,"","","","","","","","","","","","","" +31,"","","","","","","","","","","","","" +32,"","","","","","","","","","","","","" +33,"","","","","","","","","","","","","" +34,"","","","","","","","","","","","","" +35,"","","","","","","","","","","","","random" +36,"","","","","","","","","","","","","" +37,"","","","","","","","","","","","","" +38,"","","","","","","","","","","","","" +39,"","","","","","","","","","","","","" +40,"","","","","","","","","","","","","" +41,"","","","","","","","","","","","","" +42,"","","","","","","","","","","","","" +43,"","","","","","","","","","","","","" +44,"","","","","","","","","","","","","" +45,"","","","","","","","","","","","","random" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_random.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_random.csv new file mode 100644 index 00000000..b35f17af --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_random.csv @@ -0,0 +1,359 @@ +ref,weight +"callsign_02_col",15.000000 +"callsign_08_col",15.000000 +"callsign_10_col",15.000000 +"callsign_12_col",15.000000 +"callsign_17_col",15.000000 +"callsign_20_col",15.000000 +"callsign_25_col",15.000000 +"callsign_28_col",15.000000 +"callsign_32_col",15.000000 +"callsign_43_col",15.000000 +"callsign_44_col",15.000000 +"callsign_49_col",15.000000 +"callsign_50_col",15.000000 +"callsign_52_col",15.000000 +"callsign_54_col",15.000000 +"callsign_56_col",15.000000 +"callsign_58_col",15.000000 +"callsign_60_col",15.000000 +"callsign_61_col",15.000000 +"callsign_62_col",15.000000 +"callsign_63_col",15.000000 +"callsign_64_col",15.000000 +"callsign_71_col",15.000000 +"callsign_72_col",15.000000 +"callsign_73_col",15.000000 +"callsign_74_col",15.000000 +"callsign_77_col",15.000000 +"callsign_80_col",15.000000 +"callsign_81_col",15.000000 +"callsign_82_col",15.000000 +"callsign_83_col",15.000000 +"callsign_84_col",15.000000 +"callsign_85_col",15.000000 +"callsign_86_col",15.000000 +"callsign_87_col",15.000000 +"callsign_88_col",15.000000 +"callsign_89_col",15.000000 +"callsign_90_col",15.000000 +"callsign_91_col",15.000000 +"callsign_93_col",15.000000 +"callsign_95_col",15.000000 +"callsign_98_col",15.000000 +"callsign_101_col",15.000000 +"callsign_102_col",15.000000 +"callsign_02_col_prism",3.000000 +"callsign_08_col_prism",3.000000 +"callsign_10_col_prism",3.000000 +"callsign_12_col_prism",3.000000 +"callsign_17_col_prism",3.000000 +"callsign_20_col_prism",3.000000 +"callsign_25_col_prism",3.000000 +"callsign_28_col_prism",3.000000 +"callsign_32_col_prism",3.000000 +"callsign_43_col_prism",3.000000 +"callsign_44_col_prism",3.000000 +"callsign_49_col_prism",3.000000 +"callsign_50_col_prism",3.000000 +"callsign_52_col_prism",3.000000 +"callsign_54_col_prism",3.000000 +"callsign_56_col_prism",3.000000 +"callsign_58_col_prism",3.000000 +"callsign_60_col_prism",3.000000 +"callsign_61_col_prism",3.000000 +"callsign_62_col_prism",3.000000 +"callsign_63_col_prism",3.000000 +"callsign_64_col_prism",3.000000 +"callsign_71_col_prism",3.000000 +"callsign_72_col_prism",3.000000 +"callsign_73_col_prism",3.000000 +"callsign_74_col_prism",3.000000 +"callsign_77_col_prism",3.000000 +"callsign_80_col_prism",3.000000 +"callsign_81_col_prism",3.000000 +"callsign_82_col_prism",3.000000 +"callsign_83_col_prism",3.000000 +"callsign_84_col_prism",3.000000 +"callsign_85_col_prism",3.000000 +"callsign_86_col_prism",3.000000 +"callsign_87_col_prism",3.000000 +"callsign_88_col_prism",3.000000 +"callsign_89_col_prism",3.000000 +"callsign_90_col_prism",3.000000 +"callsign_91_col_prism",3.000000 +"callsign_93_col_prism",3.000000 +"callsign_95_col_prism",3.000000 +"callsign_98_col_prism",3.000000 +"callsign_101_col_prism",3.000000 +"callsign_102_col_prism",3.000000 +"execution_backshot",3.000000 +"execution_combo",3.000000 +"execution_knockout",3.000000 +"credit_award",50.000000 +"coliseum_ticket",35.000000 +"northstar.northstar_nose_art_12",5.000000 +"northstar.northstar_nose_art_13",5.000000 +"ronin.ronin_nose_art_08",5.000000 +"ronin.ronin_nose_art_12",5.000000 +"tone.tone_nose_art_11",5.000000 +"tone.tone_nose_art_12",5.000000 +"scorch.scorch_nose_art_12",5.000000 +"legion.legion_nose_art_12",5.000000 +"legion.legion_nose_art_14",5.000000 +"camo_skin04",5.000000 +"camo_skin05",5.000000 +"camo_skin06",5.000000 +"camo_skin11",5.000000 +"camo_skin12",5.000000 +"camo_skin20",5.000000 +"camo_skin21",5.000000 +"camo_skin22",5.000000 +"camo_skin23",5.000000 +"camo_skin28",5.000000 +"camo_skin29",5.000000 +"camo_skin32",5.000000 +"camo_skin33",5.000000 +"camo_skin34",5.000000 +"camo_skin35",5.000000 +"camo_skin36",5.000000 +"camo_skin37",5.000000 +"camo_skin38",5.000000 +"camo_skin39",5.000000 +"camo_skin40",5.000000 +"camo_skin41",5.000000 +"camo_skin42",5.000000 +"camo_skin43",5.000000 +"camo_skin44",5.000000 +"camo_skin45",5.000000 +"camo_skin46",5.000000 +"camo_skin47",5.000000 +"camo_skin48",5.000000 +"camo_skin49",5.000000 +"camo_skin50",5.000000 +"camo_skin51",5.000000 +"camo_skin52",5.000000 +"camo_skin53",5.000000 +"camo_skin54",5.000000 +"camo_skin68",5.000000 +"camo_skin69",5.000000 +"camo_skin70",5.000000 +"camo_skin71",5.000000 +"camo_skin72",5.000000 +"camo_skin73",5.000000 +"camo_skin74",5.000000 +"camo_skin75",5.000000 +"camo_skin76",5.000000 +"camo_skin77",5.000000 +"camo_skin78",5.000000 +"camo_skin79",5.000000 +"camo_skin80",5.000000 +"camo_skin84",5.000000 +"camo_skin86",5.000000 +"camo_skin88",5.000000 +"camo_skin89",5.000000 +"camo_skin90",5.000000 +"camo_skin95",5.000000 +"camo_skin96",5.000000 +"camo_skin98",5.000000 +"camo_skin99",5.000000 +"pilot_camo_skin04",10.000000 +"pilot_camo_skin05",10.000000 +"pilot_camo_skin06",10.000000 +"pilot_camo_skin11",10.000000 +"pilot_camo_skin12",10.000000 +"pilot_camo_skin20",10.000000 +"pilot_camo_skin21",10.000000 +"pilot_camo_skin22",10.000000 +"pilot_camo_skin23",10.000000 +"pilot_camo_skin28",10.000000 +"pilot_camo_skin29",10.000000 +"pilot_camo_skin32",10.000000 +"pilot_camo_skin33",10.000000 +"pilot_camo_skin34",10.000000 +"pilot_camo_skin35",10.000000 +"pilot_camo_skin36",10.000000 +"pilot_camo_skin37",10.000000 +"pilot_camo_skin38",10.000000 +"pilot_camo_skin39",10.000000 +"pilot_camo_skin40",10.000000 +"pilot_camo_skin41",10.000000 +"pilot_camo_skin42",10.000000 +"pilot_camo_skin43",10.000000 +"pilot_camo_skin44",10.000000 +"pilot_camo_skin45",10.000000 +"pilot_camo_skin46",10.000000 +"pilot_camo_skin47",10.000000 +"pilot_camo_skin48",10.000000 +"pilot_camo_skin49",10.000000 +"pilot_camo_skin50",10.000000 +"pilot_camo_skin51",10.000000 +"pilot_camo_skin52",10.000000 +"pilot_camo_skin53",10.000000 +"pilot_camo_skin54",10.000000 +"pilot_camo_skin68",10.000000 +"pilot_camo_skin69",10.000000 +"pilot_camo_skin70",10.000000 +"pilot_camo_skin71",10.000000 +"pilot_camo_skin72",10.000000 +"pilot_camo_skin73",10.000000 +"pilot_camo_skin74",10.000000 +"pilot_camo_skin75",10.000000 +"pilot_camo_skin76",10.000000 +"pilot_camo_skin77",10.000000 +"pilot_camo_skin78",10.000000 +"pilot_camo_skin79",10.000000 +"pilot_camo_skin80",10.000000 +"pilot_camo_skin84",10.000000 +"pilot_camo_skin86",10.000000 +"pilot_camo_skin88",10.000000 +"pilot_camo_skin89",10.000000 +"pilot_camo_skin90",10.000000 +"pilot_camo_skin95",10.000000 +"pilot_camo_skin96",10.000000 +"pilot_camo_skin98",10.000000 +"pilot_camo_skin99",10.000000 +"titan_camo_skin04",10.000000 +"titan_camo_skin05",10.000000 +"titan_camo_skin06",10.000000 +"titan_camo_skin11",10.000000 +"titan_camo_skin12",10.000000 +"titan_camo_skin20",10.000000 +"titan_camo_skin21",10.000000 +"titan_camo_skin22",10.000000 +"titan_camo_skin23",10.000000 +"titan_camo_skin28",10.000000 +"titan_camo_skin29",10.000000 +"titan_camo_skin32",10.000000 +"titan_camo_skin33",10.000000 +"titan_camo_skin34",10.000000 +"titan_camo_skin35",10.000000 +"titan_camo_skin36",10.000000 +"titan_camo_skin37",10.000000 +"titan_camo_skin38",10.000000 +"titan_camo_skin39",10.000000 +"titan_camo_skin40",10.000000 +"titan_camo_skin41",10.000000 +"titan_camo_skin42",10.000000 +"titan_camo_skin43",10.000000 +"titan_camo_skin44",10.000000 +"titan_camo_skin45",10.000000 +"titan_camo_skin46",10.000000 +"titan_camo_skin47",10.000000 +"titan_camo_skin48",10.000000 +"titan_camo_skin49",10.000000 +"titan_camo_skin50",10.000000 +"titan_camo_skin51",10.000000 +"titan_camo_skin52",10.000000 +"titan_camo_skin53",10.000000 +"titan_camo_skin54",10.000000 +"titan_camo_skin68",10.000000 +"titan_camo_skin69",10.000000 +"titan_camo_skin70",10.000000 +"titan_camo_skin71",10.000000 +"titan_camo_skin72",10.000000 +"titan_camo_skin73",10.000000 +"titan_camo_skin74",10.000000 +"titan_camo_skin75",10.000000 +"titan_camo_skin76",10.000000 +"titan_camo_skin77",10.000000 +"titan_camo_skin78",10.000000 +"titan_camo_skin79",10.000000 +"titan_camo_skin80",10.000000 +"titan_camo_skin84",10.000000 +"titan_camo_skin86",10.000000 +"titan_camo_skin88",10.000000 +"titan_camo_skin89",10.000000 +"titan_camo_skin90",10.000000 +"titan_camo_skin95",10.000000 +"titan_camo_skin96",10.000000 +"titan_camo_skin98",10.000000 +"titan_camo_skin99",10.000000 +"gc_icon_5star",15.000000 +"gc_icon_angryface",15.000000 +"gc_icon_bear",15.000000 +"gc_icon_bee",15.000000 +"gc_icon_bigcat",15.000000 +"gc_icon_bird",15.000000 +"gc_icon_bunnyskull",15.000000 +"gc_icon_chicken",15.000000 +"gc_icon_club",15.000000 +"gc_icon_corporal",15.000000 +"gc_icon_cow",15.000000 +"gc_icon_cupcake",15.000000 +"gc_icon_dataknife",15.000000 +"gc_icon_doublerainbow",15.000000 +"gc_icon_dragon",15.000000 +"gc_icon_earthworm",15.000000 +"gc_icon_fair_warning",15.000000 +"gc_icon_falcon",15.000000 +"gc_icon_fingerprint",15.000000 +"gc_icon_flying_skull",15.000000 +"gc_icon_ghostface",15.000000 +"gc_icon_hamburger",15.000000 +"gc_icon_hammer",15.000000 +"gc_icon_handprint",15.000000 +"gc_icon_hawkmoth",15.000000 +"gc_icon_heartless",15.000000 +"gc_icon_hvt",15.000000 +"gc_icon_jollyrgr",15.000000 +"gc_icon_knife",15.000000 +"gc_icon_lol",15.000000 +"gc_icon_mad_hat",15.000000 +"gc_icon_marksman",15.000000 +"gc_icon_omg",15.000000 +"gc_icon_ordnance",15.000000 +"gc_icon_pizza",15.000000 +"gc_icon_pvt",15.000000 +"gc_icon_question",15.000000 +"gc_icon_rainbow",15.000000 +"gc_icon_ram",15.000000 +"gc_icon_respawn",15.000000 +"gc_icon_saturn",15.000000 +"gc_icon_scorpion",15.000000 +"gc_icon_senior_sgt_e6",15.000000 +"gc_icon_senior_sgt",15.000000 +"gc_icon_sgt",15.000000 +"gc_icon_skull",15.000000 +"gc_icon_snake",15.000000 +"gc_icon_stab",15.000000 +"gc_icon_teabage",15.000000 +"gc_icon_widow",15.000000 +"gc_icon_witch_hat",15.000000 +"gc_icon_wizard_hat",15.000000 +"gc_icon_wraith",15.000000 +"gc_icon_wtf",15.000000 +"gc_icon_down",35.000000 +"gc_icon_joy",35.000000 +"execution_face_stab",1.000000 +"ion.ion_skin_03",1.000000 +"camo_skin08",1.000000 +"pilot_camo_skin08",1.000000 +"titan_camo_skin08",1.000000 +"ion.ion_nose_art_05",1.000000 +"callsign_tt_gameover",10.000000 +"callsign_tt_gameover_prism",1.000000 +"callsign_tt_guardtheflag",10.000000 +"callsign_tt_guardtheflag_prism",1.000000 +"callsign_tt_megamarvin",10.000000 +"callsign_tt_megamarvin_prism",1.000000 +"callsign_tt_nessievault",10.000000 +"callsign_tt_nessievault_prism",1.000000 +"callsign_tt_nsbt",10.000000 +"callsign_tt_nsbt_prism",1.000000 +"callsign_tt_protocol2",10.000000 +"callsign_tt_protocol2_prism",1.000000 +"callsign_tt_rekt",10.000000 +"callsign_tt_rekt_prism",1.000000 +"callsign_tt_titantoons",10.000000 +"callsign_tt_titantoons_prism",1.000000 +"callsign_eat_ion",1.000000 +"callsign_eat_legion",1.000000 +"callsign_eat_northstar",1.000000 +"callsign_eat_ronin",1.000000 +"callsign_eat_scorch",1.000000 +"callsign_eat_tone",1.000000 +"callsign_126_col_prism",1.000000 +"callsign_127_col_prism",1.000000 +"callsign_130_col_prism",1.000000 +"callsign_131_col_prism",1.000000 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_titan_level.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_titan_level.csv new file mode 100644 index 00000000..24f54fea --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_titan_level.csv @@ -0,0 +1,402 @@ +titanLevel,ion,scorch,northstar,ronin,tone,legion,vanguard,end +"","ion","scorch","northstar","ronin","tone","legion","vanguard","END" +"1","pas_ion_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,ion_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_0,execution_ion,execution_ion_prime","pas_scorch_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,scorch_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_1,execution_scorch,execution_scorch_prime","pas_northstar_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,northstar_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_2,execution_northstar,execution_northstar_prime","pas_ronin_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,ronin_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_3,execution_ronin,execution_ronin_prime","pas_tone_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,tone_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_4,execution_tone,execution_tone_prime","pas_legion_weapon,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,titan_camo_skin00,camo_skin00,legion_nose_art_none,pas_vanguard_core1, pas_vanguard_core4,pas_vanguard_core7,execution_random_5,execution_legion,execution_legion_prime","pas_vanguard_shield,pas_mobility_dash_capacity,pas_enhanced_titan_ai,pas_auto_eject,pas_bubbleshield,pas_vanguard_core1,pas_vanguard_core4,pas_vanguard_core7,titan_camo_skin00,camo_skin00,vanguard_nose_art_none,execution_random_6,execution_vanguard","" +"2","pas_hyper_core","pas_hyper_core","pas_hyper_core","pas_hyper_core","pas_hyper_core","pas_hyper_core","pas_hyper_core","" +"3","pas_build_up_nuclear_core","pas_build_up_nuclear_core","pas_build_up_nuclear_core","pas_build_up_nuclear_core","pas_build_up_nuclear_core","pas_build_up_nuclear_core","pas_vanguard_core2,pas_build_up_nuclear_core","" +"4","pas_anti_rodeo,ion_nose_art_14","pas_anti_rodeo,scorch_nose_art_11","pas_anti_rodeo,northstar_nose_art_11","pas_anti_rodeo,ronin_nose_art_14","pas_anti_rodeo,tone_nose_art_13","pas_anti_rodeo,legion_nose_art_13","pas_anti_rodeo,vanguard_nose_art_01","" +"5","pas_warpfall,random","pas_warpfall,random","pas_warpfall,random","pas_warpfall,random","pas_warpfall,random","pas_warpfall,random","pas_warpfall,pas_vanguard_core5,random","" +"6","pas_ion_tripwire,titan_camo_skin01","pas_scorch_selfdmg,titan_camo_skin01","pas_northstar_cluster,titan_camo_skin01","pas_ronin_arcwave,titan_camo_skin01","pas_tone_wall,titan_camo_skin01","pas_legion_smartcore,titan_camo_skin01","pas_vanguard_coremeter,titan_camo_skin01","" +"7","pas_ion_vortex","pas_scorch_shield","pas_northstar_trap","pas_ronin_phase","pas_tone_sonar","pas_legion_gunshield","pas_vanguard_core8,pas_vanguard_rearm","" +"8","pas_ion_lasercannon,camo_skin01","pas_scorch_firewall,camo_skin01","pas_northstar_flightcore,camo_skin01","pas_ronin_swordcore,camo_skin01","pas_tone_rockets,camo_skin01","pas_legion_spinup,camo_skin01","pas_vanguard_core3,pas_vanguard_doom,camo_skin01","" +"9","titan_camo_skin03,pas_ion_weapon_ads","titan_camo_skin03,pas_scorch_flamecore","titan_camo_skin03,pas_northstar_optics","titan_camo_skin03,pas_ronin_autoshift","titan_camo_skin03,pas_tone_burst","titan_camo_skin03,pas_legion_chargeshot","titan_camo_skin03,pas_vanguard_core6","" +"10","gc_icon_cateye,ion_nose_art_01","gc_icon_fireball,scorch_nose_art_02","gc_icon_stinger,northstar_nose_art_08","gc_icon_sword,ronin_nose_art_02","gc_icon_crosshair,tone_nose_art_14","gc_icon_bullet,legion_nose_art_09","gc_icon_monarch,vanguard_nose_art_02,pas_vanguard_core9","" +"11","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","" +"12","titan_camo_skin02","titan_camo_skin02","titan_camo_skin02","titan_camo_skin02","titan_camo_skin02","titan_camo_skin02","titan_camo_skin02","" +"13","","","","","","","","" +"14","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","" +"15","titan_camo_skin97","titan_camo_skin97","titan_camo_skin97","titan_camo_skin97","titan_camo_skin97","titan_camo_skin97","titan_camo_skin97","" +"16","","","","","","","","" +"17","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","" +"18","titan_camo_skin24","titan_camo_skin24","titan_camo_skin24","titan_camo_skin24","titan_camo_skin24","titan_camo_skin24","titan_camo_skin24","" +"19","","","","","","","","" +"20","camo_skin24,ion_nose_art_08","camo_skin24,scorch_nose_art_03","camo_skin24,northstar_nose_art_06","camo_skin24,ronin_nose_art_11","camo_skin24,tone_nose_art_04","camo_skin24,legion_nose_art_06","camo_skin24,vanguard_nose_art_03","" +"1","titan_camo_skin16,callsign_24_col","titan_camo_skin16,callsign_47_col","titan_camo_skin16,callsign_36_col","titan_camo_skin16,callsign_45_col","titan_camo_skin16,callsign_68_col","titan_camo_skin16,callsign_26_col","titan_camo_skin16,callsign_165_col","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","camo_skin16","camo_skin16","camo_skin16","camo_skin16","camo_skin16","camo_skin16","camo_skin16","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","titan_camo_skin25","titan_camo_skin25","titan_camo_skin25","titan_camo_skin25","titan_camo_skin25","titan_camo_skin25","titan_camo_skin25","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_04","scorch_nose_art_05","northstar_nose_art_04","ronin_nose_art_05","tone_nose_art_03","legion_nose_art_03","vanguard_nose_art_04","" +"1","titan_camo_skin14,callsign_24_col_fire","titan_camo_skin14,callsign_47_col_fire","titan_camo_skin14,callsign_36_col_fire","titan_camo_skin14,callsign_45_col_fire","titan_camo_skin14,callsign_68_col_fire","titan_camo_skin14,callsign_26_col_fire","titan_camo_skin14,callsign_165_col_fire","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","titan_camo_skin26","titan_camo_skin26","titan_camo_skin26","titan_camo_skin26","titan_camo_skin26","titan_camo_skin26","titan_camo_skin26","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_03","scorch_nose_art_01","northstar_nose_art_01","ronin_nose_art_06","tone_nose_art_07","legion_nose_art_10","vanguard_nose_art_05","" +"1","titan_camo_skin83,callsign_24_col_gold","titan_camo_skin83,callsign_47_col_gold","titan_camo_skin83,callsign_36_col_gold","titan_camo_skin83,callsign_45_col_gold","titan_camo_skin83,callsign_68_col_gold","titan_camo_skin83,callsign_26_col_gold","titan_camo_skin83,callsign_165_col_gold","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","titan_camo_skin27","titan_camo_skin27","titan_camo_skin27","titan_camo_skin27","titan_camo_skin27","titan_camo_skin27","titan_camo_skin27","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_12","scorch_nose_art_13","northstar_nose_art_09","ronin_nose_art_04","tone_nose_art_02","legion_nose_art_02","vanguard_nose_art_06","" +"1","titan_camo_skin31","titan_camo_skin31","titan_camo_skin31","titan_camo_skin31","titan_camo_skin31","titan_camo_skin31","titan_camo_skin31","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","titan_camo_skin19","titan_camo_skin19","titan_camo_skin19","titan_camo_skin19","titan_camo_skin19","titan_camo_skin19","titan_camo_skin19","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_13","scorch_nose_art_10","northstar_nose_art_03","ronin_nose_art_09","tone_nose_art_09","legion_nose_art_01","vanguard_nose_art_07","" +"1","titan_camo_skin82","titan_camo_skin82","titan_camo_skin82","titan_camo_skin82","titan_camo_skin82","titan_camo_skin82","titan_camo_skin82","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","titan_camo_skin15","titan_camo_skin15","titan_camo_skin15","titan_camo_skin15","titan_camo_skin15","titan_camo_skin15","titan_camo_skin15","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_02","scorch_nose_art_04","northstar_nose_art_02","ronin_nose_art_01","tone_nose_art_01","legion_nose_art_08","","" +"1","titan_camo_skin17","titan_camo_skin17","titan_camo_skin17","titan_camo_skin17","titan_camo_skin17","titan_camo_skin17","titan_camo_skin17","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_06","scorch_nose_art_14","northstar_nose_art_10","ronin_nose_art_13","tone_nose_art_05","legion_nose_art_11","vanguard_nose_art_08","" +"1","titan_camo_skin81","titan_camo_skin81","titan_camo_skin81","titan_camo_skin81","titan_camo_skin81","titan_camo_skin81","titan_camo_skin81","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_11","scorch_nose_art_09","northstar_nose_art_05","ronin_nose_art_10","tone_nose_art_08","legion_nose_art_04","","" +"1","titan_camo_skin18","titan_camo_skin18","titan_camo_skin18","titan_camo_skin18","titan_camo_skin18","titan_camo_skin18","titan_camo_skin18","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_10","scorch_nose_art_08","northstar_nose_art_14","ronin_nose_art_03","tone_nose_art_06","legion_nose_art_05","vanguard_nose_art_09","" +"1","titan_camo_skin30","titan_camo_skin30","titan_camo_skin30","titan_camo_skin30","titan_camo_skin30","titan_camo_skin30","titan_camo_skin30","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","ion_nose_art_09","","","","","","","" +"1","","","","","","","","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" +"1","random","random","random","random","random","random","random","" +"2","","","","","","","","" +"3","","","","","","","","" +"4","","","","","","","","" +"5","","","","","","","","" +"6","","","","","","","","" +"7","","","","","","","","" +"8","","","","","","","","" +"9","","","","","","","","" +"10","","","","","","","","" +"11","","","","","","","","" +"12","","","","","","","","" +"13","","","","","","","","" +"14","","","","","","","","" +"15","","","","","","","","" +"16","","","","","","","","" +"17","","","","","","","","" +"18","","","","","","","","" +"19","","","","","","","","" +"20","","","","","","","","" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/unlocks_weapon_level_pilot.csv b/Northstar.CustomServers/mod/scripts/datatable/unlocks_weapon_level_pilot.csv new file mode 100644 index 00000000..5c881ac5 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/unlocks_weapon_level_pilot.csv @@ -0,0 +1,383 @@ +weaponLevel,weap1,weap2,weap3,weap4,weap5,weap6,weap7,weap8,weap9,weap10,weap11,weap12,weap13,weap14,weap15,weap16,weap17,weap18,weap19,weap20,weap21,weap22,weap23,weap24,weap25,weap26,weap27,weap28,weap29,weap30,end +"","mp_weapon_alternator_smg","mp_weapon_arc_launcher","mp_weapon_autopistol","mp_weapon_car","mp_weapon_defender","mp_weapon_dmr","mp_weapon_doubletake","mp_weapon_epg","mp_weapon_esaw","mp_weapon_g2","mp_weapon_hemlok","mp_weapon_hemlok_smg","mp_weapon_lmg","mp_weapon_lstar","mp_weapon_mastiff","mp_weapon_mgl","mp_weapon_pulse_lmg","mp_weapon_r97","mp_weapon_rocket_launcher","mp_weapon_rspn101","mp_weapon_semipistol","mp_weapon_shotgun","mp_weapon_shotgun_pistol","mp_weapon_smr","mp_weapon_sniper","mp_weapon_softball","mp_weapon_vinson","mp_weapon_wingman","mp_weapon_wingman_n","mp_weapon_rspn101_og","END" +"1","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","camo_skin00, pro_screen","" +"2","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","extended_ammo","" +"3","hcog","pas_fast_reload","silencer","holosight","quick_charge","scope_4x","scope_4x","pas_run_and_gun","aog","hcog","hcog","holosight","aog","aog","holosight","pas_fast_reload","pas_run_and_gun","holosight","pas_fast_reload","hcog","silencer","holosight","silencer","pas_run_and_gun","scope_4x","pas_run_and_gun","hcog","silencer","ricochet","hcog","" +"4","pas_run_and_gun","pas_fast_ads","pas_run_and_gun","pas_run_and_gun","pas_fast_ads","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_fast_ads","pas_fast_reload","pas_run_and_gun","pas_fast_ads","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","pas_run_and_gun","" +"5","pas_fast_reload","pas_fast_swap","pas_fast_reload","pas_fast_reload","pas_fast_swap","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_swap","pas_fast_ads","pas_fast_reload","pas_fast_swap","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_reload","pas_fast_reload","pas_fast_reload","pas_fast_reload","" +"6","redline_sight","secondarymod2","pas_fast_ads","redline_sight","secondarymod2","pas_fast_swap","pas_fast_swap","pas_fast_swap","redline_sight","redline_sight","redline_sight","redline_sight","redline_sight","redline_sight","redline_sight","secondarymod2","pas_fast_swap","redline_sight","secondarymod2","redline_sight","pas_fast_ads","redline_sight","pas_fast_ads","pas_fast_swap","pas_fast_swap","pas_fast_swap","redline_sight","pas_fast_ads","pas_fast_ads","redline_sight","" +"7","pas_fast_ads","","tactical_cdr_on_kill","pas_fast_ads","","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_ads","pas_fast_ads","","tactical_cdr_on_kill","pas_fast_ads","","pas_fast_ads","tactical_cdr_on_kill","pas_fast_ads","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","pas_fast_ads","tactical_cdr_on_kill","tactical_cdr_on_kill","pas_fast_ads","" +"8","pas_fast_swap,random","random","secondarymod2,random","pas_fast_swap,random","random","threat_scope,random","threat_scope,random","random,primarymod2","pas_fast_swap,random","pas_fast_swap,random","pas_fast_swap,random","pas_fast_swap,random","pas_fast_swap,random","pas_fast_swap,random","pas_fast_swap,random","random","primarymod2,random","pas_fast_swap,random","random","pas_fast_swap,random","secondarymod2,random","pas_fast_swap,random","primarymod2,random","primarymod2,random","threat_scope,random","primarymod2,random","pas_fast_swap,random","secondarymod2,random","primarymod2,random","pas_fast_swap,random","" +"9","tactical_cdr_on_kill","","","tactical_cdr_on_kill","","primarymod2","ricochet","","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","tactical_cdr_on_kill","","","tactical_cdr_on_kill","","tactical_cdr_on_kill","","tactical_cdr_on_kill","","","ricochet","","tactical_cdr_on_kill","","","tactical_cdr_on_kill","" +"10","threat_scope,camo_skin01","camo_skin01","camo_skin01","threat_scope,camo_skin01","camo_skin01","camo_skin01","primarymod2,camo_skin01","camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","threat_scope,camo_skin01","camo_skin01","camo_skin01","threat_scope,camo_skin01","camo_skin01","threat_scope,camo_skin01","camo_skin01","threat_scope,camo_skin01","camo_skin01","camo_skin01","primarymod2,camo_skin01","camo_skin01","threat_scope,camo_skin01","camo_skin01","camo_skin01","threat_scope,camo_skin01","" +"11","primarymod2","","","primarymod2","","","","","primarymod2","primarymod2","primarymod2","primarymod2","primarymod2","primarymod2","primarymod2","","","primarymod2","","primarymod2","","primarymod2","","","","","primarymod2","","","primarymod2","" +"12","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","camo_skin03","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","camo_skin02","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","camo_skin97","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","camo_skin24","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","gc_icon_yuckface","gc_icon_raincloud","gc_icon_diamond","gc_icon_wasp","gc_icon_bullseye","gc_icon_fin","gc_icon_dice","gc_icon_comet","gc_icon_heart","gc_icon_ramskull","gc_icon_waves","gc_icon_lightning","gc_icon_hawk","gc_icon_star","gc_icon_paw","gc_icon_frag","gc_icon_moon","gc_icon_assault","gc_icon_rocket","gc_icon_atom","gc_icon_spade","gc_icon_8ball","gc_icon_clawmark","gc_icon_bomb_02","gc_icon_happyface","gc_icon_bomb_01","gc_icon_medic","gc_icon_dragonfly","gc_icon_b3_wing","gc_icon_mushroom","" +"1","primarymod3,camo_skin16","secondarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","secondarymod3,camo_skin16","primarymod3,camo_skin16","primarymod3,camo_skin16","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","callsign_13_col","callsign_76_col","callsign_29_col","callsign_55_col","callsign_66_col","callsign_30_col","callsign_21_col","callsign_94_col","callsign_15_col","callsign_31_col","callsign_40_col","callsign_18_col","callsign_27_col","callsign_22_col","callsign_48_col","callsign_42_col","callsign_78_col","callsign_75_col","callsign_92_col","callsign_03_col","callsign_37_col","callsign_79_col","callsign_51_col","callsign_11_col","callsign_57_col","callsign_59_col","callsign_69_col","callsign_19_col","callsign_139_col","callsign_128_col","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","camo_skin25","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","camo_skin14","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","callsign_13_col_fire","callsign_76_col_fire","callsign_29_col_fire","callsign_55_col_fire","callsign_66_col_fire","callsign_30_col_fire","callsign_21_col_fire","callsign_94_col_fire","callsign_15_col_fire","callsign_31_col_fire","callsign_40_col_fire","callsign_18_col_fire","callsign_27_col_fire","callsign_22_col_fire","callsign_48_col_fire","callsign_42_col_fire","callsign_78_col_fire","callsign_75_col_fire","callsign_92_col_fire","callsign_03_col_fire","callsign_37_col_fire","callsign_79_col_fire","callsign_51_col_fire","callsign_11_col_fire","callsign_57_col_fire","callsign_59_col_fire","callsign_69_col_fire","callsign_19_col_fire","callsign_139_col_fire","callsign_128_col_fire","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","camo_skin26","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","camo_skin83","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","callsign_13_col_gold","callsign_76_col_gold","callsign_29_col_gold","callsign_55_col_gold","callsign_66_col_gold","callsign_30_col_gold","callsign_21_col_gold","callsign_94_col_gold","callsign_15_col_gold","callsign_31_col_gold","callsign_40_col_gold","callsign_18_col_gold","callsign_27_col_gold","callsign_22_col_gold","callsign_48_col_gold","callsign_42_col_gold","callsign_78_col_gold","callsign_75_col_gold","callsign_92_col_gold","callsign_03_col_gold","callsign_37_col_gold","callsign_79_col_gold","callsign_51_col_gold","callsign_11_col_gold","callsign_57_col_gold","callsign_59_col_gold","callsign_69_col_gold","callsign_19_col_gold","callsign_139_col_gold","callsign_128_col_gold","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","camo_skin27","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","camo_skin31","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","camo_skin19","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","camo_skin82","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","camo_skin15","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","camo_skin17","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","camo_skin81","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","camo_skin18","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","camo_skin30","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" +"2","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"3","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"4","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"5","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"6","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"7","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"8","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"9","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"10","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"11","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"12","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"14","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"15","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"16","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"17","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"18","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"19","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"20","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +"1","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","random","" \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/weapon_skins.csv b/Northstar.CustomServers/mod/scripts/datatable/weapon_skins.csv new file mode 100644 index 00000000..0f074882 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/weapon_skins.csv @@ -0,0 +1,35 @@ +ref,weaponRef,image,name,cost,skinIndex,skinType +"skin_rspn101_wasteland","mp_weapon_rspn101","rui/weapon_skin_swatches/swatch_wasteland","#SKIN_WASTELAND",0,8,1 +"skin_g2_masterwork","mp_weapon_g2","rui/weapon_skin_swatches/swatch_masterwork","#SKIN_MASTERWORK",0,6,1 +"skin_vinson_blue_fade","mp_weapon_vinson","rui/weapon_skin_swatches/swatch_blue_fade","#SKIN_BLUE_FADE",0,7,1 +"skin_car_crimson_fury","mp_weapon_car","rui/weapon_skin_swatches/swatch_crimson_fury","#SKIN_CRIMSON_FURY",0,6,1 +"skin_alternator_patriot","mp_weapon_alternator_smg","rui/weapon_skin_swatches/swatch_patriot","#SKIN_PATRIOT",0,2,1 +"skin_shotgun_badlands","mp_weapon_shotgun","rui/weapon_skin_swatches/swatch_badlands","#SKIN_BADLANDS",0,4,1 +"skin_wingman_aqua_fade","mp_weapon_wingman","rui/weapon_skin_swatches/swatch_aqua_fade","#SKIN_AQUA_FADE",0,7,1 +"skin_rocket_launcher_psych_spectre","mp_weapon_rocket_launcher","rui/weapon_skin_swatches/swatch_psych_spectre","#SKIN_PHANTOM",0,2,1 +"skin_rspn101_patriot","mp_weapon_rspn101","rui/weapon_skin_swatches/swatch_patriot","#SKIN_PATRIOT",0,9,1 +"skin_hemlok_mochi","mp_weapon_hemlok","rui/weapon_skin_swatches/swatch_mochi","#SKIN_MOCHI",0,5,1 +"skin_r97_purple_fade","mp_weapon_r97","rui/weapon_skin_swatches/swatch_purple_fade","#SKIN_PURPLE_FADE",0,7,1 +"skin_kraber_masterwork","mp_weapon_sniper","rui/weapon_skin_swatches/swatch_masterwork","#SKIN_MASTERWORK",0,2,1 +"skin_spitfire_lead_farmer","mp_weapon_lmg","rui/weapon_skin_swatches/swatch_lead_farmer","#SKIN_LEAD_FARMER",0,8,1 +"skin_devotion_rspn_customs","mp_weapon_esaw","rui/weapon_skin_swatches/swatch_rspn_customs","#SKIN_RSPN_CUSTOMS",0,8,1 +"skin_mozambique_crimson_fury","mp_weapon_shotgun_pistol","rui/weapon_skin_swatches/swatch_crimson_fury","#SKIN_CRIMSON_FURY",0,7,1 +"skin_thunderbolt_8bit","mp_weapon_arc_launcher","rui/weapon_skin_swatches/swatch_8_bit","#SKIN_8_BIT",0,2,1 +"skin_lstar_heatsink","mp_weapon_lstar","rui/weapon_skin_swatches/swatch_heatsink","#SKIN_HEAT_SINK",0,6,1 +"skin_mastiff_crimson_fury","mp_weapon_mastiff","rui/weapon_skin_swatches/swatch_crimson_fury","#SKIN_CRIMSON_FURY",0,7,1 +"skin_sidewinder_masterwork","mp_weapon_smr","rui/weapon_skin_swatches/swatch_masterwork","#SKIN_MASTERWORK",0,2,1 +"skin_rspn101_halloween","mp_weapon_rspn101","rui/weapon_skin_swatches/swatch_rspn101_halloween","#SKIN_HALLOWEEN",0,10,1 +"skin_car_halloween","mp_weapon_car","rui/weapon_skin_swatches/swatch_car_halloween","#SKIN_HALLOWEEN",0,8,1 +"skin_spitfire_halloween","mp_weapon_lmg","rui/weapon_skin_swatches/swatch_spitfire_halloween","#SKIN_HALLOWEEN",0,9,1 +"skin_rspn101_og_blue_fade","mp_weapon_rspn101_og","rui/weapon_skin_swatches/swatch_blue_fade","#SKIN_BLUE_FADE",0,7,1 +"skin_vinson_badlands","mp_weapon_vinson","rui/weapon_skin_swatches/swatch_badlands_flatline","#SKIN_BADLANDS",0,8,1 +"skin_volt_heatsink","mp_weapon_hemlok_smg","rui/weapon_skin_swatches/swatch_heatsink","#SKIN_HEAT_SINK",0,6,1 +"skin_alternator_headhunter","mp_weapon_alternator_smg","rui/weapon_skin_swatches/swatch_headhunter","#SKIN_HEADHUNTER",0,5,1 +"skin_softball_masterwork","mp_weapon_softball","rui/weapon_skin_swatches/swatch_masterwork","#SKIN_MASTERWORK",0,2,1 +"skin_epg_mrvn","mp_weapon_epg","rui/weapon_skin_swatches/swatch_mrvn","#SKIN_MRVN",0,5,1 +"skin_dmr_phantom","mp_weapon_dmr","rui/weapon_skin_swatches/swatch_psych_spectre","#SKIN_PHANTOM",0,3,1 +"skin_doubletake_masterwork","mp_weapon_doubletake","rui/weapon_skin_swatches/swatch_masterwork","#SKIN_MASTERWORK",0,2,1 +"skin_g2_purple_fade","mp_weapon_g2","rui/weapon_skin_swatches/swatch_purple_fade","#SKIN_PURPLE_FADE",0,7,1 +"skin_coldwar_heatsink","mp_weapon_pulse_lmg","rui/weapon_skin_swatches/swatch_heatsink","#SKIN_HEAT_SINK",0,6,1 +"skin_r97_sky","mp_weapon_r97","rui/weapon_skin_swatches/swatch_sky","#SKIN_SKY",0,5,1 +"skin_rspn101_crimson_fury","mp_weapon_rspn101","rui/weapon_skin_swatches/swatch_crimson_fury","#SKIN_CRIMSON_FURY",0,7,1 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/xp_per_faction_level.csv b/Northstar.CustomServers/mod/scripts/datatable/xp_per_faction_level.csv new file mode 100644 index 00000000..e28cf8c0 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/xp_per_faction_level.csv @@ -0,0 +1,6 @@ +level,xpPerLevel +1,2 +2,3 +3,4 +4,5 +5,5 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/xp_per_fd_titan_level.csv b/Northstar.CustomServers/mod/scripts/datatable/xp_per_fd_titan_level.csv new file mode 100644 index 00000000..28c33f5e --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/xp_per_fd_titan_level.csv @@ -0,0 +1,25 @@ +level,xpPerLevel +1,12 +2,12 +3,14 +4,14 +5,16 +6,16 +7,18 +8,18 +9,20 +10,20 +11,20 +12,20 +13,20 +14,20 +15,20 +16,20 +17,20 +18,20 +19,20 +20,20 +21,20 +22,20 +23,20 +24,20 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/xp_per_player_level.csv b/Northstar.CustomServers/mod/scripts/datatable/xp_per_player_level.csv new file mode 100644 index 00000000..36e52bc8 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/xp_per_player_level.csv @@ -0,0 +1,51 @@ +level,xpPerLevel +1,3 +2,4 +3,5 +4,6 +5,7 +6,8 +7,9 +8,10 +9,10 +10,10 +11,10 +12,10 +13,10 +14,10 +15,10 +16,10 +17,10 +18,10 +19,10 +20,10 +21,10 +22,10 +23,10 +24,10 +25,10 +26,10 +27,10 +28,10 +29,10 +30,10 +31,10 +32,10 +33,10 +34,10 +35,10 +36,10 +37,10 +38,10 +39,10 +40,10 +41,10 +42,10 +43,10 +44,10 +45,10 +46,10 +47,10 +48,10 +49,10 +50,10 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/xp_per_titan_level.csv b/Northstar.CustomServers/mod/scripts/datatable/xp_per_titan_level.csv new file mode 100644 index 00000000..d607f589 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/xp_per_titan_level.csv @@ -0,0 +1,21 @@ +level,xpPerLevel +1,3 +2,5 +3,7 +4,10 +5,10 +6,10 +7,10 +8,10 +9,10 +10,10 +11,10 +12,10 +13,10 +14,10 +15,10 +16,10 +17,10 +18,10 +19,10 +20,10 \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/datatable/xp_per_weapon_level.csv b/Northstar.CustomServers/mod/scripts/datatable/xp_per_weapon_level.csv new file mode 100644 index 00000000..a6859594 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/datatable/xp_per_weapon_level.csv @@ -0,0 +1,21 @@ +level,default,sniper,pistol,antititan +1,3,2,2,2 +2,5,3,3,3 +3,7,4,4,4 +4,10,5,5,4 +5,10,5,5,4 +6,10,5,5,4 +7,10,5,5,4 +8,10,5,5,4 +9,10,5,5,4 +10,10,5,5,4 +11,10,5,5,4 +12,10,5,5,4 +13,10,5,5,4 +14,10,5,5,4 +15,10,5,5,4 +16,10,5,5,4 +17,10,5,5,4 +18,10,5,5,4 +19,10,5,5,4 +20,10,5,5,4 \ No newline at end of file -- cgit v1.2.3 From 919acdacd2ef8b230df5d75d125e074d31c75f17 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Tue, 1 Nov 2022 07:18:38 +0800 Subject: Better Decloaking Check to Support Modding (#514) * Better Decloaking Check to Support Modding Respawn hardcoded decloaking which messed up many things, this will make vanilla cloak to behave properly in any offhand slot and have a better support for modded cloak * commit fix --- .../mod/scripts/vscripts/mp/_base_gametype.gnut | 29 ++++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) 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 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 -- cgit v1.2.3 From 0a5c705f662773ecb97a9b06d2c92e023307b441 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 6 Nov 2022 02:17:53 +0100 Subject: Bump version number (#526) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7dcfcd21..7ca8dd5e 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 0, "ConVars": [ { diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 28825a58..1a08f0d4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 79663feb..2ed89910 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.9.0", + "Version": "1.10.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From f5e4a7be5b6d48006e5f3b9ac218993aa4ee284e Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 10 Nov 2022 00:05:18 +0000 Subject: Improve mouse capture handling in menus (#520) * rework mouse capture handling * small improvement to comment * move to new script file * refactor to use only the capturePanel * refactor part 2 * github please commit everything * remove non-implemented global function * cleanup * rename variable * formatting and a comment * run callbacks for menus * update comment accordingly * small formatting change * slight refactor to avoid duplicate code * improve comment * pass correct parameters * newline at end of file :) --- Northstar.Client/mod.json | 4 ++ .../mod/scripts/vscripts/sh_menu_models.gnut | 36 ------------- .../mod/scripts/vscripts/ui/menu_map_select.nut | 2 +- .../mod/scripts/vscripts/ui/menu_ns_modmenu.nut | 2 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- .../mod/scripts/vscripts/ui/ui_mouse_capture.nut | 60 ++++++++++++++++++++++ 6 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7ca8dd5e..15853be7 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -115,6 +115,10 @@ { "Path": "ui/controller_prompts.nut", "RunOn": "UI" + }, + { + "Path": "ui/ui_mouse_capture.nut", + "RunOn": "UI" } ], "Localisation": [ diff --git a/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut b/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut index 6d446654..0bcb7864 100644 --- a/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut +++ b/Northstar.Client/mod/scripts/vscripts/sh_menu_models.gnut @@ -207,19 +207,9 @@ #endif // CLIENT && MP #if UI - struct - { - table MouseMovementCaptureFunctionsTable = {} - } file - - const MOUSE_ROTATE_MULTIPLIER = 25.0 - global function UpdateUIMapSupportsMenuModels global function RunMenuClientFunction global function UI_SetPresentationType - - global function AddMouseMovementCaptureHandler - global function UICodeCallback_MouseMovementCapture #endif // UI global const STORE_BG_DEFAULT = 0 @@ -2897,30 +2887,4 @@ RunClientScript( "UpdateMenuToHarvester" ) } } - - void function AddMouseMovementCaptureHandler( var menu, void functionref( int, int ) func ) - { - file.MouseMovementCaptureFunctionsTable.rawset( menu, func ) - } - - void function UpdateMouseMovementCaptureFunctions( int deltaX, int deltaY ) - { - var activeMenu = GetActiveMenu() - if ( file.MouseMovementCaptureFunctionsTable.rawin( activeMenu ) ) - file.MouseMovementCaptureFunctionsTable.rawget( activeMenu )(deltaX, deltaY) - } - - void function UICodeCallback_MouseMovementCapture( var capturePanel, int deltaX, int deltaY ) - { - float screenScaleXModifier = 1920.0 / GetScreenSize()[0] // 1920 is base screen width - float mouseXRotateDelta = deltaX * screenScaleXModifier * MOUSE_ROTATE_MULTIPLIER - //printt( "deltaX:", deltaX, "deltaY:", deltaY ) - - float screenScaleYModifier = 1080.0 / GetScreenSize()[1] // 1920 is base screen width - float mouseYRotationDelta = deltaY * screenScaleYModifier * MOUSE_ROTATE_MULTIPLIER - - UpdateMouseMovementCaptureFunctions( deltaX, deltaY ) - - RunMenuClientFunction( "UpdateMouseRotateDelta", mouseXRotateDelta, mouseYRotationDelta ) - } #endif // UI diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut index 930e472b..8e8071f5 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_map_select.nut @@ -43,7 +43,7 @@ void function InitMapsMenu() { file.menu = GetMenu( "MapsMenu" ) - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnCloseMapsMenu ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut index 329ea73f..3f643aa3 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_modmenu.nut @@ -83,7 +83,7 @@ void function InitModMenu() RuiSetImage( rui, "basicImage", $"ui/menu/common/dialog_error" ) } - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) // UI Events AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index eb068374..d9b11ccc 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -142,7 +142,7 @@ void function InitServerBrowserMenu() { file.menu = GetMenu( "ServerBrowserMenu" ) - AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + AddMouseMovementCaptureHandler( Hud_GetChild(file.menu, "MouseMovementCapture"), UpdateMouseDeltaBuffer ) // Get menu stuff file.serverButtons = GetElementsByClassname( file.menu, "ServerButton" ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut b/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut new file mode 100644 index 00000000..fa5c9217 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/ui_mouse_capture.nut @@ -0,0 +1,60 @@ +untyped // untyped purely so I can index into a table with var + +global function AddMouseMovementCaptureHandler +global function UICodeCallback_MouseMovementCapture + +struct +{ + // a table of capturePanels and menus, each of which contains an array of callbacks + table< var, array< void functionref( int deltaX, int deltaY ) > > mouseMovementCaptureCallbacks = {} +} file + +// this function registers a callback (or "handler") function for a MouseMovementCapture menu panel +// use this for scrollbars, sliders, etc. +void function AddMouseMovementCaptureHandler( var capturePanelOrMenu, void functionref( int deltaX, int deltaY ) func ) +{ + // if the capturePanel or menu already has an array in the table, we append to the array + // if not, we should create the array, [func] just turns func into an array + if ( capturePanelOrMenu in file.mouseMovementCaptureCallbacks ) + file.mouseMovementCaptureCallbacks[capturePanelOrMenu].append( func ) + else + file.mouseMovementCaptureCallbacks[capturePanelOrMenu] <- [func] +} + +void function RunMouseMovementCallbacks( var capturePanelOrMenu, int deltaX, int deltaY ) +{ + // check that the capturePanelOrMenu is in the table before trying anything stupid + if ( capturePanelOrMenu in file.mouseMovementCaptureCallbacks ) + { + // iterate through the different callback functions + foreach ( void functionref( int deltaX, int deltaY ) callback in file.mouseMovementCaptureCallbacks[capturePanelOrMenu] ) + { + // run the callback function + callback( deltaX, deltaY ) + } + } +} + +void function UICodeCallback_MouseMovementCapture( var capturePanel, int deltaX, int deltaY ) +{ + // run callbacks for the capturePanel + RunMouseMovementCallbacks( capturePanel, deltaX, deltaY ) + + // get the current menu and run callbacks, this preserves backwards compatibility + RunMouseMovementCallbacks( GetActiveMenu(), deltaX, deltaY ) + + // everything below here originally existed in vanilla sh_menu_models.gnut and is meant to be used for like all of their rotation stuff + // its easier to move this here than to add a shared callback for all of the vanilla capture handlers (there are like >20) + + // this const was moved instead of made global because it was literally only used in the code below + const MOUSE_ROTATE_MULTIPLIER = 25.0 + + float screenScaleXModifier = 1920.0 / GetScreenSize()[0] // 1920 is base screen width + float mouseXRotateDelta = deltaX * screenScaleXModifier * MOUSE_ROTATE_MULTIPLIER + //printt( "deltaX:", deltaX, "screenScaleModifier:", screenScaleModifier, "mouseRotateDelta:", mouseRotateDelta ) + + float screenScaleYModifier = 1080.0 / GetScreenSize()[1] // 1080 is base screen height + float mouseYRotationDelta = deltaY * screenScaleYModifier * MOUSE_ROTATE_MULTIPLIER + + RunMenuClientFunction( "UpdateMouseRotateDelta", mouseXRotateDelta, mouseYRotationDelta ) +} -- cgit v1.2.3 From 85d771e8f971a2ab2a1aca751c51a8202a3dd355 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 12 Nov 2022 22:06:33 +0800 Subject: Fixed Burn Cards Animations (#511) * Fixed Burn Cards Animations Burn cards no longer taken right after using * commit fix * adding EndSignal() * Update Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * Update Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> --- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 2 +- .../vscripts/item_inventory/sv_item_inventory.gnut | 29 ++++++++++++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 0d189017..81f7fbc2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -264,7 +264,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 ) 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 4e8f85ac..d4ec5879 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 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 ) } @@ -94,7 +109,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 ) @@ -117,9 +132,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 ) } } -- cgit v1.2.3 From 3b02ecd43c2c1efd6e2d966b9659e4268dc1bbc5 Mon Sep 17 00:00:00 2001 From: Erlite Date: Sat, 12 Nov 2022 15:09:43 +0100 Subject: Add support for hiding the [SERVER] tag in server messages (#506) --- .../vscripts/_custom_codecallbacks_client.gnut | 29 ++++++++++++++++------ .../mod/scripts/vscripts/_chat.gnut | 8 +++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 66a40cb0..3caf4336 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -11,6 +11,7 @@ global struct ClClient_MessageStruct { bool isDead bool isWhisper bool shouldBlock + bool noServerTag } struct { @@ -29,6 +30,7 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { localMessage.isDead = returnStruct.isDead localMessage.isWhisper = returnStruct.isWhisper localMessage.shouldBlock = localMessage.shouldBlock || returnStruct.shouldBlock + localMessage.noServerTag = returnStruct.noServerTag } } @@ -39,7 +41,13 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { NSChatWriteRaw(1, "\n") - if (localMessage.player == null) NSChatWrite(1, "\x1b[95m") + if (localMessage.player == null) + { + if (!localMessage.noServerTag || localMessage.isWhisper) + { + NSChatWrite(1, "\x1b[95m") + } + } else { bool isFriendly = localMessage.player.GetTeam() == GetLocalClientPlayer().GetTeam() @@ -54,15 +62,18 @@ void function OnReceivedMessage(ClClient_MessageStruct localMessage) { if (localMessage.player == null) { - NSChatWriteRaw(1, Localize("#HUD_CHAT_SERVER_PREFIX") + " ") + if (!localMessage.noServerTag) + { + NSChatWriteRaw(1, Localize("#HUD_CHAT_SERVER_PREFIX") + " ") + } } - else { + else + { NSChatWriteRaw(1, localMessage.playerName) NSChatWriteRaw(1, ": ") } - NSChatWrite(1, "\x1b[0m") - + if (localMessage.player != null || !localMessage.noServerTag || localMessage.isWhisper) NSChatWrite(1, "\x1b[0m") NSChatWrite(1, localMessage.message) } @@ -87,16 +98,19 @@ void function CHudChat_OnReceivedSayTextMessageCallback(int fromPlayerIndex, str fromPlayerName = fromPlayer.GetPlayerNameWithClanTag() } + // Null player + isTeam == true: Server with no tag. + if (messageType == 0 || messageType == 1) { ClClient_MessageStruct localMessage localMessage.message = message localMessage.player = fromPlayer localMessage.playerName = fromPlayerName - localMessage.isTeam = isTeam + localMessage.isTeam = fromPlayer != null && isTeam localMessage.isDead = isDead localMessage.isWhisper = false localMessage.shouldBlock = false + localMessage.noServerTag = fromPlayer == null && isTeam OnReceivedMessage(localMessage) return } @@ -107,10 +121,11 @@ void function CHudChat_OnReceivedSayTextMessageCallback(int fromPlayerIndex, str localMessage.message = message localMessage.player = fromPlayer localMessage.playerName = fromPlayerName - localMessage.isTeam = isTeam + localMessage.isTeam = fromPlayer != null && isTeam localMessage.isDead = isDead localMessage.isWhisper = true localMessage.shouldBlock = false + localMessage.noServerTag = fromPlayer == null && isTeam OnReceivedMessage(localMessage) return } 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 ) -- cgit v1.2.3 From 7c30c44d2bfea9cf64a374f690a23a6e6eb1165b Mon Sep 17 00:00:00 2001 From: Respawn Date: Sat, 12 Nov 2022 23:08:24 +0100 Subject: Add cl_titan_cockpit.nut from englishclient_mp_common --- .../scripts/vscripts/client/cl_titan_cockpit.nut | 1652 ++++++++++++++++++++ 1 file changed, 1652 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut new file mode 100644 index 00000000..828f3056 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -0,0 +1,1652 @@ +untyped + +global function ClTitanCockpit_Init + +global function ServerCallback_TitanEMP +global function ServerCallback_TitanCockpitBoot +global function TitanCockpit_DamageFeedback +global function TitanCockpit_AddPlayer +global function RegisterTitanBindings +global function GetTitanBindings +global function DeregisterTitanBindings +global function ServerCallback_TitanEmbark +global function ServerCallback_TitanDisembark +global function PlayerPressed_EjectEnable // so can be called directly for debugging +global function PlayerPressed_Eject // so can be called directly for debugging +global function TitanCockpit_IsBooting +global function ServerCallback_TitanCockpitEMP +global function TitanCockpit_EMPFadeScale +global function TitanCockpit_DoEMP +global function TitanEMP_Internal +global function ServerCallback_EjectConfirmed +global function LinkCoreHint + +global function AddTitanCockpitManagedRUI +global function UpdateTitanCockpitVisibility +global function TitanCockpitDestroyRui +global function TitanCockpitDoomedThink +global function PlayerEjects +global function IsDisplayingEjectInterface +global function FlashCockpitLight +global function PlayCockpitSparkFX + +global function FlashCockpitHealth + +global function UpdateEjectHud_SetButtonPressTime +global function UpdateEjectHud_SetButtonPressCount + +global function SetUnlimitedDash +#if MP +global function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus +global function DisplayFrontierRank +#endif +struct TitanCockpitManagedRUI +{ + bool exists = false + var functionref() create + void functionref() destroy + bool functionref() shouldCreate + int drawGroup = RUI_DRAW_COCKPIT +} + +const TITAN_ALARM_SOUND = "titan_alarm" +const TITAN_NUCLEAR_DEATH_ALARM = "titan_nuclear_death_alarm" +const TITAN_EJECT_BOOST = "titan_eject_boost" +const TITAN_EJECT_ASCENT = "player_eject_windrush" +const TITAN_EJECT_APEX = "player_eject_apex_wind" +const TITAN_EJECT_DESCENT = "player_fallingdescent_windrush" + +const EJECT_MIN_VELOCITY = 200.0 +const EJECT_MAX_VELOCITY = 1000.0 + +struct +{ + var coreHintRui + var cockpitRui + var cockpitLowerRui + var cockpitAdditionalRui + array titanCockpitManagedRUIs + + string lastPilotSettings + + bool isFirstBoot = true + var scorchHotstreakRui +} file + +function ClTitanCockpit_Init() +{ + if ( reloadingScripts ) + return + + RegisterSignal( "DisembarkCheck" ) + RegisterSignal( "Rumble_Forward_End" ) + RegisterSignal( "Rumble_Back_End" ) + RegisterSignal( "Rumble_Left_End" ) + RegisterSignal( "Rumble_Right_End" ) + RegisterSignal( "EMP" ) + RegisterSignal( "Ejecting" ) + RegisterSignal( "TitanEMP_Internal" ) + RegisterSignal( "TitanUnDoomed" ) + RegisterSignal( "MonitorPlayerEjectAnimBeingStuck" ) + RegisterSignal( "DisplayFrontierRank" ) + + PrecacheParticleSystem( $"xo_cockpit_spark_01" ) + + if ( !IsModelViewer() && !IsLobby() ) + { + AddCreateCallback( "titan_cockpit", TitanCockpitInit ) + } + + if ( !reloadingScripts ) + { + level.cockpitGeoRef <- null + } + + AddPlayerFunc( TitanCockpit_AddPlayer ) + + AddCinematicEventFlagChangedCallback( CE_FLAG_TITAN_3P_CAM, CinematicEventFlagChanged ) + AddCinematicEventFlagChangedCallback( CE_FLAG_INTRO, CinematicEventFlagChanged ) + + AddCallback_PlayerClassChanged( UpdateLastPlayerSettings ) + + AddTitanCockpitManagedRUI( Scorch_CreateHotstreakBar, Scorch_DestroyHotstreakBar, Scorch_ShouldCreateHotstreakBar, RUI_DRAW_COCKPIT ) //RUI_DRAW_HUD +} + +void function UpdateLastPlayerSettings( entity player ) +{ + if ( IsPilot( player ) ) + file.lastPilotSettings = player.GetPlayerSettings() +} + +TitanBindings function GetTitanBindings() +{ + TitanBindings Table + Table.PlayerPressed_Eject = PlayerPressed_Eject + Table.PlayerPressed_EjectEnable = PlayerPressed_EjectEnable + return Table +} + +bool function RegisterTitanBindings( entity player, TitanBindings bind ) +{ + if ( player != GetLocalViewPlayer() ) + return false + + if ( player != GetLocalClientPlayer() ) + return false + + RegisterConCommandTriggeredCallback( "+useAndReload", bind.PlayerPressed_Eject ) + RegisterConCommandTriggeredCallback( "+use", bind.PlayerPressed_Eject ) + + RegisterConCommandTriggeredCallback( "+scriptCommand1", bind.PlayerPressed_EjectEnable ) + + return true +} + +void function DeregisterTitanBindings( TitanBindings bind ) +{ + DeregisterConCommandTriggeredCallback( "+useAndReload", bind.PlayerPressed_Eject ) + DeregisterConCommandTriggeredCallback( "+use", bind.PlayerPressed_Eject ) + + if ( GetMapName() != "" ) + { + DeregisterConCommandTriggeredCallback( "+scriptCommand1", bind.PlayerPressed_EjectEnable ) + } +} + + +void function TitanCockpit_AddPlayer( entity player ) +{ + if ( IsModelViewer() ) + return + + player.s.lastCockpitDamageSoundTime <- 0 + player.s.inTitanCockpit <- false + player.s.lastDialogTime <- 0 + player.s.titanCockpitDialogActive <- false + player.s.titanCockpitDialogAliasList <- [] + + player.s.hitVectors <- [] +} + +void function TitanCockpitInit( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + Assert( player.GetCockpit() == cockpit ) + + cockpit.s.ejectStartTime <- 0 // placed here to fix http://bugzilla.respawn.net/show_bug.cgi?id=156786 + + if ( !IsAlive( player ) ) + return + + if ( !IsTitanCockpitModelName( cockpit.GetModelName() ) || IsWatchingThirdPersonKillReplay() ) + { + player.s.inTitanCockpit = false + return + } + + if ( !player.s.inTitanCockpit ) + TitanEmbarkDSP( 0.5 ) + + player.s.inTitanCockpit = true + + // code aint callin this currently + CodeCallback_PlayerInTitanCockpit( GetLocalViewPlayer(), GetLocalViewPlayer() ) + + // move this + array targets = GetClientEntArrayBySignifier( "info_target" ) + foreach ( target in targets ) + { + if ( target.GetTargetName() != "cockpit_geo_ref" ) + continue + + level.cockpitGeoRef = target + } + + entity cockpitParent = expect entity( level.cockpitGeoRef ) + + if ( !IsValid( cockpitParent ) ) + cockpitParent = GetLocalViewPlayer() + + cockpit.s.empInfo <- {} + cockpit.s.empInfo["xOffset"] <- 0 + cockpit.s.empInfo["yOffset"] <- 0 + cockpit.s.empInfo["startTime"] <- 0 + cockpit.s.empInfo["duration"] <- 0 + cockpit.s.empInfo["sub_count"] <- 0 + cockpit.s.empInfo["sub_start"] <- 0 + cockpit.s.empInfo["sub_duration"] <- 0 + cockpit.s.empInfo["sub_pause"] <- 0 + cockpit.s.empInfo["sub_alpha"] <- 0 + + cockpit.s.cockpitType <- 1 + cockpit.s.FOV <- 70 + + cockpit.e.body = CreateCockpitBody( cockpit, player, cockpitParent ) + + thread TitanCockpitAnimThink( cockpit, cockpit.e.body ) + + if ( player.IsTitan() && IsAlive( player ) ) // pilot with titan cockpit gets thrown from titan + thread TitanCockpitDoomedThink( cockpit, player ) + + SetCockpitLightingEnabled( 0, true ) + ShowRUIHUD( cockpit ) +} + +//bind r "script_client ReloadScripts();script_client GetLocalViewPlayer().GetCockpit().Destroy()" +void function ShowRUIHUD( entity cockpit ) +{ + // update topo positions + int cameraAttachId = cockpit.LookupAttachment( "CAMERA" ) + vector cameraOrigin = cockpit.GetAttachmentOrigin( cameraAttachId ) + + int lowerScreenAttachId = cockpit.LookupAttachment( "COCKPIT_HUD_BOTTOM" ) + vector lowerScreenOrigin = cockpit.GetAttachmentOrigin( lowerScreenAttachId ) + vector lowerScreenAngles = cockpit.GetAttachmentAngles( lowerScreenAttachId ) + + int instrument1AttachId = cockpit.LookupAttachment( "COCKPIT_OBJ_1" ) + vector instrument1Origin = cockpit.GetAttachmentOrigin( instrument1AttachId ) + vector instrument1Angles = cockpit.GetAttachmentAngles( instrument1AttachId ) + + lowerScreenOrigin = lowerScreenOrigin - cameraOrigin + vector lowerScreenPosition = + + instrument1Origin = instrument1Origin - cameraOrigin + vector instrument1Position = + vector instrument1RightVector = AnglesToRight( instrument1Angles ) * -1 + vector instrument1DownVector = AnglesToUp( instrument1Angles ) * -1 + + RuiTopology_UpdatePos( clGlobal.topoTitanCockpitLowerHud, lowerScreenPosition, <0, -TITAN_COCKPIT_LOWER_RUI_SCREEN_SQUARE_SIZE, 0>, <0, 0, -(TITAN_COCKPIT_LOWER_RUI_SCREEN_SQUARE_SIZE * TITAN_COCKPIT_LOWER_RUI_SCREEN_HEIGHT_SCALE)> ) + RuiTopology_UpdatePos( clGlobal.topoTitanCockpitInstrument1, instrument1Position - (instrument1RightVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE * 0.5) - (instrument1DownVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE * 0.5), instrument1RightVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE, instrument1DownVector * TITAN_COCKPIT_INSTRUMENT1_RUI_SCREEN_SQUARE_SIZE ) + + // create ruis + entity player = GetLocalViewPlayer() + + #if SP + file.coreHintRui = CreateTitanCockpitRui( $"ui/core_hint.rpak" ) + #endif + + file.cockpitRui = CreateTitanCockpitRui( $"ui/ajax_cockpit_base.rpak" ) + RuiTrackFloat3( file.cockpitRui, "playerOrigin", player, RUI_TRACK_ABSORIGIN_FOLLOW ) + RuiTrackFloat3( file.cockpitRui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackFloat( file.cockpitRui, "healthFrac", player, RUI_TRACK_HEALTH ) + RuiTrackFloat( file.cockpitRui, "shieldFrac", player, RUI_TRACK_SHIELD_FRACTION ) + RuiTrackFloat( file.cockpitRui, "dashFrac", player, RUI_TRACK_PLAYER_SUIT_POWER ) + RuiSetFloat( file.cockpitRui, "ejectManualTimeOut", EJECT_FADE_TIME ) + RuiSetFloat( file.cockpitRui, "ejectButtonTimeOut", TITAN_EJECT_MAX_PRESS_DELAY ) + RuiSetGameTime( file.cockpitRui, "ejectManualStartTime", -60.0 ) + RuiSetGameTime( file.cockpitRui, "ejectButtonPressTime", -60.0 ) + #if MP + string titanName = GetTitanCharacterName( player ) + if ( titanName == "vanguard" ) + { + RuiSetString( file.cockpitRui, "titanInfo1", GetVanguardCoreString( player, 1 ) ) + RuiSetString( file.cockpitRui, "titanInfo2", GetVanguardCoreString( player, 2 ) ) + RuiSetString( file.cockpitRui, "titanInfo3", GetVanguardCoreString( player, 3 ) ) + RuiSetString( file.cockpitRui, "titanInfo4", GetVanguardCoreString( player, 4 ) ) + } + + file.cockpitAdditionalRui = CreateTitanCockpitRui( $"ui/ajax_cockpit_fd.rpak" ) + RuiSetFloat( file.cockpitAdditionalRui, "ejectManualTimeOut", EJECT_FADE_TIME ) + RuiSetFloat( file.cockpitAdditionalRui, "ejectButtonTimeOut", TITAN_EJECT_MAX_PRESS_DELAY ) + RuiSetGameTime( file.cockpitAdditionalRui, "ejectManualStartTime", -60.0 ) + + RuiSetDrawGroup( file.cockpitAdditionalRui, RUI_DRAW_NONE ) + #endif + +#if SP + bool ejectIsAllowed = false +#else + bool ejectIsAllowed = !TitanEjectIsDisabled() +#endif + RuiSetBool( file.cockpitRui, "ejectIsAllowed", ejectIsAllowed ) + + string playerSettings = GetLocalViewPlayer().GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( file.cockpitRui, "numHealthSegments", int( health / healthPerSegment ) ) + RuiTrackFloat( file.cockpitRui, "cockpitColor", player, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.cockpitColor ) + + file.cockpitLowerRui = CreateTitanCockpitLowerRui( $"ui/ajax_cockpit_lower.rpak" ) + RuiTrackFloat( file.cockpitLowerRui, "dashFrac", player, RUI_TRACK_PLAYER_SUIT_POWER ) + RuiTrackFloat3( file.cockpitLowerRui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + RuiTrackFloat( file.cockpitLowerRui, "cockpitColor", player, RUI_TRACK_STATUS_EFFECT_SEVERITY, eStatusEffect.cockpitColor ) + + var instrument1Rui = CreateTitanCockpitInstrument1Rui( $"ui/ajax_cockpit_insturment1.rpak" ) + RuiTrackFloat3( instrument1Rui, "playerEyeAngles", player, RUI_TRACK_EYEANGLES_FOLLOW ) + + int numDashPips = int( floor( 100 / GetSettingsForPlayer_DodgeTable( GetLocalViewPlayer() )["dodgePowerDrain"] ) ) + RuiSetInt( file.cockpitRui, "numDashSegments", numDashPips ) + RuiSetInt( file.cockpitLowerRui, "numDashSegments", numDashPips ) + + thread CockpitDoomedThink( cockpit ) + thread TitanCockpitDestroyRuisOnDeath( cockpit ) + thread TitanCockpitHealthChangedThink( cockpit, player ) + + #if MP + if ( GetCurrentPlaylistVarInt( "aegis_upgrades", 0 ) == 1 && !IsSpectating() && !IsWatchingKillReplay() ) + thread DisplayFrontierRank( file.isFirstBoot ) + #endif + file.isFirstBoot = false + + UpdateTitanCockpitVisibility() +} + +#if MP +void function DisplayFrontierRank( bool isFirstBoot = true ) +{ + GetLocalClientPlayer().Signal( "DisplayFrontierRank" ) + GetLocalClientPlayer().EndSignal( "DisplayFrontierRank" ) + + wait 2.0 + + TitanLoadoutDef titanLoadout = GetTitanLoadoutFromPersistentData( GetLocalClientPlayer(), GetPersistentSpawnLoadoutIndex( GetLocalClientPlayer(), "titan" ) ) + string titanClass = titanLoadout.titanClass + + array titanUpgrades = FD_GetUpgradesForTitanClass( titanClass ) + int maxActiveIndex + foreach ( index, item in titanUpgrades ) + { + RuiSetImage( file.cockpitAdditionalRui, "upgradeIcon" + (index + 1), item.image ) + RuiSetString( file.cockpitAdditionalRui, "upgradeName" + (index + 1), item.name ) + + if ( !IsSubItemLocked( GetLocalClientPlayer(), item.ref, item.parentRef ) ) + maxActiveIndex++ + } + + RuiSetDrawGroup( file.cockpitAdditionalRui, RUI_DRAW_COCKPIT ) + + bool firstBootDisplay + if ( GameRules_GetGameMode() == FD ) + firstBootDisplay = isFirstBoot || !GetGlobalNetBool( "FD_waveActive" ) + else + firstBootDisplay = isFirstBoot + + RuiSetBool( file.cockpitAdditionalRui, "isFirstBoot", firstBootDisplay ) + RuiSetImage( file.cockpitAdditionalRui, "titanIcon", GetIconForTitanClass( titanClass ) ) + RuiSetInt( file.cockpitAdditionalRui, "titanRank", FD_TitanGetLevel( GetLocalClientPlayer(), titanClass ) ) + RuiSetInt( file.cockpitAdditionalRui, "maxActiveIndex", maxActiveIndex ) + RuiSetGameTime( file.cockpitAdditionalRui, "updateTime", Time() ) + + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeAnnouncement" ) + + if ( firstBootDisplay ) + { + wait 2.0 + + for ( int index = 0; index < maxActiveIndex; index++ ) + { + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeTextAppear" ) + + wait 0.85 + + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeBarFill" ) + + wait 0.15 + } + } + else + { + wait 0.5 + + for ( int index = 0; index < maxActiveIndex; index++ ) + { + EmitSoundOnEntity( GetLocalClientPlayer(), "UI_InGame_FD_MetaUpgradeBarFill" ) + wait 0.05 + } + } +} + +string function GetVanguardCoreString( entity player, int index ) +{ + Assert( player.IsTitan() ) + + if ( !IsConnected() ) //Persistence isn't available when we disconnect + return "" + + if ( player != GetLocalClientPlayer() ) //Client Persistence doesn't know about other players. + return "" + + TitanLoadoutDef loadout = GetActiveTitanLoadout( player ) + + entity soul = player.GetTitanSoul() + if ( !IsValid( soul ) ) + return "" + + if ( index == 1 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 1 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE1_TITLE" ), Localize( GetItemName( loadout.passive4 ) ) ) + } + else + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE1_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + } + } + if ( index == 2 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 2 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( GetItemName( loadout.passive5 ) ) ) + } + else + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 1 ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + else + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE2_TITLE" ), Localize( "#UPGRADE_NOT_INSTALLED" ) ) + } + } + if ( index == 3 ) + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 3 ) + { + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( GetItemName( loadout.passive6 ) ) ) + } + else + { + if ( soul.GetTitanSoulNetInt( "upgradeCount" ) >= 2 ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( "#UPGRADE_IN_PROGRESS" ) ) + else + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE3_TITLE" ), Localize( "#UPGRADE_NOT_INSTALLED" ) ) + } + } + if ( index == 4 ) + { + printt( loadout.passive4 ) + if ( loadout.passive4 == "pas_vanguard_core1" ) // Arc Rounds + { + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_RIGHT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "missile_racks" ) || offhandWeapon.HasMod( "upgradeCore_MissileRack_Vanguard" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE2" ) ) + offhandWeapon = player.GetOffhandWeapon( OFFHAND_LEFT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "energy_transfer" ) || offhandWeapon.HasMod( "energy_field_energy_transfer" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE3" ) ) + } + else if ( loadout.passive4 == "pas_vanguard_core2" ) // Missile Racks + { + entity weapon = player.GetMainWeapons()[0] + if ( IsValid( weapon ) && ( weapon.HasMod( "arc_rounds" ) || weapon.HasMod( "arc_rounds_with_battle_rifle" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE1" ) ) + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_LEFT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "energy_transfer" ) || offhandWeapon.HasMod( "energy_field_energy_transfer" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE3" ) ) + } + else if ( loadout.passive4 == "pas_vanguard_core3" ) // Energy Transfer + { + entity weapon = player.GetMainWeapons()[0] + if ( IsValid( weapon ) && ( weapon.HasMod( "arc_rounds" ) || weapon.HasMod( "arc_rounds_with_battle_rifle" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE1" ) ) + entity offhandWeapon = player.GetOffhandWeapon( OFFHAND_RIGHT ) + if ( IsValid( offhandWeapon ) && ( offhandWeapon.HasMod( "missile_racks" ) || offhandWeapon.HasMod( "upgradeCore_MissileRack_Vanguard" ) ) ) + return Localize( "#TITAN_UPGRADE_STATUS_N_N", Localize( "#TITAN_UPGRADE4_TITLE" ), Localize( "#GEAR_VANGUARD_CORE2" ) ) + } + return "" + } + + unreachable +} +#endif + +void function SetUnlimitedDash( bool active ) +{ + if ( file.cockpitLowerRui == null ) + return + + RuiSetBool( file.cockpitLowerRui, "hasUnlimitedDash", active ) +} + +void function UpdateEjectHud_SetManualEjectStartTime( entity player ) +{ + float timeNow = Time() + player.p.ejectEnableTime = timeNow + + if ( file.cockpitRui != null ) + RuiSetGameTime( file.cockpitRui, "ejectManualStartTime", timeNow ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetGameTime( file.cockpitAdditionalRui, "ejectManualStartTime", timeNow ) +} + +void function UpdateEjectHud_SetButtonPressTime( entity player ) +{ + float timeNow = Time() + player.p.ejectPressTime = timeNow + + if ( file.cockpitRui != null ) + RuiSetGameTime( file.cockpitRui, "ejectButtonPressTime", timeNow ) + + //if ( file.cockpitAdditionalRui != null ) + // RuiSetGameTime( file.cockpitAdditionalRui, "ejectButtonPressTime", timeNow ) +} + +void function UpdateEjectHud_SetButtonPressCount( entity player, int buttonCount ) +{ + player.p.ejectPressCount = buttonCount + + if ( file.cockpitRui != null ) + RuiSetInt( file.cockpitRui, "ejectButtonCount", buttonCount ) + + //if ( file.cockpitAdditionalRui != null ) + // RuiSetInt( file.cockpitAdditionalRui, "ejectButtonCount", buttonCount ) +} + +void function UpdateTitanCockpitVisibility() +{ + entity player = GetLocalViewPlayer() + if ( !IsValid( player ) ) + return + + if ( Tone_ShouldCreateTrackerHud( player ) ) + thread Tone_HudThink( player ) + else + player.Signal( "StopToneHud" ) + + foreach ( managedRUI in file.titanCockpitManagedRUIs ) + { + bool shouldCreate = managedRUI.shouldCreate() + if ( !managedRUI.exists && shouldCreate ) + { + var rui = managedRUI.create() + + bool found = false + foreach ( cockpitRui in player.p.titanCockpitRUIs ) + { + if ( cockpitRui.rui == rui ) + found = true + } + if ( !found ) + { + TitanCockpitRUI tcRUI + tcRUI.rui = rui + tcRUI.drawGroup = managedRUI.drawGroup + player.p.titanCockpitRUIs.append( tcRUI ) + } + + managedRUI.exists = true + } + else if ( managedRUI.exists && !shouldCreate ) + { + managedRUI.destroy() + managedRUI.exists = false + } + } + + bool isVisible = true + + int ceFlags = player.GetCinematicEventFlags() + if ( (ceFlags & CE_FLAG_INTRO) || (ceFlags & CE_FLAG_TITAN_3P_CAM) ) + isVisible = false + if ( clGlobal.isSoloDialogMenuOpen ) + isVisible = false + + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + TitanCockpitRUI tcRUI = player.p.titanCockpitRUIs[ i ] + RuiSetDrawGroup( tcRUI.rui, isVisible ? tcRUI.drawGroup : RUI_DRAW_NONE ) + } +} + +void function AddTitanCockpitManagedRUI( var functionref() createFunc, void functionref() destroyFunc, bool functionref() shouldCreateFunc, int drawGroup ) +{ + TitanCockpitManagedRUI managedRUI + managedRUI.create = createFunc + managedRUI.destroy = destroyFunc + managedRUI.shouldCreate = shouldCreateFunc + managedRUI.drawGroup = drawGroup + + file.titanCockpitManagedRUIs.append( managedRUI ) +} + +void function CinematicEventFlagChanged( entity player ) +{ + UpdateTitanCockpitVisibility() +} + +void function CockpitDoomedThink( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + cockpit.EndSignal( "OnDestroy" ) + + while ( IsAlive( player ) ) + { + entity soul = player.GetTitanSoul() + if ( !IsValid( soul ) ) //Defensive fix for bug 227087. Assumption is that the cockpit is likely to be destroyed soon if the soul is invalid. + return + if ( !soul.IsDoomed() ) + player.WaitSignal( "Doomed" ) + + SetCockpitUIDoomedState( true ) + + if ( !IsValid( soul ) ) //Defensive fix for bug 227087. Assumption is that the cockpit is likely to be destroyed soon if the soul is invalid. + return + if ( soul.IsDoomed() ) + player.WaitSignal( "TitanUnDoomed" ) + + SetCockpitUIDoomedState( false ) + } +} + +void function SetCockpitUIEjectingState( bool state ) +{ + if ( file.cockpitRui != null ) + RuiSetBool( file.cockpitRui, "isEjecting", state ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetBool( file.cockpitAdditionalRui, "isEjecting", state ) + + if ( file.cockpitLowerRui != null ) + { + RuiSetBool( file.cockpitLowerRui, "isEjecting", state ) + if ( state ) + RuiSetString( file.cockpitLowerRui, "ejectPrompt", Localize( RollRandomEjectString() ) ) + else + RuiSetString( file.cockpitLowerRui, "ejectPrompt", "" ) + } +} + +void function SetCockpitUIDoomedState( bool state ) +{ + if ( file.cockpitRui != null ) + RuiSetBool( file.cockpitRui, "isDoomed", state ) + + if ( file.cockpitAdditionalRui != null ) + RuiSetBool( file.cockpitAdditionalRui, "isDoomed", state ) +} + +void function TitanCockpitDestroyRui( var ruiToDestroy ) +{ + if ( ruiToDestroy == null ) + return + + entity player = GetLocalViewPlayer() + + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + TitanCockpitRUI tcRUI = player.p.titanCockpitRUIs[ i ] + if ( tcRUI.rui == ruiToDestroy ) + { + RuiDestroy( tcRUI.rui ) + player.p.titanCockpitRUIs.remove( i ) + } + } +} + +void function TitanCockpitDestroyRuisOnDeath( entity cockpit ) +{ + entity player = GetLocalViewPlayer() + + OnThreadEnd( + function() : ( cockpit ) + { + foreach ( managedRUI in file.titanCockpitManagedRUIs ) + { + if ( managedRUI.exists ) + { + managedRUI.destroy() + managedRUI.exists = false + } + } + + entity player = GetLocalViewPlayer() + for ( int i = player.p.titanCockpitRUIs.len() - 1; i >= 0; i-- ) + { + RuiDestroy( player.p.titanCockpitRUIs[ i ].rui ) + player.p.titanCockpitRUIs.remove( i ) + } + + player = GetLocalClientPlayer() + if ( IsValid( player ) ) + player.Signal( "DisplayFrontierRank" ) + file.cockpitAdditionalRui = null + file.cockpitRui = null + file.cockpitLowerRui = null + file.coreHintRui = null + } + ) + + player.EndSignal( "OnDeath" ) + cockpit.EndSignal( "OnDestroy" ) + WaitForever() +} + +function CockpitBodyThink( cockpit, cockpitBody ) +{ + cockpitBody.EndSignal( "OnDestroy" ) + + cockpit.WaitSignal( "OnDestroy" ) + + cockpitBody.Destroy() +} + + +entity function CreateCockpitBody( entity cockpit, entity player, entity cockpitParent ) +{ + #if SP + string bodySettings = DEFAULT_PILOT_SETTINGS + #else + string bodySettings = file.lastPilotSettings + if ( bodySettings == "" || bodySettings == "spectator" ) + bodySettings = Loadouts_GetSetFileForRequestedClass( player ) + if ( bodySettings == "" ) + bodySettings = "pilot_base" + #endif + + asset bodyModelName = GetPlayerSettingsAssetForClassName( bodySettings, "armsmodel" ) + #if DEV + if ( bodySettings == "" ) + { + CodeWarning( "Couldn't find armsmodel for set file: " + bodySettings ) + } + #endif + + entity cockpitBody = CreateClientSidePropDynamic( cockpitParent.GetOrigin(), Vector( 0, 0, 0 ), bodyModelName ) + cockpitBody.EnableRenderWithCockpit() + cockpitBody.SetOrigin( cockpit.GetOrigin() ) + cockpitBody.SetParent( cockpit ) + + thread CockpitBodyThink( cockpit, cockpitBody ) + + return cockpitBody +} + +function TitanEmbarkDSP( transitionTime ) +{ +} + +function TitanDisembarkDSP( transitionTime ) +{ +} + +function TitanCockpit_EMPFadeScale( entity cockpit, elapsedMod = 0 ) +{ + local fadeInTime = 0.0 + local fadeOutTime = 1.5 + local elapsedTime = Time() - cockpit.s.empInfo.startTime + elapsedTime += elapsedMod + + // ToDo: + // Fade in/out from last frames amount so it doesnt pop + // Make strength var to control max fade ( less strength returns max of like 0.5 ) + + //------------------------ + // EMP effect is finished + //------------------------ + + //printt( "elapsedTime:" + elapsedTime + " cockpit.s.empInfo.duration:" + cockpit.s.empInfo.duration + " fadeOutTime:" + fadeOutTime ) + if ( elapsedTime < cockpit.s.empInfo.duration - fadeOutTime ) + { + return 1.0 + } + + + if ( elapsedTime >= fadeInTime + cockpit.s.empInfo.duration + fadeOutTime ) + { + cockpit.s.empInfo.startTime = 0 + return 0.0 + } + + //------------------------ + // EMP effect is starting + //------------------------ + + if ( elapsedTime < fadeInTime ) + { + return GraphCapped( elapsedTime, 0.0, fadeInTime, 0.0, 1.0 ) + } + + //---------------------- + // EMP effect is ending + //---------------------- + + if ( elapsedTime > fadeInTime + cockpit.s.empInfo.duration ) + { + cockpit.s.empInfo["sub_count"] = 0 + return GraphCapped( elapsedTime, fadeInTime + cockpit.s.empInfo.duration, fadeInTime + cockpit.s.empInfo.duration + fadeOutTime, 1.0, 0.0 ) + } + + //--------------------- + // EMP flicker effect + //--------------------- + + // Time to start a new flicker + if ( cockpit.s.empInfo["sub_start"] == 0 ) + { + cockpit.s.empInfo["sub_start"] <- Time() + if ( cockpit.s.empInfo["sub_count"] == 0 ) + cockpit.s.empInfo["sub_pause"] <- RandomFloatRange( 0.5, 1.5 ) + else + cockpit.s.empInfo["sub_pause"] <- RandomFloat( 0.5 ) + cockpit.s.empInfo["sub_duration"] <- RandomFloatRange( 0.1, 0.4 ) + cockpit.s.empInfo["sub_alpha"] <- RandomFloatRange( 0.4, 0.9 ) + cockpit.s.empInfo["sub_count"]++; + } + local flickerElapsedTime = Time() - cockpit.s.empInfo["sub_start"] + + // Start a new flicker if the current one is finished + if ( flickerElapsedTime > cockpit.s.empInfo["sub_pause"] + cockpit.s.empInfo["sub_duration"] ) + cockpit.s.empInfo["sub_start"] = 0 + + if ( flickerElapsedTime < cockpit.s.empInfo["sub_pause"] ) + { + // Pause before the flicker + return 1.0 + } + else if ( flickerElapsedTime < cockpit.s.empInfo["sub_pause"] + ( cockpit.s.empInfo["sub_duration"] / 2.0 ) ) + { + // First half of the flicker + return GraphCapped( flickerElapsedTime, 0.0, cockpit.s.empInfo["sub_duration"] / 2.0, 1.0, cockpit.s.empInfo["sub_alpha"] ) + } + else + { + // Second half of the flicker + return GraphCapped( flickerElapsedTime, cockpit.s.empInfo["sub_duration"] / 2.0, cockpit.s.empInfo["sub_duration"], cockpit.s.empInfo["sub_alpha"], 1.0 ) + } +} + +function ServerCallback_TitanCockpitEMP( duration ) +{ + thread TitanCockpit_DoEMP( duration / 4 ) +} + +function TitanCockpit_DoEMP( duration ) +{ + entity player = GetLocalViewPlayer() + entity cockpit = player.GetCockpit() + + if ( !IsValid( cockpit ) ) + return + + if ( !player.IsTitan() ) + return + + if ( !player.s.inTitanCockpit ) + return + + Signal( player, "EMP" ) + EndSignal( player, "EMP" ) + player.EndSignal( "OnDestroy" ) + + // this needs tweaking... looks a bit artificial + ClientCockpitShake( 0.25, 3, 1.0, Vector( 0, 0, 1 ) ) // amplitude, frequency, duration, direction + + thread PlayCockpitEMPLights( cockpit, duration ) + + // Start the screens and vdu power outages + cockpit.s.empInfo.xOffset = RandomFloatRange( 0.5, 0.75 ) + cockpit.s.empInfo.yOffset = RandomFloatRange( 0.5, 0.75 ) + if ( CoinFlip() ) + cockpit.s.empInfo.xOffset *= -1 + if ( CoinFlip() ) + cockpit.s.empInfo.yOffset *= -1 + + cockpit.s.empInfo.startTime = Time() + cockpit.s.empInfo.duration = duration + + EmitSoundOnEntity( player, EMP_IMPARED_SOUND ) + wait duration + FadeOutSoundOnEntity( player, EMP_IMPARED_SOUND, 1.5 ) +} + +function PlayCockpitEMPLights( cockpit, duration ) +{ + duration += 1.5 // blend out + local attachID + local origin + local angles + local fxLights = [] + + string tagName = "COCKPIT" // SCR_CL_BL" + attachID = cockpit.LookupAttachment( tagName ) + origin = cockpit.GetAttachmentOrigin( attachID ) + origin.z -= 25 + angles = Vector( 0, 0, 0 ) + local lightTable = {} + lightTable.light <- CreateClientSideDynamicLight( origin, angles, Vector( 0.0, 0.0, 0.0 ), 80.0 ) + lightTable.modulate <- true + fxLights.append( lightTable ) + + wait 0.5 + + foreach ( fxLight in fxLights ) + { + fxLight.light.SetCockpitLight( true ) + } + + local startTime = Time() + local rate = 1.2 + + local endTime = Time() + duration + + while ( IsValid( cockpit ) ) + { + if ( Time() > endTime ) + break + + float subtractColor = GraphCapped( Time(), endTime - 0.25, endTime, 1.0, 0.0 ) + local pulseFrac = GetPulseFrac( rate, startTime ) + pulseFrac *= subtractColor + //pulseFrac -= fadeInColor + + foreach ( index, fxLight in fxLights ) + { + Assert( fxLight.modulate ) + fxLight.light.SetLightColor( Vector( pulseFrac, 0, 0 ) ) + + // the case where fxLight.modulate == false used to be handled by this script, which used undefined variable fadeInColor: + // fxLight.light.SetLightColor( Vector( fadeInColor, fadeInColor, fadeInColor ) ) + } + + WaitFrame() + } + + foreach ( fxLight in fxLights ) + { + fxLight.light.Destroy() + } +} + + +function TitanCockpit_IsBooting( cockpit ) +{ + return cockpit.GetTimeInCockpit() < 1.3 +} + +function TitanCockpitAnimThink( cockpit, body ) +{ + cockpit.SetOpenViewmodelOffset( 20.0, 0.0, 10.0 ) + cockpit.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + + if ( body ) + body.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) +} + + +bool function IsDisplayingEjectInterface( entity player ) +{ + if ( !player.IsTitan() ) + return false + + if ( player.ContextAction_IsMeleeExecution() ) //Could just check for ContextAction_IsActive() if we need to be more general + return false + + if ( !GetDoomedState( player ) && Time() - player.p.ejectEnableTime > EJECT_FADE_TIME ) + return false + + if ( Riff_TitanExitEnabled() == eTitanExitEnabled.Never || Riff_TitanExitEnabled() == eTitanExitEnabled.DisembarkOnly ) + return false + + //if ( !CanDisembark( player ) ) + // return false + + return true +} + +void function PlayerPressed_Eject( entity player ) +{ + if ( !IsDisplayingEjectInterface( player ) ) + return + + if ( Time() - player.p.ejectPressTime > TITAN_EJECT_MAX_PRESS_DELAY ) + UpdateEjectHud_SetButtonPressCount( player, 0 ) + + if ( !IsAlive( player ) ) + return + + EmitSoundOnEntity( player, "titan_eject_xbutton" ) + EmitSoundOnEntity( player, "hud_boost_card_radar_jammer_redtextbeep_1p" ) + UpdateEjectHud_SetButtonPressTime( player ) + UpdateEjectHud_SetButtonPressCount( player, (player.p.ejectPressCount + 1) ) + + player.ClientCommand( "TitanEject " + player.p.ejectPressCount ) + + entity cockpit = player.GetCockpit() + if ( player.p.ejectPressCount < 3 || cockpit.s.ejectStartTime ) + return + + PlayerEjects( player, cockpit ) +} + +string function RollRandomEjectString() +{ + const int COCKPIT_EJECT_COMMON_COUNT = 6 + const int COCKPIT_EJECT_RARE_COUNT = 36 + const float CHANCE_FOR_RARE = 0.15 + + float randForType = RandomFloat( 1.0 ) + if ( randForType < CHANCE_FOR_RARE ) + { + int index = RandomInt( COCKPIT_EJECT_RARE_COUNT ) + string result = "#COCKPIT_EJECT_RARE_" + index + return result + } + + int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT ) + string result = "#COCKPIT_EJECT_COMMON_" + index + return result +} + +void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal +{ + // prevent animation from playing if player is in the middle of execution + if ( player.ContextAction_IsActive() && !player.ContextAction_IsBusy() ) + return + + player.Signal( "Ejecting" ) + + SetCockpitUIEjectingState( true ) + + local ejectAlarmSound + cockpit.s.ejectStartTime = Time() + string animationName + if ( GetNuclearPayload( player ) > 0 ) + { + animationName = "atpov_cockpit_eject_nuclear" + cockpit.Anim_NonScriptedPlay( animationName ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_eject_nuclear" ) + ejectAlarmSound = TITAN_NUCLEAR_DEATH_ALARM + } + else + { + animationName = "atpov_cockpit_eject" + cockpit.Anim_NonScriptedPlay( animationName ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_eject" ) + + ejectAlarmSound = TITAN_ALARM_SOUND + } + + thread LightingUpdateAfterOpeningCockpit() + thread EjectAudioThink( player, ejectAlarmSound ) + + float animDuration = cockpit.GetSequenceDuration( animationName ) + + thread MonitorPlayerEjectAnimBeingStuck( player, animDuration ) +} + +void function MonitorPlayerEjectAnimBeingStuck( entity player, float duration ) +{ + player.Signal( "MonitorPlayerEjectAnimBeingStuck" ) + player.EndSignal( "MonitorPlayerEjectAnimBeingStuck" ) + player.EndSignal( "OnDeath" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "SettingsChanged" ) + + + wait duration + 2.0 // 1s as a buffer + + if ( player.IsTitan() ) + { + entity cockpit = player.GetCockpit() + cockpit.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + if ( IsValid( cockpit.e.body ) ) + cockpit.e.body.Anim_NonScriptedPlay( "atpov_cockpit_hatch_close_idle" ) + + SetCockpitUIEjectingState( false ) + } +} + +function ServerCallback_EjectConfirmed() +{ + if ( !IsWatchingReplay() ) + return + + entity player = GetLocalViewPlayer() + entity cockpit = player.GetCockpit() + + if ( !cockpit || !IsTitanCockpitModelName( cockpit.GetModelName() ) ) + return + + PlayerEjects( player, cockpit ) +} + +function EjectAudioThink( entity player, ejectAlarmSound = TITAN_ALARM_SOUND ) +{ + EmitSoundOnEntity( player, ejectAlarmSound ) + TitanCockpit_PlayDialog( player, "manualEjectNotice" ) + + player.EndSignal( "OnDeath" ) + + player.WaitSignal( "SettingsChanged" ) + + if ( player.GetPlayerClass() != "pilot" ) + return + + OnThreadEnd( + function() : ( player ) + { + if ( !IsAlive( player ) ) + { + StopSoundOnEntity( player, TITAN_EJECT_ASCENT ) + StopSoundOnEntity( player, TITAN_EJECT_DESCENT ) + } + else + { + FadeOutSoundOnEntity( player, TITAN_EJECT_ASCENT, 0.25 ) + FadeOutSoundOnEntity( player, TITAN_EJECT_DESCENT, 0.25 ) + } + + StopSoundOnEntity( player, TITAN_EJECT_APEX ) + } + ) + + EmitSoundOnEntity( player, TITAN_EJECT_BOOST ) + + float startTime = Time() + float duration = GetSoundDuration( TITAN_EJECT_ASCENT ) + EmitSoundOnEntity( player, TITAN_EJECT_ASCENT ) + float timeOut = duration - 0.25 + vector velocity + float diff = 0.0 + + const int STAGE_ASCENT = 1 + const int STAGE_APEX = 2 + const int STAGE_DESCENT = 3 + + int ejectStage = STAGE_ASCENT + + string currentSound = TITAN_EJECT_ASCENT + + while ( diff < timeOut ) + { + PerfStart( 127 ) + + diff = (Time() - startTime) + + velocity = player.GetVelocity() + float length = Length( velocity ) + + if ( diff > 0.5 ) + { + if ( player.IsOnGround() ) + { + PerfEnd( 127 ) + break + } + } + + if ( ejectStage != STAGE_DESCENT && velocity.z < 0 ) + { + FadeOutSoundOnEntity( player, TITAN_EJECT_ASCENT, 0.25 ) + timeOut = GetSoundDuration( TITAN_EJECT_DESCENT ) + EmitSoundOnEntity( player, TITAN_EJECT_DESCENT ) + currentSound = TITAN_EJECT_DESCENT + ejectStage = STAGE_DESCENT + } + else if ( ejectStage == STAGE_ASCENT && length < 400 ) + { + EmitSoundOnEntity( player, TITAN_EJECT_APEX ) + ejectStage = STAGE_APEX + } + + PerfEnd( 127 ) + + WaitFrame() + } +} + +function LightingUpdateAfterOpeningCockpit() +{ + while ( true ) + { + if ( !GetLocalViewPlayer().s.inTitanCockpit ) + break + WaitFrame() + } + + SetCockpitLightingEnabled( 0, false ) +} + + +function TonemappingUpdateAfterOpeningCockpit() //Deprecated, no longer used +{ + local duration = 3 + local tonemapMin = 2 + local tonemapMax = 5 + + while ( true ) + { + if ( !GetLocalViewPlayer().s.inTitanCockpit ) + break + WaitFrame() + } + + SetCockpitLightingEnabled( 0, false ) + + AutoExposureSetExposureCompensationBias( tonemapMax ) + AutoExposureSnap() + wait( 0.1 ) + + TitanDisembarkDSP( 0.5 ) + + local startTime = Time() + while ( true ) + { + local time = Time() - startTime + float factor = GraphCapped( time, 0, duration, 1, 0 ) + factor = factor * factor * factor + local toneMapScale = tonemapMin + (tonemapMax - tonemapMin) * factor + AutoExposureSetExposureCompensationBias( toneMapScale ) + AutoExposureSnap() + wait 0 + if ( factor == 0 ) + break + } + + AutoExposureSetExposureCompensationBias( 0 ) +} + +function ServerCallback_TitanEmbark() +{ + TitanCockpit_PlayDialog( GetLocalViewPlayer(), "embark" ) +} + +function ServerCallback_TitanDisembark() +{ + entity player = GetLocalViewPlayer() + + thread LightingUpdateAfterOpeningCockpit() + + //HideFriendlyIndicatorAndCrosshairNames() + + //PlayMusic( "Music_FR_Militia_PilotAction2" ) +} + + +function PlayerPressed_QuickDisembark( player ) +{ + player.ClientCommand( "TitanDisembark" ) +} + +void function PlayerPressed_EjectEnable( entity player ) +{ + if ( !player.IsTitan() ) + return + + if ( !IsAlive( player ) ) + return + + if ( IsValid( player.GetParent() ) ) + return + + if ( TitanEjectIsDisabled() ) + { + EmitSoundOnEntity( player, "CoOp_SentryGun_DeploymentDeniedBeep" ) + SetTimedEventNotification( 1.5, "" ) + SetTimedEventNotification( 1.5, "#NOTIFY_EJECT_DISABLED" ) + return + } + + if ( Riff_TitanExitEnabled() == eTitanExitEnabled.Never || Riff_TitanExitEnabled() == eTitanExitEnabled.DisembarkOnly ) + return + + //if ( !CanDisembark( player ) ) + // return + + if ( player.ContextAction_IsMeleeExecution() ) //Could just check for ContextAction_IsActive() if we need to be more general + return + + if ( player.GetHealth() == 1 ) + { + #if MP + if ( !FD_ReadyUpEnabled() ) + #endif + { + player.ClientCommand( "TitanEject " + 3 ) + return + } + } + + EmitSoundOnEntity( player, "titan_eject_dpad" ) + UpdateEjectHud_SetManualEjectStartTime( player ) + player.Signal( "UpdateRodeoAlert" ) // need this to hide titan stomp hint +} + +float function CalcJoltMagnitude( player, cockpit, joltDir, float damageAmount, damageType, int damageSourceID ) +{ + const float COCKPIT_MAX_JOLT_DAMAGE = 2000.0 + + float resultRaw = damageAmount / COCKPIT_MAX_JOLT_DAMAGE + return clamp( resultRaw, 0.0, 1.0 ) +} + +function JoltCockpit( cockpit, player, joltDir, float damageAmount, damageType, damageSourceId ) +{ + float severity = CalcJoltMagnitude( player, cockpit, joltDir, damageAmount, damageType, expect int( damageSourceId ) ) + player.CockpitJolt( joltDir, severity ) +} + +function RandomizeDir( dir, randPitch = 0, randYaw = 0, basePitch = 0, baseYaw = 0 ) +{ + local pitch = RandomFloatRange( -randPitch, randPitch ) + local yaw = RandomFloatRange( -randYaw, randYaw ) + local angles = VectorToAngles( dir ) + angles = AnglesCompose( angles, Vector( pitch, yaw, 0 ) ) + angles = AnglesCompose( angles, Vector( basePitch, baseYaw, 0 ) ) + return AnglesToForward( angles ) +} + +function TitanCockpitDoomedThink( cockpit, player ) +{ + cockpit.EndSignal( "OnDestroy" ) + + local titanSoul = player.GetTitanSoul() + + if ( titanSoul == null || !titanSoul.IsDoomed() ) + WaitSignal( player, "Doomed", "Ejecting" ) + + local color = Vector( 0.6, 0.06, 0 ) + local radius = 70.0 + + FlashCockpitLight( cockpit, color, radius, -1 ) +} + +void function TitanCockpitHealthChangedThink( cockpit, entity player ) +{ + cockpit.EndSignal( "OnDestroy" ) + + while ( true ) + { + table results = WaitSignal( player, "HealthChanged" ) + + if ( !IsAlive( player ) ) + continue + + float oldHealthFrac = float( results.oldHealth ) / float( player.GetMaxHealth() ) + float newHealthFrac = float( results.newHealth ) / float( player.GetMaxHealth() ) + + if ( oldHealthFrac > newHealthFrac ) + { + var rui = RuiCreate( $"ui/ajax_cockpit_lost_health_segment.rpak", clGlobal.topoTitanCockpitHud, RUI_DRAW_COCKPIT, 10 ) + RuiSetGameTime( rui, "startTime", Time() ) + RuiSetFloat( rui, "oldHealthFrac", oldHealthFrac ) + RuiSetFloat( rui, "newHealthFrac", newHealthFrac ) + + string playerSettings = GetLocalViewPlayer().GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( rui, "numHealthSegments", int( health / healthPerSegment ) ) + } + } +} + + +function FlashCockpitLight( cockpit, color, radius, duration, tag = "SCR_CL_BL" ) +{ + cockpit.EndSignal( "TitanUnDoomed" ) + cockpit.EndSignal( "OnDestroy" ) + + local attachID = cockpit.LookupAttachment( tag ) + local origin = cockpit.GetAttachmentOrigin( attachID ) + local angles = Vector( 0, 0, 0 ) + + local fxLight = CreateClientSideDynamicLight( origin, angles, color, radius ) + fxLight.SetCockpitLight( true ) + fxLight.SetParent( cockpit ) + + OnThreadEnd( + function() : ( fxLight ) + { + fxLight.Destroy() + } + ) + + local startTime = Time() + local rate = 3.0 + + while ( IsValid( cockpit ) && (Time() < startTime + duration || duration == -1 ) ) + { + local pulseFrac = GetPulseFrac( rate, startTime ) + pulseFrac += 0.5 + fxLight.SetLightColor( Vector( color.x * pulseFrac, color.y * pulseFrac, color.z * pulseFrac ) ) + + WaitFrame() + } +} + +function PlayCockpitSparkFX_Internal( cockpit, string tagName ) +{ + expect entity( cockpit ) + + // this is called from a delaythread so needs valid check + if ( !IsValid( cockpit ) ) + return + + int attachID = cockpit.LookupAttachment( tagName ) + if ( attachID == 0 ) + { + tagName = CoinFlip() ? "FX_TL_PANEL" : "FX_TR_PANEL" + attachID = cockpit.LookupAttachment( tagName ) + Assert( attachID, "Could not find fallback attachment index " + attachID + " for '" + tagName + "'' in model " + GetLocalViewPlayer().GetCockpit().GetModelName() ) + } + + int fxID = GetParticleSystemIndex( $"xo_cockpit_spark_01" ) + int fxInstID = PlayFXOnTag( cockpit, fxID, attachID ) + + EffectSetIsWithCockpit( fxInstID, true ) +} + +function PlayCockpitSparkFX( cockpit, int sparkCount ) +{ + const int TAG_COUNT = 6 + const string[TAG_COUNT] cockpitFXEmitTags = [ "FX_TL_PANEL", "FX_TR_PANEL", "FX_TC_PANELA", "FX_TC_PANELB", "FX_BL_PANEL", "FX_BR_PANEL" ] + array playlist = [0,1,2,3,4,5] + playlist.randomize() + + for ( int idx = 0; idx < sparkCount; idx++ ) + { + int lookup = (idx % TAG_COUNT) + int tagIndex = playlist[lookup] + string tagName = cockpitFXEmitTags[tagIndex] + PlayCockpitSparkFX_Internal( cockpit, tagName ) + } +} + +const int DAMAGE_PER_SPARK = 1000 +const int SPARK_MULTIPLIER = 3 + +int function CalSparkCountForHit( entity player, float damageAmount, bool becameDoomed ) +{ + if ( becameDoomed ) + return 20 + if ( damageAmount <= 0 ) + return 0 + + int healthNow = player.GetHealth() + int healthPrev = healthNow + int( damageAmount ) + int healthMax = player.GetMaxHealth() + + bool isDoomed = GetDoomedState( player ) + int sparksNow = (healthNow / DAMAGE_PER_SPARK) + int sparksPrev = (healthPrev / DAMAGE_PER_SPARK) + if ( (healthPrev == healthMax) && !isDoomed ) + --sparksPrev // no spark on first damage + + int delta = (sparksPrev - sparksNow) + if ( delta < 0 ) + return 0 + + return (delta * SPARK_MULTIPLIER) +} + +function TitanCockpit_DamageFeedback( entity player, cockpit, float damageAmount, damageType, damageOrigin, damageSourceId, bool doomedNow, int doomedDamage ) +{ + RumbleForTitanDamage( damageAmount ) + + vector joltDir = Normalize( player.CameraPosition() - damageOrigin ) + float joltDamage = doomedNow ? float( doomedDamage ) : damageAmount + JoltCockpit( cockpit, player, joltDir, joltDamage, damageType, damageSourceId ) + + bool isShieldHit = (damageType & DF_SHIELD_DAMAGE) ? true : false + if ( isShieldHit ) + return + + int sparkCount = CalSparkCountForHit( player, damageAmount, doomedNow ); + //printt( "sparks: " + sparkCount + " dmg: " + damageAmount + " - " + player.GetHealth() + " / " + player.GetMaxHealth() ) + PlayCockpitSparkFX( cockpit, sparkCount ) +} + +function ServerCallback_TitanCockpitBoot() +{ + thread ServerCallback_TitanCockpitBoot_Internal() +} + +function ServerCallback_TitanCockpitBoot_Internal() +{ + AutoExposureSetExposureCompensationBias( -6 ) + AutoExposureSnap() + wait 0.1 + AutoExposureSetExposureCompensationBias( 0 ) +} + +function ServerCallback_TitanEMP( maxValue, duration, fadeTime, doFlash = true, doSound = true ) +{ + thread TitanEMP_Internal( maxValue, duration, fadeTime, doFlash, doSound ) +} + +function TitanEMP_Internal( maxValue, duration, fadeTime, doFlash = true, doSound = true ) +{ + entity player = GetLocalViewPlayer() + + player.Signal( "TitanEMP_Internal" ) + player.EndSignal( "TitanEMP_Internal" ) + + player.EndSignal( "OnDeath" ) + player.EndSignal( "SettingsChanged" ) + + local angles = Vector( 0, -90, 90 ) + + local wide = 16 + local tall = 9 + + float fovOffset = Graph( player.GetFOV(), 75, 120, 4, 2.5 ) + + local empVgui = CreateClientsideVGuiScreen( "vgui_titan_emp", VGUI_SCREEN_PASS_VIEWMODEL, Vector(0,0,0), Vector(0,0,0), wide, tall ); + + //empVgui.SetParent( player.GetViewModelEntity(), "CAMERA_BASE" ) + empVgui.SetRefract( true ) // Force refract resolve before drawing vgui. (This can cost GPU!) + empVgui.SetParent( player ) + empVgui.SetAttachOffsetOrigin( < fovOffset, wide / 2, -tall / 2 > ) + empVgui.SetAttachOffsetAngles( angles ) + + empVgui.GetPanel().WarpEnable() + + local EMPScreenFX = HudElement( "EMPScreenFX", empVgui.GetPanel() ) + local EMPScreenFlash = HudElement( "EMPScreenFlash", empVgui.GetPanel() ) + + OnThreadEnd( + function() : ( player, empVgui ) + { + empVgui.Destroy() + } + ) + + EMPScreenFX.Show() + EMPScreenFX.SetAlpha( maxValue * 255 ) + EMPScreenFX.FadeOverTimeDelayed( 0, fadeTime, duration ) + + if ( doFlash ) + { + EMPScreenFlash.Show() + EMPScreenFlash.SetAlpha( 255 ) + EMPScreenFlash.FadeOverTimeDelayed( 0, fadeTime + duration, 0 ) + } + + if ( doSound ) + { + EmitSoundOnEntity( player, EMP_IMPARED_SOUND ) + wait duration + FadeOutSoundOnEntity( player, EMP_IMPARED_SOUND, fadeTime ) + } + + wait fadeTime +} + + +void function LinkCoreHint( entity soul ) +{ + if ( file.coreHintRui == null ) + return + + RuiTrackFloat( file.coreHintRui, "coreFrac", soul, RUI_TRACK_SCRIPT_NETWORK_VAR, GetNetworkedVariableIndex( "coreAvailableFrac" ) ) +} + + +void function FlashCockpitHealth( vector color ) +{ + if ( file.cockpitRui == null ) + return + + RuiSetGameTime( file.cockpitRui, "startFlashTime", Time() ) + RuiSetFloat3( file.cockpitRui, "flashColor", color ) +} + +void function UpdateHealthSegmentCount() +{ + if ( file.cockpitRui == null ) + return + + entity player = GetLocalViewPlayer() + string playerSettings = player.GetPlayerSettings() + float health = player.GetPlayerModHealth() + float healthPerSegment = GetPlayerSettingsFieldForClassName_HealthPerSegment( playerSettings ) + RuiSetInt( file.cockpitRui, "numHealthSegments", int( health / healthPerSegment ) ) +} +#if MP +void function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus( entity soul, int oldValue, int newValue, bool actuallyChanged ) +{ + if ( file.cockpitRui == null ) + return + + if ( actuallyChanged == false ) + return + + entity player = GetLocalViewPlayer() + if ( !IsValid( player ) || !player.IsTitan() ) + return + + UpdateHealthSegmentCount() + + string titanName = GetTitanCharacterName( player ) + if ( titanName == "vanguard" ) + { + RuiSetString( file.cockpitRui, "titanInfo1", GetVanguardCoreString( player, 1 ) ) + RuiSetString( file.cockpitRui, "titanInfo2", GetVanguardCoreString( player, 2 ) ) + RuiSetString( file.cockpitRui, "titanInfo3", GetVanguardCoreString( player, 3 ) ) + RuiSetString( file.cockpitRui, "titanInfo4", GetVanguardCoreString( player, 4 ) ) + } +} +#endif + +var function Scorch_CreateHotstreakBar() +{ + Assert( file.scorchHotstreakRui == null ) + + file.scorchHotstreakRui = CreateFixedTitanCockpitRui( $"ui/scorch_hotstreak_bar.rpak" ) + + RuiTrackFloat( file.scorchHotstreakRui, "coreMeterMultiplier", GetLocalViewPlayer(), RUI_TRACK_SCRIPT_NETWORK_VAR, GetNetworkedVariableIndex( "coreMeterModifier" ) ) + + return file.scorchHotstreakRui +} + +void function Scorch_DestroyHotstreakBar() +{ + TitanCockpitDestroyRui( file.scorchHotstreakRui ) + file.scorchHotstreakRui = null +} + +bool function Scorch_ShouldCreateHotstreakBar() +{ + entity player = GetLocalViewPlayer() + + if ( !IsAlive( player ) ) + return false + + array mainWeapons = player.GetMainWeapons() + if ( mainWeapons.len() == 0 ) + return false + + entity primaryWeapon = mainWeapons[0] + return primaryWeapon.HasMod( "fd_hot_streak" ) +} -- cgit v1.2.3 From 74f0ee8b5807e2c46541cdbc3460165200051b07 Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Sat, 12 Nov 2022 14:15:03 +0000 Subject: Add eject quotes (#527) * Upload cl_titan_cockpit.nut * Add eject string in script * Moved to client * index issue + removed else so always returns * Apply suggestions from code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Rest of the suggestions because github makes me want to cry * Commit suggestions from review GitHub really hates batching suggestions Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../scripts/vscripts/client/cl_titan_cockpit.nut | 35 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut index 828f3056..4df1af42 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -36,6 +36,11 @@ global function UpdateEjectHud_SetButtonPressTime global function UpdateEjectHud_SetButtonPressCount global function SetUnlimitedDash + +// Added by northstar +global function AddCommonEjectMessage +global function AddRareEjectMessage + #if MP global function NetworkedVarChangedCallback_UpdateVanguardRUICoreStatus global function DisplayFrontierRank @@ -71,6 +76,9 @@ struct bool isFirstBoot = true var scorchHotstreakRui + // Added by northstar + array moddedRareEjectMessages + array moddedCommonEjectMessages } file function ClTitanCockpit_Init() @@ -1007,6 +1015,16 @@ void function PlayerPressed_Eject( entity player ) PlayerEjects( player, cockpit ) } +void function AddCommonEjectMessage( string message ) +{ + file.moddedCommonEjectMessages.append( message ) +} + +void function AddRareEjectMessage( string message ) +{ + file.moddedRareEjectMessages.append( message ) +} + string function RollRandomEjectString() { const int COCKPIT_EJECT_COMMON_COUNT = 6 @@ -1016,14 +1034,19 @@ string function RollRandomEjectString() float randForType = RandomFloat( 1.0 ) if ( randForType < CHANCE_FOR_RARE ) { - int index = RandomInt( COCKPIT_EJECT_RARE_COUNT ) - string result = "#COCKPIT_EJECT_RARE_" + index - return result + int index = RandomInt( COCKPIT_EJECT_RARE_COUNT + file.moddedRareEjectMessages.len() ) + if ( index < COCKPIT_EJECT_RARE_COUNT ) + return "#COCKPIT_EJECT_RARE_" + index + else + return file.moddedRareEjectMessages[index - COCKPIT_EJECT_RARE_COUNT] } - int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT ) - string result = "#COCKPIT_EJECT_COMMON_" + index - return result + int index = RandomInt( COCKPIT_EJECT_COMMON_COUNT + file.moddedCommonEjectMessages.len() ) + if ( index < COCKPIT_EJECT_COMMON_COUNT ) + return "#COCKPIT_EJECT_COMMON_" + index + else + return file.moddedCommonEjectMessages[index - COCKPIT_EJECT_COMMON_COUNT] + } void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal -- cgit v1.2.3 From 17d8f97607f51e75497ed413d0d80f8416a2b3e6 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 14 Nov 2022 22:22:52 +0000 Subject: Add missing `unreachable` to stop compile error (#528) --- Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut index 4df1af42..8261b3fd 100644 --- a/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut +++ b/Northstar.Client/mod/scripts/vscripts/client/cl_titan_cockpit.nut @@ -1047,6 +1047,7 @@ string function RollRandomEjectString() else return file.moddedCommonEjectMessages[index - COCKPIT_EJECT_COMMON_COUNT] + unreachable } void function PlayerEjects( entity player, entity cockpit ) //Note that this can be run multiple times in a frame, e.g. get damaged by 4 pellets of a shotgun that brings the Titan into a doomed state with auto eject. Not ideal -- cgit v1.2.3 From 3f80f07ac14dc210261601e7c59968b5d2c38e2c Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Wed, 16 Nov 2022 00:58:23 +0000 Subject: Use new system for adding keybinds to `kb_act.lst` (#529) --- Northstar.Client/kb_act.lst | 13 +++++++ Northstar.Client/mod/scripts/kb_act.lst | 63 --------------------------------- 2 files changed, 13 insertions(+), 63 deletions(-) create mode 100644 Northstar.Client/kb_act.lst delete mode 100644 Northstar.Client/mod/scripts/kb_act.lst diff --git a/Northstar.Client/kb_act.lst b/Northstar.Client/kb_act.lst new file mode 100644 index 00000000..1a4f7129 --- /dev/null +++ b/Northstar.Client/kb_act.lst @@ -0,0 +1,13 @@ +"blank" "==========================" +"blank" "NORTHSTAR" +"blank" "==========================" +"toggleconsole" "Toggle Developer Console" +"vote 1" "Vote 1" +"vote 2" "Vote 2" +"vote 3" "Vote 3" +"vote 4" "Vote 4" +"vote 5" "Vote 5" +"vote 6" "Vote 6" +"vote 7" "Vote 7" +"vote 8" "Vote 8" +"vote 9" "Vote 9" diff --git a/Northstar.Client/mod/scripts/kb_act.lst b/Northstar.Client/mod/scripts/kb_act.lst deleted file mode 100644 index 238d7eef..00000000 --- a/Northstar.Client/mod/scripts/kb_act.lst +++ /dev/null @@ -1,63 +0,0 @@ -"blank" "==========================" -"blank" "NORTHSTAR" -"blank" "==========================" -"toggleconsole" "Toggle Developer Console" -"vote 1" "Vote 1" -"vote 2" "Vote 2" -"vote 3" "Vote 3" -"vote 4" "Vote 4" -"vote 5" "Vote 5" -"vote 6" "Vote 6" -"vote 7" "Vote 7" -"vote 8" "Vote 8" -"vote 9" "Vote 9" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_ACTIONS" -"blank" "==========================" -"+attack" "#FIRE" -"+zoom" "#AIM_MODIFIER" -"+toggle_zoom" "#TOGGLE_AIM_MODIFIER" -"+reload" "#RELOAD" -"+weaponCycle" "#SWITCH_WEAPONS_PILOT" -"weaponSelectPrimary0" "#SWITCH_TO_WEAPON1" -"weaponSelectPrimary1" "#SWITCH_TO_WEAPON2" -"weaponSelectPrimary2" "#SWITCH_TO_WEAPON3" -"+melee" "#MELEE" -"+offhand0" "#ORDNANCE_GRENADE" -"+offhand1" "#TACTICAL_ABILITY" -"+offhand2" "#TITAN_UTILITY_BIND" -"+use" "#USE_DISEMBARK" -"+scriptCommand1" "#DISABLE_EJECT_SAFETY_TITAN" -"+ability 1" "#SWITCH_TITAN_AI_MODE_PILOT" -"+ability 6" "#KEYBINDING_MENU_BURN_CARD" -"titan_loadout_select" "#TITAN_LOADOUT_SELECT" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_MOVEMENT" -"blank" "==========================" -"+forward" "#MOVE_FORWARD" -"+back" "#MOVE_BACK" -"+moveleft" "#MOVE_LEFT" -"+moveright" "#MOVE_RIGHT" -"+speed" "#SPRINT" -"+ability 3" "#JUMP_PILOT_DASH_TITAN" -"+duck" "#CROUCH" -"+toggle_duck" "#TOGGLE_CROUCH" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_COMMUNICATION" -"blank" "==========================" -"+pushtotalk" "#PUSH_TO_TALK_KEY" -"say" "#CHAT_MESSAGE" -"say_team" "#TEAM_CHAT_MESSAGE" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_SCOREBOARD" -"blank" "==========================" -"+showscores" "#TOGGLE_SCOREBOARD" -"scoreboard_toggle_focus" "#SCOREBOARD_FOCUS" -"scoreboard_up" "#SCOREBOARD_SCROLL_UP" -"scoreboard_down" "#SCOREBOARD_SCROLL_DOWN" -"scoreboard_profile" "#SCOREBOARD_VIEW_PROFILE" -"scoreboard_mute" "#SCOREBOARD_MUTE" -"blank" "==========================" -"blank" "#KEY_BINDINGS_HEADER_MISCELLANEOUS" -"blank" "==========================" -"jpeg" "#SCREENSHOT" -- cgit v1.2.3 From 4730389c3bc0e750eab2ecdc3fd9a781f70e12a3 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Mon, 21 Nov 2022 00:00:02 +0000 Subject: Add entity functions for reading userinfo cvars to CPlayer class (#521) * add entity functions for reading userinfo cvars to CPlayer class * fix formatting * update to use new functions from launcher pr --- .../mod/scripts/vscripts/class/cplayer.nut | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) 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 ) -- cgit v1.2.3 From 891c2afe222930d9bd5a0edb6471c9f7d8da2d42 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 1 Dec 2022 20:25:12 +0000 Subject: Remove unnecessary root table setting and make functions global (#534) * fix for CHudChat_ProcessMessageStartThread not working in native * remove unneeded NSSetupChathooksClient callback * fix for CServerGameDLL_ProcessMessageStartThread not working in native * remove unneeded NSSetupChathooksServer callback * remove root table setting for ServerToClientStringCommands_Init * remove unneeded ServerToClientStringCommands_Init callback * remove global function --- Northstar.Client/mod.json | 5 +---- .../mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 9 ++++----- Northstar.CustomServers/mod.json | 10 ++-------- .../mod/scripts/vscripts/_custom_codecallbacks.gnut | 9 ++++----- .../scripts/vscripts/sh_server_to_client_stringcommands.gnut | 7 ------- 5 files changed, 11 insertions(+), 29 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 15853be7..3b236980 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -46,10 +46,7 @@ "Scripts": [ { "Path": "_custom_codecallbacks_client.gnut", - "RunOn": "CLIENT", - "ClientCallback": { - "Before": "NSSetupChathooksClient" - } + "RunOn": "CLIENT" }, { "Path": "client/cl_chat.gnut", diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 3caf4336..811874c5 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -1,7 +1,10 @@ untyped global function AddCallback_OnReceivedSayTextMessage -global function NSSetupChathooksClient + +// 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 (although there isnt rly a downside to it?) +global function CHudChat_ProcessMessageStartThread global struct ClClient_MessageStruct { string message @@ -135,7 +138,3 @@ void function AddCallback_OnReceivedSayTextMessage( ClClient_MessageStruct funct { NsCustomCallbacksClient.OnReceivedSayTextMessageCallbacks.append(callbackFunc) } - -void function NSSetupChathooksClient() { - getroottable().rawset("CHudChat_ProcessMessageStartThread", CHudChat_ProcessMessageStartThread) -} diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 2ed89910..f67aeb19 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -58,10 +58,7 @@ "Scripts": [ { "Path": "_custom_codecallbacks.gnut", - "RunOn": "SERVER", - "ServerCallback": { - "Before": "NSSetupChathooksServer" - } + "RunOn": "SERVER" }, { "Path": "_northstar_cheatcommands.nut", @@ -104,10 +101,7 @@ }, { "Path": "sh_server_to_client_stringcommands.gnut", - "RunOn": "CLIENT || SERVER", - "ClientCallback": { - "After": "ServerToClientStringCommands_Init" - } + "RunOn": "CLIENT || SERVER" }, { "Path": "gamemodes/_gamemode_fra.nut", 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/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 args ) > > callbacks } file -void function ServerToClientStringCommands_Init() -{ - getroottable().rawset( "NSClientCodeCallback_RecievedServerToClientStringCommand", NSClientCodeCallback_RecievedServerToClientStringCommand ) -} - void function AddServerToClientStringCommandCallback( string command, void functionref( array args ) callback ) { if ( !( command in file.callbacks ) ) -- cgit v1.2.3 From a4606ba8c3c6d816499ab73b6633dd1f33728adb Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 4 Dec 2022 23:04:45 +0100 Subject: Display server region in serverbrowser (#479) * Replace latency column with region in serverbrowser * Add English and German localisation * Mark remaining localisations as TODOs * Enable filtering by region using search field * Update tchinese translation for display server region in serverbrowser (#484) * Add French translation * Add Japanese translation * Add Portuguese translation * Add Russian translation * Add Spanish translation * Add Italian translation * Add Mexican Spanish translation --- .../northstar_client_localisation_english.txt | 2 +- .../northstar_client_localisation_french.txt | 2 +- .../northstar_client_localisation_german.txt | 2 +- .../northstar_client_localisation_italian.txt | 2 +- .../northstar_client_localisation_japanese.txt | 2 +- .../northstar_client_localisation_mspanish.txt | 2 +- .../northstar_client_localisation_portuguese.txt | 2 +- .../northstar_client_localisation_russian.txt | 2 +- .../northstar_client_localisation_spanish.txt | 2 +- .../northstar_client_localisation_tchinese.txt | 2 +- .../mod/resource/ui/menus/server_browser.menu | 70 +++++++++++----------- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 43 ++++++------- 12 files changed, 67 insertions(+), 66 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 3382e5b1..c25708a6 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -276,7 +276,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "PLAYERS_COLUMN" "Players" "MAP_COLUMN" "Map" "GAMEMODE_COLUMN" "Gamemode" - "LATENCY_COLUMN" "Latency" + "REGION_COLUMN" "Region" "SEARCHBAR_LABEL" "Search:" "MAP_FILTER" "Map" "GAMEMODE_FILTER" "Gamemode" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 276698a0..2a199186 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -276,7 +276,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PLAYERS_COLUMN" "Joueurs" "MAP_COLUMN" "Carte" "GAMEMODE_COLUMN" "Mode de jeu" - "LATENCY_COLUMN" "Latence" + "REGION_COLUMN" "Région" "SEARCHBAR_LABEL" "Recherche :" "MAP_FILTER" "Carte" "GAMEMODE_FILTER" "Mode de jeu" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 9077fac0..0316bbcf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -267,7 +267,7 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "PLAYERS_COLUMN" "Spieler" "MAP_COLUMN" "Karte" "GAMEMODE_COLUMN" "Modus" - "LATENCY_COLUMN" "Ping" + "REGION_COLUMN" "Region" "SEARCHBAR_LABEL" "Suche:" "MAP_FILTER" "Karte" "GAMEMODE_FILTER" "Modus" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index b0bc348f..72bf7030 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -275,7 +275,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PLAYERS_COLUMN" "Players" "MAP_COLUMN" "Mappa" "GAMEMODE_COLUMN" "Modalità" - "LATENCY_COLUMN" "Latenza" + "REGION_COLUMN" "Regione" "SEARCHBAR_LABEL" "Cerca:" "MAP_FILTER" "Mappa" "GAMEMODE_FILTER" "Modalità" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index b35c9fb8..b7fadeaf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -303,7 +303,7 @@ "PLAYERS_COLUMN" "プレイヤー" "MAP_COLUMN" "マップ" "GAMEMODE_COLUMN" "ゲームモード" - "LATENCY_COLUMN" "レイテンシー" + "REGION_COLUMN" "領域" "SEARCHBAR_LABEL" "検索:" "MAP_FILTER" "マップ" "GAMEMODE_FILTER" "ゲームモード" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index 208747f9..18634668 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -276,7 +276,7 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "PLAYERS_COLUMN" "Jugadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo de juego" - "LATENCY_COLUMN" "Latencia" + "REGION_COLUMN" "Región" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo de juego" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index d398e557..51854726 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -274,7 +274,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PLAYERS_COLUMN" "Jogadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo" - "LATENCY_COLUMN" "Latência" + "REGION_COLUMN" "Região" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index af9eb0ff..9ce0c2e3 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -219,7 +219,7 @@ "PLAYERS_COLUMN" "Игроки" "MAP_COLUMN" "Карта" "GAMEMODE_COLUMN" "Режим игры" - "LATENCY_COLUMN" "Задержка" + "REGION_COLUMN" "Регион" "SEARCHBAR_LABEL" "Поиск:" "MAP_FILTER" "Карта" "GAMEMODE_FILTER" "Режим игры" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index fa732b63..0dc82570 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -276,7 +276,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PLAYERS_COLUMN" "Jugadores" "MAP_COLUMN" "Mapa" "GAMEMODE_COLUMN" "Modo de juego" - "LATENCY_COLUMN" "Latencia" + "REGION_COLUMN" "Región" "SEARCHBAR_LABEL" "Buscar:" "MAP_FILTER" "Mapa" "GAMEMODE_FILTER" "Modo de juego" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 276a192d..12b6cad1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -276,7 +276,7 @@ "PLAYERS_COLUMN" "玩家" "MAP_COLUMN" "地圖" "GAMEMODE_COLUMN" "遊戲模式" - "LATENCY_COLUMN" "延遲" + "REGION_COLUMN" "地區" "SEARCHBAR_LABEL" "搜尋:" "MAP_FILTER" "地圖" "GAMEMODE_FILTER" "遊戲模式" diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index d25d1219..b66fb8a6 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -1178,7 +1178,7 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner TOP_RIGHT navDown BtnServer1 navLeft BtnServerMapTab - navRight BtnServerLatencyTab + navRight BtnServerRegionTab navUp BtnFiltersClear } @@ -1408,12 +1408,12 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner BOTTOM_LEFT } - // Latency - BtnServerLatencyTab + // Region + BtnServerRegionTab { ControlName RuiButton InheritProperties RuiSmallButton - labelText "#LATENCY_COLUMN" + labelText "#REGION_COLUMN" wide 110 xpos 4 @@ -1428,11 +1428,11 @@ resource/ui/menus/mods_browse.menu navUp BtnFiltersClear } - BtnServerLatency1 + BtnServerRegion1 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1443,11 +1443,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency2 + BtnServerRegion2 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1458,11 +1458,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency3 + BtnServerRegion3 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1473,11 +1473,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency4 + BtnServerRegion4 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1488,11 +1488,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency5 + BtnServerRegion5 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1503,11 +1503,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency6 + BtnServerRegion6 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1518,11 +1518,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency7 + BtnServerRegion7 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1533,11 +1533,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency8 + BtnServerRegion8 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1548,11 +1548,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency9 + BtnServerRegion9 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1563,11 +1563,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency10 + BtnServerRegion10 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1578,11 +1578,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency11 + BtnServerRegion11 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1593,11 +1593,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency12 + BtnServerRegion12 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1608,11 +1608,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency13 + BtnServerRegion13 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1623,11 +1623,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency14 + BtnServerRegion14 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1638,11 +1638,11 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - BtnServerLatency15 + BtnServerRegion15 { ControlName Label labelText "" - classname Serverlatency + classname Serverregion textAlignment center wide 110 tall 44 @@ -1737,7 +1737,7 @@ resource/ui/menus/mods_browse.menu xpos 3 ypos -1 - pin_to_sibling BtnServerLatencyTab + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner TOP_LEFT } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index d9b11ccc..03028255 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -38,7 +38,7 @@ enum sortingBy PLAYERS, MAP, GAMEMODE, - LATENCY + REGION } // Column sort direction, only one of these can be aplied at once @@ -48,8 +48,8 @@ struct { bool serverPlayers = true bool serverMap = true bool serverGamemode = true - bool serverLatency = true - // 0 = none; 1 = default; 2 = name; 3 = players; 4 = map; 5 = gamemode; 6 = latency + bool serverRegion = true + // 0 = none; 1 = default; 2 = name; 3 = players; 4 = map; 5 = gamemode; 6 = region int sortingBy = 1 } filterDirection @@ -61,7 +61,7 @@ struct serverStruct { int serverPlayersMax string serverMap string serverGamemode - int serverLatency + string serverRegion } struct { @@ -87,7 +87,7 @@ struct { array serversProtected array serversMap array serversGamemode - array serversLatency + array serversRegion } file @@ -151,7 +151,7 @@ void function InitServerBrowserMenu() file.serversProtected = GetElementsByClassname( file.menu, "ServerLock" ) file.serversMap = GetElementsByClassname( file.menu, "ServerMap" ) file.serversGamemode = GetElementsByClassname( file.menu, "ServerGamemode" ) - file.serversLatency = GetElementsByClassname( file.menu, "ServerLatency" ) + file.serversRegion = GetElementsByClassname( file.menu, "Serverregion" ) filterArguments.filterMaps = [ "SWITCH_ANY" ] Hud_DialogList_AddListItem( Hud_GetChild( file.menu, "SwtBtnSelectMap" ), "SWITCH_ANY", "0" ) @@ -194,7 +194,7 @@ void function InitServerBrowserMenu() AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerPlayersTab"), UIE_CLICK, SortServerListByPlayers_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerMapTab"), UIE_CLICK, SortServerListByMap_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerGamemodeTab"), UIE_CLICK, SortServerListByGamemode_Activate ) - AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerLatencyTab"), UIE_CLICK, SortServerListByLatency_Activate ) + AddButtonEventHandler( Hud_GetChild( file.menu, "BtnServerRegionTab"), UIE_CLICK, SortServerListByRegion_Activate ) AddButtonEventHandler( Hud_GetChild( file.menu, "SwtBtnSelectMap"), UIE_CHANGE, FilterAndUpdateList ) @@ -218,8 +218,6 @@ void function InitServerBrowserMenu() Hud_SetText( Hud_GetChild( file.menu, "BtnServerDescription"), "" ) Hud_SetText( Hud_GetChild( file.menu, "BtnServerMods"), "" ) - // Unfinished features - Hud_SetLocked( Hud_GetChild( file.menu, "BtnServerLatencyTab" ), true ) // Rui is a pain RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnHideFull") ), "buttonText", "" ) @@ -675,9 +673,9 @@ void function FilterAndUpdateList( var n ) filterDirection.serverGamemode = !filterDirection.serverGamemode SortServerListByGamemode_Activate(0) break - case sortingBy.LATENCY: - filterDirection.serverLatency = !filterDirection.serverLatency - SortServerListByLatency_Activate(0) + case sortingBy.REGION: + filterDirection.serverRegion = !filterDirection.serverRegion + SortServerListByRegion_Activate(0) break default: printt( "How the f did you get here" ) @@ -715,7 +713,7 @@ void function WaitForServerListRequest() Hud_SetText( file.playerCountLabels[ i ], "" ) Hud_SetText( file.serversMap[ i ], "" ) Hud_SetText( file.serversGamemode[ i ], "" ) - Hud_SetText( file.serversLatency[ i ], "" ) + Hud_SetText( file.serversRegion[ i ], "" ) } HideServerInfo() @@ -756,6 +754,7 @@ void function FilterServerList() tempServer.serverPlayersMax = NSGetServerMaxPlayerCount( i ) tempServer.serverMap = NSGetServerMap( i ) tempServer.serverGamemode = GetGameModeDisplayName( NSGetServerPlaylist ( i ) ) + tempServer.serverRegion = NSGetServerRegion( i ) totalPlayers += tempServer.serverPlayers @@ -786,6 +785,7 @@ void function FilterServerList() sName.append( tempServer.serverGamemode.tolower() ) sName.append( Localize( tempServer.serverGamemode ).tolower() ) sName.append( NSGetServerDescription( i ).tolower() ) + sName.append( NSGetServerRegion( i ).tolower() ) string sTerm = filterArguments.searchTerm.tolower() @@ -821,7 +821,7 @@ void function UpdateShownPage() Hud_SetText( file.playerCountLabels[ i ], "" ) Hud_SetText( file.serversMap[ i ], "" ) Hud_SetText( file.serversGamemode[ i ], "" ) - Hud_SetText( file.serversLatency[ i ], "" ) + Hud_SetText( file.serversRegion[ i ], "" ) } int j = file.serversArrayFiltered.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.serversArrayFiltered.len() @@ -840,6 +840,7 @@ void function UpdateShownPage() Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", file.serversArrayFiltered[ buttonIndex ].serverPlayers, file.serversArrayFiltered[ buttonIndex ].serverPlayersMax ) ) Hud_SetText( file.serversMap[ i ], GetMapDisplayName( file.serversArrayFiltered[ buttonIndex ].serverMap ) ) Hud_SetText( file.serversGamemode[ i ], file.serversArrayFiltered[ buttonIndex ].serverGamemode ) + Hud_SetText( file.serversRegion[ i ], file.serversArrayFiltered[ buttonIndex ].serverRegion ) } @@ -1161,10 +1162,10 @@ int function ServerSortLogic ( serverStruct a, serverStruct b ) bTemp = Localize( b.serverGamemode ).tolower() direction = filterDirection.serverGamemode break; - case sortingBy.LATENCY: - aTemp = a.serverLatency - bTemp = b.serverLatency - direction = filterDirection.serverLatency + case sortingBy.REGION: + aTemp = a.serverRegion + bTemp = b.serverRegion + direction = filterDirection.serverRegion break; default: return 0 @@ -1238,13 +1239,13 @@ void function SortServerListByGamemode_Activate( var button ) UpdateShownPage() } -void function SortServerListByLatency_Activate( var button ) +void function SortServerListByRegion_Activate( var button ) { - filterDirection.sortingBy = sortingBy.LATENCY + filterDirection.sortingBy = sortingBy.REGION file.serversArrayFiltered.sort( ServerSortLogic ) - filterDirection.serverLatency = !filterDirection.serverLatency + filterDirection.serverRegion = !filterDirection.serverRegion UpdateShownPage() } -- cgit v1.2.3 From b71a63e32beabec1d91029f88527c3462c80d758 Mon Sep 17 00:00:00 2001 From: ScureX <47725553+ScureX@users.noreply.github.com> Date: Mon, 5 Dec 2022 19:16:16 +0100 Subject: Fix calling `TitanEject` without arguments crashing server (#538) --- Northstar.CustomServers/mod/scripts/vscripts/titan/class_titan.gnut | 5 +++++ 1 file changed, 5 insertions(+) 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 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 -- cgit v1.2.3 From 4a1ff7d1f01b86e0eeb58850641e31a3d17282c4 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 9 Dec 2022 00:57:28 +0000 Subject: Localize stringcommands to allow servers to use localised messages (#535) * localize stringcommands to allow servers to use localised messages * formatting ig --- Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut index 6bbf77bd..4cfdc6fb 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_message_utils.gnut @@ -225,7 +225,7 @@ string function CombineArgsIntoString( array args ) // Ignore the first argument for( int i = 1; i < args.len(); i++ ) - result += args[i] + " " + result += Localize( args[i] ) + " " return result } -- cgit v1.2.3 From 52de846403d600e5f30c0a50d2c2ea24db2274b9 Mon Sep 17 00:00:00 2001 From: Erlite Date: Tue, 13 Dec 2022 17:37:31 +0100 Subject: Add Squirrel code for HTTP requests (#531) * Squirrel side of HTTP requests * Move to Northstar.Custom * Working HTTP requests from Squirrel * Fix overlooked delete, add comments * Add request success bool as return in req funcs. * Success callback uses struct now. * Never fix conflicts on mobile browsers, noted. * HttpRequest.baseUrl -> url --- Northstar.Custom/mod.json | 4 + .../vscripts/sh_northstar_http_requests.gnut | 235 +++++++++++++++++++++ 2 files changed, 239 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/sh_northstar_http_requests.gnut diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 1a08f0d4..d47c42cf 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -417,6 +417,10 @@ "ServerCallback": { "Before": "MessageUtils_ServerInit" } + }, + { + "Path": "sh_northstar_http_requests.gnut", + "RunOn": "CLIENT || SERVER || UI" } ], diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_http_requests.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_http_requests.gnut new file mode 100644 index 00000000..8ff55eae --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_http_requests.gnut @@ -0,0 +1,235 @@ +globalize_all_functions + +global enum HttpRequestMethod +{ + GET = 0, + POST = 1 + HEAD = 2, + PUT = 3, + DELETE = 4, + PATCH = 5, + OPTIONS = 6, +} + +global struct HttpRequest +{ + /** Method used for this http request. */ + int method + /** Base URL of this http request. */ + string url + /** Headers used for this http request. Some may get overridden or ignored. */ + table< string, array< string > > headers + /** Query parameters for this http request. */ + table< string, array< string > > queryParameters + /** The content type of this http request. Defaults to application/json & UTF-8 charset. */ + string contentType = "application/json; charset=utf-8" + /** The body of this http request. If set, will override queryParameters.*/ + string body + /** The timeout for the http request in seconds. Must be between 1 and 60. */ + int timeout = 60 + /** If set, the override to use for the User-Agent header. */ + string userAgent +} + +global struct HttpRequestResponse +{ + /** The status code returned by the remote the call was made to. */ + int statusCode + /** The body of the response. */ + string body + /** The raw headers returned by the remote. */ + string rawHeaders + /** A key -> values table of headers returned by the remote. */ + table< string, array< string > > headers +} + +global struct HttpRequestFailure +{ + /** The error code returned by native for this failure. */ + int errorCode + /** The reason why this http request failed. */ + string errorMessage +} + +struct HttpRequestCallbacks +{ + /** + * The function to call if the HTTP request was a success. + * Passes in the response received from the remote. + */ + void functionref( HttpRequestResponse ) onSuccess + + /** + * The function to call if the HTTP request failed. + */ + void functionref( HttpRequestFailure ) onFailure +} + +table< int, HttpRequestCallbacks > pendingCallbacks + +/** + * Called from native when a HTTP request is successful. + * This is internal and shouldn't be used. + * Keep in mind that the success can be successful, but have a non-success status code. + * @param handle The handle of the request we got a response for. + * @param statusCode The status code returned in the response. + * @param body The body returned for GET requests. + * @param headers The headers that were returned in the response. + */ +void function NSHandleSuccessfulHttpRequest( int handle, int statusCode, string body, string headers ) +{ + if ( !( handle in pendingCallbacks ) ) + { + return + } + + if ( pendingCallbacks[ handle ].onSuccess != null ) + { + HttpRequestResponse response + response.statusCode = statusCode + response.body = body + response.rawHeaders = headers + + // Parse the raw headers into key -> values + array values = split( headers, "\n" ) + + foreach ( string header in values ) + { + var index = header.find( ":" ) + if ( index == null ) + { + continue + } + + expect int( index ) + + string name = strip( header.slice( 0, index ) ) + string value = strip( header.slice( index + 1 ) ) + + if ( name in response.headers ) + { + response.headers[ name ].append( value ) + } + else + { + response.headers[ name ] <- [ value ] + } + } + + pendingCallbacks[ handle ].onSuccess( response ) + } + + delete pendingCallbacks[ handle ] +} + +/** + * Called from native when a HTTP request has failed. + * This is internal and shouldn't be used. + * @param handle The handle of the request that failed. + * @param errorCode The error code returned by curl. + * @param errorMessage The error message returned by curl. + */ +void function NSHandleFailedHttpRequest( int handle, int errorCode, string errorMessage ) +{ + if ( handle in pendingCallbacks ) + { + if ( pendingCallbacks[ handle ].onFailure != null ) + { + HttpRequestFailure failure + failure.errorCode = errorCode + failure.errorMessage = errorMessage + + pendingCallbacks[ handle ].onFailure( failure ) + } + + delete pendingCallbacks[ handle ] + } +} + +/** + * Launch a HTTP request with the given request data. + * This function is async, and the provided callbacks will be called when it is completed. + * @param requestParameters The parameters to use for this request. + * @param onSuccess The callback to execute if the request is successful. + * @param onFailure The callback to execute if the request has failed. + * @returns Whether or not the request has been successfully started. + */ +bool function NSHttpRequest( HttpRequest requestParameters, void functionref( HttpRequestResponse ) onSuccess = null, void functionref( HttpRequestFailure ) onFailure = null ) +{ + int handle = NS_InternalMakeHttpRequest( requestParameters.method, requestParameters.url, requestParameters.headers, + requestParameters.queryParameters, requestParameters.contentType, requestParameters.body, requestParameters.timeout, requestParameters.userAgent ) + + if ( handle != -1 && ( onSuccess != null || onFailure != null ) ) + { + HttpRequestCallbacks callback + callback.onSuccess = onSuccess + callback.onFailure = onFailure + + pendingCallbacks[ handle ] <- callback + } + + return handle != -1 +} + +/** + * Launches an HTTP GET request at the specified URL with the given query parameters. + * This function is async, and the provided callbacks will be called when it is completed. + * @param url The url to make the http request for. + * @param queryParameters A table of key value parameters to insert in the url. + * @param onSuccess The callback to execute if the request is successful. + * @param onFailure The callback to execute if the request has failed. + * @returns Whether or not the request has been successfully started. + */ +bool function NSHttpGet( string url, table< string, array< string > > queryParameters = {}, void functionref( HttpRequestResponse ) onSuccess = null, void functionref( HttpRequestFailure ) onFailure = null ) +{ + HttpRequest request + request.method = HttpRequestMethod.GET + request.url = url + request.queryParameters = queryParameters + + return NSHttpRequest( request, onSuccess, onFailure ) +} + +/** + * Launches an HTTP POST request at the specified URL with the given query parameters. + * This function is async, and the provided callbacks will be called when it is completed. + * @param url The url to make the http request for. + * @param queryParameters A table of key value parameters to insert in the url. + * @param onSuccess The callback to execute if the request is successful. + * @param onFailure The callback to execute if the request has failed. + * @returns Whether or not the request has been successfully started. + */ +bool function NSHttpPostQuery( string url, table< string, array< string > > queryParameters, void functionref( HttpRequestResponse ) onSuccess = null, void functionref( HttpRequestFailure ) onFailure = null ) +{ + HttpRequest request + request.method = HttpRequestMethod.POST + request.url = url + request.queryParameters = queryParameters + + return NSHttpRequest( request, onSuccess, onFailure ) +} + +/** + * Launches an HTTP POST request at the specified URL with the given body. + * This function is async, and the provided callbacks will be called when it is completed. + * @param url The url to make the http request for. + * @param queryParameters A table of key value parameters to insert in the url. + * @param onSuccess The callback to execute if the request is successful. + * @param onFailure The callback to execute if the request has failed. + * @returns Whether or not the request has been successfully started. + */ +bool function NSHttpPostBody( string url, string body, void functionref( HttpRequestResponse ) onSuccess = null, void functionref( HttpRequestFailure ) onFailure = null ) +{ + HttpRequest request + request.method = HttpRequestMethod.POST + request.url = url + request.body = body + + return NSHttpRequest( request, onSuccess, onFailure ) +} + +/** Whether or not the given status code is considered successful. */ +bool function NSIsSuccessHttpCode( int statusCode ) +{ + return statusCode >= 200 && statusCode <= 299 +} -- cgit v1.2.3 From 952b4605040de305e38cd32d647c08b8cd63091e Mon Sep 17 00:00:00 2001 From: Maya <11448698+RoyalBlue1@users.noreply.github.com> Date: Mon, 2 Jan 2023 14:22:54 +0100 Subject: Add Harvester File (#546) Moved out of the fd branch because it was needed for fw --- .../mod/scripts/vscripts/_harvester.gnut | 68 +++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut index 37b89169..f2776bda 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut @@ -1 +1,67 @@ -//fuck \ No newline at end of file +global function SpawnHarvester +global function generateBeamFX +global function generateShieldFX + +global struct HarvesterStruct { + entity harvester + entity particleBeam + entity particleShield + entity rings + float lastDamage + bool shieldBoost + +} + +HarvesterStruct function SpawnHarvester( vector origin, vector angles, int health, int shieldHealth, int team ) +{ + entity harvester = CreateEntity( "prop_script" ) + harvester.SetValueForModelKey( $"models/props/generator_coop/generator_coop.mdl" ) + harvester.SetOrigin( origin ) + harvester.SetAngles( angles ) + harvester.kv.solid = SOLID_VPHYSICS + + harvester.SetMaxHealth( health ) + harvester.SetHealth( health ) + harvester.SetShieldHealthMax( shieldHealth ) + harvester.SetShieldHealth( shieldHealth ) + harvester.EnableAttackableByAI( 30, 0, AI_AP_FLAG_NONE ) + SetObjectCanBeMeleed( harvester, false ) + SetTeam(harvester,team) + + DispatchSpawn( harvester ) + + + entity blackbox = CreatePropDynamic( MODEL_HARVESTER_TOWER_COLLISION, origin, angles, 0 ) + blackbox.Hide() + blackbox.Solid() + // blackbox.kv.CollisionGroup = TRACE_COLLISION_GROUP_PLAYER + + entity rings = CreatePropDynamic( MODEL_HARVESTER_TOWER_RINGS, origin, angles, 6 ) + thread PlayAnim( rings, "generator_cycle_fast" ) + + + + HarvesterStruct ret + ret.harvester = harvester + ret.lastDamage = Time() + ret.rings = rings + + return ret +} + +HarvesterStruct function generateBeamFX( HarvesterStruct harvester ) +{ + entity Harvester_Beam = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_BEAM ), FX_PATTACH_ABSORIGIN_FOLLOW ,0 ) + EffectSetControlPointVector( Harvester_Beam, 1, GetShieldTriLerpColor( 0.0 ) ) + harvester.particleBeam = Harvester_Beam + Harvester_Beam.DisableHibernation() + return harvester +} + +HarvesterStruct function generateShieldFX( HarvesterStruct harvester ) +{ + entity Harvester_Shield = StartParticleEffectOnEntity_ReturnEntity( harvester.harvester, GetParticleSystemIndex( FX_HARVESTER_OVERSHIELD ), FX_PATTACH_ABSORIGIN_FOLLOW, 0 ) + EffectSetControlPointVector( Harvester_Shield, 1, GetShieldTriLerpColor( 0.0 ) ) + harvester.particleShield = Harvester_Shield + return harvester +} \ No newline at end of file -- cgit v1.2.3 From 27e000e3feb3741c91708ea47c92ec95d9f3d4d1 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Tue, 3 Jan 2023 00:27:15 +0100 Subject: Move region column to the left (#553) --- .../mod/resource/ui/menus/server_browser.menu | 900 ++++++++++----------- 1 file changed, 450 insertions(+), 450 deletions(-) diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index b66fb8a6..48cddd73 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -143,7 +143,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -462 + xpos -422 zpos 101 //fgcolor_override "107 166 196 255" @@ -159,7 +159,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -462 + xpos -422 zpos 100 rui "ui/control_options_description.rpak" @@ -419,6 +419,252 @@ resource/ui/menus/mods_browse.menu pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } + + // Region + BtnServerRegionTab + { + ControlName RuiButton + InheritProperties RuiSmallButton + labelText "#REGION_COLUMN" + wide 110 + xpos -4 + ypos -1 + + scriptID 999 + + pin_to_sibling BtnServerPasswordProtectedTab + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner TOP_RIGHT + navDown BtnServer1 + navRight BtnServerNameTab + navUp BtnFiltersClear + } + + BtnServerRegion1 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer1 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion2 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer2 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion3 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer3 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion4 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer4 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion5 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer5 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion6 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer6 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion7 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer7 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion8 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer8 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion9 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer9 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion10 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer10 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion11 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer11 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion12 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer12 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion13 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer13 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion14 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer14 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } + BtnServerRegion15 + { + ControlName Label + labelText "" + classname Serverregion + textAlignment center + wide 110 + tall 44 + ypos -42 + xpos 0 + + pin_to_sibling BtnServer15 + pin_corner_to_sibling TOP_LEFT + pin_to_sibling_corner BOTTOM_LEFT + } // Name BtnServerNameTab @@ -427,16 +673,16 @@ resource/ui/menus/mods_browse.menu InheritProperties RuiSmallButton labelText "#SERVERS_COLUMN" wide 600 - xpos -4 - ypos -1 + xpos 4 scriptID 999 - pin_to_sibling BtnServerPasswordProtectedTab + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner TOP_RIGHT navUp BtnFiltersClear navDown BtnServer1 + navLeft BtnServerRegionTab navRight BtnServerPlayersTab } @@ -448,8 +694,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 interactive false @@ -465,8 +711,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -480,8 +726,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -495,8 +741,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -510,8 +756,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -525,8 +771,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -540,8 +786,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -555,8 +801,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -570,8 +816,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -585,8 +831,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -600,8 +846,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -615,8 +861,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -630,8 +876,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -645,8 +891,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -660,8 +906,8 @@ resource/ui/menus/mods_browse.menu classname ServerName wide 586 tall 44 - ypos -44 - xpos -14 + ypos -42 + xpos -122 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -697,8 +943,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -712,8 +958,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -727,8 +973,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -742,8 +988,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -757,8 +1003,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -772,8 +1018,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -787,8 +1033,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -802,8 +1048,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -817,8 +1063,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -832,8 +1078,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -847,8 +1093,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -862,8 +1108,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -877,8 +1123,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -892,8 +1138,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -907,8 +1153,8 @@ resource/ui/menus/mods_browse.menu textAlignment center wide 104 tall 44 - ypos -44 - xpos -600 + ypos -42 + xpos -718 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -944,8 +1190,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -959,8 +1205,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -974,8 +1220,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -989,8 +1235,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -1004,8 +1250,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -1019,8 +1265,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -1034,8 +1280,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -1049,8 +1295,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -1064,8 +1310,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -1079,8 +1325,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -1094,8 +1340,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -1109,8 +1355,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -1124,8 +1370,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -1139,8 +1385,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -1154,8 +1400,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -709 + ypos -42 + xpos -828 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT @@ -1178,7 +1424,7 @@ resource/ui/menus/mods_browse.menu pin_to_sibling_corner TOP_RIGHT navDown BtnServer1 navLeft BtnServerMapTab - navRight BtnServerRegionTab + navRight BtnServerJoin navUp BtnFiltersClear } @@ -1190,8 +1436,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer1 pin_corner_to_sibling TOP_LEFT @@ -1205,8 +1451,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer2 pin_corner_to_sibling TOP_LEFT @@ -1220,8 +1466,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer3 pin_corner_to_sibling TOP_LEFT @@ -1235,8 +1481,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer4 pin_corner_to_sibling TOP_LEFT @@ -1250,8 +1496,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer5 pin_corner_to_sibling TOP_LEFT @@ -1265,8 +1511,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer6 pin_corner_to_sibling TOP_LEFT @@ -1280,8 +1526,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer7 pin_corner_to_sibling TOP_LEFT @@ -1295,8 +1541,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer8 pin_corner_to_sibling TOP_LEFT @@ -1310,8 +1556,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer9 pin_corner_to_sibling TOP_LEFT @@ -1325,8 +1571,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer10 pin_corner_to_sibling TOP_LEFT @@ -1340,8 +1586,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer11 pin_corner_to_sibling TOP_LEFT @@ -1355,8 +1601,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer12 pin_corner_to_sibling TOP_LEFT @@ -1370,8 +1616,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer13 pin_corner_to_sibling TOP_LEFT @@ -1385,8 +1631,8 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer14 pin_corner_to_sibling TOP_LEFT @@ -1400,366 +1646,120 @@ resource/ui/menus/mods_browse.menu wide 140 textAlignment center tall 44 - ypos -44 - xpos -860 + ypos -42 + xpos -972 pin_to_sibling BtnServer15 pin_corner_to_sibling TOP_LEFT pin_to_sibling_corner BOTTOM_LEFT } - // Region - BtnServerRegionTab - { - ControlName RuiButton - InheritProperties RuiSmallButton - labelText "#REGION_COLUMN" - wide 110 - xpos 4 - - scriptID 999 - - pin_to_sibling BtnServerGamemodeTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_RIGHT - navDown BtnServer1 - navLeft BtnServerGamemodeTab - navRight BtnServerJoin - navUp BtnFiltersClear - } - - BtnServerRegion1 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer1 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion2 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer2 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion3 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - - pin_to_sibling BtnServer3 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion4 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + // Dividers: - pin_to_sibling BtnServer4 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion5 + // Y + YDivider0 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer5 + pin_to_sibling BtnServerNameTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion6 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer6 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion7 + YDivider1 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer7 + pin_to_sibling BtnServerPlayersTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion8 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer8 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion9 + YDivider2 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer9 + pin_to_sibling BtnServerMapTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion10 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer10 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion11 + YDivider3 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer11 + pin_to_sibling BtnServerGamemodeTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion12 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer12 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion13 + YDivider4 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 2 + tall 641 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + xpos 3 + ypos -1 - pin_to_sibling BtnServer13 + pin_to_sibling BtnServerRegionTab pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT + pin_to_sibling_corner TOP_LEFT } - BtnServerRegion14 - { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 - pin_to_sibling BtnServer14 - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - BtnServerRegion15 + // X + XDivider0 { - ControlName Label - labelText "" - classname Serverregion - textAlignment center - wide 110 - tall 44 - ypos -44 - xpos -1006 + ControlName ImagePanel + wide 1150 + tall 2 + visible 1 + image "vgui/hud/white" + drawColor "160 157 149 255" + scaleImage 1 + ypos 3 + xpos 37 - pin_to_sibling BtnServer15 - pin_corner_to_sibling TOP_LEFT + pin_to_sibling BtnServerRegionTab + pin_corner_to_sibling BOTTOM_LEFT pin_to_sibling_corner BOTTOM_LEFT } - // Dividers: - - // Y - YDivider0 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerNameTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider1 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerPlayersTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider2 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerMapTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider3 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerGamemodeTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - YDivider4 - { - ControlName ImagePanel - wide 2 - tall 641 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - xpos 3 - ypos -1 - - pin_to_sibling BtnServerRegionTab - pin_corner_to_sibling TOP_LEFT - pin_to_sibling_corner TOP_LEFT - } - - // X - XDivider0 - { - ControlName ImagePanel - wide 1150 - tall 2 - visible 1 - image "vgui/hud/white" - drawColor "160 157 149 255" - scaleImage 1 - ypos 3 - xpos 37 - - pin_to_sibling BtnServerNameTab - pin_corner_to_sibling BOTTOM_LEFT - pin_to_sibling_corner BOTTOM_LEFT - } - // List: BtnServerDummmyTop { ControlName RuiButton @@ -2082,7 +2082,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 zpos 0 image "vgui/hud/white" @@ -2099,7 +2099,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 rui "ui/control_options_description.rpak" @@ -2120,7 +2120,7 @@ resource/ui/menus/mods_browse.menu wide 40 tall 562 xpos 2 - ypos -40 + ypos -42 zpos 1 pin_to_sibling ServerDetailsPanel -- cgit v1.2.3 From a203eea6c3129c1572e760e943b5b97cab1f20c0 Mon Sep 17 00:00:00 2001 From: GalacticMoblin <100473309+GalacticMoblin@users.noreply.github.com> Date: Tue, 3 Jan 2023 02:16:33 +0000 Subject: Fixed Multiple Amped Weapons Timers (#500) * Add files via upload * Delete _burnmeter.gnut * Add files via upload Fixed multiple Amped Weapon uses not resetting the timer * Add eject quotes (#527) * Upload cl_titan_cockpit.nut * Add eject string in script * Moved to client * index issue + removed else so always returns * Apply suggestions from code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Rest of the suggestions because github makes me want to cry * Commit suggestions from review GitHub really hates batching suggestions Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Add files via upload * Delete _burnmeter.gnut * Rename _burnmeter.gnut.txt to _burnmeter.gnut * Update _burnmeter.gnut * Update _burnmeter.gnut * Update _burnmeter.gnut * Update _burnmeter.gnut Co-authored-by: JMM889901 <41163714+JMM889901@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 81f7fbc2..5821d015 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -294,10 +294,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 weapons = player.GetMainWeapons() //weapons.extend( player.GetOffhandWeapons() ) // idk? unsure of vanilla behaviour here foreach ( entity weapon in weapons ) @@ -606,4 +610,4 @@ void function PlayerUsesReaperfallBurncard( entity player ) DispatchSpawn( reaper ) thread SuperSpectre_WarpFall( reaper ) -} \ No newline at end of file +} -- cgit v1.2.3 From 92a3d6c0d00e2d4cb8a320ee47870beb407110b3 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Wed, 4 Jan 2023 02:50:11 +0100 Subject: Fix connecting UI (#560) Fixes misaligned buttons when showing server connecting pop up --- Northstar.Client/mod/resource/ui/menus/server_browser.menu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/ui/menus/server_browser.menu b/Northstar.Client/mod/resource/ui/menus/server_browser.menu index 48cddd73..4a84a714 100644 --- a/Northstar.Client/mod/resource/ui/menus/server_browser.menu +++ b/Northstar.Client/mod/resource/ui/menus/server_browser.menu @@ -143,7 +143,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -422 + xpos -462 zpos 101 //fgcolor_override "107 166 196 255" @@ -159,7 +159,7 @@ resource/ui/menus/mods_browse.menu wide 100 tall 40 ypos -220 - xpos -422 + xpos -462 zpos 100 rui "ui/control_options_description.rpak" -- cgit v1.2.3 From 0fd3cef04c04adb7c8aa368fda75e10a93462ec4 Mon Sep 17 00:00:00 2001 From: Respawn Date: Thu, 5 Jan 2023 15:37:45 +0100 Subject: Add sh_powerup.gnut from englishclient_mp_common --- .../mod/scripts/vscripts/sh_powerup.gnut | 292 +++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut 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..75002e81 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut @@ -0,0 +1,292 @@ +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 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 + + return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB ) +} + +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 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 -- cgit v1.2.3 From b8ad5076113c84136efa859c274bd515dbf984f8 Mon Sep 17 00:00:00 2001 From: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Date: Fri, 6 Jan 2023 06:03:55 +0800 Subject: [FW] Networked Variable fix (#544) * Support to input other languages in the search box Support to input other languages in the search box * fw Networked Variable fix Networked Variable fix * defaultValue,rangemin,rangemax defaultValue,rangemin,rangemax --- .../mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut index ca238d5d..e2cdc1a3 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut @@ -59,13 +59,13 @@ void function FWOnRegisteringNetworkVars() RegisterNetworkedVariable( "imcTowerThreatLevel", SNDC_GLOBAL, SNVT_INT ) RegisterNetworkedVariable( "milTowerThreatLevel", SNDC_GLOBAL, SNVT_INT ) RegisterNetworkedVariable( "fwCampAlertA", SNDC_GLOBAL, SNVT_INT ) - RegisterNetworkedVariable( "fwCampStressA", SNDC_GLOBAL, SNVT_INT ) + RegisterNetworkedVariable( "fwCampStressA", SNDC_GLOBAL, SNVT_FLOAT_RANGE, 0.0, 0.0, 1.0 ) RegisterNetworkedVariable( "fwCampAlertB", SNDC_GLOBAL, SNVT_INT ) - RegisterNetworkedVariable( "fwCampStressB", SNDC_GLOBAL, SNVT_INT ) + RegisterNetworkedVariable( "fwCampStressB", SNDC_GLOBAL, SNVT_FLOAT_RANGE, 0.0, 0.0, 1.0 ) RegisterNetworkedVariable( "fwCampAlertC", SNDC_GLOBAL, SNVT_INT ) - RegisterNetworkedVariable( "fwCampStressC", SNDC_GLOBAL, SNVT_INT ) + RegisterNetworkedVariable( "fwCampStressC", SNDC_GLOBAL, SNVT_FLOAT_RANGE, 0.0, 0.0, 1.0 ) #if CLIENT CLFortWar_RegisterNetworkFunctions() #endif -} \ No newline at end of file +} -- cgit v1.2.3 From 4e83b351a8581ec04cd7ecd54588514eb6207ba6 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 7 Jan 2023 04:42:13 +0800 Subject: [GAMEMODE] Add gamemode_fw (#545) * Initial commit Co-Authored-By: Ghroth-follower <45908037+Ghroth-follower@users.noreply.github.com> Co-Authored-By: zxcPandora <81985226+zxcPandora@users.noreply.github.com> * add customized scripts Co-Authored-By: Ghroth-follower <45908037+Ghroth-follower@users.noreply.github.com> Co-Authored-By: zxcPandora <81985226+zxcPandora@users.noreply.github.com> * add royal as co-worker Co-Authored-By: Maya <11448698+RoyalBlue1@users.noreply.github.com> * reset harvester.gnut * Update _gamemode_fw.nut * no need to update alertLevel right after clear * hacked natural turret receives less health * change consts name * update HACK_ForceDestroyNPCs() * update battery port's usePrompts * batteryPort useHint update * should do a check for titans * disable cloak while applying battery * add debounce for turret notifications * fix escalate * fix complex crash * late spawn camp trackers * defensive fix after havester destroyed * nerf salvo core and titan's earn meter * edit rodeo_titan in Northstar.Custom * make settings controllable by playlistvars * use tabs for indenting use tabs for indenting * Move game mode specific behaviour to callback use post damage callback * Move FW specific code out of _battery_port.gnut Also Split Damage Callbacks to onDamage and onPostDamage * Fix globalizing same function twice * Adding vars back to HarvesterStruct * use tabs for indenting use tabs for indenting Co-authored-by: Ghroth-follower <45908037+Ghroth-follower@users.noreply.github.com> Co-authored-by: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com> Co-authored-by: zxcPandora <1158500986@qq.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 12 +- Northstar.Custom/mod.json | 4 + .../scripts/vscripts/gamemodes/_gamemode_fw.nut | 2269 ++++++++++++++++++++ .../vscripts/gamemodes/sh_gamemode_fw_custom.nut | 56 +- .../mod/scripts/vscripts/rodeo/_rodeo_titan.gnut | 3 + .../mod/scripts/vscripts/_harvester.gnut | 3 + .../mod/scripts/vscripts/mp/_battery_port.gnut | 220 +- .../mod/scripts/vscripts/rodeo/_rodeo_titan.gnut | 9 +- .../mod/scripts/vscripts/sh_powerup.gnut | 4 +- .../vscripts/titan/_replacement_titans.gnut | 53 +- .../vscripts/titan/_replacement_titans_drop.gnut | 17 +- 11 files changed, 2624 insertions(+), 26 deletions(-) create mode 100644 Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index a47cc07e..21934b31 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -30,6 +30,7 @@ playlists max_teams 2 classic_mp 1 scorelimit 100 // score is a percentage so ofc need max to be 100% + timelimit 15 } } gg @@ -573,6 +574,7 @@ playlists max_teams 2 classic_mp 1 scorelimit 100 + timelimit 15 gamemode_score_hint #GAMEMODE_SCORE_HINT_TDM } @@ -580,23 +582,15 @@ playlists { fw { - maps + maps // only 7 maps respawn had done { mp_forwardbase_kodai 1 mp_grave 1 mp_homestead 1 mp_thaw 1 - mp_black_water_canal 1 mp_eden 1 - mp_drydock 1 mp_crashsite3 1 mp_complex3 1 - mp_angel_city 1 - mp_colony02 1 - mp_glitch 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 } } } diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index d47c42cf..1952f72a 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -418,6 +418,10 @@ "Before": "MessageUtils_ServerInit" } }, + { + "Path": "gamemodes/_gamemode_fw.nut", + "RunOn": "SERVER && MP" + }, { "Path": "sh_northstar_http_requests.gnut", "RunOn": "CLIENT || SERVER || UI" diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut new file mode 100644 index 00000000..dd2b3200 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -0,0 +1,2269 @@ +untyped +global function GamemodeFW_Init +global function RateSpawnpoints_FW + +// for battery_port.gnut to work +global function FW_ReplaceMegaTurret + +// fw specific titanfalls +global function FW_IsPlayerInFriendlyTerritory +global function FW_IsPlayerInEnemyTerritory + +// you need to deal this much damage to trigger "FortWarTowerDamage" score event +const int FW_HARVESTER_DAMAGE_SEGMENT = 1500 + +// basically needs to match "waves count - bosswaves count" +const int FW_MAX_LEVELS = 3 + +// to confirm it's a npc from camps.. +const string FW_NPC_SCRIPTNAME = "fw_npcsFromCamp" +const int FW_AI_TEAM = TEAM_BOTH +const float WAVE_STATE_TRANSITION_TIME = 5.0 + +// from sh_gamemode_fw, if half of these npcs cleared in one camp, it gets escalate +const int FW_GRUNT_COUNT = 36//32 +const int FW_SPECTRE_COUNT = 24 +const int FW_REAPER_COUNT = 2 + +// max deployment each camp +const int FW_GRUNT_MAX_DEPLOYED = 8 +const int FW_SPECTRE_MAX_DEPLOYED = 8 +const int FW_REAPER_MAX_DEPLOYED = 1 + +// if other camps been cleaned many times, we levelDown +const int FW_CAMP_IGNORE_NEEDED = 2 + +// debounce for showing damaged infos +const float FW_HARVESTER_DAMAGED_DEBOUNCE = 5.0 +const float FW_TURRET_DAMAGED_DEBOUNCE = 2.0 + +global HarvesterStruct& fw_harvesterMlt +global HarvesterStruct& fw_harvesterImc + +// these are not using respawn's remaining code( sh_gamemode_fw.nut )! + +// respawn already have a FW_TowerData struct! this struct is only for score events +struct HarvesterDamageStruct +{ + float recentDamageTime + int storedDamage +} + +struct TurretSiteStruct +{ + entity site + entity turret + entity minimapstate + string turretflagid +} + +// respawn already have a FW_CampData, FW_WaveOrigin and FW_SpawnData struct! +struct CampSiteStruct +{ + entity camp + entity info + entity tracker + array validDropPodSpawns + array validTitanSpawns + string campId // "A", "B", "C" + int npcsAlive + int ignoredSinceLastClean +} + +struct CampSpawnStruct +{ + string spawnContent // what npcs to spawn + int maxSpawnCount // max spawn count on this camp + int countPerSpawn // how many npcs to deploy per spawn, for droppods most be 4 + int killsToEscalate // how many kills needed to escalate +} + +struct +{ + array harvesters + + // save camp's info_target, we spawn camps after game starts, or player's first life won't show up correct camp icons + array camps + + array fwTerritories + + array turretsites + + array fwCampSites + + // respawn already have a FW_TowerData struct! this table is only for score events + table< entity, HarvesterDamageStruct > playerDamageHarvester // team, table< player, time > + + // this is for saving territory's connecting time, try not to make faction dialogues play together + table< int, float > teamTerrLastConnectTime // team, time + + array etitaninmlt + array etitaninimc + + entity harvesterMlt_info + entity harvesterImc_info + + table fwNpcLevel // basically use to powerup certian camp, sync with alertLevel + table< string, table< string, int > > trackedCampNPCSpawns +}file + +void function GamemodeFW_Init() +{ + // _battery_port.gnut needs this + RegisterSignal( "BatteryActivate" ) + + AiGameModes_SetGruntWeapons( [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) + AiGameModes_SetSpectreWeapons( [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + + AddCallback_EntitiesDidLoad( LoadEntities ) + AddCallback_GameStateEnter( eGameState.Prematch, OnFWGamePrematch ) + AddCallback_GameStateEnter( eGameState.Playing, OnFWGamePlaying ) + + AddSpawnCallback( "item_powerup", FWAddPowerUpIcon ) + // check spawn point, WIP + AddSpawnCallback( "npc_titan", FWForcedTitanSpawnPoint ) + + AddCallback_OnClientConnected( OnFWPlayerConnected ) + AddCallback_OnPlayerKilled( OnFWPlayerKilled ) + AddCallback_OnPilotBecomesTitan( OnFWPilotBecomesTitan ) + AddCallback_OnTitanBecomesPilot( OnFWTitanBecomesPilot ) + + ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetRecalculateTitanReplacementPointCallback(FW_ReCalculateTitanReplacementPoint) + SetRequestTitanAllowedCallback(FW_RequestTitanAllowed) + + // so many things in battle, this is required to avoid crash! + ServerCommand( "sv_max_props_multiplayer 200000" ) + ServerCommand( "sv_max_prop_data_dwords_multiplayer 300000" ) +} + + + +////////////////////////// +///// HACK FUNCTIONS ///// +////////////////////////// + +const array HACK_CLEANUP_MAPS = +[ + "mp_grave", + "mp_homestead", + "mp_complex3" +] + +//if npcs outside the map try to fire( like in death animation ), it will cause a engine error + +// in mp_grave, npcs will sometimes stuck underground +const float GRAVE_CHECK_HEIGHT = 1700 // the map's lowest ground is 1950+, npcs will stuck under -4000 or -400 +// in mp_homestead, npcs will sometimes stuck in the sky +const float HOMESTEAD_CHECK_HIEGHT = 8000 // the map's highest part is 7868+, npcs will stuck above 13800+ +// in mp_complex3, npcs will sometimes stuck in the sky +const float COMPLEX_CHECK_HEIGHT = 7000 // the map's highest part is 6716+, npcs will stuck above 9700+ + +// do a hack +void function HACK_ForceDestroyNPCs() +{ + thread HACK_ForceDestroyNPCs_Threaded() +} + +void function HACK_ForceDestroyNPCs_Threaded() +{ + string mapName = GetMapName() + if( !( HACK_CLEANUP_MAPS.contains( mapName ) ) ) + return + + while( true ) + { + if( mapName == "mp_grave" ) + { + foreach( entity npc in GetNPCArray() ) + { + if( npc.GetOrigin().z <= GRAVE_CHECK_HEIGHT ) + { + npc.ClearParent() + npc.Destroy() + } + } + } + if( mapName == "mp_homestead" ) + { + foreach( entity npc in GetNPCArray() ) + { + // neither spawning from droppod nor hotdropping + if( !IsValid( npc.GetParent() ) && !npc.e.isHotDropping ) + { + if( npc.GetOrigin().z >= HOMESTEAD_CHECK_HIEGHT ) + { + npc.Destroy() + } + } + } + } + if( mapName == "mp_complex3" ) + { + foreach( entity npc in GetNPCArray() ) + { + // neither spawning from droppod nor hotdropping + if( !IsValid( npc.GetParent() ) && !npc.e.isHotDropping ) + { + if( npc.GetOrigin().z >= COMPLEX_CHECK_HEIGHT ) + { + npc.Destroy() + } + } + } + } + WaitFrame() + } +} + +////////////////////////////// +///// HACK FUNCTIONS END ///// +////////////////////////////// + + + +//////////////////////////////// +///// SPAWNPOINT FUNCTIONS ///// +//////////////////////////////// + +void function RateSpawnpoints_FW( int checkClass, array spawnpoints, int team, entity player ) +{ + if ( HasSwitchedSides() ) + team = GetOtherTeam( team ) + + // check hardpoints, determine which ones we own + array startSpawns = SpawnPoints_GetPilotStart( team ) + vector averageFriendlySpawns + + // average out startspawn positions + foreach ( entity spawnpoint in startSpawns ) + averageFriendlySpawns += spawnpoint.GetOrigin() + + averageFriendlySpawns /= startSpawns.len() + + entity friendlyTerritory + foreach ( entity territory in file.fwTerritories ) + { + if ( team == territory.GetTeam() ) + { + friendlyTerritory = territory + break + } + } + + vector ratingPos + if ( IsValid( friendlyTerritory ) ) + ratingPos = friendlyTerritory.GetOrigin() + else + ratingPos = averageFriendlySpawns + + foreach ( entity spawnpoint in spawnpoints ) + { + // idk about magic number here really + float rating = 1.0 - ( Distance2D( spawnpoint.GetOrigin(), ratingPos ) / 1000.0 ) + spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating ) + } +} + +//////////////////////////////////// +///// SPAWNPOINT FUNCTIONS END ///// +//////////////////////////////////// + + + +////////////////////////////// +///// CALLBACK FUNCTIONS ///// +////////////////////////////// + +void function OnFWGamePrematch() +{ + InitFWScoreEvents() + FW_createHarvester() + InitFWCampSites() + InitCampSpawnerLevel() +} + +void function OnFWGamePlaying() +{ + startFWHarvester() + FWAreaThreatLevelThink() + StartFWCampThink() + InitTurretSettings() + FWPlayerObjectiveState() + + HACK_ForceDestroyNPCs() +} + +void function OnFWPlayerConnected( entity player ) +{ + InitFWPlayers( player ) +} + +void function OnFWPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + HandleFWPlayerKilledScoreEvent( victim, attacker ) +} + +void function OnFWPilotBecomesTitan( entity player, entity titan ) +{ + // objective stuff + SetTitanObjective( player, titan ) +} + +void function OnFWTitanBecomesPilot( entity player, entity titan ) +{ + // objective stuff + SetPilotObjective( player, titan ) +} + +////////////////////////////////// +///// CALLBACK FUNCTIONS END ///// +////////////////////////////////// + + +///////////////////////////////// +///// SCORE EVENT FUNCTIONS ///// +///////////////////////////////// + +void function InitFWScoreEvents() +{ + // common scoreEvents + ScoreEvent_SetEarnMeterValues( "KillHeavyTurret", 0.0, 0.20 ) // can only adds to titan's in this mode + + // fw special: save for later use of scoreEvents + + // combat + ScoreEvent_SetEarnMeterValues( "FortWarAssault", 0.0, 0.05, 0.0 ) // titans don't earn + ScoreEvent_SetEarnMeterValues( "FortWarDefense", 0.0, 0.05, 0.0 ) // titans don't earn + ScoreEvent_SetEarnMeterValues( "FortWarPerimeterDefense", 0.0, 0.05 ) // unused + ScoreEvent_SetEarnMeterValues( "FortWarSiege", 0.0, 0.05 ) // unused + ScoreEvent_SetEarnMeterValues( "FortWarSnipe", 0.0, 0.05 ) // unused + + // constructions + ScoreEvent_SetEarnMeterValues( "FortWarBaseConstruction", 0.0, 0.15 ) + ScoreEvent_SetEarnMeterValues( "FortWarForwardConstruction", 0.0, 0.15 ) + ScoreEvent_SetEarnMeterValues( "FortWarInvasiveConstruction", 0.0, 0.25 ) // unused + ScoreEvent_SetEarnMeterValues( "FortWarResourceDenial", 0.0, 0.05 ) // unused + ScoreEvent_SetEarnMeterValues( "FortWarSecuringGatheredResources", 0.0, 0.05 ) // unused + + // tower + ScoreEvent_SetEarnMeterValues( "FortWarTowerDamage", 0.0, 0.10, 0.0 ) // using the const FW_HARVESTER_DAMAGE_SEGMENT, titans don't earn + ScoreEvent_SetEarnMeterValues( "FortWarTowerDefense", 0.0, 0.10, 0.0 ) // titans don't earn + ScoreEvent_SetEarnMeterValues( "FortWarShieldDestroyed", 0.0, 0.15 ) + + // turrets + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_One", 0.0, 0.15, 0.5 ) // give more meter if no turret left + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_Two", 0.0, 0.15, 0.5 ) + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_Three", 0.0, 0.10, 0.5 ) + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_Four", 0.0, 0.10, 0.5 ) // give less meter if controlled most turrets + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_Five", 0.0, 0.05, 0.5 ) + ScoreEvent_SetEarnMeterValues( "FortWarTeamTurretControlBonus_Six", 0.0, 0.05, 0.5 ) +} + +// consider this means victim recently damaged harvester +const float TOWER_DEFENSE_REQURED_TIME = 10.0 + +void function HandleFWPlayerKilledScoreEvent( entity victim, entity attacker ) +{ + // this function only handles player's kills + if( !attacker.IsPlayer() ) + return + + // suicide don't get scores + if( attacker == victim ) + return + + int attackerTeam = attacker.GetTeam() + int victimTeam = victim.GetTeam() + + string scoreEvent = "" + int secondaryScore = 0 + entity attackerHarvester = FW_GetTeamHarvesterProp( attackerTeam ) + + if( FW_IsPlayerInEnemyTerritory( victim ) ) // victim is in enemy territory + { + scoreEvent = "FortWarDefense" // enemy earn score from defense + secondaryScore = POINTVALUE_FW_DEFENSE + } + + if( FW_IsPlayerInFriendlyTerritory( victim ) ) // victim is in friendly territory + { + scoreEvent = "FortWarAssault" // enemy earn score from assault + secondaryScore = POINTVALUE_FW_ASSAULT + } + + if( victim in file.playerDamageHarvester ) // victim has damaged the harvester this life + { + float damageTime = file.playerDamageHarvester[ victim ].recentDamageTime + + // is victim recently damaged havester? + if( damageTime + TOWER_DEFENSE_REQURED_TIME >= Time() ) + { + scoreEvent = "FortWarTowerDefense" // you defend the tower! + secondaryScore = POINTVALUE_FW_TOWER_DEFENSE + } + + } + + if( scoreEvent != "" ) + { + AddPlayerScore( attacker, scoreEvent, victim ) + attacker.AddToPlayerGameStat( PGS_DEFENSE_SCORE, secondaryScore ) + } +} + +///////////////////////////////////// +///// SCORE EVENT FUNCTIONS END ///// +///////////////////////////////////// + + + +////////////////////////////////////// +///// FACTION DIALOGUE FUNCTIONS ///// +////////////////////////////////////// + +const float FW_TERRYTORY_DIALOGUE_DEBOUNCE = 5.0 + +// WORKING IN PROGRESS +bool function TryFWTerritoryDialogue( entity territory, entity player ) +{ + bool thisTimeIsTitan = player.IsTitan() + int terrTeam = territory.GetTeam() + int enemyTeam = GetOtherTeam( terrTeam ) + bool sameTeam = terrTeam == player.GetTeam() + bool isInDebounce = file.teamTerrLastConnectTime[ terrTeam ] + FW_TERRYTORY_DIALOGUE_DEBOUNCE >= Time() + + // the territory trigger will only save players and titans + array allEntsInside = GetAllEntitiesInTrigger( territory ) + allEntsInside.removebyvalue( null ) // since we're using a fake trigger, need to check this + array friendliesInside // this means territory's friendly team + array enemiesInside // this means territory's enemy team + array enemyTitansInside + foreach( entity ent in allEntsInside ) + { + if( !IsValid( ent ) ) // since we're using a fake trigger, need to check this + continue + if( ent.GetTeam() == terrTeam ) + friendliesInside.append( ent ) + } + foreach( entity ent in allEntsInside ) + { + if( !IsValid( ent ) ) // since we're using a fake trigger, need to check this + continue + if( ent.GetTeam() != terrTeam ) + enemiesInside.append( ent ) + } + foreach( entity enemy in enemiesInside ) + { + if( !IsValid( enemy ) ) // since we're using a fake trigger, need to check this + continue + if( enemy.IsTitan() ) + enemyTitansInside.append( enemy ) + } + + print( "enemy in territory: " + string( enemiesInside.len() ) ) + print( "friendly in territory: " + string( friendliesInside.len() ) ) + + print( "sameTeam: " + string( sameTeam ) ) + print( "isInDebounce: " + string( isInDebounce ) ) + print( "thisTimeIsTitan: " + string( thisTimeIsTitan ) ) + + if( enemiesInside.len() > 3 || friendliesInside.len() > 1 ) // already have some players triggered dialogue + return false + + // notify player enemy's behaves + if( !sameTeam ) // player is not the same team as territory + { + // consider this means all enemies has left friendly territory, should use a debounce + if( enemiesInside.len() == 0 && !isInDebounce ) + { + PlayFactionDialogueToTeam( "fortwar_terEnemyExpelled", terrTeam ) + return true + } + // has more than 3 titans inside including new one, ignores debounce + else if( enemyTitansInside.len() >= 3 && thisTimeIsTitan ) + { + PlayFactionDialogueToTeam( "fortwar_terPresentEnemyTitans", terrTeam ) + return true + } + // only the player inside terrytory + else if( enemyTitansInside.len() == 1 ) + { + // entered territory as titan, ignores debounce + if( thisTimeIsTitan ) + { + PlayFactionDialogueToTeam( "fortwar_terEnteredEnemyPilot", terrTeam ) + return true + } + // entered territory as pilot + else if( !isInDebounce ) + { + PlayFactionDialogueToTeam( "fortwar_terEnteredEnemyPilot", terrTeam ) + return true + } + } + + // notify player friendly's behaves + // consider this means all friendlies has left enemy territory + if( friendliesInside.len() == 0 && !sameTeam && !isInDebounce ) + { + PlayFactionDialogueToTeam( "fortwar_terFriendlyExpelled", terrTeam ) + return true + } + } + + return false +} + +////////////////////////////////////////// +///// FACTION DIALOGUE FUNCTIONS END ///// +////////////////////////////////////////// + + + +///////////////////////////////////////// +///// GAMEMODE INITIALIZE FUNCTIONS ///// +///////////////////////////////////////// + +void function LoadEntities() +{ + // info_target + foreach ( entity info_target in GetEntArrayByClass_Expensive( "info_target" ) ) + { + if( info_target.HasKey( "editorclass" ) ) + { + switch( info_target.kv.editorclass ) + { + case "info_fw_team_tower": + if ( info_target.GetTeam() == TEAM_IMC ) + { + file.harvesterImc_info = info_target + //print("fw_tower tracker spawned") + } + if ( info_target.GetTeam() == TEAM_MILITIA ) + { + file.harvesterMlt_info = info_target + //print("fw_tower tracker spawned") + } + break + case "info_fw_camp": + file.camps.append( info_target ) + //InitCampTracker( info_target ) + //print("fw_camp spawned") + break + case "info_fw_turret_site": + string idString = expect string(info_target.kv.turretId) + int id = int( info_target.kv.turretId ) + //print("info_fw_turret_siteID : " + idString ) + + // set this for replace function to find + TurretSiteStruct turretsite + file.turretsites.append( turretsite ) + + turretsite.site = info_target + + // create turret, spawn with no team and set it after game starts + entity turret = CreateNPC( "npc_turret_mega", TEAM_UNASSIGNED, info_target.GetOrigin(), info_target.GetAngles() ) + SetSpawnOption_AISettings( turret, "npc_turret_mega_fortwar" ) + SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work + AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) + DispatchSpawn( turret ) + + turretsite.turret = turret + + // init turret settings + turret.s.minimapstate <- null // entity, for saving turret's minimap handler + turret.s.baseTurret <- false // bool, is this turret from base + turret.s.turretflagid <- "" // string, turret's id like "1", "2", "3" + turret.s.lastDamagedTime <- 0.0 // float, for showing turret underattack icons + turret.s.relatedBatteryPort <- null // entity, corssfile + + // minimap icons holder + entity minimapstate = CreateEntity( "prop_script" ) + minimapstate.SetValueForModelKey( info_target.GetModelName() ) // these info must have model to work + minimapstate.Hide() // hide the model! it will still work on minimaps + minimapstate.SetOrigin( info_target.GetOrigin() ) + minimapstate.SetAngles( info_target.GetAngles() ) + //SetTeam( minimapstate, info_target.GetTeam() ) // setTeam() for icons is done in TurretStateWatcher() + minimapstate.kv.solid = SOLID_VPHYSICS + DispatchSpawn( minimapstate ) + // show on minimaps + minimapstate.Minimap_AlwaysShow( TEAM_IMC, null ) + minimapstate.Minimap_AlwaysShow( TEAM_MILITIA, null ) + minimapstate.Minimap_SetCustomState( eMinimapObject_prop_script.FW_BUILDSITE_SHIELDED ) + + turretsite.minimapstate = minimapstate + turret.s.minimapstate = minimapstate + + break + } + } + } + + // script_ref + foreach ( entity script_ref in GetEntArrayByClass_Expensive( "script_ref" ) ) + { + if( script_ref.HasKey( "editorclass" ) ) + { + switch( script_ref.kv.editorclass ) + { + case "info_fw_foundation_plate": + entity prop = CreatePropScript( script_ref.GetModelName(), script_ref.GetOrigin(), script_ref.GetAngles(), 6 ) + break + case "info_fw_battery_port": + entity batteryPort = CreatePropScript( script_ref.GetModelName(), script_ref.GetOrigin(), script_ref.GetAngles(), 6 ) + FW_InitBatteryPort(batteryPort) + + break + } + } + } + + // trigger_multiple + foreach ( entity trigger_multiple in GetEntArrayByClass_Expensive( "trigger_multiple" ) ) + { + if( trigger_multiple.HasKey( "editorclass" ) ) + { + switch( trigger_multiple.kv.editorclass ) + { + case "trigger_fw_territory": + SetupFWTerritoryTrigger( trigger_multiple ) + break + } + } + } + + // maybe for tick_spawning reapers? + ValidateAndFinalizePendingStationaryPositions() +} + +void function InitCampSpawnerLevel() // can edit this to make more spawns, alertLevel icons supports max to lv3( 0,1,2 ) +{ + // lv1 spawns: grunts + CampSpawnStruct campSpawnLv1 + campSpawnLv1.spawnContent = "npc_soldier" + campSpawnLv1.maxSpawnCount = FW_GRUNT_MAX_DEPLOYED + campSpawnLv1.countPerSpawn = 4 // how many npcs to deploy per spawn, for droppods most be 4 + campSpawnLv1.killsToEscalate = FW_GRUNT_COUNT / 2 + + file.fwNpcLevel[0] <- campSpawnLv1 + + // lv2 spawns: spectres + CampSpawnStruct campSpawnLv2 + campSpawnLv2.spawnContent = "npc_spectre" + campSpawnLv2.maxSpawnCount = FW_SPECTRE_MAX_DEPLOYED + campSpawnLv2.countPerSpawn = 4 // how many npcs to deploy per spawn, for droppods most be 4 + campSpawnLv2.killsToEscalate = FW_SPECTRE_COUNT / 2 + + file.fwNpcLevel[1] <- campSpawnLv2 + + // lv3 spawns: reapers + CampSpawnStruct campSpawnLv3 + campSpawnLv3.spawnContent = "npc_super_spectre" + campSpawnLv3.maxSpawnCount = FW_REAPER_MAX_DEPLOYED + campSpawnLv3.countPerSpawn = 1 // how many npcs to deploy per spawn + campSpawnLv3.killsToEscalate = FW_REAPER_COUNT / 2 // only 1 kill needed to spawn the boss? + + file.fwNpcLevel[2] <- campSpawnLv3 +} + +///////////////////////////////////////////// +///// GAMEMODE INITIALIZE FUNCTIONS END ///// +///////////////////////////////////////////// + + + +/////////////////////////////////////// +///// PLAYER INITIALIZE FUNCTIONS ///// +/////////////////////////////////////// + +void function InitFWPlayers( entity player ) +{ + HarvesterDamageStruct emptyStruct + file.playerDamageHarvester[ player ] <- emptyStruct + + // objective stuff + player.s.notifiedTitanfall <- false + + // notification stuff + player.s.lastTurretNotifyTime <- 0.0 +} + +/////////////////////////////////////////// +///// PLAYER INITIALIZE FUNCTIONS END ///// +/////////////////////////////////////////// + + + +///////////////////////////// +///// POWERUP FUNCTIONS ///// +///////////////////////////// + +void function FWAddPowerUpIcon( entity powerup ) +{ + powerup.Minimap_SetAlignUpright( true ) + powerup.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + powerup.Minimap_SetClampToEdge( false ) + powerup.Minimap_AlwaysShow( TEAM_MILITIA, null ) + powerup.Minimap_AlwaysShow( TEAM_IMC, null ) +} + +///////////////////////////////// +///// POWERUP FUNCTIONS END ///// +///////////////////////////////// + + + +///////////////////////////// +///// AICAMPS FUNCTIONS ///// +///////////////////////////// + +void function InitFWCampSites() +{ + // init here + foreach( entity info_target in file.camps ) + { + InitCampTracker( info_target ) + } + + // camps don't have a id, set them manually + foreach( int index, CampSiteStruct campsite in file.fwCampSites ) + { + entity campInfo = campsite.camp + float radius = float( campInfo.kv.radius ) + + // get droppod spawns + foreach ( entity spawnpoint in SpawnPoints_GetDropPod() ) + if ( Distance( campInfo.GetOrigin(), spawnpoint.GetOrigin() ) < radius ) + campsite.validDropPodSpawns.append( spawnpoint ) + + // get titan spawns + foreach ( entity spawnpoint in SpawnPoints_GetTitan() ) + if ( Distance( campInfo.GetOrigin(), spawnpoint.GetOrigin() ) < radius ) + campsite.validTitanSpawns.append( spawnpoint ) + + if ( index == 0 ) + { + campsite.campId = "A" + SetGlobalNetInt( "fwCampAlertA", 0 ) + SetGlobalNetFloat( "fwCampStressA", 0.0 ) // start from empty + SetLocationTrackerID( campsite.tracker, 0 ) + file.trackedCampNPCSpawns["A"] <- {} + continue + } + if ( index == 1 ) + { + campsite.campId = "B" + SetGlobalNetInt( "fwCampAlertB", 0 ) + SetGlobalNetFloat( "fwCampStressB", 0.0 ) // start from empty + SetLocationTrackerID( campsite.tracker, 1 ) + file.trackedCampNPCSpawns["B"] <- {} + continue + } + if ( index == 2 ) + { + campsite.campId = "C" + SetGlobalNetInt( "fwCampAlertC", 0 ) + SetGlobalNetFloat( "fwCampStressC", 0.0 ) // start from empty + SetLocationTrackerID( campsite.tracker, 2 ) + file.trackedCampNPCSpawns["C"] <- {} + continue + } + } +} + +void function InitCampTracker( entity camp ) +{ + //print("InitCampTracker") + CampSiteStruct campsite + campsite.camp = camp + file.fwCampSites.append( campsite ) + + entity placementHelper = CreateEntity( "info_placement_helper" ) + placementHelper.SetOrigin( camp.GetOrigin() ) // tracker needs a owner to display + campsite.info = placementHelper + DispatchSpawn( placementHelper ) + + float radius = float( camp.kv.radius ) // radius to show up icon and spawn ais + + entity tracker = GetAvailableCampLocationTracker() + tracker.SetOwner( placementHelper ) + campsite.tracker = tracker + SetLocationTrackerRadius( tracker, radius ) + DispatchSpawn( tracker ) +} + +void function StartFWCampThink() +{ + foreach( CampSiteStruct camp in file.fwCampSites ) + { + //print( "has " + string( file.fwCampSites.len() ) + " camps in total" ) + //print( "campId is " + camp.campId ) + thread FWAiCampThink( camp ) + } +} + +// this is not using respawn's remaining code! +void function FWAiCampThink( CampSiteStruct campsite ) +{ + string campId = campsite.campId + string alertVarName = "fwCampAlert" + campId + string stressVarName = "fwCampStress" + campId + + + bool firstSpawn = true + while( GamePlayingOrSuddenDeath() ) + { + wait WAVE_STATE_TRANSITION_TIME + + int alertLevel = GetGlobalNetInt( alertVarName ) + //print( "campsite" + campId + ".ignoredSinceLastClean: " + string( campsite.ignoredSinceLastClean ) ) + if( campsite.ignoredSinceLastClean >= FW_CAMP_IGNORE_NEEDED && alertLevel > 0 ) // has been ignored many times, level > 0 + alertLevel = 0 // reset level + else if( !firstSpawn ) // not the first spawn! + alertLevel += 1 // level up + + if( alertLevel >= FW_MAX_LEVELS - 1 ) // reached max level? + alertLevel = FW_MAX_LEVELS - 1 // stay + + // update netVars, don't know how client update these, sometimes they can't catch up + SetGlobalNetInt( alertVarName, alertLevel ) + SetGlobalNetFloat( stressVarName, 1.0 ) // refill + + // under attack, clean this + campsite.ignoredSinceLastClean = 0 + + CampSpawnStruct curSpawnStruct = file.fwNpcLevel[alertLevel] + string npcToSpawn = curSpawnStruct.spawnContent + int maxSpawnCount = curSpawnStruct.maxSpawnCount + int countPerSpawn = curSpawnStruct.countPerSpawn + int killsToEscalate = curSpawnStruct.killsToEscalate + + // for this time's loop + file.trackedCampNPCSpawns[campId] = {} + int killsNeeded = killsToEscalate + int lastNpcLeft + while( true ) + { + WaitFrame() + + //print( alertVarName + " : " + string( GetGlobalNetInt( alertVarName ) ) ) + //print( stressVarName + " : " + string( GetGlobalNetFloat( stressVarName ) ) ) + //print( "campsite" + campId + ".ignoredSinceLastClean: " + string( campsite.ignoredSinceLastClean ) ) + + if( !( npcToSpawn in file.trackedCampNPCSpawns[campId] ) ) // init it + file.trackedCampNPCSpawns[campId][npcToSpawn] <- 0 + + int npcsLeft = file.trackedCampNPCSpawns[campId][npcToSpawn] + killsNeeded -= lastNpcLeft - npcsLeft + + if( killsNeeded <= 0 ) // check if needs more kills + { + SetGlobalNetFloat( stressVarName, 0.0 ) // empty + AddIgnoredCountToOtherCamps( campsite ) + break + } + + // update stress bar + float campStressLeft = float( killsNeeded ) / float( killsToEscalate ) + SetGlobalNetFloat( stressVarName, campStressLeft ) + //print( "campStressLeft: " + string( campStressLeft ) ) + + if( maxSpawnCount - npcsLeft >= countPerSpawn && killsNeeded >= countPerSpawn ) // keep spawning + { + // spawn functions, for fw we only spawn one kind of enemy each time + // light units + if( npcToSpawn == "npc_soldier" + || npcToSpawn == "npc_spectre" + || npcToSpawn == "npc_stalker" ) + thread FW_SpawnDroppodSquad( campsite, npcToSpawn ) + + // reapers + if( npcToSpawn == "npc_super_spectre" ) + thread FW_SpawnReaper( campsite ) + + file.trackedCampNPCSpawns[campId][npcToSpawn] += countPerSpawn + + // titans? + //else if( npcToSpawn == "npc_titan" ) + //{ + // file.trackedCampNPCSpawns[campId][npcToSpawn] += 4 + //} + } + + lastNpcLeft = file.trackedCampNPCSpawns[campId][npcToSpawn] + } + + // first loop ends + firstSpawn = false + } +} + +void function AddIgnoredCountToOtherCamps( CampSiteStruct senderCamp ) +{ + foreach( CampSiteStruct camp in file.fwCampSites ) + { + //print( "senderCampId is: " + senderCamp.campId ) + //print( "curCampId is " + camp.campId ) + if( camp.campId != senderCamp.campId ) // other camps + { + camp.ignoredSinceLastClean += 1 + } + } +} + +// functions from at +void function FW_SpawnDroppodSquad( CampSiteStruct campsite, string aiType ) +{ + entity spawnpoint + if ( campsite.validDropPodSpawns.len() == 0 ) + spawnpoint = campsite.tracker // no spawnPoints valid, use camp itself to spawn + else + spawnpoint = campsite.validDropPodSpawns.getrandom() + + // add variation to spawns + wait RandomFloat( 1.0 ) + + AiGameModes_SpawnDropPod( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), FW_AI_TEAM, aiType, void function( array guys ) : ( campsite, aiType ) + { + FW_HandleSquadSpawn( guys, campsite, aiType ) + }) +} + +void function FW_HandleSquadSpawn( array guys, CampSiteStruct campsite, string aiType ) +{ + foreach ( entity guy in guys ) + { + guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) // NPC_ALLOW_INVESTIGATE is not allowed + guy.SetScriptName( FW_NPC_SCRIPTNAME ) // well no need + // show on minimap to let players kill them + guy.Minimap_AlwaysShow( TEAM_MILITIA, null ) + guy.Minimap_AlwaysShow( TEAM_IMC, null ) + + // untrack them on death + thread FW_WaitToUntrackNPC( guy, campsite.campId, aiType ) + } + // at least don't let them running around + thread FW_ForceAssaultInCamp( guys, campsite.camp ) +} + +void function FW_SpawnReaper( CampSiteStruct campsite ) +{ + entity spawnpoint + if ( campsite.validDropPodSpawns.len() == 0 ) + spawnpoint = campsite.tracker // no spawnPoints valid, use camp itself to spawn + else + spawnpoint = campsite.validDropPodSpawns.getrandom() + + // add variation to spawns + wait RandomFloat( 1.0 ) + + AiGameModes_SpawnReaper( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), FW_AI_TEAM, "npc_super_spectre_aitdm",void function( entity reaper ) : ( campsite ) + { + reaper.SetScriptName( FW_NPC_SCRIPTNAME ) // no neet rn + // show on minimap to let players kill them + reaper.Minimap_AlwaysShow( TEAM_MILITIA, null ) + reaper.Minimap_AlwaysShow( TEAM_IMC, null ) + + // at least don't let them running around + thread FW_ForceAssaultInCamp( [reaper], campsite.camp ) + // untrack them on death + thread FW_WaitToUntrackNPC( reaper, campsite.campId, "npc_super_spectre" ) + }) +} + +// maybe this will make them stay around the camp +void function FW_ForceAssaultInCamp( array guys, entity camp ) +{ + while( true ) + { + bool oneGuyValid = false + foreach( entity guy in guys ) + { + if( IsValid( guy ) ) + { + guy.AssaultPoint( camp.GetOrigin() ) + guy.AssaultSetGoalRadius( float( camp.kv.radius ) ) // the camp's radius + guy.AssaultSetFightRadius( 0 ) + oneGuyValid = true + } + } + if( !oneGuyValid ) // no guys left + return + + wait RandomFloatRange( 10, 15 ) // make randomness + } +} + +void function FW_WaitToUntrackNPC( entity guy, string campId, string aiType ) +{ + guy.WaitSignal( "OnDeath", "OnDestroy" ) + if( aiType in file.trackedCampNPCSpawns[ campId ] ) // maybe escalated? + file.trackedCampNPCSpawns[ campId ][ aiType ]-- +} + +///////////////////////////////// +///// AICAMPS FUNCTIONS END ///// +///////////////////////////////// + + + +/////////////////////////////// +///// TERRITORY FUNCTIONS ///// +/////////////////////////////// + +void function SetupFWTerritoryTrigger( entity trigger ) +{ + //print("trigger_fw_territory detected") + file.fwTerritories.append( trigger ) + trigger.ConnectOutput( "OnStartTouch", EntityEnterFWTrig ) + trigger.ConnectOutput( "OnEndTouch", EntityLeaveFWTrig ) + + // respawn didn't leave a key for trigger's team, let's set it manually. + if( Distance( trigger.GetOrigin(), file.harvesterMlt_info.GetOrigin() ) > Distance( trigger.GetOrigin(), file.harvesterImc_info.GetOrigin() ) ) + SetTeam( trigger, TEAM_IMC ) + else + SetTeam( trigger, TEAM_MILITIA ) + + // init + file.teamTerrLastConnectTime[ trigger.GetTeam() ] <- 0.0 + + thread FWTerritoryTriggerThink( trigger ) +} + +// since we're using a trigger_multiple, needs this to remove invalid keys +void function FWTerritoryTriggerThink( entity trigger ) +{ + trigger.EndSignal( "OnDestroy" ) + + while( true ) + { + if( null in trigger.e.scriptTriggerData.entities ) + delete trigger.e.scriptTriggerData.entities[ null ] + WaitFrame() + } +} + +void function EntityEnterFWTrig( entity trigger, entity ent, entity caller, var value ) +{ + if( !IsValid( ent ) ) // post-spawns + return + if( !ent.IsPlayer() && !ent.IsTitan() ) // no neet to add props and grunts i guess + return + // functions that trigger_multiple missing + if( IsValid( ent ) ) + { + ScriptTriggerAddEntity( trigger, ent ) + thread ScriptTriggerPlayerDisconnectThink( trigger, ent ) + //TryFWTerritoryDialogue( trigger, ent ) // WIP + file.teamTerrLastConnectTime[ trigger.GetTeam() ] = Time() + } + + if( !IsValid(ent) ) + return + if ( ent.IsPlayer() ) // notifications for player + { + MessageToPlayer( ent, eEventNotifications.Clear ) // clean up last message + bool sameTeam = ent.GetTeam() == trigger.GetTeam() + if ( sameTeam ) + { + Remote_CallFunction_NonReplay( ent , "ServerCallback_FW_NotifyEnterFriendlyArea" ) + ent.SetPlayerNetInt( "indicatorId", 1 ) // 1 means "FRIENDLY TERRITORY" + } + else + { + Remote_CallFunction_NonReplay( ent , "ServerCallback_FW_NotifyEnterEnemyArea" ) + ent.SetPlayerNetInt( "indicatorId", 2 ) // 2 means "ENEMY TERRITORY" + } + } +} + +void function EntityLeaveFWTrig( entity trigger, entity ent, entity caller, var value ) +{ + if( !IsValid( ent ) ) // post-spawns + return + if( !ent.IsPlayer() && !ent.IsTitan() ) // no neet to add props and grunts i guess + return + // functions that trigger_multiple missing + if( IsValid( ent ) ) + { + if( ent in trigger.e.scriptTriggerData.entities ) // need to check this! + { + ScriptTriggerRemoveEntity( trigger, ent ) + //TryFWTerritoryDialogue( trigger, ent ) // WIP + file.teamTerrLastConnectTime[ trigger.GetTeam() ] = Time() + } + } + + if( !IsValid(ent) ) + return + if ( ent.IsPlayer() ) // notifications for player + { + MessageToPlayer( ent, eEventNotifications.Clear ) // clean up + bool sameTeam = ent.GetTeam() == trigger.GetTeam() + if ( sameTeam ) + Remote_CallFunction_NonReplay( ent , "ServerCallback_FW_NotifyExitFriendlyArea" ) + else + Remote_CallFunction_NonReplay( ent , "ServerCallback_FW_NotifyExitEnemyArea" ) + ent.SetPlayerNetInt( "indicatorId", 4 ) // 4 means "NO MAN'S LAND" + } +} + +// globlized! +bool function FW_IsPlayerInFriendlyTerritory( entity player ) +{ + foreach( entity trigger in file.fwTerritories ) + { + if( trigger.GetTeam() == player.GetTeam() ) // is it friendly one? + { + if( GetAllEntitiesInTrigger( trigger ).contains( player ) ) // is player inside? + return true + } + } + return false // can't find the player +} + +// globlized! +bool function FW_IsPlayerInEnemyTerritory( entity player ) +{ + foreach( entity trigger in file.fwTerritories ) + { + if( trigger.GetTeam() != player.GetTeam() ) // is it enemy one? + { + if( GetAllEntitiesInTrigger( trigger ).contains( player ) ) // is player inside? + return true + } + } + return false // can't find the player +} + +/////////////////////////////////// +///// TERRITORY FUNCTIONS END ///// +/////////////////////////////////// + + + +//////////////////////////////// +///// TITANSPAWN FUNCTIONS ///// +//////////////////////////////// + +// territory trigger don't have a kv.radius, let's use a const +// 1800 will pretty much get harvester's near titan startpoints +const float FW_SPAWNPOINT_SEARCH_RADIUS = 1800.0 + + +Point function FW_ReCalculateTitanReplacementPoint( Point basePoint, entity player) +{ + int team = player.GetTeam() + // find team's harvester + entity teamHarvester = FW_GetTeamHarvesterProp( team ) + + if( Distance2D( basePoint.origin, teamHarvester.GetOrigin() ) <= FW_SPAWNPOINT_SEARCH_RADIUS ) // close enough! + return basePoint // this origin is good enough + + // if not close enough to base, re-calculate + array fortWarPoints = FW_GetTitanSpawnPointsForTeam( team ) + entity validPoint = GetClosest( fortWarPoints, basePoint.origin ) + basePoint.origin = validPoint.GetOrigin() + return basePoint +} + +bool function FW_RequestTitanAllowed( entity player, array< string > args ) +{ + if( !FW_IsPlayerInFriendlyTerritory( player ) ) // is player in friendly base? + { + PlayFactionDialogueToPlayer( "tw_territoryNag", player ) // notify player + TryPlayTitanfallNegativeSoundToPlayer( player ) + int objectiveID = 101 // which means "#FW_OBJECTIVE_TITANFALL" + //CreateCustomMessageForRefusingTitanfall( player ) + Remote_CallFunction_NonReplay( player, "ServerCallback_FW_SetObjective", objectiveID ) + return false + } + return true +} + +array function FW_GetTitanSpawnPointsForTeam( int team ) +{ + array validSpawnPoints + // find team's harvester + entity teamHarvester = FW_GetTeamHarvesterProp( team ) + + array allPoints + // same as _replacement_titans_drop.gnut does + allPoints.extend( GetEntArrayByClass_Expensive( "info_spawnpoint_titan" ) ) + allPoints.extend( GetEntArrayByClass_Expensive( "info_spawnpoint_titan_start" ) ) + allPoints.extend( GetEntArrayByClass_Expensive( "info_replacement_titan_spawn" ) ) + + // get valid points from all points + foreach( entity point in allPoints ) + { + if( Distance2D( point.GetOrigin(), teamHarvester.GetOrigin() ) <= FW_SPAWNPOINT_SEARCH_RADIUS ) + validSpawnPoints.append( point ) + } + + return validSpawnPoints +} + +// WORKING IN PROGRESS +void function FWForcedTitanSpawnPoint( entity titan ) +{ + +} + +//////////////////////////////////// +///// TITANSPAWN FUNCTIONS END ///// +//////////////////////////////////// + + + +///////////////////////////////// +///// THREATLEVEL FUNCTIONS ///// +///////////////////////////////// + +void function FWAreaThreatLevelThink() +{ + thread FWAreaThreatLevelThink_Threaded() +} + +void function FWAreaThreatLevelThink_Threaded() +{ + entity imcTerritory + entity mltTerritory + foreach( entity territory in file.fwTerritories ) + { + if( territory.GetTeam() == TEAM_IMC ) + imcTerritory = territory + else + mltTerritory = territory + } + + float lastWarningTime // for debounce + bool warnImcTitanApproach + bool warnMltTitanApproach + bool warnImcTitanInArea + bool warnMltTitanInArea + + while( GamePlayingOrSuddenDeath() ) + { + //print( " imc threat level is: " + string( GetGlobalNetInt( "imcTowerThreatLevel" ) ) ) + //print( " mlt threat level is: " + string( GetGlobalNetInt( "milTowerThreatLevel" ) ) ) + float imcLastDamage = fw_harvesterImc.lastDamage + float mltLastDamage = fw_harvesterMlt.lastDamage + bool imcShieldDown = fw_harvesterImc.harvesterShieldDown + bool mltShieldDown = fw_harvesterMlt.harvesterShieldDown + + // imc threatLevel + if( imcLastDamage + FW_HARVESTER_DAMAGED_DEBOUNCE >= Time() && imcShieldDown ) + SetGlobalNetInt( "imcTowerThreatLevel", 3 ) // 3 will show a "harvester being damaged" warning to player + else if( warnImcTitanInArea ) + SetGlobalNetInt( "imcTowerThreatLevel", 2 ) // 2 will show a "titan in area" warning to player + else if( warnImcTitanApproach ) + SetGlobalNetInt( "imcTowerThreatLevel", 1 ) // 1 will show a "titan approach" waning to player + else + SetGlobalNetInt( "imcTowerThreatLevel", 0 ) // 0 will hide all warnings + + // militia threatLevel + if( mltLastDamage + FW_HARVESTER_DAMAGED_DEBOUNCE >= Time() && mltShieldDown ) + SetGlobalNetInt( "milTowerThreatLevel", 3 ) // 3 will show a "harvester being damaged" warning to player + else if( warnMltTitanInArea ) + SetGlobalNetInt( "milTowerThreatLevel", 2 ) // 2 will show a "titan in area" warning to player + else if( warnMltTitanApproach ) + SetGlobalNetInt( "milTowerThreatLevel", 1 ) // 1 will show a "titan approach" waning to player + else + SetGlobalNetInt( "milTowerThreatLevel", 0 ) // 0 will hide all warnings + + + // clean it here + warnImcTitanInArea = false + warnMltTitanInArea = false + warnImcTitanApproach = false + warnMltTitanApproach = false + + // get valid titans + array allTitans = GetNPCArrayByClass( "npc_titan" ) + array allPlayers = GetPlayerArray() + foreach( entity player in allPlayers ) + { + if( IsAlive( player ) && player.IsTitan() ) + { + allTitans.append( player ) + } + } + + // check threats + array imcEntArray = GetAllEntitiesInTrigger( imcTerritory ) + array mltEntArray = GetAllEntitiesInTrigger( mltTerritory ) + imcEntArray.removebyvalue( null ) // since we're using a fake trigger, need to check this + mltEntArray.removebyvalue( null ) + foreach( entity ent in imcEntArray ) + { + //print( ent ) + if( !IsValid( ent ) ) // since we're using a fake trigger, need to check this + continue + if( ent.IsPlayer() || ent.IsNPC() ) + { + if( ent.IsTitan() && ent.GetTeam() != TEAM_IMC ) + warnImcTitanInArea = true + } + } + foreach( entity ent in mltEntArray ) + { + //print( ent ) + if( !IsValid( ent ) ) // since we're using a fake trigger, need to check this + continue + if( ent.IsPlayer() || ent.IsNPC() ) + { + if( ent.IsTitan() && ent.GetTeam() != TEAM_MILITIA ) + warnMltTitanInArea = true + } + } + + foreach( entity titan in allTitans ) + { + if( !imcEntArray.contains( titan ) + && !mltEntArray.contains( titan ) + && titan.GetTeam() != TEAM_IMC + && !titan.e.isHotDropping ) + warnImcTitanApproach = true // this titan must be in natural space + + if( !mltEntArray.contains( titan ) + && !imcEntArray.contains( titan ) + && titan.GetTeam() != TEAM_MILITIA + && !titan.e.isHotDropping ) + warnMltTitanApproach = true // this titan must be in natural space + } + + WaitFrame() + } +} + +///////////////////////////////////// +///// THREATLEVEL FUNCTIONS END ///// +///////////////////////////////////// + + + +//////////////////////////// +///// TURRET FUNCTIONS ///// +//////////////////////////// + +// for battery_port, replace the turret with new one +entity function FW_ReplaceMegaTurret( entity perviousTurret ) +{ + if( !IsValid( perviousTurret ) ) // previous turret not exist! + return + + entity turret = CreateNPC( "npc_turret_mega", perviousTurret.GetTeam(), perviousTurret.GetOrigin(), perviousTurret.GetAngles() ) + SetSpawnOption_AISettings( turret, "npc_turret_mega_fortwar" ) + SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work + AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) + DispatchSpawn( turret ) + + // apply settings to new turret, must up on date + turret.s.baseTurret <- perviousTurret.s.baseTurret + turret.s.minimapstate <- perviousTurret.s.minimapstate + turret.s.turretflagid <- perviousTurret.s.turretflagid + turret.s.lastDamagedTime <- perviousTurret.s.lastDamagedTime + turret.s.relatedBatteryPort <- perviousTurret.s.relatedBatteryPort + + int maxHealth = perviousTurret.GetMaxHealth() + int maxShield = perviousTurret.GetShieldHealthMax() + turret.SetMaxHealth( maxHealth ) + turret.SetHealth( maxHealth ) + turret.SetShieldHealth( maxShield ) + turret.SetShieldHealthMax( maxShield ) + + // update turretSiteStruct + foreach( TurretSiteStruct turretsite in file.turretsites ) + { + if( turretsite.turret == perviousTurret ) + { + turretsite.turret = turret // only changed this + } + } + + perviousTurret.Destroy() // destroy previous one + + return turret +} + +// avoid notifications overrides itself +const float TURRET_NOTIFICATION_DEBOUNCE = 10.0 + +void function OnMegaTurretDamaged( entity turret, var damageInfo ) +{ + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + entity attacker = DamageInfo_GetAttacker( damageInfo ) + float damageAmount = DamageInfo_GetDamage( damageInfo ) + int scriptType = DamageInfo_GetCustomDamageType( damageInfo ) + int turretTeam = turret.GetTeam() + + if ( !damageSourceID && !damageAmount && !attacker ) + return + + if( turret.GetShieldHealth() - damageAmount <= 0 && scriptType != damageTypes.rodeoBatteryRemoval ) // this shot breaks shield + { + if ( !attacker.IsTitan() && !IsSuperSpectre( attacker ) ) + { + if( attacker.IsPlayer() && attacker.GetTeam() != turret.GetTeam() ) // good to have + { + // avoid notifications overrides itself + if( attacker.s.lastTurretNotifyTime + TURRET_NOTIFICATION_DEBOUNCE < Time() ) + { + MessageToPlayer( attacker, eEventNotifications.Clear ) // clean up last message + MessageToPlayer( attacker, eEventNotifications.TurretTitanDamageOnly ) + attacker.s.lastTurretNotifyTime = Time() + } + } + DamageInfo_SetDamage( damageInfo, turret.GetShieldHealth() ) // destroy shields + return + } + } + + // successfully damaged turret + turret.s.lastDamagedTime = Time() + + if ( damageSourceID == eDamageSourceId.mp_titanweapon_heat_shield || + damageSourceID == eDamageSourceId.mp_titanweapon_meteor_thermite || + damageSourceID == eDamageSourceId.mp_titanweapon_flame_wall || + damageSourceID == eDamageSourceId.mp_titanability_slow_trap || + damageSourceID == eDamageSourceId.mp_titancore_flame_wave_secondary + ) // scorch's thermite damages + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo )/2 ) // nerf scorch + + // faction dialogue + damageAmount = DamageInfo_GetDamage( damageInfo ) + if( turret.GetHealth() - damageAmount <= 0 ) // turret killed this shot + { + if( GamePlayingOrSuddenDeath() ) + PlayFactionDialogueToTeam( "fortwar_turretDestroyedFriendly", turretTeam ) + } +} + +void function InitTurretSettings() +{ + foreach( TurretSiteStruct turretSite in file.turretsites ) + { + entity turret = turretSite.turret + entity minimapstate = turretSite.minimapstate + int teamNum = turretSite.site.GetTeam() + int id = int( string( turretSite.site.kv.turretId ) ) + string idString = string( id + 1 ) + int team = int( string( turretSite.site.kv.teamnumber ) ) + + int stateFlag = 1 // netural + + // spawn with teamNumber? + if( team == TEAM_IMC || team == TEAM_MILITIA ) + turret.s.baseTurret = true + + //SetTeam( minimapstate, team ) // setTeam() for icons is done in TurretStateWatcher() + SetTeam( turret, team ) + + //print( "Try to set globatNetEnt: " + "turretSite" + idString ) + + turret.s.turretflagid = idString + turretSite.turretflagid = idString + + thread TurretStateWatcher( turretSite ) + } +} + +// about networkvar "turretStateFlags" value +// 1 means destoryed/netural +// 2 means imc turret +// 4 means mlt turret +// 10 means shielded imc turret +// 13 means shielded mlt turret +// 16 means destoryed/netural being attacked +// 18 means imc turret being attacked +// 20 means mlt turret being attacked +// 26 means shielded imc turret being attacked +// 28 means shielded mlt turret being attacked + +// unsure: +// 24 means destroyed imc turret being attacked? +// 40 means destroyed imc turret? +// 48 means destroyed mlt turret being attacked? + +const int TURRET_DESTROYED_FLAG = 1 +const int TURRET_NATURAL_FLAG = 1 +const int TURRET_IMC_FLAG = 2 +const int TURRET_MLT_FLAG = 4 +const int TURRET_SHIELDED_IMC_FLAG = 10 +const int TURRET_SHIELDED_MLT_FLAG = 13 + +const int TURRET_UNDERATTACK_NATURAL_FLAG = 16 +const int TURRET_UNDERATTACK_IMC_FLAG = 18 +const int TURRET_UNDERATTACK_MLT_FLAG = 20 +// natural turret noramlly can't get shielded +const int TURRET_SHIELDED_UNDERATTACK_IMC_FLAG = 26 +const int TURRET_SHIELDED_UNDERATTACK_MLT_FLAG = 28 + +void function TurretStateWatcher( TurretSiteStruct turretSite ) +{ + entity mapIcon = turretSite.minimapstate + entity turret = turretSite.turret + entity batteryPort = expect entity( turret.s.relatedBatteryPort ) + + int turretHealth = GetCurrentPlaylistVarInt( "fw_turret_health", FW_DEFAULT_TURRET_HEALTH ) + int turretShield = GetCurrentPlaylistVarInt( "fw_turret_shield", FW_DEFAULT_TURRET_SHIELD ) + turret.SetMaxHealth( turretHealth ) + turret.SetHealth( turretHealth ) + turret.SetShieldHealthMax( turretShield ) + + string idString = turretSite.turretflagid + string siteVarName = "turretSite" + idString + string stateVarName = "turretStateFlags" + idString + + // battery overlay icons holder + entity overlayState = CreateEntity( "prop_script" ) + overlayState.SetValueForModelKey( $"models/communication/flag_base.mdl" ) // requires a model to show overlays + overlayState.Hide() // this can still show players overlay icons + overlayState.SetOrigin( batteryPort.GetOrigin() ) // tracking batteryPort's positions + overlayState.SetAngles( batteryPort.GetAngles() ) + overlayState.kv.solid = SOLID_VPHYSICS + DispatchSpawn( overlayState ) + + svGlobal.levelEnt.EndSignal( "CleanUpEntitiesForRoundEnd" ) // end dialogues is good + mapIcon.EndSignal( "OnDestroy" ) // mapIcon should be valid all time, tracking it + batteryPort.EndSignal( "OnDestroy" ) // also track this + overlayState.EndSignal( "OnDestroy" ) + + SetGlobalNetEnt( siteVarName, overlayState ) // tracking batteryPort's positions and team + SetGlobalNetInt( stateVarName, TURRET_NATURAL_FLAG ) // init for all turrets + + int lastFrameTeam + bool lastFrameIsAlive + + while( true ) + { + WaitFrame() // start of the loop + + turret = turretSite.turret // need to keep updating, for sometimes it being replaced + + if( !IsValid( turret ) ) // replacing turret this frame + continue // skip the loop once + + bool isBaseTurret = expect bool( turret.s.baseTurret ) + int turretTeam = turret.GetTeam() + bool turretAlive = IsAlive( turret ) + + bool changedTeamThisFrame = lastFrameTeam != turretTeam // turret has changed team? + bool killedThisFrame = lastFrameIsAlive != turretAlive // turret has no health left? + + if( !turretAlive ) // turret down, waiting to be repaired + { + if( !isBaseTurret ) // never reset base turret's team + { + SetTeam( turret, TEAM_UNASSIGNED ) + SetTeam( mapIcon, TEAM_UNASSIGNED ) + SetTeam( batteryPort, TEAM_UNASSIGNED ) + SetTeam( overlayState, TEAM_UNASSIGNED ) + batteryPort.SetUsableByGroup( "pilot" ) // show hints to any pilot + } + SetGlobalNetInt( stateVarName, TURRET_DESTROYED_FLAG ) + continue + } + + // wrong dialogue, it will say "The turret you requested is on the way" + //if( changedTeamThisFrame ) // has been hacked! + // PlayFactionDialogueToTeam( "fortwar_turretDeployFriendly", turretTeam ) + + int iconTeam = turretTeam == TEAM_BOTH ? TEAM_UNASSIGNED : turretTeam // specific check + SetTeam( mapIcon, iconTeam ) // update icon's team + SetTeam( batteryPort, turretTeam ) // update batteryPort's team + SetTeam( overlayState, iconTeam ) // update overlayEnt's team + + if( turretTeam != TEAM_BOTH && turretTeam != TEAM_UNASSIGNED ) // not a natural turret nor dead + batteryPort.SetUsableByGroup( "friendlies pilot" ) // only show hint to friendlies + + float lastDamagedTime = expect float( turret.s.lastDamagedTime ) + int stateFlag = TURRET_NATURAL_FLAG + + // imc states + if( iconTeam == TEAM_IMC ) + { + if( lastDamagedTime + FW_TURRET_DAMAGED_DEBOUNCE >= Time() ) // recent underattack + { + if( turret.GetShieldHealth() > 0 ) // has shields + stateFlag = TURRET_SHIELDED_UNDERATTACK_IMC_FLAG + else + stateFlag = TURRET_UNDERATTACK_IMC_FLAG + + // these dialogue have 30s debounce inside + if( isBaseTurret ) + PlayFactionDialogueToTeam( "fortwar_baseTurretsUnderAttack", TEAM_IMC ) + else + PlayFactionDialogueToTeam( "fortwar_awayTurretsUnderAttack", TEAM_IMC ) + } + else if( turret.GetShieldHealth() > 0 ) // has shields left + stateFlag = TURRET_SHIELDED_IMC_FLAG + else + stateFlag = TURRET_IMC_FLAG + } + + // mlt states + if( iconTeam == TEAM_MILITIA ) + { + if( lastDamagedTime + FW_TURRET_DAMAGED_DEBOUNCE >= Time() ) // recent underattack + { + if( turret.GetShieldHealth() > 0 ) // has shields + stateFlag = TURRET_SHIELDED_UNDERATTACK_MLT_FLAG + else + stateFlag = TURRET_UNDERATTACK_MLT_FLAG + + // these dialogue have 30s debounce inside + if( isBaseTurret ) + PlayFactionDialogueToTeam( "fortwar_baseTurretsUnderAttack", TEAM_MILITIA ) + else + PlayFactionDialogueToTeam( "fortwar_awayTurretsUnderAttack", TEAM_MILITIA ) + } + else if( turret.GetShieldHealth() > 0 ) // has shields left + stateFlag = TURRET_SHIELDED_MLT_FLAG + else + stateFlag = TURRET_MLT_FLAG + } + + // natural states + if( iconTeam == TEAM_UNASSIGNED ) + { + if( lastDamagedTime + FW_TURRET_DAMAGED_DEBOUNCE >= Time() ) // recent underattack + stateFlag = TURRET_UNDERATTACK_NATURAL_FLAG + else + stateFlag = TURRET_NATURAL_FLAG + } + + SetGlobalNetInt( stateVarName, stateFlag ) + + // update these + lastFrameTeam = turretTeam + lastFrameIsAlive = turretAlive + + WaitFrame() + } +} + +//////////////////////////////// +///// TURRET FUNCTIONS END ///// +//////////////////////////////// + + + +/////////////////////////////// +///// HARVESTER FUNCTIONS ///// +/////////////////////////////// + +void function startFWHarvester() +{ + thread HarvesterThink(fw_harvesterImc) + thread HarvesterAlarm(fw_harvesterImc) + thread UpdateHarvesterHealth( TEAM_IMC ) + + thread HarvesterThink(fw_harvesterMlt) + thread HarvesterAlarm(fw_harvesterMlt) + thread UpdateHarvesterHealth( TEAM_MILITIA ) +} + +entity function FW_GetTeamHarvesterProp( int team ) +{ + if( team == TEAM_IMC ) + return fw_harvesterImc.harvester + else if( team == TEAM_MILITIA ) + return fw_harvesterMlt.harvester + + unreachable // crash the game +} + +void function FW_createHarvester() +{ + // mlt havester spawn + fw_harvesterImc = SpawnHarvester( file.harvesterImc_info.GetOrigin(), file.harvesterImc_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_IMC ) + fw_harvesterImc.harvester.Minimap_SetAlignUpright( true ) + fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) + fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null ) + fw_harvesterImc.harvester.Minimap_SetHeightTracking( true ) + fw_harvesterImc.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + fw_harvesterImc.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) + AddEntityCallback_OnDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged ) + AddEntityCallback_OnPostDamaged( fw_harvesterImc.harvester, OnHarvesterPostDamaged ) + // imc havester settings + // don't set this, or sonar pulse will try to find it and failed to set highlight + //fw_harvesterMlt.harvester.SetScriptName("fw_team_tower") + file.harvesters.append(fw_harvesterImc) + entity trackerImc = GetAvailableBaseLocationTracker() + trackerImc.SetOwner( fw_harvesterImc.harvester ) + DispatchSpawn( trackerImc ) + SetLocationTrackerRadius( trackerImc, 1 ) // whole map + + // scores starts from 100, TeamScore means harvester health; TeamScore2 means shield bar + GameRules_SetTeamScore( TEAM_MILITIA , 100 ) + GameRules_SetTeamScore2( TEAM_MILITIA , 100 ) + + + // mlt havester spawn + fw_harvesterMlt = SpawnHarvester( file.harvesterMlt_info.GetOrigin(), file.harvesterMlt_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_MILITIA ) + fw_harvesterMlt.harvester.Minimap_SetAlignUpright( true ) + fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) + fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null ) + fw_harvesterMlt.harvester.Minimap_SetHeightTracking( true ) + fw_harvesterMlt.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + fw_harvesterMlt.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) + AddEntityCallback_OnDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged ) + + // mlt havester settings + // don't set this, or sonar pulse will try to find it and failed to set highlight + //fw_harvesterImc.harvester.SetScriptName("fw_team_tower") + file.harvesters.append(fw_harvesterMlt) + entity trackerMlt = GetAvailableBaseLocationTracker() + trackerMlt.SetOwner( fw_harvesterMlt.harvester ) + DispatchSpawn( trackerMlt ) + SetLocationTrackerRadius( trackerMlt, 1 ) // whole map + + // scores starts from 100, TeamScore means harvester health; TeamScore2 means shield bar + GameRules_SetTeamScore( TEAM_IMC , 100 ) + GameRules_SetTeamScore2( TEAM_IMC , 100 ) +} +void function OnHarvesterDamaged( entity harvester, var damageInfo ) +{ + if ( !IsValid( harvester ) ) + return + + int friendlyTeam = harvester.GetTeam() + int enemyTeam = GetOtherTeam( friendlyTeam ) + + HarvesterStruct harvesterstruct // current harveter's struct + if( friendlyTeam == TEAM_MILITIA ) + harvesterstruct = fw_harvesterMlt + if( friendlyTeam == TEAM_IMC ) + harvesterstruct = fw_harvesterImc + + float damageAmount = DamageInfo_GetDamage( damageInfo ) + if((harvester.GetShieldHealth()-damageAmount)<0) + { + if( !harvesterstruct.harvesterShieldDown ) + { + PlayFactionDialogueToTeam( "fortwar_baseShieldDownFriendly", friendlyTeam ) + PlayFactionDialogueToTeam( "fortwar_baseShieldDownEnemy", enemyTeam ) + harvesterstruct.harvesterShieldDown = true // prevent shield dialogues from repeating + } + } + + // always reset harvester's recharge delay + harvesterstruct.lastDamage = Time() +} +void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) +{ + if ( !IsValid( harvester ) ) + return + + int friendlyTeam = harvester.GetTeam() + int enemyTeam = GetOtherTeam( friendlyTeam ) + + GameRules_SetTeamScore( friendlyTeam , 1.0 * GetHealthFrac( harvester ) * 100 ) + + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + entity attacker = DamageInfo_GetAttacker( damageInfo ) + float damageAmount = DamageInfo_GetDamage( damageInfo ) + if(damageAmount == 0) + return + printt("Harvester damage", damageAmount,attacker, damageSourceID) + if ( !damageSourceID && !damageAmount && !attacker ) // actually not dealing any damage? + return + + // done damage adjustments here, since harvester prop's health is setting manually through damageAmount + if ( damageSourceID == eDamageSourceId.mp_titancore_laser_cannon ) + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 50 ) // laser core shreds super well for some reason + + // plasma railgun can always do no-charge shots and deal same damage + if ( damageSourceID == eDamageSourceId.mp_titanweapon_sniper ) // nerf northstar + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) + + // leadwall have high pilot damage so works really well aginst harvester + if ( damageSourceID == eDamageSourceId.mp_titanweapon_leadwall ) // nerf ronin + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) + + // missiles mostly have high pilot damage so works really well aginst harvester + if ( damageSourceID == eDamageSourceId.mp_titanweapon_salvo_rockets || + damageSourceID == eDamageSourceId.mp_titanweapon_shoulder_rockets || + damageSourceID == eDamageSourceId.mp_titancore_salvo_core + ) // titan missiles + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) + + if ( damageSourceID == eDamageSourceId.mp_titanweapon_flightcore_rockets ) // flight core shreds well + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) + + // cluster missle is very effective against non-moving targets + if ( damageSourceID == eDamageSourceId.mp_titanweapon_dumbfire_rockets ) // cluster missile shreds super well + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 10 ) + + // scorch's thermites is very effective against non-moving targets + if ( damageSourceID == eDamageSourceId.mp_titanweapon_heat_shield || + damageSourceID == eDamageSourceId.mp_titanweapon_meteor_thermite || + damageSourceID == eDamageSourceId.mp_titanweapon_flame_wall || + damageSourceID == eDamageSourceId.mp_titanability_slow_trap || + damageSourceID == eDamageSourceId.mp_titancore_flame_wave_secondary + ) // scorch's thermite damages, nerf scorch + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) + + HarvesterStruct harvesterstruct // current harveter's struct + if( friendlyTeam == TEAM_MILITIA ) + harvesterstruct = fw_harvesterMlt + if( friendlyTeam == TEAM_IMC ) + harvesterstruct = fw_harvesterImc + + damageAmount = DamageInfo_GetDamage( damageInfo ) // get damageAmount again after all damage adjustments + + if ( !attacker.IsTitan() ) + { + if( attacker.IsPlayer() ) + Remote_CallFunction_NonReplay( attacker , "ServerCallback_FW_NotifyTitanRequired" ) + DamageInfo_SetDamage( damageInfo, harvester.GetShieldHealth() ) + damageAmount = 0 // never damage haveter's prop + } + + harvesterstruct.harvesterDamageTaken = harvesterstruct.harvesterDamageTaken + damageAmount // track damage for wave recaps + float newHealth = harvester.GetHealth() - damageAmount + float oldhealthpercent = ( ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth() ) * 100 ) + + float healthpercent = ( ( newHealth / harvester.GetMaxHealth() ) * 100 ) + + if (healthpercent <= 75 && oldhealthpercent > 75) // we don't want the dialogue to keep saying "Harvester is below 75% health" everytime they take additional damage + { + PlayFactionDialogueToTeam( "fortwar_baseDmgFriendly75", friendlyTeam ) + PlayFactionDialogueToTeam( "fortwar_baseDmgEnemy75", enemyTeam ) + } + + if (healthpercent <= 50 && oldhealthpercent > 50) + { + PlayFactionDialogueToTeam( "fortwar_baseDmgFriendly50", friendlyTeam ) + PlayFactionDialogueToTeam( "fortwar_baseDmgEnemy50", enemyTeam ) + } + + if (healthpercent <= 25 && oldhealthpercent > 25) + { + PlayFactionDialogueToTeam( "fortwar_baseDmgFriendly25", friendlyTeam ) + PlayFactionDialogueToTeam( "fortwar_baseDmgEnemy25", enemyTeam ) + } + + if( newHealth <= 0 ) + { + EmitSoundAtPosition(TEAM_UNASSIGNED,harvesterstruct.harvester.GetOrigin(),"coop_generator_destroyed") + newHealth = 0 + harvesterstruct.rings.Destroy() + harvesterstruct.harvester.Dissolve( ENTITY_DISSOLVE_CORE, Vector( 0, 0, 0 ), 500 ) + } + + harvester.SetHealth( newHealth ) + harvesterstruct.havesterWasDamaged = true + + + if ( attacker.IsPlayer() ) + { + // dialogue for enemy attackers + if( !harvesterstruct.harvesterShieldDown ) + PlayFactionDialogueToTeam( "fortwar_baseEnemyAllyAttacking", enemyTeam ) + + attacker.NotifyDidDamage( harvester, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamagePosition( damageInfo ), DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageFlags( damageInfo ), DamageInfo_GetHitGroup( damageInfo ), DamageInfo_GetWeapon( damageInfo ), DamageInfo_GetDistFromAttackOrigin( damageInfo ) ) + + // get newest damage for adding score! + int scoreDamage = int( DamageInfo_GetDamage( damageInfo ) ) + // score events + attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, scoreDamage ) + + // add to player structs + file.playerDamageHarvester[ attacker ].recentDamageTime = Time() + file.playerDamageHarvester[ attacker ].storedDamage += scoreDamage + + // enough to earn score? + if( file.playerDamageHarvester[ attacker ].storedDamage >= FW_HARVESTER_DAMAGE_SEGMENT ) + { + AddPlayerScore( attacker, "FortWarTowerDamage", attacker ) + attacker.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_FW_TOWER_DAMAGE ) + file.playerDamageHarvester[ attacker ].storedDamage -= FW_HARVESTER_DAMAGE_SEGMENT // reset stored damage + } + } + + + + if ( harvester.GetHealth() == 0 ) + { + SetWinner( enemyTeam ) + //PlayFactionDialogueToTeam( "scoring_wonMercy", enemyTeam ) + //PlayFactionDialogueToTeam( "fortwar_matchLoss", friendlyTeam ) + GameRules_SetTeamScore2( friendlyTeam, 0 ) // force set score2 to 0( shield bar will empty ) + GameRules_SetTeamScore( friendlyTeam, 0 ) // force set score to 0( health 0% ) + } +} + +void function HarvesterThink( HarvesterStruct fd_harvester ) +{ + entity harvester = fd_harvester.harvester + + + EmitSoundOnEntity( harvester, "coop_generator_startup" ) + + float lastTime = Time() + wait 4 + int lastShieldHealth = harvester.GetShieldHealth() + generateBeamFX( fd_harvester ) + generateShieldFX( fd_harvester ) + + EmitSoundOnEntity( harvester, "coop_generator_ambient_healthy" ) + + bool isRegening = false // stops the regenning sound to keep stacking on top of each other + + while ( IsAlive( harvester ) ) + { + float currentTime = Time() + float deltaTime = currentTime -lastTime + + if ( IsValid( fd_harvester.particleShield ) ) + { + vector shieldColor = GetShieldTriLerpColor( 1.0 - ( harvester.GetShieldHealth().tofloat() / harvester.GetShieldHealthMax().tofloat() ) ) + EffectSetControlPointVector( fd_harvester.particleShield, 1, shieldColor ) + } + + if( IsValid( fd_harvester.particleBeam ) ) + { + vector beamColor = GetShieldTriLerpColor( 1.0 - ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth().tofloat() ) ) + EffectSetControlPointVector( fd_harvester.particleBeam, 1, beamColor ) + } + + if ( fd_harvester.harvester.GetShieldHealth() == 0 ) + if( IsValid( fd_harvester.particleShield ) ) + fd_harvester.particleShield.Destroy() + + if ( ( ( currentTime-fd_harvester.lastDamage ) >= GENERATOR_SHIELD_REGEN_DELAY ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + { + if( !IsValid( fd_harvester.particleShield ) ) + generateShieldFX( fd_harvester ) + + if( harvester.GetShieldHealth() == 0 ) + EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_start" ) + + if (!isRegening) + { + EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_resume" ) + fd_harvester.harvesterShieldDown = false + isRegening = true + } + + float newShieldHealth = ( harvester.GetShieldHealthMax() / GENERATOR_SHIELD_REGEN_TIME * deltaTime ) + harvester.GetShieldHealth() + + if ( newShieldHealth >= harvester.GetShieldHealthMax() ) + { + StopSoundOnEntity( harvester, "coop_generator_shieldrecharge_resume" ) + harvester.SetShieldHealth( harvester.GetShieldHealthMax() ) + EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_end" ) + PlayFactionDialogueToTeam( "fortwar_baseShieldUpFriendly", harvester.GetTeam() ) + isRegening = false + } + else + { + harvester.SetShieldHealth( newShieldHealth ) + } + } + else if ( ( ( currentTime-fd_harvester.lastDamage ) < GENERATOR_SHIELD_REGEN_DELAY ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + { + isRegening = false + } + + if ( ( lastShieldHealth > 0 ) && ( harvester.GetShieldHealth() == 0 ) ) + { + EmitSoundOnEntity( harvester, "TitanWar_Harvester_ShieldDown" ) // add this + EmitSoundOnEntity( harvester, "coop_generator_shielddown" ) + } + + lastShieldHealth = harvester.GetShieldHealth() + lastTime = currentTime + WaitFrame() + } +} + +void function HarvesterAlarm( HarvesterStruct fd_harvester ) +{ + while( IsAlive( fd_harvester.harvester ) ) + { + if( fd_harvester.harvester.GetShieldHealth() == 0 ) + { + wait EmitSoundOnEntity( fd_harvester.harvester, "coop_generator_underattack_alarm" ) + } + else + { + WaitFrame() + } + } +} + +void function UpdateHarvesterHealth( int team ) +{ + entity harvester + if( team == TEAM_MILITIA ) + harvester = fw_harvesterMlt.harvester + if( team == TEAM_IMC ) + harvester = fw_harvesterImc.harvester + + while( true ) + { + if( IsValid(harvester) ) + { + GameRules_SetTeamScore2( team, 1.0 * harvester.GetShieldHealth() / harvester.GetShieldHealthMax() * 100 ) + WaitFrame() + } + else // harvester down + { + int winnerTeam = GetOtherTeam(team) + SetWinner( winnerTeam ) + //PlayFactionDialogueToTeam( "scoring_wonMercy", winnerTeam ) + //PlayFactionDialogueToTeam( "fortwar_matchLoss", team ) + GameRules_SetTeamScore2( team, 0 ) // force set score2 to 0( shield bar will empty ) + GameRules_SetTeamScore( team, 0 ) // force set score to 0( health 0% ) + break + } + } +} + +/////////////////////////////////// +///// HARVESTER FUNCTIONS END ///// +/////////////////////////////////// + + + +////////////////////////////////////// +///// PLAYER OBJECTIVE FUNCTIONS ///// +////////////////////////////////////// + +const int APPLY_BATTERY_TEXT_INDEX = 96 // notify player to use batteries on turrets +const int EARN_TITAN_TEXT_INDEX = 100 // notify player to earn titans +const int CALL_IN_TITAN_TEXT_INDEX = 101 // notify player to call in titans in territory +const int EMBARK_TITAN_TEXT_INDEX = 102 // notify player to embark titans +const int ATTACK_HARVESTER_TEXT_INDEX = 103 // notify player to attack harvester + +void function FWPlayerObjectiveState() +{ + thread FWPlayerObjectiveState_Threaded() +} + +void function FWPlayerObjectiveState_Threaded() +{ + while( GamePlayingOrSuddenDeath() ) + { + foreach( player in GetPlayerArray() ) + { + entity petTitan = player.GetPetTitan() + entity titanSoul + if( IsValid( petTitan ) ) + titanSoul = petTitan.GetTitanSoul() + + if ( IsValid( GetBatteryOnBack( player ) ) ) + player.SetPlayerNetInt( "gameInfoStatusText", APPLY_BATTERY_TEXT_INDEX ) + else if ( IsTitanAvailable( player ) ) + { + if( !player.s.notifiedTitanfall ) // first notification, also do a objective announcement + { + SetObjective( player, CALL_IN_TITAN_TEXT_INDEX ) + player.s.notifiedTitanfall = true + } + else + player.SetPlayerNetInt( "gameInfoStatusText", CALL_IN_TITAN_TEXT_INDEX ) + } + else if ( IsValid( petTitan ) ) + player.SetPlayerNetInt( "gameInfoStatusText", EMBARK_TITAN_TEXT_INDEX ) + else if ( IsAlive( player ) && !player.IsTitan() ) + player.SetPlayerNetInt( "gameInfoStatusText", EARN_TITAN_TEXT_INDEX ) + else if( !IsValid( titanSoul ) ) // titan died or player first embarked + player.s.notifiedTitanfall = false + + if ( !IsAlive( player ) ) // don't show objetive for dying players + player.SetPlayerNetInt( "gameInfoStatusText", -1 ) + } + WaitFrame() + } + + // game entered other state, clean this + foreach( player in GetPlayerArray() ) + { + player.SetPlayerNetInt( "gameInfoStatusText", -1 ) + } +} + +void function SetObjective( entity player, int stringid ) +{ + Remote_CallFunction_NonReplay( player, "ServerCallback_FW_SetObjective", stringid ) + player.SetPlayerNetInt( "gameInfoStatusText", stringid ) +} + +void function SetTitanObjective( entity player, entity titan ) +{ + SetObjective( player, ATTACK_HARVESTER_TEXT_INDEX ) +} + +void function SetPilotObjective( entity player, entity titan ) +{ + if( titan.GetTitanSoul().IsEjecting() ) // this time titan is ejecting + { + SetObjective( player, EARN_TITAN_TEXT_INDEX ) + player.s.notifiedTitanfall = false + } + else + player.SetPlayerNetInt( "gameInfoStatusText", EMBARK_TITAN_TEXT_INDEX ) +} + +////////////////////////////////////////// +///// PLAYER OBJECTIVE FUNCTIONS END ///// +////////////////////////////////////////// + + + +///////////////////////////////// +///// BatteryPort Functions ///// +///////////////////////////////// + +void function FW_InitBatteryPort( entity batteryPort ) +{ + batteryPort.kv.fadedist = 10000 // try not to fade + InitTurretBatteryPort( batteryPort ) + + batteryPort.s.relatedTurret <- null // entity, for saving batteryPort's nearest turret + + entity turret = GetNearestMegaTurret( batteryPort ) // consider this is the port's related turret + + bool isBaseTurret = expect bool( turret.s.baseTurret ) + SetTeam( batteryPort, turret.GetTeam() ) + batteryPort.s.relatedTurret = turret + batteryPort.s.isUsable <- FW_IsBatteryPortUsable + batteryPort.s.useBattery <- FW_UseBattery + if( isBaseTurret ) // this is a base turret! + { + batteryPort.s.hackAvaliable = false + batteryPort.SetUsableByGroup( "friendlies pilot" ) // only show hint to friendlies + } // it can never be hacked! + + turret.s.relatedBatteryPort = batteryPort // do it here +} + +function FW_IsBatteryPortUsable( batteryPortvar, playervar ) //actually bool function( entity, entity ) +{ + entity batteryPort = expect entity( batteryPortvar ) + entity player = expect entity( playervar ) + entity turret = expect entity( batteryPort.s.relatedTurret ) + if( !IsValid( turret ) ) // turret has been destroyed! + return false + + // get turret's settings, decide behavior + bool validTeam = turret.GetTeam() == player.GetTeam() || turret.GetTeam() == TEAM_BOTH || turret.GetTeam() == TEAM_UNASSIGNED + bool isBaseTurret = expect bool( turret.s.baseTurret ) + // is this port able to be hacked + bool portHackAvaliable = expect bool( batteryPort.s.hackAvaliable ) + + // player has a battery, team valid or able to hack && not a base turret + return ( PlayerHasBattery( player ) && ( validTeam || ( portHackAvaliable && !isBaseTurret ) ) ) +} + +function FW_UseBattery( batteryPortvar, playervar ) //actually void function( entity, entity ) +{ + entity batteryPort = expect entity( batteryPortvar ) + entity player = expect entity( playervar ) + // change turret settings + entity turret = expect entity( batteryPort.s.relatedTurret ) // consider this is the port's related turret + + int playerTeam = player.GetTeam() + bool turretReplaced = false + bool sameTeam = turret.GetTeam() == player.GetTeam() + + if( !IsAlive( turret ) ) // turret has been killed! + { + turret = FW_ReplaceMegaTurret( turret ) + if( !IsValid( turret ) ) // replace failed! + return + batteryPort.s.relatedTurret = turret + turretReplaced = true // if turret has been replaced, mostly reset team! + } + + bool teamChanged = false + bool isBaseTurret = expect bool( turret.s.baseTurret ) + if( ( !sameTeam || turretReplaced ) && !isBaseTurret ) // is there a need to change team? + { + SetTeam( turret, playerTeam ) + teamChanged = true + } + + // restore turret health + int newHealth = int ( min( turret.GetMaxHealth(), turret.GetHealth() + ( turret.GetMaxHealth() * GetCurrentPlaylistVarFloat( "fw_turret_fixed_health", TURRET_FIXED_HEALTH_PERCENTAGE ) ) ) ) + if( turretReplaced || teamChanged ) // replaced/hacked turret will spawn with 50% health + newHealth = int ( turret.GetMaxHealth() * GetCurrentPlaylistVarFloat( "fw_turret_hacked_health", TURRET_HACKED_HEALTH_PERCENTAGE ) ) + // restore turret shield + int newShield = int ( min( turret.GetShieldHealthMax(), turret.GetShieldHealth() + ( turret.GetShieldHealth() * GetCurrentPlaylistVarFloat( "fw_turret_fixed_shield", TURRET_FIXED_SHIELD_PERCENTAGE ) ) ) ) + if( turretReplaced || teamChanged ) // replaced/hacked turret will spawn with 50% shield + newShield = int ( turret.GetShieldHealthMax() * GetCurrentPlaylistVarFloat( "fw_turret_hacked_shield", TURRET_HACKED_SHIELD_PERCENTAGE ) ) + // only do team score event if turret's shields down, encourage players to hack more turrets + bool additionalScore = turret.GetShieldHealth() <= 0 + // this can be too much powerful + turret.SetHealth( newHealth ) + turret.SetShieldHealth( newShield ) + + // score event + string scoreEvent = "FortWarForwardConstruction" + int secondaryScore = POINTVALUE_FW_FORWARD_CONSTRUCTION + if( isBaseTurret ) // this is a base turret + { + scoreEvent = "FortWarBaseConstruction" + secondaryScore = POINTVALUE_FW_BASE_CONSTRUCTION + } + AddPlayerScore( player, scoreEvent, player ) // player themself gets more meter + player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, secondaryScore ) + + // only do team score event if turret's shields down + if( additionalScore ) + { + // get turrets alive, for adding scores + string teamTurretCount = GetTeamAliveTurretCount_ReturnString( playerTeam ) + foreach( entity friendly in GetPlayerArrayOfTeam( playerTeam ) ) + AddPlayerScore( friendly, "FortWarTeamTurretControlBonus_" + teamTurretCount, friendly ) + + PlayFactionDialogueToTeam( "fortwar_turretShieldedByFriendlyPilot", playerTeam ) + } + +} + +// get nearest turret, consider it belongs to the port +entity function GetNearestMegaTurret( entity ent ) +{ + array allTurrets = GetNPCArrayByClass( "npc_turret_mega" ) + entity turret = GetClosest( allTurrets, ent.GetOrigin() ) + return turret +} + +// this will get english name of the count, since the "FortWarTeamTurretControlBonus_" score event uses it +string function GetTeamAliveTurretCount_ReturnString( int team ) +{ + int turretCount + foreach( entity turret in GetNPCArrayByClass( "npc_turret_mega" ) ) + { + if( turret.GetTeam() == team && IsAlive( turret ) ) + turretCount += 1 + } + + switch( turretCount ) + { + case 1: + return "One" + case 2: + return "Two" + case 3: + return "Three" + case 4: + return "Four" + case 5: + return "Five" + case 6: + return "Six" + } + + return "" +} + +///////////////////////////////////// +///// BatteryPort Functions End ///// +///////////////////////////////////// \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut index e2cdc1a3..0cd2fd62 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut @@ -5,8 +5,35 @@ global function SHCreateGamemodeFW_Init +// object settings, changable through playlist vars +// default havester settings +global const int FW_DEFAULT_HARVESTER_HEALTH = 25000 +global const int FW_DEFAULT_HARVESTER_SHIELD = 5000 +// default turret settings +global const int FW_DEFAULT_TURRET_HEALTH = 12500 +global const int FW_DEFAULT_TURRET_SHIELD = 4000 + +// fix a turret +global const float TURRET_FIXED_HEALTH_PERCENTAGE = 0.33 +global const float TURRET_FIXED_SHIELD_PERCENTAGE = 1.0 // default is regen all shield +// hack a turret +global const float TURRET_HACKED_HEALTH_PERCENTAGE = 0.5 +global const float TURRET_HACKED_SHIELD_PERCENTAGE = 0.5 + void function SHCreateGamemodeFW_Init() { + // harvester playlistvar + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD.tostring() ) + // turret playlistvar + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_health", FW_DEFAULT_TURRET_HEALTH.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_shield", FW_DEFAULT_TURRET_SHIELD.tostring() ) + // battery port playlistvar + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_fixed_health", TURRET_FIXED_HEALTH_PERCENTAGE.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_fixed_shield", TURRET_FIXED_SHIELD_PERCENTAGE.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_hacked_health", TURRET_HACKED_HEALTH_PERCENTAGE.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_hacked_shield", TURRET_HACKED_SHIELD_PERCENTAGE.tostring() ) + AddCallback_OnCustomGamemodesInit( CreateGamemodeFW ) AddCallback_OnRegisteringCustomNetworkVars( FWOnRegisteringNetworkVars ) } @@ -19,16 +46,27 @@ void function CreateGamemodeFW() GameMode_Create( FORT_WAR ) GameMode_SetName( FORT_WAR, "#GAMEMODE_fw" ) GameMode_SetDesc( FORT_WAR, "#PL_fw_desc" ) - GameMode_SetGameModeAnnouncement( FORT_WAR, "ffa_modeDesc" ) // fw lines are unfortunately not registered to faction dialogue + + // fw lines are unfortunately not registered to faction dialogue, maybe do it in gamemode script manually, current using it's modeName + GameMode_SetGameModeAnnouncement( FORT_WAR, "fortwar_modeName" ) - #if SERVER - //GameMode_AddServerInit( FORT_WAR, GamemodeFW_Init ) // doesn't exist yet lol - #elseif CLIENT - GameMode_AddClientInit( FORT_WAR, CLGamemodeFW_Init ) - #endif - #if !UI - GameMode_AddSharedInit( FORT_WAR, SHGamemodeFW_Init ) - #endif + // waiting to be synced with client + GameMode_AddScoreboardColumnData( FORT_WAR, "#SCOREBOARD_KILLS", PGS_KILLS, 2 ) + GameMode_AddScoreboardColumnData( FORT_WAR, "#SCOREBOARD_SUPPORT_SCORE", PGS_DEFENSE_SCORE, 4 ) + GameMode_AddScoreboardColumnData( FORT_WAR, "#SCOREBOARD_COOP_POINTS", PGS_ASSAULT_SCORE, 6 ) + + AddPrivateMatchMode( FORT_WAR ) + + #if SERVER + GameMode_AddServerInit( FORT_WAR, GamemodeFW_Init ) + GameMode_SetPilotSpawnpointsRatingFunc( FORT_WAR, RateSpawnpoints_FW ) + GameMode_SetTitanSpawnpointsRatingFunc( FORT_WAR, RateSpawnpoints_FW ) + #elseif CLIENT + GameMode_AddClientInit( FORT_WAR, CLGamemodeFW_Init ) + #endif + #if !UI + GameMode_AddSharedInit( FORT_WAR, SHGamemodeFW_Init ) + #endif } void function FWOnRegisteringNetworkVars() diff --git a/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut b/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut index ad433ae2..9aa86a43 100644 --- a/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut @@ -41,6 +41,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. +// fort war needs these +global function Rodeo_TakeBatteryAwayFromPilot + #if DEV global function SetDebugRodeoPrint global function GetDebugRodeoPrint diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut index f2776bda..542db4d5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut @@ -9,6 +9,9 @@ global struct HarvesterStruct { entity rings float lastDamage bool shieldBoost + bool harvesterShieldDown + float harvesterDamageTaken + bool havesterWasDamaged } 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/rodeo/_rodeo_titan.gnut b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut index 9f05a0cd..78cfdb27 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/rodeo/_rodeo_titan.gnut @@ -41,6 +41,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 @@ -336,7 +339,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 ) @@ -1853,7 +1856,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 } @@ -1878,7 +1881,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_powerup.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut index 75002e81..c390b5f5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_powerup.gnut @@ -79,7 +79,9 @@ bool function LTSShouldSpawnPowerUp() if ( HasIronRules() ) return false - return ( GAMETYPE == LAST_TITAN_STANDING || GAMETYPE == LTS_BOMB ) + // 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() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut index c9d986bc..349f9131 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut @@ -20,7 +20,7 @@ global function req global function ReplacementTitan global function TryAnnounceTitanfallWarningToEnemyTeam global function GetTitanForPlayer - +global function TryPlayTitanfallNegativeSoundToPlayer global function ShouldSetTitanRespawnTimer @@ -33,6 +33,7 @@ global function SetReplacementTitanGamemodeRules global function SetRequestTitanGamemodeRules global function CreateTitanForPlayerAndHotdrop +global function SetRequestTitanAllowedCallback struct { array ETATimeThresholds = [ 120, 60, 30, 15 ] @@ -53,6 +54,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 +90,10 @@ function ReplacementTitans_Init() FlagInit( "LevelHasRoof" ) } +void function SetRequestTitanAllowedCallback( bool functionref( entity player, array args ) RequestTitanAllowedCallback ) +{ + file.RequestTitanAllowedCallback = RequestTitanAllowedCallback +} void function ReplacementTitan_InitPlayer( entity player ) { @@ -424,6 +431,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,10 +532,39 @@ function req() bool function ClientCommand_RequestTitan( entity player, array args ) { + if( file.RequestTitanAllowedCallback != null && !file.RequestTitanAllowedCallback( player, args ) ) + return true + ReplacementTitan( player ) //Separate function because other functions will call ReplacementTitan return true } +bool function TryPlayTitanfallNegativeSoundToPlayer( entity player ) +{ + if( !( "lastNegativeSound" in player.s ) ) + player.s.lastNegativeSound <- 0.0 // float + if( player.s.lastNegativeSound + 3.0 > Time() ) // in sound cooldown + return false + + EmitSoundOnEntityOnlyToPlayer( player, player, "titan_dryfire" ) + player.s.lastNegativeSound = Time() + + return true +} + +/* // serverSideRUI can't handle localized strings +void function CreateCustomMessageForRefusingTitanfall( entity player ) +{ + if( !( "lastMessageSend" in player.s ) ) + player.s.lastMessageSend <- 0.0 // float + if( player.s.lastMessageSend + 10 > Time() ) // in message cooldown + return + + NSSendInfoMessageToPlayer( player, "#FW_OBJECTIVE_TITANFALL" ) + player.s.lastMessageSend = Time() +} +*/ + // This a baseline titan request function; the only things that prevent this from happening are // common cases; wrong gamestate, already has a titan, is currently dead, etc... bool function RequestTitan( entity player ) @@ -877,6 +914,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 ) -- cgit v1.2.3 From ffac4617f33d3a2f595276e7d393e0957d68ae06 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Fri, 6 Jan 2023 23:22:19 +0100 Subject: [FW]: Add missing callback for milita harvester (#561) Add missing callback --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index dd2b3200..48163b97 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -1710,6 +1710,7 @@ void function FW_createHarvester() fw_harvesterMlt.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) fw_harvesterMlt.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) AddEntityCallback_OnDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged ) + AddEntityCallback_OnPostDamaged( fw_harvesterMlt.harvester, OnHarvesterPostDamaged ) // mlt havester settings // don't set this, or sonar pulse will try to find it and failed to set highlight @@ -2266,4 +2267,4 @@ string function GetTeamAliveTurretCount_ReturnString( int team ) ///////////////////////////////////// ///// BatteryPort Functions End ///// -///////////////////////////////////// \ No newline at end of file +///////////////////////////////////// -- cgit v1.2.3 From 26e49bdf49689f64453a398a3a76f7e44946e20c Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Sun, 8 Jan 2023 02:40:10 +0100 Subject: Fix server chat messages being send twice when watching a replay (#555) * fixes chat messages being send twice * OCD is a real issue --- .../mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 811874c5..277ed030 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -22,6 +22,10 @@ struct { } NsCustomCallbacksClient void function OnReceivedMessage(ClClient_MessageStruct localMessage) { + + if ( IsWatchingReplay() ) + return + if (localMessage.player != null) { foreach (callbackFunc in NsCustomCallbacksClient.OnReceivedSayTextMessageCallbacks) -- cgit v1.2.3 From 3b2049a933b0831e65283b89c0ecca865ebe985c Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 13 Jan 2023 15:30:00 +0100 Subject: Set FW specific convar values via cfg file (#569) Squirrel scripts set the value too late, so they do not get updated until after map rotation. Requires https://github.com/R2Northstar/NorthstarLauncher/pull/398 on launcher Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> --- Northstar.Custom/mod/cfg/server/cleanup_gamemode_fw.cfg | 3 +++ Northstar.Custom/mod/cfg/server/setup_gamemode_fw.cfg | 4 ++++ Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut | 4 ---- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 Northstar.Custom/mod/cfg/server/cleanup_gamemode_fw.cfg create mode 100644 Northstar.Custom/mod/cfg/server/setup_gamemode_fw.cfg diff --git a/Northstar.Custom/mod/cfg/server/cleanup_gamemode_fw.cfg b/Northstar.Custom/mod/cfg/server/cleanup_gamemode_fw.cfg new file mode 100644 index 00000000..6961e56b --- /dev/null +++ b/Northstar.Custom/mod/cfg/server/cleanup_gamemode_fw.cfg @@ -0,0 +1,3 @@ +// reset cvars that fortwar set +cvar_reset sv_max_props_multiplayer +cvar_reset sv_max_prop_data_dwords_multiplayer diff --git a/Northstar.Custom/mod/cfg/server/setup_gamemode_fw.cfg b/Northstar.Custom/mod/cfg/server/setup_gamemode_fw.cfg new file mode 100644 index 00000000..e98ebb1a --- /dev/null +++ b/Northstar.Custom/mod/cfg/server/setup_gamemode_fw.cfg @@ -0,0 +1,4 @@ +// setup engine for fortwar +// this has to run before server initialisation, so it can't be in gamemode script +sv_max_props_multiplayer 1250000 +sv_max_prop_data_dwords_multiplayer 2500000 diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 48163b97..89ca0636 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -131,10 +131,6 @@ void function GamemodeFW_Init() ScoreEvent_SetupEarnMeterValuesForMixedModes() SetRecalculateTitanReplacementPointCallback(FW_ReCalculateTitanReplacementPoint) SetRequestTitanAllowedCallback(FW_RequestTitanAllowed) - - // so many things in battle, this is required to avoid crash! - ServerCommand( "sv_max_props_multiplayer 200000" ) - ServerCommand( "sv_max_prop_data_dwords_multiplayer 300000" ) } -- cgit v1.2.3 From 9bbe6832460aaabd96fef18d6e4ebb05779bb71d Mon Sep 17 00:00:00 2001 From: Maya <11448698+RoyalBlue1@users.noreply.github.com> Date: Fri, 13 Jan 2023 17:20:12 +0100 Subject: Fortwar fixes from #564 with my requested changes (#571) * Initial commit * add playlistvar "fw_harvester_regen_time" * adding friendly highlights * Scale Damage before shield Health but let other damage callbacks run * Make Gamemode 8v8 again * Fix NotifyEnterEnemyArea Callback Co-authored-by: DBmaoha <56738369+DBmaoha@users.noreply.github.com> --- Northstar.Custom/mod.json | 12 +- .../mod/resource/northstar_custom_english.txt | Bin 5110 -> 6318 bytes .../scripts/vscripts/gamemodes/_gamemode_fw.nut | 301 ++++++++++++++------- .../vscripts/gamemodes/cl_gamemode_fw_custom.nut | 13 + .../vscripts/gamemodes/sh_gamemode_fw_custom.nut | 10 +- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 15 +- .../vscripts/titan/_replacement_titans.gnut | 27 -- 7 files changed, 239 insertions(+), 139 deletions(-) create mode 100644 Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_fw_custom.nut diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 1952f72a..e81b197f 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -95,6 +95,10 @@ "Path": "gamemodes/_gamemode_sns.gnut", "RunOn": "SERVER && MP" }, + { + "Path": "gamemodes/_gamemode_fw.nut", + "RunOn": "SERVER && MP" + }, { "Path": "gamemodes/sh_gamemode_fw_custom.nut", "RunOn": "( CLIENT || SERVER ) && MP", @@ -109,6 +113,10 @@ "Path": "gamemodes/sh_gamemode_fw.nut", "RunOn": "( CLIENT || SERVER ) && MP" }, + { + "Path": "gamemodes/cl_gamemode_fw_custom.nut", + "RunOn": "CLIENT && MP" + }, { "Path": "gamemodes/cl_gamemode_fw.nut", "RunOn": "CLIENT && MP" @@ -418,10 +426,6 @@ "Before": "MessageUtils_ServerInit" } }, - { - "Path": "gamemodes/_gamemode_fw.nut", - "RunOn": "SERVER && MP" - }, { "Path": "sh_northstar_http_requests.gnut", "RunOn": "CLIENT || SERVER || UI" diff --git a/Northstar.Custom/mod/resource/northstar_custom_english.txt b/Northstar.Custom/mod/resource/northstar_custom_english.txt index 794aa664..04a8d009 100644 Binary files a/Northstar.Custom/mod/resource/northstar_custom_english.txt and b/Northstar.Custom/mod/resource/northstar_custom_english.txt differ diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 89ca0636..7a5b0ee5 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -1,6 +1,10 @@ untyped global function GamemodeFW_Init -global function RateSpawnpoints_FW + +// spawn points +global function RateSpawnpointsPilot_FW +global function RateSpawnpointsTitan_FW +//global function RateSpawnpoints_FW // for battery_port.gnut to work global function FW_ReplaceMegaTurret @@ -96,7 +100,8 @@ struct // this is for saving territory's connecting time, try not to make faction dialogues play together table< int, float > teamTerrLastConnectTime // team, time - + + // unused array etitaninmlt array etitaninimc @@ -120,17 +125,18 @@ void function GamemodeFW_Init() AddCallback_GameStateEnter( eGameState.Playing, OnFWGamePlaying ) AddSpawnCallback( "item_powerup", FWAddPowerUpIcon ) - // check spawn point, WIP - AddSpawnCallback( "npc_titan", FWForcedTitanSpawnPoint ) + AddSpawnCallback( "npc_turret_mega", FWTurretHighlight ) AddCallback_OnClientConnected( OnFWPlayerConnected ) + AddCallback_PlayerClassChanged( OnFWPlayerClassChanged ) AddCallback_OnPlayerKilled( OnFWPlayerKilled ) AddCallback_OnPilotBecomesTitan( OnFWPilotBecomesTitan ) AddCallback_OnTitanBecomesPilot( OnFWTitanBecomesPilot ) ScoreEvent_SetupEarnMeterValuesForMixedModes() - SetRecalculateTitanReplacementPointCallback(FW_ReCalculateTitanReplacementPoint) - SetRequestTitanAllowedCallback(FW_RequestTitanAllowed) + SetRecalculateRespawnAsTitanStartPointCallback( FW_ForcedTitanStartPoint ) + SetRecalculateTitanReplacementPointCallback( FW_ReCalculateTitanReplacementPoint ) + SetRequestTitanAllowedCallback( FW_RequestTitanAllowed ) } @@ -222,16 +228,25 @@ void function HACK_ForceDestroyNPCs_Threaded() ///// SPAWNPOINT FUNCTIONS ///// //////////////////////////////// -void function RateSpawnpoints_FW( int checkClass, array spawnpoints, int team, entity player ) +void function RateSpawnpointsPilot_FW( int checkClass, array spawnpoints, int team, entity player ) +{ + array startSpawns = SpawnPoints_GetPilotStart( team ) + RateSpawnpoints_FW( startSpawns, checkClass, spawnpoints, team, player ) +} + +void function RateSpawnpointsTitan_FW( int checkClass, array spawnpoints, int team, entity player ) +{ + array startSpawns = SpawnPoints_GetTitanStart( team ) + RateSpawnpoints_FW( startSpawns, checkClass, spawnpoints, team, player ) +} + +void function RateSpawnpoints_FW( array startSpawns, int checkClass, array spawnpoints, int team, entity player ) { if ( HasSwitchedSides() ) team = GetOtherTeam( team ) - // check hardpoints, determine which ones we own - array startSpawns = SpawnPoints_GetPilotStart( team ) - vector averageFriendlySpawns - // average out startspawn positions + vector averageFriendlySpawns foreach ( entity spawnpoint in startSpawns ) averageFriendlySpawns += spawnpoint.GetOrigin() @@ -295,6 +310,12 @@ void function OnFWPlayerConnected( entity player ) InitFWPlayers( player ) } +void function OnFWPlayerClassChanged( entity player ) +{ + // give player a friendly highlight + Highlight_SetFriendlyHighlight( player, "fw_friendly" ) +} + void function OnFWPlayerKilled( entity victim, entity attacker, var damageInfo ) { HandleFWPlayerKilledScoreEvent( victim, attacker ) @@ -562,6 +583,7 @@ void function LoadEntities() entity turret = CreateNPC( "npc_turret_mega", TEAM_UNASSIGNED, info_target.GetOrigin(), info_target.GetAngles() ) SetSpawnOption_AISettings( turret, "npc_turret_mega_fortwar" ) SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work + Highlight_SetFriendlyHighlight( turret, "fw_friendly" ) AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) DispatchSpawn( turret ) @@ -1144,16 +1166,19 @@ bool function FW_IsPlayerInEnemyTerritory( entity player ) //////////////////////////////// // territory trigger don't have a kv.radius, let's use a const -// 1800 will pretty much get harvester's near titan startpoints -const float FW_SPAWNPOINT_SEARCH_RADIUS = 1800.0 +// 2800 will pretty much get harvester's near titan startpoints +const float FW_SPAWNPOINT_SEARCH_RADIUS = 2800.0 -Point function FW_ReCalculateTitanReplacementPoint( Point basePoint, entity player) +Point function FW_ReCalculateTitanReplacementPoint( Point basePoint, entity player ) { int team = player.GetTeam() // find team's harvester entity teamHarvester = FW_GetTeamHarvesterProp( team ) + if ( !IsValid( teamHarvester ) ) // team's havester has been destroyed! + return basePoint // return given value + if( Distance2D( basePoint.origin, teamHarvester.GetOrigin() ) <= FW_SPAWNPOINT_SEARCH_RADIUS ) // close enough! return basePoint // this origin is good enough @@ -1171,13 +1196,26 @@ bool function FW_RequestTitanAllowed( entity player, array< string > args ) PlayFactionDialogueToPlayer( "tw_territoryNag", player ) // notify player TryPlayTitanfallNegativeSoundToPlayer( player ) int objectiveID = 101 // which means "#FW_OBJECTIVE_TITANFALL" - //CreateCustomMessageForRefusingTitanfall( player ) Remote_CallFunction_NonReplay( player, "ServerCallback_FW_SetObjective", objectiveID ) return false } return true } +bool function TryPlayTitanfallNegativeSoundToPlayer( entity player ) +{ + if( !( "lastNegativeSound" in player.s ) ) + player.s.lastNegativeSound <- 0.0 // float + if( player.s.lastNegativeSound + 1.0 > Time() ) // in sound cooldown + return false + + // use a sound to notify player they can't titanfall here + EmitSoundOnEntityOnlyToPlayer( player, player, "titan_dryfire" ) + player.s.lastNegativeSound = Time() + + return true +} + array function FW_GetTitanSpawnPointsForTeam( int team ) { array validSpawnPoints @@ -1200,10 +1238,13 @@ array function FW_GetTitanSpawnPointsForTeam( int team ) return validSpawnPoints } -// WORKING IN PROGRESS -void function FWForcedTitanSpawnPoint( entity titan ) +// "Respawn as Titan" don't follow the rateSpawnPoints, fix it manually +entity function FW_ForcedTitanStartPoint( entity player, entity basePoint ) { - + int team = player.GetTeam() + array startPoints = SpawnPoints_GetTitanStart( team ) + entity validPoint = startPoints[ RandomInt( startPoints.len() ) ] // choose a random( maybe not safe ) start point + return validPoint } //////////////////////////////////// @@ -1343,6 +1384,21 @@ void function FWAreaThreatLevelThink_Threaded() ///// TURRET FUNCTIONS ///// //////////////////////////// +void function FWTurretHighlight( entity turret ) +{ + thread FWTurretHighlightThink( turret ) +} + +// this will clear turret's highlight upon their death, for notifying players to fix them +void function FWTurretHighlightThink( entity turret ) +{ + turret.EndSignal( "OnDestroy" ) + Highlight_SetFriendlyHighlight( turret, "fw_friendly" ) + + turret.WaitSignal( "OnDeath" ) + Highlight_ClearFriendlyHighlight( turret ) +} + // for battery_port, replace the turret with new one entity function FW_ReplaceMegaTurret( entity perviousTurret ) { @@ -1673,7 +1729,7 @@ entity function FW_GetTeamHarvesterProp( int team ) void function FW_createHarvester() { - // mlt havester spawn + // imc havester spawn fw_harvesterImc = SpawnHarvester( file.harvesterImc_info.GetOrigin(), file.harvesterImc_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_IMC ) fw_harvesterImc.harvester.Minimap_SetAlignUpright( true ) fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) @@ -1683,6 +1739,7 @@ void function FW_createHarvester() fw_harvesterImc.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) AddEntityCallback_OnDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged ) AddEntityCallback_OnPostDamaged( fw_harvesterImc.harvester, OnHarvesterPostDamaged ) + // imc havester settings // don't set this, or sonar pulse will try to find it and failed to set highlight //fw_harvesterMlt.harvester.SetScriptName("fw_team_tower") @@ -1721,6 +1778,8 @@ void function FW_createHarvester() GameRules_SetTeamScore( TEAM_IMC , 100 ) GameRules_SetTeamScore2( TEAM_IMC , 100 ) } + +// this function can't handle specific damageSourceID, such as plasma railgun, but is the best to scale both shield and health damage void function OnHarvesterDamaged( entity harvester, var damageInfo ) { if ( !IsValid( harvester ) ) @@ -1728,7 +1787,8 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo ) int friendlyTeam = harvester.GetTeam() int enemyTeam = GetOtherTeam( friendlyTeam ) - + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + HarvesterStruct harvesterstruct // current harveter's struct if( friendlyTeam == TEAM_MILITIA ) harvesterstruct = fw_harvesterMlt @@ -1748,53 +1808,45 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo ) // always reset harvester's recharge delay harvesterstruct.lastDamage = Time() -} -void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) -{ - if ( !IsValid( harvester ) ) - return - - int friendlyTeam = harvester.GetTeam() - int enemyTeam = GetOtherTeam( friendlyTeam ) - - GameRules_SetTeamScore( friendlyTeam , 1.0 * GetHealthFrac( harvester ) * 100 ) - - int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) - entity attacker = DamageInfo_GetAttacker( damageInfo ) - float damageAmount = DamageInfo_GetDamage( damageInfo ) - if(damageAmount == 0) - return - printt("Harvester damage", damageAmount,attacker, damageSourceID) - if ( !damageSourceID && !damageAmount && !attacker ) // actually not dealing any damage? - return + // done damage adjustments here, since harvester prop's health is setting manually through damageAmount if ( damageSourceID == eDamageSourceId.mp_titancore_laser_cannon ) DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 50 ) // laser core shreds super well for some reason - // plasma railgun can always do no-charge shots and deal same damage - if ( damageSourceID == eDamageSourceId.mp_titanweapon_sniper ) // nerf northstar + // plasma railgun can always do no-charge shots and deal same damage + if ( damageSourceID == eDamageSourceId.mp_titanweapon_sniper ) // nerf northstar + { DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + if( IsValid( inflictor ) && inflictor.IsProjectile() ) + { + inflictor.s.extraDamagePerBullet = expect int( inflictor.s.extraDamagePerBullet ) / 3 + } + } - // leadwall have high pilot damage so works really well aginst harvester - if ( damageSourceID == eDamageSourceId.mp_titanweapon_leadwall ) // nerf ronin - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) + // leadwall have high pilot damage so works really well aginst harvester + if ( damageSourceID == eDamageSourceId.mp_titanweapon_leadwall ) // nerf ronin + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) - // missiles mostly have high pilot damage so works really well aginst harvester + // missiles mostly have high pilot damage so works really well aginst harvester if ( damageSourceID == eDamageSourceId.mp_titanweapon_salvo_rockets || damageSourceID == eDamageSourceId.mp_titanweapon_shoulder_rockets || - damageSourceID == eDamageSourceId.mp_titancore_salvo_core + damageSourceID == eDamageSourceId.mp_titancore_salvo_core ) // titan missiles DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) - if ( damageSourceID == eDamageSourceId.mp_titanweapon_flightcore_rockets ) // flight core shreds well - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) + if ( damageSourceID == eDamageSourceId.mp_titanweapon_sticky_40mm ) // 40mm trakcer cannon + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) + + if ( damageSourceID == eDamageSourceId.mp_titanweapon_flightcore_rockets ) // flight core shreds well + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) - // cluster missle is very effective against non-moving targets - if ( damageSourceID == eDamageSourceId.mp_titanweapon_dumbfire_rockets ) // cluster missile shreds super well - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 10 ) + // cluster missle is very effective against non-moving targets + if ( damageSourceID == eDamageSourceId.mp_titanweapon_dumbfire_rockets ) // cluster missile shreds super well + DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 10 ) - // scorch's thermites is very effective against non-moving targets + // scorch's thermites is very effective against non-moving targets if ( damageSourceID == eDamageSourceId.mp_titanweapon_heat_shield || damageSourceID == eDamageSourceId.mp_titanweapon_meteor_thermite || damageSourceID == eDamageSourceId.mp_titanweapon_flame_wall || @@ -1803,12 +1855,44 @@ void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) ) // scorch's thermite damages, nerf scorch DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) +} +void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) +{ + if ( !IsValid( harvester ) ) + return + + int friendlyTeam = harvester.GetTeam() + int enemyTeam = GetOtherTeam( friendlyTeam ) + + GameRules_SetTeamScore( friendlyTeam , 1.0 * GetHealthFrac( harvester ) * 100 ) + + int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + entity attacker = DamageInfo_GetAttacker( damageInfo ) + int scriptType = DamageInfo_GetCustomDamageType( damageInfo ) + float damageAmount = DamageInfo_GetDamage( damageInfo ) + + if(damageAmount == 0) + return + + if ( !damageSourceID && !damageAmount && !attacker ) // actually not dealing any damage? + return + + // prevent player from sniping the harvester cross-map + if ( attacker.IsPlayer() && !FW_IsPlayerInEnemyTerritory( attacker ) ) + { + Remote_CallFunction_NonReplay( attacker , "ServerCallback_FW_NotifyNeedsEnterEnemyArea" ) + DamageInfo_SetDamage( damageInfo, 0 ) + DamageInfo_SetCustomDamageType( damageInfo, scriptType | DF_NO_INDICATOR ) // hide the hitmarker + return // these damage won't do anything to the harvester + } + HarvesterStruct harvesterstruct // current harveter's struct if( friendlyTeam == TEAM_MILITIA ) harvesterstruct = fw_harvesterMlt if( friendlyTeam == TEAM_IMC ) harvesterstruct = fw_harvesterImc + damageAmount = DamageInfo_GetDamage( damageInfo ) // get damageAmount again after all damage adjustments if ( !attacker.IsTitan() ) @@ -1819,12 +1903,18 @@ void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) damageAmount = 0 // never damage haveter's prop } + if( !harvesterstruct.harvesterShieldDown ) + { + PlayFactionDialogueToTeam( "fortwar_baseShieldDownFriendly", friendlyTeam ) + PlayFactionDialogueToTeam( "fortwar_baseShieldDownEnemy", enemyTeam ) + harvesterstruct.harvesterShieldDown = true // prevent shield dialogues from repeating + } + harvesterstruct.harvesterDamageTaken = harvesterstruct.harvesterDamageTaken + damageAmount // track damage for wave recaps float newHealth = harvester.GetHealth() - damageAmount float oldhealthpercent = ( ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth() ) * 100 ) - float healthpercent = ( ( newHealth / harvester.GetMaxHealth() ) * 100 ) - + if (healthpercent <= 75 && oldhealthpercent > 75) // we don't want the dialogue to keep saying "Harvester is below 75% health" everytime they take additional damage { PlayFactionDialogueToTeam( "fortwar_baseDmgFriendly75", friendlyTeam ) @@ -1854,48 +1944,48 @@ void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) harvester.SetHealth( newHealth ) harvesterstruct.havesterWasDamaged = true - if ( attacker.IsPlayer() ) { - // dialogue for enemy attackers - if( !harvesterstruct.harvesterShieldDown ) - PlayFactionDialogueToTeam( "fortwar_baseEnemyAllyAttacking", enemyTeam ) + // dialogue for enemy attackers + if( !harvesterstruct.harvesterShieldDown ) + PlayFactionDialogueToTeam( "fortwar_baseEnemyAllyAttacking", enemyTeam ) attacker.NotifyDidDamage( harvester, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamagePosition( damageInfo ), DamageInfo_GetCustomDamageType( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageFlags( damageInfo ), DamageInfo_GetHitGroup( damageInfo ), DamageInfo_GetWeapon( damageInfo ), DamageInfo_GetDistFromAttackOrigin( damageInfo ) ) - // get newest damage for adding score! - int scoreDamage = int( DamageInfo_GetDamage( damageInfo ) ) - // score events - attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, scoreDamage ) - - // add to player structs - file.playerDamageHarvester[ attacker ].recentDamageTime = Time() - file.playerDamageHarvester[ attacker ].storedDamage += scoreDamage - - // enough to earn score? - if( file.playerDamageHarvester[ attacker ].storedDamage >= FW_HARVESTER_DAMAGE_SEGMENT ) - { - AddPlayerScore( attacker, "FortWarTowerDamage", attacker ) - attacker.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_FW_TOWER_DAMAGE ) - file.playerDamageHarvester[ attacker ].storedDamage -= FW_HARVESTER_DAMAGE_SEGMENT // reset stored damage - } + // get newest damage for adding score! + int scoreDamage = int( DamageInfo_GetDamage( damageInfo ) ) + // score events + attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, scoreDamage ) + + // add to player structs + file.playerDamageHarvester[ attacker ].recentDamageTime = Time() + file.playerDamageHarvester[ attacker ].storedDamage += scoreDamage + + // enough to earn score? + if( file.playerDamageHarvester[ attacker ].storedDamage >= FW_HARVESTER_DAMAGE_SEGMENT ) + { + AddPlayerScore( attacker, "FortWarTowerDamage", attacker ) + attacker.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_FW_TOWER_DAMAGE ) + file.playerDamageHarvester[ attacker ].storedDamage -= FW_HARVESTER_DAMAGE_SEGMENT // reset stored damage + } } - - if ( harvester.GetHealth() == 0 ) - { - SetWinner( enemyTeam ) - //PlayFactionDialogueToTeam( "scoring_wonMercy", enemyTeam ) - //PlayFactionDialogueToTeam( "fortwar_matchLoss", friendlyTeam ) - GameRules_SetTeamScore2( friendlyTeam, 0 ) // force set score2 to 0( shield bar will empty ) - GameRules_SetTeamScore( friendlyTeam, 0 ) // force set score to 0( health 0% ) - } + // harvester down! + if ( harvester.GetHealth() == 0 ) + { + // force deciding winner + SetWinner( enemyTeam ) + //PlayFactionDialogueToTeam( "scoring_wonMercy", enemyTeam ) + //PlayFactionDialogueToTeam( "fortwar_matchLoss", friendlyTeam ) + GameRules_SetTeamScore2( friendlyTeam, 0 ) // force set score2 to 0( shield bar will empty ) + GameRules_SetTeamScore( friendlyTeam, 0 ) // force set score to 0( health 0% ) + } } -void function HarvesterThink( HarvesterStruct fd_harvester ) +void function HarvesterThink( HarvesterStruct fw_harvester ) { - entity harvester = fd_harvester.harvester + entity harvester = fw_harvester.harvester EmitSoundOnEntity( harvester, "coop_generator_startup" ) @@ -1903,8 +1993,8 @@ void function HarvesterThink( HarvesterStruct fd_harvester ) float lastTime = Time() wait 4 int lastShieldHealth = harvester.GetShieldHealth() - generateBeamFX( fd_harvester ) - generateShieldFX( fd_harvester ) + generateBeamFX( fw_harvester ) + generateShieldFX( fw_harvester ) EmitSoundOnEntity( harvester, "coop_generator_ambient_healthy" ) @@ -1915,26 +2005,26 @@ void function HarvesterThink( HarvesterStruct fd_harvester ) float currentTime = Time() float deltaTime = currentTime -lastTime - if ( IsValid( fd_harvester.particleShield ) ) + if ( IsValid( fw_harvester.particleShield ) ) { vector shieldColor = GetShieldTriLerpColor( 1.0 - ( harvester.GetShieldHealth().tofloat() / harvester.GetShieldHealthMax().tofloat() ) ) - EffectSetControlPointVector( fd_harvester.particleShield, 1, shieldColor ) + EffectSetControlPointVector( fw_harvester.particleShield, 1, shieldColor ) } - if( IsValid( fd_harvester.particleBeam ) ) + if( IsValid( fw_harvester.particleBeam ) ) { vector beamColor = GetShieldTriLerpColor( 1.0 - ( harvester.GetHealth().tofloat() / harvester.GetMaxHealth().tofloat() ) ) - EffectSetControlPointVector( fd_harvester.particleBeam, 1, beamColor ) + EffectSetControlPointVector( fw_harvester.particleBeam, 1, beamColor ) } - if ( fd_harvester.harvester.GetShieldHealth() == 0 ) - if( IsValid( fd_harvester.particleShield ) ) - fd_harvester.particleShield.Destroy() + if ( fw_harvester.harvester.GetShieldHealth() == 0 ) + if( IsValid( fw_harvester.particleShield ) ) + fw_harvester.particleShield.Destroy() - if ( ( ( currentTime-fd_harvester.lastDamage ) >= GENERATOR_SHIELD_REGEN_DELAY ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + if ( ( ( currentTime-fw_harvester.lastDamage ) >= GetCurrentPlaylistVarFloat( "fw_harvester_regen_delay", FW_DEFAULT_HARVESTER_REGEN_DELAY ) ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) { - if( !IsValid( fd_harvester.particleShield ) ) - generateShieldFX( fd_harvester ) + if( !IsValid( fw_harvester.particleShield ) ) + generateShieldFX( fw_harvester ) if( harvester.GetShieldHealth() == 0 ) EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_start" ) @@ -1942,15 +2032,16 @@ void function HarvesterThink( HarvesterStruct fd_harvester ) if (!isRegening) { EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_resume" ) - fd_harvester.harvesterShieldDown = false + fw_harvester.harvesterShieldDown = false isRegening = true } - float newShieldHealth = ( harvester.GetShieldHealthMax() / GENERATOR_SHIELD_REGEN_TIME * deltaTime ) + harvester.GetShieldHealth() + float newShieldHealth = ( harvester.GetShieldHealthMax() / GetCurrentPlaylistVarFloat( "fw_harvester_regen_time", FW_DEFAULT_HARVESTER_REGEN_TIME ) * deltaTime ) + harvester.GetShieldHealth() + // shield full if ( newShieldHealth >= harvester.GetShieldHealthMax() ) { - StopSoundOnEntity( harvester, "coop_generator_shieldrecharge_resume" ) + StopSoundOnEntity( harvester, "coop_generator_shieldrecharge_resume" ) harvester.SetShieldHealth( harvester.GetShieldHealthMax() ) EmitSoundOnEntity( harvester, "coop_generator_shieldrecharge_end" ) PlayFactionDialogueToTeam( "fortwar_baseShieldUpFriendly", harvester.GetTeam() ) @@ -1961,7 +2052,7 @@ void function HarvesterThink( HarvesterStruct fd_harvester ) harvester.SetShieldHealth( newShieldHealth ) } } - else if ( ( ( currentTime-fd_harvester.lastDamage ) < GENERATOR_SHIELD_REGEN_DELAY ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) + else if ( ( ( currentTime-fw_harvester.lastDamage ) < GENERATOR_SHIELD_REGEN_DELAY ) && ( harvester.GetShieldHealth() < harvester.GetShieldHealthMax() ) ) { isRegening = false } @@ -1978,13 +2069,13 @@ void function HarvesterThink( HarvesterStruct fd_harvester ) } } -void function HarvesterAlarm( HarvesterStruct fd_harvester ) +void function HarvesterAlarm( HarvesterStruct fw_harvester ) { - while( IsAlive( fd_harvester.harvester ) ) + while( IsAlive( fw_harvester.harvester ) ) { - if( fd_harvester.harvester.GetShieldHealth() == 0 ) + if( fw_harvester.harvester.GetShieldHealth() == 0 ) { - wait EmitSoundOnEntity( fd_harvester.harvester, "coop_generator_underattack_alarm" ) + wait EmitSoundOnEntity( fw_harvester.harvester, "coop_generator_underattack_alarm" ) } else { diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_fw_custom.nut new file mode 100644 index 00000000..68a710e8 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/cl_gamemode_fw_custom.nut @@ -0,0 +1,13 @@ +// cl_gamemode_fw already exists in vanilla game file +// this file is to register more network vars or remote functions +global function ServerCallback_FW_NotifyNeedsEnterEnemyArea + +void function ServerCallback_FW_NotifyNeedsEnterEnemyArea() +{ + AnnouncementData announcement = Announcement_Create( "#FW_ENTER_ENEMY_AREA" ) + Announcement_SetSoundAlias( announcement, "UI_InGame_LevelUp" ) + Announcement_SetSubText( announcement, "#FW_TITAN_REQUIRED_SUB" ) + Announcement_SetPurge( announcement, true ) + Announcement_SetPriority( announcement, 200 ) //Be higher priority than Titanfall ready indicator etc + AnnouncementFromClass( GetLocalViewPlayer(), announcement ) +} diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut index 0cd2fd62..d999bb4c 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut @@ -9,6 +9,8 @@ global function SHCreateGamemodeFW_Init // default havester settings global const int FW_DEFAULT_HARVESTER_HEALTH = 25000 global const int FW_DEFAULT_HARVESTER_SHIELD = 5000 +global const float FW_DEFAULT_HARVESTER_REGEN_DELAY = 12.0 +global const float FW_DEFAULT_HARVESTER_REGEN_TIME = 10.0 // default turret settings global const int FW_DEFAULT_TURRET_HEALTH = 12500 global const int FW_DEFAULT_TURRET_SHIELD = 4000 @@ -25,6 +27,8 @@ void function SHCreateGamemodeFW_Init() // harvester playlistvar AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH.tostring() ) AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_regen_delay", FW_DEFAULT_HARVESTER_REGEN_DELAY.tostring() ) + AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_harvester_regen_time", FW_DEFAULT_HARVESTER_REGEN_TIME.tostring() ) // turret playlistvar AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_health", FW_DEFAULT_TURRET_HEALTH.tostring() ) AddPrivateMatchModeSettingArbitrary( "#PL_fw", "fw_turret_shield", FW_DEFAULT_TURRET_SHIELD.tostring() ) @@ -59,8 +63,8 @@ void function CreateGamemodeFW() #if SERVER GameMode_AddServerInit( FORT_WAR, GamemodeFW_Init ) - GameMode_SetPilotSpawnpointsRatingFunc( FORT_WAR, RateSpawnpoints_FW ) - GameMode_SetTitanSpawnpointsRatingFunc( FORT_WAR, RateSpawnpoints_FW ) + GameMode_SetPilotSpawnpointsRatingFunc( FORT_WAR, RateSpawnpointsPilot_FW ) + GameMode_SetTitanSpawnpointsRatingFunc( FORT_WAR, RateSpawnpointsTitan_FW ) #elseif CLIENT GameMode_AddClientInit( FORT_WAR, CLGamemodeFW_Init ) #endif @@ -74,6 +78,8 @@ void function FWOnRegisteringNetworkVars() if ( GAMETYPE != FORT_WAR ) return + Remote_RegisterFunction( "ServerCallback_FW_NotifyNeedsEnterEnemyArea" ) + RegisterNetworkedVariable( "turretSite1", SNDC_GLOBAL, SNVT_ENTITY ) RegisterNetworkedVariable( "turretSite2", SNDC_GLOBAL, SNVT_ENTITY ) RegisterNetworkedVariable( "turretSite3", SNDC_GLOBAL, SNVT_ENTITY ) 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 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/titan/_replacement_titans.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut index 349f9131..57361362 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan/_replacement_titans.gnut @@ -20,7 +20,6 @@ global function req global function ReplacementTitan global function TryAnnounceTitanfallWarningToEnemyTeam global function GetTitanForPlayer -global function TryPlayTitanfallNegativeSoundToPlayer global function ShouldSetTitanRespawnTimer @@ -539,32 +538,6 @@ bool function ClientCommand_RequestTitan( entity player, array args ) return true } -bool function TryPlayTitanfallNegativeSoundToPlayer( entity player ) -{ - if( !( "lastNegativeSound" in player.s ) ) - player.s.lastNegativeSound <- 0.0 // float - if( player.s.lastNegativeSound + 3.0 > Time() ) // in sound cooldown - return false - - EmitSoundOnEntityOnlyToPlayer( player, player, "titan_dryfire" ) - player.s.lastNegativeSound = Time() - - return true -} - -/* // serverSideRUI can't handle localized strings -void function CreateCustomMessageForRefusingTitanfall( entity player ) -{ - if( !( "lastMessageSend" in player.s ) ) - player.s.lastMessageSend <- 0.0 // float - if( player.s.lastMessageSend + 10 > Time() ) // in message cooldown - return - - NSSendInfoMessageToPlayer( player, "#FW_OBJECTIVE_TITANFALL" ) - player.s.lastMessageSend = Time() -} -*/ - // This a baseline titan request function; the only things that prevent this from happening are // common cases; wrong gamestate, already has a titan, is currently dead, etc... bool function RequestTitan( entity player ) -- cgit v1.2.3 From 9775ffb3b478a921f7d64d8907ab6c2b91128f40 Mon Sep 17 00:00:00 2001 From: zxcPandora <81985226+zxcPandora@users.noreply.github.com> Date: Wed, 25 Jan 2023 00:58:53 +0800 Subject: Add a function to take away all inventory item (#565) --- .../scripts/vscripts/item_inventory/sv_item_inventory.gnut | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 d4ec5879..7d4552a0 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 @@ -8,6 +8,7 @@ global function PlayerInventory_EndCriticalSectionForWeaponOnEndFrame global function PlayerInventory_PushInventoryItem global function PlayerInventory_PushInventoryItemByBurnRef global function PlayerInventory_PopInventoryItem +global function PlayerInventory_TakeAllInventoryItems global function PlayerInventory_CountBurnRef struct @@ -141,6 +142,14 @@ void function PlayerInventory_PopInventoryItem( entity player ) return } +void function PlayerInventory_TakeAllInventoryItems( entity player ) +{ + file.playerInventoryStacks[ player ].clear() + waitthread PlayerInventory_TakeInventoryItem( player ) + player.SetPlayerNetInt( "itemInventoryCount", 0 ) + return +} + void function PlayerInventory_RefreshEquippedState( entity player ) { @@ -154,4 +163,4 @@ void function PlayerInventory_StartCriticalSection( entity player ) void function PlayerInventory_EndCriticalSectionForWeaponOnEndFrame( entity weapon ) { -} \ No newline at end of file +} -- cgit v1.2.3 From 12cf8b98dea6407c031f3117b5c295480c87183a Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 9 Feb 2023 21:50:57 +0000 Subject: Compile check tests in CI (#575) * first test compile * rename job step * compile separately without Northstar.Custom * move to release instead of main branch * create json for compile check native functions * update to use v2 and json file * Add description of compile-check action Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com> --- .github/nativefuncs.json | 644 ++++++++++++++++++++++++++++++++++++ .github/workflows/compile-check.yml | 29 ++ 2 files changed, 673 insertions(+) create mode 100644 .github/nativefuncs.json create mode 100644 .github/workflows/compile-check.yml diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json new file mode 100644 index 00000000..50bba0e5 --- /dev/null +++ b/.github/nativefuncs.json @@ -0,0 +1,644 @@ +{ + "SERVER":[ + { + "name":"NSGetModNames", + "helpText":"", + "returnTypeString":"array", + "argTypes":"" + }, + { + "name":"NSIsModEnabled", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSSetModEnabled", + "helpText":"", + "returnTypeString":"void", + "argTypes":"string modName, bool enabled" + }, + { + "name":"NSGetModDescriptionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModVersionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModDownloadLinkByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModLoadPriority", + "helpText":"", + "returnTypeString":"int", + "argTypes":"string modName" + }, + { + "name":"NSIsModRequiredOnClient", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSGetModConvarsByModName", + "helpText":"", + "returnTypeString":"array", + "argTypes":"string modName" + }, + { + "name":"DecodeJSON", + "helpText":"converts a json string to a squirrel table", + "returnTypeString":"table", + "argTypes":"string json, bool fatalParseErrors = false" + }, + { + "name":"EncodeJSON", + "helpText":"converts a squirrel table to a json string", + "returnTypeString":"string", + "argTypes":"table data" + }, + { + "name":"StringToAsset", + "helpText":"converts a given string to an asset", + "returnTypeString":"asset", + "argTypes":"string assetName" + }, + { + "name":"NSGetLocalPlayerUID", + "helpText":"Returns the local player's uid.", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSEarlyWritePlayerPersistenceForLeave", + "helpText":"", + "returnTypeString":"void", + "argTypes":"entity player" + }, + { + "name":"NSIsWritingPlayerPersistence", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSIsPlayerLocalPlayer", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"entity player" + }, + { + "name":"NSIsDedicated", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSDisconnectPlayer", + "helpText":"Disconnects the player from the server with the given reason", + "returnTypeString":"bool", + "argTypes":"entity player, string reason" + }, + { + "name":"GetUserInfoKVString_Internal", + "helpText":"Gets the string value of a given player's userinfo convar by name", + "returnTypeString":"string", + "argTypes":"entity player, string key, string defaultValue = \"\"" + }, + { + "name":"GetUserInfoKVAsset_Internal", + "helpText":"Gets the asset value of a given player's userinfo convar by name", + "returnTypeString":"asset", + "argTypes":"entity player, string key, asset defaultValue = $\"\"" + }, + { + "name":"GetUserInfoKVInt_Internal", + "helpText":"Gets the int value of a given player's userinfo convar by name", + "returnTypeString":"int", + "argTypes":"entity player, string key, int defaultValue = 0" + }, + { + "name":"GetUserInfoKVFloat_Internal", + "helpText":"Gets the float value of a given player's userinfo convar by name", + "returnTypeString":"float", + "argTypes":"entity player, string key, float defaultValue = 0" + }, + { + "name":"GetUserInfoKVBool_Internal", + "helpText":"Gets the bool value of a given player's userinfo convar by name", + "returnTypeString":"bool", + "argTypes":"entity player, string key, bool defaultValue = false" + }, + { + "name":"NSSendMessage", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int playerIndex, string text, bool isTeam" + }, + { + "name":"NSBroadcastMessage", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int fromPlayerIndex, int toPlayerIndex, string text, bool isTeam, bool isDead, int messageType" + }, + { + "name":"NSGetCurrentModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSGetCallingModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"int depth = 0" + }, + { + "name":"NS_InternalMakeHttpRequest", + "helpText":"[Internal use only] Passes the HttpRequest struct fields to be reconstructed in native and used for an http request", + "returnTypeString":"int", + "argTypes":"int method, string baseUrl, table > headers, table > queryParams, string contentType, string body, int timeout, string userAgent" + }, + { + "name":"NSIsHttpEnabled", + "helpText":"Whether or not HTTP requests are enabled. You can opt-out by starting the game with -disablehttprequests.", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSIsLocalHttpAllowed", + "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", + "returnTypeString":"bool", + "argTypes":"" + } + ], + "CLIENT":[ + { + "name":"NSChatWrite", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int context, string text" + }, + { + "name":"NSChatWriteRaw", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int context, string text" + }, + { + "name":"NSChatWriteLine", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int context, string text" + }, + { + "name":"NSGetModNames", + "helpText":"", + "returnTypeString":"array", + "argTypes":"" + }, + { + "name":"NSIsModEnabled", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSSetModEnabled", + "helpText":"", + "returnTypeString":"void", + "argTypes":"string modName, bool enabled" + }, + { + "name":"NSGetModDescriptionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModVersionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModDownloadLinkByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModLoadPriority", + "helpText":"", + "returnTypeString":"int", + "argTypes":"string modName" + }, + { + "name":"NSIsModRequiredOnClient", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSGetModConvarsByModName", + "helpText":"", + "returnTypeString":"array", + "argTypes":"string modName" + }, + { + "name":"DecodeJSON", + "helpText":"converts a json string to a squirrel table", + "returnTypeString":"table", + "argTypes":"string json, bool fatalParseErrors = false" + }, + { + "name":"EncodeJSON", + "helpText":"converts a squirrel table to a json string", + "returnTypeString":"string", + "argTypes":"table data" + }, + { + "name":"StringToAsset", + "helpText":"converts a given string to an asset", + "returnTypeString":"asset", + "argTypes":"string assetName" + }, + { + "name":"NSGetLocalPlayerUID", + "helpText":"Returns the local player's uid.", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSGetCurrentModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSGetCallingModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"int depth = 0" + }, + { + "name":"NSUpdateGameStateClient", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int playerCount, int maxPlayers, int outScore, int secondHighestScore, int highestScore, bool roundBased, int scoreLimit" + }, + { + "name":"NSUpdateServerInfoReload", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int maxPlayers" + }, + { + "name":"NSUpdateTimeInfo", + "helpText":"", + "returnTypeString":"void", + "argTypes":"float timeInFuture" + }, + { + "name":"NS_InternalMakeHttpRequest", + "helpText":"[Internal use only] Passes the HttpRequest struct fields to be reconstructed in native and used for an http request", + "returnTypeString":"int", + "argTypes":"int method, string baseUrl, table > headers, table > queryParams, string contentType, string body, int timeout, string userAgent" + }, + { + "name":"NSIsHttpEnabled", + "helpText":"Whether or not HTTP requests are enabled. You can opt-out by starting the game with -disablehttprequests.", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSIsLocalHttpAllowed", + "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", + "returnTypeString":"bool", + "argTypes":"" + } + ], + "UI":[ + { + "name":"NSGetCursorPosition", + "helpText":"", + "returnTypeString":"vector ornull", + "argTypes":"" + }, + { + "name":"NSRequestCustomMainMenuPromos", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSHasCustomMainMenuPromoData", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSGetCustomMainMenuPromoData", + "helpText":"", + "returnTypeString":"var", + "argTypes":"int promoDataKey" + }, + { + "name":"NSGetModNames", + "helpText":"", + "returnTypeString":"array", + "argTypes":"" + }, + { + "name":"NSIsModEnabled", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSSetModEnabled", + "helpText":"", + "returnTypeString":"void", + "argTypes":"string modName, bool enabled" + }, + { + "name":"NSGetModDescriptionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModVersionByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModDownloadLinkByModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"string modName" + }, + { + "name":"NSGetModLoadPriority", + "helpText":"", + "returnTypeString":"int", + "argTypes":"string modName" + }, + { + "name":"NSIsModRequiredOnClient", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"string modName" + }, + { + "name":"NSGetModConvarsByModName", + "helpText":"", + "returnTypeString":"array", + "argTypes":"string modName" + }, + { + "name":"NSReloadMods", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSIsMasterServerAuthenticated", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSRequestServerList", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSIsRequestingServerList", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSMasterServerConnectionSuccessful", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSGetServerCount", + "helpText":"", + "returnTypeString":"int", + "argTypes":"" + }, + { + "name":"NSGetServerName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerDescription", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerMap", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerPlaylist", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerPlayerCount", + "helpText":"", + "returnTypeString":"int", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerMaxPlayerCount", + "helpText":"", + "returnTypeString":"int", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerID", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSServerRequiresPassword", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerRequiredModsCount", + "helpText":"", + "returnTypeString":"int", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerRegion", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex" + }, + { + "name":"NSGetServerRequiredModName", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex, int modIndex" + }, + { + "name":"NSGetServerRequiredModVersion", + "helpText":"", + "returnTypeString":"string", + "argTypes":"int serverIndex, int modIndex" + }, + { + "name":"NSClearRecievedServerList", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSTryAuthWithServer", + "helpText":"", + "returnTypeString":"void", + "argTypes":"int serverIndex, string password = ''" + }, + { + "name":"NSIsAuthenticatingWithServer", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSWasAuthSuccessful", + "helpText":"", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSConnectToAuthedServer", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSTryAuthWithLocalServer", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSCompleteAuthWithLocalServer", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NSGetAuthFailReason", + "helpText":"", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"DecodeJSON", + "helpText":"converts a json string to a squirrel table", + "returnTypeString":"table", + "argTypes":"string json, bool fatalParseErrors = false" + }, + { + "name":"EncodeJSON", + "helpText":"converts a squirrel table to a json string", + "returnTypeString":"string", + "argTypes":"table data" + }, + { + "name":"StringToAsset", + "helpText":"converts a given string to an asset", + "returnTypeString":"asset", + "argTypes":"string assetName" + }, + { + "name":"NSGetLocalPlayerUID", + "helpText":"Returns the local player's uid.", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSGetCurrentModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"" + }, + { + "name":"NSGetCallingModName", + "helpText":"Returns the mod name of the script running this function", + "returnTypeString":"string", + "argTypes":"int depth = 0" + }, + { + "name":"NSUpdateGameStateUI", + "helpText":"", + "returnTypeString":"void", + "argTypes":"string gamemode, string gamemodeName, string map, string mapName, bool connected, bool loading" + }, + { + "name":"NSUpdateServerInfo", + "helpText":"", + "returnTypeString":"void", + "argTypes":"string id, string name, string password, int players, int maxPlayers, string map, string mapDisplayName, string playlist, string playlistDisplayName" + }, + { + "name":"NSSetLoading", + "helpText":"", + "returnTypeString":"void", + "argTypes":"bool loading" + }, + { + "name":"NSUpdateListenServer", + "helpText":"", + "returnTypeString":"void", + "argTypes":"" + }, + { + "name":"NS_InternalMakeHttpRequest", + "helpText":"[Internal use only] Passes the HttpRequest struct fields to be reconstructed in native and used for an http request", + "returnTypeString":"int", + "argTypes":"int method, string baseUrl, table > headers, table > queryParams, string contentType, string body, int timeout, string userAgent" + }, + { + "name":"NSIsHttpEnabled", + "helpText":"Whether or not HTTP requests are enabled. You can opt-out by starting the game with -disablehttprequests.", + "returnTypeString":"bool", + "argTypes":"" + }, + { + "name":"NSIsLocalHttpAllowed", + "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", + "returnTypeString":"bool", + "argTypes":"" + } + ] +} \ No newline at end of file diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml new file mode 100644 index 00000000..b62c8313 --- /dev/null +++ b/.github/workflows/compile-check.yml @@ -0,0 +1,29 @@ +# This action checks whether all Squirrel files compile successfully using standalone Squirrel compiler +name: compile-check + +on: [push, pull_request] + +jobs: + compile: + runs-on: windows-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + with: + path: "mods" + + - name: Compile Scripts + uses: ASpoonPlaysGames/squirrel-re-compiler@v2 + with: + mods-directory: "${{ github.workspace }}/mods" + native-json: "${{ github.workspace }}/mods/.github/nativefuncs.json" + + - name: Remove Northstar.Custom + run: rmdir ${{ github.workspace }}\mods\Northstar.Custom /s /q + shell: cmd + + - name: Compile Scripts (No Northstar.Custom) + uses: ASpoonPlaysGames/squirrel-re-compiler@v2 + with: + mods-directory: "${{ github.workspace }}/mods" + native-json: "${{ github.workspace }}/mods/.github/nativefuncs.json" -- cgit v1.2.3 From 554761ab629418048e367c7ba1504acd87b5b6e1 Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Sat, 25 Feb 2023 22:52:08 +0100 Subject: Fix chat messages when dead (#574) * Fix chat messages when dead * Spoons fix was better Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut index 277ed030..db4865ee 100644 --- a/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut +++ b/Northstar.Client/mod/scripts/vscripts/_custom_codecallbacks_client.gnut @@ -23,7 +23,7 @@ struct { void function OnReceivedMessage(ClClient_MessageStruct localMessage) { - if ( IsWatchingReplay() ) + if ( IsWatchingReplay() && localMessage.player == null ) return if (localMessage.player != null) -- cgit v1.2.3 From afea3530d872f6b50fe6be5a04bbe54c1551aa31 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Tue, 28 Feb 2023 05:58:48 +0800 Subject: [FW] Enable Turrets By Default (#587) * turrets are enabled by default, with some formatting * update indentation * add commentaries for turret highlight --- .../scripts/vscripts/gamemodes/_gamemode_fw.nut | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 7a5b0ee5..b025ff0a 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -125,7 +125,7 @@ void function GamemodeFW_Init() AddCallback_GameStateEnter( eGameState.Playing, OnFWGamePlaying ) AddSpawnCallback( "item_powerup", FWAddPowerUpIcon ) - AddSpawnCallback( "npc_turret_mega", FWTurretHighlight ) + AddSpawnCallback( "npc_turret_mega", OnFWTurretSpawned ) AddCallback_OnClientConnected( OnFWPlayerConnected ) AddCallback_PlayerClassChanged( OnFWPlayerClassChanged ) @@ -582,9 +582,6 @@ void function LoadEntities() // create turret, spawn with no team and set it after game starts entity turret = CreateNPC( "npc_turret_mega", TEAM_UNASSIGNED, info_target.GetOrigin(), info_target.GetAngles() ) SetSpawnOption_AISettings( turret, "npc_turret_mega_fortwar" ) - SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work - Highlight_SetFriendlyHighlight( turret, "fw_friendly" ) - AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) DispatchSpawn( turret ) turretsite.turret = turret @@ -1384,19 +1381,23 @@ void function FWAreaThreatLevelThink_Threaded() ///// TURRET FUNCTIONS ///// //////////////////////////// -void function FWTurretHighlight( entity turret ) +void function OnFWTurretSpawned( entity turret ) { - thread FWTurretHighlightThink( turret ) + turret.EnableTurret() // always enabled + SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work + AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) + thread FWTurretHighlightThink( turret ) } // this will clear turret's highlight upon their death, for notifying players to fix them void function FWTurretHighlightThink( entity turret ) { - turret.EndSignal( "OnDestroy" ) - Highlight_SetFriendlyHighlight( turret, "fw_friendly" ) + turret.EndSignal( "OnDestroy" ) + WaitFrame() // wait a frame for other turret spawn options to set up + Highlight_SetFriendlyHighlight( turret, "fw_friendly" ) // initialize the highlight, they will show upon player's next respawn - turret.WaitSignal( "OnDeath" ) - Highlight_ClearFriendlyHighlight( turret ) + turret.WaitSignal( "OnDeath" ) + Highlight_ClearFriendlyHighlight( turret ) } // for battery_port, replace the turret with new one @@ -1407,8 +1408,6 @@ entity function FW_ReplaceMegaTurret( entity perviousTurret ) entity turret = CreateNPC( "npc_turret_mega", perviousTurret.GetTeam(), perviousTurret.GetOrigin(), perviousTurret.GetAngles() ) SetSpawnOption_AISettings( turret, "npc_turret_mega_fortwar" ) - SetDefaultMPEnemyHighlight( turret ) // for sonar highlights to work - AddEntityCallback_OnDamaged( turret, OnMegaTurretDamaged ) DispatchSpawn( turret ) // apply settings to new turret, must up on date -- cgit v1.2.3 From 2e5e740558719f53cd29c979d9f78c0f9e03dbc1 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Thu, 2 Mar 2023 07:59:41 +0800 Subject: Infection Bug Fixes (sonar warning and late joiners) (#454) * General Infection Bug Fixes Last player alive gets a warning that they are visible to all infected * Taken Gecko's suggestion instead. Late joiners before first infected spawn as survivors --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index 35e034cc..fef4c8b6 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -29,7 +29,7 @@ void function GamemodeInfection_Init() void function InfectionInitPlayer( entity player ) { - if ( GetGameState() < eGameState.Playing ) + if ( GetGameState() < eGameState.Playing || !file.hasHadFirstInfection ) // per Gecko's suggestion, make anyone joining before first infected to stay as survivor instead SetTeam( player, INFECTION_TEAM_SURVIVOR ) else InfectPlayer( player ) @@ -185,6 +185,8 @@ void function SetLastSurvivor( entity player ) Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_AnnounceLastSurvivor", player.GetEncodedEHandle() ) Highlight_SetEnemyHighlight( player, "enemy_sonar" ) + StatusEffect_AddEndless( player, eStatusEffect.sonar_detected, 1.0 ) // sonar is better here so the player themselves see the SONAR DETECTED warning. + if ( SpawnPoints_GetTitan().len() > 0 ) thread CreateTitanForPlayerAndHotdrop( player, GetTitanReplacementPoint( player, false ) ) -- cgit v1.2.3 From 85e2c14c5979cf350b488cd42abf9084d4a64bb1 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Fri, 3 Mar 2023 05:24:33 +0800 Subject: Clean Team Score After Player Disconnecting in FFA (#589) * Update _gamemode_ffa.nut * delete the player struct after disconnecting * force struct start from 0 * fix compile error * remove useless structs * Update _gamemode_ffa.nut * Update _gamemode_ffa.nut --- .../mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut index 27eef177..4bff6038 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ffa.nut @@ -6,6 +6,9 @@ void function FFA_Init() ScoreEvent_SetupEarnMeterValuesForMixedModes() AddCallback_OnPlayerKilled( OnPlayerKilled ) + + // modified for northstar + AddCallback_OnClientConnected( OnClientConnected ) } void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) @@ -16,4 +19,18 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) // why isn't this PGS_SCORE? odd game attacker.AddToPlayerGameStat( PGS_ASSAULT_SCORE, 1 ) } +} + +// modified for northstar +void function OnClientConnected( entity player ) +{ + thread FFAPlayerScoreThink( player ) // good to have this! instead of DisconnectCallback this could handle a null player +} + +void function FFAPlayerScoreThink( entity player ) +{ + int team = player.GetTeam() + + player.WaitSignal( "OnDestroy" ) // this can handle disconnecting + AddTeamScore( team, -GameRules_GetTeamScore( team ) ) } \ No newline at end of file -- cgit v1.2.3 From bd99d5a6b1d8de68215df6b503474f93073a02f7 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Fri, 3 Mar 2023 05:33:04 +0800 Subject: Fix GameTime_TimeLeftSeconds() not tracking time correctly (#447) Co-authored-by: EladNLG <44613424+EladNLG@users.noreply.github.com> --- .../mod/scripts/vscripts/_utility.gnut | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut index 3546e3b7..4e5c5aa9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility.gnut @@ -4017,7 +4017,7 @@ int function GameTime_TimeLeftMinutes() if ( GetGameState() == eGameState.Prematch ) return int( ( expect float( GetServerVar( "gameStartTime" ) ) - Time()) / 60.0 ) - return floor( GameTime_TimeLimitMinutes() - GameTime_PlayingTime() / 60 ).tointeger() + return floor( GameTime_PlayingTime() / 60 ).tointeger() } int function GameTime_TimeLeftSeconds() @@ -4025,30 +4025,25 @@ int function GameTime_TimeLeftSeconds() if ( GetGameState() == eGameState.Prematch ) return int( expect float( GetServerVar( "gameStartTime" ) ) - Time() ) - return floor( GameTime_TimeLimitSeconds() - GameTime_PlayingTime() ).tointeger() + return GameTime_PlayingTime().tointeger() } +// WARN: this function includes WaitingForPlayers and Prematch duration! int function GameTime_Seconds() { return floor( Time() ).tointeger() } +// WARN: this function includes WaitingForPlayers Prematch duration! int function GameTime_Minutes() { return int( floor( GameTime_Seconds() / 60 ) ) } +// this function only counts the time limit during eGameState.Playing float function GameTime_PlayingTime() -{ - return GameTime_PlayingTimeSince( Time() ) -} - -float function GameTime_PlayingTimeSince( float sinceTime ) { int gameState = GetGameState() - - // temp fix because i have no fucking clue why this crashes - if ( gameState < eGameState.Playing ) return 0 @@ -4057,17 +4052,15 @@ float function GameTime_PlayingTimeSince( float sinceTime ) if ( gameState > eGameState.SuddenDeath ) return (expect float( GetServerVar( "roundEndTime" ) ) - expect float( GetServerVar( "roundStartTime" ) ) ) else - return sinceTime - expect float( GetServerVar( "roundStartTime" ) ) - + return floor( expect float( GetServerVar( "roundEndTime" ) ) - Time() ) } else { if ( gameState > eGameState.SuddenDeath ) return (expect float( GetServerVar( "gameEndTime" ) ) - expect float( GetServerVar( "gameStartTime" ) ) ) else - return sinceTime - expect float( GetServerVar( "gameStartTime" ) ) + return floor( expect float( GetServerVar( "gameEndTime" ) ) - Time() ) } - unreachable } @@ -4411,4 +4404,4 @@ bool function PlayerHasTitan( entity player ) return true return false -} \ No newline at end of file +} -- cgit v1.2.3 From 2376c5339776d8ef6cb6e0f60d8fcf5a61ef2885 Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 8 Mar 2023 02:08:35 +0100 Subject: Add _menus.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/_menus.nut | 2002 ++++++++++++++++++++ 1 file changed, 2002 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/_menus.nut diff --git a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut new file mode 100644 index 00000000..90a535ee --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut @@ -0,0 +1,2002 @@ +untyped + +global const bool EDIT_LOADOUT_SELECTS = true +global const string PURCHASE_SUCCESS_SOUND = "UI_Menu_Store_Purchase_Success" + +global function UICodeCallback_CloseAllMenus +global function UICodeCallback_ActivateMenus +global function UICodeCallback_LevelInit +global function UICodeCallback_LevelLoadingStarted +global function UICodeCallback_LevelLoadingFinished +global function UICodeCallback_LevelShutdown +global function UICodeCallback_OnConnected +global function UICodeCallback_OnFocusChanged +global function UICodeCallback_NavigateBack +global function UICodeCallback_ToggleInGameMenu +global function UICodeCallback_TryCloseDialog +global function UICodeCallback_UpdateLoadingLevelName +global function UICodeCallback_ConsoleKeyboardClosed +global function UICodeCallback_ErrorDialog +global function UICodeCallback_AcceptInvite +global function UICodeCallback_OnDetenteDisplayed +global function UICodeCallback_OnSpLogDisplayed +global function UICodeCallback_EntitlementsChanged +global function UICodeCallback_StoreTransactionCompleted +global function UICodeCallback_GamePurchased +global function UICodeCallback_PartyUpdated +global function UICodeCallback_KeyBindOverwritten + +global function AdvanceMenu +global function OpenSubmenu // REMOVE +global function CloseSubmenu // REMOVE +global function CloseActiveMenu +global function CloseActiveMenuNoParms +global function CloseAllMenus +global function CloseAllInGameMenus +global function CloseAllDialogs +global function CloseAllToTargetMenu +global function PrintMenuStack +global function CleanupInGameMenus +global function GetActiveMenu +global function GetMenu +global function GetPanel +global function GetAllMenuPanels +global function InitGamepadConfigs +global function InitMenus +global function AdvanceMenuEventHandler +global function PCSwitchTeamsButton_Activate +global function PCToggleSpectateButton_Activate +global function AddMenuElementsByClassname +global function FocusDefault +global function SetPanelDefaultFocus +global function PanelFocusDefault +global function OpenMenuWrapper +global function CloseMenuWrapper +global function IsLevelMultiplayer +global function AddMenuEventHandler +global function AddPanelEventHandler +global function AddButtonEventHandler +global function AddEventHandlerToButton +global function AddEventHandlerToButtonClass +global function DisableMusic +global function EnableMusic +global function PlayMusic +global function StopMusic +global function IsMenuInMenuStack +global function GetTopNonDialogMenu +global function IsDialog +global function IsDialogActive +global function IsDialogOnlyActiveMenu +global function SetNavUpDown +global function SetNavLeftRight +global function IsTrialPeriodActive +global function LaunchGamePurchaseOrDLCStore +global function SetMenuThinkFunc + +global function PCBackButton_Activate + +global function RegisterMenuVarInt +global function GetMenuVarInt +global function SetMenuVarInt +global function RegisterMenuVarBool +global function GetMenuVarBool +global function SetMenuVarBool +global function RegisterMenuVarVar +global function GetMenuVarVar +global function SetMenuVarVar +global function AddMenuVarChangeHandler + +global function InviteFriends + +global function HACK_DelayedSetFocus_BecauseWhy + +#if DURANGO_PROG + global function OpenXboxPartyApp + global function OpenXboxHelp +#endif // DURANGO_PROG + +global function OpenReviewTermsDialog +global function ClassicMusic_OnChange +global function IsClassicMusicAvailable + + +void function UICodeCallback_CloseAllMenus() +{ + printt( "UICodeCallback_CloseAllMenus" ) + CloseAllMenus() + // This is usually followed by a call to UICodeCallback_ActivateMenus(). +} + +// Bringing up the console will cause this, and it probably shouldn't +void function UICodeCallback_ActivateMenus() +{ + if ( IsConnected() ) + return + + printt( "UICodeCallback_ActivateMenus:", uiGlobal.activeMenu && Hud_GetHudName( uiGlobal.activeMenu ) ) + + if ( uiGlobal.menuStack.len() == 0 ) + { + AdvanceMenu( GetMenu( "MainMenu" ) ) + } + + if ( uiGlobal.activeMenu == GetMenu( "MainMenu" ) ) + Signal( uiGlobal.signalDummy, "OpenErrorDialog" ) + + PlayMusic() + + #if DURANGO_PROG + Durango_LeaveParty() + #endif // DURANGO_PROG +} + +void function UICodeCallback_ToggleInGameMenu() +{ + if ( !IsFullyConnected() ) + return + + var activeMenu = uiGlobal.activeMenu + bool isMP = IsLevelMultiplayer( GetActiveLevel() ) + bool isLobby = IsLobby() + + var ingameMenu + if ( isMP ) + { + ingameMenu = GetMenu( "InGameMPMenu" ) + } + else + { + // Disable this callback for this special case menu so players can't skip it. + var spTitanTutorialMenu = GetMenu( "SPTitanLoadoutTutorialMenu" ) + if ( activeMenu == spTitanTutorialMenu ) + return + + ingameMenu = GetMenu( "InGameSPMenu" ) + } + + if ( IsDialog( uiGlobal.activeMenu ) ) + { + // Do nothing if a dialog is showing + } + else if ( TeamTitanSelectMenuIsOpen() ) + { + if ( uiGlobal.activeMenu == GetMenu( "TeamTitanSelectMenu" ) ) + { + // Do nothing here either + } + else + { + CloseActiveMenu() + } + } + else if ( ( isMP && !isLobby ) || !isMP ) + { + if ( !activeMenu ) + AdvanceMenu( ingameMenu ) + else + CloseAllInGameMenus() + } +} + +// Return true to show load screen, false to not show load screen. +// levelname can be "" because the level to load isn't always known when the load screen starts +bool function UICodeCallback_LevelLoadingStarted( string levelname ) +{ + printt( "UICodeCallback_LevelLoadingStarted: " + levelname ) + + CloseAllDialogs() + + uiGlobal.loadingLevel = levelname + + StopMusic() + + if ( uiGlobal.playingVideo ) + Signal( uiGlobal.signalDummy, "PlayVideoEnded" ) + + if ( uiGlobal.playingCredits ) + Signal( uiGlobal.signalDummy, "PlayingCreditsDone" ) + + // kill lingering postgame summary since persistent data may not be available at this point + Signal( uiGlobal.signalDummy, "PGDisplay" ) + +#if CONSOLE_PROG + if ( !Console_IsSignedIn() ) + return false +#endif + + return true +} + +// Return true to show load screen, false to not show load screen. +bool function UICodeCallback_UpdateLoadingLevelName( string levelname ) +{ + printt( "UICodeCallback_UpdateLoadingLevelName: " + levelname ) + +#if CONSOLE_PROG + if ( !Console_IsSignedIn() ) + return false +#endif + + return true +} + +void function UICodeCallback_LevelLoadingFinished( bool error ) +{ + printt( "UICodeCallback_LevelLoadingFinished: " + uiGlobal.loadingLevel + " (" + error + ")" ) + + if ( !IsLobby() ) + { + HudChat_ClearTextFromAllChatPanels() + ResetActiveChatroomLastModified() + } + else + { + uiGlobal.lobbyFromLoadingScreen = true + } + + uiGlobal.loadingLevel = "" + Signal( uiGlobal.signalDummy, "LevelFinishedLoading" ) +} + +void function UICodeCallback_LevelInit( string levelname ) +{ + Assert( IsConnected() ) + + StopVideo() + + uiGlobal.loadedLevel = levelname + + printt( "UICodeCallback_LevelInit: " + uiGlobal.loadedLevel ) + + if ( !uiGlobal.loadoutsInitialized ) + { + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString != "solo" ) + { + InitStatsTables() + } + } + + InitItems() + + if ( IsMultiplayer() ) + { + ShWeaponXP_Init() + ShTitanXP_Init() + ShFactionXP_Init() + } + else + { + SPObjectiveStringsInit() + } + + #if DEV + UpdatePrecachedSPWeapons() + #endif + + + if ( !uiGlobal.loadoutsInitialized ) + { + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString != "solo" ) + { + DeathHints_Init() + InitDefaultLoadouts() + CreateChallenges() + uiGlobal.loadoutsInitialized = true + } + } + + if ( IsLevelMultiplayer( levelname ) || IsLobbyMapName( levelname ) ) + { + thread UpdateCachedLoadouts() + thread UpdateCachedNewItems() + thread InitUISpawnLoadoutIndexes() + + if ( !uiGlobal.eventHandlersAdded ) + { + uiGlobal.eventHandlersAdded = true + } + + UI_GetAllChallengesProgress() + + bool isLobby = IsLobbyMapName( levelname ) + + string gameModeString = GetConVarString( "mp_gamemode" ) + if ( gameModeString == "" ) + gameModeString = "" + + Assert( gameModeString == GetConVarString( "mp_gamemode" ) ) + Assert( gameModeString != "" ) + + int gameModeId = GameMode_GetGameModeId( gameModeString ) + + int mapId = eMaps.invalid + if ( levelname in getconsttable().eMaps ) + { + mapId = expect int( getconsttable().eMaps[ levelname ] ) + } + else + { + // Don't worry about this until we have to consider R2 Durango TCRs (10/2015) + //if ( !IsTestMap() ) + // CodeWarning( "No map named '" + levelname + "' exists in eMaps, all shipping maps should be in this enum" ) + } + + int difficultyLevelId = 0 + int roundId = 0 + + if ( isLobby ) + Durango_OnLobbySessionStart( gameModeId, difficultyLevelId ) + else + Durango_OnMultiplayerRoundStart( gameModeId, mapId, difficultyLevelId, roundId, 0 ) + } + else + { + // SP loadout stuff + UI_GetAllChallengesProgress() // TODO: Can this be moved so we don't call it twice? It's called above. + + SP_ResetObjectiveStringIndex() // Since this persists thru level load, we need to explicitely clear it. + } + + if ( IsMultiplayer() ) + { + foreach ( callbackFunc in uiGlobal.onLevelInitCallbacks ) + { + thread callbackFunc() + } + + } + thread UpdateMenusOnConnect( levelname ) + + uiGlobal.previousLevel = uiGlobal.loadedLevel + uiGlobal.previousPlaylist = GetCurrentPlaylistName() +} + +void function UICodeCallback_LevelShutdown() +{ + Signal( uiGlobal.signalDummy, "LevelShutdown" ) + + printt( "UICodeCallback_LevelShutdown: " + uiGlobal.loadedLevel ) + + StopVideo() + + if ( uiGlobal.loadedLevel != "" ) + CleanupInGameMenus() + + uiGlobal.loadedLevel = "" + uiGlobal.mapSupportsMenuModelsUpdated = false + uiGlobal.sp_showAlternateMissionLog = false +} + +void function UICodeCallback_NavigateBack() +{ + if ( uiGlobal.activeMenu == null ) + return + + if ( IsDialog( uiGlobal.activeMenu ) ) + { + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.noChoice || + uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.forceChoice || + Time() < uiGlobal.dialogInputEnableTime ) + return + } + + Assert( uiGlobal.activeMenu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].navBackFunc != null ) + { + thread uiGlobal.menuData[ uiGlobal.activeMenu ].navBackFunc() + return + } + + if ( uiGlobal.activeMenu.GetType() == "submenu" ) // REMOVE + { + CloseSubmenu() + return + } + + CloseActiveMenu( true ) +} + +// Called when IsConnected() will start returning true. +void function UICodeCallback_OnConnected() +{ + +} + +void function UICodeCallback_OnFocusChanged( var oldFocusedPanel, var newFocusedPanel ) +{ + +} + +// Accepting an origin invite closes dialogs, or aborts if they can't be closed +bool function UICodeCallback_TryCloseDialog() +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return true + + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData.forceChoice ) + return false + + CloseAllDialogs() + Assert( !IsDialog( uiGlobal.activeMenu ) ) + return true +} + +void function UICodeCallback_ConsoleKeyboardClosed() +{ + switch ( uiGlobal.activeMenu ) + { + case GetMenu( "EditPilotLoadoutMenu" ): + string oldName = GetPilotLoadoutName( GetCachedPilotLoadout( uiGlobal.editingLoadoutIndex ) ) + string newName = GetPilotLoadoutRenameText() + + // strip doesn't work on UTF-8 strings + // newName = strip( newName ) // Remove leading/trailing whitespace + if ( newName == "" ) // If all whitespace entered reset to previous name + newName = oldName + + SetPilotLoadoutName( newName ) + SelectPilotLoadoutRenameText() + if ( newName != oldName ) + EmitUISound( "Menu.Accept" ) // No callback when cancelled so for now assume name was changed + break + + default: + break + } +} + +void function UICodeCallback_OnDetenteDisplayed() +{ +// thread PlayDetentSound() +//} +// +//void function PlayDetentSound() +//{ +// WaitFrame() // otherwise gets killed off by code pause +// WaitFrame() // otherwise gets killed off by code pause +// EmitUISound( "Pilot_Killed_Indicator" ) +} + +void function UICodeCallback_OnSpLogDisplayed() +{ +} + +void function UICodeCallback_ErrorDialog( string errorDetails ) +{ + printt( "UICodeCallback_ErrorDialog: " + errorDetails ) + thread OpenErrorDialog( errorDetails ) +} + +void function UICodeCallback_AcceptInviteThread( string accesstoken ) +{ + printt( "UICodeCallback_AcceptInviteThread '" + accesstoken + "'") + + #if PS4_PROG + if ( !Ps4_PSN_Is_Loggedin() ) + { + Ps4_LoginDialog_Schedule(); + while( Ps4_LoginDialog_Running() ) + WaitFrame() + if ( !Ps4_PSN_Is_Loggedin() ) + return; + } + + if( Ps4_CheckPlus_Schedule() ) + { + while( Ps4_CheckPlus_Running() ) + WaitFrame() + if( !Ps4_CheckPlus_Allowed() ) + { + if( Ps4_CheckPlus_GetLastRequestResults() != 0 ) + { + return + } + + if( Ps4_ScreenPlusDialog_Schedule() ) + { + while( Ps4_ScreenPlusDialog_Running() ) + WaitFrame() + if( !Ps4_ScreenPlusDialog_Allowed() ) + return; + } + else + { + return; + } + } + } + + #endif // #if PS4_PROG + + SubscribeToChatroomPartyChannel( accesstoken ); + +} + + +void function UICodeCallback_AcceptInvite( string accesstoken ) +{ + printt( "UICodeCallback_AcceptInvite '" + accesstoken + "'") + thread UICodeCallback_AcceptInviteThread( accesstoken ) +} + +// TODO: replaceCurrent should not be an option. It should be a different function. +void function AdvanceMenu( var menu, bool replaceCurrent = false ) +{ + //foreach ( index, menu in uiGlobal.menuStack ) + //{ + // if ( menu != null ) + // printt( "menu index " + index + " is named " + menu.GetDisplayName() ) + //} + + if ( uiGlobal.activeMenu ) + { + // Don't open the same menu again if it's already open + if ( uiGlobal.activeMenu == menu ) + return + + // Opening a normal menu while a dialog is open + Assert( !IsDialog( uiGlobal.activeMenu ), "Tried opening menu: " + Hud_GetHudName( menu ) + " when uiGlobal.activeMenu was: " + Hud_GetHudName( uiGlobal.activeMenu ) ) + } + + if ( uiGlobal.activeMenu && !IsDialog( menu ) ) // Dialogs show on top so don't close existing menu when opening them + { + SetBlurEnabled( false ) + + if ( replaceCurrent ) + { + CloseMenuWrapper( uiGlobal.activeMenu ) + uiGlobal.menuStack.pop() + } + else + { + CloseMenu( uiGlobal.activeMenu ) + printt( Hud_GetHudName( uiGlobal.activeMenu ), "menu closed" ) + } + } + + if ( IsDialog( menu ) && uiGlobal.activeMenu ) + SetFooterPanelVisibility( uiGlobal.activeMenu, false ) + + uiGlobal.menuStack.push( menu ) + uiGlobal.activeMenu = menu + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + if ( uiGlobal.activeMenu ) + { + if ( !IsLobby() && !uiGlobal.mapSupportsMenuModels ) + SetBlurEnabled( true ) + + OpenMenuWrapper( uiGlobal.activeMenu, true ) + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function SetFooterPanelVisibility( var menu, bool visible ) +{ + if ( !Hud_HasChild( menu, "FooterButtons" ) ) + return + + var panel = Hud_GetChild( menu, "FooterButtons" ) + Hud_SetVisible( panel, visible ) +} + +void function OpenSubmenu( var menu, bool updateMenuPos = true ) +{ + Assert( menu ) + Assert( menu.GetType() == "submenu" ) + + if ( uiGlobal.activeMenu ) + { + // Don't open the same menu again if it's already open + if ( uiGlobal.activeMenu == menu ) + return + } + + local submenuPos = Hud_GetAbsPos( GetFocus() ) + + uiGlobal.menuStack.push( menu ) + uiGlobal.activeMenu = menu + + OpenMenuWrapper( uiGlobal.activeMenu, true ) + + if ( updateMenuPos ) + { + var vguiButtonFrame = Hud_GetChild( uiGlobal.activeMenu, "ButtonFrame" ) + Hud_SetPos( vguiButtonFrame, submenuPos[0], submenuPos[1] ) + } + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseSubmenu( bool openStackMenu = true ) +{ + if ( !uiGlobal.activeMenu ) + return + + if ( uiGlobal.activeMenu.GetType() != "submenu" ) + return + + CloseMenuWrapper( uiGlobal.activeMenu ) + uiGlobal.menuStack.pop() + + uiGlobal.lastMenuNavDirection = MENU_NAV_FORWARD + + if ( uiGlobal.menuStack.len() ) + { + uiGlobal.activeMenu = uiGlobal.menuStack.top() + + // This runs any OnOpen function for the menu and sets focus, but doesn't actually open the menu because it is already open + if ( openStackMenu ) + OpenMenuWrapper( uiGlobal.activeMenu, false ) + } + else + { + uiGlobal.activeMenu = null + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseActiveMenuNoParms() +{ + CloseActiveMenu() +} + +void function CloseActiveMenu( bool cancelled = false, bool openStackMenu = true ) +{ + bool updateBlur = true + bool wasDialog = false + + if ( uiGlobal.activeMenu ) + { + if ( IsDialog( uiGlobal.activeMenu ) ) + { + updateBlur = false + wasDialog = true + uiGlobal.dialogInputEnableTime = 0.0 + + if ( uiGlobal.dialogCloseCallback ) + { + uiGlobal.dialogCloseCallback( cancelled ) + uiGlobal.dialogCloseCallback = null + } + } + + if ( updateBlur ) + SetBlurEnabled( false ) + + CloseMenuWrapper( uiGlobal.activeMenu ) + } + + uiGlobal.menuStack.pop() + if ( uiGlobal.menuStack.len() ) + uiGlobal.activeMenu = uiGlobal.menuStack.top() + else + uiGlobal.activeMenu = null + + uiGlobal.lastMenuNavDirection = MENU_NAV_BACK + + if ( wasDialog ) + { + if ( uiGlobal.activeMenu ) + SetFooterPanelVisibility( uiGlobal.activeMenu, true ) + + if ( IsDialog( uiGlobal.activeMenu ) ) + openStackMenu = true + else + openStackMenu = false + } + + if ( uiGlobal.activeMenu ) + { + if ( uiGlobal.activeMenu.GetType() == "submenu" ) + { + Hud_SetFocused( uiGlobal.menuData[ uiGlobal.activeMenu ].lastFocus ) + } + else if ( openStackMenu ) + { + OpenMenuWrapper( uiGlobal.activeMenu, false ) + + if ( updateBlur && !IsLobby() && !uiGlobal.mapSupportsMenuModels ) + SetBlurEnabled( true ) + } + } + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseAllMenus() +{ + if ( IsDialog( uiGlobal.activeMenu ) ) + CloseActiveMenu( true ) + + if ( uiGlobal.activeMenu && uiGlobal.activeMenu.GetType() == "submenu" ) + CloseSubmenu( false ) + + if ( uiGlobal.activeMenu ) + { + SetBlurEnabled( false ) + CloseMenuWrapper( uiGlobal.activeMenu ) + } + + uiGlobal.menuStack = [] + uiGlobal.activeMenu = null + + uiGlobal.lastMenuNavDirection = MENU_NAV_BACK + + Signal( uiGlobal.signalDummy, "ActiveMenuChanged" ) +} + +void function CloseAllInGameMenus() +{ + while ( uiGlobal.activeMenu ) + { + if ( uiGlobal.activeMenu.GetType() == "submenu" ) + CloseSubmenu( false ) + + CloseActiveMenu( true, false ) + } +} + +void function CloseAllDialogs() +{ + while ( IsDialog( uiGlobal.activeMenu ) ) + CloseActiveMenu( true ) +} + +void function CloseAllToTargetMenu( var targetMenu ) +{ + while ( uiGlobal.activeMenu != targetMenu ) + CloseActiveMenu( true, false ) +} + +void function PrintMenuStack() +{ + array stack = clone uiGlobal.menuStack + stack.reverse() + + printt( "MENU STACK:" ) + + foreach ( menu in stack ) + { + if ( menu ) + printt( " ", Hud_GetHudName( menu ) ) + else + printt( " null" ) + } +} + +// Happens on any level load +void function UpdateMenusOnConnect( string levelname ) +{ + EndSignal( uiGlobal.signalDummy, "LevelShutdown" ) // HACK fix because UICodeCallback_LevelInit() incorrectly runs when disconnected by client error. Test with "script_error_client" while a level is loaded. + + CloseAllDialogs() + + var mainMenu = GetMenu( "MainMenu" ) + if ( IsMenuInMenuStack( mainMenu ) && !IsMenuInMenuStack( null ) ) + CloseAllToTargetMenu( mainMenu ) + + Assert( uiGlobal.activeMenu != null || uiGlobal.menuStack.len() == 0 ) + + AdvanceMenu( null ) + + // TODO: The order things are called in should be predictable so this isn't needed + while ( !uiGlobal.mapSupportsMenuModelsUpdated ) + { + //printt( Time(), "beginning waitframe, uiGlobal.mapSupportsMenuModelsUpdated is:", uiGlobal.mapSupportsMenuModelsUpdated ) + WaitFrame() + //printt( Time(), "ended waitframe, uiGlobal.mapSupportsMenuModelsUpdated is:", uiGlobal.mapSupportsMenuModelsUpdated ) + } + + if ( IsLevelMultiplayer( levelname ) ) + { + bool isLobby = IsLobbyMapName( levelname ) + + if ( isLobby ) + { + if ( IsPrivateMatch() ) + { + AdvanceMenu( GetMenu( "PrivateLobbyMenu" ) ) + } + else + { + AdvanceMenu( GetMenu( "LobbyMenu" ) ) + } + + thread UpdateAnnouncementDialog() + } + else + { + UI_SetPresentationType( ePresentationType.INACTIVE ) + } + } +} + +bool function IsMenuInMenuStack( var searchMenu ) +{ + foreach ( menu in uiGlobal.menuStack ) + { + // loading a map pushes a null sentinel onto the menu stack + if ( !menu ) + continue + + if ( menu == searchMenu ) + return true + } + + return false +} + +var function GetTopNonDialogMenu() +{ + array menuArray = clone uiGlobal.menuStack + menuArray.reverse() + + foreach ( menu in menuArray ) + { + if ( menu == null || IsDialog( menu ) ) + continue + + return menu + } + + return null +} + +void function CleanupInGameMenus() +{ + Signal( uiGlobal.signalDummy, "CleanupInGameMenus" ) + + CloseAllInGameMenus() + Assert( uiGlobal.activeMenu == null ) + if ( uiGlobal.menuStack.len() ) + { + if ( uiGlobal.loadingLevel == "" ) + CloseActiveMenu() // Disconnected. Remove stack null and open main menu. + else + CloseActiveMenu( true, false ) // Level to level transition. Remove stack null and DON'T open main menu. + } +} + +var function GetActiveMenu() +{ + return uiGlobal.activeMenu +} + +var function GetMenu( string menuName ) +{ + return uiGlobal.menus[ menuName ] +} + +var function GetPanel( string panelName ) +{ + return uiGlobal.panels[ panelName ] +} + +array function GetAllMenuPanels( var menu ) +{ + array menuPanels + + foreach ( panel in uiGlobal.allPanels ) + { + if ( Hud_GetParent( panel ) == menu ) + menuPanels.append( panel ) + } + + return menuPanels +} + +void function InitGamepadConfigs() +{ + uiGlobal.buttonConfigs = [ { orthodox = "gamepad_button_layout_default.cfg", southpaw = "gamepad_button_layout_default_southpaw.cfg" } ] + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_bumper_jumper.cfg", southpaw = "gamepad_button_layout_bumper_jumper_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_bumper_jumper_alt.cfg", southpaw = "gamepad_button_layout_bumper_jumper_alt_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_pogo_stick.cfg", southpaw = "gamepad_button_layout_pogo_stick_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_button_kicker.cfg", southpaw = "gamepad_button_layout_button_kicker_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_circle.cfg", southpaw = "gamepad_button_layout_circle_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_ninja.cfg", southpaw = "gamepad_button_layout_ninja_southpaw.cfg" } ) + uiGlobal.buttonConfigs.append( { orthodox = "gamepad_button_layout_custom.cfg", southpaw = "gamepad_button_layout_custom.cfg" } ) + + uiGlobal.stickConfigs = [] + uiGlobal.stickConfigs.append( "gamepad_stick_layout_default.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_southpaw.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_legacy.cfg" ) + uiGlobal.stickConfigs.append( "gamepad_stick_layout_legacy_southpaw.cfg" ) + + foreach ( key, val in uiGlobal.buttonConfigs ) + { + VPKNotifyFile( "cfg/" + val.orthodox ) + VPKNotifyFile( "cfg/" + val.southpaw ) + } + + foreach ( key, val in uiGlobal.stickConfigs ) + VPKNotifyFile( "cfg/" + val ) + + ExecCurrentGamepadButtonConfig() + ExecCurrentGamepadStickConfig() + + SetStandardAbilityBindingsForPilot( GetLocalClientPlayer() ) +} + +void function InitMenus() +{ + InitGlobalMenuVars() + SpShWeaponsInit() + + AddMenu( "MainMenu", $"resource/ui/menus/main.menu", InitMainMenu, "#MAIN" ) + AddPanel( GetMenu( "MainMenu" ), "EstablishUserPanel", InitEstablishUserPanel ) + AddPanel( GetMenu( "MainMenu" ), "MainMenuPanel", InitMainMenuPanel ) + + AddMenu( "PlayVideoMenu", $"resource/ui/menus/play_video.menu", InitPlayVideoMenu ) + AddMenu( "LobbyMenu", $"resource/ui/menus/lobby.menu", InitLobbyMenu, "#LOBBY" ) + + AddMenu( "FDMenu", $"resource/ui/menus/playlist_fd.menu", InitFDPlaylistMenu ) + AddMenu( "TeamTitanSelectMenu", $"resource/ui/menus/team_titan_select.menu", InitTeamTitanSelectMenu ) + AddMenu( "PlaylistMenu", $"resource/ui/menus/playlist.menu", InitPlaylistMenu ) + AddMenu( "PlaylistMixtapeMenu", $"resource/ui/menus/playlist_mixtape.menu", InitPlaylistMixtapeMenu ) + AddMenu( "PlaylistMixtapeChecklistMenu", $"resource/ui/menus/playlist_mixtape_checklist.menu", InitPlaylistMixtapeChecklistMenu ) + + AddMenu( "SinglePlayerDevMenu", $"resource/ui/menus/singleplayer_dev.menu", InitSinglePlayerDevMenu, "SINGLE PLAYER DEV" ) + AddMenu( "SinglePlayerMenu", $"resource/ui/menus/singleplayer.menu", InitSinglePlayerMenu, "SINGLE PLAYER" ) + + AddMenu( "SearchMenu", $"resource/ui/menus/search.menu", InitSearchMenu ) + + AddMenu( "GammaMenu", $"resource/ui/menus/gamma.menu", InitGammaMenu, "#BRIGHTNESS" ) + + AddMenu( "CommunitiesMenu", $"resource/ui/menus/community.menu", InitCommunitiesMenu ) + AddMenu( "Notifications", $"resource/ui/menus/notifications.menu", InitNotificationsMenu ) + AddMenu( "MyNetworks", $"resource/ui/menus/communities_mine.menu", InitMyNetworksMenu ) + AddMenu( "InboxFrontMenu", $"resource/ui/menus/inbox_front.menu", InitInboxFrontMenu ) + AddMenu( "Inbox", $"resource/ui/menus/inbox.menu", InitInboxMenu ) + AddMenu( "BrowseCommunities", $"resource/ui/menus/communities_browse.menu" ) + AddMenu( "CommunityEditMenu", $"resource/ui/menus/community_edit.menu" ) + AddMenu( "CommunityAdminSendMessage", $"resource/ui/menus/community_sendMessage.menu" ) + AddMenu( "CommunityAdminInviteRequestMenu", $"resource/ui/menus/community_inviteRequest.menu" ) +#if NETWORK_INVITE + AddMenu( "InviteFriendsToNetworkMenu", $"resource/ui/menus/invite_friends.menu", InitInviteFriendsToNetworkMenu ) +#endif + + AddMenu( "InGameMPMenu", $"resource/ui/menus/ingame_mp.menu", InitInGameMPMenu ) + AddMenu( "InGameSPMenu", $"resource/ui/menus/ingame_sp.menu", InitInGameSPMenu ) + + AddMenu( "Dialog", $"resource/ui/menus/dialog.menu", InitDialogMenu ) + AddMenu( "AnnouncementDialog", $"resource/ui/menus/dialog_announcement.menu", InitAnnouncementDialog ) + AddMenu( "ConnectingDialog", $"resource/ui/menus/dialog_connecting.menu", InitConnectingDialog ) + AddMenu( "DataCenterDialog", $"resource/ui/menus/dialog_datacenter.menu", InitDataCenterDialogMenu ) + AddMenu( "EULADialog", $"resource/ui/menus/dialog_eula.menu", InitEULADialog ) + AddMenu( "ReviewTermsDialog", $"resource/ui/menus/dialog_review_terms.menu", InitReviewTermsDialog ) + AddMenu( "RegistrationDialog", $"resource/ui/menus/dialog_registration.menu", InitRegistrationDialog ) + AddMenu( "AdvocateGiftDialog", $"resource/ui/menus/dialog_advocate_gift.menu", InitAdvocateGiftDialog ) + + AddMenu( "ControlsMenu", $"resource/ui/menus/controls.menu", InitControlsMenu, "#CONTROLS" ) + AddMenu( "ControlsAdvancedLookMenu", $"resource/ui/menus/controls_advanced_look.menu", InitControlsAdvancedLookMenu, "#CONTROLS_ADVANCED_LOOK" ) + AddMenu( "GamepadLayoutMenu", $"resource/ui/menus/gamepadlayout.menu", InitGamepadLayoutMenu ) +#if PC_PROG + AddMenu_WithCreateFunc( "MouseKeyboardBindingsMenu", $"resource/ui/menus/mousekeyboardbindings.menu", InitMouseKeyboardMenu, CreateKeyBindingMenu ) + AddMenu( "AudioMenu", $"resource/ui/menus/audio.menu", InitAudioMenu, "#AUDIO" ) + AddMenu_WithCreateFunc( "VideoMenu", $"resource/ui/menus/video.menu", InitVideoMenu, CreateVideoOptionsMenu ) +#elseif CONSOLE_PROG + AddMenu( "AudioVideoMenu", $"resource/ui/menus/audio_video.menu", InitAudioVideoMenu, "#AUDIO_VIDEO" ) +#endif + + AddMenu( "AdvancedHudMenu", $"resource/ui/menus/advanced_hud.menu", InitAdvancedHudMenu, "#ADVANCED_HUD" ) + + AddMenu( "PilotLoadoutsMenu", $"resource/ui/menus/pilotloadouts.menu", InitPilotLoadoutsMenu ) + AddMenu( "TitanLoadoutsMenu", $"resource/ui/menus/titanloadouts.menu", InitTitanLoadoutsMenu ) + AddMenu( "EditPilotLoadoutsMenu", $"resource/ui/menus/pilotloadouts.menu", InitEditPilotLoadoutsMenu ) + AddMenu( "EditTitanLoadoutsMenu", $"resource/ui/menus/titanloadouts.menu", InitEditTitanLoadoutsMenu ) + AddMenu( "EditPilotLoadoutMenu", $"resource/ui/menus/editpilotloadout.menu", InitEditPilotLoadoutMenu ) + AddMenu( "EditTitanLoadoutMenu", $"resource/ui/menus/edittitanloadout.menu", InitEditTitanLoadoutMenu ) + + AddMenu( "SPTitanLoadoutMenu", $"resource/ui/menus/sptitanloadout.menu", InitSPTitanLoadoutMenu ) + AddMenu( "SPTitanLoadoutTutorialMenu", $"resource/ui/menus/sptitanloadout_tutorial.menu", InitSPTitanLoadoutTutorialMenu ) + + AddMenu( "SuitSelectMenu", $"resource/ui/menus/suitselect.menu", InitSuitSelectMenu ) + AddMenu( "WeaponSelectMenu", $"resource/ui/menus/weaponselect.menu", InitWeaponSelectMenu ) + AddMenu( "CategorySelectMenu", $"resource/ui/menus/categoryselect.menu", InitCategorySelectMenu ) + AddMenu( "AbilitySelectMenu", $"resource/ui/menus/abilityselect.menu", InitAbilitySelectMenu ) + AddMenu( "PassiveSelectMenu", $"resource/ui/menus/passiveselect.menu", InitPassiveSelectMenu ) + AddSubmenu( "ModSelectMenu", $"resource/ui/menus/modselect.menu", InitModSelectMenu ) + AddMenu( "CamoSelectMenu", $"resource/ui/menus/camoselect.menu", InitCamoSelectMenu ) + AddMenu( "NoseArtSelectMenu", $"resource/ui/menus/noseartselect.menu", InitNoseArtSelectMenu ) + AddMenu( "CallsignCardSelectMenu", $"resource/ui/menus/callsigncardselect.menu", InitCallsignCardSelectMenu ) + AddMenu( "CallsignIconSelectMenu", $"resource/ui/menus/callsigniconselect.menu", InitCallsignIconSelectMenu ) + AddMenu( "BoostStoreMenu", $"resource/ui/menus/booststore.menu", InitBoostStoreMenu ) + + AddMenu( "PrivateLobbyMenu", $"resource/ui/menus/private_lobby.menu", InitPrivateMatchMenu, "#PRIVATE_MATCH" ) + AddMenu( "MapsMenu", $"resource/ui/menus/map_select.menu", InitMapsMenu ) + AddMenu( "ModesMenu", $"resource/ui/menus/mode_select.menu", InitModesMenu ) + AddMenu( "MatchSettingsMenu", $"resource/ui/menus/match_settings.menu", InitMatchSettingsMenu ) + + AddMenu( "Advocate_Letter", $"resource/ui/menus/advocate_letter.menu", InitAdvocateLetterMenu ) + AddMenu( "Generation_Respawn", $"resource/ui/menus/generation_respawn.menu", InitGenerationRespawnMenu ) + AddMenu( "ChallengesMenu", $"resource/ui/menus/challenges.menu", InitChallengesMenu ) + + AddMenu( "ViewStatsMenu", $"resource/ui/menus/viewstats.menu", InitViewStatsMenu, "#PERSONAL_STATS" ) + AddMenu( "ViewStats_Overview_Menu", $"resource/ui/menus/viewstats_overview.menu", InitViewStatsOverviewMenu ) + //AddMenu( "ViewStats_Kills_Menu", $"resource/ui/menus/viewstats_kills.menu", InitViewStatsKillsMenu ) + AddMenu( "ViewStats_Time_Menu", $"resource/ui/menus/viewstats_time.menu", InitViewStatsTimeMenu ) + //AddMenu( "ViewStats_Distance_Menu", $"resource/ui/menus/viewstats_distance.menu", InitViewStatsDistanceMenu ) + AddMenu( "ViewStats_Weapons_Menu", $"resource/ui/menus/viewstats_weapons.menu", InitViewStatsWeaponsMenu ) + AddMenu( "ViewStats_Titans_Menu", $"resource/ui/menus/viewstats_titans.menu", InitViewStatsTitansMenu ) + AddMenu( "ViewStats_Misc_Menu", $"resource/ui/menus/viewstats_misc.menu", InitViewStatsMiscMenu ) + AddMenu( "ViewStats_Maps_Menu", $"resource/ui/menus/viewstats_maps.menu", InitViewStatsMapsMenu ) + + AddMenu( "PostGameMenu", $"resource/ui/menus/postgame.menu", InitPostGameMenu ) + AddMenu( "EOG_XP", $"resource/ui/menus/eog_xp.menu", InitEOG_XPMenu ) + AddMenu( "EOG_Coins", $"resource/ui/menus/eog_coins.menu", InitEOG_CoinsMenu ) + AddMenu( "EOG_Challenges", $"resource/ui/menus/eog_challenges.menu", InitEOG_ChallengesMenu ) + AddMenu( "EOG_Unlocks", $"resource/ui/menus/eog_unlocks.menu", InitEOG_UnlocksMenu ) + AddMenu( "EOG_Scoreboard", $"resource/ui/menus/eog_scoreboard.menu", InitEOG_ScoreboardMenu ) + + AddMenu( "CreditsMenu", $"resource/ui/menus/credits.menu", InitCreditsMenu, "#CREDITS" ) + + AddMenu( "BurnCardMenu", $"resource/ui/menus/burn_cards.menu", InitBurnCardMenu, "#MENU_BURNCARD_MENU" ) + AddMenu( "FactionChoiceMenu", $"resource/ui/menus/faction_choice.menu", InitFactionChoiceMenu, "#FACTION_CHOICE_MENU" ) + AddMenu( "ArmoryMenu", $"resource/ui/menus/armory.menu", InitArmoryMenu, "#ARMORY_MENU" ) + + AddMenu( "StoreMenu", $"resource/ui/menus/store.menu", InitStoreMenu, "#STORE_MENU" ) + AddMenu( "StoreMenu_NewReleases", $"resource/ui/menus/store_new_releases.menu", InitStoreMenuNewReleases, "#STORE_NEW_RELEASES" ) + AddMenu( "StoreMenu_Limited", $"resource/ui/menus/store_limited.menu", InitStoreMenuLimited, "#STORE_LIMITED" ) + AddMenu( "StoreMenu_Sales", $"resource/ui/menus/store_bundles.menu", InitStoreMenuSales, "#STORE_BUNDLES" ) + AddMenu( "StoreMenu_Titans", $"resource/ui/menus/store_prime_titans.menu", InitStoreMenuTitans, "#STORE_TITANS" ) // reusing store_prime_titans.menu + AddMenu( "StoreMenu_PrimeTitans", $"resource/ui/menus/store_prime_titans.menu", InitStoreMenuPrimeTitans, "#STORE_PRIME_TITANS" ) + //AddMenu( "StoreMenu_WeaponSelect", $"resource/ui/menus/store_weapon_select.menu", InitStoreMenuWeaponSelect ) + //AddMenu( "StoreMenu_WeaponSkinPreview", $"resource/ui/menus/store_weapon_skin_preview.menu", InitStoreMenuWeaponSkinPreview ) + AddMenu( "StoreMenu_WeaponSkinBundles", $"resource/ui/menus/store_weapon_skin_bundles.menu", InitStoreMenuWeaponSkinBundles ) + AddMenu( "StoreMenu_WeaponSkins", $"resource/ui/menus/store_weapons.menu", InitStoreMenuWeaponSkins ) + AddMenu( "StoreMenu_Customization", $"resource/ui/menus/store_customization.menu", InitStoreMenuCustomization, "#STORE_CUSTOMIZATION_PACKS" ) + AddMenu( "StoreMenu_CustomizationPreview", $"resource/ui/menus/store_customization_preview.menu", InitStoreMenuCustomizationPreview, "#STORE_CUSTOMIZATION_PACKS" ) + AddMenu( "StoreMenu_Camo", $"resource/ui/menus/store_camo.menu", InitStoreMenuCamo, "#STORE_CAMO_PACKS" ) + AddMenu( "StoreMenu_CamoPreview", $"resource/ui/menus/store_camo_preview.menu", InitStoreMenuCamoPreview, "#STORE_CAMO_PACKS" ) + AddMenu( "StoreMenu_Callsign", $"resource/ui/menus/store_callsign.menu", InitStoreMenuCallsign, "#STORE_CALLSIGN_PACKS" ) + AddMenu( "StoreMenu_CallsignPreview", $"resource/ui/menus/store_callsign_preview.menu", InitStoreMenuCallsignPreview, "#STORE_CALLSIGN_PACKS" ) + + AddMenu( "KnowledgeBaseMenu", $"resource/ui/menus/knowledgebase.menu", InitKnowledgeBaseMenu ) + AddMenu( "KnowledgeBaseMenuSubMenu", $"resource/ui/menus/knowledgebase_submenu.menu", InitKnowledgeBaseMenuSubMenu ) + + AddMenu( "DevMenu", $"resource/ui/menus/dev.menu", InitDevMenu, "Dev" ) + InitSharedStartPoints() + + foreach ( menu in uiGlobal.allMenus ) + { + if ( uiGlobal.menuData[ menu ].initFunc != null ) + uiGlobal.menuData[ menu ].initFunc() + + array elems = GetElementsByClassname( menu, "TabsCommonClass" ) + if ( elems.len() ) + uiGlobal.menuData[ menu ].hasTabs = true + + elems = GetElementsByClassname( menu, "EnableKeyBindingIcons" ) + foreach ( elem in elems ) + Hud_EnableKeyBindingIcons( elem ) + } + + InitTabs() + + var tabbedMenu = GetMenu( "PostGameMenu" ) + AddPanel( tabbedMenu, "PVEPanel", InitPVEPanel ) + AddPanel( tabbedMenu, "SummaryPanel", InitSummaryPanel ) + AddPanel( tabbedMenu, "FDAwardsPanel", InitFDAwardsPanel ) + + AddPanel( tabbedMenu, "ScoreboardPanel", InitScoreboardPanel ) + + foreach ( panel in uiGlobal.allPanels ) + { + if ( uiGlobal.panelData[ panel ].initFunc != null ) + uiGlobal.panelData[ panel ].initFunc() + } + + // A little weird, but GetElementsByClassname() uses menu scope rather than parent scope. + foreach ( menu in uiGlobal.allMenus ) + { + array buttons = GetElementsByClassname( menu, "DefaultFocus" ) + foreach ( button in buttons ) + { + var panel = Hud_GetParent( button ) + + //Assert( elems.len() == 1, "More than 1 panel element set as DefaultFocus!" ) + Assert( panel != null, "no parent panel found for button " + Hud_GetHudName( button ) ) + Assert( panel in uiGlobal.panelData, "panel " + Hud_GetHudName( panel ) + " isn't in uiGlobal.panelData, but button " + Hud_GetHudName( button ) + " has defaultFocus set!" ) + uiGlobal.panelData[ panel ].defaultFocus = button + //printt( "Found DefaultFocus, button was:", Hud_GetHudName( button ), "panel was:", Hud_GetHudName( panel ) ) + } + } + + InitFooterOptions() + + #if DEV + if ( Dev_CommandLineHasParm( "-autoprecache_all" ) ) + { + // repreache all levels + ExecuteLoadingClientCommands_SetStartPoint( "sp_training" ) + ClientCommand( "map sp_training" ) + CloseAllMenus() + } + #endif +} + +void functionref( var ) function AdvanceMenuEventHandler( var menu ) +{ + return void function( var item ) : ( menu ) + { + if ( Hud_IsLocked( item ) ) + return + + AdvanceMenu( menu ) + } +} + +void function PCBackButton_Activate( var button ) +{ + UICodeCallback_NavigateBack() +} + +void function PCSwitchTeamsButton_Activate( var button ) +{ + ClientCommand( "PrivateMatchSwitchTeams" ) +} + +void function PCToggleSpectateButton_Activate( var button ) +{ + ClientCommand( "PrivateMatchToggleSpectate" ) +} + +void function ToggleButtonStates( var button ) +{ + for ( ;; ) + { + Hud_SetEnabled( button, true ) + wait 1 + Hud_SetSelected( button, true ) + wait 1 + Hud_SetLocked( button, true ) + wait 1 + Hud_SetNew( button, true ) + wait 1 + Hud_SetNew( button, false ) + wait 1 + Hud_SetLocked( button, false ) + wait 1 + Hud_SetSelected( button, false ) + wait 1 + Hud_SetEnabled( button, false ) + wait 1 + } +} + +void function AddMenuElementsByClassname( var menu, string classname ) +{ + array elements = GetElementsByClassname( menu, classname ) + + if ( !(classname in menu.classElements) ) + menu.classElements[classname] <- [] + + menu.classElements[classname].extend( elements ) +} + +void function FocusDefault( var menu ) +{ + if ( + menu == GetMenu( "MainMenu" ) || + menu == GetMenu( "CategorySelectMenu" ) || + menu == GetMenu( "AbilitySelectMenu" ) || + menu == GetMenu( "PassiveSelectMenu" ) || + menu == GetMenu( "WeaponSelectMenu" ) || + menu == GetMenu( "SuitSelectMenu" ) || + menu == GetMenu( "CamoSelectMenu" ) || + menu == GetMenu( "NoseArtSelectMenu" ) || + menu == GetMenu( "FactionChoiceMenu" ) || + menu == GetMenu( "BurnCardMenu" ) || + menu == GetMenu( "CallsignCardSelectMenu" ) || + menu == GetMenu( "CallsignIconSelectMenu" ) ) + { + } + else + { + //printt( "FocusDefaultMenuItem() called" ) + FocusDefaultMenuItem( menu ) + } +} + +void function SetPanelDefaultFocus( var panel, var button ) +{ + uiGlobal.panelData[ panel ].defaultFocus = button +} + +void function PanelFocusDefault( var panel ) +{ + //printt( "PanelFocusDefault called" ) + if ( uiGlobal.panelData[ panel ].defaultFocus ) + { + Hud_SetFocused( uiGlobal.panelData[ panel ].defaultFocus ) + //printt( "PanelFocusDefault if passed,", Hud_GetHudName( uiGlobal.panelData[ panel ].defaultFocus ), "focused" ) + } +} + +void function SetMenuThinkFunc( var menu, void functionref() func ) +{ + Assert( uiGlobal.menuData[ menu ].thinkFunc == null ) + uiGlobal.menuData[ menu ].thinkFunc = func +} + +void function AddMenuEventHandler( var menu, int event, void functionref() func ) +{ + if ( event == eUIEvent.MENU_OPEN ) + { + Assert( uiGlobal.menuData[ menu ].openFunc == null ) + uiGlobal.menuData[ menu ].openFunc = func + } + else if ( event == eUIEvent.MENU_CLOSE ) + { + Assert( uiGlobal.menuData[ menu ].closeFunc == null ) + uiGlobal.menuData[ menu ].closeFunc = func + } + else if ( event == eUIEvent.MENU_SHOW ) + { + Assert( uiGlobal.menuData[ menu ].showFunc == null ) + uiGlobal.menuData[ menu ].showFunc = func + } + else if ( event == eUIEvent.MENU_HIDE ) + { + Assert( uiGlobal.menuData[ menu ].hideFunc == null ) + uiGlobal.menuData[ menu ].hideFunc = func + } + else if ( event == eUIEvent.MENU_NAVIGATE_BACK ) + { + Assert( uiGlobal.menuData[ menu ].navBackFunc == null ) + uiGlobal.menuData[ menu ].navBackFunc = func + } + else if ( event == eUIEvent.MENU_TAB_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].tabChangedFunc == null ) + uiGlobal.menuData[ menu ].tabChangedFunc = func + } + else if ( event == eUIEvent.MENU_ENTITLEMENTS_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].entitlementsChangedFunc == null ) + uiGlobal.menuData[ menu ].entitlementsChangedFunc = func + } + else if ( event == eUIEvent.MENU_INPUT_MODE_CHANGED ) + { + Assert( uiGlobal.menuData[ menu ].inputModeChangedFunc == null ) + uiGlobal.menuData[ menu ].inputModeChangedFunc = func + } +} + +void function AddPanelEventHandler( var panel, int event, void functionref() func ) +{ + if ( event == eUIEvent.PANEL_SHOW ) + uiGlobal.panelData[ panel ].showFunc = func + else if ( event == eUIEvent.PANEL_HIDE ) + uiGlobal.panelData[ panel ].hideFunc = func +} + +// TODO: Get a real on open event from code? +void function OpenMenuWrapper( var menu, bool focusDefault ) +{ + OpenMenu( menu ) + printt( Hud_GetHudName( menu ), "menu opened" ) + + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].openFunc != null ) + { + thread uiGlobal.menuData[ menu ].openFunc() + //printt( "Called openFunc for:", menu.GetHudName() ) + } + + if ( focusDefault ) + FocusDefault( menu ) + + //UpdateMenuTabs() + UpdateFooterOptions() +} + +void function CloseMenuWrapper( var menu ) +{ + CloseMenu( menu ) + printt( Hud_GetHudName( menu ), "menu closed" ) + + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].closeFunc != null ) + { + thread uiGlobal.menuData[ menu ].closeFunc() + //printt( "Called closeFunc for:", Hud_GetHudName( menu ) ) + } +} + +bool function IsLevelMultiplayer( string levelname ) +{ + return levelname.find( "mp_" ) == 0 +} + +void function AddButtonEventHandler( var button, int event, void functionref( var ) func ) +{ + Hud_AddEventHandler( button, event, func ) +} + +void function AddEventHandlerToButton( var menu, string buttonName, int event, void functionref( var ) func ) +{ + var button = Hud_GetChild( menu, buttonName ) + Hud_AddEventHandler( button, event, func ) +} + +void function AddEventHandlerToButtonClass( var menu, string classname, int event, void functionref( var ) func ) +{ + array buttons = GetElementsByClassname( menu, classname ) + + foreach ( button in buttons ) + { + //printt( "button name:", Hud_GetHudName( button ) ) + Hud_AddEventHandler( button, event, func ) + } +} + +// Added slight delay to main menu music to work around a hitch caused when the game first starts up +void function PlayMusicAfterDelay() +{ + wait MAINMENU_MUSIC_DELAY + if ( uiGlobal.playingMusic ) + EmitUISound( "MainMenu_Music" ) +} + +void function DisableMusic() +{ + EmitUISound( "Movie_MuteAllGameSound" ) +} + +void function EnableMusic() +{ + StopUISoundByName( "Movie_MuteAllGameSound" ) +} + +void function PlayMusic() +{ + if ( !uiGlobal.playingMusic && !uiGlobal.playingVideo && !uiGlobal.playingCredits ) + { + //printt( "PlayMusic() called. Playing: MainMenu_Music. uiGlobal.playingMusic:", uiGlobal.playingMusic, "uiGlobal.playingVideo:", uiGlobal.playingVideo, "uiGlobal.playingCredits:", uiGlobal.playingCredits ) + uiGlobal.playingMusic = true + thread PlayMusicAfterDelay() + } + else + { + //printt( "PlayMusic() called, but doing nothing. uiGlobal.playingMusic:", uiGlobal.playingMusic, "uiGlobal.playingVideo:", uiGlobal.playingVideo, "uiGlobal.playingCredits:", uiGlobal.playingCredits ) + } +} + +void function StopMusic() +{ + //printt( "StopMusic() called. Stopping: MainMenu_Music" ) + StopUISound( "MainMenu_Music" ) + uiGlobal.playingMusic = false +} + +void function RegisterMenuVarInt( string varName, int value ) +{ + table intVars = uiGlobal.intVars + + Assert( !( varName in intVars ) ) + + intVars[varName] <- value +} + +void function RegisterMenuVarBool( string varName, bool value ) +{ + table boolVars = uiGlobal.boolVars + + Assert( !( varName in boolVars ) ) + + boolVars[varName] <- value +} + +void function RegisterMenuVarVar( string varName, var value ) +{ + table varVars = uiGlobal.varVars + + Assert( !( varName in varVars ) ) + + varVars[varName] <- value +} + +int function GetMenuVarInt( string varName ) +{ + table intVars = uiGlobal.intVars + + Assert( varName in intVars ) + + return intVars[varName] +} + +bool function GetMenuVarBool( string varName ) +{ + table boolVars = uiGlobal.boolVars + + Assert( varName in boolVars ) + + return boolVars[varName] +} + +var function GetMenuVarVar( string varName ) +{ + table varVars = uiGlobal.varVars + + Assert( varName in varVars ) + + return varVars[varName] +} + +void function SetMenuVarInt( string varName, int value ) +{ + table intVars = uiGlobal.intVars + + Assert( varName in intVars ) + + if ( intVars[varName] == value ) + return + + intVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function SetMenuVarBool( string varName, bool value ) +{ + table boolVars = uiGlobal.boolVars + + Assert( varName in boolVars ) + + if ( boolVars[varName] == value ) + return + + boolVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function SetMenuVarVar( string varName, var value ) +{ + table varVars = uiGlobal.varVars + + Assert( varName in varVars ) + + if ( varVars[varName] == value ) + return + + varVars[varName] = value + + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( varName in varChangeFuncs ) + { + foreach ( func in varChangeFuncs[varName] ) + { + //printt( varName, "changed, calling changeFunc:", string( func ) ) + func() + } + } +} + +void function AddMenuVarChangeHandler( string varName, void functionref() func ) +{ + table > varChangeFuncs = uiGlobal.varChangeFuncs + + if ( !( varName in varChangeFuncs ) ) + varChangeFuncs[varName] <- [] + + // TODO: Verify we're not duplicating an existing func + varChangeFuncs[varName].append( func ) +} + +// These are common menu statuses that trigger menu logic any time they change +// They should become code callbacks, so script doesn't poll +void function InitGlobalMenuVars() +{ + RegisterMenuVarVar( "focus", null ) + RegisterMenuVarBool( "isConnected", false ) + RegisterMenuVarBool( "isFullyConnected", false ) + RegisterMenuVarBool( "isPartyLeader", false ) + RegisterMenuVarBool( "isPrivateMatch", false ) + RegisterMenuVarBool( "isGamepadActive", IsControllerModeActive() ) + + #if CONSOLE_PROG + RegisterMenuVarBool( "CONSOLE_isOnline", false ) + RegisterMenuVarBool( "CONSOLE_isSignedIn", false ) + #endif // CONSOLE_PROG + + #if DURANGO_PROG + RegisterMenuVarBool( "DURANGO_isGameFullyInstalled", false ) + RegisterMenuVarBool( "DURANGO_canInviteFriends", false ) + RegisterMenuVarBool( "DURANGO_isJoinable", false ) + #elseif PS4_PROG + RegisterMenuVarBool( "PS4_canInviteFriends", false) + #elseif PC_PROG + RegisterMenuVarBool( "ORIGIN_isEnabled", false ) + RegisterMenuVarBool( "ORIGIN_isJoinable", false ) + #endif + + thread UpdateFocus() + thread UpdateIsConnected() + thread UpdateIsFullyConnected() + thread UpdateAmIPartyLeader() + thread UpdateIsPrivateMatch() + thread UpdateActiveMenuThink() + + #if CONSOLE_PROG + thread UpdateConsole_IsOnline() + thread UpdateConsole_IsSignedIn() + #endif // CONSOLE_PROG + + #if DURANGO_PROG + thread UpdateDurango_IsGameFullyInstalled() + thread UpdateDurango_CanInviteFriends() + thread UpdateDurango_IsJoinable() + #elseif PS4_PROG + thread UpdatePS4_CanInviteFriends() + #elseif PC_PROG + thread UpdateOrigin_IsEnabled() + thread UpdateOrigin_IsJoinable() + thread UpdateIsGamepadActive() + #endif +} + +void function UpdateFocus() +{ + while ( true ) + { + SetMenuVarVar( "focus", GetFocus() ) + WaitFrame() + } +} + +void function UpdateActiveMenuThink() +{ + while ( true ) + { + var menu = GetActiveMenu() + if ( menu ) + { + Assert( menu in uiGlobal.menuData ) + if ( uiGlobal.menuData[ menu ].thinkFunc != null ) + uiGlobal.menuData[ menu ].thinkFunc() + } + + WaitFrame() + } +} + +void function UpdateIsConnected() +{ + while ( true ) + { + SetMenuVarBool( "isConnected", IsConnected() ) + WaitFrame() + } +} + +void function UpdateIsFullyConnected() +{ + while ( true ) + { + SetMenuVarBool( "isFullyConnected", IsFullyConnected() ) + WaitFrame() + } +} + +void function UpdateAmIPartyLeader() +{ + while ( true ) + { + SetMenuVarBool( "isPartyLeader", AmIPartyLeader() ) + WaitFrame() + } +} + +void function UpdateIsPrivateMatch() +{ + while ( true ) + { + SetMenuVarBool( "isPrivateMatch", IsPrivateMatch() ) + WaitFrame() + } +} + +#if CONSOLE_PROG + void function UpdateConsole_IsOnline() + { + while ( true ) + { + SetMenuVarBool( "CONSOLE_isOnline", Console_IsOnline() ) + WaitFrame() + } + } + + void function UpdateConsole_IsSignedIn() + { + while ( true ) + { + SetMenuVarBool( "CONSOLE_isSignedIn", Console_IsSignedIn() ) + WaitFrame() + } + } +#endif // CONSOLE_PROG + + +#if PS4_PROG + void function UpdatePS4_CanInviteFriends() + { + while ( true ) + { + SetMenuVarBool( "PS4_canInviteFriends", PS4_canInviteFriends() ) + WaitFrame() + } + } +#endif // PS4_PROG + + + +#if DURANGO_PROG + void function UpdateDurango_IsGameFullyInstalled() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_isGameFullyInstalled", IsGameFullyInstalled() ) + wait 1 // Poll less frequent + } + } + + void function UpdateDurango_CanInviteFriends() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_canInviteFriends", Durango_CanInviteFriends() ) + WaitFrame() + } + } + + void function UpdateDurango_IsJoinable() + { + while ( true ) + { + SetMenuVarBool( "DURANGO_isJoinable", Durango_IsJoinable() ) + WaitFrame() + } + } +#endif // DURANGO_PROG + +#if PC_PROG + void function UpdateOrigin_IsEnabled() + { + while ( true ) + { + SetMenuVarBool( "ORIGIN_isEnabled", Origin_IsEnabled() ) + WaitFrame() + } + } + + void function UpdateOrigin_IsJoinable() + { + while ( true ) + { + SetMenuVarBool( "ORIGIN_isJoinable", Origin_IsJoinable() ) + WaitFrame() + } + } + + void function UpdateIsGamepadActive() + { + while ( true ) + { + SetMenuVarBool( "isGamepadActive", IsControllerModeActive() ) + WaitFrame() + } + } +#endif // PC_PROG + +void function InviteFriends( var button ) +{ + //AdvanceMenu( GetMenu( "InviteFriendsToPartyMenu" ) ) + + #if DURANGO_PROG + Durango_InviteFriends() + #elseif PS4_PROG + ClientCommand("session_debug_invite"); + #elseif PC_PROG + Assert( Origin_IsEnabled() ) + Assert( Origin_IsJoinable() ) + + Origin_ShowInviteFriendsDialog() + #endif +} + +#if DURANGO_PROG +void function OpenXboxPartyApp( var button ) +{ + Durango_OpenPartyApp() +} + +void function OpenXboxHelp( var button ) +{ + Durango_ShowHelpWindow() +} +#endif // DURANGO_PROG + +void function OpenReviewTermsDialog( var button ) +{ + AdvanceMenu( GetMenu( "ReviewTermsDialog" ) ) +} + +void function OpenErrorDialog( string errorDetails ) +{ + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = errorDetails + dialogData.image = $"ui/menu/common/dialog_error" + +#if PC_PROG + AddDialogButton( dialogData, "#DISMISS" ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) +#endif // PC_PROG + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + while ( uiGlobal.activeMenu != GetMenu( "MainMenu" ) ) + { + WaitSignal( uiGlobal.signalDummy, "OpenErrorDialog", "ActiveMenuChanged" ) + } + + OpenDialog( dialogData ) +} + +bool function IsDialog( var menu ) +{ + if ( menu == null ) + return false + + return uiGlobal.menuData[ menu ].isDialog +} + +bool function IsDialogActive( DialogData dialogData ) +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return false + + return uiGlobal.menuData[ uiGlobal.activeMenu ].dialogData == dialogData +} + +bool function IsDialogOnlyActiveMenu() +{ + if ( !IsDialog( uiGlobal.activeMenu ) ) + return false + + int stackLen = uiGlobal.menuStack.len() + if ( stackLen < 1 ) + return false + + if ( uiGlobal.menuStack[stackLen - 1] != uiGlobal.activeMenu ) + return false + + if ( stackLen == 1 ) + return true + + if ( uiGlobal.menuStack[stackLen - 2] == null ) + return true + + return false +} + +void function SetNavUpDown( array buttons, var wrap = true ) +{ + Assert( buttons.len() > 0 ) + + var first = buttons[0] + var last = buttons[buttons.len() - 1] + var prev + var next + var button + + for ( int i = 0; i < buttons.len(); i++ ) + { + button = buttons[i] + + if ( button == first ) + prev = last + else + prev = buttons[i - 1] + + if ( button == last ) + next = first + else + next = buttons[i + 1] + + button.SetNavUp( prev ) + button.SetNavDown( next ) + + //printt( "SetNavUP for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( prev ) ) + //printt( "SetNavDown for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( next ) ) + } +} + +void function SetNavLeftRight( array buttons, var wrap = true ) +{ + Assert( buttons.len() > 0 ) + + var first = buttons[0] + var last = buttons[buttons.len() - 1] + var prev + var next + var button + + for ( int i = 0; i < buttons.len(); i++ ) + { + button = buttons[i] + + if ( button == first ) + prev = last + else + prev = buttons[i - 1] + + if ( button == last ) + next = first + else + next = buttons[i + 1] + + button.SetNavLeft( prev ) + button.SetNavRight( next ) + + //printt( "SetNavUP for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( prev ) ) + //printt( "SetNavDown for:", Hud_GetHudName( button ), "to:", Hud_GetHudName( next ) ) + } +} + +void function UICodeCallback_EntitlementsChanged() +{ + if ( uiGlobal.activeMenu == null ) + return + + if ( uiGlobal.menuData[ uiGlobal.activeMenu ].entitlementsChangedFunc != null ) + thread uiGlobal.menuData[ uiGlobal.activeMenu ].entitlementsChangedFunc() +} + +#if PC_PROG +void function QuitGame() +{ + ClientCommand( "quit" ) +} +#endif + +void function UICodeCallback_StoreTransactionCompleted() +{ + // this callback is only supported and needed on PS4 currently +#if PS4_PROG + if ( InStoreMenu() ) + OnOpenDLCStore() +#endif +} + +void function UICodeCallback_GamePurchased() +{ + // this callback is only supported and needed on PC currently +#if PC_PROG + DialogData dialogData + dialogData.header = "#PURCHASE_GAME_COMPLETE" + dialogData.message = "#PURCHASE_GAME_RESTART" + AddDialogButton( dialogData, "#QUIT", QuitGame ) + + OpenDialog( dialogData ) +#endif +} + +bool function IsTrialPeriodActive() +{ + return GetConVarBool( "trialPeriodIsActive" ) +} + +void function LaunchGamePurchaseOrDLCStore( array menuNames = [ "StoreMenu" ] ) +{ + if ( Script_IsRunningTrialVersion() ) + { + LaunchGamePurchase() + } + else + { + void functionref() preOpenFunc = null + + foreach ( menuName in menuNames ) + { + // Special case because this menu needs a few properties set before opening + if ( menuName == "StoreMenu_WeaponSkins" ) + { + preOpenFunc = DefaultToDLC11WeaponWarpaintBundle + break + } + } + + OpenStoreMenu( menuNames, preOpenFunc ) + } +} + +void function UICodeCallback_PartyUpdated() +{ + if ( AmIPartyLeader() ) + { + string activeSearchingPlaylist = GetActiveSearchingPlaylist() + if ( activeSearchingPlaylist != "" && !CanPlaylistFitMyParty( activeSearchingPlaylist ) ) + { + CancelMatchSearch() + + DialogData dialogData + dialogData.header = "#MATCHMAKING_CANCELED" + dialogData.message = "#MATCHMAKING_CANCELED_REASON_PARTY_SIZE" + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) + } + } +} + + +void function HACK_DelayedSetFocus_BecauseWhy( var item ) +{ + wait 0.1 + if ( IsValid( item ) ) + Hud_SetFocused( item ) +} + +void function ClassicMusic_OnChange( var button ) +{ + bool isEnabled = GetConVarBool( "sound_classic_music" ) + + if ( IsFullyConnected() && IsMultiplayer() && GetUIPlayer() ) + { + if ( IsItemLocked( GetUIPlayer(), "classic_music" ) ) + SetConVarBool( "sound_classic_music", false ) + + if ( IsLobby() ) + thread RunClientScript( "OnSoundClassicMusicChanged" ) + } +} + +bool function IsClassicMusicAvailable() +{ + bool classicMusicAvailable = false + if ( IsFullyConnected() && IsMultiplayer() && GetUIPlayer() ) + classicMusicAvailable = !IsItemLocked( GetUIPlayer(), "classic_music" ) + + return classicMusicAvailable +} + +void function UICodeCallback_KeyBindOverwritten( string key, string oldbinding, string newbinding ) +{ + DialogData dialogData + dialogData.header = Localize( "#MENU_KEYBIND_WAS_BEING_USED", key ) + dialogData.message = Localize( "#MENU_KEYBIND_WAS_BEING_USED_SUB", key, Localize( oldbinding ) ) + + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) +} -- cgit v1.2.3 From 967889c217bcea0a9edcfd5828febed45e31b0fd Mon Sep 17 00:00:00 2001 From: Masterliberty <94194459+Masterliberty@users.noreply.github.com> Date: Wed, 8 Mar 2023 19:49:26 -0500 Subject: Add Triple Threat animations (#599) * Add files via upload triple threat w anims --- .../atpov_titan_triple_threat_og.mdl | Bin 2402701 -> 756461 bytes .../w_titan_triple_threat_og.mdl | Bin 925524 -> 588501 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/atpov_titan_triple_threat_og.mdl b/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/atpov_titan_triple_threat_og.mdl index 7ea0d4da..f2dafaf1 100644 Binary files a/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/atpov_titan_triple_threat_og.mdl and b/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/atpov_titan_triple_threat_og.mdl differ diff --git a/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/w_titan_triple_threat_og.mdl b/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/w_titan_triple_threat_og.mdl index 1c338bcf..b955e1c0 100644 Binary files a/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/w_titan_triple_threat_og.mdl and b/Northstar.Custom/mod/models/weapons/titan_triple_threat_og/w_titan_triple_threat_og.mdl differ -- cgit v1.2.3 From e1215c96997a0f348285055998254ba064787af5 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:05:01 -0500 Subject: Add damage source IDs for custom Northstar weapons (#539) * Add custom IDs for custom northstar weapons * Update to use localization * Merge updated files * Fix missing text --- Northstar.Custom/mod.json | 5 +---- .../mod/resource/northstar_custom_english.txt | Bin 6318 -> 6446 bytes .../vscripts/sh_northstar_custom_precache.gnut | 10 ++++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index e81b197f..1f672ee4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -29,10 +29,7 @@ "Scripts": [ { "Path": "sh_northstar_custom_precache.gnut", - "RunOn": "( CLIENT || SERVER ) && MP", - "ClientCallback": { - "After": "NorthstarCustomPrecache" - }, + "RunOn": "SERVER && MP", "ServerCallback": { "After": "NorthstarCustomPrecache" } diff --git a/Northstar.Custom/mod/resource/northstar_custom_english.txt b/Northstar.Custom/mod/resource/northstar_custom_english.txt index 04a8d009..dbd3b106 100644 Binary files a/Northstar.Custom/mod/resource/northstar_custom_english.txt and b/Northstar.Custom/mod/resource/northstar_custom_english.txt differ diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut index 848a4b86..79e64684 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut @@ -1,4 +1,3 @@ -untyped global function NorthstarCustomPrecache void function NorthstarCustomPrecache() @@ -7,7 +6,10 @@ void function NorthstarCustomPrecache() PrecacheWeapon( "mp_titanweapon_triplethreat" ) PrecacheWeapon( "melee_pilot_kunai" ) - // create kunai damage source so game won't crash when we hit smth with it - // just using the default melee one, easier than making a new one - getconsttable()[ "eDamageSourceId" ][ "melee_pilot_kunai" ] <- eDamageSourceId.melee_pilot_emptyhanded + RegisterWeaponDamageSources( + { + mp_weapon_peacekraber = "#WPN_PEACEKRABER", + melee_pilot_kunai = "#MELEE_KUNAI" + } + ) } -- cgit v1.2.3 From b54e03852d3afa75b50abbc5eb0569c89dfc2783 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:57:13 -0500 Subject: Add support for entity final damage callbacks (#578) * Add support for entity final damage callbacks * Add final damage callback for non-Players/NPCs * Remove accidental duplicate code * Remove other unnecessary (duplicated) code * Implement uniboi suggestion --- .../scripts/vscripts/_codecallbacks_common.gnut | 29 ++++++++++++++++++++-- .../mod/scripts/vscripts/_entitystructs.gnut | 1 + .../mod/scripts/vscripts/mp/_codecallbacks.gnut | 14 +++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_codecallbacks_common.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_codecallbacks_common.gnut index d2621db3..3704b5cc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_codecallbacks_common.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_codecallbacks_common.gnut @@ -46,6 +46,8 @@ global function CodeCallback_OnEntityChangedTeam global function AddEntityCallback_OnDamaged global function RemoveEntityCallback_OnDamaged +global function AddEntityCallback_OnFinalDamaged +global function RemoveEntityCallback_OnFinalDamaged global function AddEntityCallback_OnPostDamaged global function RemoveEntityCallback_OnPostDamaged global function AddEntityCallback_OnKilled @@ -121,6 +123,13 @@ void function CodeCallback_DamageEntity( entity ent, var damageInfo ) printt( " after class damage final callbacks:", DamageInfo_GetDamage( damageInfo ) ) #endif + foreach ( callbackFunc in ent.e.entFinalDamageCallbacks ) + callbackFunc( ent, damageInfo ) + + #if VERBOSE_DAMAGE_PRINTOUTS + printt( " after AddEntityCallback_OnFinalDamaged callbacks:", DamageInfo_GetDamage( damageInfo ) ) + #endif + // make destructible vehicles take more damage from DF_EXPLOSION damage type if ( "isDestructibleVehicle" in ent.s && DamageInfo_GetCustomDamageType( damageInfo ) & DF_EXPLOSION ) { @@ -566,7 +575,23 @@ void function RemoveEntityCallback_OnDamaged( entity ent, void functionref( enti Assert( index != -1, "Requested DamageCallback " + string( callbackFunc ) + " to be removed not found! " ) ent.e.entDamageCallbacks.fastremove( index ) - if ( ent.e.entDamageCallbacks.len() == 0 && ent.e.entPostDamageCallbacks.len() == 0 ) + if ( ent.e.entDamageCallbacks.len() == 0 && ent.e.entFinalDamageCallbacks.len() == 0 && ent.e.entPostDamageCallbacks.len() == 0 ) + ent.SetDamageNotifications( false ) +} + +void function AddEntityCallback_OnFinalDamaged( entity ent, void functionref( entity ent, var damageInfo ) callbackFunc ) +{ + Assert( !ent.e.entFinalDamageCallbacks.contains( callbackFunc ), "Already added " + string( callbackFunc ) + " to entity" ) + + ent.SetDamageNotifications( true ) + ent.e.entFinalDamageCallbacks.append( callbackFunc ) +} + +void function RemoveEntityCallback_OnFinalDamaged( entity ent, void functionref( entity ent, var damageInfo ) callbackFunc ) +{ + ent.e.entFinalDamageCallbacks.fastremovebyvalue( callbackFunc ) + + if ( ent.e.entFinalDamageCallbacks.len() == 0 && ent.e.entPostDamageCallbacks.len() == 0 && ent.e.entDamageCallbacks.len() == 0 ) ent.SetDamageNotifications( false ) } @@ -585,7 +610,7 @@ void function RemoveEntityCallback_OnPostDamaged( entity ent, void functionref( Assert( index != -1, "Requested PostDamageCallback " + string( callbackFunc ) + " to be removed not found! " ) ent.e.entPostDamageCallbacks.fastremove( index ) - if ( ent.e.entPostDamageCallbacks.len() == 0 && ent.e.entDamageCallbacks.len() == 0 ) + if ( ent.e.entPostDamageCallbacks.len() == 0 && ent.e.entDamageCallbacks.len() == 0 && ent.e.entFinalDamageCallbacks.len() == 0 ) ent.SetDamageNotifications( false ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_entitystructs.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_entitystructs.gnut index 378ceae3..9dadea15 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_entitystructs.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_entitystructs.gnut @@ -232,6 +232,7 @@ global struct ServerEntityStruct SpawnPointData spawnPointData array entDamageCallbacks + array entFinalDamageCallbacks array entPostDamageCallbacks array entSegmentLostCallbacks array entPostShieldDamageCallbacks diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index 425a8b8b..ff281d6e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -283,9 +283,23 @@ void function CodeCallback_DamagePlayerOrNPC( entity ent, var damageInfo ) return RunClassDamageFinalCallbacks( ent, damageInfo ) + #if VERBOSE_DAMAGE_PRINTOUTS printt( " after class damage final callbacks:", DamageInfo_GetDamage( damageInfo ) ) #endif + if ( DamageInfo_GetDamage( damageInfo ) == 0 ) + return + + // Added via AddEntityCallback_OnFinalDamaged + foreach ( callbackFunc in ent.e.entFinalDamageCallbacks ) + { + callbackFunc( ent, damageInfo ) + } + + #if VERBOSE_DAMAGE_PRINTOUTS + printt( " afterAddEntityCallback_OnFinalDamaged callbacks:", DamageInfo_GetDamage( damageInfo ) ) + #endif + if ( DamageInfo_GetDamage( damageInfo ) == 0 ) return -- cgit v1.2.3 From 28d444c26a1da5496d1cf3f7610a261cd739ef73 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Fri, 10 Mar 2023 07:39:15 +0800 Subject: Hardpoint UI Fixes (#416) * fixed not showing Auto-Titans death in killfeed * bug fix * Hardpoint Fixes --- .../mod/scripts/vscripts/gamemodes/_gamemode_cp.nut | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index 705b7836..1bc42de0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -471,8 +471,10 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(cappingTeam==TEAM_UNASSIGNED) // nobody on point { - if((GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPED)||(GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPING)) + if((GetHardpointState(hardpoint)>=CAPTURE_POINT_STATE_AMPED) || (GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_SELF_UNAMPING)) { + if (GetHardpointState(hardpoint) == CAPTURE_POINT_STATE_AMPED) + SetHardpointState(hardpoint,CAPTURE_POINT_STATE_SELF_UNAMPING) // plays a pulsating effect on the UI only when the hardpoint is amped SetHardpointCappingTeam(hardpoint,hardpointEnt.GetTeam()) SetHardpointCaptureProgress(hardpoint,max(1.0,GetHardpointCaptureProgress(hardpoint)-(deltaTime/HARDPOINT_AMPED_DELAY))) if(GetHardpointCaptureProgress(hardpoint)<=1.001) // unamp @@ -546,8 +548,10 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(file.ampingEnabled)//amping or reamping { - if(GetHardpointState(hardpoint) Date: Sun, 12 Mar 2023 19:35:29 +0100 Subject: Bump version number (#602) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 3b236980..d52f95fc 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 0, "ConVars": [ { diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 1f672ee4..374e13e4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index f67aeb19..657854da 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.10.0", + "Version": "1.12.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From ec992d12ff07db58a6417671a23065ad774c96e1 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 29 Mar 2023 00:00:42 +0100 Subject: Bump compile check version to v3 (#603) Adds initscript support --- .github/workflows/compile-check.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-check.yml b/.github/workflows/compile-check.yml index b62c8313..cb7ab1d0 100644 --- a/.github/workflows/compile-check.yml +++ b/.github/workflows/compile-check.yml @@ -13,17 +13,18 @@ jobs: path: "mods" - name: Compile Scripts - uses: ASpoonPlaysGames/squirrel-re-compiler@v2 + uses: ASpoonPlaysGames/squirrel-re-compiler@v3 with: mods-directory: "${{ github.workspace }}/mods" native-json: "${{ github.workspace }}/mods/.github/nativefuncs.json" + # It's important that scripts compile when Northstar.Custom isn't enabled/installed, so run again without it - name: Remove Northstar.Custom run: rmdir ${{ github.workspace }}\mods\Northstar.Custom /s /q shell: cmd - name: Compile Scripts (No Northstar.Custom) - uses: ASpoonPlaysGames/squirrel-re-compiler@v2 + uses: ASpoonPlaysGames/squirrel-re-compiler@v3 with: mods-directory: "${{ github.workspace }}/mods" native-json: "${{ github.workspace }}/mods/.github/nativefuncs.json" -- cgit v1.2.3 From 80ceb2b317336c454d83392028501a31da89e77e Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 5 Apr 2023 01:25:35 +0200 Subject: Add menu_ingame.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/menu_ingame.nut | 693 +++++++++++++++++++++ 1 file changed, 693 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut new file mode 100644 index 00000000..03bd8959 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut @@ -0,0 +1,693 @@ +//global function InitLobbyStartMenu +global function InitInGameMPMenu +global function InitInGameSPMenu +global function ServerCallback_UI_ObjectiveUpdated +global function ServerCallback_UI_UpdateMissionLog +global function SP_ResetObjectiveStringIndex +global function SCB_SetDoubleXPStatus + +global function SCB_SetCompleteMeritState +global function SCB_SetEvacMeritState +global function SCB_SetMeritCount +global function SCB_SetScoreMeritState +global function SCB_SetWinMeritState +global function SCB_SetWeaponMeritCount +global function SCB_SetTitanMeritCount + +const DATA_TABLE = $"datatable/sp_difficulty.rpak" + +struct +{ + var menuMP + var menuSP + var BtnTrackedChallengeBackground + var BtnTrackedChallengeTitle + array trackedChallengeButtons + var BtnLastCheckpoint + int objectiveStringIndex + bool SP_displayObjectiveOnClose + var settingsHeader + var faqButton + int titanHeaderIndex + var titanHeader + var titanSelectButton + var titanEditButton + + ComboStruct &comboStruct + + array loadoutButtons + array loadoutHeaders +} file + +void function InitInGameMPMenu() +{ + var menu = GetMenu( "InGameMPMenu" ) + file.menuMP = menu + + SP_ResetObjectiveStringIndex() + file.SP_displayObjectiveOnClose = true + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnInGameMPMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnInGameMPMenu_Close ) + + AddUICallback_OnLevelInit( OnInGameLevelInit ) + + ComboStruct comboStruct = ComboButtons_Create( menu ) + + int headerIndex = 0 + int buttonIndex = 0 + var pilotHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PILOT" ) + file.loadoutHeaders.append( pilotHeader ) + var pilotSelectButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#SELECT" ) + Hud_AddEventHandler( pilotSelectButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "PilotLoadoutsMenu" ) ) ) + file.loadoutButtons.append( pilotSelectButton ) + var pilotEditButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#EDIT" ) + Hud_AddEventHandler( pilotEditButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditPilotLoadoutsMenu" ) ) ) + file.loadoutButtons.append( pilotEditButton ) + + headerIndex++ + buttonIndex = 0 + var titanHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_TITAN" ) + file.titanHeader = titanHeader + file.titanHeaderIndex = headerIndex + file.loadoutHeaders.append( titanHeader ) + var titanSelectButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#SELECT" ) + file.titanSelectButton = titanSelectButton + file.loadoutButtons.append( titanSelectButton ) + Hud_AddEventHandler( titanSelectButton, UIE_CLICK, TitanSelectButtonHandler ) + var titanEditButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#EDIT" ) + Hud_AddEventHandler( titanEditButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "EditTitanLoadoutsMenu" ) ) ) + file.titanEditButton = titanEditButton + file.loadoutButtons.append( titanEditButton ) + + headerIndex++ + buttonIndex = 0 + var gameHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_GAME" ) + var leaveButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#LEAVE_MATCH" ) + Hud_AddEventHandler( leaveButton, UIE_CLICK, OnLeaveButton_Activate ) + #if DEV + var devButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Dev" ) + Hud_AddEventHandler( devButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "DevMenu" ) ) ) + #endif + + headerIndex++ + buttonIndex = 0 + var dummyHeader = AddComboButtonHeader( comboStruct, headerIndex, "" ) + var dummyButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "" ) + Hud_SetVisible( dummyHeader, false ) + Hud_SetVisible( dummyButton, false ) + + headerIndex++ + buttonIndex = 0 + file.settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + #if CONSOLE_PROG + var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) + Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) + #elseif PC_PROG + var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) + Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) + var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) + Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) + #endif + + file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) + Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) + + //var dataCenterButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#DATA_CENTER" ) + //Hud_AddEventHandler( dataCenterButton, UIE_CLICK, OpenDataCenterDialog ) + + ComboButtons_Finalize( comboStruct ) + + file.comboStruct = comboStruct + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_CLOSE", "#CLOSE" ) +} + +void function OnInGameMPMenu_Open() +{ + Lobby_SetFDMode( GetCurrentPlaylistVarInt( "ingame_menu_fd_mode", 0 ) == 1 ) + UI_SetPresentationType( ePresentationType.DEFAULT ) + + bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew ) + + UpdateLoadoutButtons() + RefreshCreditsAvailable() + thread UpdateCachedNewItems() +} + +void function OnInGameMPMenu_Close() +{ + UI_SetPresentationType( ePresentationType.INACTIVE ) + + if ( IsConnected() && !IsLobby() && IsLevelMultiplayer( GetActiveLevel() ) ) + { + //printt( "OnInGameMPMenu_Close() uiGlobal.updatePilotSpawnLoadout is:", uiGlobal.updatePilotSpawnLoadout ) + //printt( "OnInGameMPMenu_Close() uiGlobal.updateTitanSpawnLoadout is:", uiGlobal.updateTitanSpawnLoadout ) + + string updatePilotSpawnLoadout = uiGlobal.updatePilotSpawnLoadout ? "1" : "0" + string updateTitanSpawnLoadout = uiGlobal.updateTitanSpawnLoadout ? "1" : "0" + + ClientCommand( "InGameMPMenuClosed " + updatePilotSpawnLoadout + " " + updateTitanSpawnLoadout ) + + uiGlobal.updatePilotSpawnLoadout = false + uiGlobal.updateTitanSpawnLoadout = false + + RunClientScript( "RefreshIntroLoadoutDisplay", GetLocalClientPlayer(), uiGlobal.pilotSpawnLoadoutIndex, uiGlobal.titanSpawnLoadoutIndex ) + } +} + +void function UpdateLoadoutButtons() +{ + bool loadoutSelectionEnabled = (GetCurrentPlaylistVarInt( "loadout_selection_enabled", 1 ) == 1) + + SetTitanSelectButtonVisibleState( true ) + + foreach ( button in file.loadoutButtons ) + { + Hud_SetEnabled( button, loadoutSelectionEnabled ) + } + + foreach ( header in file.loadoutHeaders ) + { + if ( loadoutSelectionEnabled ) + Hud_Show( header ) + else + Hud_Hide( header ) + } + + entity player = GetUIPlayer() + + if ( GetAvailableTitanRefs( player ).len() > 1 ) + { + SetComboButtonHeaderTitle( file.menuMP, file.titanHeaderIndex, "#MENU_HEADER_TITAN" ) + ComboButton_SetText( file.titanSelectButton, "#SELECT" ) + Hud_Show( file.titanEditButton ) + } + else if ( GetAvailableTitanRefs( player ).len() == 1 ) + { + TitanLoadoutDef loadout = GetCachedTitanLoadout( uiGlobal.titanSpawnLoadoutIndex ) + + SetComboButtonHeaderTitle( file.menuMP, file.titanHeaderIndex, GetTitanLoadoutName( loadout ) ) + ComboButton_SetText( file.titanSelectButton, "#EDIT" ) + + Hud_Hide( file.titanEditButton ) + ComboButtons_ResetColumnFocus( file.comboStruct ) + } + else + { + SetTitanSelectButtonVisibleState( true ) + } +} + +////////// + +////////// + +void function InitInGameSPMenu() +{ + var menu = GetMenu( "InGameSPMenu" ) + file.menuSP = menu + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnOpenInGameSPMenu ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnCloseInGameSPMenu ) + + ComboStruct comboStruct = ComboButtons_Create( menu ) + + int headerIndex = 0 + int buttonIndex = 0 + + // MISSION Menu + var missionHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_MISSION" ) + var resumeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#RESUME_GAME_SHORT" ) + Hud_AddEventHandler( resumeButton, UIE_CLICK, OnResumeGame_Activate ) + var lastCheckpointButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#LAST_CHECKPOINT" ) + Hud_AddEventHandler( lastCheckpointButton, UIE_CLICK, OnReloadCheckpoint_Activate ) + file.BtnLastCheckpoint = lastCheckpointButton + var restartButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#RESTART_LEVEL_SHORT" ) + Hud_AddEventHandler( restartButton, UIE_CLICK, OnRestartLevel_Activate ) + + // GAME Menu + // headerIndex++ + // buttonIndex = 0 + // var gameHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_GAME" ) + // var difficultyButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CHANGE_DIFFICULTY" ) + // Hud_AddEventHandler( difficultyButton, UIE_CLICK, OnChangeDifficulty_Activate ) + // var leaveButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#QUIT" ) + // Hud_AddEventHandler( leaveButton, UIE_CLICK, OnLeaveButton_Activate ) + + // SETTINGS Menu + headerIndex++ + buttonIndex = 0 + var settingsHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_SETTINGS" ) + var controlsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#CONTROLS" ) + Hud_AddEventHandler( controlsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ControlsMenu" ) ) ) + #if CONSOLE_PROG + var avButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO_VIDEO" ) + Hud_AddEventHandler( avButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioVideoMenu" ) ) ) + #elseif PC_PROG + var audioButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#AUDIO" ) + Hud_AddEventHandler( audioButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "AudioMenu" ) ) ) + var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) + Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) + #endif + + array orderedButtons + + var changeDifficultyBtn = Hud_GetChild( menu, "BtnChangeDifficulty" ) + + AddButtonEventHandler( changeDifficultyBtn, UIE_CLICK, OnChangeDifficulty_Activate ) + Hud_Show( changeDifficultyBtn ) + orderedButtons.append( changeDifficultyBtn ) + + var quitBtn = Hud_GetChild( menu, "BtnQuit" ) + SetButtonRuiText( quitBtn, "#QUIT" ) + AddButtonEventHandler( quitBtn, UIE_CLICK, OnLeaveButton_Activate ) + Hud_Show( quitBtn ) + orderedButtons.append( quitBtn ) + + // DEV button + var devButton = Hud_GetChild( menu, "BtnDev" ) + #if DEV + SetButtonRuiText( devButton, "--- Dev" ) + AddButtonEventHandler( devButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "DevMenu" ) ) ) + Hud_Show( devButton ) + orderedButtons.append( devButton ) + comboStruct.navUpButton = devButton + #else + Hud_Hide( devButton ) + comboStruct.navUpButton = quitBtn + #endif // DEV + + SetNavUpDown( orderedButtons ) + comboStruct.navDownButton = changeDifficultyBtn + + ComboButtons_Finalize( comboStruct ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_CLOSE", "#CLOSE" ) +} + + +void function OnOpenInGameSPMenu() +{ + var collectiblesFoundDesc = Hud_GetChild( file.menuSP, "CollectiblesFoundDesc" ) + var missionLogDesc = Hud_GetChild( file.menuSP, "MissionLogDesc" ) + var changeDifficultyBtn = Hud_GetChild( file.menuSP, "BtnChangeDifficulty" ) + + Hud_SetEnabled( file.BtnLastCheckpoint, HasValidSaveGame() ) + + int currentDifficulty = GetConVarInt( "sp_difficulty" ) + string newDifficultyString + + switch ( currentDifficulty ) + { + case 0: + newDifficultyString = "#CHANGE_DIFFICULTY_EASY" + break + + case 1: + newDifficultyString = "#CHANGE_DIFFICULTY_REGULAR" + break + + case 2: + newDifficultyString = "#CHANGE_DIFFICULTY_HARD" + break + + case 3: + newDifficultyString = "#CHANGE_DIFFICULTY_MASTER" + break + + default: + Assert( 0, "Unknown difficulty " + currentDifficulty ) + break + } + SetButtonRuiText( changeDifficultyBtn, newDifficultyString ) + + string activeLevelName = GetActiveLevel() + if ( activeLevelName != "" ) + { + var dataTable = GetDataTable( $"datatable/sp_levels_data.rpak" ) + + // Make sure this level actually has data to display. + bool levelHasData = false + int numRows = GetDatatableRowCount( dataTable ) + for ( int i = 0; i < numRows; i++ ) + { + string levelName = GetDataTableString( dataTable, i, GetDataTableColumnByName( dataTable, "level" ) ) + if ( activeLevelName == levelName ) + { + levelHasData = true + break + } + } + + if ( levelHasData ) + { + // Mission Log + int row = GetDataTableRowMatchingStringValue( dataTable, GetDataTableColumnByName( dataTable, "level" ), activeLevelName ) + string missionLog = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "missionLog" ) ) + + if ( uiGlobal.sp_showAlternateMissionLog ) + { + string alternateMissionLog = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "alternateMissionLog" ) ) + missionLog = alternateMissionLog + } + + Hud_SetText( missionLogDesc, missionLog ) + + // Collectibles + int foundLions = GetCollectiblesFoundForLevel( activeLevelName ) + int maxLions = GetMaxLionsInLevel( activeLevelName ) + Hud_SetText( collectiblesFoundDesc, "#MENU_SP_COLLECTIBLE_DESC", foundLions, maxLions ) + } + else + { + Hud_SetText( missionLogDesc, "#MENU_SP_OBJECTIVES_NO_ENTRY" ) + Hud_SetText( collectiblesFoundDesc, "#MENU_SP_COLLECTIBLE_DESC", 0, 0 ) + } + + // Make sure trial mode doesn't reveal any spoilers! + if ( Script_IsRunningTrialVersion() ) + Hud_SetText( missionLogDesc, "#MENU_SP_OBJECTIVES_NO_ENTRY" ) + } + + SPMenu_UpdateReloadCheckpointButton() +} + + +void function OnCloseInGameSPMenu() +{ + if ( file.SP_displayObjectiveOnClose ) + ClientCommand( "ShowObjective closedSPMenu" ) +} + +void function SPMenu_UpdateReloadCheckpointButton() +{ + if ( level.ui.playerRunningGauntlet ) + ComboButton_SetText( file.BtnLastCheckpoint, "#GAUNTLET_RESTART" ) + else + ComboButton_SetText( file.BtnLastCheckpoint, "#LAST_CHECKPOINT" ) +} + +void function MobilityDifficultyButton_Activate( var button ) +{ + OpenMobilityDifficultyMenu() +} + +void function OnLeaveButton_Activate( var button ) +{ + file.SP_displayObjectiveOnClose = false + LeaveDialog() +} + +void function OnRestartLevel_Activate( var button ) +{ + ShowAreYouSureDialog( "#MENU_RESTART_MISSION_CONFIRM", RestartMission, "#WARNING_LOSE_PROGRESS" ) +} + +void function OnChangeDifficulty_Activate( var button ) +{ + SPDifficultyButton_Click( button ) +} + +void function OnResumeGame_Activate( var button ) +{ + CloseActiveMenu() +} + +void function OnReloadCheckpoint_Activate( var button ) +{ + if ( level.ui.playerRunningGauntlet ) + { + CloseActiveMenu() + ClientCommand( "Gauntlet_PlayerRestartedFromMenu" ) + } + else + { + ShowAreYouSureDialog( "#MENU_RESTART_CHECKPOINT_CONFIRM", ReloadLastCheckpoint, "#EMPTY_STRING" ) + } +} + +void function ShowAreYouSureDialog( string header, void functionref() func, string details ) +{ + DialogData dialogData + dialogData.header = header + dialogData.message = details + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", func ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) +} + +void function RestartMission() +{ + file.SP_displayObjectiveOnClose = false + ClientCommand( "RestartMission" ) +} + +void function ReloadLastCheckpoint() +{ + file.SP_displayObjectiveOnClose = false + + printt( "SAVEGAME: Trying to load saveName" ) + if ( HasValidSaveGame() ) + { + printt( "SAVEGAME: Trying to load checkpoint from menu_ingame" ) + SaveGame_LoadWithStartPointFallback() + return + } + + ClientCommand( "RestartFromLevelTransition" ) +} + +void function SP_ResetObjectiveStringIndex() +{ + file.objectiveStringIndex = -1 +} + +void function ServerCallback_UI_ObjectiveUpdated( int stringIndex ) +{ + file.objectiveStringIndex = stringIndex +} + +void function ServerCallback_UI_UpdateMissionLog( bool showAltLog ) +{ + uiGlobal.sp_showAlternateMissionLog = showAltLog +} + +void function SPDifficultyButton_Click( var button ) +{ + DialogData dialogData + dialogData.header = "#SP_DIFFICULTY_MISSION_SELECT_TITLE" + + int currentDifficulty = GetConVarInt( "sp_difficulty" ) + dialogData.coloredButton[ currentDifficulty ] <- true + + if ( currentDifficulty == DIFFICULTY_EASY ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_EASY_TITLE", SPPickEasy, "#SP_DIFFICULTY_EASY_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_EASY_TITLE", SPPickEasy, "#SP_DIFFICULTY_EASY_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_NORMAL ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_NORMAL_TITLE", SPPickNormal, "#SP_DIFFICULTY_NORMAL_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_NORMAL_TITLE", SPPickNormal, "#SP_DIFFICULTY_NORMAL_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_HARD ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_HARD_TITLE", SPPickHard, "#SP_DIFFICULTY_HARD_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_HARD_TITLE", SPPickHard, "#SP_DIFFICULTY_HARD_DESCRIPTION", false ) + + + if ( currentDifficulty == DIFFICULTY_MASTER ) + AddDialogButton( dialogData, "#SP_DIFFICULTY_MASTER_TITLE", SPPickMaster, "#SP_DIFFICULTY_MASTER_DESCRIPTION", true ) + else + AddDialogButton( dialogData, "#SP_DIFFICULTY_MASTER_TITLE", SPPickMaster, "#SP_DIFFICULTY_MASTER_DESCRIPTION", false ) + + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + AddDialogPCBackButton( dialogData ) + + OpenDialog( dialogData ) +} + +void function SPPickEasy() +{ + RequestSPDifficultyChange( DIFFICULTY_EASY ) + CloseAllMenus() +} + +void function SPPickNormal() +{ + RequestSPDifficultyChange( DIFFICULTY_NORMAL ) + CloseAllMenus() +} + +void function SPPickHard() +{ + RequestSPDifficultyChange( DIFFICULTY_HARD ) + CloseAllMenus() +} + +void function SPPickMaster() +{ + RequestSPDifficultyChange( DIFFICULTY_MASTER ) + CloseAllMenus() +} + +void function RequestSPDifficultyChange( int selectedDifficulty ) +{ + var dataTable = GetDataTable( DATA_TABLE ) + int difficulty = GetDataTableInt( dataTable, selectedDifficulty, GetDataTableColumnByName( dataTable, "index" ) ) + + ClientCommand( "ClientCommand_RequestSPDifficultyChange " + difficulty ) +} + +void function SCB_SetDoubleXPStatus( int status ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + RuiSetInt( Hud_GetRui( doubleXPWidget ), "doubleXPStatus", status ) + + // update this menu too + TTSUpdateDoubleXPStatus( status ) +} + +void function OnInGameLevelInit() +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + RuiSetInt( rui, "doubleXPStatus", 0 ) + RuiSetBool( rui, "isVisible", false ) + + string gameModeScoreHint = expect string( GetCurrentPlaylistVar( "gamemode_score_hint" ) ) + if ( gameModeScoreHint != "" ) + { + RuiSetString( rui, "scoreMeritText", Localize( gameModeScoreHint ) ) + RuiSetInt( rui, "matchScoreMerit", MERIT_STATE_AVAILABLE ) + } + else + { + RuiSetString( rui, "scoreMeritText", "" ) + RuiSetInt( rui, "matchScoreMerit", MERIT_STATE_HIDDEN ) + } + + Hud_SetVisible( doubleXPWidget, !IsPrivateMatch() ) +} +/* +int matchScoreMerit = MERIT_STATE_AVAILABLE +int matchCompleteMerit = MERIT_STATE_AVAILABLE +int matchWinMerit = MERIT_STATE_AVAILABLE +int matchEvacMerit = MERIT_STATE_HIDDEN +int happyHourMerits = MERIT_STATE_HIDDEN + +int meritCount = 0 +*/ + +void function SCB_SetScoreMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchScoreMerit", meritState ) +} + +void function SCB_SetCompleteMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchCompleteMerit", meritState ) +} + +void function SCB_SetWinMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchWinMerit", meritState ) +} + +void function SCB_SetEvacMeritState( int meritState ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "matchEvacMerit", meritState ) +} + +void function SCB_SetMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "meritCount", meritCount ) +} + +void function SCB_SetWeaponMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "weaponMeritCount", meritCount ) +} + +void function SCB_SetTitanMeritCount( int meritCount ) +{ + var doubleXPWidget = Hud_GetChild( file.menuMP, "DoubleXP" ) + var rui = Hud_GetRui( doubleXPWidget ) + + RuiSetInt( rui, "titanMeritCount", meritCount ) +} + +void function TitanSelectButtonHandler( var button ) +{ + if ( !IsFullyConnected() ) + return + + entity player = GetUIPlayer() + if ( GetAvailableTitanRefs( player ).len() > 1 ) + { + AdvanceMenu( GetMenu( "TitanLoadoutsMenu" ) ) + } + else if ( GetAvailableTitanRefs( player ).len() == 1 ) + { + uiGlobal.updateTitanSpawnLoadout = false + SetEditLoadout( "titan", uiGlobal.titanSpawnLoadoutIndex ) + + RunMenuClientFunction( "SetEditingTitanLoadoutIndex", uiGlobal.titanSpawnLoadoutIndex ) + AdvanceMenu( GetMenu( "EditTitanLoadoutMenu" ) ) + } + else + { + // HIDE + } +} + +void function SetTitanSelectButtonVisibleState( bool state ) +{ + if ( state ) + { + Hud_Show( file.titanHeader ) + Hud_Show( file.titanEditButton ) + Hud_Show( file.titanSelectButton ) + } + else + { + ComboButtons_ResetColumnFocus( file.comboStruct ) + Hud_Hide( file.titanHeader ) + Hud_Hide( file.titanEditButton ) + Hud_Hide( file.titanSelectButton ) + } +} -- cgit v1.2.3 From 7ec5413c0e71300814350164c69e6452136bd4cd Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Thu, 6 Apr 2023 00:28:09 +0200 Subject: Add CI logic for finding missing translations (#608) * build: add script to get missing keys per language * fix: typo * fix: check arguments before launching script * feat: script can be run with language argument * docs: add readme * fix: remove multiple spaces while searching for translations * build: add translations check CI * refactor: put translation job alongside encoding job * feat: add unicode characters because why not * build: exit with an error code if some translations are missing * build: exit using process.exit * feat: CI should continue running with missing translations * build: use actions/checkout v3 * refactor: put build directory into .github directory --- .github/build/README.md | 28 +++++++++++++ .github/build/find-missing-translations.js | 66 ++++++++++++++++++++++++++++++ .github/workflows/encoding.yml | 8 ++++ 3 files changed, 102 insertions(+) create mode 100644 .github/build/README.md create mode 100644 .github/build/find-missing-translations.js diff --git a/.github/build/README.md b/.github/build/README.md new file mode 100644 index 00000000..84d479a3 --- /dev/null +++ b/.github/build/README.md @@ -0,0 +1,28 @@ +# Finding missing translations + +This package contains a script that detects missing translation keys in Titanfall2 translation files contained in this repository (in the `Northstar.Client/mod/resource` folder). + +It uses english translations file as reference. + +You have to launch it **from the repository root folder**: +```shell +node .github/build/find-missing-translations.js +``` +The script will then list all missing translations for all supported languages. + +If you want to display missing keys for a given language, just add it as an argument: +```shell +node .github/build/find-missing-translations.js french +``` + +Here's the list of supported languages: +* english +* french +* german +* italian +* japanese +* mspanish +* portuguese +* russian +* spanish +* tchinese \ No newline at end of file diff --git a/.github/build/find-missing-translations.js b/.github/build/find-missing-translations.js new file mode 100644 index 00000000..3f6c6c99 --- /dev/null +++ b/.github/build/find-missing-translations.js @@ -0,0 +1,66 @@ +const fs = require('fs'); +const { exit } = require('process'); +const langPath = "Northstar.Client/mod/resource"; +const knownLanguages = ['english', 'french', 'german', 'italian', 'japanese', 'mspanish', 'portuguese', 'russian', 'spanish', 'tchinese']; + + +// Proceed checks before launch +if (![2,3].includes(process.argv.length)) { + console.error('Wrong number of arguments, either call this script with no argument, or with a language.'); + return; +} +const inputLang = process.argv[2]; +if (process.argv.length === 3 && !knownLanguages.includes(inputLang)) { + console.error(`"${inputLang}" is not a valid language.\nValid languages are: ${knownLanguages}`); + return; +} + + +// Get language files names +const langs = fs.readdirSync(langPath) + .filter(lang => lang.indexOf('northstar_client_localisation_') !== -1); + + +function getLanguageKeys (lang) { + if (knownLanguages.indexOf(lang) === -1) return; + return fs.readFileSync(`${langPath}/northstar_client_localisation_${lang}.txt`, {encoding:'utf16le', flag:'r'}) + .split('\n') + .filter(line => line.length !== 0) // remove empty lines + .map(line => line.replaceAll(/\s+/g, ' ').trim()) // remove multiple spaces + .map(line => line.replaceAll('\t', '')) // remove tabs characters + + // keep only lines with translation keys + .filter(line => { + const words = line.split('" "'); + return words.length === 2 && words[1] !== 'english"' + }) + .map(line => line.split('" "')[0].substring(1)); // only keep translation keys (throw values) +} + +// We use english keys as reference for other languages +const englishKeys = getLanguageKeys('english'); +const inputLanguages = inputLang !== undefined ? ["", inputLang] : [...knownLanguages]; +inputLanguages.shift(); + +// Check for each language if there are missing keys +var missingKeysCount = 0; + +for (const language of inputLanguages) { + const languageKeys = getLanguageKeys(language); + const missingKeys = [...englishKeys] // clone + .filter(key => languageKeys.indexOf(key) === -1); + const missingKeysLength = missingKeys.length; + console.log( + missingKeysLength === 0 + ? `✔️ "${language}" doesn't have missing keys.` + : `❌ "${language}" has ${missingKeys.length} missing key${missingKeys.length === 1 ? '' : 's'}:` + ); + + if (missingKeysLength !== 0) { + console.log(missingKeys); + missingKeysCount += missingKeys.length; + } +} + +process.exitCode = missingKeysCount; +exit(); diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index ac63e784..bafdb15b 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -11,3 +11,11 @@ jobs: run: | files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) IFS=$'\n'; files=($files); unset IFS; ! file --mime "${files[@]}" | grep -v "charset=utf-16le" + check-missing-translations: + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Look out for missing translations + run: node .github/build/find-missing-translations.js + continue-on-error: true -- cgit v1.2.3 From db2434b524c284913c91556c75ff1ebd4226c96e Mon Sep 17 00:00:00 2001 From: Emma Miler Date: Tue, 11 Apr 2023 20:49:35 +0200 Subject: New presence code for plugins v2 (#532) * test * Update cl_presence.nut * Update Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut * Apply suggestions from code review * New scripts * fix playlist and add native funcs to build * remove snake cases from GameStateStruct * I forgor --------- Co-authored-by: cat_or_not <41955154+catornot@users.noreply.github.com> --- .github/nativefuncs.json | 12 +++ Northstar.Client/mod.json | 1 + .../scripts/vscripts/cl_northstar_client_init.nut | 22 +++++ .../mod/scripts/vscripts/presence/cl_presence.nut | 95 +++++++++------------- .../mod/scripts/vscripts/presence/ui_presence.nut | 42 ++-------- .../mod/scripts/vscripts/ui/_menus.nut | 2 + .../mod/scripts/vscripts/ui/menu_lobby.nut | 2 - .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 12 --- 8 files changed, 85 insertions(+), 103 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 50bba0e5..f52a969c 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -325,6 +325,12 @@ "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", "returnTypeString":"bool", "argTypes":"" + }, + { + "name":"NSPushGameStateData", + "helpText":"", + "returnTypeString":"void", + "argTypes":"struct gamestate" } ], "UI":[ @@ -639,6 +645,12 @@ "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", "returnTypeString":"bool", "argTypes":"" + }, + { + "name":"NSPushUIPresence", + "helpText":"", + "returnTypeString":"void", + "argTypes":"struct presence" } ] } \ No newline at end of file diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index d52f95fc..f0f45e67 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -3,6 +3,7 @@ "Description": "Various ui and client changes to fix bugs and add better support for mods", "Version": "1.12.0", "LoadPriority": 0, + "InitScript": "cl_northstar_client_init.nut", "ConVars": [ { "Name": "filter_hide_empty", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut new file mode 100644 index 00000000..212568d0 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -0,0 +1,22 @@ +global struct GameStateStruct { + + string map + string mapDisplayname + + string playlist + string playlistDisplayname + + int currentPlayers + int maxPlayers + int ownScore + int otherHighestScore + int maxScore + float timeEnd +} + +global struct UIPresenceStruct { + bool isLoading + bool isLobby + string loadingLevel + string loadedLevel +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut index 755396e3..c8a8274a 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut @@ -1,60 +1,45 @@ untyped globalize_all_functions -struct { - int highestScore = 0 - int secondHighestScore = 0 -} file - -void function OnPrematchStart() -{ - if ( GetServerVar( "roundBased" ) ) - NSUpdateTimeInfo( level.nv.roundEndTime - Time() ) - else - NSUpdateTimeInfo( level.nv.gameEndTime - Time() ) -} - -void function NSUpdateGameStateClientStart() -{ - #if MP - AddCallback_GameStateEnter( eGameState.Prematch, OnPrematchStart ) - #endif - - thread NSUpdateGameStateLoopClient() - OnPrematchStart() -} - -void function NSUpdateGameStateLoopClient() -{ - while ( true ) +void function NorthstarCodeCallback_GenerateGameState() { + + GameStateStruct gs + + int highestScore = 0 + int secondHighest = 0 + + foreach ( player in GetPlayerArray() ) { - if ( IsSingleplayer() ) - { - NSUpdateGameStateClient( GetPlayerArray().len(), GetCurrentPlaylistVarInt( "max_players", 65535 ), 1, 1, 1, GetServerVar( "roundBased" ), 1 ) - wait 1.0 - } - else - { - foreach ( player in GetPlayerArray() ) - { - if ( GameRules_GetTeamScore( player.GetTeam() ) >= file.highestScore ) - { - file.highestScore = GameRules_GetTeamScore( player.GetTeam() ) - } - else if ( GameRules_GetTeamScore( player.GetTeam() ) > file.secondHighestScore ) - { - file.secondHighestScore = GameRules_GetTeamScore( player.GetTeam() ) - } - } - - int ourScore = 0 - if ( IsValid( GetLocalClientPlayer() ) ) - ourScore = GameRules_GetTeamScore( GetLocalClientPlayer().GetTeam() ) - - int limit = IsRoundBased() ? GetCurrentPlaylistVarInt( "roundscorelimit", 0 ) : GetCurrentPlaylistVarInt( "scorelimit", 0 ) - NSUpdateGameStateClient( GetPlayerArray().len(), GetCurrentPlaylistVarInt( "max_players", 65535 ), ourScore, file.secondHighestScore, file.highestScore, GetServerVar( "roundBased" ), limit ) - OnPrematchStart() - wait 1.0 - } + if ( GameRules_GetTeamScore( player.GetTeam() ) >= highestScore ) + { + highestScore = GameRules_GetTeamScore( player.GetTeam() ) + } + else if ( GameRules_GetTeamScore( player.GetTeam() ) > secondHighest ) + { + secondHighest = GameRules_GetTeamScore( player.GetTeam() ) + } } -} + + gs.map = GetMapName() + gs.mapDisplayname = Localize(GetMapDisplayName(GetMapName())) + + gs.playlist = GetCurrentPlaylistName() + gs.playlistDisplayname = Localize(GetCurrentPlaylistVarString("name", GetCurrentPlaylistName())) + + gs.currentPlayers = GetPlayerArray().len() + gs.maxPlayers = GetCurrentPlaylistVarInt( "maxPlayers", -1 ) + + if ( IsValid( GetLocalClientPlayer() ) ) + gs.ownScore = GameRules_GetTeamScore( GetLocalClientPlayer().GetTeam() ) + + gs.otherHighestScore = gs.ownScore == highestScore ? secondHighest : highestScore + + gs.maxScore = IsRoundBased() ? GetCurrentPlaylistVarInt( "roundscorelimit", 0 ) : GetCurrentPlaylistVarInt( "scorelimit", 0 ) + + if ( GetServerVar( "roundBased" ) ) + gs.timeEnd = expect float(level.nv.roundEndTime - Time()) + else + gs.timeEnd = expect float(level.nv.gameEndTime - Time()) + + NSPushGameStateData(gs) +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut index 1e381989..cdf1c981 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut @@ -1,38 +1,12 @@ untyped globalize_all_functions -void function NSUpdateGameStateUIStart() -{ - thread NSUpdateGameStateLoopUI() -} +void function NorthstarCodeCallback_GenerateUIPresence() { + UIPresenceStruct uis -void function NSUpdateGameStateLoopUI() -{ - while ( true ) - { - wait 1.0 - - if ( uiGlobal.loadedLevel == "" ) - { - if ( uiGlobal.isLoading ) - NSSetLoading( true ) - else - { - NSSetLoading( false ) - NSUpdateGameStateUI( "", "", "", "", true, false ) - } - - continue - } - - NSSetLoading( false ) - if( GetConVarString( "mp_gamemode" ) == "solo" ) - { - NSUpdateGameStateUI( GetActiveLevel(), Localize( GetMapDisplayName( GetActiveLevel() + "_CAMPAIGN_NAME" ) ), "Campaign", "Campaign", IsFullyConnected(), false ) - } - else - { - NSUpdateGameStateUI( GetActiveLevel(), Localize( GetMapDisplayName( GetActiveLevel() ) ), GetConVarString( "mp_gamemode" ), Localize( GetPlaylistDisplayName( GetConVarString( "mp_gamemode" ) ) ), IsFullyConnected(), false ) - } - } -} + uis.isLoading = uiGlobal.isLoading + uis.isLobby = IsLobby() + uis.loadingLevel = uiGlobal.loadingLevel + uis.loadedLevel = uiGlobal.loadedLevel + NSPushUIPresence(uis) +} \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut index 90a535ee..c83381fd 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/_menus.nut @@ -187,6 +187,7 @@ bool function UICodeCallback_LevelLoadingStarted( string levelname ) CloseAllDialogs() uiGlobal.loadingLevel = levelname + uiGlobal.isLoading = true StopMusic() @@ -235,6 +236,7 @@ void function UICodeCallback_LevelLoadingFinished( bool error ) } uiGlobal.loadingLevel = "" + uiGlobal.isLoading = false Signal( uiGlobal.signalDummy, "LevelFinishedLoading" ) } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 938e0d3f..3c868aab 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -372,8 +372,6 @@ void function StartPrivateMatch( var button ) return ClientCommand( "StartPrivateMatchSearch" ) - NSSetLoading(true) - NSUpdateListenServer() } void function DoRoomInviteIfAllowed( var button ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 03028255..b2e2a8b6 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1058,18 +1058,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) } file.cancelConnection = false - NSSetLoading( true ) - NSUpdateServerInfo( - NSGetServerID( file.lastSelectedServer ), - NSGetServerName( file.lastSelectedServer ), - password, - NSGetServerPlayerCount( file.lastSelectedServer ), - NSGetServerMaxPlayerCount( file.lastSelectedServer ), - NSGetServerMap( file.lastSelectedServer ), - Localize( GetMapDisplayName( NSGetServerMap( file.lastSelectedServer ) ) ), - NSGetServerPlaylist( file.lastSelectedServer ), - Localize( GetPlaylistDisplayName( NSGetServerPlaylist( file.lastSelectedServer ) ) ) - ) if ( NSWasAuthSuccessful() ) { -- cgit v1.2.3 From 16656ea022f943e1ab4848a83578f4f75afce676 Mon Sep 17 00:00:00 2001 From: ScureX <47725553+ScureX@users.noreply.github.com> Date: Fri, 14 Apr 2023 14:54:27 +0200 Subject: lolololol server crasher hehe hooo (#614) * why dont we have this fucking file * the actual fix * why is it fukcing formatted liek taht --- .../mod/scripts/vscripts/sh_store.gnut | 933 +++++++++++++++++++++ 1 file changed, 933 insertions(+) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/sh_store.gnut diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_store.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_store.gnut new file mode 100644 index 00000000..371cc1c7 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_store.gnut @@ -0,0 +1,933 @@ + +global function Store_Init +global function Store_GetCustomizationRefs +global function Store_GetPatchRefs +global function Store_GetBannerRefs +global function Store_GetCamoRefs + +global struct CamoRef +{ + string ref + string pilotRef + string titanRef +} + +struct RefData +{ + string ref + string parentRef +} + +struct +{ + table< int, array > customizationRefs + table< int, array > patchRefs + table< int, array > bannerRefs + table< int, array > camoRefs + table< int, array > limitedEditionFDRefData +} file + +void function Store_Init() +{ + #if SERVER + AddClientCommandCallback( "SetHasSeenStore", ClientCommand_SetHasSeenStore ) + AddClientCommandCallback( "StoreSetNewItemStatus", ClientCommand_StoreSetNewItemStatus ) + #endif + + file.customizationRefs[ ET_DLC1_ION ] <- [] + file.customizationRefs[ ET_DLC1_ION ].append( "ion_skin_10" ) + file.customizationRefs[ ET_DLC1_ION ].append( "ion_nose_art_17" ) + file.customizationRefs[ ET_DLC1_ION ].append( "ion_nose_art_18" ) + file.customizationRefs[ ET_DLC1_ION ].append( "ion_nose_art_19" ) + file.customizationRefs[ ET_DLC1_ION ].append( "ion_nose_art_20" ) + file.customizationRefs[ ET_DLC1_ION ].append( "ion_nose_art_21" ) + file.customizationRefs[ ET_DLC3_ION ] <- [] + file.customizationRefs[ ET_DLC3_ION ].append( "ion_skin_11" ) + file.customizationRefs[ ET_DLC3_ION ].append( "ion_nose_art_22" ) + file.customizationRefs[ ET_DLC3_ION ].append( "ion_nose_art_23" ) + file.customizationRefs[ ET_DLC3_ION ].append( "ion_nose_art_24" ) + file.customizationRefs[ ET_DLC3_ION ].append( "ion_nose_art_25" ) + file.customizationRefs[ ET_DLC3_ION ].append( "ion_nose_art_26" ) + file.customizationRefs[ ET_DLC5_ION ] <- [] + file.customizationRefs[ ET_DLC5_ION ].append( "ion_skin_07" ) + file.customizationRefs[ ET_DLC5_ION ].append( "ion_nose_art_27" ) + file.customizationRefs[ ET_DLC5_ION ].append( "ion_nose_art_28" ) + file.customizationRefs[ ET_DLC5_ION ].append( "ion_nose_art_29" ) + file.customizationRefs[ ET_DLC5_ION ].append( "ion_nose_art_30" ) + file.customizationRefs[ ET_DLC5_ION ].append( "ion_nose_art_31" ) + + file.customizationRefs[ ET_DLC1_SCORCH ] <- [] + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_skin_07" ) + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_nose_art_15" ) + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_nose_art_16" ) + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_nose_art_17" ) + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_nose_art_18" ) + file.customizationRefs[ ET_DLC1_SCORCH ].append( "scorch_nose_art_19" ) + file.customizationRefs[ ET_DLC3_SCORCH ] <- [] + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_skin_08" ) + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_nose_art_20" ) + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_nose_art_21" ) + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_nose_art_22" ) + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_nose_art_23" ) + file.customizationRefs[ ET_DLC3_SCORCH ].append( "scorch_nose_art_24" ) + file.customizationRefs[ ET_DLC5_SCORCH ] <- [] + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_skin_06" ) + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_nose_art_25" ) + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_nose_art_26" ) + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_nose_art_27" ) + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_nose_art_28" ) + file.customizationRefs[ ET_DLC5_SCORCH ].append( "scorch_nose_art_29" ) + + file.customizationRefs[ ET_DLC1_NORTHSTAR ] <- [] + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_skin_10" ) + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_nose_art_18" ) + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_nose_art_19" ) + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_nose_art_20" ) + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_nose_art_21" ) + file.customizationRefs[ ET_DLC1_NORTHSTAR ].append( "northstar_nose_art_22" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ] <- [] + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_skin_11" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_nose_art_23" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_nose_art_24" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_nose_art_25" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_nose_art_26" ) + file.customizationRefs[ ET_DLC3_NORTHSTAR ].append( "northstar_nose_art_27" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ] <- [] + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_skin_06" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_nose_art_28" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_nose_art_29" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_nose_art_30" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_nose_art_31" ) + file.customizationRefs[ ET_DLC5_NORTHSTAR ].append( "northstar_nose_art_32" ) + + file.customizationRefs[ ET_DLC1_RONIN ] <- [] + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_skin_10" ) + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_nose_art_16" ) + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_nose_art_17" ) + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_nose_art_18" ) + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_nose_art_19" ) + file.customizationRefs[ ET_DLC1_RONIN ].append( "ronin_nose_art_20" ) + file.customizationRefs[ ET_DLC3_RONIN ] <- [] + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_skin_11" ) + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_nose_art_21" ) + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_nose_art_22" ) + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_nose_art_23" ) + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_nose_art_24" ) + file.customizationRefs[ ET_DLC3_RONIN ].append( "ronin_nose_art_25" ) + file.customizationRefs[ ET_DLC5_RONIN ] <- [] + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_skin_07" ) + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_nose_art_26" ) + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_nose_art_27" ) + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_nose_art_28" ) + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_nose_art_29" ) + file.customizationRefs[ ET_DLC5_RONIN ].append( "ronin_nose_art_30" ) + + file.customizationRefs[ ET_DLC1_TONE ] <- [] + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_skin_06" ) + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_nose_art_17" ) + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_nose_art_18" ) + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_nose_art_19" ) + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_nose_art_20" ) + file.customizationRefs[ ET_DLC1_TONE ].append( "tone_nose_art_21" ) + file.customizationRefs[ ET_DLC3_TONE ] <- [] + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_skin_07" ) + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_nose_art_22" ) + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_nose_art_23" ) + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_nose_art_24" ) + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_nose_art_25" ) + file.customizationRefs[ ET_DLC3_TONE ].append( "tone_nose_art_26" ) + file.customizationRefs[ ET_DLC5_TONE ] <- [] + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_skin_08" ) + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_nose_art_27" ) + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_nose_art_28" ) + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_nose_art_29" ) + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_nose_art_30" ) + file.customizationRefs[ ET_DLC5_TONE ].append( "tone_nose_art_31" ) + + file.customizationRefs[ ET_DLC1_LEGION ] <- [] + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_skin_07" ) + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_nose_art_17" ) + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_nose_art_18" ) + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_nose_art_19" ) + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_nose_art_20" ) + file.customizationRefs[ ET_DLC1_LEGION ].append( "legion_nose_art_21" ) + file.customizationRefs[ ET_DLC3_LEGION ] <- [] + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_skin_08" ) + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_nose_art_22" ) + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_nose_art_23" ) + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_nose_art_24" ) + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_nose_art_25" ) + file.customizationRefs[ ET_DLC3_LEGION ].append( "legion_nose_art_26" ) + file.customizationRefs[ ET_DLC5_LEGION ] <- [] + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_skin_09" ) + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_nose_art_27" ) + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_nose_art_28" ) + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_nose_art_29" ) + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_nose_art_30" ) + file.customizationRefs[ ET_DLC5_LEGION ].append( "legion_nose_art_31" ) + + file.patchRefs[ ET_DLC1_CALLSIGN ] <- [] + file.patchRefs[ ET_DLC3_CALLSIGN ] <- [] + file.patchRefs[ ET_DLC5_CALLSIGN ] <- [] + + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_64" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_aces" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_alien" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_apex" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_ares" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_controller" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_drone" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_heartbreaker" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_hexes" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_kodai" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_lastimosa" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_lawai" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_mcor" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_phoenix" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_pilot" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_robot" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_sentry" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_super_spectre" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_vinson" ) + file.patchRefs[ ET_DLC1_CALLSIGN ].append( "gc_icon_wonyeon" ) + + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_balance" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_boot" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_bt_eye" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_buzzsaw" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_crossed_lighting" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_flying_bullet" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_hammer2" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_keyboard" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_lightbulb" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_narwhal" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_peace" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_pilot2" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_robot_eye" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_srs" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_starline" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_taco" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_thumbdown" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_thumbup" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_treble" ) + file.patchRefs[ ET_DLC3_CALLSIGN ].append( "gc_icon_vanguard" ) + + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_monarch_dlc5" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_militia" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_militia_alt" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_imc" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_hammond" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_tri_chevron" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_pilot_circle" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_x" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_nessie" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_spicy" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_crown" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_pawn" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_excite" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_duck" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_sock" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_rabbit" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_peanut" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_clock" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_shamrock" ) + file.patchRefs[ ET_DLC5_CALLSIGN ].append( "gc_icon_trident" ) + + file.bannerRefs[ ET_DLC1_CALLSIGN ] <- [] + file.bannerRefs[ ET_DLC3_CALLSIGN ] <- [] + file.bannerRefs[ ET_DLC5_CALLSIGN ] <- [] + + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_106_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_107_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_108_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_109_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_110_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_111_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_112_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_113_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_114_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_115_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_116_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_117_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_118_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_119_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_120_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_121_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_122_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_123_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_124_col" ) + file.bannerRefs[ ET_DLC1_CALLSIGN ].append( "callsign_125_col" ) + + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_143_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_144_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_145_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_146_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_147_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_148_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_149_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_150_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_151_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_152_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_153_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_154_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_155_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_156_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_157_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_158_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_159_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_160_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_161_col" ) + file.bannerRefs[ ET_DLC3_CALLSIGN ].append( "callsign_162_col" ) + + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_166_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_167_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_168_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_169_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_170_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_171_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_172_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_173_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_174_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_175_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_176_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_177_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_178_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_179_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_180_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_181_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_182_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_183_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_184_col" ) + file.bannerRefs[ ET_DLC5_CALLSIGN ].append( "callsign_185_col" ) + + file.camoRefs[ ET_DLC1_CAMO ] <- [] + file.camoRefs[ ET_DLC3_CAMO ] <- [] + file.camoRefs[ ET_DLC5_CAMO ] <- [] + + for ( int i = 101; i <= 120; i++ ) + { + AddCamoRef( ET_DLC1_CAMO, i ) + } + + for ( int i = 121; i <= 140; i++ ) + { + AddCamoRef( ET_DLC3_CAMO, i ) + } + + // You did it reddit! + int numRefs = file.camoRefs[ ET_DLC3_CAMO ].len() + CamoRef tempRef = file.camoRefs[ ET_DLC3_CAMO ][numRefs - 1] + file.camoRefs[ ET_DLC3_CAMO ][numRefs - 1] = file.camoRefs[ ET_DLC3_CAMO ][numRefs - 2] + file.camoRefs[ ET_DLC3_CAMO ][numRefs - 2] = tempRef + + for ( int i = 141; i <= 160; i++ ) + { + AddCamoRef( ET_DLC5_CAMO, i ) + } + + file.limitedEditionFDRefData[ ET_DLC7_ION_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_ION_WARPAINT ].append( CreateRefData( "ion_skin_fd", "ion" ) ) + file.limitedEditionFDRefData[ ET_DLC7_ION_WARPAINT ].append( CreateRefData( "callsign_fd_ion_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_SCORCH_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_SCORCH_WARPAINT ].append( CreateRefData( "scorch_skin_fd", "scorch" ) ) + file.limitedEditionFDRefData[ ET_DLC7_SCORCH_WARPAINT ].append( CreateRefData( "callsign_fd_scorch_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_NORTHSTAR_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_NORTHSTAR_WARPAINT ].append( CreateRefData( "northstar_skin_fd", "northstar" ) ) + file.limitedEditionFDRefData[ ET_DLC7_NORTHSTAR_WARPAINT ].append( CreateRefData( "callsign_fd_northstar_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_RONIN_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_RONIN_WARPAINT ].append( CreateRefData( "ronin_skin_fd", "ronin" ) ) + file.limitedEditionFDRefData[ ET_DLC7_RONIN_WARPAINT ].append( CreateRefData( "callsign_fd_ronin_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_TONE_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_TONE_WARPAINT ].append( CreateRefData( "tone_skin_fd", "tone" ) ) + file.limitedEditionFDRefData[ ET_DLC7_TONE_WARPAINT ].append( CreateRefData( "callsign_fd_tone_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_LEGION_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_LEGION_WARPAINT ].append( CreateRefData( "legion_skin_fd", "legion" ) ) + file.limitedEditionFDRefData[ ET_DLC7_LEGION_WARPAINT ].append( CreateRefData( "callsign_fd_legion_dynamic" ) ) + + file.limitedEditionFDRefData[ ET_DLC7_MONARCH_WARPAINT ] <- [] + file.limitedEditionFDRefData[ ET_DLC7_MONARCH_WARPAINT ].append( CreateRefData( "monarch_skin_fd", "vanguard" ) ) + file.limitedEditionFDRefData[ ET_DLC7_MONARCH_WARPAINT ].append( CreateRefData( "callsign_fd_monarch_dynamic" ) ) +} + +RefData function CreateRefData( string ref, string parentRef = "" ) +{ + RefData data + data.ref = ref + data.parentRef = parentRef + + return data +} + +array function Store_GetCustomizationRefs( int entitlementId ) +{ + return file.customizationRefs[ entitlementId ] +} + +array function Store_GetPatchRefs( int entitlementId ) +{ + return file.patchRefs[ entitlementId ] +} + +array function Store_GetBannerRefs( int entitlementId ) +{ + return file.bannerRefs[ entitlementId ] +} + +array function Store_GetCamoRefs( int entitlementId ) +{ + return file.camoRefs[ entitlementId ] +} + +void function AddCamoRef( int entitlementId, int index ) +{ + CamoRef cref + cref.ref = "camo_skin" + index + cref.pilotRef = "pilot_camo_skin" + index + cref.titanRef = "titan_camo_skin" + index + file.camoRefs[ entitlementId ].append( cref ) +} + +#if SERVER +bool function ClientCommand_SetHasSeenStore( entity player, array args ) +{ + player.SetPersistentVar( "hasSeenStore", true ) + + return true +} + +// TODO: refParam is problematic, because it assumes an entitlement maps to a single ref which is not the case for limited edition frontier defense entitlements +void function StoreUpdatePIN( entity player, int entitlementId, string refParam ) +{ + printt( "StoreUpdatePIN", entitlementId, refParam) + + switch ( entitlementId ) + { + case ET_DLC1_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc1_bundle", 0 ) + break + + case ET_DLC3_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc3_bundle", 0 ) + break + + case ET_DLC5_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc5_bundle", 0 ) + break + + case ET_PRIME_TITANS_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "sprime_titans_bundle", 0 ) + break + + case ET_DLC1_PRIME_ION: + case ET_DLC1_PRIME_SCORCH: + case ET_DLC3_PRIME_NORTHSTAR: + case ET_DLC3_PRIME_LEGION: + case ET_DLC5_PRIME_TONE: + case ET_DLC5_PRIME_RONIN: + Assert( refParam != "" ) + if ( refParam == "" || !ItemDefined( refParam ) ) + return + + PIN_BuyItemWithRealMoney( player, false, refParam, 0 ) + break + + case ET_DLC1_ION: + case ET_DLC1_SCORCH: + case ET_DLC1_NORTHSTAR: + case ET_DLC1_RONIN: + case ET_DLC1_TONE: + case ET_DLC1_LEGION: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "customization_" + refParam, 0 ) + break + + case ET_DLC3_ION: + case ET_DLC3_SCORCH: + case ET_DLC3_NORTHSTAR: + case ET_DLC3_RONIN: + case ET_DLC3_TONE: + case ET_DLC3_LEGION: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc3_customization_" + refParam, 0 ) + break + + case ET_DLC5_ION: + case ET_DLC5_SCORCH: + case ET_DLC5_NORTHSTAR: + case ET_DLC5_RONIN: + case ET_DLC5_TONE: + case ET_DLC5_LEGION: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc5_customization_" + refParam, 0 ) + break + + case ET_DLC1_CAMO: + PIN_BuyItemWithRealMoney( player, false, "dlc_camos", 0 ) + break + + case ET_DLC3_CAMO: + PIN_BuyItemWithRealMoney( player, false, "dlc3_camos", 0 ) + break + + case ET_DLC5_CAMO: + PIN_BuyItemWithRealMoney( player, false, "dlc5_camos", 0 ) + break + + case ET_DLC1_CALLSIGN: + PIN_BuyItemWithRealMoney( player, false, "dlc_callsigns", 0 ) + break + + case ET_DLC3_CALLSIGN: + PIN_BuyItemWithRealMoney( player, false, "dlc3_callsigns", 0 ) + break + + case ET_DLC5_CALLSIGN: + PIN_BuyItemWithRealMoney( player, false, "dlc5_callsigns", 0 ) + break + + case ET_DLC7_TITAN_WARPAINT_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc7_frontier_titan_warpaint_bundle", 0 ) + break + + case ET_DLC7_ION_WARPAINT: + case ET_DLC7_SCORCH_WARPAINT: + case ET_DLC7_NORTHSTAR_WARPAINT: + case ET_DLC7_RONIN_WARPAINT: + case ET_DLC7_TONE_WARPAINT: + case ET_DLC7_LEGION_WARPAINT: + case ET_DLC7_MONARCH_WARPAINT: + PIN_BuyItemWithRealMoney( player, false, "dlc7_frontier_titan_warpaint_" + file.limitedEditionFDRefData[ entitlementId ][0].ref, 0 ) + break + + case ET_DLC7_WEAPON_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc7_weapon_warpaint_bundle", 0 ) + break + + case ET_DLC7_R201_WARPAINT: + case ET_DLC7_G2A5_WARPAINT: + case ET_DLC7_FLATLINE_WARPAINT: + case ET_DLC7_CAR_WARPAINT: + case ET_DLC7_ALTERNATOR_WARPAINT: + case ET_DLC7_EVA8_WARPAINT: + case ET_DLC7_WINGMAN_WARPAINT: + case ET_DLC7_ARCHER_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc7_weapon_warpaint_" + refParam, 0 ) + break + + case ET_DLC8_WEAPON_WARPAINT_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc8_weapon_warpaint_bundle", 0 ) + break + + case ET_DLC8_R201_WARPAINT: + case ET_DLC8_HEMLOK_WARPAINT: + case ET_DLC8_R97_WARPAINT: + case ET_DLC8_KRABER_WARPAINT: + case ET_DLC8_SPITFIRE_WARPAINT: + case ET_DLC8_DEVOTION_WARPAINT: + case ET_DLC8_MOZAMBIQUE_WARPAINT: + case ET_DLC8_THUNDERBOLT_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc8_weapon_warpaint_" + refParam, 0 ) + break + + case ET_JUMPSTARTERBUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc10_jump_starter_pack", 0 ) + + case ET_DLC9_WEAPON_WARPAINT_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc9_weapon_warpaint_bundle", 0 ) + break + + case ET_DLC9_LSTAR_WARPAINT: + case ET_DLC9_MASTIFF_WARPAINT: + case ET_DLC9_SIDEWINDER_WARPAINT: + case ET_DLC9_R201_WARPAINT: + case ET_DLC9_CAR_WARPAINT: + case ET_DLC9_SPITFIRE_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc9_weapon_warpaint_" + refParam, 0 ) + break + + case ET_DLC10_WEAPON_WARPAINT_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc10_weapon_warpaint_bundle", 0 ) + break + + case ET_DLC10_R101_WARPAINT: + case ET_DLC10_FLATLINE_WARPAINT: + case ET_DLC10_VOLT_WARPAINT: + case ET_DLC10_ALTERNATOR_WARPAINT: + case ET_DLC10_SOFTBALL_WARPAINT: + case ET_DLC10_EPG1_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc10_weapon_warpaint_" + refParam, 0 ) + break + + case ET_DLC11_WEAPON_WARPAINT_BUNDLE: + PIN_BuyItemWithRealMoney( player, false, "dlc11_weapon_warpaint_bundle", 0 ) + break + + case ET_DLC11_DMR_WARPAINT: + case ET_DLC11_DOUBLETAKE_WARPAINT: + case ET_DLC11_G2A5_WARPAINT: + case ET_DLC11_COLDWAR_WARPAINT: + case ET_DLC11_R97_WARPAINT: + case ET_DLC11_R101_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" ) + return + + PIN_BuyItemWithRealMoney( player, false, "dlc11_weapon_warpaint_" + refParam, 0 ) + break + } +} + +bool function ClientCommand_StoreSetNewItemStatus( entity player, array args ) +{ + // fix crash + if( args.len() < 1 ) + return true + + int entitlementId = int( args[0] ) + string refParam + string parentRefParam + + if ( args.len() >= 2 ) + refParam = args[1] + + if ( args.len() >= 3 ) + parentRefParam = args[2] + + StoreUpdatePIN( player, entitlementId, refParam ) + StoreSetNewItemStatus( player, entitlementId, refParam, parentRefParam ) + + return true +} + +bool function StoreSetNewItemStatus( entity player, int entitlementId, string refParam, string parentRefParam ) +{ + string e = entitlementId == ET_JUMPSTARTERBUNDLE ? "ET_JUMPSTARTERBUNDLE" : string( entitlementId ) + printt( "!!!!!!!!!!! StoreSetNewItemStatus() running for entitlement:", e ) + + switch ( entitlementId ) + { + case 3: + // Prime Titans + SetItemNewStatus( player, "ion_prime", "", true ) + SetItemNewStatus( player, "scorch_prime", "", true ) + + // Customization Packs + table< string, array > dlc1BundleCustomizationRefs + dlc1BundleCustomizationRefs[ "ion" ] <- file.customizationRefs[ ET_DLC1_ION ] + dlc1BundleCustomizationRefs[ "tone" ] <- file.customizationRefs[ ET_DLC1_TONE ] + dlc1BundleCustomizationRefs[ "scorch" ] <- file.customizationRefs[ ET_DLC1_SCORCH ] + dlc1BundleCustomizationRefs[ "legion" ] <- file.customizationRefs[ ET_DLC1_LEGION ] + dlc1BundleCustomizationRefs[ "ronin" ] <- file.customizationRefs[ ET_DLC1_RONIN ] + dlc1BundleCustomizationRefs[ "northstar" ] <- file.customizationRefs[ ET_DLC1_NORTHSTAR ] + + foreach ( parentRef, childRefs in dlc1BundleCustomizationRefs ) + { + foreach ( ref in childRefs ) + { + if ( !SubitemDefined( parentRef, ref ) ) + return false + + SetItemNewStatus( player, ref, parentRef, true ) + } + } + + // Callsigns + foreach ( ref in file.patchRefs[ ET_DLC1_CALLSIGN ] ) + { + SetItemNewStatus( player, ref, "", true ) + } + + break + + case ET_DLC3_BUNDLE: + // Prime Titans + SetItemNewStatus( player, "northstar_prime", "", true ) + SetItemNewStatus( player, "legion_prime", "", true ) + + // Customization Packs + table< string, array > dlc3BundleCustomizationRefs + dlc3BundleCustomizationRefs[ "ion" ] <- file.customizationRefs[ ET_DLC3_ION ] + dlc3BundleCustomizationRefs[ "tone" ] <- file.customizationRefs[ ET_DLC3_TONE ] + dlc3BundleCustomizationRefs[ "scorch" ] <- file.customizationRefs[ ET_DLC3_SCORCH ] + dlc3BundleCustomizationRefs[ "legion" ] <- file.customizationRefs[ ET_DLC3_LEGION ] + dlc3BundleCustomizationRefs[ "ronin" ] <- file.customizationRefs[ ET_DLC3_RONIN ] + dlc3BundleCustomizationRefs[ "northstar" ] <- file.customizationRefs[ ET_DLC3_NORTHSTAR ] + + foreach ( parentRef, childRefs in dlc3BundleCustomizationRefs ) + { + foreach ( ref in childRefs ) + { + if ( !SubitemDefined( parentRef, ref ) ) + return false + + SetItemNewStatus( player, ref, parentRef, true ) + } + } + + // Callsigns + foreach ( ref in file.patchRefs[ ET_DLC3_CALLSIGN ] ) + { + SetItemNewStatus( player, ref, "", true ) + } + + break + + case ET_DLC5_BUNDLE: + // Prime Titans + SetItemNewStatus( player, "ronin_prime", "", true ) + SetItemNewStatus( player, "tone_prime", "", true ) + + // Customization Packs + table< string, array > dlc5BundleCustomizationRefs + dlc5BundleCustomizationRefs[ "ion" ] <- file.customizationRefs[ ET_DLC5_ION ] + dlc5BundleCustomizationRefs[ "tone" ] <- file.customizationRefs[ ET_DLC5_TONE ] + dlc5BundleCustomizationRefs[ "scorch" ] <- file.customizationRefs[ ET_DLC5_SCORCH ] + dlc5BundleCustomizationRefs[ "legion" ] <- file.customizationRefs[ ET_DLC5_LEGION ] + dlc5BundleCustomizationRefs[ "ronin" ] <- file.customizationRefs[ ET_DLC5_RONIN ] + dlc5BundleCustomizationRefs[ "northstar" ] <- file.customizationRefs[ ET_DLC5_NORTHSTAR ] + + foreach ( parentRef, childRefs in dlc5BundleCustomizationRefs ) + { + foreach ( ref in childRefs ) + { + if ( !SubitemDefined( parentRef, ref ) ) + return false + + SetItemNewStatus( player, ref, parentRef, true ) + } + } + + // Callsigns + foreach ( ref in file.patchRefs[ ET_DLC5_CALLSIGN ] ) + { + SetItemNewStatus( player, ref, "", true ) + } + + break + + case ET_PRIME_TITANS_BUNDLE: + SetItemNewStatus( player, "ion_prime", "", true ) + SetItemNewStatus( player, "scorch_prime", "", true ) + SetItemNewStatus( player, "northstar_prime", "", true ) + SetItemNewStatus( player, "legion_prime", "", true ) + SetItemNewStatus( player, "ronin_prime", "", true ) + SetItemNewStatus( player, "tone_prime", "", true ) + break + + case ET_DLC1_PRIME_ION: + case ET_DLC1_PRIME_SCORCH: + case ET_DLC3_PRIME_NORTHSTAR: + case ET_DLC3_PRIME_LEGION: + case ET_DLC5_PRIME_TONE: + case ET_DLC5_PRIME_RONIN: + Assert( refParam != "" ) + if ( refParam == "" || !ItemDefined( refParam ) ) + return false + + SetItemNewStatus( player, refParam, "", true ) + break + + case ET_DLC1_ION: + case ET_DLC3_ION: + case ET_DLC5_ION: + case ET_DLC1_SCORCH: + case ET_DLC3_SCORCH: + case ET_DLC5_SCORCH: + case ET_DLC1_NORTHSTAR: + case ET_DLC3_NORTHSTAR: + case ET_DLC5_NORTHSTAR: + case ET_DLC1_RONIN: + case ET_DLC3_RONIN: + case ET_DLC5_RONIN: + case ET_DLC1_TONE: + case ET_DLC3_TONE: + case ET_DLC5_TONE: + case ET_DLC1_LEGION: + case ET_DLC3_LEGION: + case ET_DLC5_LEGION: + Assert( refParam != "" ) + if ( refParam == "" ) + return false + + foreach ( ref in file.customizationRefs[ entitlementId ] ) + { + if ( !SubitemDefined( refParam, ref ) ) + return false + + SetItemNewStatus( player, ref, refParam, true ) + } + break + + case ET_DLC1_CAMO: + case ET_DLC3_CAMO: + case ET_DLC5_CAMO: + // Not implemented, way too many camos would show as new + break + + case ET_DLC1_CALLSIGN: + case ET_DLC3_CALLSIGN: + case ET_DLC5_CALLSIGN: + foreach ( ref in file.patchRefs[ entitlementId ] ) + { + SetItemNewStatus( player, ref, "", true ) + } + + foreach ( ref in file.bannerRefs[ entitlementId ] ) + { + SetItemNewStatus( player, ref, "", true ) + } + break + + case ET_DLC7_TITAN_WARPAINT_BUNDLE: + array childEntitlements = GetChildEntitlements( entitlementId ) + + foreach ( entitlement in childEntitlements ) + { + foreach ( data in file.limitedEditionFDRefData[ entitlement ] ) + SetItemNewStatus( player, data.ref, data.parentRef, true ) + } + break + + case ET_DLC7_ION_WARPAINT: + case ET_DLC7_SCORCH_WARPAINT: + case ET_DLC7_NORTHSTAR_WARPAINT: + case ET_DLC7_RONIN_WARPAINT: + case ET_DLC7_TONE_WARPAINT: + case ET_DLC7_LEGION_WARPAINT: + case ET_DLC7_MONARCH_WARPAINT: + foreach ( data in file.limitedEditionFDRefData[ entitlementId ] ) + SetItemNewStatus( player, data.ref, data.parentRef, true ) + break + + case ET_DLC7_R201_WARPAINT: + case ET_DLC7_G2A5_WARPAINT: + case ET_DLC7_FLATLINE_WARPAINT: + case ET_DLC7_CAR_WARPAINT: + case ET_DLC7_ALTERNATOR_WARPAINT: + case ET_DLC7_EVA8_WARPAINT: + case ET_DLC7_WINGMAN_WARPAINT: + case ET_DLC7_ARCHER_WARPAINT: + case ET_DLC8_R201_WARPAINT: + case ET_DLC8_HEMLOK_WARPAINT: + case ET_DLC8_R97_WARPAINT: + case ET_DLC8_KRABER_WARPAINT: + case ET_DLC8_SPITFIRE_WARPAINT: + case ET_DLC8_DEVOTION_WARPAINT: + case ET_DLC8_MOZAMBIQUE_WARPAINT: + case ET_DLC8_THUNDERBOLT_WARPAINT: + case ET_DLC9_LSTAR_WARPAINT: + case ET_DLC9_MASTIFF_WARPAINT: + case ET_DLC9_SIDEWINDER_WARPAINT: + case ET_DLC9_R201_WARPAINT: + case ET_DLC9_CAR_WARPAINT: + case ET_DLC9_SPITFIRE_WARPAINT: + case ET_DLC10_R101_WARPAINT: + case ET_DLC10_FLATLINE_WARPAINT: + case ET_DLC10_VOLT_WARPAINT: + case ET_DLC10_ALTERNATOR_WARPAINT: + case ET_DLC10_SOFTBALL_WARPAINT: + case ET_DLC10_EPG1_WARPAINT: + case ET_DLC11_DMR_WARPAINT: + case ET_DLC11_DOUBLETAKE_WARPAINT: + case ET_DLC11_G2A5_WARPAINT: + case ET_DLC11_COLDWAR_WARPAINT: + case ET_DLC11_R97_WARPAINT: + case ET_DLC11_R101_WARPAINT: + Assert( refParam != "" ) + if ( refParam == "" || !ItemDefined( refParam ) ) + return false + + Assert( parentRefParam != "" ) + if ( parentRefParam == "" || !ItemDefined( parentRefParam ) ) + return false + + SetItemNewStatus( player, refParam, parentRefParam, true ) + break + + case ET_DLC7_WEAPON_BUNDLE: + SetItemNewStatus( player, "skin_rspn101_wasteland", "mp_weapon_rspn101", true ) + SetItemNewStatus( player, "skin_g2_masterwork", "mp_weapon_g2", true ) + SetItemNewStatus( player, "skin_vinson_blue_fade", "mp_weapon_vinson", true ) + SetItemNewStatus( player, "skin_car_crimson_fury", "mp_weapon_car", true ) + SetItemNewStatus( player, "skin_alternator_patriot", "mp_weapon_alternator_smg", true ) + SetItemNewStatus( player, "skin_shotgun_badlands", "mp_weapon_shotgun", true ) + SetItemNewStatus( player, "skin_wingman_aqua_fade", "mp_weapon_wingman", true ) + SetItemNewStatus( player, "skin_rocket_launcher_psych_spectre", "mp_weapon_rocket_launcher", true ) + break + + case ET_DLC8_WEAPON_WARPAINT_BUNDLE: + SetItemNewStatus( player, "skin_rspn101_patriot", "mp_weapon_rspn101", true ) + SetItemNewStatus( player, "skin_hemlok_mochi", "mp_weapon_hemlok", true ) + SetItemNewStatus( player, "skin_r97_purple_fade", "mp_weapon_r97", true ) + SetItemNewStatus( player, "skin_kraber_masterwork", "mp_weapon_sniper", true ) + SetItemNewStatus( player, "skin_spitfire_lead_farmer", "mp_weapon_lmg", true ) + SetItemNewStatus( player, "skin_devotion_rspn_customs", "mp_weapon_esaw", true ) + SetItemNewStatus( player, "skin_mozambique_crimson_fury", "mp_weapon_shotgun_pistol", true ) + SetItemNewStatus( player, "skin_thunderbolt_8bit", "mp_weapon_arc_launcher", true ) + break + + case ET_DLC9_WEAPON_WARPAINT_BUNDLE: + SetItemNewStatus( player, "skin_lstar_heatsink", "mp_weapon_lstar", true ) + SetItemNewStatus( player, "skin_mastiff_crimson_fury", "mp_weapon_mastiff", true ) + SetItemNewStatus( player, "skin_sidewinder_masterwork", "mp_weapon_smr", true ) + SetItemNewStatus( player, "skin_rspn101_halloween", "mp_weapon_rspn101", true ) + SetItemNewStatus( player, "skin_car_halloween", "mp_weapon_car", true ) + SetItemNewStatus( player, "skin_spitfire_halloween", "mp_weapon_lmg", true ) + break + + case ET_DLC10_WEAPON_WARPAINT_BUNDLE: + SetItemNewStatus( player, "skin_rspn101_og_blue_fade", "mp_weapon_rspn101_og", true ) + SetItemNewStatus( player, "skin_vinson_badlands", "mp_weapon_vinson", true ) + SetItemNewStatus( player, "skin_volt_heatsink", "mp_weapon_hemlok_smg", true ) + SetItemNewStatus( player, "skin_alternator_headhunter", "mp_weapon_alternator_smg", true ) + SetItemNewStatus( player, "skin_softball_masterwork", "mp_weapon_softball", true ) + SetItemNewStatus( player, "skin_epg_mrvn", "mp_weapon_epg", true ) + break + + case ET_DLC11_WEAPON_WARPAINT_BUNDLE: + SetItemNewStatus( player, "skin_dmr_phantom", "mp_weapon_dmr", true ) + SetItemNewStatus( player, "skin_doubletake_masterwork", "mp_weapon_doubletake", true ) + SetItemNewStatus( player, "skin_g2_purple_fade", "mp_weapon_g2", true ) + SetItemNewStatus( player, "skin_coldwar_heatsink", "mp_weapon_pulse_lmg", true ) + SetItemNewStatus( player, "skin_r97_sky", "mp_weapon_r97", true ) + SetItemNewStatus( player, "skin_rspn101_crimson_fury", "mp_weapon_rspn101", true ) + break + + case ET_JUMPSTARTERBUNDLE: + UnlockUltimateEdition( player ) + break + } + + return true +} +#endif -- cgit v1.2.3 From f7b0e6ffeced13190eb58a65ac9b88af1b4127ba Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 16 Apr 2023 00:57:31 +0100 Subject: Fix Fastball respawning spectating player (#616) --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut index 5ce11eb3..409d5ec0 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fastball.gnut @@ -283,7 +283,7 @@ function FastballOnPanelHacked( panel, player ) // respawn dead players foreach ( entity deadPlayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) { - if ( !IsAlive( deadPlayer ) && !IsPrivateMatchSpectator( player ) ) + if ( !IsAlive( deadPlayer ) && !IsPrivateMatchSpectator( deadPlayer ) ) { deadPlayer.SetOrigin( panel.s.startOrigin ) deadPlayer.RespawnPlayer( null ) -- cgit v1.2.3 From 04b1b0be8abf1a83771e663bcee8a618a8f798ab Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 20 Apr 2023 00:47:57 +0200 Subject: Revert "Hardpoint UI Fixes (#416)" (#618) This reverts commit 28d444c26a1da5496d1cf3f7610a261cd739ef73. As it causes crash as explained in https://github.com/R2Northstar/NorthstarMods/pull/416#pullrequestreview-1392973121 --- .../mod/scripts/vscripts/gamemodes/_gamemode_cp.nut | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index 1bc42de0..705b7836 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -471,10 +471,8 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(cappingTeam==TEAM_UNASSIGNED) // nobody on point { - if((GetHardpointState(hardpoint)>=CAPTURE_POINT_STATE_AMPED) || (GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_SELF_UNAMPING)) + if((GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPED)||(GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPING)) { - if (GetHardpointState(hardpoint) == CAPTURE_POINT_STATE_AMPED) - SetHardpointState(hardpoint,CAPTURE_POINT_STATE_SELF_UNAMPING) // plays a pulsating effect on the UI only when the hardpoint is amped SetHardpointCappingTeam(hardpoint,hardpointEnt.GetTeam()) SetHardpointCaptureProgress(hardpoint,max(1.0,GetHardpointCaptureProgress(hardpoint)-(deltaTime/HARDPOINT_AMPED_DELAY))) if(GetHardpointCaptureProgress(hardpoint)<=1.001) // unamp @@ -548,10 +546,8 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(file.ampingEnabled)//amping or reamping { - // i have no idea why but putting it CAPTURE_POINT_STATE_AMPING will say 'CONTESTED' on the UI - // since whether the point is contested is checked above, putting the hardpoint state to a value of 8 fixes it somehow - if(GetHardpointState(hardpoint)<=CAPTURE_POINT_STATE_AMPING) - SetHardpointState( hardpoint, 8 ) + if(GetHardpointState(hardpoint) Date: Thu, 20 Apr 2023 18:22:54 -0400 Subject: Improve server connection error messages (#598) * Also show masterserver error for server connections It's already used for self auth and is available for both, but we currently only show it for the former. * Don't localize server connection errors It never fully worked, and it's more useful to have non-localized detailed error messages. * Don't prepend NS_SERVERBROWSER_CONNECTIONFAILED to server conn err msg The message always contains something like it, and it's always right after a connectiom anyways. * NSGetAuthFailReason always returns a string, so don't make it untyped --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 4 +++- Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index b2e2a8b6..b663a25a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1085,9 +1085,11 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) } else { + string reason = NSGetAuthFailReason() + DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Authentication Failed" + dialogData.message = reason dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index 95b7bdae..53d85387 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -571,12 +571,12 @@ void function TryAuthWithLocalServer() { CloseAllDialogs() - var reason = NSGetAuthFailReason() + string reason = NSGetAuthFailReason() DialogData dialogData dialogData.image = $"ui/menu/common/dialog_error" dialogData.header = "#ERROR" - dialogData.message = Localize("#NS_SERVERBROWSER_CONNECTIONFAILED") + "\nERROR: " + reason + "\n" + Localize("#" + reason) + dialogData.message = reason AddDialogButton( dialogData, "#OK", null ) OpenDialog( dialogData ) -- cgit v1.2.3 From f6716069a26dde85866741cc066f380ddf442f7d Mon Sep 17 00:00:00 2001 From: pg9182 <96569817+pg9182@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:57:09 -0400 Subject: Update check-loc-encoding checkout action (#620) Fixes Node.js 12 deprecation. --- .github/workflows/encoding.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index bafdb15b..a88e3961 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Check localization files encoding run: | files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) -- cgit v1.2.3 From 64b666d19698380760f7c8381c6abef98e55ef11 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Sat, 22 Apr 2023 08:59:07 +0800 Subject: Revert "Revert 'Hardpoint UI Fixes (#416)' (#618)" (#619) * fixed not showing Auto-Titans death in killfeed * revert indents * revert indents again * bug fix * Hardpoint Fixes * "fixed" spacing for like one line the rest of the file is kinda oof tho but not related to my pr * 69 spacing * SetPlayerNetInt is placed inside a player entity check --- .../mod/scripts/vscripts/gamemodes/_gamemode_cp.nut | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index 705b7836..c5765300 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -471,8 +471,10 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(cappingTeam==TEAM_UNASSIGNED) // nobody on point { - if((GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPED)||(GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_AMPING)) + if((GetHardpointState(hardpoint)>=CAPTURE_POINT_STATE_AMPED) || (GetHardpointState(hardpoint)==CAPTURE_POINT_STATE_SELF_UNAMPING)) { + if (GetHardpointState(hardpoint) == CAPTURE_POINT_STATE_AMPED) + SetHardpointState(hardpoint,CAPTURE_POINT_STATE_SELF_UNAMPING) // plays a pulsating effect on the UI only when the hardpoint is amped SetHardpointCappingTeam(hardpoint,hardpointEnt.GetTeam()) SetHardpointCaptureProgress(hardpoint,max(1.0,GetHardpointCaptureProgress(hardpoint)-(deltaTime/HARDPOINT_AMPED_DELAY))) if(GetHardpointCaptureProgress(hardpoint)<=1.001) // unamp @@ -546,8 +548,10 @@ void function HardpointThink( HardpointStruct hardpoint ) } else if(file.ampingEnabled)//amping or reamping { - if(GetHardpointState(hardpoint) Date: Sun, 23 Apr 2023 14:28:00 +0200 Subject: Bump mods version to `1.13.0` (#627) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index f0f45e67..00b779a4 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 374e13e4..66d29cae 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 657854da..e1df99ba 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.12.0", + "Version": "1.13.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 2d6ca83c3ab5f045dfbc5d0a167b925112b2bd84 Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Thu, 27 Apr 2023 12:55:32 +0000 Subject: Use structs in the server browser (#623) * move to native structs * add connect callbacks * update native functions register * trigger callbacks on double click * use suggestions --- .github/nativefuncs.json | 74 +----- .../scripts/vscripts/cl_northstar_client_init.nut | 23 +- .../vscripts/ui/menu_ns_connect_password.nut | 3 + .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 254 +++++++++++---------- 4 files changed, 165 insertions(+), 189 deletions(-) diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index f52a969c..751b4893 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -449,76 +449,10 @@ "argTypes":"" }, { - "name":"NSGetServerName", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerDescription", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerMap", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerPlaylist", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerPlayerCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerMaxPlayerCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerID", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSServerRequiresPassword", - "helpText":"", - "returnTypeString":"bool", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRequiredModsCount", - "helpText":"", - "returnTypeString":"int", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRegion", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex" - }, - { - "name":"NSGetServerRequiredModName", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex, int modIndex" - }, - { - "name":"NSGetServerRequiredModVersion", - "helpText":"", - "returnTypeString":"string", - "argTypes":"int serverIndex, int modIndex" + "name": "NSGetGameServers", + "helpText": "Gets all fetched servers", + "returnTypeString": "array", + "argTypes": "" }, { "name":"NSClearRecievedServerList", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 212568d0..2a2ed3db 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -19,4 +19,25 @@ global struct UIPresenceStruct { bool isLobby string loadingLevel string loadedLevel -} \ No newline at end of file +} + +global struct RequiredModInfo +{ + string name + string version +} + +global struct ServerInfo +{ + int index + string id + string name + string description + string map + string playlist + int playerCount + int maxPlayerCount + bool requiresPassword + string region + array< RequiredModInfo > requiredMods +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index b5a2e9b6..1e10aa45 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -54,5 +54,8 @@ void function OnConnectWithPasswordMenuOpened() void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) + { + TriggerConnectToServerCallbacks() thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index b663a25a..c31185ee 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -4,6 +4,9 @@ untyped global function AddNorthstarServerBrowserMenu global function ThreadedAuthAndConnectToServer +global function AddConnectToServerCallback +global function RemoveConnectToServerCallback +global function TriggerConnectToServerCallbacks // Stop peeking @@ -67,7 +70,6 @@ struct serverStruct { struct { // UI state vars var menu - int lastSelectedServer = 999 int focusedServerIndex = 0 int scrollOffset = 0 bool serverListRequestFailed = false @@ -79,6 +81,10 @@ struct { // filtered array of servers array serversArrayFiltered + + array filteredServers + ServerInfo& focusedServer + ServerInfo& lastSelectedServer // UI references array serverButtons @@ -88,6 +94,8 @@ struct { array serversMap array serversGamemode array serversRegion + + array< void functionref( ServerInfo ) > connectCallbacks } file @@ -253,7 +261,7 @@ void function FlushMouseDeltaBuffer() void function SliderBarUpdate() { - if ( file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE ) + if ( file.filteredServers.len() <= BUTTONS_PER_PAGE ) { FlushMouseDeltaBuffer() return @@ -270,7 +278,7 @@ void function SliderBarUpdate() float maxYPos = minYPos - ( maxHeight - Hud_GetHeight( sliderPanel ) ) float useableSpace = ( maxHeight - Hud_GetHeight( sliderPanel ) ) - float jump = minYPos - ( useableSpace / ( float( file.serversArrayFiltered.len() ) ) ) + float jump = minYPos - ( useableSpace / ( float( file.filteredServers.len() ) ) ) // got local from official respaw scripts, without untyped throws an error local pos = Hud_GetPos( sliderButton )[1] @@ -284,7 +292,7 @@ void function SliderBarUpdate() Hud_SetPos( sliderPanel , 2, newPos ) Hud_SetPos( movementCapture , 2, newPos ) - file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.serversArrayFiltered.len() - BUTTONS_PER_PAGE ) ) + file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.filteredServers.len() - BUTTONS_PER_PAGE ) ) UpdateShownPage() } @@ -328,13 +336,13 @@ void function UpdateListSliderPosition( int servers ) void function OnScrollDown( var button ) { - if (file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE) return + if (file.filteredServers.len() <= BUTTONS_PER_PAGE) return file.scrollOffset += 5 - if (file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len()) { - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + if (file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len()) { + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } void function OnScrollUp( var button ) @@ -344,7 +352,7 @@ void function OnScrollUp( var button ) file.scrollOffset = 0 } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } //////////////////////////// @@ -484,7 +492,7 @@ void function OnHitDummyTop( var button ) { // only update if list position changed UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) DisplayFocusedServerInfo( file.serverButtonFocusedID ) Hud_SetFocused( Hud_GetChild( file.menu, "BtnServer1" ) ) } @@ -493,10 +501,10 @@ void function OnHitDummyTop( var button ) void function OnHitDummyBottom( var button ) { file.scrollOffset += 1 - if ( file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len() ) + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len() ) { // was at bottom already - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE Hud_SetFocused( Hud_GetChild( file.menu, "BtnServerSearch" ) ) HideServerInfo() } @@ -504,7 +512,7 @@ void function OnHitDummyBottom( var button ) { // only update if list position changed UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) DisplayFocusedServerInfo( file.serverButtonFocusedID ) Hud_SetFocused( Hud_GetChild( file.menu, "BtnServer15" ) ) } @@ -518,15 +526,15 @@ void function OnHitDummyAfterFilterClear( var button ) void function OnDownArrowSelected( var button ) { - if ( file.serversArrayFiltered.len() <= BUTTONS_PER_PAGE ) return + if ( file.filteredServers.len() <= BUTTONS_PER_PAGE ) return file.scrollOffset += 1 - if ( file.scrollOffset + BUTTONS_PER_PAGE > file.serversArrayFiltered.len() ) + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredServers.len() ) { - file.scrollOffset = file.serversArrayFiltered.len() - BUTTONS_PER_PAGE + file.scrollOffset = file.filteredServers.len() - BUTTONS_PER_PAGE } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } @@ -539,7 +547,7 @@ void function OnUpArrowSelected( var button ) } UpdateShownPage() - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) } //////////////////////// @@ -642,7 +650,7 @@ void function FilterAndUpdateList( var n ) filterArguments.hideProtected = GetConVarBool( "filter_hide_protected" ) file.scrollOffset = 0 - UpdateListSliderPosition( file.serversArrayFiltered.len() ) + UpdateListSliderPosition( file.filteredServers.len() ) HideServerInfo() FilterServerList() @@ -741,51 +749,42 @@ void function WaitForServerListRequest() void function FilterServerList() { - file.serversArrayFiltered.clear() + file.filteredServers.clear() int totalPlayers = 0 - for ( int i = 0; i < NSGetServerCount(); i++ ) - { - serverStruct tempServer - tempServer.serverIndex = i - tempServer.serverProtected = NSServerRequiresPassword( i ) - tempServer.serverName = NSGetServerName( i ) - tempServer.serverPlayers = NSGetServerPlayerCount( i ) - tempServer.serverPlayersMax = NSGetServerMaxPlayerCount( i ) - tempServer.serverMap = NSGetServerMap( i ) - tempServer.serverGamemode = GetGameModeDisplayName( NSGetServerPlaylist ( i ) ) - tempServer.serverRegion = NSGetServerRegion( i ) - - totalPlayers += tempServer.serverPlayers + array servers = NSGetGameServers() + foreach ( ServerInfo server in servers ) + { + totalPlayers += server.playerCount // Filters - if ( filterArguments.hideEmpty && tempServer.serverPlayers == 0 ) + if ( filterArguments.hideEmpty && server.playerCount == 0 ) continue; - if ( filterArguments.hideFull && tempServer.serverPlayers == tempServer.serverPlayersMax ) + if ( filterArguments.hideFull && server.playerCount == server.maxPlayerCount ) continue; - if ( filterArguments.hideProtected && tempServer.serverProtected ) + if ( filterArguments.hideProtected && server.requiresPassword ) continue; - if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != tempServer.serverMap ) + if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != server.map ) continue; - if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != tempServer.serverGamemode ) + if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != server.playlist ) continue; - + // Search if ( filterArguments.useSearch ) { array sName - sName.append( tempServer.serverName.tolower() ) - sName.append( Localize( GetMapDisplayName( tempServer.serverMap ) ).tolower() ) - sName.append( tempServer.serverMap.tolower() ) - sName.append( tempServer.serverGamemode.tolower() ) - sName.append( Localize( tempServer.serverGamemode ).tolower() ) - sName.append( NSGetServerDescription( i ).tolower() ) - sName.append( NSGetServerRegion( i ).tolower() ) + sName.append( server.name.tolower() ) + sName.append( Localize( GetMapDisplayName( server.map ) ).tolower() ) + sName.append( server.map.tolower() ) + sName.append( server.playlist.tolower() ) + sName.append( Localize( server.playlist ).tolower() ) + sName.append( server.description.tolower() ) + sName.append( server.region.tolower() ) string sTerm = filterArguments.searchTerm.tolower() @@ -799,9 +798,8 @@ void function FilterServerList() if ( !found ) continue; } - - // Server fits our requirements, add it to the list - file.serversArrayFiltered.append( tempServer ) + + file.filteredServers.append( server ) } // Update player and server count @@ -824,23 +822,22 @@ void function UpdateShownPage() Hud_SetText( file.serversRegion[ i ], "" ) } - int j = file.serversArrayFiltered.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.serversArrayFiltered.len() + int j = file.filteredServers.len() > BUTTONS_PER_PAGE ? BUTTONS_PER_PAGE : file.filteredServers.len() for ( int i = 0; i < j; i++ ) { - int buttonIndex = file.scrollOffset + i - int serverIndex = file.serversArrayFiltered[ buttonIndex ].serverIndex + ServerInfo server = file.filteredServers[ buttonIndex ] Hud_SetEnabled( file.serverButtons[ i ], true ) Hud_SetVisible( file.serverButtons[ i ], true ) - Hud_SetVisible( file.serversProtected[ i ], file.serversArrayFiltered[ buttonIndex ].serverProtected ) - Hud_SetText( file.serversName[ i ], file.serversArrayFiltered[ buttonIndex ].serverName ) - Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", file.serversArrayFiltered[ buttonIndex ].serverPlayers, file.serversArrayFiltered[ buttonIndex ].serverPlayersMax ) ) - Hud_SetText( file.serversMap[ i ], GetMapDisplayName( file.serversArrayFiltered[ buttonIndex ].serverMap ) ) - Hud_SetText( file.serversGamemode[ i ], file.serversArrayFiltered[ buttonIndex ].serverGamemode ) - Hud_SetText( file.serversRegion[ i ], file.serversArrayFiltered[ buttonIndex ].serverRegion ) + Hud_SetVisible( file.serversProtected[ i ], server.requiresPassword ) + Hud_SetText( file.serversName[ i ], server.name ) + Hud_SetText( file.playerCountLabels[ i ], format( "%i/%i", server.playerCount, server.maxPlayerCount ) ) + Hud_SetText( file.serversMap[ i ], GetMapDisplayName( server.map ) ) + Hud_SetText( file.serversGamemode[ i ], GetGameModeDisplayName( server.playlist ) ) + Hud_SetText( file.serversRegion[ i ], server.region ) } @@ -850,7 +847,7 @@ void function UpdateShownPage() Hud_SetVisible( file.serverButtons[ 0 ], true ) Hud_SetText( file.serversName[ 0 ], "#NS_SERVERBROWSER_NOSERVERS" ) } - UpdateListSliderHeight( float( file.serversArrayFiltered.len() ) ) + UpdateListSliderHeight( float( file.filteredServers.len() ) ) } void function OnServerButtonFocused( var button ) @@ -860,8 +857,9 @@ void function OnServerButtonFocused( var button ) int scriptID = int ( Hud_GetScriptID( button ) ) file.serverButtonFocusedID = scriptID - if ( file.serversArrayFiltered.len() > 0 ) - file.focusedServerIndex = file.serversArrayFiltered[ file.scrollOffset + scriptID ].serverIndex + if ( file.filteredServers.len() > 0 ) + // file.focusedServerIndex = file.filteredServers[ file.scrollOffset + scriptID ].serverIndex + file.focusedServer = file.filteredServers[ file.scrollOffset + scriptID ] DisplayFocusedServerInfo( scriptID ) } @@ -882,13 +880,12 @@ void function CheckDoubleClick( int scriptID, bool wasClickNav ) int serverIndex = file.scrollOffset + scriptID bool sameServer = false - if ( file.lastSelectedServer == serverIndex ) sameServer = true - + if ( file.lastSelectedServer == file.filteredServers[ serverIndex ] ) sameServer = true file.serverSelectedTimeLast = file.serverSelectedTime file.serverSelectedTime = Time() - file.lastSelectedServer = serverIndex + file.lastSelectedServer = file.filteredServers[ serverIndex ] if ( wasClickNav && ( file.serverSelectedTime - file.serverSelectedTimeLast < DOUBLE_CLICK_TIME_MS ) && sameServer ) { @@ -900,7 +897,7 @@ void function DisplayFocusedServerInfo( int scriptID ) { if ( scriptID == 999 || scriptID == -1 || scriptID == 16 ) return - if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed || file.serversArrayFiltered.len() == 0 ) + if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed || file.filteredServers.len() == 0 ) return var menu = GetMenu( "ServerBrowserMenu" ) @@ -908,6 +905,7 @@ void function DisplayFocusedServerInfo( int scriptID ) int serverIndex = file.scrollOffset + scriptID if ( serverIndex < 0 ) serverIndex = 0 + ServerInfo server = file.filteredServers[ serverIndex ] Hud_SetVisible( Hud_GetChild( menu, "BtnServerDescription" ), true ) Hud_SetVisible( Hud_GetChild( menu, "BtnServerMods" ), true ) @@ -915,39 +913,39 @@ void function DisplayFocusedServerInfo( int scriptID ) // text panels Hud_SetVisible( Hud_GetChild( menu, "LabelDescription" ), true ) Hud_SetVisible( Hud_GetChild( menu, "LabelMods" ), false ) - Hud_SetText( Hud_GetChild( menu, "LabelDescription" ), NSGetServerDescription( file.serversArrayFiltered[ serverIndex ].serverIndex ) + "\n\nRequired Mods:\n" + FillInServerModsLabel( file.serversArrayFiltered[ serverIndex ].serverIndex ) ) + Hud_SetText( Hud_GetChild( menu, "LabelDescription" ), server.description + "\n\nRequired Mods:\n" + FillInServerModsLabel( server.requiredMods ) ) // map name/image/server name - string map = file.serversArrayFiltered[ serverIndex ].serverMap + string map = server.map Hud_SetVisible( Hud_GetChild( menu, "NextMapImage" ), true ) Hud_SetVisible( Hud_GetChild( menu, "NextMapBack" ), true ) RuiSetImage( Hud_GetRui( Hud_GetChild( menu, "NextMapImage" ) ), "basicImage", GetMapImageForMapName( map ) ) Hud_SetVisible( Hud_GetChild( menu, "NextMapName" ), true ) Hud_SetText( Hud_GetChild( menu, "NextMapName" ), GetMapDisplayName( map ) ) Hud_SetVisible( Hud_GetChild( menu, "ServerName" ), true ) - Hud_SetText( Hud_GetChild( menu, "ServerName" ), NSGetServerName( file.serversArrayFiltered[ serverIndex ].serverIndex ) ) + Hud_SetText( Hud_GetChild( menu, "ServerName" ), server.name ) // mode name/image - string mode = file.serversArrayFiltered[ serverIndex ].serverGamemode + string mode = server.playlist Hud_SetVisible( Hud_GetChild( menu, "NextModeIcon" ), true ) RuiSetImage( Hud_GetRui( Hud_GetChild( menu, "NextModeIcon" ) ), "basicImage", GetPlaylistThumbnailImage( mode ) ) Hud_SetVisible( Hud_GetChild( menu, "NextGameModeName" ), true ) if ( mode.len() != 0 ) - Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), mode ) + Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), GetGameModeDisplayName( mode ) ) else Hud_SetText( Hud_GetChild( menu, "NextGameModeName" ), "#NS_SERVERBROWSER_UNKNOWNMODE" ) } -string function FillInServerModsLabel( int server ) +string function FillInServerModsLabel( array mods ) { string ret - for ( int i = 0; i < NSGetServerRequiredModsCount( server ); i++ ) + foreach ( RequiredModInfo mod in mods ) { - ret += " " - ret += NSGetServerRequiredModName( server, i ) + " v" + NSGetServerRequiredModVersion( server, i ) + "\n" + ret += format( " %s v%s\n", mod.name, mod.version ) } + return ret } @@ -957,18 +955,17 @@ void function OnServerSelected( var button ) if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return - int serverIndex = file.focusedServerIndex + ServerInfo server = file.focusedServer - file.lastSelectedServer = serverIndex + file.lastSelectedServer = server - // check mods - for ( int i = 0; i < NSGetServerRequiredModsCount( serverIndex ); i++ ) + foreach ( RequiredModInfo mod in server.requiredMods ) { - if ( !NSGetModNames().contains( NSGetServerRequiredModName( serverIndex, i ) ) ) + if ( !NSGetModNames().contains( mod.name ) ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Missing mod \"" + NSGetServerRequiredModName( serverIndex, i ) + "\" v" + NSGetServerRequiredModVersion( serverIndex, i ) + dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG @@ -985,8 +982,8 @@ void function OnServerSelected( var button ) else { // this uses semver https://semver.org - array serverModVersion = split( NSGetServerRequiredModVersion( serverIndex, i ), "." ) - array clientModVersion = split( NSGetModVersionByModName( NSGetServerRequiredModName( serverIndex, i ) ), "." ) + array serverModVersion = split( mod.name, "." ) + array clientModVersion = split( NSGetModVersionByModName( mod.name ), "." ) bool semverFail = false // if server has invalid semver don't bother checking @@ -1004,7 +1001,7 @@ void function OnServerSelected( var button ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = "Server has mod \"" + NSGetServerRequiredModName( serverIndex, i ) + "\" v" + NSGetServerRequiredModVersion( serverIndex, i ) + " while we have v" + NSGetModVersionByModName( NSGetServerRequiredModName( serverIndex, i ) ) + dialogData.message = format( "Server has mod \"%s\" v%s while we have v%s", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG @@ -1021,13 +1018,16 @@ void function OnServerSelected( var button ) } } - if ( NSServerRequiresPassword( serverIndex ) ) + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else + { + TriggerConnectToServerCallbacks() thread ThreadedAuthAndConnectToServer() + } } @@ -1036,9 +1036,7 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSIsAuthenticatingWithServer() ) return - print( "trying to authenticate with server " + NSGetServerName( file.lastSelectedServer ) + " with password " + password ) - - NSTryAuthWithServer( file.lastSelectedServer, password ) + NSTryAuthWithServer( file.lastSelectedServer.index, password ) ToggleConnectingHUD( true ) @@ -1063,17 +1061,13 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) { bool modsChanged - array requiredMods - for ( int i = 0; i < NSGetServerRequiredModsCount( file.lastSelectedServer ); i++ ) - requiredMods.append( NSGetServerRequiredModName( file.lastSelectedServer, i ) ) - // unload mods we don't need, load necessary ones and reload mods before connecting - foreach ( string mod in NSGetModNames() ) + foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) { - if ( NSIsModRequiredOnClient( mod ) ) + if ( NSIsModRequiredOnClient( mod.name ) ) { - modsChanged = modsChanged || NSIsModEnabled( mod ) != requiredMods.contains( mod ) - NSSetModEnabled( mod, requiredMods.contains( mod ) ) + modsChanged = modsChanged || NSIsModEnabled( mod.name ) != file.lastSelectedServer.requiredMods.contains( mod ) + NSSetModEnabled( mod.name, file.lastSelectedServer.requiredMods.contains( mod ) ) } } @@ -1106,7 +1100,7 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) ////////////////////////////////////// // Shadow realm ////////////////////////////////////// -int function ServerSortLogic ( serverStruct a, serverStruct b ) +int function ServerSortLogic ( ServerInfo a, ServerInfo b ) { var aTemp var bTemp @@ -1117,44 +1111,44 @@ int function ServerSortLogic ( serverStruct a, serverStruct b ) switch ( filterDirection.sortingBy ) { case sortingBy.DEFAULT: - aTemp = a.serverPlayers - bTemp = b.serverPlayers + aTemp = a.playerCount + bTemp = b.playerCount // `1000` is assumed to always be higher than `serverPlayersMax` - if (aTemp + 1 < a.serverPlayersMax) + if (aTemp + 1 < a.maxPlayerCount) aTemp = aTemp+2000 - if (bTemp + 1 < b.serverPlayersMax) + if (bTemp + 1 < b.maxPlayerCount) bTemp = bTemp+2000 - if (aTemp + 1 == a.serverPlayersMax) + if (aTemp + 1 == a.maxPlayerCount) aTemp = aTemp+1000 - if (bTemp + 1 == b.serverPlayersMax) + if (bTemp + 1 == b.maxPlayerCount) bTemp = bTemp+1000 direction = filterDirection.serverName break; case sortingBy.NAME: - aTemp = a.serverName.tolower() - bTemp = b.serverName.tolower() + aTemp = a.name.tolower() + bTemp = b.name.tolower() direction = filterDirection.serverName break; case sortingBy.PLAYERS: - aTemp = a.serverPlayers - bTemp = b.serverPlayers + aTemp = a.playerCount + bTemp = b.playerCount direction = filterDirection.serverPlayers break; case sortingBy.MAP: - aTemp = Localize( a.serverMap ).tolower() - bTemp = Localize( b.serverMap ).tolower() + aTemp = Localize( a.map ).tolower() + bTemp = Localize( b.map ).tolower() direction = filterDirection.serverMap break; case sortingBy.GAMEMODE: - aTemp = Localize( a.serverGamemode ).tolower() - bTemp = Localize( b.serverGamemode ).tolower() + aTemp = Localize( a.playlist ).tolower() + bTemp = Localize( b.playlist ).tolower() direction = filterDirection.serverGamemode break; case sortingBy.REGION: - aTemp = a.serverRegion - bTemp = b.serverRegion + aTemp = a.region + bTemp = b.region direction = filterDirection.serverRegion break; default: @@ -1176,7 +1170,7 @@ void function SortServerListByDefault_Activate ( var button ) { filterDirection.sortingBy = sortingBy.DEFAULT - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverName = !filterDirection.serverName @@ -1188,7 +1182,7 @@ void function SortServerListByName_Activate ( var button ) { filterDirection.sortingBy = sortingBy.NAME - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverName = !filterDirection.serverName @@ -1200,7 +1194,7 @@ void function SortServerListByPlayers_Activate( var button ) { filterDirection.sortingBy = sortingBy.PLAYERS - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverPlayers = !filterDirection.serverPlayers @@ -1211,7 +1205,7 @@ void function SortServerListByMap_Activate( var button ) { filterDirection.sortingBy = sortingBy.MAP - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverMap = !filterDirection.serverMap @@ -1222,7 +1216,7 @@ void function SortServerListByGamemode_Activate( var button ) { filterDirection.sortingBy = sortingBy.GAMEMODE - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverGamemode = !filterDirection.serverGamemode @@ -1233,9 +1227,33 @@ void function SortServerListByRegion_Activate( var button ) { filterDirection.sortingBy = sortingBy.REGION - file.serversArrayFiltered.sort( ServerSortLogic ) + file.filteredServers.sort( ServerSortLogic ) filterDirection.serverRegion = !filterDirection.serverRegion UpdateShownPage() } + +////////////////////////////////////// +// Callbacks +////////////////////////////////////// + +void function AddConnectToServerCallback( void functionref( ServerInfo ) callback ) +{ + if ( file.connectCallbacks.find( callback ) >= 0 ) + throw "ConnectToServerCallback has been registered twice. Duplicate callbacks are not allowed." + file.connectCallbacks.append( callback ) +} + +void function RemoveConnectToServerCallback( void functionref( ServerInfo ) callback ) +{ + file.connectCallbacks.fastremovebyvalue( callback ) +} + +void function TriggerConnectToServerCallbacks() +{ + foreach( callback in file.connectCallbacks ) + { + callback( file.lastSelectedServer ) + } +} -- cgit v1.2.3 From 5fbd1edf7942a542605f6274604ed0e0ba9f20b7 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Sat, 29 Apr 2023 01:55:50 +0800 Subject: Improve AI spawn functions (#626) * initial commit * remove modded contents * Update _ai_gamemodes.gnut * restore HandleScoreEvent() checks * fix squad minimap icon * fix compile error * Update _gamemode_aitdm.nut * update formatting as requested changes * add missing reaper highlight * Formatting * Newline test * Did this work? --------- Co-authored-by: F1F7Y <64418963+F1F7Y@users.noreply.github.com> --- .../scripts/vscripts/gamemodes/_gamemode_fw.nut | 4 +- .../scripts/vscripts/gamemodes/_ai_gamemodes.gnut | 115 +++++++++------- .../scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 146 +++++++++++++++------ 3 files changed, 176 insertions(+), 89 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index b025ff0a..8a26f8bf 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -117,8 +117,8 @@ void function GamemodeFW_Init() // _battery_port.gnut needs this RegisterSignal( "BatteryActivate" ) - AiGameModes_SetGruntWeapons( [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) - AiGameModes_SetSpectreWeapons( [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) AddCallback_EntitiesDidLoad( LoadEntities ) AddCallback_GameStateEnter( eGameState.Prematch, OnFWGamePrematch ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut index 0fad768c..78a9a208 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut @@ -1,7 +1,6 @@ global function AiGameModes_Init -global function AiGameModes_SetGruntWeapons -global function AiGameModes_SetSpectreWeapons +global function AiGameModes_SetNPCWeapons global function AiGameModes_SpawnDropShip global function AiGameModes_SpawnDropPod @@ -15,25 +14,20 @@ const INTRO_DROPSHIP_CUTOFF = 2000 struct { - array< string > gruntWeapons = [ "mp_weapon_rspn101" ] - array< string > spectreWeapons = [ "mp_weapon_hemlok_smg" ] + table< string, array > npcWeaponsTable // npcs have their default weapon in aisettings file } file void function AiGameModes_Init() { - } //------------------------------------------------------ -void function AiGameModes_SetGruntWeapons( array< string > weapons ) +void function AiGameModes_SetNPCWeapons( string npcClass, array weapons ) { - file.gruntWeapons = weapons -} - -void function AiGameModes_SetSpectreWeapons( array< string > weapons ) -{ - file.spectreWeapons = weapons + if ( !( npcClass in file.npcWeaponsTable ) ) + file.npcWeaponsTable[ npcClass ] <- [] + file.npcWeaponsTable[ npcClass ] = weapons } //------------------------------------------------------ @@ -59,7 +53,7 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c foreach ( guy in guys ) { - ReplaceWeapon( guy, file.gruntWeapons[ RandomInt( file.gruntWeapons.len() ) ], [] ) + SetUpNPCWeapons( guy ) guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) } @@ -70,29 +64,21 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null ) { - string squadName = MakeSquadName( team, UniqueString( "" ) ) - array guys - entity pod = CreateDropPod( pos, <0,0,0> ) InitFireteamDropPod( pod ) - + + waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) + + string squadName = MakeSquadName( team, UniqueString( "" ) ) + array guys for ( int i = 0; i < 4 ;i++ ) { entity npc = CreateNPC( content, team, pos,<0,0,0> ) DispatchSpawn( npc ) SetSquad( npc, squadName ) - switch ( content ) - { - case "npc_soldier": - ReplaceWeapon( npc, file.gruntWeapons[ RandomInt( file.gruntWeapons.len() ) ], [] ) - break - - case "npc_spectre": - ReplaceWeapon( npc, file.spectreWeapons[ RandomInt( file.spectreWeapons.len() ) ], [] ) - break - } + SetUpNPCWeapons( npc ) npc.SetParent( pod, "ATTACH", true ) @@ -100,25 +86,26 @@ void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string guys.append( npc ) } - // The order here is different so we can show on minimap while were still falling + ActivateFireteamDropPod( pod, guys ) + + // start searching for enemies if ( squadHandler != null ) thread squadHandler( guys ) - - waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) - - ActivateFireteamDropPod( pod, guys ) } +const float REAPER_WARPFALL_DELAY = 4.7 // same as fd does void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string aiSettings = "", void functionref( entity reaper ) reaperHandler = null ) { - thread Reaper_Spawnpoint( pos, team, 11.2 ) + float reaperLandTime = REAPER_WARPFALL_DELAY + 1.2 // reaper takes ~1.2s to warpfall + thread HotDrop_Spawnpoint( pos, team, reaperLandTime, false, damagedef_reaper_fall ) - wait 10 - // spawn reapers right before it warpfalls, or round_end clean up will crash the game + wait REAPER_WARPFALL_DELAY entity reaper = CreateSuperSpectre( team, pos, rot ) + reaper.EndSignal( "OnDestroy" ) // reaper highlight Highlight_SetFriendlyHighlight( reaper, "sp_enemy_pilot" ) - reaper.Highlight_SetParam( 1, 0, < 3,3,3 > ) + reaper.Highlight_SetParam( 1, 0, < 1,1,1 > ) + SetDefaultMPEnemyHighlight( reaper ) Highlight_SetEnemyHighlight( reaper, "enemy_titan" ) SetSpawnOption_Titanfall( reaper ) @@ -127,15 +114,18 @@ void function AiGameModes_SpawnReaper( vector pos, vector rot, int team, string if ( aiSettings != "" ) SetSpawnOption_AISettings( reaper, aiSettings ) + HideName( reaper ) // prevent flash a name onto it DispatchSpawn( reaper ) - + + reaper.WaitSignal( "WarpfallComplete" ) + ShowName( reaper ) // show name again after drop if ( reaperHandler != null ) thread reaperHandler( reaper ) } // copied from cl_replacement_titan_hud.gnut -void function Reaper_Spawnpoint( vector origin, int team, float impactTime, bool hasFriendlyWarning = false ) +void function HotDrop_Spawnpoint( vector origin, int team, float impactTime, bool hasFriendlyWarning = false, int damageDef = -1 ) { array targetEffects = [] vector surfaceNormal = < 0, 0, 1 > @@ -146,32 +136,50 @@ void function Reaper_Spawnpoint( vector origin, int team, float impactTime, bool { entity effectFriendly = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) SetTeam( effectFriendly, team ) - EffectSetControlPointVector( effectFriendly, 1, < 128,188,255 > ) + EffectSetControlPointVector( effectFriendly, 1, FRIENDLY_COLOR_FX ) effectFriendly.kv.VisibilityFlags = ENTITY_VISIBLE_TO_FRIENDLY + effectFriendly.DisableHibernation() // prevent it from fading out targetEffects.append( effectFriendly ) } entity effectEnemy = StartParticleEffectInWorld_ReturnEntity( index, origin, surfaceNormal ) SetTeam( effectEnemy, team ) - EffectSetControlPointVector( effectEnemy, 1, < 255,99,0 > ) + EffectSetControlPointVector( effectEnemy, 1, ENEMY_COLOR_FX ) effectEnemy.kv.VisibilityFlags = ENTITY_VISIBLE_TO_ENEMY + effectEnemy.DisableHibernation() // prevent it from fading out targetEffects.append( effectEnemy ) - + + // so enemy npcs will mostly avoid them + entity damageAreaInfo + if ( damageDef > -1 ) + { + damageAreaInfo = CreateEntity( "info_target" ) + DispatchSpawn( damageAreaInfo ) + AI_CreateDangerousArea_DamageDef( damageDef, damageAreaInfo, team, true, true ) + } + wait impactTime + // clean up foreach( entity targetEffect in targetEffects ) { if ( IsValid( targetEffect ) ) EffectStop( targetEffect ) } + if ( IsValid( damageAreaInfo ) ) + damageAreaInfo.Destroy() } // including aisettings stuff specifically for at bounty titans +const float TITANFALL_WARNING_DURATION = 5.0 void function AiGameModes_SpawnTitan( vector pos, vector rot, int team, string setFile, string aiSettings = "", void functionref( entity titan ) titanHandler = null ) { entity titan = CreateNPCTitan( setFile, TEAM_BOTH, pos, rot ) SetSpawnOption_Titanfall( titan ) SetSpawnOption_Warpfall( titan ) + + // modified: do a hotdrop spawnpoint warning + thread HotDrop_Spawnpoint( pos, team, TITANFALL_WARNING_DURATION, false, damagedef_titan_fall ) if ( aiSettings != "" ) SetSpawnOption_AISettings( titan, aiSettings ) @@ -182,12 +190,27 @@ void function AiGameModes_SpawnTitan( vector pos, vector rot, int team, string s thread titanHandler( titan ) } -// entity.ReplaceActiveWeapon gave grunts archers sometimes, this is my replacement for it -void function ReplaceWeapon( entity guy, string weapon, array mods ) +void function SetUpNPCWeapons( entity guy ) { - guy.TakeActiveWeapon() - guy.GiveWeapon( weapon, mods ) - guy.SetActiveWeaponByName( weapon ) + string className = guy.GetClassName() + + array mainWeapons + if ( className in file.npcWeaponsTable ) + mainWeapons = file.npcWeaponsTable[ className ] + + if ( mainWeapons.len() == 0 ) // no valid weapons + return + + // take off existing main weapons, or sometimes they'll have a archer by default + foreach ( entity weapon in guy.GetMainWeapons() ) + guy.TakeWeapon( weapon.GetWeaponClassName() ) + + if ( mainWeapons.len() > 0 ) + { + string weaponName = mainWeapons[ RandomInt( mainWeapons.len() ) ] + guy.GiveWeapon( weaponName ) + guy.SetActiveWeaponByName( weaponName ) + } } // Checks if we can spawn a dropship at a node, this should guarantee dropship ziplines diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index fae778d6..702e4500 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -1,22 +1,36 @@ untyped global function GamemodeAITdm_Init -const SQUADS_PER_TEAM = 3 +// these are now default settings +const int SQUADS_PER_TEAM = 4 -const REAPERS_PER_TEAM = 2 +const int REAPERS_PER_TEAM = 2 -const LEVEL_SPECTRES = 125 -const LEVEL_STALKERS = 380 -const LEVEL_REAPERS = 500 +const int LEVEL_SPECTRES = 125 +const int LEVEL_STALKERS = 380 +const int LEVEL_REAPERS = 500 + +// add settings +global function AITdm_SetSquadsPerTeam +global function AITdm_SetReapersPerTeam +global function AITdm_SetLevelSpectres +global function AITdm_SetLevelStalkers +global function AITdm_SetLevelReapers struct { // Due to team based escalation everything is an array - array< int > levels = [ LEVEL_SPECTRES, LEVEL_SPECTRES ] + array< int > levels = [] // Initilazed in `Spawner_Threaded` array< array< string > > podEntities = [ [ "npc_soldier" ], [ "npc_soldier" ] ] array< bool > reapers = [ false, false ] -} file + // default settings + int squadsPerTeam = SQUADS_PER_TEAM + int reapersPerTeam = REAPERS_PER_TEAM + int levelSpectres = LEVEL_SPECTRES + int levelStalkers = LEVEL_STALKERS + int levelReapers = LEVEL_REAPERS +} file void function GamemodeAITdm_Init() { @@ -34,18 +48,47 @@ void function GamemodeAITdm_Init() if ( GetCurrentPlaylistVarInt( "aitdm_archer_grunts", 0 ) == 0 ) { - AiGameModes_SetGruntWeapons( [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) - AiGameModes_SetSpectreWeapons( [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_hemlok_smg", "mp_weapon_lstar", "mp_weapon_mastiff" ] ) } else { - AiGameModes_SetGruntWeapons( [ "mp_weapon_rocket_launcher" ] ) - AiGameModes_SetSpectreWeapons( [ "mp_weapon_rocket_launcher" ] ) + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rocket_launcher" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_rocket_launcher" ] ) + AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_rocket_launcher" ] ) } ScoreEvent_SetupEarnMeterValuesForMixedModes() } +// add settings +void function AITdm_SetSquadsPerTeam( int squads ) +{ + file.squadsPerTeam = squads +} + +void function AITdm_SetReapersPerTeam( int reapers ) +{ + file.reapersPerTeam = reapers +} + +void function AITdm_SetLevelSpectres( int level ) +{ + file.levelSpectres = level +} + +void function AITdm_SetLevelStalkers( int level ) +{ + file.levelStalkers = level +} + +void function AITdm_SetLevelReapers( int level ) +{ + file.levelReapers = level +} +// + // Starts skyshow, this also requiers AINs but doesn't crash if they're missing void function OnPrematchStart() { @@ -74,11 +117,9 @@ void function HandleScoreEvent( entity victim, entity attacker, var damageInfo ) // Basic checks if ( victim == attacker || !( attacker.IsPlayer() || attacker.IsTitan() ) || GetGameState() != eGameState.Playing ) return - // Hacked spectre filter if ( victim.GetOwner() == attacker ) return - // NPC titans without an owner player will not count towards any team's score if ( attacker.IsNPC() && attacker.IsTitan() && !IsValid( GetPetTitanOwner( attacker ) ) ) return @@ -193,7 +234,7 @@ void function SpawnIntroBatch_Threaded( int team ) int ships = shipNodes.len() - for ( int i = 0; i < SQUADS_PER_TEAM; i++ ) + for ( int i = 0; i < file.squadsPerTeam; i++ ) { if ( pods != 0 || ships == 0 ) { @@ -238,6 +279,7 @@ void function Spawner_Threaded( int team ) // used to index into escalation arrays int index = team == TEAM_MILITIA ? 0 : 1 + file.levels = [ file.levelSpectres, file.levelSpectres ] // due we added settings, should init levels here! while( true ) { @@ -252,7 +294,7 @@ void function Spawner_Threaded( int team ) if ( file.reapers[ index ] ) { array< entity > points = SpawnPoints_GetDropPod() - if ( reaperCount < REAPERS_PER_TEAM ) + if ( reaperCount < file.reapersPerTeam ) { entity node = points[ GetSpawnPointIndex( points, team ) ] waitthread AiGameModes_SpawnReaper( node.GetOrigin(), node.GetAngles(), team, "npc_super_spectre_aitdm", ReaperHandler ) @@ -260,7 +302,7 @@ void function Spawner_Threaded( int team ) } // NORMAL SPAWNS - if ( count < SQUADS_PER_TEAM * 4 - 2 ) + if ( count < file.squadsPerTeam * 4 - 2 ) { string ent = file.podEntities[ index ][ RandomInt( file.podEntities[ index ].len() ) ] @@ -306,19 +348,19 @@ void function Escalate( int team ) // Based on score escalate a team switch ( file.levels[ index ] ) { - case LEVEL_SPECTRES: - file.levels[ index ] = LEVEL_STALKERS + case file.levelSpectres: + file.levels[ index ] = file.levelStalkers file.podEntities[ index ].append( "npc_spectre" ) SetGlobalNetInt( defcon, 2 ) return - case LEVEL_STALKERS: - file.levels[ index ] = LEVEL_REAPERS + case file.levelStalkers: + file.levels[ index ] = file.levelReapers file.podEntities[ index ].append( "npc_stalker" ) SetGlobalNetInt( defcon, 3 ) return - case LEVEL_REAPERS: + case file.levelReapers: file.reapers[ index ] = true SetGlobalNetInt( defcon, 4 ) return @@ -355,30 +397,47 @@ int function GetSpawnPointIndex( array< entity > points, int team ) // AI can also flee deeper into their zone suggesting someone spent way too much time on this void function SquadHandler( array guys ) { + int team = guys[0].GetTeam() + // show the squad enemy radar + array players = GetPlayerArrayOfEnemies( team ) + foreach ( entity guy in guys ) + { + if ( IsAlive( guy ) ) + { + foreach ( player in players ) + guy.Minimap_AlwaysShow( 0, player ) + } + } + // Not all maps have assaultpoints / have weird assault points ( looking at you ac ) // So we use enemies with a large radius - array< entity > points = GetNPCArrayOfEnemies( guys[0].GetTeam() ) - - if ( points.len() == 0 ) + while ( GetNPCArrayOfEnemies( team ).len() == 0 ) // if we can't find any enemy npcs, keep waiting + WaitFrame() + + // our waiting is end, check if any soldiers left + bool squadAlive = false + foreach ( entity guy in guys ) + { + if ( IsAlive( guy ) ) + squadAlive = true + else + guys.removebyvalue( guy ) + } + if ( !squadAlive ) return + + array points = GetNPCArrayOfEnemies( team ) vector point point = points[ RandomInt( points.len() ) ].GetOrigin() - array players = GetPlayerArrayOfEnemies( guys[0].GetTeam() ) - - // Setup AI + // Setup AI, first assault point foreach ( guy in guys ) { guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) guy.AssaultPoint( point ) guy.AssaultSetGoalRadius( 1600 ) // 1600 is minimum for npc_stalker, works fine for others - - // show on enemy radar - foreach ( player in players ) - guy.Minimap_AlwaysShow( 0, player ) - - + //thread AITdm_CleanupBoredNPCThread( guy ) } @@ -396,16 +455,21 @@ void function SquadHandler( array guys ) // Stop func if our squad has been killed off if ( guys.len() == 0 ) return + } + + // Get point and send our whole squad to it + points = GetNPCArrayOfEnemies( team ) + if ( points.len() == 0 ) // can't find any points here + continue - // Get point and send guy to it - points = GetNPCArrayOfEnemies( guy.GetTeam() ) - if ( points.len() == 0 ) - continue - - point = points[ RandomInt( points.len() ) ].GetOrigin() - - guy.AssaultPoint( point ) + point = points[ RandomInt( points.len() ) ].GetOrigin() + + foreach ( guy in guys ) + { + if ( IsAlive( guy ) ) + guy.AssaultPoint( point ) } + wait RandomFloatRange(5.0,15.0) } } -- cgit v1.2.3 From 0c14242f758d294187cd9cfbe7057bbe239d1ee1 Mon Sep 17 00:00:00 2001 From: F1F7Y <64418963+F1F7Y@users.noreply.github.com> Date: Mon, 1 May 2023 02:56:11 +0200 Subject: Add Bounty Hunt (#634) * Unlock bountyhunt in mode select menu * Initial push * Go through bank functions * Bug spotting * dissolve droppods faster * better camp hack solution * Revert wave start to 1st wave * Small formatting cleanup * Limit score to max playlist allows * Try to make ai camps work * Potentially fix winner not being set * metal pipe falling sound effect * Acteally document change * Better fix for match not properly ending * Add MVP dialogue (#631) * MVP dialogue and small audio fix * maybe better AI movement * revert accidental change * Remove comment about a already fixed issue * Revert froce assault point waitsignal * Don't reward player for ejecting * Don't reward for killing player npc titan * Don't allow titans to run banking thread * Bored npcs cleanup logic * Remove lefover whitespace changes * Metal pipe falling sound 2x * One day my brain will start properly functioning * Include reapers in bored check * Add bored check to other droppod func * Revert testing change * Fix typo * Remove debug prints * Debug log stuck AI for future navmesh debugging Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Fix formatting * [BH] Lock scores after game end (#635) * stop awarding score after game is ended --------- Co-authored-by: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../mod/scripts/vscripts/ui/menu_mode_select.nut | 3 +- .../scripts/vscripts/gamemodes/_ai_gamemodes.gnut | 4 +- .../scripts/vscripts/gamemodes/_gamemode_at.nut | 1941 +++++++++++++++++--- 3 files changed, 1694 insertions(+), 254 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut index 32a3c8f5..52a99b6f 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut @@ -52,7 +52,8 @@ void function UpdateVisibleModes() Hud_SetEnabled( buttons[ i ], true ) Hud_SetVisible( buttons[ i ], true ) - if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" ) + // This check is refactored in the new mode menu so we can just ignore this atrocity + if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" || modesArray[ modeIndex ] == "at" ) Hud_SetLocked( buttons[ i ], false ) else Hud_SetLocked( buttons[ i ], true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut index 78a9a208..4ed7ee4a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_ai_gamemodes.gnut @@ -62,11 +62,11 @@ void function AiGameModes_SpawnDropShip( vector pos, vector rot, int team, int c } -void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null ) +void function AiGameModes_SpawnDropPod( vector pos, vector rot, int team, string content /*( ͡° ͜ʖ ͡°)*/, void functionref( array guys ) squadHandler = null, int flags = 0 ) { entity pod = CreateDropPod( pos, <0,0,0> ) - InitFireteamDropPod( pod ) + InitFireteamDropPod( pod, flags ) waitthread LaunchAnimDropPod( pod, "pod_testpath", pos, rot ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 915e03e0..c61cb585 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -1,12 +1,54 @@ +untyped // AddCallback_OnUseEntity() needs this global function GamemodeAt_Init global function RateSpawnpoints_AT -const int BH_AI_TEAM = TEAM_BOTH -const int BOUNTY_TITAN_DAMAGE_POOL = 400 // Rewarded for damage -const int BOUNTY_TITAN_KILL_REWARD = 100 // Rewarded for kill -const float WAVE_STATE_TRANSITION_TIME = 5.0 +// Old bobr note which still applies after a year :) +// IMPLEMENTATION NOTES: +// bounty hunt is a mode that was clearly pretty heavily developed, and had alot of scrapped concepts (i.e. most wanted player bounties, turret bounties, collectable blackbox objectives) +// in the interest of time, this script isn't gonna support any of that atm +// alot of the remote functions also take parameters that aren't used, i'm not gonna populate these and just use default values for now instead +// however, if you do want to mess with this stuff, almost all the remote functions for this stuff are still present in cl_gamemode_at, and should work fine with minimal fuckery in my experience + + +// Bank settings +const float AT_BANKS_OPEN_DURATION = 45.0 // Bank open time +const int AT_BANK_DEPOSIT_RATE = 10 // Amount deposited per second +const int AT_BANK_DEPOSIT_RADIUS = 256 // bank radius for depositing +const float AT_BANK_FORCE_CLOSE_DELAY = 4.0 // If all bonus money has been deposited close the banks after this constant early + +// TODO: The reference function no longer exists, check if this still holds true +// VoyageDB: HACK score events... respawn made things in AT_SetScoreEventOverride() really messed up, have to do some hack here +const array AT_ENABLE_SCOREEVENTS = +[ + // these are disabled in AT_SetScoreEventOverride(), but related scoreEvents are not implemented into gamemode + // needs to re-enable them + "DoomTitan", + "DoomAutoTitan" +] +const array AT_DISABLE_SCOREEVENTS = +[ + // these are missed in AT_SetScoreEventOverride(), but game actually used them + // needs to disable them + "KillStalker" +] + +// Wave settings +// General +const int AT_AI_TEAM = TEAM_BOTH // Allow AI to attack and be attacked by both player teams +const float AT_FIRST_WAVE_START_DELAY = 10.0 // First wave has an extra delay before begining +const float AT_WAVE_TRANSITION_DELAY = 5.0 // Time between each wave and banks opening/closing +const float AT_WAVE_END_ANNOUNCEMENT_DELAY = 1.0 // Extra wait before announcing wave cleaned + +// Squad settings +const int AT_DROPPOD_SQUADS_ALLOWED_ON_FIELD = 4 // default is 4 droppod squads on field, won't use if AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK turns on // TODO: verify this + +// Titan bounty settings +const float AT_BOUNTY_TITAN_CHECK_DELAY = 10.0 // wait for bounty titans landing before we start checking their life state +const float AT_BOUNTY_TITAN_HEALTH_MULTIPLIER = 3 // TODO: Verify this -const array VALID_BOUNTY_TITAN_SETTINGS = [ +// Titan boss settings, check sh_gamemode_at.nut for more info +const array AT_BOUNTY_TITANS_AI_SETTINGS = +[ "npc_titan_atlas_stickybomb_bounty", "npc_titan_atlas_tracker_bounty", "npc_titan_ogre_minigun_bounty", @@ -16,302 +58,1565 @@ const array VALID_BOUNTY_TITAN_SETTINGS = [ "npc_titan_atlas_vanguard_bounty" ] +// Extra +// Respawn didn't use the "totalAllowedOnField" for npc spawning, they only allow 1 squad to be on field for each type of npc. enabling this might cause too much npcs spawning and crash the game +const bool AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK = false + +// Objectives +const int AT_OBJECTIVE_EMPTY = -1 // Remove objective +const int AT_OBJECTIVE_KILL_DZ = 104 // #AT_OBJECTIVE_KILL_DZ +const int AT_OBJECTIVE_KILL_DZ_MULTI = 105 // #AT_OBJECTIVE_KILL_DZ_MULTI +const int AT_OBJECTIVE_KILL_BOSS = 106 // #AT_OBJECTIVE_KILL_BOSS +const int AT_OBJECTIVE_KILL_BOSS_MULTI = 107 // #AT_OBJECTIVE_KILL_BOSS_MULTI +const int AT_OBJECTIVE_BANK_OPEN = 109 // #AT_BANK_OPEN_OBJECTIVE + +// When a player tries to deposit when they have 0 bonus money +// we show a help mesage, this is the ratelimit for that message +// so that we dont spam it too much +const float AT_PLAYER_HUD_MESSAGE_COOLDOWN = 2.5 + +// Due to bad navmeshes NPCs may wonder off to bumfuck nowhere or the game +// might teleport them into the map while trying to correct their position +// This obviously breaks bounty hunt where the objective is to kill ALL ai +// so we try to cleanup the camps after a set amount of time of inactivity +const int AT_CAMP_BORED_NPCS_LEFT_TO_START_CLEANUP = 3 +const float AT_CAMP_BORED_CLEANUP_WAIT = 60.0 +struct +{ + array banks + array camps + + // Used to track ScriptmanagedEntArrays of ai squads + table< int, array > campScriptEntArrays + + table< entity, bool > titanIsBountyBoss + table< entity, int > bountyTitanRewards + table< entity, int > npcStolenBonus + table< entity, bool > playerBankUploading + table< entity, table > playerSavedBountyDamage + table< entity, float > playerHudMessageAllowedTime +} file + +void function GamemodeAt_Init() +{ + // wave + RegisterSignal( "ATWaveEnd" ) + // camp + RegisterSignal( "ATCampClean" ) + RegisterSignal( "ATAllCampsClean" ) + + // Set-up score callbacks + ScoreEvent_SetupEarnMeterValuesForMixedModes() + AddDamageFinalCallback( "npc_titan", OnNPCTitanFinalDamaged ) + AddCallback_OnPlayerKilled( AT_PlayerOrNPCKilledScoreEvent ) + AddCallback_OnNPCKilled( AT_PlayerOrNPCKilledScoreEvent ) + + // Set npc weapons + AiGameModes_SetNPCWeapons( "npc_soldier", [ "mp_weapon_rspn101", "mp_weapon_dmr", "mp_weapon_r97", "mp_weapon_lmg" ] ) + AiGameModes_SetNPCWeapons( "npc_spectre", [ "mp_weapon_hemlok_smg", "mp_weapon_doubletake", "mp_weapon_mastiff" ] ) + AiGameModes_SetNPCWeapons( "npc_stalker", [ "mp_weapon_hemlok_smg", "mp_weapon_lstar", "mp_weapon_mastiff" ] ) + + // Gamestate callbacks + AddCallback_GameStateEnter( eGameState.Prematch, OnATGamePrematch ) + AddCallback_GameStateEnter( eGameState.Playing, OnATGamePlaying ) + + // Initilaze player + AddCallback_OnClientConnected( InitialiseATPlayer ) + + // Initilaze gamemode entities + AddCallback_EntitiesDidLoad( OnEntitiesDidLoad ) +} + +void function RateSpawnpoints_AT( int checkclass, array spawnpoints, int team, entity player ) +{ + RateSpawnpoints_Generic( checkclass, spawnpoints, team, player ) +} + + + +//////////////////////////////////////// +///// GAMESTATE CALLBACK FUNCTIONS ///// +//////////////////////////////////////// + +void function OnATGamePrematch() +{ + AT_ScoreEventsValueSetUp() +} + +void function OnATGamePlaying() +{ + thread AT_GameLoop_Threaded() +} + +//////////////////////////////////////////// +///// GAMESTATE CALLBACK FUNCTIONS END ///// +//////////////////////////////////////////// + + + +//////////////////////////// +///// PLAYER FUNCTIONS ///// +//////////////////////////// + +void function InitialiseATPlayer( entity player ) +{ + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_OnPlayerConnected" ) + player.SetPlayerNetInt( "AT_bonusPointMult", 1 ) + file.playerBankUploading[ player ] <- false + file.playerSavedBountyDamage[ player ] <- {} + file.playerHudMessageAllowedTime[ player ] <- 0.0 + thread AT_PlayerTitleThink( player ) + thread AT_PlayerObjectiveThink( player ) +} + +void function AT_PlayerTitleThink( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + while ( true ) + { + if ( GetGameState() == eGameState.Playing ) + { + // Set player money count + player.SetTitle( "$" + string( AT_GetPlayerBonusPoints( player ) ) ) + } + else if ( GetGameState() >= eGameState.WinnerDetermined ) + { + if ( player.IsTitan() ) + player.SetTitle( GetTitanPlayerTitle( player ) ) + else + player.SetTitle( "" ) + + return + } + + WaitFrame() + } +} + +string function GetTitanPlayerTitle( entity player ) +{ + entity soul = player.GetTitanSoul() + + if ( !IsValid( soul ) ) + return "" + + string settings = GetSoulPlayerSettings( soul ) + var title = GetPlayerSettingsFieldForClassName( settings, "printname" ) + + if ( title == null ) + return "" + + return expect string( title ) +} + +void function AT_PlayerObjectiveThink( entity player ) +{ + player.EndSignal( "OnDestroy" ) + + int curObjective = AT_OBJECTIVE_EMPTY + while ( true ) + { + // game entered other state + if ( GetGameState() >= eGameState.WinnerDetermined ) + { + player.SetPlayerNetInt( "gameInfoStatusText", AT_OBJECTIVE_EMPTY ) + return + } + + int nextObjective = AT_OBJECTIVE_EMPTY + + // Determine objective text for player + if ( !IsAlive( player ) ) // Don't show objective to dead players + { + nextObjective = AT_OBJECTIVE_EMPTY + } + else // We're still alive + { + if ( GetGlobalNetBool( "banksOpen" ) ) + { + nextObjective = AT_OBJECTIVE_BANK_OPEN + } + else if ( GetGlobalNetBool( "preBankPhase" ) ) + { + nextObjective = AT_OBJECTIVE_EMPTY + } + else + { + // No checks have passed, try to do a "Kill all x near the marked dropzone" objective + int dropZoneActiveCount = 0 + int bossAliveCount = 0 + array campEnts + campEnts.append( GetGlobalNetEnt( "camp1Ent" ) ) + campEnts.append( GetGlobalNetEnt( "camp2Ent" ) ) + + foreach ( entity ent in campEnts ) + { + if ( IsValid( ent ) ) + { + if ( ent.IsTitan() ) + bossAliveCount += 1 + else + dropZoneActiveCount += 1 + } + } + + switch( dropZoneActiveCount ) + { + case 1: + nextObjective = AT_OBJECTIVE_KILL_DZ + break + case 2: + nextObjective = AT_OBJECTIVE_KILL_DZ_MULTI + break + } + + switch( bossAliveCount ) + { + case 1: + nextObjective = AT_OBJECTIVE_KILL_BOSS + break + case 2: + nextObjective = AT_OBJECTIVE_KILL_BOSS_MULTI + break + } + + // We couldn't get an objective, set it to empty + if ( dropZoneActiveCount == 0 && bossAliveCount == 0 ) + nextObjective = AT_OBJECTIVE_EMPTY + } + } + + // Set the objective when changed + if ( curObjective != nextObjective ) + { + player.SetPlayerNetInt( "gameInfoStatusText", nextObjective ) + curObjective = nextObjective + } + + WaitFrame() + } +} + +//////////////////////////////// +///// PLAYER FUNCTIONS END ///// +//////////////////////////////// + + + +//////////////////////////////////////// +///// GAMEMODE INITILAZE FUNCTIONS ///// +//////////////////////////////////////// + +void function OnEntitiesDidLoad() +{ + foreach ( entity info_target in GetEntArrayByClass_Expensive( "info_target" ) ) + { + if( info_target.HasKey( "editorclass" ) ) + { + switch( info_target.kv.editorclass ) + { + case "info_attrition_bank": + entity bank = CreateEntity( "prop_script" ) + bank.SetScriptName( "AT_Bank" ) // VoyageDB: don't know how to make client able to track it + bank.SetOrigin( info_target.GetOrigin() ) + bank.SetAngles( info_target.GetAngles() ) + DispatchSpawn( bank ) + bank.kv.solid = SOLID_VPHYSICS + bank.SetModel( info_target.GetModelName() ) + + // Minimap icon init + bank.Minimap_SetCustomState( eMinimapObject_prop_script.AT_BANK ) + bank.Minimap_SetAlignUpright( true ) + bank.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + bank.Minimap_Hide( TEAM_IMC, null ) + bank.Minimap_Hide( TEAM_MILITIA, null ) + + // Create tracker ent + // we don't need to store these at all, client just needs to get them + DispatchSpawn( GetAvailableBankTracker( bank ) ) + + // Make sure the bank is in it's disabled pose + thread PlayAnim( bank, "mh_inactive_idle" ) + // Set the bank usable + AddCallback_OnUseEntity( bank, OnPlayerUseBank ) + bank.SetUsable() + bank.SetUsePrompts( "#AT_USE_BANK_CLOSED", "#AT_USE_BANK_CLOSED" ) + + file.banks.append( bank ) + break; + case "info_attrition_camp": + AT_WaveOrigin campStruct + campStruct.ent = info_target + campStruct.origin = info_target.GetOrigin() + campStruct.radius = expect string( info_target.kv.radius ).tofloat() + campStruct.height = expect string( info_target.kv.height ).tofloat() + + // Assumes every info_attrition_camp will have all 9 phases, possibly not a good idea? + // TODO: verify this on all vanilla maps before release + for ( int i = 0; i < 9; i++ ) + campStruct.phaseAllowed.append( expect string( info_target.kv[ "phase_" + ( i + 1 ) ] ) == "1" ) + + // Get droppod spawns within the camp + foreach ( entity spawnpoint in SpawnPoints_GetDropPod() ) + { + vector campPos = info_target.GetOrigin() + vector spawnPos = spawnpoint.GetOrigin() + if ( Distance( campPos, spawnPos ) < campStruct.radius ) + campStruct.dropPodSpawnPoints.append( spawnpoint ) + } + + // Get titan spawns within the camp + foreach ( entity spawnpoint in SpawnPoints_GetTitan() ) + { + vector campPos = info_target.GetOrigin() + vector spawnPos = spawnpoint.GetOrigin() + if ( Distance( campPos, spawnPos ) < campStruct.radius ) + campStruct.titanSpawnPoints.append( spawnpoint ) + } + + file.camps.append( campStruct ) + break; + } + } + } +} + +//////////////////////////////////////////// +///// GAMEMODE INITILAZE FUNCTIONS END ///// +//////////////////////////////////////////// + + + +///////////////////////////// +///// SCORING FUNCTIONS ///// +///////////////////////////// + +// TODO: Don't reward in postmatch +// TODO: Dropping a titan on a bounty with it's dome-shield still up rewards you the bonus, but +// it doesn't actually damage the bounty titan + +void function AT_ScoreEventsValueSetUp() +{ + ScoreEvent_SetEarnMeterValues( "KillTitan", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillAutoTitan", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "AttritionTitanKilled", 0.10, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillPilot", 0.10, 0.10 ) + ScoreEvent_SetEarnMeterValues( "AttritionPilotKilled", 0.10, 0.10 ) + ScoreEvent_SetEarnMeterValues( "AttritionBossKilled", 0.10, 0.20 ) + ScoreEvent_SetEarnMeterValues( "AttritionGruntKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionSpectreKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionStalkerKilled", 0.02, 0.02, 0.5 ) + ScoreEvent_SetEarnMeterValues( "AttritionSuperSpectreKilled", 0.10, 0.10, 0.5 ) + + // HACK + foreach ( string eventName in AT_ENABLE_SCOREEVENTS ) + ScoreEvent_Enable( GetScoreEvent( eventName ) ) + + foreach ( string eventName in AT_DISABLE_SCOREEVENTS ) + ScoreEvent_Disable( GetScoreEvent( eventName ) ) +} + +void function AT_PlayerOrNPCKilledScoreEvent( entity victim, entity attacker, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + // Suicide + if ( attacker == victim ) + { + if ( victim.IsPlayer() ) + AT_PlayerBonusLoss( victim, AT_GetPlayerBonusPoints( victim ) / 2 ) + + return + } + + // NPC is the attacker + if ( !attacker.IsPlayer() ) + { + if ( attacker.IsTitan() && IsValid( GetPetTitanOwner( attacker ) ) ) // Re-asign attacker + attacker = GetPetTitanOwner( attacker ) + else // NPC steals money from player, killing it will award the stolen bonus + normal reward + AT_NPCTryStealBonusPoints( attacker, victim ) + + return + } + + // Get event name + string eventName = GetAttritionScoreEventName( victim.GetClassName() ) + + if ( victim.IsTitan() ) // titan specific + eventName = GetAttritionScoreEventNameFromAI( victim ) + + if ( eventName == "" ) // no valid scoreEvent + return + + int scoreVal = ScoreEvent_GetPointValue( GetScoreEvent( eventName ) ) + + // pet titan check + if ( victim.IsTitan() && IsValid( GetPetTitanOwner( victim ) ) ) + { + if( GetPetTitanOwner( victim ) == attacker ) // Player ejected + return + + if( GetPetTitanOwner( victim ).IsPlayer() ) // Killed player npc titan + return + + scoreVal = ATTRITION_SCORE_TITAN_MIN + } + + // killed npc + if ( victim.IsNPC() ) + { + int bonusFromNPC = 0 + // If NPC was carrying a bonus award it to the attacker + if ( victim in file.npcStolenBonus ) + { + bonusFromNPC = file.npcStolenBonus[ victim ] + delete file.npcStolenBonus[ victim ] + } + AT_AddPlayerBonusPointsForEntityKilled( attacker, scoreVal, damageInfo, bonusFromNPC ) + AddPlayerScore( attacker, eventName ) // we add scoreEvent here, since basic score events has been overwrited by sh_gamemode_at.nut + // update score difference and scoreboard + AT_AddToPlayerTeamScore( attacker, scoreVal ) + } + + // bonus stealing check + if ( victim.IsPlayer() ) + AT_PlayerTryStealBonusPoints( attacker, victim, damageInfo ) +} + +bool function AT_NPCTryStealBonusPoints( entity attacker, entity victim ) +{ + // basic checks + if ( !attacker.IsNPC() ) + return false + + if ( !victim.IsPlayer() ) + return false + + int victimBonus = AT_GetPlayerBonusPoints( victim ) + int bonusToSteal = victimBonus / 2 // npc always steal half the bonus from player, no extra bonus for killing the player + if ( bonusToSteal == 0 ) // player has no bonus! + return false + + if ( !( attacker in file.npcStolenBonus ) ) // init + file.npcStolenBonus[ attacker ] <- 0 + + file.npcStolenBonus[ attacker ] += bonusToSteal + + AT_PlayerBonusLoss( victim, bonusToSteal ) // tell victim of bonus stolen + + if ( !( attacker in file.titanIsBountyBoss ) ) // if attacker npc is not a bounty titan, we make them highlighted + NPCBountyStolenHighlight( attacker ) + + return true +} + +void function NPCBountyStolenHighlight( entity npc ) +{ + Highlight_SetEnemyHighlight( npc, "enemy_boss_bounty" ) +} + +bool function AT_PlayerTryStealBonusPoints( entity attacker, entity victim, var damageInfo ) +{ + // basic checks + if ( !attacker.IsPlayer() ) + return false + + if ( !victim.IsPlayer() ) + return false + + int victimBonus = AT_GetPlayerBonusPoints( victim ) + + int minScoreCanSteal = ATTRITION_SCORE_PILOT_MIN + if ( victim.IsTitan() ) + minScoreCanSteal = ATTRITION_SCORE_TITAN_MIN + + int bonusToSteal = victimBonus / 2 + int attackerScore = bonusToSteal + bool realStealBonus = true + if ( bonusToSteal <= minScoreCanSteal ) // no enough bonus to steal + { + attackerScore = minScoreCanSteal // give attacker min bonus + realStealBonus = false // we don't do attacker steal events below, just half victim's bonus + } + + // servercallback + int victimEHandle = victim.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + // only do attacker events if victim has enough bonus to steal + if ( realStealBonus ) + { + Remote_CallFunction_NonReplay( + attacker, + "ServerCallback_AT_PlayerKillScorePopup", + bonusToSteal, // stolenScore + victimEHandle, // victimEHandle + damageOrigin.x, // x + damageOrigin.y, // y + damageOrigin.z // z + ) + } + else // otherwise we do a normal entity killed scoreEvent + { + AT_AddPlayerBonusPointsForEntityKilled( attacker, attackerScore, damageInfo ) + } + + // update score difference and scoreboard + AT_AddToPlayerTeamScore( attacker, minScoreCanSteal ) + + // steal bonus + // only do attacker events if victim has enough bonus to steal + if ( realStealBonus ) + { + AT_AddPlayerBonusPoints( attacker, bonusToSteal ) + AddPlayerScore( attacker, "AttritionBonusStolen" ) + } + + // tell victim of bonus stolen + AT_PlayerBonusLoss( victim, bonusToSteal ) + + return realStealBonus +} + +void function AT_PlayerBonusLoss( entity player, int bonusLoss ) +{ + AT_AddPlayerBonusPoints( player, -bonusLoss ) + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_ShowStolenBonus", + bonusLoss // stolenScore + ) +} + +// team score meter +void function AT_AddToPlayerTeamScore( entity player, int amount ) +{ + // do not award any score after the match is ended + if ( GetGameState() > eGameState.Playing ) + return + + // add to scoreboard + player.AddToPlayerGameStat( PGS_ASSAULT_SCORE, amount ) + + // Check score so we dont go over max + if ( GameRules_GetTeamScore(player.GetTeam()) + amount > GetScoreLimit_FromPlaylist() ) + { + amount = GetScoreLimit_FromPlaylist() - GameRules_GetTeamScore(player.GetTeam()) + } + + // update score difference + AddTeamScore( player.GetTeam(), amount ) +} + +// bonus points, players earn from killing +void function AT_AddPlayerBonusPoints( entity player, int amount ) +{ + // do not award any score after the match is ended + if ( GetGameState() > eGameState.Playing ) + return + + // add to scoreboard + player.AddToPlayerGameStat( PGS_SCORE, amount ) + AT_SetPlayerBonusPoints( player, player.GetPlayerNetInt( "AT_bonusPoints" ) + ( player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 ) + amount ) +} + +int function AT_GetPlayerBonusPoints( entity player ) +{ + return player.GetPlayerNetInt( "AT_bonusPoints" ) + player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 +} + +void function AT_SetPlayerBonusPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_bonusPoints256", stacks ) + player.SetPlayerNetInt( "AT_bonusPoints", amount - stacks * 256 ) +} + +// total points, the value player actually uploaded to team score +void function AT_AddPlayerTotalPoints( entity player, int amount ) +{ + // update score difference and scoreboard, calling this function meaning player has deposited their bonus to team score + AT_AddToPlayerTeamScore( player, amount ) + AT_SetPlayerTotalPoints( player, player.GetPlayerNetInt( "AT_totalPoints" ) + ( player.GetPlayerNetInt( "AT_totalPoints256" ) * 256 ) + amount ) +} + +void function AT_SetPlayerTotalPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_totalPoints256", stacks ) + player.SetPlayerNetInt( "AT_totalPoints", amount - stacks * 256 ) +} + +// earn points, seems not used +void function AT_AddPlayerEarnedPoints( entity player, int amount ) +{ + AT_SetPlayerBonusPoints( player, player.GetPlayerNetInt( "AT_earnedPoints" ) + ( player.GetPlayerNetInt( "AT_earnedPoints256" ) * 256 ) + amount ) +} + +void function AT_SetPlayerEarnedPoints( entity player, int amount ) +{ + // split into stacks of 256 where necessary + int stacks = amount / 256 // automatically rounds down because int division + + player.SetPlayerNetInt( "AT_earnedPoints256", stacks ) + player.SetPlayerNetInt( "AT_earnedPoints", amount - stacks * 256 ) +} + +// damaging bounty +void function AT_AddPlayerBonusPointsForBossDamaged( entity player, entity victim, int amount, var damageInfo ) +{ + AT_AddPlayerBonusPoints( player, amount ) + // update score difference and scoreboard + AT_AddToPlayerTeamScore( player, amount ) + + // send servercallback for damaging + int bossEHandle = victim.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_BossDamageScorePopup", + amount, // damageScore + amount, // damageBonus + bossEHandle, // bossEHandle + damageOrigin.x, // x + damageOrigin.y, // y + damageOrigin.z // z + ) +} + +void function AT_AddPlayerBonusPointsForEntityKilled( entity player, int amount, var damageInfo, int extraBonus = 0 ) +{ + AT_AddPlayerBonusPoints( player, amount + extraBonus ) + + // send servercallback for damaging + int attackerEHandle = player.GetEncodedEHandle() + vector damageOrigin = DamageInfo_GetDamagePosition( damageInfo ) + + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_ShowATScorePopup", + attackerEHandle, // attackerEHandle + amount, // damageScore + amount + extraBonus, // damageBonus + damageOrigin.x, // damagePosX + damageOrigin.y, // damagePosX + damageOrigin.z, // damagePosX + 0 // damageType ( not used ) + ) +} + +///////////////////////////////// +///// SCORING FUNCTIONS END ///// +///////////////////////////////// + + + +////////////////////////////// +///// GAMELOOP FUNCTIONS ///// +////////////////////////////// + +void function AT_GameLoop_Threaded() +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // game end func + // TODO: Cant seem to be able to get this crash ??? + OnThreadEnd + ( + function() + { + // prevent crash before entity creation on map change + if ( GetGameState() >= eGameState.Prematch ) + { + SetGlobalNetBool( "preBankPhase", false ) + SetGlobalNetBool( "banksOpen", false ) + } + } + ) + + // Initial wait before first wave + wait AT_FIRST_WAVE_START_DELAY - AT_WAVE_TRANSITION_DELAY + + int lastWaveId = -1 + for ( int waveCount = 1; ; waveCount++ ) + { + wait AT_WAVE_TRANSITION_DELAY + + // cap to number of real waves + int waveId = ( waveCount - 1 ) / 2 + int waveCapAmount = 2 + waveId = int( min( waveId, GetWaveDataSize() - waveCapAmount ) ) + + // New wave dialogue + bool waveChanged = lastWaveId != waveId + if ( waveChanged ) + { + PlayFactionDialogueToTeam( "bh_newWave", TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_newWave", TEAM_MILITIA ) + } + else // same wave, second half + { + PlayFactionDialogueToTeam( "bh_incoming", TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_incoming", TEAM_MILITIA ) + } + + lastWaveId = waveId + + SetGlobalNetInt( "AT_currentWave", waveId ) + bool isBossWave = waveCount % 2 == 0 // even number waveCount means boss wave + + // announce the wave + foreach ( entity player in GetPlayerArray() ) + { + if ( isBossWave ) + { + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnounceBoss" ) + } + else + { + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_AnnouncePreParty", + 0.0, // endTime ( not used ) + waveId // waveNum + ) + } + } + + wait AT_WAVE_TRANSITION_DELAY + + // Run the wave + thread AT_CampSpawnThink( waveId, isBossWave ) + + if ( !isBossWave ) + { + svGlobal.levelEnt.WaitSignal( "ATAllCampsClean" ) // signaled when all camps cleaned in spawn functions + } + else + { + wait AT_BOUNTY_TITAN_CHECK_DELAY + // wait until all bounty titans killed + while ( IsAlive( GetGlobalNetEnt( "camp1Ent" ) ) || IsAlive( GetGlobalNetEnt( "camp2Ent" ) ) ) + WaitFrame() + } + + // wave end, prebank phase + svGlobal.levelEnt.Signal( "ATWaveEnd" ) // defensive fix, destroy existing campEnts + SetGlobalNetBool( "preBankPhase", true ) + + wait AT_WAVE_END_ANNOUNCEMENT_DELAY + + // announce wave end + foreach ( entity player in GetPlayerArray() ) + { + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_AnnounceWaveOver", + waveId, // waveNum ( not used ) + 0, // militiaDamageTotal ( not used ) + 0, // imcDamageTotal ( not used ) + 0, // milMVP ( not used ) + 0, // imcMVP ( not used ) + 0, // milMVPDamage ( not used ) + 0 // imcMVPDamage ( not used ) + ) + } + + wait AT_WAVE_TRANSITION_DELAY + + // banking phase + SetGlobalNetBool( "preBankPhase", false ) + SetGlobalNetTime( "AT_bankStartTime", Time() ) + SetGlobalNetTime( "AT_bankEndTime", Time() + AT_BANKS_OPEN_DURATION ) + SetGlobalNetBool( "banksOpen", true ) + + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_BankOpen" ) + + foreach ( entity bank in file.banks ) + thread AT_BankActiveThink( bank ) + + + float endTime = Time() + AT_BANKS_OPEN_DURATION + bool forceCloseTriggered = false + // wait until no player is holding bonus, or max wait time + while ( Time() <= endTime ) + { + // If everyone has deposited their bonuses close the banks early + if ( !ATAnyPlayerHasBonus() && !forceCloseTriggered ) + { + forceCloseTriggered = true + endTime = Time() + AT_BANK_FORCE_CLOSE_DELAY + } + + WaitFrame() + } + + SetGlobalNetBool( "banksOpen", false ) + foreach ( entity player in GetPlayerArray() ) + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_BankClose" ) + } +} + +bool function ATAnyPlayerHasBonus() +{ + foreach ( entity player in GetPlayerArray() ) + { + if ( AT_GetPlayerBonusPoints( player ) ) + return true + } + return false +} + +////////////////////////////////// +///// GAMELOOP FUNCTIONS END ///// +////////////////////////////////// + + + +////////////////////////// +///// CAMP FUNCTIONS ///// +////////////////////////// + +void function AT_CampSpawnThink( int waveId, bool isBossWave ) +{ + AT_WaveData wave = GetWaveData( waveId ) + array< array > campSpawnData + + if ( isBossWave ) + campSpawnData = wave.bossSpawnData + else + campSpawnData = wave.spawnDataArrays + + array allCampsToUse + foreach ( AT_WaveOrigin campStruct in file.camps ) + { + if ( campStruct.phaseAllowed[ waveId ] ) + allCampsToUse.append( campStruct ) + } + + // HACK + // There's too many phase3 camps on exoplanet and rise, make sure we always have the correct count + int maxCampsForWave = waveId == 0 ? 1 : 2 + while( allCampsToUse.len() > maxCampsForWave ) + { + // Get the required number of camps + array tempCamps + for( int i = 0; i < maxCampsForWave; i++ ) + tempCamps.append( allCampsToUse[RandomInt( allCampsToUse.len() )] ) + + + // Check if they're intersecting, if they are, try again + bool intersecting = false + for( int i = 0; i < tempCamps.len(); i++ ) + { + AT_WaveOrigin campA = tempCamps[i] + for( int j = 0; j < tempCamps.len(); j++ ) + { + // Don't compare the same two camps + if( j == i ) + continue + + AT_WaveOrigin campB = tempCamps[j] + + if( Distance( campA.origin, campB.origin ) < campA.radius + campB.radius ) + intersecting = true + } + } + + if( !intersecting ) + allCampsToUse = tempCamps + + // If we ever get really unlucky just wait a frame + WaitFrame() + } + + foreach ( int spawnId, AT_WaveOrigin curCampData in allCampsToUse ) + { + array curSpawnData = campSpawnData[ spawnId ] + + int totalNPCsToSpawn = 0 + // initialise pending spawns and get total npcs + foreach ( AT_SpawnData spawnData in curSpawnData ) + { + spawnData.pendingSpawns = spawnData.totalToSpawn + // add to network variables + string npcNetVar = GetNPCNetVarName( spawnData.aitype, spawnId ) + SetGlobalNetInt( npcNetVar, spawnData.totalToSpawn ) + + totalNPCsToSpawn += spawnData.totalToSpawn + } + + if ( !isBossWave ) + { + // camp Ent, boss wave will use boss themselves as campEnt + string campEntVarName = "camp" + string( spawnId + 1 ) + "Ent" + bool waveNotActive = GetGlobalNetBool( "preBankPhase" ) || GetGlobalNetBool( "banksOpen" ) + if ( !IsValid( GetGlobalNetEnt( campEntVarName ) ) && !waveNotActive ) + SetGlobalNetEnt( campEntVarName, CreateCampTracker( curCampData, spawnId ) ) + + array minionSquadDatas + foreach ( AT_SpawnData data in curSpawnData ) + { + switch ( data.aitype ) + { + case "npc_soldier": + case "npc_spectre": + case "npc_stalker": + if ( !AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + minionSquadDatas.append( data ) + else + thread AT_DroppodSquadEvent_Single( curCampData, spawnId, data ) + break + + case "npc_super_spectre": + thread AT_ReaperEvent( curCampData, spawnId, data ) + break + } + } + + // minions squad spawn + if ( !AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + { + if ( minionSquadDatas.len() > 0 ) + thread AT_DroppodSquadEvent( curCampData, spawnId, minionSquadDatas ) + } + + // use campProgressThink for handling wave state + thread CampProgressThink( spawnId, totalNPCsToSpawn ) + } + else // bosswave spawn + { + foreach ( AT_SpawnData data in curSpawnData ) + { + if( data.aitype != "npc_titan" ) + continue + + thread AT_BountyTitanEvent( curCampData, spawnId, data ) + break + } + } + } +} + +void function CampProgressThink( int spawnId, int totalNPCsToSpawn ) +{ + string campLetter = GetCampLetter( spawnId ) + string campProgressName = campLetter + "campProgress" + string campEntVarName = "camp" + string( spawnId + 1 ) + "Ent" + + // initial wait + SetGlobalNetFloat( campProgressName, 1.0 ) + + // TODO: random wait, make this a constant ?? + wait 3.0 + + float cleanUpTime = -1.0 + + while ( true ) + { + int npcsLeft + // get all npcs might be in this camp + for ( int i = 0; i < 5; i++ ) + { + string netVarName = string( i + 1 ) + campLetter + "campCount" + int netVarValue = GetGlobalNetInt( netVarName ) + if ( netVarValue >= 0 ) // uninitialized network var starts from -1, avoid checking them + npcsLeft += netVarValue + } + + float campLeft = float( npcsLeft ) / float( totalNPCsToSpawn ) + SetGlobalNetFloat( campProgressName, campLeft ) + + if( npcsLeft <= AT_CAMP_BORED_NPCS_LEFT_TO_START_CLEANUP && cleanUpTime < 0.0 ) + { + cleanUpTime = Time() + AT_CAMP_BORED_CLEANUP_WAIT + print("Cleanup timer started!") + } + + if( Time() > cleanUpTime && cleanUpTime > 0.0 && spawnId in file.campScriptEntArrays ) + { + foreach( int handle in file.campScriptEntArrays[spawnId] ) + { + array entities = GetScriptManagedEntArray( handle ) + entities.removebyvalue( null ) + foreach ( entity ent in entities ) + { + if ( IsAlive( ent ) && ent.IsNPC() ) + { + printt( "Killing bored AI " + ent.GetClassName() + " at " + ent.GetOrigin() ) + ent.Die() + } + } + } + } -// IMPLEMENTATION NOTES: -// bounty hunt is a mode that was clearly pretty heavily developed, and had alot of scrapped concepts (i.e. most wanted player bounties, turret bounties, collectable blackbox objectives) -// in the interest of time, this script isn't gonna support any of that atm -// alot of the remote functions also take parameters that aren't used, i'm not gonna populate these and just use default values for now instead -// however, if you do want to mess with this stuff, almost all the remote functions for this stuff are still present in cl_gamemode_at, and should work fine with minimal fuckery in my experience + if ( campLeft <= 0.0 ) // camp wiped! + { + PlayFactionDialogueToTeam( "bh_cleared" + campLetter, TEAM_IMC ) + PlayFactionDialogueToTeam( "bh_cleared" + campLetter, TEAM_MILITIA ) -struct { - array campsToRegisterOnEntitiesDidLoad + entity campEnt = GetGlobalNetEnt( campEntVarName ) + if ( IsValid( campEnt ) ) + campEnt.Signal( "ATCampClean" ) // destroy the camp ent - array banks - array camps - - table< int, table< string, int > > trackedCampNPCSpawns -} file + // check if both camps being destroyed + if ( !IsValid( GetGlobalNetEnt( "camp1Ent" ) ) && !IsValid( GetGlobalNetEnt( "camp2Ent" ) ) ) + svGlobal.levelEnt.Signal( "ATAllCampsClean" ) // end the wave + + return + } -void function GamemodeAt_Init() + WaitFrame() + } +} + +// entity funcs +// camp +entity function CreateCampTracker( AT_WaveOrigin campData, int spawnId ) { - AddCallback_GameStateEnter( eGameState.Playing, RunATGame ) - - AddCallback_OnClientConnected( InitialiseATPlayer ) + // store data + vector campOrigin = campData.origin + float campRadius = campData.radius + float campHeight = campData.height + // add a minimap icon + entity mapIconEnt = CreateEntity( "prop_script" ) + DispatchSpawn( mapIconEnt ) + + mapIconEnt.SetOrigin( campOrigin ) + mapIconEnt.DisableHibernation() + SetTeam( mapIconEnt, AT_AI_TEAM ) + mapIconEnt.Minimap_AlwaysShow( TEAM_IMC, null ) + mapIconEnt.Minimap_AlwaysShow( TEAM_MILITIA, null ) + + mapIconEnt.Minimap_SetCustomState( GetCampMinimapState( spawnId ) ) + mapIconEnt.Minimap_SetAlignUpright( true ) + mapIconEnt.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) + mapIconEnt.Minimap_SetObjectScale( campRadius / 16000.0 ) // proper icon on the map - AddSpawnCallbackEditorClass( "info_target", "info_attrition_bank", CreateATBank ) - AddSpawnCallbackEditorClass( "info_target", "info_attrition_camp", CreateATCamp ) - AddCallback_EntitiesDidLoad( CreateATCamps_Delayed ) + // attach a location tracker + entity tracker = GetAvailableLocationTracker() + tracker.SetOwner( mapIconEnt ) // needs a owner to show up + tracker.SetOrigin( campOrigin ) + SetLocationTrackerRadius( tracker, campRadius ) + SetLocationTrackerID( tracker, spawnId ) + DispatchSpawn( tracker ) + + thread TrackWaveEndForCampInfo( tracker, mapIconEnt ) + return tracker } -void function RateSpawnpoints_AT( int checkclass, array spawnpoints, int team, entity player ) +void function TrackWaveEndForCampInfo( entity tracker, entity mapIconEnt ) { - RateSpawnpoints_Generic( checkclass, spawnpoints, team, player ) // temp + tracker.EndSignal( "OnDestroy" ) + tracker.EndSignal( "ATCampClean" ) + + OnThreadEnd + ( + function(): ( tracker, mapIconEnt ) + { + // camp cleaned, wave or game ended, destroy the camp info + if ( IsValid( tracker ) ) + tracker.Destroy() + + if ( IsValid( mapIconEnt ) ) + mapIconEnt.Destroy() + } + ) + + WaitSignal( svGlobal.levelEnt, "GameStateChanged", "ATWaveEnd" ) } -// world and player inits +string function GetCampLetter( int spawnId ) +{ + return spawnId == 0 ? "A" : "B" +} -void function InitialiseATPlayer( entity player ) +int function GetCampMinimapState( int id ) { - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_OnPlayerConnected" ) + switch ( id ) + { + case 0: + return eMinimapObject_prop_script.AT_DROPZONE_A + case 1: + return eMinimapObject_prop_script.AT_DROPZONE_B + case 2: + return eMinimapObject_prop_script.AT_DROPZONE_C + } + + unreachable } -void function CreateATBank( entity spawnpoint ) +////////////////////////////// +///// CAMP FUNCTIONS END ///// +////////////////////////////// + + + +////////////////////////// +///// BANK FUNCTIONS ///// +////////////////////////// + +void function AT_BankActiveThink( entity bank ) { - entity bank = CreatePropDynamic( spawnpoint.GetModelName(), spawnpoint.GetOrigin(), spawnpoint.GetAngles(), SOLID_VPHYSICS ) - bank.SetScriptName( "AT_Bank" ) - - // create tracker ent - // we don't need to store these at all, client just needs to get them - DispatchSpawn( GetAvailableBankTracker( bank ) ) + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + bank.EndSignal( "OnDestroy" ) - thread PlayAnim( bank, "mh_inactive_idle" ) + // Banks closed + OnThreadEnd + ( + function(): ( bank ) + { + if ( IsValid( bank ) ) + { + // Update use prompt + if ( GetGameState() != eGameState.Playing ) + bank.UnsetUsable() + else + bank.SetUsePrompts( "#AT_USE_BANK_CLOSED", "#AT_USE_BANK_CLOSED" ) + + thread PlayAnim( bank, "mh_active_2_inactive" ) + FadeOutSoundOnEntity( bank, "Mobile_Hardpoint_Idle", 0.5 ) + bank.Minimap_Hide( TEAM_IMC, null ) + bank.Minimap_Hide( TEAM_MILITIA, null ) + } + } + ) + + // Update use prompt to usable + bank.SetUsable() + bank.SetUsePrompts( "#AT_USE_BANK", "#AT_USE_BANK_PC" ) + + thread PlayAnim( bank, "mh_inactive_2_active" ) + EmitSoundOnEntity( bank, "Mobile_Hardpoint_Idle" ) + + // Show minimap icon for bank + bank.Minimap_AlwaysShow( TEAM_IMC, null ) + bank.Minimap_AlwaysShow( TEAM_MILITIA, null ) + bank.Minimap_SetCustomState( eMinimapObject_prop_script.AT_BANK ) - file.banks.append( bank ) + // Wait for bank close or game end + while ( GetGlobalNetBool( "banksOpen" ) ) + WaitFrame() } -void function CreateATCamp( entity spawnpoint ) +function OnPlayerUseBank( bank, player ) { - // delay this so we don't do stuff before all spawns are initialised and that - file.campsToRegisterOnEntitiesDidLoad.append( spawnpoint ) -} + // Banks are always usable so that we can show the use prompt + // Only allow deposit when banks are open + if ( !GetGlobalNetBool( "banksOpen" ) ) + return -void function CreateATCamps_Delayed() -{ - // we delay registering camps until EntitiesDidLoad since they rely on spawnpoints and stuff, which might not all be ready in the creation callback - // unsure if this would be an issue in practice, but protecting against it in case it would be - foreach ( entity camp in file.campsToRegisterOnEntitiesDidLoad ) + expect entity( bank ) + expect entity( player ) + + // bank.SetUsableByGroup( "pilot" ) didn't seem to work so we just + // exit here if player is in a titan + if( player.IsTitan() ) + return + + // Player has no bonus, try to send a tip using SendHUDMessage + if ( AT_GetPlayerBonusPoints( player ) == 0 ) { - AT_WaveOrigin campStruct - campStruct.ent = camp - campStruct.origin = camp.GetOrigin() - campStruct.radius = expect string( camp.kv.radius ).tofloat() - campStruct.height = expect string( camp.kv.height ).tofloat() - - // assumes every info_attrition_camp will have all 9 phases, possibly not a good idea? - for ( int i = 0; i < 9; i++ ) - campStruct.phaseAllowed.append( expect string( camp.kv[ "phase_" + ( i + 1 ) ] ) == "1" ) - - // get droppod spawns - foreach ( entity spawnpoint in SpawnPoints_GetDropPod() ) - if ( Distance( camp.GetOrigin(), spawnpoint.GetOrigin() ) < 1500.0 ) - campStruct.dropPodSpawnPoints.append( spawnpoint ) - - foreach ( entity spawnpoint in SpawnPoints_GetTitan() ) - if ( Distance( camp.GetOrigin(), spawnpoint.GetOrigin() ) < 1500.0 ) - campStruct.titanSpawnPoints.append( spawnpoint ) - - // todo: turret spawns someday maybe - - file.camps.append( campStruct ) + ATSendDepositTipToPlayer( player, "#AT_USE_BANK_NO_BONUS_HINT" ) + return } - - file.campsToRegisterOnEntitiesDidLoad.clear() -} -// scoring funcs + // Prevent more than one instance of this thread running + if ( !file.playerBankUploading[ player ] ) + thread PlayerUploadingBonus_Threaded( bank, player ) +} -// don't use this where possible as it doesn't set score and stuff -void function AT_SetPlayerCash( entity player, int amount ) +bool function ATSendDepositTipToPlayer( entity player, string message ) { - // split into stacks of 256 where necessary - int stacks = amount / 256 // automatically rounds down because int division + if ( Time() < file.playerHudMessageAllowedTime[ player ] ) + return false + + SendHudMessage( player, message, -1, 0.4, 255, 255, 255, 255, 0.5, 1.0, 0.5 ) + file.playerHudMessageAllowedTime[ player ] = Time() + AT_PLAYER_HUD_MESSAGE_COOLDOWN - player.SetPlayerNetInt( "AT_bonusPoints256", stacks ) - player.SetPlayerNetInt( "AT_bonusPoints", amount - stacks * 256 ) + return true } -void function AT_AddPlayerCash( entity player, int amount ) +struct AT_playerUploadStruct { - // update score difference - AddTeamScore( player.GetTeam(), amount / 2 ) - AT_SetPlayerCash( player, player.GetPlayerNetInt( "AT_bonusPoints" ) + ( player.GetPlayerNetInt( "AT_bonusPoints256" ) * 256 ) + amount ) + bool uploadSuccess = false + int depositedPoints = 0 +} + +void function PlayerUploadingBonus_Threaded( entity bank, entity player ) +{ + bank.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) + + file.playerBankUploading[ player ] = true + + // this literally only exists because structs are passed by ref, + // and primitives like ints and bools are passed by val + // which meant that the OnThreadEnd was just getting 0 and false + AT_playerUploadStruct uploadInfo + + // Cleanup and call finish deposit func + OnThreadEnd + ( + function(): ( player, uploadInfo ) + { + if ( IsValid( player ) ) + { + file.playerBankUploading[ player ] = false + + // Clean up looping sound + StopSoundOnEntity( player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + StopSoundOnEntity( player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_3P" ) + + // Do medal event + // TODO: Check if vanilla actually do.s this every time you finish depositing??? + AddPlayerScore( player, "AttritionCashedBonus" ) + + // Do server callback + Remote_CallFunction_NonReplay( + player, + "ServerCallback_AT_FinishDeposit", + uploadInfo.depositedPoints // deposit + ) + + player.SetPlayerNetBool( "AT_playerUploading", false ) + + if ( uploadInfo.uploadSuccess ) // Player deposited all remaining bonus + { + // Emit uploading successful sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Successful_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Successful_3P" ) + + // player is MVP + int ourScore = player.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + bool isMVP = true + foreach(teamPlayer in GetPlayerArrayOfTeam(player.GetTeam())) + { + if (ourScore < teamPlayer.GetPlayerGameStat( PGS_ASSAULT_SCORE )) + { + isMVP = false + break + } + } + if (isMVP) + PlayFactionDialogueToPlayer( "bh_mvp", player ) + } + else // Player was killed or left the bank radius + { + // Emit uploading failed sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Unsuccessful_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_End_Unsuccessful_3P" ) + } + } + } + ) + + // Uploading start sound + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Deposit_Start_3P" ) + EmitSoundOnEntityOnlyToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_1P" ) + EmitSoundOnEntityExceptToPlayer( player, player, "HUD_MP_BountyHunt_BankBonusPts_Ticker_Loop_3P" ) + + player.SetPlayerNetBool( "AT_playerUploading", true ) + + // Upload bonus while the player is within range of the bank + while ( Distance( player.GetOrigin(), bank.GetOrigin() ) <= AT_BANK_DEPOSIT_RADIUS && GetGlobalNetBool( "banksOpen" ) ) + { + // Calling this moves the "Uploading..." graphic to the same place it is + // in vanilla + Remote_CallFunction_NonReplay( player, "ServerCallback_AT_ShowRespawnBonusLoss" ) + + int bonusToUpload = int( min( AT_BANK_DEPOSIT_RATE, AT_GetPlayerBonusPoints( player ) ) ) + // No more bonus to upload, return + if ( bonusToUpload == 0 ) + { + uploadInfo.uploadSuccess = true + return + } + + // Remove bonus points and add them to total poins + AT_AddPlayerBonusPoints( player, -bonusToUpload ) + AT_AddPlayerTotalPoints( player, bonusToUpload ) + + uploadInfo.depositedPoints += bonusToUpload + WaitFrame() + } } -// run gamestate +////////////////////////////// +///// BANK FUNCTIONS END ///// +////////////////////////////// + -void function RunATGame() + +///////////////////////// +///// NPC FUNCTIONS ///// +///////////////////////// + +int function GetScriptManagedNPCArrayLength_Alive( int scriptManagerId ) { - thread RunATGame_Threaded() + array entities = GetScriptManagedEntArray( scriptManagerId ) + entities.removebyvalue( null ) + int npcsAlive = 0 + foreach ( entity ent in entities ) + { + if ( IsAlive( ent ) && ent.IsNPC() ) + npcsAlive += 1 + } + return npcsAlive } -void function RunATGame_Threaded() +void function AT_DroppodSquadEvent( AT_WaveOrigin campData, int spawnId, array minionDatas ) { svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + // create a script managed array for all handled minions + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] - OnThreadEnd( function() - { - SetGlobalNetBool( "banksOpen", false ) - }) - - wait WAVE_STATE_TRANSITION_TIME // initial wait before first wave - - for ( int waveCount = 1; ; waveCount++ ) + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = SQUAD_SIZE * AT_DROPPOD_SQUADS_ALLOWED_ON_FIELD + while ( true ) { - wait WAVE_STATE_TRANSITION_TIME - - // cap to number of real waves - int waveId = ( waveCount / 2 ) - // last wave is clearly unfinished so don't use, just cap to last actually used one - if ( waveId >= GetWaveDataSize() - 1 ) + foreach ( AT_SpawnData data in minionDatas ) { - waveId = GetWaveDataSize() - 2 - waveCount = waveId * 2 + string ent = data.aitype + waitthread AT_SpawnDroppodSquad( campData, spawnId, ent, eventManager ) + data.pendingSpawns -= SQUAD_SIZE + if ( data.pendingSpawns <= 0 ) // current spawn data has reached max spawn amount + minionDatas.removebyvalue( data ) // remove this data + if ( GetScriptManagedNPCArrayLength_Alive( eventManager ) >= totalAllowedOnField ) // we have enough npcs on field? + break // stop following spawning functions } - - SetGlobalNetInt( "AT_currentWave", waveId ) - bool isBossWave = waveCount / float( 2 ) > waveId // odd number waveCount means boss wave - - // announce the wave - foreach ( entity player in GetPlayerArray() ) + if ( minionDatas.len() == 0 ) // all spawn data has finished spawn + return + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField - SQUAD_SIZE ) // wait until we have lost more than 1 squad { - if ( isBossWave ) - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnounceBoss" ) - else - Remote_CallFunction_NonReplay( player, "ServerCallback_AT_AnnouncePreParty", 0.0, waveId ) + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) } - - wait WAVE_STATE_TRANSITION_TIME - - // run the wave - - AT_WaveData wave = GetWaveData( waveId ) - array< array > campSpawnData - - if ( isBossWave ) - campSpawnData = wave.bossSpawnData - else - campSpawnData = wave.spawnDataArrays - - // initialise pending spawns - foreach ( array< AT_SpawnData > campData in campSpawnData ) + } +} + +// for AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK, handles a single spawndata +void function AT_DroppodSquadEvent_Single( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // get ent and create a script managed array for current event + string ent = data.aitype + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] + + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = data.totalAllowedOnField // mostly 12 for grunts and spectres, too much! + // start spawner + while ( true ) + { + waitthread AT_SpawnDroppodSquad( campData, spawnId, ent, eventManager ) + data.pendingSpawns -= SQUAD_SIZE + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField - SQUAD_SIZE ) // wait until we have less npcs than allowed count { - foreach ( AT_SpawnData spawnData in campData ) - spawnData.pendingSpawns = spawnData.totalToSpawn - } - - // clear tracked spawns - file.trackedCampNPCSpawns = {} - while ( true ) - { - // if this is ever 0 by the end of this loop, wave is complete - int numActiveCampSpawners = 0 - - // iterate over camp data for wave - for ( int campIdx = 0; campIdx < campSpawnData.len() && campIdx < file.camps.len(); campIdx++ ) - { - if ( !( campIdx in file.trackedCampNPCSpawns ) ) - file.trackedCampNPCSpawns[ campIdx ] <- {} - - // iterate over ai spawn data for camp - foreach ( AT_SpawnData spawnData in campSpawnData[ campIdx ] ) - { - if ( !( spawnData.aitype in file.trackedCampNPCSpawns[ campIdx ] ) ) - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] <- 0 - - if ( spawnData.pendingSpawns > 0 || file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] > 0 ) - numActiveCampSpawners++ - - // try to spawn as many ai as we can, as long as the camp doesn't already have too many spawned - int spawnCount - for ( spawnCount = 0; spawnCount < spawnData.pendingSpawns && spawnCount < spawnData.totalAllowedOnField - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ]; ) - { - // not doing this in a generic way atm, but could be good for the future if we want to support more ai - switch ( spawnData.aitype ) - { - case "npc_soldier": - case "npc_spectre": - case "npc_stalker": - thread AT_SpawnDroppodSquad( campIdx, spawnData.aitype ) - spawnCount += 4 - break - - case "npc_super_spectre": - thread AT_SpawnReaper( campIdx ) - spawnCount += 1 - break - - case "npc_titan": - thread AT_SpawnBountyTitan( campIdx ) - spawnCount += 1 - break - - default: - print( "BOUNTY HUNT: Tried to spawn unsupported ai of type \"" + "\" at camp " + campIdx ) - } - } - - // track spawns - file.trackedCampNPCSpawns[ campIdx ][ spawnData.aitype ] += spawnCount - spawnData.pendingSpawns -= spawnCount - } - } - - if ( numActiveCampSpawners == 0 ) - break - - wait 0.5 + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) } - - wait WAVE_STATE_TRANSITION_TIME - - // banking phase } } -// entity funcs - -void function AT_SpawnDroppodSquad( int camp, string aiType ) +void function AT_SpawnDroppodSquad( AT_WaveOrigin campData, int spawnId, string aiType, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.dropPodSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].dropPodSpawnPoints.getrandom() + spawnpoint = campData.dropPodSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnDropPod( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, aiType, void function( array guys ) : ( camp, aiType ) - { - AT_HandleSquadSpawn( guys, camp, aiType ) - }) + AiGameModes_SpawnDropPod( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + aiType, + // squad handler + void function( array guys ) : ( campData, spawnId, aiType, scriptManagerId ) + { + AT_HandleSquadSpawn( guys, campData, spawnId, aiType, scriptManagerId ) + }, + eDropPodFlag.DISSOLVE_AFTER_DISEMBARKS + ) } -void function AT_HandleSquadSpawn( array guys, int camp, string aiType ) +void function AT_HandleSquadSpawn( array guys, AT_WaveOrigin campData, int spawnId, string aiType, int scriptManagerId ) { foreach ( entity guy in guys ) { - guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_INVESTIGATE | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) - - // untrack them on death - thread AT_WaitToUntrackNPC( guy, camp, aiType ) + // TODO: NPCs still seem to go outside their camp ??? + //guy.EnableNPCFlag( NPC_ALLOW_PATROL | NPC_ALLOW_HAND_SIGNALS | NPC_ALLOW_FLEE ) + + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, guy ) + thread AT_TrackNPCLifeTime( guy, spawnId, aiType ) + + thread AT_ForceAssaultAroundCamp( guy, campData ) + } +} + +void function AT_ForceAssaultAroundCamp( entity guy, AT_WaveOrigin campData ) +{ + guy.EndSignal( "OnDestroy" ) + guy.EndSignal( "OnDeath" ) + + // goal check + vector ornull goalPos = NavMesh_ClampPointForAI(campData.origin, guy) + goalPos = goalPos == null ? campData.origin : goalPos + expect vector(goalPos) + + float goalRadius = campData.radius / 4 + float guyGoalRadius = guy.GetMinGoalRadius() + if ( guyGoalRadius > goalRadius ) // this npc cannot use forced goal radius? + goalRadius = guyGoalRadius + + while( true ) + { + guy.AssaultPoint( goalPos ) + guy.AssaultSetGoalRadius( goalRadius ) + guy.AssaultSetFightRadius( 0 ) + guy.AssaultSetArrivalTolerance( int(goalRadius) ) + + wait RandomFloatRange( 1, 5 ) + } +} + +void function AT_ReaperEvent( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // create a script managed array for current event + int eventManager = CreateScriptManagedEntArray() + + if( !(spawnId in file.campScriptEntArrays) ) + file.campScriptEntArrays[spawnId] <- [] + + file.campScriptEntArrays[spawnId].append(eventManager) + + int totalAllowedOnField = 1 // 1 allowed at the same time for heavy armor units + if ( AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + totalAllowedOnField = data.totalAllowedOnField + + while ( true ) + { + waitthread AT_SpawnReaper( campData, spawnId, eventManager ) + data.pendingSpawns -= 1 + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField ) // wait until we have less npcs than allowed count + { + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + } } } -void function AT_SpawnReaper( int camp ) +void function AT_SpawnReaper( AT_WaveOrigin campData, int spawnId, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.dropPodSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].titanSpawnPoints.getrandom() + spawnpoint = campData.dropPodSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) - AiGameModes_SpawnReaper( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, "npc_super_spectre",void function( entity reaper ) : ( camp ) + AiGameModes_SpawnReaper( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + "npc_super_spectre_aitdm", + // reaper handler + void function( entity reaper ) : ( campData, spawnId, scriptManagerId ) + { + AT_HandleReaperSpawn( reaper, campData, spawnId, scriptManagerId ) + } + ) +} + +void function AT_HandleReaperSpawn( entity reaper, AT_WaveOrigin campData, int spawnId, int scriptManagerId ) +{ + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, reaper ) + thread AT_TrackNPCLifeTime( reaper, spawnId, "npc_super_spectre" ) + + thread AT_ForceAssaultAroundCamp( reaper, campData ) +} + +void function AT_BountyTitanEvent( AT_WaveOrigin campData, int spawnId, AT_SpawnData data ) +{ + svGlobal.levelEnt.EndSignal( "GameStateChanged" ) + + // create a script managed array for current event + int eventManager = CreateScriptManagedEntArray() + + int totalAllowedOnField = 1 // 1 allowed at the same time for heavy armor units + if ( AT_USE_TOTAL_ALLOWED_ON_FIELD_CHECK ) + totalAllowedOnField = data.totalAllowedOnField + while ( true ) { - thread AT_WaitToUntrackNPC( reaper, camp, "npc_super_spectre" ) - }) + waitthread AT_SpawnBountyTitan( campData, spawnId, eventManager ) + data.pendingSpawns -= 1 + if ( data.pendingSpawns <= 0 ) // we have reached max npcs + return // stop any spawning functions + + int npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + while ( npcOnFieldCount >= totalAllowedOnField ) // wait until we have less npcs than allowed count + { + WaitFrame() + npcOnFieldCount = GetScriptManagedNPCArrayLength_Alive( eventManager ) + } + } } -void function AT_SpawnBountyTitan( int camp ) +void function AT_SpawnBountyTitan( AT_WaveOrigin campData, int spawnId, int scriptManagerId ) { entity spawnpoint - if ( file.camps[ camp ].dropPodSpawnPoints.len() == 0 ) - spawnpoint = file.camps[ camp ].ent + if ( campData.titanSpawnPoints.len() == 0 ) + spawnpoint = campData.ent else - spawnpoint = file.camps[ camp ].titanSpawnPoints.getrandom() + spawnpoint = campData.titanSpawnPoints.getrandom() + // anti-crash + if ( !IsValid( spawnpoint ) ) + spawnpoint = campData.ent // add variation to spawns wait RandomFloat( 1.0 ) @@ -320,57 +1625,191 @@ void function AT_SpawnBountyTitan( int camp ) int bountyID = 0 try { - bountyID = ReserveBossID( VALID_BOUNTY_TITAN_SETTINGS.getrandom() ) + bountyID = ReserveBossID( AT_BOUNTY_TITANS_AI_SETTINGS.getrandom() ) } catch ( ex ) {} // if we go above the expected wave count that vanilla supports, there's basically no way to ensure that this func won't error, so default 0 after that point string aisettings = GetTypeFromBossID( bountyID ) string titanClass = expect string( Dev_GetAISettingByKeyField_Global( aisettings, "npc_titan_player_settings" ) ) + AiGameModes_SpawnTitan( + spawnpoint.GetOrigin(), + spawnpoint.GetAngles(), + AT_AI_TEAM, + titanClass, + aisettings, + // titan handler + void function( entity titan ) : ( campData, spawnId, bountyID, scriptManagerId ) + { + AT_HandleBossTitanSpawn( titan, campData, spawnId, bountyID, scriptManagerId ) + } + ) +} + +void function AT_HandleBossTitanSpawn( entity titan, AT_WaveOrigin campData, int spawnId, int bountyID, int scriptManagerId ) +{ + // set the bounty to be campEnt, for client tracking + SetGlobalNetEnt( "camp" + string( spawnId + 1 ) + "Ent", titan ) + // set up health + titan.SetMaxHealth( titan.GetMaxHealth() * AT_BOUNTY_TITAN_HEALTH_MULTIPLIER ) + titan.SetHealth( titan.GetMaxHealth() ) + // make minimap always show them and highlight them + titan.Minimap_AlwaysShow( TEAM_IMC, null ) + titan.Minimap_AlwaysShow( TEAM_MILITIA, null ) + thread BountyBossHighlightThink( titan ) + + // set up titan-specific death callbacks, mark it as bounty boss for finalDamageCallbacks to work + file.titanIsBountyBoss[ titan ] <- true + file.bountyTitanRewards[ titan ] <- ATTRITION_SCORE_BOSS_DAMAGE + AddEntityCallback_OnKilled( titan, OnBountyTitanKilled ) - AiGameModes_SpawnTitan( spawnpoint.GetOrigin(), spawnpoint.GetAngles(), BH_AI_TEAM, titanClass, aisettings, void function( entity titan ) : ( camp, bountyID ) + titan.GetTitanSoul().soul.skipDoomState = true + // i feel like this should be localised, but there's nothing for it in r1_english? + titan.SetTitle( GetNameFromBossID( bountyID ) ) + + // tracking lifetime + AddToScriptManagedEntArray( scriptManagerId, titan ) + thread AT_TrackNPCLifeTime( titan, spawnId, "npc_titan" ) +} + +void function BountyBossHighlightThink( entity titan ) +{ + titan.EndSignal( "OnDestroy" ) + titan.EndSignal( "OnDeath" ) + + while ( true ) { - // set up titan-specific death/damage callbacks - AddEntityCallback_OnDamaged( titan, OnBountyDamaged) - AddEntityCallback_OnKilled( titan, OnBountyKilled ) - - titan.GetTitanSoul().soul.skipDoomState = true - // i feel like this should be localised, but there's nothing for it in r1_english? - titan.SetTitle( GetNameFromBossID( bountyID ) ) - thread AT_WaitToUntrackNPC( titan, camp, "npc_titan" ) - } ) + Highlight_SetEnemyHighlight( titan, "enemy_boss_bounty" ) + titan.WaitSignal( "StopPhaseShift" ) // prevent phase shift mess up highlights + } +} + +void function OnNPCTitanFinalDamaged( entity titan, var damageInfo ) +{ + if ( titan in file.titanIsBountyBoss ) + OnBountyTitanDamaged( titan, damageInfo ) } -// Tracked entities will require their own "wallet" -// for titans it should be used for rounding error compenstation -// for infantry it sould be used to store money if the npc kills a player -void function OnBountyDamaged( entity titan, var damageInfo ) +void function OnBountyTitanDamaged( entity titan, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) + if ( !IsValid( attacker ) ) // delayed by projectile shots + return + // damaged by npc or something? if ( !attacker.IsPlayer() ) - attacker = GetLatestAssistingPlayerInfo( titan ).player - - if ( IsValid( attacker ) && attacker.IsPlayer() ) { - int reward = int ( BOUNTY_TITAN_DAMAGE_POOL * DamageInfo_GetDamage( damageInfo ) / titan.GetMaxHealth() ) - printt ( titan.GetMaxHealth(), DamageInfo_GetDamage( damageInfo ) ) - - AT_AddPlayerCash( attacker, reward ) + attacker = GetBountyBossDamageOwner( attacker, titan ) + if ( !IsValid( attacker ) || !attacker.IsPlayer() ) + return } + + // respawn FUCKED UP pilot weapon against titan's damage calculation, have to copy-paste this check from Titan_NPCTookDamage() + if ( HeavyArmorCriticalHitRequired( damageInfo ) && + CritWeaponInDamageInfo( damageInfo ) && + !IsCriticalHit( attacker, titan, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) ) && + IsValid( attacker ) && + !attacker.IsTitan() ) + return + + int rewardSegment = ATTRITION_SCORE_BOSS_DAMAGE + int healthSegment = titan.GetMaxHealth() / rewardSegment + + // sometimes damage is not enough to add 1 point, we save the damage for player's next attack + if ( !( titan in file.playerSavedBountyDamage[ attacker ] ) ) + file.playerSavedBountyDamage[ attacker ][ titan ] <- 0 + + file.playerSavedBountyDamage[ attacker ][ titan ] += int( DamageInfo_GetDamage( damageInfo ) ) + if ( file.playerSavedBountyDamage[ attacker ][ titan ] < healthSegment ) + return // they can't earn reward from this shot + + int damageSegment = file.playerSavedBountyDamage[ attacker ][ titan ] / healthSegment + int savedDamageLeft = file.playerSavedBountyDamage[ attacker ][ titan ] % healthSegment + file.playerSavedBountyDamage[ attacker ][ titan ] = savedDamageLeft + + float damageFrac = float( damageSegment ) / rewardSegment + int rewardLeft = file.bountyTitanRewards[ titan ] + int reward = int( ATTRITION_SCORE_BOSS_DAMAGE * damageFrac ) + if ( reward >= rewardLeft ) // overloaded shot? + reward = rewardLeft + file.bountyTitanRewards[ titan ] -= reward + + if ( reward > 0 ) + AT_AddPlayerBonusPointsForBossDamaged( attacker, titan, reward, damageInfo ) } -void function OnBountyKilled( entity titan, var damageInfo ) +void function OnBountyTitanKilled( entity titan, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) + if ( !IsValid( attacker ) ) // delayed by projectile shots + return + // damaged by npc or something? if ( !attacker.IsPlayer() ) - attacker = GetLatestAssistingPlayerInfo( titan ).player + { + attacker = GetBountyBossDamageOwner( attacker, titan ) + if ( !IsValid( attacker ) || !attacker.IsPlayer() ) + return + } + + // add all remaining reward to attacker + // bounty killed bonus handled by AT_PlayerOrNPCKilledScoreEvent() + int rewardLeft = file.bountyTitanRewards[ titan ] + delete file.bountyTitanRewards[ titan ] + if ( rewardLeft > 0 ) + AT_AddPlayerBonusPointsForBossDamaged( attacker, titan, rewardLeft, damageInfo ) + + // remove this bounty's damage saver + foreach ( entity player in GetPlayerArray() ) + { + if ( titan in file.playerSavedBountyDamage[ player ] ) + delete file.playerSavedBountyDamage[ player ][ titan ] + } + + // faction dialogue + int team = attacker.GetTeam() + PlayFactionDialogueToPlayer( "bh_playerKilledBounty", attacker ) + PlayFactionDialogueToTeamExceptPlayer( "bh_bountyClaimedByFriendly", team, attacker ) + PlayFactionDialogueToTeam( "bh_bountyClaimedByEnemy", GetOtherTeam( team ) ) +} + +entity function GetBountyBossDamageOwner( entity attacker, entity titan ) +{ + if ( attacker.IsPlayer() ) // already a player + return attacker - if ( IsValid( attacker ) && attacker.IsPlayer() ) - AT_AddPlayerCash( attacker, BOUNTY_TITAN_KILL_REWARD ) + if ( attacker.IsTitan() ) // attacker is a npc titan + { + // try to find it's pet titan owner + if ( IsValid( GetPetTitanOwner( attacker ) ) ) + return GetPetTitanOwner( attacker ) + } + + // other damages or non-owner npcs, not sure how it happens, just use this titan's last attacker + return GetLatestAssistingPlayerInfo( titan ).player } -void function AT_WaitToUntrackNPC( entity guy, int camp, string aiType ) +void function AT_TrackNPCLifeTime( entity guy, int spawnId, string aiType ) { guy.WaitSignal( "OnDeath", "OnDestroy" ) - file.trackedCampNPCSpawns[ camp ][ aiType ]-- + + string npcNetVar = GetNPCNetVarName( aiType, spawnId ) + SetGlobalNetInt( npcNetVar, GetGlobalNetInt( npcNetVar ) - 1 ) +} + + +// network var +string function GetNPCNetVarName( string className, int spawnId ) +{ + string npcId = string( GetAiTypeInt( className ) + 1 ) + string campLetter = GetCampLetter( spawnId ) + if ( npcId == "0" ) // cannot find this ai support! + { + if ( className == "npc_super_spectre" ) // stupid, reapers are not handled by GetAiTypeInt(), but it must be 4 + return "4" + campLetter + "campCount" + return "" + } + return npcId + campLetter + "campCount" } + +///////////////////////////// +///// NPC FUNCTIONS END ///// +///////////////////////////// -- cgit v1.2.3 From ff90171e6ad2ef660a80d02b5c68a06f94e7ad05 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Tue, 2 May 2023 01:25:12 +0800 Subject: [FW] Fix Reversed Titan Spawnpoint on Boomtown (#580) Add hack check for reversed maps --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 8a26f8bf..850aa7b3 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -1235,10 +1235,18 @@ array function FW_GetTitanSpawnPointsForTeam( int team ) return validSpawnPoints } +// some maps have reversed startpoints! we need a hack +const array TITAN_POINT_REVERSED_MAPS = +[ + "mp_grave" +] + // "Respawn as Titan" don't follow the rateSpawnPoints, fix it manually entity function FW_ForcedTitanStartPoint( entity player, entity basePoint ) { int team = player.GetTeam() + if ( TITAN_POINT_REVERSED_MAPS.contains( GetMapName() ) ) + team = GetOtherTeam( player.GetTeam() ) array startPoints = SpawnPoints_GetTitanStart( team ) entity validPoint = startPoints[ RandomInt( startPoints.len() ) ] // choose a random( maybe not safe ) start point return validPoint -- cgit v1.2.3 From 9181e52e0af606986af3c733ad78360f16a40be8 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 4 May 2023 22:32:48 +0100 Subject: Fix serverbrowser filtering by gamemode (#639) --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index c31185ee..7ea8134a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -771,7 +771,7 @@ void function FilterServerList() if ( filterArguments.filterMap != "SWITCH_ANY" && filterArguments.filterMap != server.map ) continue; - if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != server.playlist ) + if ( filterArguments.filterGamemode != "SWITCH_ANY" && filterArguments.filterGamemode != GetGameModeDisplayName(server.playlist) ) continue; // Search -- cgit v1.2.3 From d205d4440ffbf0947ca5cf4a2705157ba2d873e2 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 11 May 2023 18:09:47 +0100 Subject: Fix attrition freezing and killing servers sometimes (#642) Would occur when NPCs would try to find somewhere to attack after all enemy NPCs nearby were dead --- .../mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index 702e4500..f47ee90f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -460,7 +460,18 @@ void function SquadHandler( array guys ) // Get point and send our whole squad to it points = GetNPCArrayOfEnemies( team ) if ( points.len() == 0 ) // can't find any points here + { + // Have to wait some amount of time before continuing + // because if we don't the server will continue checking this + // forever, aren't loops fun? + // This definitely didn't waste ~8 hours of my time reverting various + // launcher PRs before finding this mods PR that caused servers to + // freeze forever before having their process killed by the dedi watchdog + // without any logging. If anyone reads this, PLEASE add logging to your scripts + // for when weird edge cases happen, it can literally only help debugging. -Spoon + WaitFrame() continue + } point = points[ RandomInt( points.len() ) ].GetOrigin() -- cgit v1.2.3 From c2f124f3879158e4e3e1733c2c31b3decaf2b1b4 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 12 May 2023 00:25:42 +0200 Subject: Bump mods version to `1.14.0` (#643) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 00b779a4..54834676 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 66d29cae..f3f73fde 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index e1df99ba..3525c434 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.13.0", + "Version": "1.14.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From d2a7bcbfed51494caa11da1e1376b21feb6976d6 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Wed, 24 May 2023 20:11:04 +0300 Subject: Add Mod Settings (#518) * Add Mod Settings * Make rounding optional * Add recursive search * too much shit Add custom buttons, expand menu further, sanitize display names, cleanup, add more descriptive errors and throw them early, rework slightly func params * Remove Test Stuff * Clean-Up * Revert mod version change * Replace GetIndex with PureModulo better, more understandable version of the function. * Fix Slider bug * Fix Localization * Add eject quotes (#527) * Upload cl_titan_cockpit.nut * Add eject string in script * Moved to client * index issue + removed else so always returns * Apply suggestions from code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Rest of the suggestions because github makes me want to cry * Commit suggestions from review GitHub really hates batching suggestions Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update localization * Update Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut From ASpoonPlaysGames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update Northstar.Client/mod.json From ASpoonPlaysames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Update Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut From ASpoonPlaysGames Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Delete cl_titan_cockpit.nut * Apply suggestions from Spoon's code review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Formatting for ModSettings + Remove Base Northstar Settings (#1) * fix formatting * add newline * formatting part 1 * formatting part 2 * formatting again Co-authored-by: EladNLG * reset vmt (#2) * reset vmt * formatting * more formatting * Fixes, color modification * Fix Image behind button & make image clickable using a hack because imagepanels don't get click events and i hate them * Formatting Fixes The First * Apply suggestions from Spoon's review Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> * Formatting Fixes The Second * Fix reset popup appearing when not clicking on button * Fix only being able to type 1 char at a time * Fix more bugs - never being able to get out of modsettings dialogs - setting duplication glitch * Fix alignment * add no results/mods (need localization) * he forgor :( make addmodsettingsbutton global Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * Clean up (thanks @uniboi) Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * forgot to add this too Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * Mod settings submenus (#4) * allow for submenu closing * hide reset vgui on buttons * My code got GECKO'd gecko suggestions Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * uniboi fixing his own mistakes moment + more prints removed (thanks @uniboi) Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * aaaaaaaa Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> * rename ms_slider * add a newline * add temporary aliases * fix aliases and localization * update button width for categories * fix resets accessing out of bounds index * allow unicode search * use correct index variable * update function names --------- Co-authored-by: JMM889901 <41163714+JMM889901@users.noreply.github.com> Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Co-authored-by: uniboi Co-authored-by: uniboi --- Northstar.Client/mod.json | 11 + Northstar.Client/mod/materials/vgui/reset.vmt | 12 + Northstar.Client/mod/materials/vgui/reset.vtf | Bin 0 -> 5712 bytes .../northstar_client_localisation_english.txt | 21 + .../northstar_client_localisation_french.txt | 18 + .../northstar_client_localisation_italian.txt | 18 + .../mod/resource/ui/menus/mod_settings.menu | 511 +++++++++ .../mod/resource/ui/menus/panels/mod_setting.res | 183 ++++ .../mod/scripts/vscripts/ui/menu_ingame.nut | 15 +- .../mod/scripts/vscripts/ui/menu_lobby.nut | 9 +- .../mod/scripts/vscripts/ui/menu_mod_settings.nut | 1105 ++++++++++++++++++++ .../mod/scripts/vscripts/ui/ns_slider.nut | 52 + .../mod/scripts/vscripts/ui/panel_mainmenu.nut | 4 + 13 files changed, 1952 insertions(+), 7 deletions(-) create mode 100644 Northstar.Client/mod/materials/vgui/reset.vmt create mode 100644 Northstar.Client/mod/materials/vgui/reset.vtf create mode 100644 Northstar.Client/mod/resource/ui/menus/mod_settings.menu create mode 100644 Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 54834676..e9536d66 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -115,6 +115,17 @@ "RunOn": "UI" }, { + "Path": "ui/ns_slider.nut", + "RunOn": "UI" + }, + { + "Path": "ui/menu_mod_settings.nut", + "RunOn": "UI", + "UICallback":{ + "Before": "AddModSettingsMenu" + } + }, + { "Path": "ui/ui_mouse_capture.nut", "RunOn": "UI" } diff --git a/Northstar.Client/mod/materials/vgui/reset.vmt b/Northstar.Client/mod/materials/vgui/reset.vmt new file mode 100644 index 00000000..84034586 --- /dev/null +++ b/Northstar.Client/mod/materials/vgui/reset.vmt @@ -0,0 +1,12 @@ +"Basic" +{ + "$basetexture" "vgui/reset" + "$translucent" 1 + "$vertexcolor" 1 + "$vertexalpha" 1 + "$no_fullbright" 1 + "$ignorez" 1 + "$nolod" 1 + + "$SHADERSRGBREAD360" 1 +} diff --git a/Northstar.Client/mod/materials/vgui/reset.vtf b/Northstar.Client/mod/materials/vgui/reset.vtf new file mode 100644 index 00000000..5ffb86a9 Binary files /dev/null and b/Northstar.Client/mod/materials/vgui/reset.vtf differ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index c25708a6..5dabd539 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -321,5 +321,26 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" + + // Mod Settings + "MOD_SETTINGS" "Mod Settings" + "NORTHSTAR_BASE_SETTINGS" "Northstar Base Settings" + "ONLY_HOST_MATCH_SETTINGS" "Only Host can change Private Match settings" + "ONLY_HOST_CAN_START_MATCH" "Only Host can Start the Match" + "MATCH_COUNTDOWN_LENGTH" "Private Match Countdown Duration" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Log Unknown Client Commands" + "DISALLOWED_TACTICALS" "Prohibited Tacticals" + "TACTICAL_REPLACEMENT" "Replacement Tactical" + "DISALLOWED_WEAPONS" "Prohibited Weapons" + "REPLACEMENT_WEAPON" "Replacement Weapon" + "SHOULD_RETURN_TO_LOBBY" "Return To Lobby After Match End" + "ARE_YOU_SURE" "Are you sure?" + "WILL_RESET_ALL_SETTINGS" "This will reset ALL settings that belong to this category.\n\nThis is not revertable." + "WILL_RESET_SETTING" "This will reset the %s1 setting to it's default value.\n\nThis is not revertable." + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Reset" + "MOD_SETTINGS_RESET_ALL" "Reset All" + "NO_RESULTS" "No results." + "NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 2a199186..d90cea05 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -319,5 +319,23 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "INVALID_MASTERSERVER_TOKEN" "Jeton du server maître invalide ou expiré" "JSON_PARSE_ERROR" "Une erreur est survenue durant l'analyse JSON" "UNSUPPORTED_VERSION" "La version que vous utilisez n'est plus supportée" + + "MOD_SETTINGS" "Paramètres de mod" + "NORTHSTAR_BASE_SETTINGS" "Paramètres de base de Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Seul l'hôte peut changer les paramètres de match privé" + "ONLY_HOST_CAN_START_MATCH" "Seul l'hôte peut lancer le match" + "MATCH_COUNTDOWN_LENGTH" "Durée du compte à rebours de match privé" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Enregistrer les commandes client inconnues" + "DISALLOWED_TACTICALS" "Capacités interdites" + "TACTICAL_REPLACEMENT" "Capacités de remplacement" + "DISALLOWED_WEAPONS" "Armes interdites" + "REPLACEMENT_WEAPON" "Armes de remplacement" + "SHOULD_RETURN_TO_LOBBY" "Retour au lobby après la fin du match" + "ARE_YOU_SURE" "Êtes-vous certain ?" + "WILL_RESET_ALL_SETTINGS" "Ceci réinitialisera tous les paramètres de cette catégorie.\n\nCette action est irréversible." + "WILL_RESET_SETTING" "Ceci réinitialisera le paramètre %s1 à sa valeur par défaut.\n\nCette action est irréversible." + "MOD_SETTINGS_SERVER" "Serveur" + "MOD_SETTINGS_RESET" "Réinitialiser" + "MOD_SETTINGS_RESET_ALL" "Tout réinitialiser" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index 72bf7030..13835b8b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -319,5 +319,23 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto" "JSON_PARSE_ERROR" "Errore nell'analisi di risposta json" "UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata" + + "MOD_SETTINGS" "Impostazioni Mod" + "NORTHSTAR_BASE_SETTINGS" "Impostazioni base Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Solo l'Host può modificare le impostazioni della Partita Privata" + "ONLY_HOST_CAN_START_MATCH" "Solo l'Host può Iniziare la Partita" + "MATCH_COUNTDOWN_LENGTH" "Durata Countdown della Partita Privata" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registra Comandi Client Sconosciuti" + "DISALLOWED_TACTICALS" "Abilità Proibite" + "TACTICAL_REPLACEMENT" "Sostituzione Abilità" + "DISALLOWED_WEAPONS" "Armi Proibite" + "REPLACEMENT_WEAPON" "Sostituzione Armi" + "SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita" + "ARE_YOU_SURE" "Sei sicuro?" + "WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato." + "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1. + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Ripristina" + "MOD_SETTINGS_RESET_ALL" "Ripristina Tutto" } } diff --git a/Northstar.Client/mod/resource/ui/menus/mod_settings.menu b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu new file mode 100644 index 00000000..2fed2bd1 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/mod_settings.menu @@ -0,0 +1,511 @@ +"resource/ui/menus/mods_browse.menu" +{ + "menu" + { + "ControlName" "Frame" + "xpos" "0" + "ypos" "0" + "zpos" "3" + "wide" "f0" + "tall" "f0" + "autoResize" "1" + "visible" "1" + "enabled" "1" + "pinCorner" "0" + "PaintBackgroundType" "0" + "infocus_bgcolor_override" "0 0 0 0" + "outoffocus_bgcolor_override" "0 0 0 0" + "Vignette" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuVignette" + } + "Title" + { + "ControlName" "Label" + "InheritProperties" "MenuTitle" + "labelText" "#MOD_SETTINGS" + } + "ImgTopBar" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + } + "DarkenBackground" + { + "ControlName" "Label" + "classname" "ConnectingHUD" + "xpos" "0" + "ypos" "0" + "zpos" "99" + "wide" "%100" + "tall" "%100" + "labelText" "" + "bgcolor_override" "0 0 0 0" + "visible" "0" + "paintbackground" "1" + } + "ButtonRowAnchor" + { + "ControlName" "Label" + "labelText" "" + "pin_to_sibling" "DarkenBackground" + "pin_to_sibling_corner" "TOP_LEFT" + "pin_corner_to_sibling" "BOTTOM_LEFT" + "xpos" "-150" + "ypos" "-200" + } + "FilterButtonsRowAnchor" + { + "ControlName" "Label" + "pin_to_sibling" "LabelDetails" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "pin_corner_to_sibling" "TOP_LEFT" + "labelText" "" + "ypos" "12" + } + "NoResultLabel" + { + "ControlName" "Label" + "xpos" "0" + ypos "0" + wide "1200" + tall "675" + //auto_tall_tocontents 1 + visible "1" + enabled "1" + //auto_wide_tocontents 1 + labelText "No results." + textAlignment "center" + //auto_wide_tocontents "1" + //auto_tall_tocontents "1" + //fgcolor_override "255 255 255 255" + //bgcolor_override "0 0 0 200" + font Default_41 + + pin_to_sibling ButtonRowAnchor + pin_to_sibling_corner TOP_LEFT + pin_corner_to_sibling TOP_LEFT + } + // pain // + "BtnMod1" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "pin_to_sibling" "ButtonRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + "navUp" "BtnMod15" + "navDown" "BtnMod2" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "scriptID" "0" + } + "BtnMod2" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "pin_to_sibling" "BtnMod1" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod1" + "navDown" "BtnMod3" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "scriptID" "1" + } + "BtnMod3" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "2" + "pin_to_sibling" "BtnMod2" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod2" + "navDown" "BtnMod4" + } + "BtnMod4" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "3" + "pin_to_sibling" "BtnMod3" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod3" + "navDown" "BtnMod5" + } + "BtnMod5" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "4" + "pin_to_sibling" "BtnMod4" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod4" + "navDown" "BtnMod6" + } + "BtnMod6" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "5" + "pin_to_sibling" "BtnMod5" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod5" + "navDown" "BtnMod7" + } + "BtnMod7" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "6" + "pin_to_sibling" "BtnMod6" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod6" + "navDown" "BtnMod8" + } + "BtnMod8" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "7" + "pin_to_sibling" "BtnMod7" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod7" + "navDown" "BtnMod9" + } + "BtnMod9" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "8" + "pin_to_sibling" "BtnMod8" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod8" + "navDown" "BtnMod10" + } + "BtnMod10" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "9" + "pin_to_sibling" "BtnMod9" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod9" + "navDown" "BtnMod11" + } + "BtnMod11" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "10" + "pin_to_sibling" "BtnMod10" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod10" + "navDown" "BtnMod12" + } + "BtnMod12" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "11" + "pin_to_sibling" "BtnMod11" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod11" + "navDown" "BtnMod13" + } + "BtnMod13" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "12" + "pin_to_sibling" "BtnMod12" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod12" + "navDown" "BtnMod14" + } + "BtnMod14" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "13" + "pin_to_sibling" "BtnMod13" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod13" + "navDown" "BtnMod15" + } + "BtnMod15" + { + "ControlName" "CNestedPanel" + "classname" "ModButton" + "tall" "45" + "wide" "1200" + "controlSettingsFile" "resource/UI/menus/panels/mod_setting.res" + "classname" "ModButton" + "scriptID" "14" + "pin_to_sibling" "BtnMod14" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + "navUp" "BtnMod14" + "navDown" "BtnMod1" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "FilterPanel" + { + "ControlName" "RuiPanel" + "wide" "1220" + "tall" "112" + //"xpos" "-8" + "classname" "FilterPanelChild" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "FilterButtonsRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "LabelDetails" + { + "ControlName" "RuiPanel" + "tall" "695" + "wide" "1220" + "xpos" "10" + "ypos" "10" + "pin_to_sibling" "ButtonRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + "rui" "ui/knowledgebase_panel.rpak" + "wrap" "1" + "visible" "1" + "zpos" "-1" + } + "BtnSearchLabel" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "#SEARCHBAR_LABEL" + "textAlignment" "west" + "classname" "FilterPanelChild" + "wide" "500" + "xpos" "-23" + "ypos" "-16" + "wrap" "1" + "visible" "1" + "zpos" "0" + "pin_to_sibling" "FilterButtonsRowAnchor" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModsSearch" + { + "ControlName" "TextEntry" + "classname" "FilterPanelChild" + "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + "xpos" "-400" + "ypos" "-5" + "wide" "390" + "tall" "30" + "textHidden" "0" + "editable" "1" + "font" "Default_21" + "allowRightClickMenu" "0" + "allowSpecialCharacters" "1" + "unicode" "1" + "pin_to_sibling" "BtnSearchLabel" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + } + "BtnFiltersClear" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "#CLEAR_FILTERS" + "classname" "FilterPanelChild" + "wide" "100" + "xpos" "0" + "ypos" "0" + "zpos" "90" + "scriptID" "999" + "pin_to_sibling" "BtnSearchLabel" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "BtnModListUpArrow" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "A"F + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "0" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListUpArrowPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "0" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListDownArrow" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "V" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "-655" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListDownArrowPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "40" + "xpos" "2" + "ypos" "-655" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListSlider" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + // labelText "V" + "wide" "40" + "tall" "420" + "xpos" "2" + "ypos" "-40" + "zpos" "0" + "image" "vgui/hud/white" + "drawColor" "255 255 255 128" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "BtnModListSliderPanel" + { + "ControlName" "RuiPanel" + "wide" "40" + "tall" "420" + "xpos" "2" + "ypos" "-40" + "rui" "ui/knowledgebase_panel.rpak" + "visible" "1" + "zpos" "-1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + // sh_menu_models.gnut has a global function which gets called when + // left mouse button gets called while hovering and has mouse + // deltaX; deltaY which we can yoink for ourselfes + "MouseMovementCapture" + { + "ControlName" "CMouseMovementCapturePanel" + "wide" "40" + "tall" "604" + "xpos" "2" + "ypos" "-40" + "zpos" "1" + "pin_to_sibling" "LabelDetails" + "pin_corner_to_sibling" "TOP_RIGHT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "ButtonTooltip" + { + "ControlName" "CNestedPanel" + "InheritProperties" "ButtonTooltip" + } + // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + "FooterButtons" + { + "ControlName" "CNestedPanel" + "InheritProperties" "FooterButtons" + } + } +} diff --git a/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res new file mode 100644 index 00000000..92dce922 --- /dev/null +++ b/Northstar.Client/mod/resource/ui/menus/panels/mod_setting.res @@ -0,0 +1,183 @@ +"resource/ui/menus/panels/mod_setting.res" +{ + "FULL" + { + "ControlName" "Label" + "classname" "ConnectingHUD" + "xpos" "0" + "ypos" "0" + "zpos" "99" + "wide" "1200" + "tall" "45" + "labelText" "" + "bgcolor_override" "0 0 0 0" + "visible" "0" + "paintbackground" "1" + } + "BtnMod" + { + "ControlName" "Label" + "InheritProperties" "RuiSmallButton" + "labelText" "Mod" + //"auto_wide_tocontents" "1" + "navRight" "EnumSelectButton" + "navLeft" "TextEntrySetting" + "wide" "390" + "tall" "45" + } + // we're getting to the top of this :) + "TopLine" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + "ypos" "0" + "wide" "%100" + "pin_to_sibling" "BtnMod" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_LEFT" + } + "ModTitle" + { + "ControlName" "Label" + "InheritProperties" "RuiSmallButton" + "labelText" "Mod" + "font" "DefaultBold_43" + //"auto_wide_tocontents" "1" + "zpos" "-999" + "textAlignment" "center" + "navRight" "EnumSelectButton" + "navLeft" "TextEntrySetting" + "wide" "1200" + "tall" "45" + + } + "Slider" + { + "ControlName" "SliderControl" + //"InheritProperties" "RuiSmallButton" + minValue 0.0 + maxValue 2.0 + stepSize 0.05 + "pin_to_sibling" "BtnMod" + "pin_corner_to_sibling" "TOP_LEFT" + "pin_to_sibling_corner" "TOP_RIGHT" + "navRight" "ResetModToDefault" + "navLeft" "TextEntrySetting" + //isValueClampedToStepSize 1 + BtnDropButton + { + ControlName RuiButton + //InheritProperties WideButton + style SliderButton + "wide" "320" + "tall" "45" + "labelText" "" + "auto_wide_tocontents" "0" + } + "wide" "320" + "tall" "45" + } + "EnumSelectButton" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "style" "DialogListButton" + "labelText" "" + "zpos" "4" + "wide" "225" + "tall" "45" + //"xpos" "10" + "scriptID" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "RIGHT" + "navLeft" "ResetModToDefault" + "navRight" "TextEntrySetting" + } + "ResetModToDefault" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "" + "zpos" "0" + "xpos" "10" + "wide" "45" + "tall" "45" + "scriptID" "0" + "pin_to_sibling" "EnumSelectButton" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "LEFT" + "navLeft" "Slider" + "navRight" "TextEntrySetting" + } + "ResetModImage" + { + "ControlName" "ImagePanel" + "image" "vgui/reset" + "scaleImage" "1" + "drawColor" "180 180 180 255" // vanilla label color + "visible" "0" + "wide" "30" + "tall" "30" + "enabled" "0" + + "pin_to_sibling" "ResetModToDefault" + "pin_corner_to_sibling" "CENTER" + "pin_to_sibling_corner" "CENTER" + } + "OpenCustomMenu" + { + "ControlName" "RuiButton" + "InheritProperties" "RuiSmallButton" + "labelText" "Open" + //"auto_wide_tocontents" "1" + "zpos" "4" + "wide" "1200" + "textAlignment" "center" + //"font" "Default_41" + //"xpos" "10" + "tall" "40" + "scriptID" "0" + "visible" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "RIGHT" + "pin_to_sibling_corner" "RIGHT" + "navLeft" "TextEntrySetting" + "navRight" "TextEntrySetting" + } + "TextEntrySetting" + { + "ControlName" "TextEntry" + "classname" "MatchSettingTextEntry" + //"xpos" "-35" + //"ypos" "-5" + "zpos" "100" // This works around input weirdness when the control is constructed by code instead of VGUI blackbox. + "wide" "160" + "tall" "30" + "scriptID" "0" + "textHidden" "0" + "editable" "1" + // NumericInputOnly 1 + "font" "Default_21" + "allowRightClickMenu" "0" + "allowSpecialCharacters" "1" + "unicode" "0" + "pin_to_sibling" "EnumSelectButton" + "pin_corner_to_sibling" "CENTER" + "pin_to_sibling_corner" "CENTER" + "navLeft" "EnumSelectButton" + "navRight" "EnumSelectButton" + } + // we're getting to the bottom of this :) + "BottomLine" + { + "ControlName" "ImagePanel" + "InheritProperties" "MenuTopBar" + "ypos" "5" + "wide" "%100" + //"tall" "0" + "pin_to_sibling" "FULL" + "pin_corner_to_sibling" "BOTTOM_LEFT" + "pin_to_sibling_corner" "BOTTOM_LEFT" + } +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut index 03bd8959..35c9e9ba 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ingame.nut @@ -112,8 +112,13 @@ void function InitInGameMPMenu() Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif - file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) - Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) + + // Nobody reads the FAQ so we replace it with ModSettings because of the limited combobutton space available + //file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) + //Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) //var dataCenterButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#DATA_CENTER" ) //Hud_AddEventHandler( dataCenterButton, UIE_CLICK, OpenDataCenterDialog ) @@ -133,7 +138,7 @@ void function OnInGameMPMenu_Open() bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) - ComboButton_SetNew( file.faqButton, faqIsNew ) + //ComboButton_SetNew( file.faqButton, faqIsNew ) UpdateLoadoutButtons() RefreshCreditsAvailable() @@ -255,6 +260,10 @@ void function InitInGameSPMenu() var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif + + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "Mod Settings" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) array orderedButtons diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 3c868aab..2bef0e20 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -352,8 +352,9 @@ void function SetupComboButtonTest( var menu ) var soundButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) Hud_AddEventHandler( soundButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif - file.faqButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#KNB_MENU_HEADER" ) - Hud_AddEventHandler( file.faqButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "KnowledgeBaseMenu" ) ) ) + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) comboStruct.navUpButtonDisabled = true comboStruct.navDownButton = file.genUpButton @@ -635,9 +636,9 @@ void function OnLobbyMenu_Open() ComboButton_SetNew( file.factionButton, anyNewFactions ) } - bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() + /*bool faqIsNew = !GetConVarBool( "menu_faq_viewed" ) || HaveNewPatchNotes() || HaveNewCommunityNotes() RuiSetBool( Hud_GetRui( file.settingsHeader ), "isNew", faqIsNew ) - ComboButton_SetNew( file.faqButton, faqIsNew ) + ComboButton_SetNew( file.faqButton, faqIsNew )*/ TryUnlockSRSCallsign() diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut new file mode 100644 index 00000000..a45082c7 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut @@ -0,0 +1,1105 @@ +untyped +global function AddModSettingsMenu +global function ModSettings_AddSetting +global function ModSettings_AddEnumSetting +global function ModSettings_AddSliderSetting +global function ModSettings_AddButton +global function ModSettings_AddModTitle +global function ModSettings_AddModCategory +global function PureModulo + +// Legacy functions for backwards compatability. These will be removed eventually +global function AddConVarSetting +global function AddConVarSettingEnum +global function AddConVarSettingSlider +global function AddModSettingsButton +global function AddModTitle +global function AddModCategory + +const int BUTTONS_PER_PAGE = 15 +const string SETTING_ITEM_TEXT = " " // this is long enough to be the same size as the textentry field + +enum eEmptySpaceType +{ + None, + TopBar, + BottomBar +} + +struct ConVarData { + string displayName + bool isEnumSetting = false + string conVar + string type + + string modName + string catName + bool isCategoryName = false + bool isModName = false + + bool isEmptySpace = false + int spaceType = 0 + + // SLIDER BULLSHIT + bool sliderEnabled = false + float min = 0.0 + float max = 1.0 + float stepSize = 0.05 + bool forceClamp = false + + bool isCustomButton = false + void functionref() onPress + + array values + var customMenu + bool hasCustomMenu = false +} + +struct { + var menu + int scrollOffset = 0 + bool updatingList = false + bool isOpen + + array conVarList + // if people use searches - i hate them but it'll do : ) + array filteredList + string filterText = "" + table enumRealValues + table setFuncs + array modPanels + array resetModButtons + array sliders + string currentMod = "" + string currentCat = "" +} file + +struct { + int deltaX = 0 + int deltaY = 0 +} mouseDeltaBuffer + +void function AddModSettingsMenu() +{ + AddMenu( "ModSettings", $"resource/ui/menus/mod_settings.menu", InitModMenu ) +} + +void function InitModMenu() +{ + file.menu = GetMenu( "ModSettings" ) + // DumpStack(2) + AddMenuFooterOption( file.menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) + + ///////////////////////////// + // BASE NORTHSTAR SETTINGS // + ///////////////////////////// + + /* + ModSettings_AddModTitle( "^FF000000EXAMPLE" ) + ModSettings_AddModCategory( "I wasted way too much time on this..." ) + ModSettings_AddButton( "This is a custom button you can click on!", void function() : () + { + print( "HELLOOOOOO" ) + } ) + ModSettings_AddEnumSetting( "filter_mods", "Very Huge Enum Example", split( "Never gonna give you up Never gonna let you down Never gonna run around and desert you Never gonna make you cry Never gonna say goodbye Never gonna tell a lie and hurt you", " " ) ) + */ + // Nuke weird rui on filter switch :D + // RuiSetString( Hud_GetRui( Hud_GetChild( file.menu, "SwtBtnShowFilter" ) ), "buttonText", "" ) + + file.modPanels = GetElementsByClassname( file.menu, "ModButton" ) + + AddMenuEventHandler( file.menu, eUIEvent.MENU_OPEN, OnModMenuOpened ) + AddMenuEventHandler( file.menu, eUIEvent.MENU_CLOSE, OnModMenuClosed ) + + int len = file.modPanels.len() + for ( int i = 0; i < len; i++ ) + { + + // AddButtonEventHandler( button, UIE_CHANGE, OnSettingButtonPressed ) + // get panel + var panel = file.modPanels[i] + + // reset to default nav + var child = Hud_GetChild( panel, "BtnMod" ) + + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "BtnMod" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "BtnMod" ) ) + + // Enum button nav + child = Hud_GetChild( panel, "EnumSelectButton" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "main" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "next" ) + Hud_DialogList_AddListItem( child, SETTING_ITEM_TEXT, "prev" ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "EnumSelectButton" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "EnumSelectButton" ) ) + Hud_AddEventHandler( child, UIE_CLICK, UpdateEnumSetting ) + + // reset button nav + + child = Hud_GetChild( panel, "ResetModToDefault" ) + Hud_AddEventHandler( child, UIE_GET_FOCUS, void function( var child ) : (panel) + { + Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 0, 0, 0, 255 ) + }) + Hud_AddEventHandler( child, UIE_LOSE_FOCUS, void function( var child ) : (panel) + { + Hud_SetColor( Hud_GetChild( panel, "ResetModImage" ), 180, 180, 180, 180 ) + }) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "ResetModToDefault" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "ResetModToDefault" ) ) + + Hud_AddEventHandler( child, UIE_CLICK, ResetConVar ) + file.resetModButtons.append(child) + + // text field nav + child = Hud_GetChild( panel, "TextEntrySetting" ) + + Hud_AddEventHandler( child, UIE_LOSE_FOCUS, SendTextPanelChanges ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "TextEntrySetting" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "TextEntrySetting" ) ) + + child = Hud_GetChild( panel, "Slider" ) + + child.SetNavUp( Hud_GetChild( file.modPanels[ int( PureModulo( i - 1, len ) ) ], "Slider" ) ) + child.SetNavDown( Hud_GetChild( file.modPanels[ int( PureModulo( i + 1, len ) ) ], "Slider" ) ) + + file.sliders.append( MS_Slider_Setup( child ) ) + + Hud_AddEventHandler( child, UIE_CHANGE, OnSliderChange ) + + child = Hud_GetChild( panel, "OpenCustomMenu" ) + + Hud_AddEventHandler( child, UIE_CLICK, CustomButtonPressed ) + } + + // Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_LOSE_FOCUS, OnFilterTextPanelChanged ) + Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnFiltersClear" ), UIE_CLICK, OnClearButtonPressed ) + // mouse delta + AddMouseMovementCaptureHandler( file.menu, UpdateMouseDeltaBuffer ) + + Hud_AddEventHandler( Hud_GetChild( file.menu, "BtnModsSearch" ), UIE_CHANGE, void function ( var inputField ) : () + { + file.filterText = Hud_GetUTF8Text( inputField ) + OnFiltersChange() + } ) +} + +// "PureModulo" +// Used instead of modulo in some places. +// Why? beacuse PureModulo loops back onto positive numbers instead of going into the negatives. +// DO NOT TOUCH. +// a / b != floor( float( a ) / b ) +// int( float( a ) / b ) != floor( float( a ) / b ) +// Examples: +// -1 % 5 = -1 +// PureModulo( -1, 5 ) = 4 +float function PureModulo( int a, int b ) +{ + return b * ( ( float( a ) / b ) - floor( float( a ) / b ) ) +} + +void function ResetConVar( var button ) +{ + ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ] + + if ( conVar.isCategoryName ) + ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetAllConVarsForModEventHandler( conVar.catName ), "#WILL_RESET_ALL_SETTINGS" ) + else + ShowAreYouSureDialog( "#ARE_YOU_SURE", ResetConVarEventHandler( int ( Hud_GetScriptID( Hud_GetParent( button ) ) ) + file.scrollOffset ), Localize( "#WILL_RESET_SETTING", Localize( conVar.displayName ) ) ) +} + +void function ShowAreYouSureDialog( string header, void functionref() func, string details ) +{ + DialogData dialogData + dialogData.header = header + dialogData.message = details + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", func ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_BACK" ) + + OpenDialog( dialogData ) +} + +void functionref() function ResetAllConVarsForModEventHandler( string catName ) +{ + return void function() : ( catName ) + { + for ( int i = 0; i < file.conVarList.len(); i++ ) + { + ConVarData c = file.conVarList[ i ] + if ( c.catName != catName || c.isCategoryName || c.isEmptySpace || c.isCustomButton ) + continue + SetConVarToDefault( c.conVar ) + + int index = file.filteredList.find( c ) + if ( file.filteredList.find( c ) < 0 ) + continue + + if ( min( BUTTONS_PER_PAGE - 1, max( 0, index - file.scrollOffset ) ) == index - file.scrollOffset ) + { + Hud_SetText( Hud_GetChild( file.modPanels[ index - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) ) + if( c.sliderEnabled ) + MS_Slider_SetValue( file.sliders[ index - file.scrollOffset ], GetConVarFloat( c.conVar ) ) + } + } + } +} + +void functionref() function ResetConVarEventHandler( int modIndex ) +{ + return void function() : ( modIndex ) + { + ConVarData c = file.filteredList[ modIndex ] + SetConVarToDefault( c.conVar ) + if ( min( BUTTONS_PER_PAGE - 1, max( 0, modIndex - file.scrollOffset ) ) == modIndex - file.scrollOffset ) + { + Hud_SetText( Hud_GetChild( file.modPanels[ modIndex - file.scrollOffset ], "TextEntrySetting" ), c.isEnumSetting ? c.values[ GetConVarInt( c.conVar ) ] : GetConVarString( c.conVar ) ) + if( c.sliderEnabled ) + MS_Slider_SetValue( file.sliders[ modIndex - file.scrollOffset ], GetConVarFloat( c.conVar ) ) + } + } +} + +//////////// +// slider // +//////////// +void function UpdateMouseDeltaBuffer( int x, int y ) +{ + mouseDeltaBuffer.deltaX += x + mouseDeltaBuffer.deltaY += y + + SliderBarUpdate() +} + +void function FlushMouseDeltaBuffer() +{ + mouseDeltaBuffer.deltaX = 0 + mouseDeltaBuffer.deltaY = 0 +} + +void function SliderBarUpdate() +{ + if ( file.filteredList.len() <= 15 ) + { + FlushMouseDeltaBuffer() + return + } + + var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" ) + + Hud_SetFocused( sliderButton ) + + float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded positions?!?!?!?!?! + float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 ) + float maxYPos = minYPos - ( maxHeight - Hud_GetHeight( sliderPanel ) ) + float useableSpace = ( maxHeight - Hud_GetHeight( sliderPanel ) ) + + float jump = minYPos - ( useableSpace / ( float( file.filteredList.len() ) ) ) + + int pos = expect int( expect array( Hud_GetPos( sliderButton ) )[1] ) + float newPos = float( pos - mouseDeltaBuffer.deltaY ) + FlushMouseDeltaBuffer() + + if ( newPos < maxYPos ) newPos = maxYPos + if ( newPos > minYPos ) newPos = minYPos + + Hud_SetPos( sliderButton, 2, newPos ) + Hud_SetPos( sliderPanel, 2, newPos ) + Hud_SetPos( movementCapture, 2, newPos ) + + file.scrollOffset = -int( ( ( newPos - minYPos ) / useableSpace ) * ( file.filteredList.len() - BUTTONS_PER_PAGE ) ) + UpdateList() +} + +void function UpdateListSliderHeight() +{ + var sliderButton = Hud_GetChild( file.menu, "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu, "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu, "MouseMovementCapture" ) + + float mods = float ( file.filteredList.len() ) + + float maxHeight = 615.0 * ( GetScreenSize()[1] / 1080.0 ) // why the hardcoded 320/80??? + float minHeight = 80.0 * ( GetScreenSize()[1] / 1080.0 ) + + float height = maxHeight * ( float( BUTTONS_PER_PAGE ) / mods ) + + if ( height > maxHeight ) height = maxHeight + if ( height < minHeight ) height = minHeight + + Hud_SetHeight( sliderButton, height ) + Hud_SetHeight( sliderPanel, height ) + Hud_SetHeight( movementCapture, height ) +} + +void function UpdateList() +{ + Hud_SetFocused( Hud_GetChild( file.menu, "BtnModsSearch" ) ) + file.updatingList = true + + array filteredList = [] + + array filters = split( file.filterText, "," ) + array list = file.conVarList + if ( filters.len() <= 0 ) + filters.append( "" ) + foreach( string f in filters ) + { + string filter = strip( f ) + string lastCatNameInFilter = "" + string lastModNameInFilter = "" + int curCatIndex = 0 + int curModTitleIndex = -1 + for ( int i = 0; i < list.len(); i++ ) + { + ConVarData prev = list[ maxint( 0, i - 1 ) ] + ConVarData c = list[i] + ConVarData next = list[ minint( list.len() - 1, i + 1 ) ] + if ( c.isEmptySpace ) + continue + + string displayName = c.displayName + if ( c.isModName ) + { + displayName = c.modName + curModTitleIndex = i + } + if ( c.isCategoryName ) + { + displayName = c.catName + curCatIndex = i + } + if ( filter == "" || SanitizeDisplayName( Localize( displayName ) ).tolower().find( filter.tolower() ) != null ) + { + if ( c.isModName ) + { + lastModNameInFilter = c.modName + array modVars = GetAllVarsInMod( list, c.modName ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + i += modVars.len() - 1 + } + else if ( c.isCategoryName ) + { + if ( lastModNameInFilter != c.modName ) + { + array modVars = GetModConVarDatas( list, curModTitleIndex ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + lastModNameInFilter = c.modName + } + filteredList.extend( GetAllVarsInCategory( list, c.catName ) ) + i += GetAllVarsInCategory( list, c.catName ).len() - 1 + lastCatNameInFilter = c.catName + } + else + { + if ( lastModNameInFilter != c.modName ) + { + array modVars = GetModConVarDatas( list, curModTitleIndex ) + if ( filteredList.len() <= 0 && modVars[0].spaceType == eEmptySpaceType.None ) + filteredList.extend( modVars.slice( 1, modVars.len() ) ) + else filteredList.extend( modVars ) + + lastModNameInFilter = c.modName + } + if ( lastCatNameInFilter != c.catName ) + { + filteredList.extend( GetCatConVarDatas( curCatIndex ) ) + lastCatNameInFilter = c.catName + } + filteredList.append( c ) + } + } + } + list = filteredList + filteredList = [] + } + filteredList = list + + + file.filteredList = filteredList + + int j = int( min( file.filteredList.len() + file.scrollOffset, BUTTONS_PER_PAGE ) ) + + for ( int i = 0; i < BUTTONS_PER_PAGE; i++ ) + { + Hud_SetEnabled( file.modPanels[i], i < j ) + Hud_SetVisible( file.modPanels[i], i < j ) + + if ( i < j ) + SetModMenuNameText( file.modPanels[i] ) + } + file.updatingList = false + + if ( file.conVarList.len() <= 0 ) + { + Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true ) + Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_MODS" ) + } + else if ( file.filteredList.len() <= 0 ) + { + Hud_SetVisible( Hud_GetChild( file.menu, "NoResultLabel" ), true ) + Hud_SetText( Hud_GetChild( file.menu, "NoResultLabel" ), "#NO_RESULTS" ) + } + else + { + Hud_Hide( Hud_GetChild( file.menu, "NoResultLabel" ) ) + } +} + +array function GetModConVarDatas( array arr, int index ) +{ + if ( index <= 1 ) + return [ arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ] + return [ arr[ index - 2 ], arr[ index - 1 ], arr[ index ], arr[ index + 1 ] ] +} + +array function GetCatConVarDatas( int index ) +{ + if ( file.conVarList[ index - 1 ].spaceType != eEmptySpaceType.None ) + return [ file.conVarList[ index ] ] + return [ file.conVarList[ index - 1 ], file.conVarList[ index ] ] +} + +array function GetAllVarsInCategory( array arr, string catName ) +{ + array vars = [] + for ( int i = 0; i < arr.len(); i++ ) + { + ConVarData c = arr[i] + if ( c.catName == catName ) + { + vars.append( arr[i] ) + } + } + return vars +} + +array function GetAllVarsInMod( array arr, string modName ) +{ + array vars = [] + for ( int i = 0; i < arr.len(); i++ ) + { + ConVarData c = arr[i] + if ( c.modName == modName ) + { + vars.append( arr[i] ) + } + } + return vars +} + +void function SetModMenuNameText( var button ) +{ + int index = int ( Hud_GetScriptID( button ) ) + file.scrollOffset + ConVarData conVar = file.filteredList[ int ( Hud_GetScriptID( button ) ) + file.scrollOffset ] + + var panel = file.modPanels[ int ( Hud_GetScriptID( button ) ) ] + + var label = Hud_GetChild( panel, "BtnMod" ) + var textField = Hud_GetChild( panel, "TextEntrySetting" ) + var enumButton = Hud_GetChild( panel, "EnumSelectButton" ) + var resetButton = Hud_GetChild( panel, "ResetModToDefault" ) + var resetVGUI = Hud_GetChild( panel, "ResetModImage" ) + var bottomLine = Hud_GetChild( panel, "BottomLine" ) + var topLine = Hud_GetChild( panel, "TopLine" ) + var modTitle = Hud_GetChild( panel, "ModTitle" ) + var customMenuButton = Hud_GetChild( panel, "OpenCustomMenu") + var slider = Hud_GetChild( panel, "Slider" ) + Hud_SetVisible( slider, false ) + Hud_SetEnabled( slider, true ) + + + if ( conVar.isEmptySpace ) + { + string s = "" + Hud_SetPos( label, 0, 0 ) + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( modTitle, false ) + Hud_SetVisible( customMenuButton, false ) + Hud_SetVisible( bottomLine, false ) + Hud_SetVisible( topLine, false ) + switch ( conVar.spaceType ) + { + case eEmptySpaceType.TopBar: + Hud_SetVisible( topLine, true ) + return + + case eEmptySpaceType.BottomBar: + Hud_SetVisible( bottomLine, true ) + return + + case eEmptySpaceType.None: + return + } + } + + Hud_SetVisible( textField, !conVar.isCategoryName ) + Hud_SetVisible( bottomLine, conVar.isCategoryName || conVar.spaceType == eEmptySpaceType.BottomBar ) + Hud_SetVisible( topLine, false ) + Hud_SetVisible( enumButton, !conVar.isCategoryName && conVar.isEnumSetting ) + Hud_SetVisible( modTitle, conVar.isModName ) + Hud_SetVisible( customMenuButton, false ) + float scaleX = GetScreenSize()[1] / 1080.0 + float scaleY = GetScreenSize()[1] / 1080.0 + if ( conVar.sliderEnabled ) + { + Hud_SetSize( slider, int( 320 * scaleX ), int( 45 * scaleY ) ) + MS_Slider s = file.sliders[ int ( Hud_GetScriptID( button ) ) ] + MS_Slider_SetMin( s, conVar.min ) + MS_Slider_SetMax( s, conVar.max ) + MS_Slider_SetStepSize( s, conVar.stepSize ) + MS_Slider_SetValue( s, GetConVarFloat( conVar.conVar ) ) + } + else Hud_SetSize( slider, 0, int( 45 * scaleY ) ) + if ( conVar.isCustomButton ) + { + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( modTitle, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( customMenuButton, true ) + Hud_SetText( customMenuButton, conVar.displayName ) + } + else if ( conVar.isModName ) + { + Hud_SetText( modTitle, conVar.modName ) + Hud_SetPos( label, 0, 0 ) + Hud_SetVisible( label, false ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, false ) + Hud_SetVisible( resetVGUI, false ) + Hud_SetVisible( bottomLine, false ) + Hud_SetVisible( topLine, false ) + } + else if ( conVar.isCategoryName ) + { + Hud_SetText( label, conVar.catName ) + Hud_SetPos( label, 0, 0 ) + Hud_SetSize( label, int( scaleX * ( 1180 - 420 - 85 ) ), int( scaleY * 40 ) ) + Hud_SetVisible( label, true ) + Hud_SetVisible( textField, false ) + Hud_SetVisible( enumButton, false ) + Hud_SetVisible( resetButton, true ) + Hud_SetVisible( resetVGUI, true ) + + Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) ) + } + else { + Hud_SetVisible( slider, conVar.sliderEnabled ) + + Hud_SetText( label, conVar.displayName ) + if (conVar.type == "float") + Hud_SetText( textField, string( GetConVarFloat(conVar.conVar) ) ) + else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) ) + Hud_SetPos( label, int(scaleX * 25), 0 ) + Hud_SetText( resetButton, "" ) + if (conVar.sliderEnabled) + Hud_SetSize( label, int(scaleX * (375 + 85)), int(scaleY * 40) ) + else Hud_SetSize( label, int(scaleX * (375 + 405)), int(scaleY * 40) ) + if ( conVar.type == "float" ) + Hud_SetText( textField, string( GetConVarFloat( conVar.conVar ) ) ) + else Hud_SetText( textField, conVar.isEnumSetting ? conVar.values[ GetConVarInt( conVar.conVar ) ] : GetConVarString( conVar.conVar ) ) + Hud_SetPos( label, int( scaleX * 25 ), 0 ) + Hud_SetText( resetButton, "" ) + Hud_SetSize( resetButton, int( scaleX * 90 ), int( scaleY * 40 ) ) + if ( conVar.sliderEnabled ) + Hud_SetSize( label, int( scaleX * ( 375 + 85 ) ), int( scaleY * 40 ) ) + else Hud_SetSize( label, int( scaleX * ( 375 + 405 ) ), int( scaleY * 40 ) ) + Hud_SetVisible( label, true ) + Hud_SetVisible( textField, true ) + Hud_SetVisible( resetButton, true ) + Hud_SetVisible( resetVGUI, true ) + } +} + +void function CustomButtonPressed( var button ) +{ + var panel = Hud_GetParent( button ) + ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ] + c.onPress() +} + +void function OnScrollDown( var button ) +{ + if ( file.filteredList.len() <= BUTTONS_PER_PAGE ) return + file.scrollOffset += 5 + if ( file.scrollOffset + BUTTONS_PER_PAGE > file.filteredList.len() ) + { + file.scrollOffset = file.filteredList.len() - BUTTONS_PER_PAGE + } + UpdateList() + UpdateListSliderPosition() +} + +void function OnScrollUp( var button ) +{ + file.scrollOffset -= 5 + if ( file.scrollOffset < 0 ) + { + file.scrollOffset = 0 + } + UpdateList() + UpdateListSliderPosition() +} + +void function UpdateListSliderPosition() +{ + var sliderButton = Hud_GetChild( file.menu , "BtnModListSlider" ) + var sliderPanel = Hud_GetChild( file.menu , "BtnModListSliderPanel" ) + var movementCapture = Hud_GetChild( file.menu , "MouseMovementCapture" ) + + float mods = float ( file.filteredList.len() ) + + float minYPos = -40.0 * ( GetScreenSize()[1] / 1080.0 ) + float useableSpace = ( 615.0 * ( GetScreenSize()[1] / 1080.0 ) - Hud_GetHeight( sliderPanel ) ) + + float jump = minYPos - ( useableSpace / ( mods - float( BUTTONS_PER_PAGE ) ) * file.scrollOffset ) + + + if ( jump > minYPos ) jump = minYPos + + Hud_SetPos( sliderButton , 2, jump ) + Hud_SetPos( sliderPanel , 2, jump ) + Hud_SetPos( movementCapture , 2, jump ) +} + +void function OnModMenuOpened() +{ + if( !file.isOpen ) + { + file.scrollOffset = 0 + file.filterText = "" + + RegisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp ) + RegisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown ) + RegisterButtonPressedCallback( MOUSE_LEFT , OnClick ) + + OnFiltersChange() + file.isOpen = true + } +} + +void function OnClick( var button ) +{ + if (file.resetModButtons.contains(GetFocus())) + thread CheckFocus(GetFocus()) + if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel")) + thread CheckFocus(GetFocus()) +} + +void function CheckFocus( var button ) +{ + wait 0.05 + if (file.resetModButtons.contains(GetFocus())) + { + thread ResetConVar(GetFocus()) + } + if (GetFocus() == Hud_GetChild(file.menu, "NoResultLabel")) + LaunchExternalWebBrowser( "https://northstar.thunderstore.io/", WEBBROWSER_FLAG_FORCEEXTERNAL ) +} + +void function OnFiltersChange() +{ + file.scrollOffset = 0 + + UpdateList() + + UpdateListSliderHeight() +} + +void function OnModMenuClosed() +{ + DeregisterButtonPressedCallback( MOUSE_WHEEL_UP , OnScrollUp ) + DeregisterButtonPressedCallback( MOUSE_WHEEL_DOWN , OnScrollDown ) + DeregisterButtonPressedCallback( MOUSE_LEFT , OnClick ) + + file.scrollOffset = 0 + UpdateListSliderPosition() + file.isOpen = false +} + +void function ModSettings_AddModTitle( string modName, int stackPos = 2 ) +{ + file.currentMod = modName + if ( file.conVarList.len() > 0 ) + { + ConVarData catData + + catData.isEmptySpace = true + catData.modName = file.currentMod + + file.conVarList.append( catData ) + } + ConVarData topBar + topBar.isEmptySpace = true + topBar.modName = modName + topBar.spaceType = eEmptySpaceType.TopBar + + + ConVarData modData + + modData.modName = modName + modData.displayName = modName + modData.isModName = true + + + ConVarData botBar + botBar.isEmptySpace = true + botBar.modName = modName + botBar.spaceType = eEmptySpaceType.BottomBar + file.conVarList.extend( [ topBar, modData, botBar ] ) + file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] <- false +} + +void function AddModTitle( string modName, int stackPos = 2 ) +{ + ModSettings_AddModTitle( modName, stackPos + 1 ) +} + +void function ModSettings_AddModCategory( string catName, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a category before a mod title!" + + ConVarData space + space.isEmptySpace = true + space.modName = file.currentMod + space.catName = catName + file.conVarList.append( space ) + + ConVarData catData + + catData.catName = catName + catData.displayName = catName + catData.modName = file.currentMod + catData.isCategoryName = true + + file.conVarList.append( catData ) + + file.currentCat = catName + file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] = true +} + +void function AddModCategory( string catName, int stackPos = 2 ) +{ + ModSettings_AddModCategory( catName, stackPos + 1 ) +} + +void function ModSettings_AddButton( string buttonLabel, void functionref() onPress, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a button before a category and mod title!" + + ConVarData data + + data.isCustomButton = true + data.displayName = buttonLabel + data.modName = file.currentMod + data.catName = file.currentCat + data.onPress = onPress + + file.conVarList.append( data ) +} + +void function AddModSettingsButton( string buttonLabel, void functionref() onPress, int stackPos = 2 ) +{ + ModSettings_AddButton( buttonLabel, onPress, stackPos + 1 ) +} + +void function ModSettings_AddSetting( string conVar, string displayName, string type = "", int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.conVar = conVar + data.modName = file.currentMod + data.displayName = displayName + data.type = type + + file.conVarList.append( data ) +} + +void function AddConVarSetting( string conVar, string displayName, string type = "", int stackPos = 2 ) +{ + ModSettings_AddSetting( conVar, displayName, type, stackPos + 1 ) +} + +void function ModSettings_AddSliderSetting( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.conVar = conVar + data.modName = file.currentMod + data.displayName = displayName + data.type = "float" + data.sliderEnabled = true + data.forceClamp = false + data.min = min + data.max = max + data.stepSize = stepSize + + file.conVarList.append( data ) +} + +void function AddConVarSettingSlider( string conVar, string displayName, float min = 0.0, float max = 1.0, float stepSize = 0.1, bool forceClamp = false, int stackPos = 2 ) +{ + ModSettings_AddSliderSetting( conVar, displayName, min, max, stepSize, forceClamp, stackPos + 1 ) +} + +void function ModSettings_AddEnumSetting( string conVar, string displayName, array values, int stackPos = 2 ) +{ + if ( !( getstackinfos( stackPos )[ "func" ] in file.setFuncs ) || !file.setFuncs[ expect string( getstackinfos( stackPos )[ "func" ] ) ] ) + throw getstackinfos( stackPos )[ "src" ] + " #" + getstackinfos( stackPos )[ "line" ] + "\nCannot add a setting before a category and mod title!" + ConVarData data + + data.catName = file.currentCat + data.modName = file.currentMod + data.conVar = conVar + data.displayName = displayName + data.values = values + data.isEnumSetting = true + data.min = 0 + data.max = values.len() - 1.0 + data.sliderEnabled = values.len() > 2 + data.forceClamp = true + data.stepSize = 1 + + file.conVarList.append( data ) +} + +void function AddConVarSettingEnum( string conVar, string displayName, array values, int stackPos = 2 ) +{ + ModSettings_AddEnumSetting( conVar, displayName, values, stackPos + 1 ) +} + +void function OnSliderChange( var button ) +{ + if ( file.updatingList ) + return + var panel = Hud_GetParent( button ) + ConVarData c = file.filteredList[ int( Hud_GetScriptID( panel ) ) + file.scrollOffset ] + var textPanel = Hud_GetChild( panel, "TextEntrySetting" ) + + if ( c.isEnumSetting ) + { + int val = int( RoundToNearestInt( Hud_SliderControl_GetCurrentValue( button ) ) ) + SetConVarInt( c.conVar, val ) + Hud_SetText( textPanel, ( c.values[ GetConVarInt( c.conVar ) ] ) ) + MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], float( val ) ) + + return + } + float val = Hud_SliderControl_GetCurrentValue( button ) + if ( c.forceClamp ) + { + int mod = int( RoundToNearestInt( val % c.stepSize / c.stepSize ) ) + val = ( int( val / c.stepSize ) + mod ) * c.stepSize + } + SetConVarFloat( c.conVar, val ) + MS_Slider_SetValue( file.sliders[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) ], val ) + + Hud_SetText( textPanel, string( GetConVarFloat( c.conVar ) ) ) +} + +void function SendTextPanelChanges( var textPanel ) +{ + ConVarData c = file.filteredList[ int( Hud_GetScriptID( Hud_GetParent( textPanel ) ) ) + file.scrollOffset ] + if ( c.conVar == "" ) return + // enums don't need to do this + if ( !c.isEnumSetting ) + { + string newSetting = Hud_GetUTF8Text( textPanel ) + + switch ( c.type ) + { + case "int": + try + { + SetConVarInt( c.conVar, newSetting.tointeger() ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + case "bool": + if ( newSetting != "0" && newSetting != "1" ) + { + ThrowInvalidValue( "This setting is a boolean, and only accepts values of 0 or 1." ) + + // set back to previous value : ) + Hud_SetText( textPanel, string( GetConVarBool( c.conVar ) ) ) + + break + } + SetConVarBool( c.conVar, newSetting == "1" ) + break + case "float": + try + { + SetConVarFloat( c.conVar, newSetting.tofloat() ) + } + catch ( ex ) + { + printt( ex ) + ThrowInvalidValue( "This setting is a float, and only accepts a number - we could not parse this!\n\n( Use \".\" for the floating point, not \",\". )" ) + } + if ( c.sliderEnabled ) + { + var panel = Hud_GetParent( textPanel ) + MS_Slider s = file.sliders[ int ( Hud_GetScriptID( panel ) ) ] + + MS_Slider_SetValue( s, GetConVarFloat( c.conVar ) ) + } + break + case "float2": + try + { + array split = split( newSetting, " " ) + if ( split.len() != 2 ) + { + ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put in " + split.len() + "!" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + break + } + vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 > + + SetConVarString( c.conVar, newSetting ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is a float2, and only accepts a pair of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + break + // idk sometimes it's called Float3 most of the time it's called vector, I am not complaining. + case "vector": + case "float3": + try + { + array split = split( newSetting, " " ) + if ( split.len() != 3 ) + { + ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put in " + split.len() + "!" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + break + } + vector settingTest = < split[0].tofloat(), split[1].tofloat(), 0 > + + SetConVarString( c.conVar, newSetting ) + } + catch ( ex ) + { + ThrowInvalidValue( "This setting is a float3, and only accepts a trio of numbers - you put something we could not parse!\n\n( Use \".\" for the floating point, not \",\". )" ) + Hud_SetText( textPanel, GetConVarString( c.conVar ) ) + } + break + default: + SetConVarString( c.conVar, newSetting ) + break; + } + } + else Hud_SetText( textPanel, Localize( c.values[ GetConVarInt( c.conVar ) ] ) ) +} + +void function ThrowInvalidValue( string desc ) +{ + DialogData dialogData + dialogData.header = "Invalid Value" + dialogData.image = $"ui/menu/common/dialog_error" + dialogData.message = desc + AddDialogButton( dialogData, "#OK" ) + OpenDialog( dialogData ) +} + +void function UpdateEnumSetting( var button ) +{ + int scriptId = int( Hud_GetScriptID( Hud_GetParent( button ) ) ) + ConVarData c = file.filteredList[ scriptId + file.scrollOffset ] + + var panel = file.modPanels[ scriptId ] + + var textPanel = Hud_GetChild( panel, "TextEntrySetting" ) + + string selectionVal = Hud_GetDialogListSelectionValue( button ) + + if ( selectionVal == "main" ) + return + + int enumVal = GetConVarInt( c.conVar ) + if ( selectionVal == "next" ) // enum val += 1 + enumVal = ( enumVal + 1 ) % c.values.len() + else // enum val -= 1 + { + enumVal-- + if ( enumVal == -1 ) + enumVal = c.values.len() - 1 + } + + SetConVarInt( c.conVar, enumVal ) + Hud_SetText( textPanel, c.values[ enumVal ] ) + + Hud_SetDialogListSelectionValue( button, "main" ) +} + +void function OnClearButtonPressed( var button ) +{ + file.filterText = "" + Hud_SetText( Hud_GetChild( file.menu, "BtnModsSearch" ), "" ) + + OnFiltersChange() +} + +string function SanitizeDisplayName( string displayName ) +{ + array parts = split( displayName, "^" ) + string result = "" + if ( parts.len() == 1 ) + return parts[0] + foreach ( string p in parts ) + { + if ( p == "" ) + { + result += "^" + continue + } + int i = 0 + for ( i = 0; i < 8 && i < p.len(); i++ ) + { + var c = p[i] + if ( ( c < 'a' || c > 'f' ) && ( c < 'A' || c > 'F' ) && ( c < '0' || c > '9' ) ) + break + } + if ( i == 0 ) + result += p + else result += p.slice( i, p.len() ) + } + return result +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut new file mode 100644 index 00000000..33a79cdc --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/ns_slider.nut @@ -0,0 +1,52 @@ +// ModSettings_Slider +// since we are missing some utility functions (e.g. GetMax, GetMin, SetValue), this is basically a collection of workarounds. +global struct MS_Slider +{ + var slider + float min = 0.0 + float max = 1.0 + float stepSize = 0.05 +} + +globalize_all_functions + +MS_Slider function MS_Slider_Setup( var slider, float min = 0.0, float max = 1.0, float startVal = 0.0, float stepSize = 0.05 ) +{ + MS_Slider result + result.slider = slider + result.min = min + result.max = max + result.stepSize = stepSize + Hud_SliderControl_SetMin( slider, startVal ) + Hud_SliderControl_SetMax( slider, startVal ) + Hud_SliderControl_SetStepSize( slider, stepSize ) + Hud_SliderControl_SetMin( slider, min ) + Hud_SliderControl_SetMax( slider, max ) + return result +} + +void function MS_Slider_SetValue( MS_Slider slider, float val ) +{ + Hud_SliderControl_SetMin( slider.slider, val ) + Hud_SliderControl_SetMax( slider.slider, val ) + Hud_SliderControl_SetMin( slider.slider, slider.min ) + Hud_SliderControl_SetMax( slider.slider, slider.max ) +} + +void function MS_Slider_SetMin( MS_Slider slider, float min ) +{ + slider.min = min + Hud_SliderControl_SetMin( slider.slider, min ) +} + +void function MS_Slider_SetMax( MS_Slider slider, float max ) +{ + slider.max = max + Hud_SliderControl_SetMax( slider.slider, max ) +} + +void function MS_Slider_SetStepSize( MS_Slider slider, float stepSize ) +{ + slider.stepSize = stepSize + Hud_SliderControl_SetStepSize( slider.slider, stepSize ) +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index 53d85387..eef19b5e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -101,6 +101,10 @@ void function InitMainMenuPanel() var videoButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#VIDEO" ) Hud_AddEventHandler( videoButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "VideoMenu" ) ) ) #endif + + // MOD SETTINGS + var modSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MOD_SETTINGS" ) + Hud_AddEventHandler( modSettingsButton, UIE_CLICK, AdvanceMenuEventHandler( GetMenu( "ModSettings" ) ) ) var spotlightLargeButton = Hud_GetChild( file.spotlightPanel, "SpotlightLarge" ) spotlightLargeButton.SetNavLeft( file.spButtons[0] ) -- cgit v1.2.3 From 5be5a6da1c7f658a44e396404425444fd6f83a0c Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 28 May 2023 22:37:09 +0200 Subject: Improve Italian translation (#610) Based on community suggested translations Co-authored-by: n00neheregit <94216450+n00neheregit@users.noreply.github.com> Co-authored-by: CloudSE7EN <87913937+CloudSE7EN@users.noreply.github.com> --- .../northstar_client_localisation_italian.txt | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index 13835b8b..fa84b6a2 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -7,18 +7,18 @@ "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Ricarica Mods" "WARNING", "Attenzione" - "CORE_MOD_DISABLE_WARNING", "Disattivare Mods Principali può rompere il tuo Client!" + "CORE_MOD_DISABLE_WARNING", "Disattivare le Mods Principali può rompere il tuo Client!" "DISABLE", "Disattiva" "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Grazie per aver installato Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Affinché Northstar funzioni, è necessario autenticarsi utilizzando il server principale di Northstar. Ciò richiederà l'invio del tuo token di Origin al server principale, non verrà archiviato o utilizzato per altri scopi. -Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi momento nel menu mods." +Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi momento nel Menu delle Mods." "BACK_AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT" "Accordo di autenticazione" "AUTHENTICATION_AGREEMENT_RESTART" "Dovrai riavviare Titanfall 2 affinché questa scelta abbia effetto." "DIALOG_AUTHENTICATING_MASTERSERVER", "Autenticazione Sul Master Server in corso" - "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu Mods" + "AUTHENTICATIONAGREEMENT_NO", "Hai Scelto di non autenticarti con Northstar. Puoi vedere l'Accordo nel Menu delle Mods" "MENU_TITLE_SERVER_BROWSER" "Server Browser" "NS_SERVERBROWSER_NOSERVERS" "Nessun server trovato" @@ -39,7 +39,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Single-Player)" // fra hint for private match menu, because fra only has PL_fra_desc in vanilla - "PL_fra_hint" "Tutti contro tutti. Uccidi nemici per vincere. Raccogli 3 batterie per chiamare il Titan." + "PL_fra_hint" "Tutti contro tutti. Uccidi i nemici per vincere. Raccogli 3 batterie per chiamare il tuo Titan." // mode settings "MODE_SETTING_CATEGORY_PILOT" "Pilota" @@ -63,7 +63,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "earn_meter_titan_multiplier" "Moltiplicatore nucleo Titan" "aegis_upgrades" "Upgrade Aegis" - "infinite_doomed_state" "Doom state Infinito" + "infinite_doomed_state" "Stato Doom Infinito" "titan_shield_regen" "Rigenerazione Scudi" "riff_floorislava" "Terreno Mortale" @@ -80,12 +80,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "cp_amped_capture_points" "Hardpoints Amplificati" "coliseum_loadouts_enabled" "Equipaggiamento Colosseo" - "aitdm_archer_grunts", "Schagniozzi Archer" + "aitdm_archer_grunts", "Scagnozzi Archer" // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" "PL_sbox_lobby" "Sandbox Lobby" - "PL_sbox_desc" "come gmod ma peggio." + "PL_sbox_desc" "Come gmod ma peggio." "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" @@ -94,9 +94,9 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_gg_desc" "Ottieni un'uccisione con ogni arma per vincere." "PL_gg_hint" "Ottieni una nuova arma ogni uccisione." "PL_gg_abbr" "GG" - "GAMEMODE_GG" "Gioco d'Armi" - "aitdm_archer_grunts", "Schagniozzi Archer" - "gg_kill_reward", "Punteggio Riconpensa Uccisione" + "GAMEMODE_GG" "Gioco delle Armi" + "aitdm_archer_grunts", "Scagnozzi Archer" + "gg_kill_reward", "Punteggio Ricompensa Uccisione" "gg_assist_reward", "Punteggio Ricompensa Assist" "gg_execution_reward", "Punteggio Ricompensa Esecuzione" @@ -126,11 +126,11 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_sns", "Sticks and Stones" "PL_sns_lobby", "Sticks and Stones Lobby" - "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e Esecuzioni per Resettare il Puntegio Nemico" + "PL_sns_desc", "Tutti contro Tutti, Usa la Pulse Blade e le Esecuzioni per Resettare il Punteggio Nemico" "PL_sns_abbr", "SNS" "GAMEMODE_SNS", "Sticks and Stones" "SCOREBOARD_BANKRUPTS", "Uccisioni Bancarotta" - "SNS_LEADER_BANKRUPT", "Leader Punteggio andato in Bancarotta!" + "SNS_LEADER_BANKRUPT", "Il Leader punteggio è andato in Bancarotta!" "SNS_LEADER_BANKRUPT_SUB", "%s1 è stato Resettato da %s2" "SNS_BANKRUPT", "Bancarotta!" "SNS_BANKRUPT_SUB", "Il Tuo Punteggio è stato Resettato da %s1" @@ -156,12 +156,12 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "INFECTION_YOU_ARE_LAST_SURVIVOR" "Sei l'Ultimo Sopravvissuto!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sopravvivi." - "PL_tffa", "Titan Free for All" - "PL_tffa_lobby", "Titan Free for All Lobby" + "PL_tffa", "Titan Tutti contro Tutti" + "PL_tffa_lobby", "Lobby: Titan Tutti contro Tutti" "PL_tffa_desc", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." "PL_tffa_hint", "Ogni Pilota per sè, distruggi tutti i Titan Nemici." "PL_tffa_abbr", "TFFA" - "GAMEMODE_TFFA", "Titan Free for All" + "GAMEMODE_TFFA", "Titan Tutti contro Tutti" "PL_hs" "Nascondino" "PL_hs_lobby" "Lobby: Nascondino" @@ -177,14 +177,14 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDEANDSEEK_DONT_GET_FOUND" "Non farti trovare!" "HIDEANDSEEK_GET_LAST_HIDER" "%s1 è L'ULTIMO CERCATORE" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "SEI L'ULTIMO NASCOSTO" - "HIDEANDSEEK_GOT_STIM" "Sei stimmato! Non farti prendere!" + "HIDEANDSEEK_GOT_STIM" "Sei stimolato! Non farti prendere!" "hideandseek_balance_teams" "Bilanciamento Squadre..." "hideandseek_hiding_time" "Tempo per Nascondersi" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development - "GAMEMODE_fw" "Frontier War" - "PL_fw" "Frontier War" - "PL_fw_lobby" "Lobby: Frontier War" + "GAMEMODE_fw" "Guerra di Frontiera" + "PL_fw" "Guerra di Frontiera" + "PL_fw_lobby" "Lobby: Guerra di Frontiera" "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo." "PL_fw_abbr" "FW" @@ -250,7 +250,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper incontra BT-7274." "SP_SEWERS1" "Sangue e Ruggine" - "SP_SEWERS1_CLASSIC_DESC" "Cooper e BT cercano di raggiungere il Major Anderson." + "SP_SEWERS1_CLASSIC_DESC" "Cooper e BT cercano di raggiungere il Maggiore Anderson." "SP_BOOMTOWN_START" "Nell'abisso" "SP_BOOMTOWN_START_CLASSIC_DESC" "Una scorciatoia sotterranea porta a conseguenze impreviste." @@ -272,7 +272,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo // Better.Serverbrowser "SERVERS_COLUMN" "Server" - "PLAYERS_COLUMN" "Players" + "PLAYERS_COLUMN" "Giocatori" "MAP_COLUMN" "Mappa" "GAMEMODE_COLUMN" "Modalità" "REGION_COLUMN" "Regione" @@ -306,18 +306,18 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDE_LOCKED" "Nascondi bloccati" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" + "HUD_CHAT_WHISPER_PREFIX" [BISBIGLIO]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" "NO_GAMESERVER_RESPONSE" "Non è stato possibile raggiungere il server" "BAD_GAMESERVER_RESPONSE" "Il server ha dato una risposta invalida" "UNAUTHORIZED_GAMESERVER" "Il server non è autorizzato a fare quella richiesta" - "UNAUTHORIZED_GAME" "Stryder non è riuscito a confermare che questo account possiede Titanfall 2" + "UNAUTHORIZED_GAME" "Stryder non è riuscito a confermare che questo account possieda Titanfall 2" "UNAUTHORIZED_PWD" "Password errata" - "STRYDER_RESPONSE" "Non è stato possibile analizzare la risposta Stryder" + "STRYDER_RESPONSE" "Non è stato possibile analizzare la risposta di Stryder" "PLAYER_NOT_FOUND" "Non è stato trovato l'account player" "INVALID_MASTERSERVER_TOKEN" "Token Masterserver invalido o scaduto" - "JSON_PARSE_ERROR" "Errore nell'analisi di risposta json" + "JSON_PARSE_ERROR" "Errore nell'analisi della risposta json" "UNSUPPORTED_VERSION" "La versione che stai usando non è più supportata" "MOD_SETTINGS" "Impostazioni Mod" -- cgit v1.2.3 From 9620bb200de53f6d7def694e99513e213a22e081 Mon Sep 17 00:00:00 2001 From: uniboi <64006268+uniboi@users.noreply.github.com> Date: Mon, 19 Jun 2023 20:00:20 +0000 Subject: Add Triple Threat grenade indicators (#647) --- Northstar.Custom/mod/scripts/weapons/mp_titanweapon_triplethreat.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_triplethreat.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_triplethreat.txt index a1337d9f..09aac6ea 100644 --- a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_triplethreat.txt +++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_triplethreat.txt @@ -102,6 +102,8 @@ WeaponData // Damage - When Used by Players "damage_type" "burn" + "show_grenade_indicator" "1" + "crosshair" "crosshair_t" "explosion_damage" "350" // 150 "explosion_damage_heavy_armor" "550" // 150 -- cgit v1.2.3 From 6ff307c15ef5c5797f5a0d2b2ed26ff4aa018ddd Mon Sep 17 00:00:00 2001 From: Respawn Date: Sat, 24 Jun 2023 00:32:27 +0200 Subject: Add sh_melee.gnut from englishclient_mp_common --- .../mod/scripts/vscripts/melee/sh_melee.gnut | 1212 ++++++++++++++++++++ 1 file changed, 1212 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut new file mode 100644 index 00000000..dfd957e1 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut @@ -0,0 +1,1212 @@ +untyped + +global function MeleeShared_Init + +global function CodeCallback_OnMeleePressed +//global function CodeCallback_OnMeleeHeld +//global function CodeCallback_OnMeleeReleased +global function CodeCallback_IsValidMeleeExecutionTarget +global function CodeCallback_IsValidMeleeAttackTarget +global function CodeCallback_OnMeleeAttackAnimEvent +global function AddSyncedMeleeServerCallback +global function AddSyncedMeleeServerThink + +global function GetSyncedMeleeChooser +global function CreateSyncedMeleeChooser +global function PlayerTriesSyncedMelee +global function FindBestSyncedMelee +global function GetSyncedMeleeChooserForPlayerVsTarget +global function AddSyncedMelee +global function GetEyeOrigin +global function SetObjectCanBeMeleed +global function ObjectCanBeMeleed +global function ShouldClampTargetVelocity +global function ClampVerticalVelocity +global function IsInExecutionMeleeState + +global function GetLungeTargetForPlayer +global function Melee_IsAllowed +global function IsAttackerRef + +#if SERVER + global function Melee_Enable + global function Melee_Disable + global function SyncedMelee_Enable + global function SyncedMelee_Disable + global function InitMeleeAnimEventCallbacks + global function GetRefAnglesBetweenEnts + global function CreateMeleeScriptMoverBetweenEnts + global function ShouldHolsterWeaponForMelee + global function ShouldHolsterWeaponForSyncedMelee + global function NPCTriesSyncedMeleeVsPlayer +#endif + +const SMOOTH_TIME = 0.2 +const INSTA_KILL_TIME_THRESHOLD = 0.35 +const BUG_REPRO_MOVEMELEE = 19114 + +global struct SyncedMelee +{ + string ref + bool enabled = true + vector direction = < 1, 0, 0 > + float distance + float distanceSqr + string attackerAnimation1p + string attackerAnimation3p +// void function AddAnimEvent( entity ent, string eventName, void functionref( entity ent ) func, var optionalVar = null ) + array attacker3pAnimEvents + array target3pAnimEvents + string targetAnimation1p + string targetAnimation3p + string thirdPersonCameraAttachment + asset attachModel1p + string attachTag1p + float minDot = -1.0 // always happens + string animRefPos = "target" + bool canTargetNPCs = true + float percentDamageDealtPerHit = 1.0 + bool usableByPlayers = true + + float targetMinHealthRatio = 0.0 // target health ratio must be at least this high + float targetMaxHealthRatio = 1.0 // target health ratio must be at or below this + bool onlyIfLethal // only if the strike would be lethal + bool isAttackerRef = true + +} + +global struct SyncedMeleeChooser +{ + vector functionref( entity ) attackerOriginFunc + vector functionref( entity ) targetOriginFunc + array syncedMelees + bool displayMeleePrompt = true +} + +struct +{ + table > syncedMeleeChoosers + table > syncedMeleeServerCallbacks + table syncedMeleeServerThink + + string lastExecutionUsed = "" +} file + +function MeleeShared_Init() +{ + FlagInit( "ForceSyncedMelee" ) + + level.HUMAN_VS_TITAN_MELEE <- 1 + level.titan_attack_anim_event_count <- 0 + level.titan_attack_push_button_count <- 0 + + MeleeHumanShared_Init() + MeleeTitanShared_Init() + MeleeSyncedHumanShared_Init() + MeleeSyncedTitanShared_Init() + + #if SERVER + VerifySyncedMelee() + MeleeSyncedServer_Init() + #endif + + RegisterSignal( "SyncedMeleeComplete" ) + RegisterSignal( "OnSyncedMelee" ) + RegisterSignal( "OnSyncedMeleeVictim" ) + RegisterSignal( "OnSyncedMeleeAttacker" ) +} + +int function GetPlayerMeleeDamage( entity player ) +{ + Assert( player.IsPlayer() ) + foreach ( weapon in player.GetMainWeapons() ) + { + switch ( weapon.GetWeaponInfoFileKeyField( "fire_mode" ) ) + { + case "offhand_melee": + return expect int( weapon.GetWeaponInfoFileKeyField( "melee_damage" ) ) + } + } + + return 0 +} + +void function AddSyncedMeleeServerCallback( SyncedMeleeChooser chooser, void functionref( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target ) func ) +{ + if ( !( chooser in file.syncedMeleeServerCallbacks ) ) + file.syncedMeleeServerCallbacks[ chooser ] <- [] + + file.syncedMeleeServerCallbacks[ chooser ].append( func ) +} + +void function AddSyncedMeleeServerThink( SyncedMeleeChooser chooser, bool functionref( SyncedMelee action, entity player, entity target ) func ) +{ + file.syncedMeleeServerThink[ chooser ] <- func +} + + +function VerifySyncedMelee() +{ + foreach ( attackerChoosers in file.syncedMeleeChoosers ) + { + foreach ( chooser in attackerChoosers ) + { + //Assert( chooser in file.syncedMeleeServerCallbacks, "Need to add synced server melee callback for synced melee chooser" ) + //Assert( file.syncedMeleeServerCallbacks[ chooser ].len() > 0, "Need to create a callback for chooser" ) + Assert( chooser in file.syncedMeleeServerThink, "Need to add synced server melee callback for synced melee chooser" ) + } + } +} + +SyncedMeleeChooser function GetSyncedMeleeChooser( string attackerType, string victimType ) +{ + return file.syncedMeleeChoosers[ attackerType ][ victimType ] +} + +SyncedMeleeChooser function CreateSyncedMeleeChooser( string attackerType, string victimType ) +{ + SyncedMeleeChooser chooser + + chooser.attackerOriginFunc = GetEyeOrigin + chooser.targetOriginFunc = GetEyeOrigin + + if ( !( attackerType in file.syncedMeleeChoosers ) ) + file.syncedMeleeChoosers[ attackerType ] <- {} + + Assert( !( victimType in file.syncedMeleeChoosers[ attackerType ] ), "Already has " + victimType ) + file.syncedMeleeChoosers[ attackerType ][ victimType ] <- chooser + return chooser +} + +vector function GetEyeOrigin( entity ent ) +{ + return ent.EyePosition() +} + +//Called after pressing the melee button to recheck for targets +bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity target ) +{ + if ( attacker == target ) + return false + + if ( !ShouldPlayerExecuteTarget( attacker, target ) ) + return false + + if ( !attacker.IsOnGround() && attacker.IsHuman() ) + return false + + if ( !IsAlive( target ) ) + return false + + if ( target.IsInvulnerable() ) + return false + + if ( !CanBeMeleed( target ) ) + return false + + if ( target.IsNPC() && !target.CanBeMeleeExecuted() ) + return false + + // Disallow executing someone that is already in execution. That road leads to script errors and asserts. + if ( target.ContextAction_IsMeleeExecution() ) + return false + + if ( attacker.IsTitan() && target.IsTitan() ) + { + // no melee execute for berserker + if ( PlayerHasPassive( attacker, ePassives.PAS_BERSERKER ) ) + return false + + if ( PlayerHasPassive( attacker, ePassives.PAS_SHIFT_CORE ) ) + return false + + if ( HasSoul( target ) && target.GetTitanSoul().IsEjecting() ) + return false + + if ( attacker.ContextAction_IsActive() ) + return false + + if ( target.ContextAction_IsActive() ) + return false + + if ( GetCurrentPlaylistVarInt( "vortex_blocks_melee", 0 ) == 1 ) + { + vector traceStartPos = attacker.EyePosition() + vector traceEndPos = target.EyePosition() + VortexBulletHit ornull vortexHit = VortexBulletHitCheck( attacker, traceStartPos, traceEndPos ) + if ( vortexHit != null ) + { + return false + } + } + } + + if ( !CheckVerticallyCloseEnough( attacker, target ) ) + return false + + //No necksnaps while wall running or mantling + if ( attacker.IsWallRunning() ) + return false + + if ( attacker.IsTraversing() ) + return false + + if ( target.IsPlayer() ) //Disallow execution on a bunch of player-only actions + { + + if ( target.IsHuman() ) + { + if ( target.IsWallRunning() ) + return false + + if ( target.IsTraversing() ) + return false + + if ( !target.IsOnGround() ) //disallow mid-air necksnaps. Can't really do that for Titan executions since dash puts them in mid air... will have visual glitches unfortunately. + return false + + if ( target.IsCrouched() ) + return false + + if ( Rodeo_IsAttached( target ) ) + return false + } + } + + if ( target.IsPhaseShifted() ) + return false + + //Disallow executions on contextActions marked Busy. Note that this allows + //execution on melee and leeching context actions! + if ( target.ContextAction_IsBusy() ) + return false + + if ( target.IsNPC() ) //NPC only checks + { + if ( target.ContextAction_IsActive() ) + return false + + if ( !target.IsInterruptable() ) + return false + } + + if ( attacker.GetTeam() == target.GetTeam() ) + return false + +#if SERVER + if ( "syncedMeleeAttacker" in target.s ) //Don't allow necksnap on a guy who'se already getting necksnapped + return false +#endif // #if SERVER + + SyncedMeleeChooser ornull actions = GetSyncedMeleeChooserForPlayerVsTarget( attacker, target ) + if ( actions == null ) + return false + expect SyncedMeleeChooser( actions ) + + SyncedMelee ornull action = FindBestSyncedMelee( attacker, target, actions ) + if ( action == null ) + return false + + if ( !PlayerMelee_IsExecutionReachable( attacker, target, 0.3 ) ) + return false + + return true +} + +bool function CodeCallback_IsValidMeleeAttackTarget( entity attacker, entity target ) +{ + if ( attacker == target ) + return false + + if ( target.IsBreakableGlass() ) + return true + + if ( !CanBeMeleed( target ) ) + return false + + if ( attacker.GetTeam() == target.GetTeam() ) + return false + +#if SERVER + if ( target.IsPlayer() ) + { + //Make titans not able to melee the pilot who is doing the embark animation + if ( GetTitanBeingRodeoed( target ) == attacker ) + return false + } +#endif // #if SERVER + + if ( target.IsPhaseShifted() ) + return false + + if ( target.GetParent() == attacker ) + return false + + #if SERVER //Awkward, needed because it's CBaseCombatCharacter on server and C_BaseCombatCharacter on client, and because we allow melee on non BaseCombatCharacters like props that don't have ContextActions defined + if ( target instanceof CBaseCombatCharacter && target.ContextAction_IsMeleeExecutionTarget() ) //Don't lunge towards a victim that is already being executed ) + return false + #elseif CLIENT + if ( target instanceof C_BaseCombatCharacter && target.ContextAction_IsMeleeExecutionTarget() ) //Don't lunge towards a victim that is already being executed ) + return false + #endif + + entity meleeWeapon = attacker.GetMeleeWeapon() + if ( !IsValid( meleeWeapon ) ) + return false; + + if ( !meleeWeapon.GetMeleeCanHitHumanSized() && IsHumanSized( target ) ) + return false; + if ( !meleeWeapon.GetMeleeCanHitTitans() && target.IsTitan() ) + return false; + + return true +} + +void function CodeCallback_OnMeleePressed( entity player ) +{ +#if SERVER + print( "SERVER: " + player + " pressed melee\n" ) +#else + print( "CLIENT: " + player + " pressed melee\n" ) +#endif + + if ( !Melee_IsAllowed( player ) ) + { +#if SERVER + print( "SERVER: Melee_IsAllowed() for " + player + " is false\n" ) +#else + print( "CLIENT: Melee_IsAllowed() for " + player + " is false\n" ) +#endif + return + } + +#if SERVER + if ( svGlobal.cloakBreaksOnMelee && IsCloaked( player ) ) + player.SetCloakFlicker( 1.0, 2.0 ) +#endif // #if SERVER + + if ( player.IsWeaponDisabled() ) + { +#if SERVER + print( "SERVER: IsWeaponDisabled() for " + player + " is true\n" ) +#else + print( "CLIENT: IsWeaponDisabled() for " + player + " is true\n" ) +#endif + return + } + + if ( player.PlayerMelee_GetState() != PLAYER_MELEE_STATE_NONE ) + { +#if SERVER + print( "SERVER: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" ) +#else + print( "CLIENT: PlayerMelee_GetState() for " + player + " is " + player.PlayerMelee_GetState() + "\n" ) +#endif + return + } + + if ( !IsAlive( player ) ) + { +#if SERVER + print( "SERVER: " + player + " is dead\n" ) +#else + print( "CLIENT: " + player + " is dead\n" ) +#endif + return + } + + thread CodeCallback_OnMeleePressed_InternalThread( player ) +} + +void function CodeCallback_OnMeleePressed_InternalThread( entity player ) +{ + if ( player.IsTitan() ) + { + TitanUnsyncedMelee( player ) + } + else if ( player.IsHuman() ) + { + const float STUN_EFFECT_CUTOFF = 0.05 + float movestunEffect = StatusEffect_Get( player, eStatusEffect.move_slow ) + bool movestunBlocked = (movestunEffect > STUN_EFFECT_CUTOFF) + + HumanUnsyncedMelee( player, movestunBlocked ) + } +} + +//void function CodeCallback_OnMeleeHeld( entity player ) +//{ +//} + +//void function CodeCallback_OnMeleeReleased( entity player ) +//{ +//} + +bool function ShouldHolsterWeaponForSyncedMelee( entity player ) +{ + if ( player.GetPlayerSettings() == "titan_ogre_minigun" ) + return false + + return ShouldHolsterWeaponForMelee( player ) +} + +bool function ShouldHolsterWeaponForMelee( entity player ) +{ + #if !SERVER + return true + #endif + + if ( !player.IsTitan() ) + return true + + return Time() - player.s.startDashMeleeTime > 1.0 //Fix issue with gun being out when it shouldn't, according to Mackey... +} + +#if SERVER +bool function NPCTriesSyncedMeleeVsPlayer( entity npc, entity player ) +{ + Assert( npc.IsNPC() ) + Assert( player.IsPlayer() ) + Assert( IsAlive( player ) ) + Assert( player.IsPlayer() ) + Assert( IsPilot( player ) ) + if ( player.ContextAction_IsBusy() ) + return false + + //#if SERVER + //player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION ) + //#else + //player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED ) + //#endif + + return DoSyncedMelee( npc, player ) +} +#endif + + + +bool function PlayerTriesSyncedMelee( entity player, entity target ) +{ + if ( !target ) + return false + if ( !IsAlive( target ) ) + return false + + if ( target.ContextAction_IsBusy() ) + return false + + if ( player.IsTitan() ) + { +#if SERVER + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION ) +#else + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED ) +#endif + } + else + { +#if SERVER + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION ) +#else + player.PlayerMelee_SetState( PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED ) +#endif + } + + if ( !player.Lunge_IsActive() || !player.Lunge_IsGroundExecute() || !player.Lunge_IsLungingToEntity() || (player.Lunge_GetTargetEntity() != target) ) + { +#if SERVER + print( "SERVER: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" ) +#else + print( "CLIENT: " + player + " is calling Lunge_SetTargetEntity() from PlayerTriesSyncedMelee()\n" ) +#endif + player.Lunge_SetTargetEntity( target, false ) + } + +#if SERVER + OnThreadEnd( + function() : ( player, target ) + { + if ( IsValid( player ) && player.IsPlayer() ) + { + RemoveCinematicFlag( player, CE_FLAG_TITAN_3P_CAM ) + RemoveCinematicFlag( player, CE_FLAG_EXECUTION ) + } + if ( IsValid( target ) && target.IsPlayer() ) + { + RemoveCinematicFlag( target, CE_FLAG_TITAN_3P_CAM ) + RemoveCinematicFlag( target, CE_FLAG_EXECUTION ) + } + } + ) + + if ( player.IsTitan() ) + TransferDamageHistoryToTarget( target ) + if ( player.IsPlayer() ) + { + AddCinematicFlag( player, CE_FLAG_TITAN_3P_CAM ) + AddCinematicFlag( player, CE_FLAG_EXECUTION ) + } + if ( IsValid( target ) && target.IsPlayer() ) + { + AddCinematicFlag( target, CE_FLAG_TITAN_3P_CAM ) + AddCinematicFlag( player, CE_FLAG_EXECUTION ) + } +#endif + + bool success = DoSyncedMelee( player, target ) + if ( !success ) + { + player.Lunge_ClearTarget() + } + + return success +} + +function TransferDamageHistoryToTarget( entity target ) +{ + entity titanSoul = target.GetTitanSoul() + target.e.recentDamageHistory = titanSoul.e.recentDamageHistory +} + +bool function DoSyncedMelee( entity player, entity target ) +{ + SyncedMeleeChooser ornull actions = GetSyncedMeleeChooserForPlayerVsTarget( player, target ) + + Assert( actions != null, "No melee action for " + player + " vs " + target ) + expect SyncedMeleeChooser( actions ) + +#if SERVER + if ( player.IsPlayer() ) + { + PlayerMelee_StartLagCompensateTargetForLunge( player, target ) + } +#endif // #if SERVER + + SyncedMelee ornull action = FindBestSyncedMelee( player, target, actions ) + +#if SERVER + if ( player.IsPlayer() ) + { + + player.ForceStand() + player.UnforceStand() + PlayerMelee_FinishLagCompensateTarget( player ) + } +#endif // #if SERVER + + if ( action == null ) + return false + + expect SyncedMelee( action ) + + + + player.Signal( "OnSyncedMelee" ) + target.Signal( "OnSyncedMelee" ) + player.Signal( "OnSyncedMeleeAttacker" ) + target.Signal( "OnSyncedMeleeVictim" ) + +#if SERVER + player.p.lastExecutionUsed = action.ref + + if ( actions in file.syncedMeleeServerCallbacks ) + thread SyncedMeleeServerCallbacks( actions, action, player, target ) + bool functionref( SyncedMelee action, entity player, entity target ) think = file.syncedMeleeServerThink[ actions ] + return think( action, player, target ) +#endif // #if SERVER + + return true +} + +void function SyncedMeleeServerCallbacks( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target ) +{ + // Added via AddSyncedMeleeServerCallback + foreach ( index, _ in file.syncedMeleeServerCallbacks[ actions ] ) + { + void functionref( SyncedMeleeChooser actions, SyncedMelee action, entity player, entity target ) item = file.syncedMeleeServerCallbacks[ actions ][ index ] + item( actions, action, player, target ) + } +} + +/* +void function CodeCallback_OnMeleeReleased( entity player ) +{ +} +*/ + +function TextDebug( string msg ) +{ + wait 0.5 + printt( msg ) +} + +bool function ShouldClampTargetVelocity( vector targetVelocity, vector pushBackVelocity, float clampRatio ) +{ + float dot = DotProduct( targetVelocity, pushBackVelocity ) + if ( dot < 0 ) + return true + + if ( dot <= 0 ) + return false + + float velRatio = LengthSqr( targetVelocity ) / LengthSqr( pushBackVelocity ) + + return velRatio < clampRatio +} + +bool function CanBeMeleed( entity target ) +{ + if ( target.IsPlayer() ) + return true + if ( target.IsNPC() ) + return true + + if ( ObjectCanBeMeleed( target ) ) + return true + + return false +} + +// IMPORTANT: Only used for non-player, non-living special cases like prop_dynamics we want to be able to melee (drones, etc) +bool function ObjectCanBeMeleed( entity ent ) +{ + if ( !( "canBeMeleed" in ent.s ) ) + return false + + return expect bool( ent.s.canBeMeleed ) +} + +// IMPORTANT: Only used for non-player, non-living special cases like prop_dynamics we want to be able to melee (drones, etc) +function SetObjectCanBeMeleed( entity ent, bool value ) +{ + Assert( !ent.IsPlayer(), ent + " should not be a player. This is for non-player, non-NPC entities.") + Assert( !ent.IsNPC(), ent + " should not be an NPC. This is for non-player, non-NPC entities.") + + if ( !( "canBeMeleed" in ent.s ) ) + ent.s.canBeMeleed <- false + + ent.s.canBeMeleed = value +} + +//function TitanExposionDeath( entity titan, entity attacker ) +//{ +// if ( !IsAlive( titan ) ) +// return +// +// ExplodeTitanBits( titan ) +// // and your pretty titan too! +// +// //TitanEjectExplosion +// table deathTable = { scriptType = damageTypes.titanMelee, forceKill = true, damageType = DMG_MELEE_EXECUTION, damageSourceId = eDamageSourceId.titan_execution } +// titan.TakeDamage( titan.GetMaxHealth() + 1, attacker, attacker, deathTable ) +//} + +#if SERVER +vector function GetRefAnglesBetweenEnts( entity attacker, entity target ) +{ + vector endOrigin = target.GetOrigin() + vector startOrigin = attacker.GetOrigin() + vector refVec = endOrigin - startOrigin + vector refAng = VectorToAngles( refVec ) + if ( fabs( AngleNormalize( refAng.x ) ) > 35 ) //If pitch is too much, use angles from either attacker or target + { + if ( attacker.IsTitan() ) + refAng = attacker.GetAngles() //Doing titan synced kill from front, so use attacker's origin + else + refAng = target.GetAngles() // Doing rear necksnap, so use target's angles + } + return refAng +} + +entity function CreateMeleeScriptMoverBetweenEnts( entity attacker, entity target ) +{ + vector refAng = GetRefAnglesBetweenEnts( attacker, target ) + + vector endOrigin = target.GetOrigin() + vector startOrigin = attacker.GetOrigin() + vector refVec = endOrigin - startOrigin + vector refPos = endOrigin - refVec * 0.5 + + entity ref = CreateOwnedScriptMover( attacker ) + ref.SetOrigin( refPos ) + ref.SetAngles( refAng ) + + return ref +} +#endif // SERVER + +void function AddSyncedMelee( SyncedMeleeChooser chooser, SyncedMelee melee ) +{ + // sqr the distance + melee.distanceSqr = melee.distance * melee.distance + + chooser.syncedMelees.append( melee ) +} + +SyncedMelee ornull function FindBestSyncedMelee( entity attacker, entity target, SyncedMeleeChooser actions ) +{ + #if CLIENT + Assert( attacker == GetLocalViewPlayer() ) + #endif // CLIENT + + vector absTargetToPlayerDir + if ( attacker.IsPlayer() && attacker.Lunge_IsActive() && (attacker.Lunge_GetTargetEntity() == target) ) + { + absTargetToPlayerDir = attacker.Lunge_GetStartPositionOffset() + absTargetToPlayerDir = Normalize( absTargetToPlayerDir ) + } + else + { + vector attackerPos = actions.attackerOriginFunc( attacker ) // + ( attacker.GetVelocity() * SMOOTH_TIME ) + vector targetPos = actions.targetOriginFunc( target ) + + if ( attackerPos == targetPos ) + { + absTargetToPlayerDir = < 1, 0, 0 > + } + else + { + absTargetToPlayerDir = Normalize( attackerPos - targetPos ) + } + } + + vector angles = attacker.EyeAngles() + vector forward = AnglesToForward( angles ) + + vector relTargetToPlayerDir = CalcRelativeVector( < 0, target.EyeAngles().y, 0 >, absTargetToPlayerDir ) + + array bestActions + float bestDot = -2.0 + float distSqr = LengthSqr( actions.attackerOriginFunc( attacker ) - actions.targetOriginFunc( target ) ) + + bool npcTarget = target.IsNPC() + bool playerAttacker = attacker.IsPlayer() + + int health = target.GetHealth() + float healthRatio = HealthRatio( target ) + int meleeDamage + if ( attacker.IsNPC() ) + { + meleeDamage = attacker.GetMeleeDamageMaxForTarget( target ) + } + else if ( attacker.IsPlayer() ) + { + meleeDamage = GetPlayerMeleeDamage( attacker ) + } + + SyncedMelee ornull returnVal = null + +#if MP + if ( IsPilot( attacker ) ) + { + PilotLoadoutDef loadout = GetActivePilotLoadout( attacker ) + + foreach ( action in actions.syncedMelees ) + { + if ( action.ref != loadout.execution ) + continue + + if ( npcTarget && !action.canTargetNPCs ) + break + + if ( playerAttacker && !action.usableByPlayers ) + break + + if ( healthRatio < action.targetMinHealthRatio ) + break + + if ( healthRatio > action.targetMaxHealthRatio ) + break + + if ( action.onlyIfLethal && health > meleeDamage ) + break + + if ( distSqr > action.distanceSqr ) + break + + float dot = relTargetToPlayerDir.Dot( action.direction ) + if ( dot < action.minDot ) + break + +#if SERVER + //Random Execution + if ( string( attacker.GetPersistentVar( "activePilotLoadout.execution" )) == "execution_random") + { + returnVal = PickRandomExecution(actions, attacker) + break + } +#endif + + returnVal = action + break + } + } + else + { +#endif + foreach ( action in actions.syncedMelees ) + { + if ( !action.enabled ) + continue + + if ( npcTarget && !action.canTargetNPCs ) + continue + + if ( playerAttacker && !action.usableByPlayers ) + continue + + if ( healthRatio < action.targetMinHealthRatio ) + continue + + if ( healthRatio > action.targetMaxHealthRatio ) + continue + + if ( action.onlyIfLethal && health > meleeDamage ) + continue + + if ( distSqr > action.distanceSqr ) + continue + + float dot = relTargetToPlayerDir.Dot( action.direction ) + + //printt( "Dot: " + dot ) + + if ( dot < action.minDot ) + continue + + if ( dot == bestDot ) + { + bestActions.append( action ) + continue + } + + if ( dot > bestDot ) + { + // found new best dot + bestActions.clear() + bestDot = dot + bestActions.append( action ) + } + } + + if ( bestActions.len() ) + returnVal = bestActions.getrandom() +#if MP + } +#endif + + return returnVal +} + +string function GetAttackerSyncedMelee( entity ent ) +{ + if ( ent.IsPlayer() ) + { + // TODO: for MP, change this to be based on loadout choice + string bodyType = GetPlayerBodyType( ent ) + if ( bodyType == "human" ) + { + entity weapon = ent.GetActiveWeapon() + var weaponSyncedMelee + + if ( IsValid( weapon ) ) + weaponSyncedMelee = weapon.GetWeaponInfoFileKeyField( "synced_melee_action" ) + + if ( weaponSyncedMelee ) + return string( weaponSyncedMelee ) + } + + return bodyType + + } + else if ( IsProwler( ent ) ) + { + return "prowler" + } + else if ( IsPilotElite( ent ) ) + { + return "pilotelite" + } + else if ( IsSpectre( ent ) ) + { + return "spectre" + } + else if ( ent.IsNPC() ) + { + return ent.GetBodyType() + } + else if ( ent.IsTitan() ) + { + return "titan" + } + + unreachable +} + +string function GetVictimSyncedMeleeTargetType( entity ent ) +{ + string targetType + + if ( ent.IsPlayer() && GetPlayerBodyType( ent ) == "human" ) + { + targetType = "human" + } + else if ( IsProwler( ent ) ) + { + targetType = "prowler" + } + else if ( IsPilotElite( ent ) ) + { + targetType = "pilotelite" + } + else if ( ent.IsNPC() ) + { + targetType = ent.GetBodyType() + } + else if ( ent.IsTitan() ) + { + targetType = "titan" + } + else + { + Assert( 0, "Unknown ent type" ) + } + + return targetType +} + +SyncedMeleeChooser ornull function GetSyncedMeleeChooserForPlayerVsTarget( entity attacker, entity target ) +{ + string attackerType = GetAttackerSyncedMelee( attacker ) + string targetType = GetVictimSyncedMeleeTargetType( target ) + + if ( !( attackerType in file.syncedMeleeChoosers ) ) + return null + + if ( !( targetType in file.syncedMeleeChoosers[ attackerType ] ) ) + return null + + return file.syncedMeleeChoosers[ attackerType ][ targetType ] +} + +void function CodeCallback_OnMeleeAttackAnimEvent( entity player ) +{ + Assert( IsValid( player ) ) +#if SERVER + print( "SERVER: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" ) +#else + print( "CLIENT: " + player + " is calling CodeCallback_OnMeleeAttackAnimEvent()\n" ) +#endif + if ( player.PlayerMelee_IsAttackActive() ) + { + if ( player.IsTitan() ) + TitanMeleeAttack( player ) + else if ( player.IsHuman() ) + HumanMeleeAttack( player ) + } +} + +bool function IsInExecutionMeleeState( entity player ) +{ + local meleeState = player.PlayerMelee_GetState() + switch ( meleeState ) + { + case PLAYER_MELEE_STATE_HUMAN_EXECUTION_PREDICTED: + case PLAYER_MELEE_STATE_HUMAN_EXECUTION: + case PLAYER_MELEE_STATE_TITAN_EXECUTION_PREDICTED: + case PLAYER_MELEE_STATE_TITAN_EXECUTION: + return true + + default: + return false + } + + unreachable +} + +#if SERVER +void function InitMeleeAnimEventCallbacks( entity player ) +{ + AddAnimEvent( player, "screen_blackout", MeleeBlackoutScreen_AE ) +} + +void function MeleeBlackoutScreen_AE( entity player ) +{ + ScreenFadeToBlack( player, 0.7, 1.2 ) +} +#endif + +bool function ShouldPlayerExecuteTarget( entity player, entity target ) +{ + if ( player.IsTitan() ) + { + if ( !target.IsTitan() ) + return false + + if ( Flag( "ForceSyncedMelee" ) ) + return true + + if ( !GetDoomedState( target ) ) + return false + + entity soul = target.GetTitanSoul() + if ( soul != null ) + { + if ( soul.GetShieldHealth() > 0 && GetCurrentPlaylistVarInt( "titan_shield_blocks_execution", 0 ) != 0 ) + return false + } + + if ( !SyncedMelee_IsAllowed( player ) ) + return false + + return true + } + + if ( player.IsHuman() ) + { + if ( !IsHumanSized( target ) ) + return false + +#if SERVER + if ( Flag( "ForceSyncedMelee" ) ) + return true +#endif // #if SERVER + + if ( !SyncedMelee_IsAllowed( player ) ) + return false + } + + return true +} + +vector function ClampVerticalVelocity( vector targetVelocity, float maxVerticalVelocity ) +{ + vector clampedVelocity = targetVelocity + if ( clampedVelocity.z > maxVerticalVelocity ) + { + printt( "clampedVelocity.z: " + clampedVelocity.z +", maxVerticalVelocity:" + maxVerticalVelocity ) + clampedVelocity = Vector( targetVelocity.x, targetVelocity.y, maxVerticalVelocity ) + } + + return clampedVelocity +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool function CheckVerticallyCloseEnough( entity attacker, entity target ) +{ + vector attackerOrigin = attacker.GetOrigin() + vector targetOrigin = target.GetOrigin() + + float verticalDistance = fabs( attackerOrigin.z - targetOrigin.z ) + float halfHeight = 0 + + if ( attacker.IsTitan() ) + halfHeight = 92.5 + else if ( attacker.IsHuman() ) + halfHeight = 30 + + Assert( halfHeight, "Attacker is neither Titan nor Human" ) + + //printt( "vertical distance: " + verticalDistance ) + return verticalDistance < halfHeight +} + + +entity function GetLungeTargetForPlayer( entity player ) +{ + // Titan melee does not lunge + if ( player.IsTitan() ) + return null + + if ( player.IsPhaseShifted() ) + return null + + entity lungeTarget = PlayerMelee_LungeConeTrace( player, SHARED_CB_IS_VALID_MELEE_ATTACK_TARGET ) + return lungeTarget +} + +#if SERVER +void function Melee_Enable( entity player ) +{ + player.SetPlayerNetBool( "playerAllowedToMelee", true ) +} + +void function Melee_Disable( entity player ) +{ + player.SetPlayerNetBool( "playerAllowedToMelee", false ) +} + +void function SyncedMelee_Enable( entity player ) +{ + player.SetPlayerNetBool( "playerAllowedToSyncedMelee", true ) +} + +void function SyncedMelee_Disable( entity player ) +{ + player.SetPlayerNetBool( "playerAllowedToSyncedMelee", false ) +} +#endif + +bool function Melee_IsAllowed( entity player ) +{ + return player.GetPlayerNetBool( "playerAllowedToMelee" ) +} + +bool function SyncedMelee_IsAllowed( entity player ) +{ + return player.GetPlayerNetBool( "playerAllowedToSyncedMelee" ) +} + +bool function IsAttackerRef( SyncedMelee ornull action, entity target ) +{ + if ( action != null ) + { + expect SyncedMelee( action ) + if ( action.isAttackerRef ) + { + return true + } + } + + if ( !target ) + return true + + if ( !IsValid( target ) ) + return true + + if ( !target.IsPlayer() ) + return true + + return false +} + +#if MP +#if SERVER +SyncedMelee ornull function PickRandomExecution( SyncedMeleeChooser actions, entity attacker ) +{ + array possibleExecutions = [] + + SyncedMelee neckSnap + + foreach ( action in actions.syncedMelees ) + { + if (action.ref == "execution_neck_snap") + neckSnap = action + + if(!IsItemLocked( attacker, action.ref ) && action.ref != "execution_random" && action.ref != attacker.p.lastExecutionUsed) + + possibleExecutions.append(action) + } + + if (possibleExecutions.len() == 0) + return neckSnap + + possibleExecutions.randomize() + + return possibleExecutions[0] +} +#endif +#endif \ No newline at end of file -- cgit v1.2.3 From 68e34153fb72328d549aa362ff40dac467ce8f39 Mon Sep 17 00:00:00 2001 From: Neoministein <57015772+Neoministein@users.noreply.github.com> Date: Sat, 24 Jun 2023 00:42:12 +0200 Subject: Add ability to disable executions via a Callback (#633) --- .../mod/scripts/vscripts/melee/sh_melee.gnut | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut index dfd957e1..95ab3915 100644 --- a/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/melee/sh_melee.gnut @@ -27,6 +27,7 @@ global function IsInExecutionMeleeState global function GetLungeTargetForPlayer global function Melee_IsAllowed global function IsAttackerRef +global function AddCallback_IsValidMeleeExecutionTarget #if SERVER global function Melee_Enable @@ -88,7 +89,7 @@ struct table > syncedMeleeChoosers table > syncedMeleeServerCallbacks table syncedMeleeServerThink - + array isValidMeleeExecutionTargetCallBacks string lastExecutionUsed = "" } file @@ -183,6 +184,11 @@ vector function GetEyeOrigin( entity ent ) return ent.EyePosition() } +void function AddCallback_IsValidMeleeExecutionTarget( bool functionref( entity attacker, entity target ) callbackFunc ) +{ + file.isValidMeleeExecutionTargetCallBacks.append( callbackFunc ) +} + //Called after pressing the melee button to recheck for targets bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity target ) { @@ -310,6 +316,14 @@ bool function CodeCallback_IsValidMeleeExecutionTarget( entity attacker, entity if ( !PlayerMelee_IsExecutionReachable( attacker, target, 0.3 ) ) return false + foreach ( callbackFunc in file.isValidMeleeExecutionTargetCallBacks ) + { + if ( !callbackFunc( attacker, target ) ) + { + return false + } + } + return true } -- cgit v1.2.3 From fd5680a6ba02896ce30a88e0f683fa3f4b1e0c5a Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 24 Jun 2023 00:51:46 +0200 Subject: Translations update from Weblate (#646) * Translated using Weblate (German) Currently translated at 89.4% (246 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ * Translated using Weblate (Italian) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/it/ * Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/zh_Hant/ * Translated using Weblate (Russian) Currently translated at 74.5% (205 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ --------- Co-authored-by: GeckoEidechse Co-authored-by: CloudSE7EN Co-authored-by: SamZong Co-authored-by: Andrew --- .../northstar_client_localisation_german.txt | 1 + .../northstar_client_localisation_italian.txt | 65 ++++++++++++++++---- .../northstar_client_localisation_russian.txt | 6 ++ .../northstar_client_localisation_tchinese.txt | 71 ++++++++++++++-------- 4 files changed, 107 insertions(+), 36 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index 0316bbcf..f5c814f5 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -310,5 +310,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "INVALID_MASTERSERVER_TOKEN" "Ungültiger oder abgelaufener Token vom Masterserver" "JSON_PARSE_ERROR" "Fehler beim Verarbeiten der JSON-Antwort" "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" + "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt index fa84b6a2..38e67dea 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_italian.txt @@ -84,8 +84,8 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Sandbox" - "PL_sbox_lobby" "Sandbox Lobby" - "PL_sbox_desc" "Come gmod ma peggio." + "PL_sbox_lobby" "Lobby: Sandbox" + "PL_sbox_desc" "Come gmod ma peggio" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" @@ -170,7 +170,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "PL_hs_abbr" "NS" "GAMEMODE_hs" "Nascondino" "HIDEANDSEEK_YOU_ARE_SEEKER" "TROVA I GIOCATORI NASCOSTI" - "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi." + "HIDEANDSEEK_SEEKER_DESC" "Trova ed uccidi tutti i giocatori nascosti. \nRespawnerai in %s1 secondi" "HIDEANDSEEK_YOU_ARE_HIDER" "NASCONDITI" "HIDEANDSEEK_HIDER_DESC" "Nasconditi e cerca di non farti trovare." "HIDEANDSEEK_SEEKERS_INCOMING" "HANNO INIZIATO A CERCARTI" @@ -178,14 +178,14 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "HIDEANDSEEK_GET_LAST_HIDER" "%s1 è L'ULTIMO CERCATORE" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "SEI L'ULTIMO NASCOSTO" "HIDEANDSEEK_GOT_STIM" "Sei stimolato! Non farti prendere!" - "hideandseek_balance_teams" "Bilanciamento Squadre..." + "hideandseek_balance_teams" "Bilanciamento Squadre" "hideandseek_hiding_time" "Tempo per Nascondersi" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development "GAMEMODE_fw" "Guerra di Frontiera" "PL_fw" "Guerra di Frontiera" "PL_fw_lobby" "Lobby: Guerra di Frontiera" - "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo." + "PL_fw_desc" "Distruggi il mietiore nemico e proteggi il tuo" "PL_fw_abbr" "FW" "GAMEMODE_kr" "Killrace Amplificata" @@ -198,10 +198,10 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "KR_NEW_RACER" "%s1 è il killracer amplificato" "KR_YOU_ARE_NEW_RACER" "Sei il killracer amplificato" "KR_YOU_SET_NEW_RECORD" "Stabilisci un nuovo record di uccisioni!" - "KR_FLAG_INCOMING" "Bandiera in Arrivo!" + "KR_FLAG_INCOMING" "Bandiera in Arrivo" "KR_COLLECT_FLAG" "Raccoglila per diventare il killracer!" - "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita." - "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita." + "KR_ENEMY_KILLRACE_OVER" "La killrace di %s1 è finita" + "KR_YOUR_KILLRACE_OVER" "La tua killrace è finita" "KR_YOUR_KILLRACE_SCORE" "Hai ottenuto %s1 uccisioni." "GAMEMODE_fastball" "Fastball" @@ -222,7 +222,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "custom_air_accel_pilot" "Accelerazione Aerea" "no_pilot_collision" "Collisione tra Piloti" "promode_enable" "Armi Modalità Competitiva" - "fp_embark_enabled" "Imbarchi/esecuzioni in 1ºpers." + "fp_embark_enabled" "Imbarchi/esecuzioni in 1º persona" "classic_rodeo" "Rodeo classico" "oob_timer_enabled" "Timer Fuori dai Limiti" "riff_instagib" "Modalità Instagib" @@ -262,7 +262,7 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SP_BEACON_CLASSIC_DESC" "Cooper e BT tentano di informare la flotta rimanente dei piani dell'IMC." "SP_TDAY" "Prova del fuoco" - "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca." + "SP_TDAY_CLASSIC_DESC" "Le abilità del Titan di Cooper vengono messe alla prova in una battaglia senza quartiere per la cattura dell'Arca" "SP_S2S" "L'Arca" "SP_S2S_CLASSIC_DESC" "Cooper e BT inseguono l'Arca affrontando una nave dopo l'altra." @@ -333,9 +333,52 @@ Premi Sì se sei d'accordo. Questa scelta può essere modificata in qualsiasi mo "SHOULD_RETURN_TO_LOBBY" "Ritorna alla Lobby dopo Fine Partita" "ARE_YOU_SURE" "Sei sicuro?" "WILL_RESET_ALL_SETTINGS" "Questo ripristinerà TUTTE le impostazioni che appartengono a questa categoria.\n\nNON può essere annullato." - "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON può essere annullato" // obviously, don't translate %s1. + "WILL_RESET_SETTING" "Questo ripristinerà l'impostazione %s1 al suo valore predefinito.\n\nNON è reversibile." // obviously, don't translate %s1. "MOD_SETTINGS_SERVER" "Server" "MOD_SETTINGS_RESET" "Ripristina" "MOD_SETTINGS_RESET_ALL" "Ripristina Tutto" + "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" + "NO_RESULTS" "Nessun Risultato." + "DISABLE" "Disattiva" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticazione al master server." + "NS_SERVERBROWSER_UNKNOWNMODE" "Modalità sconosciuta" + "respawnprotection" "Tempo di protezione al respawn" + "NO_MODS" "Nessuna impostazione disponibile! Installa più mods a ^5588FF00northstar.thunderstore.io^0." + "gg_assist_reward" "Percentuale ricompensa per assist" + "gg_execution_reward" "Percentuale ricompensa per esecuzione" + "PL_sns" "Sticks and Stones" + "PL_sns_lobby" "Lobby: Sticks and Stones" + "PL_sns_abbr" "SNS" + "GAMEMODE_SNS" "Sticks and Stones" + "SCOREBOARD_BANKRUPTS" "Uccisioni bancarotta" + "SNS_LEADER_BANKRUPT" "Leader punteggio in bancarotta!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 è stato resettato da %s2" + "SNS_BANKRUPT" "Bancarotta!" + "sns_softball_kill_value" "Valore per uccisione Softball" + "sns_offhand_kill_value" "Valore per uccisione manuale" + "sns_melee_kill_value" "Valore per uccisione corpo a corpo" + "sns_softball_enabled" "Softball abilitato" + "PL_tffa" "Tutti contro tutti Titan" + "PL_tffa_lobby" "Lobby: Tutti contro tutti Titan" + "PL_tffa_hint" "Ogni pilota per sè, distruggi tutti i titan nemici." + "PL_tffa_abbr" "TFFA" + "GAMEMODE_TFFA" "Tutti contro tutti Titan" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Cooldown reset all'uccisione" + "SHOW" "Mostra" + "SHOW_ALL" "Tutto" + "SHOW_ONLY_ENABLED" "Solo Abilitate" + "SHOW_ONLY_DISABLED" "Solo Disabilitate" + "SHOW_ONLY_NOT_REQUIRED" "Solo Mods opzionali" + "SHOW_ONLY_REQUIRED" "Solo Mods richieste" + "WARNING" "Attenzione" + "CORE_MOD_DISABLE_WARNING" "Disattivare mods di base può rompere il client!" + "AUTHENTICATIONAGREEMENT_NO" "Hai scelto di non autenticarti con Northstar. Puoi vedere l'accordo nel menu delle Mods." + "aitdm_archer_grunts" "Soldati Archer" + "gg_kill_reward" "Percentuale ricompensa per uccisione" + "PL_sns_desc" "Tutti contro tutti. Usa la Lama Impulsi e l'esecuzione per resettare il punteggio avversario" + "SNS_BANKRUPT_SUB" "Il you punteggio è stato resettato da %s1" + "sns_wme_kill_value" "Valore per uccisione Wingman d'Elite" + "sns_reset_kill_value" "Valore per uccisione Lama Impulsi/Esecuzione" + "PL_tffa_desc" "Ogni pilota per sè, distruggi tutti i titan nemici." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 9ce0c2e3..fe7cf2b3 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -253,5 +253,11 @@ "INVALID_MASTERSERVER_TOKEN" "Срок действия жетона главного сервера истек или не является правильным" "JSON_PARSE_ERROR" "Ошибка разбора ответа json" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" + "DISABLE" "Выключить" + "DIALOG_AUTHENTICATING_MASTERSERVER" "Аутентификация на главном сервере." + "WARNING" "Предупреждение" + "CORE_MOD_DISABLE_WARNING" "Выключение главных модов может сломать ваш клиент!" + "AUTHENTICATIONAGREEMENT_NO" "Вы выбрали не аутентифицироваться с Northstar-ом. Вы можете посмотреть соглашение в меню модов." + "NS_SERVERBROWSER_UNKNOWNMODE" "Неизвестный режим" } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 12b6cad1..e543f711 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -127,7 +127,7 @@ "PL_sns" "冷兵器" "PL_sns_lobby" "冷兵器大廳" - "PL_sns_desc" "模擬十字弓和飛斧的作戰模式。使用脈衝刀及處決擊殺來重置敵人的分數。" + "PL_sns_desc" "无规则. 使用脈衝刀及處決擊殺來重置敵人的分數" "PL_sns_abbr" "SNS" "GAMEMODE_SNS" "冷兵器" "SCOREBOARD_BANKRUPTS" "破產次數" @@ -155,7 +155,7 @@ "INFECTION_LAST_SURVIVOR" "%s1是最後的倖存者!" "INFECTION_KILL_LAST_SURVIVOR" "在時間用盡前感染他!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "你是最後的倖存者!" - "INFECTION_SURVIVE_LAST_SURVIVOR" "倖存" + "INFECTION_SURVIVE_LAST_SURVIVOR" "最後幸存者." "PL_tffa" "泰坦混戰" "PL_tffa_lobby" "泰坦混戰大廳" @@ -238,38 +238,38 @@ "player_bleedout_aiBleedingPlayerMissChance" "倒地時AI的失誤率" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Singleplayer Coop Lobby" - "PL_sp_coop_desc" "Play through the singleplayer campaign with friends" - "PL_sp_coop_hint" "Play through the singleplayer campaign with friends" + "PL_sp_coop" "(未完成) 單人合作" + "PL_sp_coop_lobby" "單人合作模式大廳" + "PL_sp_coop_desc" "與朋友一起遊玩單人戰役" + "PL_sp_coop_hint" "與朋友一起遊玩單人戰役" "PL_sp_coop_abbr" "SP" - "SP_TRAINING" "The Pilot's Gauntlet" - "SP_TRAINING_CLASSIC_DESC" "Captain Lastimosa's training simulation." + "SP_TRAINING" "鐵御的試煉" + "SP_TRAINING_CLASSIC_DESC" "拉絲提莫沙上尉的模擬訓練." "SP_CRASHSITE" "BT-7274" - "SP_CRASHSITE_CLASSIC_DESC" "Jack Cooper meets BT-7274." + "SP_CRASHSITE_CLASSIC_DESC" "傑克庫博預見BT-7274." - "SP_SEWERS1" "Blood and Rust" - "SP_SEWERS1_CLASSIC_DESC" "Cooper and BT set out to rendezvous with Major Anderson." + "SP_SEWERS1" "鮮血與鐵鏽" + "SP_SEWERS1_CLASSIC_DESC" "庫博和BT一起出發前往與安德森上尉回合." - "SP_BOOMTOWN_START" "Into the Abyss" - "SP_BOOMTOWN_START_CLASSIC_DESC" "An underground shortcut yields unexpected consequences." + "SP_BOOMTOWN_START" "踏入虛空" + "SP_BOOMTOWN_START_CLASSIC_DESC" "一個地下捷徑造成了不可預見的後果." - "SP_HUB_TIMESHIFT" "Effect and Cause" - "SP_HUB_TIMESHIFT_CLASSIC_DESC" "A strange phenomenon is discovered at Major Anderson's coordinates." + "SP_HUB_TIMESHIFT" "因果報應" + "SP_HUB_TIMESHIFT_CLASSIC_DESC" "在安德森上尉的坐標處發現了奇異的現象." - "SP_BEACON" "The Beacon" - "SP_BEACON_CLASSIC_DESC" "Cooper and BT attempt to inform the remaining fleet of the IMC's plans." + "SP_BEACON" "信號台" + "SP_BEACON_CLASSIC_DESC" "庫博和BT嘗試將IMC的計劃通知給剩餘反抗軍艦隊." - "SP_TDAY" "Trial by Fire" - "SP_TDAY_CLASSIC_DESC" "Cooper's Titan skills are put to the test in an all-out battle to capture the Ark" + "SP_TDAY" "烈火審判" + "SP_TDAY_CLASSIC_DESC" "庫博驾馭泰坦的技術在爭奪聖櫃的全面戰爭中得到考驗" - "SP_S2S" "The Ark" - "SP_S2S_CLASSIC_DESC" "Cooper and BT go ship to ship in pursuit of the Ark." + "SP_S2S" "聖櫃" + "SP_S2S_CLASSIC_DESC" "庫博和BT在艦艇中穿梭追尋聖櫃." - "SP_SKYWAY_V1" "The Fold Weapon" - "SP_SKYWAY_V1_CLASSIC_DESC" "BT and Cooper are captured by Kuben Blisk." + "SP_SKYWAY_V1" "折疊時空武器" + "SP_SKYWAY_V1_CLASSIC_DESC" "BT和庫博被庫本布里斯克擒拿." // Better.Serverbrowser "SERVERS_COLUMN" "伺服器" @@ -310,8 +310,8 @@ "HUD_CHAT_SERVER_PREFIX" "[伺服器]" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" - "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "HUD_CHAT_WHISPER_PREFIX" "[悄悄話]" + "HUD_CHAT_SERVER_PREFIX" "[伺服器]" "NO_GAMESERVER_RESPONSE" "無法連接到遊戲伺服器'" "BAD_GAMESERVER_RESPONSE" "遊戲伺服器回應無效" @@ -323,5 +323,26 @@ "INVALID_MASTERSERVER_TOKEN" "主伺服器token過期或無效" "JSON_PARSE_ERROR" "讀取json回應時發生錯誤" "UNSUPPORTED_VERSION" "您的遊戲版本過低" + "NORTHSTAR_BASE_SETTINGS" "北极星基础设置" + "ONLY_HOST_CAN_START_MATCH" "只有服主可以開始對局" + "MATCH_COUNTDOWN_LENGTH" "私人對局倒計時時間" + "DISALLOWED_TACTICALS" "禁用的技能" + "TACTICAL_REPLACEMENT" "替換的技能" + "NO_RESULTS" "無結果." + "LOG_UNKNOWN_CLIENTCOMMANDS" "登記未知客戶端指令" + "SHOULD_RETURN_TO_LOBBY" "對局結束後返回大廳" + "ARE_YOU_SURE" "確定?" + "WILL_RESET_SETTING" "這將會重置 %s1 的設置為默認值.\n\n此操作不可復原." + "MOD_SETTINGS_SERVER" "服務器" + "MOD_SETTINGS_RESET" "重置" + "MOD_SETTINGS_RESET_ALL" "重置所有" + "SHOW_ONLY_NOT_REQUIRED" "僅展示非必需模組" + "SHOW_ONLY_REQUIRED" "僅展示必須模組" + "MOD_SETTINGS" "模组设置" + "ONLY_HOST_MATCH_SETTINGS" "只有服主可以修改私人對局設置" + "DISALLOWED_WEAPONS" "禁用的武器" + "REPLACEMENT_WEAPON" "替换的武器" + "WILL_RESET_ALL_SETTINGS" "這將會重置所有屬於改條目的設置.\n\n此操作不可復原." + "NO_MODS" "無可用模組! 前往 ^5588FF00northstar.thunderstore.io^0 下載更多." } } -- cgit v1.2.3 From 77ef26e748fa66e2b94a31889029c7b477dd6826 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:46:39 +0100 Subject: disable RequiredOnClient mods properly (#658) * disable RequiredOnClient mods properly * better disabling logic --- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 7ea8134a..c4046132 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1059,15 +1059,39 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged + bool modsChanged = false - // unload mods we don't need, load necessary ones and reload mods before connecting + // disable all RequiredOnClient mods that are not required by the server and are currently enabled + foreach ( string modName in NSGetModNames() ) + { + if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) + { + // find the mod name in the list of server required mods + bool found = false + foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) + { + if (mod.name == modName) + { + found = true + break + } + } + // if we didnt find the mod name, disable the mod + if (!found) + { + modsChanged = true + NSSetModEnabled( modName, false ) + } + } + } + + // enable all RequiredOnClient mods that are required by the server and are currently disabled foreach ( RequiredModInfo mod in file.lastSelectedServer.requiredMods ) { - if ( NSIsModRequiredOnClient( mod.name ) ) + if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name )) { - modsChanged = modsChanged || NSIsModEnabled( mod.name ) != file.lastSelectedServer.requiredMods.contains( mod ) - NSSetModEnabled( mod.name, file.lastSelectedServer.requiredMods.contains( mod ) ) + modsChanged = true + NSSetModEnabled( mod.name, true ) } } -- cgit v1.2.3 From af8f5cdfb05face11659f26ea79cf8b6139c544b Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Mon, 10 Jul 2023 03:24:54 +0800 Subject: [FW] Fix Scoreboard Sorting (#622) add missing GameMode_SetScoreCompareFunc() for fw --- .../mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut index d999bb4c..be93193d 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut @@ -69,6 +69,7 @@ void function CreateGamemodeFW() GameMode_AddClientInit( FORT_WAR, CLGamemodeFW_Init ) #endif #if !UI + GameMode_SetScoreCompareFunc( FORT_WAR, CompareAssaultScore ) GameMode_AddSharedInit( FORT_WAR, SHGamemodeFW_Init ) #endif } -- cgit v1.2.3 From 9d8573a844cdb6bddd2779af8ddeb4128db055f4 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Mon, 10 Jul 2023 03:37:47 +0800 Subject: [BH] Fix Bounty Titan Damage Checks (#654) Update _gamemode_at.nut --- .../mod/scripts/vscripts/gamemodes/_gamemode_at.nut | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index c61cb585..93a3aa16 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -107,7 +107,6 @@ void function GamemodeAt_Init() // Set-up score callbacks ScoreEvent_SetupEarnMeterValuesForMixedModes() - AddDamageFinalCallback( "npc_titan", OnNPCTitanFinalDamaged ) AddCallback_OnPlayerKilled( AT_PlayerOrNPCKilledScoreEvent ) AddCallback_OnNPCKilled( AT_PlayerOrNPCKilledScoreEvent ) @@ -1658,9 +1657,10 @@ void function AT_HandleBossTitanSpawn( entity titan, AT_WaveOrigin campData, int titan.Minimap_AlwaysShow( TEAM_MILITIA, null ) thread BountyBossHighlightThink( titan ) - // set up titan-specific death callbacks, mark it as bounty boss for finalDamageCallbacks to work + // set up titan-specific death callbacks, mark it as bounty boss file.titanIsBountyBoss[ titan ] <- true file.bountyTitanRewards[ titan ] <- ATTRITION_SCORE_BOSS_DAMAGE + AddEntityCallback_OnPostDamaged( titan, OnBountyTitanPostDamage ) AddEntityCallback_OnKilled( titan, OnBountyTitanKilled ) titan.GetTitanSoul().soul.skipDoomState = true @@ -1684,13 +1684,7 @@ void function BountyBossHighlightThink( entity titan ) } } -void function OnNPCTitanFinalDamaged( entity titan, var damageInfo ) -{ - if ( titan in file.titanIsBountyBoss ) - OnBountyTitanDamaged( titan, damageInfo ) -} - -void function OnBountyTitanDamaged( entity titan, var damageInfo ) +void function OnBountyTitanPostDamage( entity titan, var damageInfo ) { entity attacker = DamageInfo_GetAttacker( damageInfo ) if ( !IsValid( attacker ) ) // delayed by projectile shots @@ -1703,14 +1697,6 @@ void function OnBountyTitanDamaged( entity titan, var damageInfo ) return } - // respawn FUCKED UP pilot weapon against titan's damage calculation, have to copy-paste this check from Titan_NPCTookDamage() - if ( HeavyArmorCriticalHitRequired( damageInfo ) && - CritWeaponInDamageInfo( damageInfo ) && - !IsCriticalHit( attacker, titan, DamageInfo_GetHitBox( damageInfo ), DamageInfo_GetDamage( damageInfo ), DamageInfo_GetDamageType( damageInfo ) ) && - IsValid( attacker ) && - !attacker.IsTitan() ) - return - int rewardSegment = ATTRITION_SCORE_BOSS_DAMAGE int healthSegment = titan.GetMaxHealth() / rewardSegment -- cgit v1.2.3 From 6727571794b28cf5b5cdb190fd1661a1000143ad Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 9 Jul 2023 20:44:57 +0100 Subject: Fix grunt death callbacks (#632) fix weird bug with grunt deaths --- .../mod/scripts/vscripts/ai/_ai_soldiers.gnut | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut index 9717c76d..89fb7a82 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/ai/_ai_soldiers.gnut @@ -60,6 +60,19 @@ function AiSoldiers_Init() level.COOP_AT_WEAPON_RATES[ "mp_weapon_smr" ] <- 0.4 level.COOP_AT_WEAPON_RATES[ "mp_weapon_mgl" ] <- 0.1 + // add stub death callback, because in _codecallbacks_common.gnut there is + // CodeCallback_OnEntityKilled which is only called when an entity is being tracked. An + // entity is set to be tracked if it has a death callback for it's class, unfortunately this + // is then relayed to clients and used for client side death callbacks. The end result of + // not having this function called is that clients become completely unaware of any grunt + // deaths. A noticeable difference here is that grunts do not play the kill confirmed audio + // except on War Games, which does register a callback for grunt deaths to make them dissolve. + // + // Whilst this may seem like a bit of a hacky solution, it is generally better than simply + // tracking all entities. If a different callback is created in the future for grunt deaths + // that is not specific to a gamemode, map, etc. then this could be removed + AddDeathCallback( "npc_soldier", void function( entity guy, var damageInfo ){} ) + PrecacheSprite( $"sprites/glow_05.vmt" ) FlagInit( "disable_npcs" ) FlagInit( "Disable_IMC" ) -- cgit v1.2.3 From 41f104e5f40654948dccfefd169152d47064c6ae Mon Sep 17 00:00:00 2001 From: EnderBoy9217 <122132914+EnderBoy9217@users.noreply.github.com> Date: Mon, 10 Jul 2023 10:12:23 -0400 Subject: Fix dropship related crash (#662) * Fix infinite loading screen * Update Northstar.Client/mod/scripts/vscripts/ui/_menus.nut * Update _menus.nut * Update _menus.nut * Update _menus.nut * Add files via upload * Update _menus.nut * Update _menus.nut * Update cplayer.nut * Update cplayer.nut * Add files via upload * Update _classic_mp_dropship_intro.gnut --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 0555df9b..23ae37a1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -188,7 +188,8 @@ void function SpawnPlayerIntoDropship( entity player ) } // respawn player and holster their weapons so they aren't out - player.RespawnPlayer( null ) + if ( !IsAlive( player ) ) + player.RespawnPlayer( null ) HolsterAndDisableWeapons(player) player.DisableWeaponViewModel() @@ -255,4 +256,4 @@ void function PlayerJumpsFromDropship( entity player ) WaitFrame() TryGameModeAnnouncement( player ) -} \ No newline at end of file +} -- cgit v1.2.3 From d23828da5b08ce06c8385ec4ff5002afbd9a9b82 Mon Sep 17 00:00:00 2001 From: DBmaoha <56738369+DBmaoha@users.noreply.github.com> Date: Tue, 11 Jul 2023 00:22:52 +0800 Subject: Prematch now cleans up boosts (#568) * Initial Commit * update format * update to use https://github.com/R2Northstar/NorthstarMods/pull/565's function * remove random whitespace * github suggestions nuked the line and i dont know why --------- Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> --- .../mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut | 9 +++++++++ 1 file changed, 9 insertions(+) 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 7d4552a0..9057f7d8 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 @@ -20,6 +20,7 @@ void function Sv_ItemInventory_Init() { AddCallback_OnClientConnected( Sv_ItemInventory_OnClientConnected ) AddCallback_OnPlayerGetsNewPilotLoadout( Sv_ItemInventory_OnPlayerGetsNewPilotLoadout ) + AddCallback_GameStateEnter( eGameState.Prematch, PrematchClearInventory ) } void function Sv_ItemInventory_OnClientConnected( entity player ) @@ -27,6 +28,14 @@ void function Sv_ItemInventory_OnClientConnected( entity player ) file.playerInventoryStacks[ player ] <- [] } +void function PrematchClearInventory() // vanilla behavior +{ + foreach( entity player in GetPlayerArray() ) + { + PlayerInventory_TakeAllInventoryItems( player ) + } +} + void function Sv_ItemInventory_OnPlayerGetsNewPilotLoadout( entity player, PilotLoadoutDef newPilotLoadout ) { array playerInventoryStack = file.playerInventoryStacks[ player ] -- cgit v1.2.3 From fc6c8c0d295fee70d08d422bf0426d807d7b740b Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 12 Jul 2023 23:08:22 +0200 Subject: Bump mods version to `1.16.0` (#665) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index e9536d66..8040c14c 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index f3f73fde..ca33fa22 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 3525c434..4f19307d 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.14.0", + "Version": "1.16.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From bceb950a18ee0a8155acb99bb66dd57e4107547e Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 13 Jul 2023 19:48:17 +0200 Subject: Remove `ns_player_auth_port` from server config (#628) With connectionless we no longer use the TCP port. --- Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg index d92ca3ec..f28f601b 100644 --- a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg +++ b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg @@ -6,7 +6,6 @@ ns_report_sp_server_to_masterserver 0 // whether this server should report itsel ns_auth_allow_insecure 0 // keep this to 0 unless you want to allow people to join without masterserver auth/persistence ns_erase_auth_info 1 // keep this to 1 unless you're testing and crashing alot, so you don't have to go through the northstar lobby to reauth -ns_player_auth_port 8081 // this can be whatever, make sure it's portforwarded over tcp ns_masterserver_hostname "https://northstar.tf" // masterserver hostname everything_unlocked 1 // unlock everything -- cgit v1.2.3 From ef596fb867c91e4772bdc87e51ca7ecafc9217ee Mon Sep 17 00:00:00 2001 From: Respawn Date: Sun, 16 Jul 2023 22:58:48 +0200 Subject: Add _arc_cannon.nut from englishclient_mp_common --- .../mod/scripts/vscripts/weapons/_arc_cannon.nut | 1006 ++++++++++++++++++++ 1 file changed, 1006 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut new file mode 100644 index 00000000..4268422e --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -0,0 +1,1006 @@ + +// Aiming & Range +const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain +const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency ) +const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another +const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another +const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge +const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge +const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon +const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets +const ARC_CANNON_FORK_DELAY = 0.1 + +const ARC_CANNON_RANGE_CHAIN_BURN = 400 +const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900 +const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge +const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge +const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon +const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets +const ARC_CANNON_BEAM_LIFETIME_BURN = 1 + +// Visual settings +const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol ) +const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol ) +const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge +const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge +const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC +const ARC_CANNON_BEAM_COLOR = "150 190 255" +const ARC_CANNON_BEAM_LIFETIME = 0.75 + +// Player Effects +const ARC_CANNON_TITAN_SCREEN_SFX = "Weapon_R1_LaserMine.Activate" +const ARC_CANNON_PILOT_SCREEN_SFX = "Weapon_R1_LaserMine.Activate" +const ARC_CANNON_EMP_DURATION_MIN = 0.1 +const ARC_CANNON_EMP_DURATION_MAX = 1.8 +const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4 +const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.025 +const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.075 +const ARC_CANNON_SCREEN_THRESHOLD = 0.3385 +const ARC_CANNON_SLOW_SCALE_MIN = 0.8 +const ARC_CANNON_SLOW_SCALE_MAX = 0.7 +const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2 + +// Rumble +const ARC_CANNON_RUMBLE_CHARGE_MIN = 5 +const ARC_CANNON_RUMBLE_CHARGE_MAX = 50 +const ARC_CANNON_RUMBLE_TYPE_INDEX = 14 // These are defined in code, 14 = RUMBLE_FLAT_BOTH + +// Damage +const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep +const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage. +const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage. +const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0 + +// Options +const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon + +//Mods +const OVERCHARGE_MAX_SHIELD_DECAY = 0.2 +const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04 +const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05 + +const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6 +const SPLITTER_FORK_COUNT_MAX = 10 + +const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated" +RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED ) + +const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd" +RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND ) + +const ARC_CANNON_BEAM_EFFECT = "wpn_arc_cannon_beam" +PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT ) + +const ARC_CANNON_BEAM_EFFECT_MOD = "wpn_arc_cannon_beam_mod" +PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD ) + +const ARC_CANNON_FX_TABLE = "exp_arc_cannon" +PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE ) + +if ( !reloadingScripts ) +{ + // Valid Arc Cannon Target Classnames + level.arcCannonTargetClassnames <- {} + level.arcCannonTargetClassnames[ "npc_turret_floor" ] <- true + level.arcCannonTargetClassnames[ "npc_spectre" ] <- true + level.arcCannonTargetClassnames[ "npc_soldier_shield" ] <- true + level.arcCannonTargetClassnames[ "npc_soldier_heavy" ] <- true + level.arcCannonTargetClassnames[ "npc_soldier" ] <- true + level.arcCannonTargetClassnames[ "npc_cscanner" ] <- true + level.arcCannonTargetClassnames[ "npc_titan" ] <- true + level.arcCannonTargetClassnames[ "npc_marvin" ] <- true + level.arcCannonTargetClassnames[ "player" ] <- true + level.arcCannonTargetClassnames[ "script_mover" ] <- true + level.arcCannonTargetClassnames[ "npc_grenade_frag" ] <- true + level.arcCannonTargetClassnames[ "rpg_missile" ] <- true + level.arcCannonTargetClassnames[ "npc_turret_mega" ] <- true + level.arcCannonTargetClassnames[ "npc_turret_sentry" ] <- true + level.arcCannonTargetClassnames[ "npc_dropship" ] <- true + level.arcCannonTargetClassnames[ "prop_dynamic" ] <- true +} + +function main() +{ + Globalize( ArcCannon_PrecacheFX ) + Globalize( ArcCannon_Start ) + Globalize( ArcCannon_Stop ) + Globalize( ArcCannon_ChargeBegin ) + Globalize( ArcCannon_ChargeEnd ) + Globalize( FireArcCannon ) + Globalize( ArcCannon_HideIdleEffect ) + Globalize( AddToArcCannonTargets ) + Globalize( ConvertTitanShieldIntoBonusCharge ) + Globalize( GetArcCannonChargeFraction ) + Globalize( StopChargeEffects ) + + if( IsClient() ) + { + AddDestroyCallback( "mp_titanweapon_arc_cannon", ClientDestroyCallback_ArcCannon_Stop ) + } + else + { + level._arcCannonTargetsArrayID <- CreateScriptManagedEntArray() + } + + PrecacheParticleSystem( "impact_arc_cannon_titan" ) +} + +function ArcCannon_PrecacheFX( weapon ) +{ + if ( WeaponIsPrecached( weapon ) ) + return + + PrecacheParticleSystem( "wpn_arc_cannon_electricity_fp" ) + PrecacheParticleSystem( "wpn_arc_cannon_electricity" ) + + PrecacheParticleSystem( "wpn_ARC_knob_FP" ) + PrecacheParticleSystem( "wpn_ARC_knob" ) + + PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" ) + PrecacheParticleSystem( "wpn_arc_cannon_charge" ) + + PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" ) + PrecacheParticleSystem( "wpn_arc_cannon_charge" ) + + PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon_fp" ) + PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon" ) +} + +function ArcCannon_Start( weapon ) +{ + weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" ) + weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) +} + +function ArcCannon_Stop( weapon, player = null ) +{ + weapon.Signal( ARC_CANNON_SIGNAL_DEACTIVATED ) + StopChargeEffects( weapon, player ) + + weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" ) + weapon.StopWeaponSound( "arc_cannon_charged_loop" ) + weapon.StopWeaponSound( "arc_cannon_charge" ) +} + +function ArcCannon_ChargeBegin( weapon ) +{ + local weaponOwner = weapon.GetWeaponOwner() + local weaponScriptScope = weapon.GetScriptScope() + local useNormalChargeSounds = true + if( weapon.HasMod( "overcharge" ) ) + { + if ( weaponOwner.IsTitan() ) + { + local soul = weaponOwner.GetTitanSoul() + if ( soul.GetShieldHealth() > 0 ) + { + weapon.EmitWeaponSound( "arc_cannon_fastcharge" ) + useNormalChargeSounds = false + } + if ( IsServer() ) + thread ConvertTitanShieldIntoBonusCharge( soul, weapon ) + } + } + + if ( useNormalChargeSounds ) + { + weapon.EmitWeaponSound( "arc_cannon_charge" ) + } + + if( !("maxChargeTime" in weapon.s) ) + weapon.s.maxChargeTime <- weapon.GetWeaponModSetting( "charge_time" ) + + weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge", "muzzle_flash" ) + local chargeTime = weapon.GetWeaponChargeTime() + + if ( IsClient() ) + { + if ( !weapon.ShouldPredictProjectiles() ) + return + + if ( weaponOwner.IsPlayer() ) + weaponOwner.StartArcCannon(); + + local handle = weapon.AllocateHandleForViewmodelEffect( "wpn_arc_cannon_charge_fp" ) + if ( handle ) + EffectSkipForwardToTime( handle, chargeTime ) + + thread cl_ChargeRumble( weapon, ARC_CANNON_RUMBLE_TYPE_INDEX, ARC_CANNON_RUMBLE_CHARGE_MIN, ARC_CANNON_RUMBLE_CHARGE_MAX, ARC_CANNON_SIGNAL_CHARGEEND ) + } + thread ChargeEffects( weapon ) +} + +function ArcCannon_ChargeEnd( weapon, player = null ) +{ + if ( IsClient() && weapon.GetWeaponOwner() == GetLocalViewPlayer() ) + { + local weaponOwner + if ( player != null ) + weaponOwner = player + else + weaponOwner = weapon.GetWeaponOwner() + + if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() ) + weaponOwner.StopArcCannon() + } + if( IsValid( weapon ) ) + StopChargeEffects( weapon ) +} + +function StopChargeEffects( weapon, player = null ) +{ + weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND ) + + local weaponScriptScope = weapon.GetScriptScope() + weapon.StopWeaponSound( "arc_cannon_charge" ) + weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" ) + weapon.StopWeaponSound( "arc_cannon_fastcharge" ) + //weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" ) + weapon.StopWeaponEffect( "wpn_ARC_knob_FP", "wpn_ARC_knob" ) +} + +function ChargeEffects( weapon ) +{ + weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND ) + weapon.EndSignal( "OnDestroy" ) + + local player = weapon.GetWeaponOwner() + + wait ( weapon.s.maxChargeTime * GetArcCannonChargeFraction( weapon ) ) + + weapon.PlayWeaponEffectNoCull( "wpn_ARC_knob_FP", "wpn_ARC_knob", "SPINNING_KNOB" ) +} + +function ConvertTitanShieldIntoBonusCharge( soul, weapon ) +{ + weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND ) + weapon.EndSignal( "OnDestroy" ) + + local maxShieldDecay = OVERCHARGE_MAX_SHIELD_DECAY + local bonusChargeFraction = OVERCHARGE_BONUS_CHARGE_FRACTION + local shieldDecayMultiplier = OVERCHARGE_SHIELD_DECAY_MULTIPLIER + local shieldHealthMax = soul.GetShieldHealthMax() + local chargeRatio = GetArcCannonChargeFraction( weapon ) + + while( 1 ) + { + if( !IsValid( soul ) || !IsValid( weapon ) ) + break + + local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction() + local charge = clamp ( baseCharge * ( 1 / chargeRatio ), 0.0, 1.0 ) + if( charge < 1.0 || maxShieldDecay > 0) + { + local shieldHealth = soul.GetShieldHealth() + + //Slight inconsistency in server updates, this ensures it never takes too much. + if ( shieldDecayMultiplier > maxShieldDecay ) + shieldDecayMultiplier = maxShieldDecay + maxShieldDecay -= shieldDecayMultiplier + + local shieldDecayAmount = shieldHealthMax * shieldDecayMultiplier + local newShieldAmount = shieldHealth - shieldDecayAmount + soul.SetShieldHealth( max( newShieldAmount, 0 ) ) + soul.s.nextRegenTime = Time() + TITAN_SHIELD_REGEN_DELAY + + if( shieldDecayAmount > shieldHealth ) + bonusChargeFraction = bonusChargeFraction * ( shieldHealth / shieldDecayAmount ) + weapon.SetWeaponChargeFraction( baseCharge + bonusChargeFraction ) + } + wait 0.1 + } +} + +function FireArcCannon( weapon, attackParams ) +{ + local weaponScriptScope = weapon.GetScriptScope() + local owner = weapon.GetWeaponOwner() + + local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction() + local charge = clamp ( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 ) + local newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 ) + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + { + weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot_Amped" ) + weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_fire_BigShot_Amped", newVolume ) + } + else + { + weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot" ) + weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_Fire_BigShot", newVolume ) + } + + weapon.StopWeaponSound( "arc_cannon_charged_loop" ) + + weapon.EmitWeaponNpcSound( LOUD_WEAPON_AI_SOUND_RADIUS_MP, 0.2 ) + + weapon.PlayWeaponEffect( "wpn_muzzleflash_arc_cannon_fp", "wpn_muzzleflash_arc_cannon", "muzzle_flash" ) + + StopChargeEffects( weapon ) + + local attachmentName = "muzzle_flash" + local attachmentIndex = weapon.LookupAttachment( attachmentName ) + Assert( attachmentIndex >= 0 ) + local muzzleOrigin = weapon.GetAttachmentOrigin( attachmentIndex ) + + //printt( "-------- FIRING ARC CANNON --------" ) + + local firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams ) + if ( !IsValid( firstTargetInfo.target ) ) + FireArcNoTargets( weapon, attackParams, muzzleOrigin ) + else + FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin ) + + return 1 +} + +function GetFirstArcCannonTarget( weapon, attackParams ) +{ + local owner = weapon.GetWeaponOwner() + local coneHeight = weapon.GetMaxDamageFarDist() + + local angleToAxis = 8 // set this too high and auto-titans using it will error on GetVisibleEntitiesInCone + local ignoredEntities = [ owner, weapon ] + local traceMask = TRACE_MASK_SHOT + local flags = VIS_CONE_ENTS_TEST_HITBOXES // | VIS_CONE_ENTS_IGNORE_VORTEX + local antilagPlayer = null + if ( owner.IsPlayer() ) + { + angleToAxis = owner.GetAttackSpreadAngle() * 0.095 + antilagPlayer = owner + } + + local results + local ownerTeam = owner.GetTeam() + + // Get a missile target and a non-missile target in the cone that the player can zap + // We do this in a separate check so we can use a wider cone to be more forgiving for targeting missiles + local firstTargetInfo = {} + firstTargetInfo.target <- null + firstTargetInfo.hitLocation <- null + for ( local i = 0 ; i < 2 ; i++ ) + { + local missileCheck = i == 0 + local coneAngle = angleToAxis + if ( missileCheck ) + coneAngle *= 3.0 + + results = GetVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer, false, false ) + foreach( result in results ) + { + local visibleEnt = result.entity + + if ( !IsValid( visibleEnt ) ) + continue + + local classname = IsServer() ? visibleEnt.GetClassname() : visibleEnt.GetSignifierName() + + if ( !( classname in level.arcCannonTargetClassnames ) ) + continue + + if ( "GetTeam" in visibleEnt ) + { + local visibleEntTeam = visibleEnt.GetTeam() + if ( visibleEntTeam == ownerTeam ) + continue + if ( IsEntANeutralMegaTurret( visibleEnt, ownerTeam ) ) + continue + } + + if ( missileCheck && classname != "rpg_missile" ) + continue + + if ( !missileCheck && classname == "rpg_missile" ) + continue + + firstTargetInfo.target = visibleEnt + firstTargetInfo.hitLocation = result.visiblePosition + break + } + } + //Creating a whiz-by sound. + weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true ) + + return firstTargetInfo +} + +function FireArcNoTargets( weapon, attackParams, muzzleOrigin ) +{ + Assert( IsValid( weapon ) ) + local player = weapon.GetWeaponOwner() + local chargeFrac = weapon.GetWeaponChargeFraction() + local beamVec = attackParams.dir * weapon.GetMaxDamageFarDist() + local playerEyePos = player.EyePosition() + local traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + local beamEnd = traceResults.endPos + + local vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd ) + if ( vortexHit ) + { + if( IsServer() ) + { + local vortexWeapon = vortexHit.vortex.GetOwnerWeapon() + if( vortexWeapon && vortexWeapon.GetClassname() == "mp_titanweapon_vortex_shield" ) + VortexDrainedByImpact( vortexWeapon, weapon, null, null ) + } + beamEnd = vortexHit.hitPos + } + + local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) + local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX ) + if ( player.IsNPC() ) + boltWidth = ARC_CANNON_BOLT_WIDTH_NPC + thread CreateArcCannonBeam( weapon, null, muzzleOrigin, beamEnd, player, ARC_CANNON_BEAM_LIFETIME, radius, boltWidth, 2, false, true ) + if( IsServer() ) + CreateExplosion( beamEnd, 0, 0, 1, 1, player, 0, null, -1, false, ARC_CANNON_FX_TABLE ) +} + +function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin ) +{ + local beamStart = muzzleOrigin + local beamEnd + local player = weapon.GetWeaponOwner() + local chargeFrac = weapon.GetWeaponChargeFraction() + local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) + local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX ) + local maxChains + local minChains + + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + { + if ( player.IsNPC() ) + maxChains = ARC_CANNON_CHAIN_COUNT_NPC_BURN + else + maxChains = ARC_CANNON_CHAIN_COUNT_MAX_BURN + + minChains = ARC_CANNON_CHAIN_COUNT_MIN_BURN + } + else + { + if ( player.IsNPC() ) + maxChains = ARC_CANNON_CHAIN_COUNT_NPC + else + maxChains = ARC_CANNON_CHAIN_COUNT_MAX + + minChains = ARC_CANNON_CHAIN_COUNT_MIN + } + + if ( !player.IsNPC() ) + maxChains = Graph( chargeFrac, 0, 1, minChains, maxChains ) + + local zapInfo = {} + zapInfo.weapon <- weapon + zapInfo.player <- player + zapInfo.muzzleOrigin <- muzzleOrigin + zapInfo.radius <- radius + zapInfo.boltWidth <- boltWidth + zapInfo.maxChains <- maxChains + zapInfo.chargeFrac <- chargeFrac + zapInfo.zappedTargets <- {} + zapInfo.zappedTargets[ firstTargetInfo.target ] <- true + local chainNum = 1 + thread ZapTargetRecursive( firstTargetInfo.target, zapInfo, zapInfo.muzzleOrigin, firstTargetInfo.hitLocation, chainNum ) +} + +function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPos = null, chainNum = 1 ) +{ + if ( !IsValid( target ) ) + return + + if ( !IsValid( zapInfo.weapon ) ) + return + + Assert( target in zapInfo.zappedTargets ) + if ( chainNum > zapInfo.maxChains ) + return + local beamEndPos + if ( firstTargetBeamEndPos == null ) + beamEndPos = target.GetWorldSpaceCenter() + else + beamEndPos = firstTargetBeamEndPos + + waitthread ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum ) + + // Get other nearby targets we can chain to + if ( IsServer() ) + { + if ( !IsValid( target ) ) + return + + if ( !IsValid( zapInfo.weapon ) ) + return + + local chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo ) + foreach( chainTarget in chainTargets ) + { + local newChainNum = chainNum + if( !chainTarget.GetClassname() != "rpg_missile" ) + newChainNum++ + zapInfo.zappedTargets[ chainTarget ] <- true + thread ZapTargetRecursive( chainTarget, zapInfo, beamEndPos, null, newChainNum ) + } + + if ( IsValid( zapInfo.player ) && zapInfo.player.IsPlayer() && zapInfo.zappedTargets.len() >= 5 ) + { + if ( PlayerProgressionAllowed( zapInfo.player ) ) + zapInfo.player.SetPersistentVar( "ach_multikillArcRifle", true ) + if ( chainNum == 5 ) + UpdatePlayerStat( zapInfo.player, "misc_stats", "arcCannonMultiKills", 1 ) + } + } +} + +function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) +{ + //DebugDrawLine( beamStartPos, beamEndPos, 255, 0, 0, true, 5.0 ) + local boltWidth = zapInfo.boltWidth + if ( zapInfo.player.IsNPC() ) + boltWidth = ARC_CANNON_BOLT_WIDTH_NPC + local firstBeam = ( chainNum == 1 ) + if( firstBeam && IsServer() ) + CreateExplosion( beamEndPos, 0, 0, 1, 1, zapInfo.player, 0, null, -1, false, ARC_CANNON_FX_TABLE ) + thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam ) + + if ( IsClient() ) + return + + local isMissile = ( target.GetClassname() == "rpg_missile" ) + if( !isMissile ) + wait ARC_CANNON_FORK_DELAY + else + wait 0.05 + + local deathPackage = damageTypes.ArcCannon + + local damageAmount + local damageMin + local damageMax + + if ( IsValid( target ) && IsValid( zapInfo.player ) ) + { + if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) + { + if ( IsValid( zapInfo.weapon ) ) + { + damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value_titanarmor" ) + damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value_titanarmor" ) + } + else + { + damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value_titanarmor" ) + damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value_titanarmor" ) + } + + // Due to auto-titans not charging, they do very little damage with this weapon against one another. + if ( zapInfo.player.IsNPC() ) + { + damageMin *= 7.0 + damageMax *= 7.0 + } + + // HACK; temp fix for non titan heavy armor targets (e.g. mega turret) + } + else + { + if ( IsValid( zapInfo.weapon ) ) + { + damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value" ) + damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value" ) + } + else + { + damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value" ) + damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value" ) + } + + if ( target.IsNPC() ) + { + damageMin *= 3.0 // more powerful against NPC humans so they die easy + damageMax *= 3.0 + } + } + + + // Scale damage amount based on how many chains deep we are + local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon ) + damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax ) + local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER + if( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) ) + damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER + damageAmount *= pow( damageFalloff, chainNum - 1 ) + + local dmgSourceID = eDamageSourceId.mp_titanweapon_arc_cannon + + // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target + // move to Damaged callback instead + if( damageAmount > 0 ) + { + local empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX ) + + if ( target.IsPlayer() ) + { + local empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX ) + + if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + { + Remote.CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) + EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX ) + + local scale = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SLOW_SCALE_MIN, ARC_CANNON_SLOW_SCALE_MAX ) + thread EMP_SlowPlayer( target, scale, empDuration ) + } + else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + { + Remote.CallFunction_Replay( target, "ServerCallback_PilotEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) + EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX ) + } + } + + // Do 3rd person effect on the body + local effect = null + local tag = null + target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = zapInfo.player.GetOrigin(), force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID } ) + + if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD ) + empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION + else + empDuration += ARC_CANNON_EMP_FADEOUT_DURATION + + if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) + { + effect = "impact_arc_cannon_titan" + tag = "exp_torso_front" + } + else + { + effect = "P_emp_body_human" + tag = "CHESTFOCUS" + } + + if ( target.IsPlayer() && effect != null && tag != null ) + { + if ( target.LookupAttachment( tag ) != 0 ) + ClientStylePlayFXOnEntity( effect, target, tag, empDuration ) + } + + if ( target.IsPlayer() ) + EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" ) + else + EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" ) + + thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 ) + } + else + { + //Don't bounce if the beam is set to do 0 damage. + chainNum = zapInfo.maxChains + } + + if ( isMissile ) + { + if ( IsValid ( zapInfo.player ) ) + target.SetOwner( zapInfo.player ) + target.Explode() + } + } +} + + +function FadeOutSoundOnEntityAfterDelay( entity, soundAlias, delay, fadeTime ) +{ + + if ( !IsValid( entity ) ) + return + + entity.EndSignal( "OnDestroy" ) + wait delay + FadeOutSoundOnEntity( entity, soundAlias, fadeTime ) +} + + +function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) +{ + Assert( IsServer() ) + + local results = [] + if ( !IsValid( zapInfo.player ) ) + return results + + local playerTeam = zapInfo.player.GetTeam() + local allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, zapInfo.weapon ) + allTargets = ArrayClosest( allTargets, fromOrigin ) + + local viewVector + if ( zapInfo.player.IsPlayer() ) + viewVector = zapInfo.player.GetViewVector() + else + viewVector = zapInfo.player.EyeAngles().AnglesToForward() + + local eyePosition = zapInfo.player.EyePosition() + + foreach( ent in allTargets ) + { + local forkCount = ARC_CANNON_FORK_COUNT_MAX + if ( zapInfo.weapon.HasMod( "splitter" ) ) + forkCount = SPLITTER_FORK_COUNT_MAX + else if ( zapInfo.weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + forkCount = ARC_CANNON_FORK_COUNT_MAX_BURN + + if ( results.len() >= forkCount ) + break + + if ( ent.IsPlayer() ) + { + if ( ent.GetPlayerClass() == "operator" ) + continue + + if ( ent.GetPlayerClass() == "dronecontroller" ) + continue + + // Ignore players that are passing damage to their parent. This is to address zapping a friendly rodeo player + local entParent = ent.GetParent() + if ( IsValid( entParent ) && ent.kv.PassDamageToParent.tointeger() ) + continue + } + + if ( ent.GetClassname() == "script_mover" ) + continue + + if ( IsEntANeutralMegaTurret( ent, playerTeam ) ) + continue + + if ( !IsAlive( ent ) ) + continue + + // Don't consider targets that already got zapped + if ( ent in zapInfo.zappedTargets ) + continue + + //Preventing the arc-cannon from firing behind. + local vecToEnt = ( ent.GetWorldSpaceCenter() - eyePosition ) + vecToEnt.Norm() + local dotVal = vecToEnt.Dot( viewVector ) + if ( dotVal < 0 ) + continue + + // Check if we can see them, they aren't behind a wall or something + local ignoreEnts = [] + ignoreEnts.append( zapInfo.player ) + ignoreEnts.append( ent ) + + foreach( zappedTarget, val in zapInfo.zappedTargets ) + { + if ( IsValid( zappedTarget ) ) + ignoreEnts.append( zappedTarget ) + } + + local traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + + // Trace failed, lets try an eye to eye trace + if ( traceResult.fraction < 1 && IsValid( fromTarget ) ) + traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + + if ( traceResult.fraction < 1 ) + continue + + // Enemy is in visible, and within range. + if ( !IsValueInArray( results, ent ) ) + results.append( ent ) + } + + //printt( "NEARBY TARGETS VALID AND VISIBLE:", results.len() ) + + return results +} +Globalize( GetArcCannonChainTargets ) + + +function IsEntANeutralMegaTurret( ent, playerTeam ) +{ + if ( ent.GetClassname() != "npc_turret_mega" ) + return false + local entTeam = ent.GetTeam() + if ( entTeam == playerTeam ) + return false + if ( entTeam != GetOtherTeam( playerTeam ) ) + return true + + return false +} +Globalize( IsEntANeutralMegaTurret ) + +function ArcCannon_HideIdleEffect( weapon, delay ) +{ + //printt( "HideIdleEffect" ) + weapon.EndSignal( ARC_CANNON_SIGNAL_DEACTIVATED ) + weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" ) + wait delay + + if( !IsValid( weapon ) ) + return + + local weaponOwner = weapon.GetWeaponOwner() + //The weapon can be valid, but the player isn't a Titan during melee execute. + // JFS: threads with waits should just end on "OnDestroy" + if ( !IsValid(weaponOwner) ) + return + + if ( !weapon.GetWeaponOwner().IsTitan() || weapon != weaponOwner.GetActiveWeapon() ) + return + + weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" ) + weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) +} + +function AddToArcCannonTargets( ent ) +{ + AddToScriptManagedEntArray( level._arcCannonTargetsArrayID, ent ); +} + +function GetArcCannonTargets( origin, team ) +{ + local targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) + + if ( ARC_CANNON_TARGETS_MISSILES ) + { + local enemyTeam = GetEnemyTeam( team ) + targets.extend( GetProjectileArrayEx( "rpg_missile", enemyTeam, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) ) + } + + return targets +} +Globalize( GetArcCannonTargets ) + +function GetArcCannonTargetsInRange( origin, team, weapon ) +{ + local allTargets = GetArcCannonTargets( origin, team ) + local targetsInRange = [] + + local titanDistSq + local distSq + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + { + titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN_BURN * ARC_CANNON_TITAN_RANGE_CHAIN_BURN + distSq = ARC_CANNON_RANGE_CHAIN_BURN * ARC_CANNON_RANGE_CHAIN_BURN + } + else + { + titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN * ARC_CANNON_TITAN_RANGE_CHAIN + distSq = ARC_CANNON_RANGE_CHAIN * ARC_CANNON_RANGE_CHAIN + } + + foreach( target in allTargets ) + { + local d = DistanceSqr( target.GetOrigin(), origin ) + local validDist = target.IsTitan() ? titanDistSq : distSq + if ( d <= validDist ) + targetsInRange.append( target ) + } + + return targetsInRange +} + +function SortArcCannonTargets( weapon, targets ) +{ + Assert( targets.len() > 0 ) + local originalTargetCount = targets.len() + //printt( " sorting", originalTargetCount, "targets" ) + + local sortedTargets = [] + local lastEnt = weapon.GetWeaponOwner() + local closestIndex = null + local closestEnt = null + + while( targets.len() > 0 ) + { + closestEnt = null + closestIndex = null + + closestIndex = GetClosestIndex( targets, lastEnt.GetOrigin() ) + Assert( closestIndex != null ) + closestEnt = targets[ closestIndex ] + Assert( closestEnt != null ) + + sortedTargets.append( closestEnt ) + targets.remove( closestIndex ) + + lastEnt = closestEnt + } + + Assert( sortedTargets.len() == originalTargetCount ) + return sortedTargets +} + +function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDuration = ARC_CANNON_BEAM_LIFETIME, radius = 256, boltWidth = 4, noiseAmplitude = 5, hasTarget = true, firstBeam = false ) +{ + Assert( startPos ) + Assert( endPos ) + + //************************** + // LIGHTNING BEAM EFFECT + //************************** + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN + // If it's the first beam and on client we do a special beam so it's lined up with the muzzle origin + if ( IsClient() && firstBeam ) + thread CreateClientArcBeam( weapon, endPos, lifeDuration, target ) + + if ( IsClient() ) + return + + // Control point sets the end position of the effect + local cpEnd = CreateEntity( "info_placement_helper" ) + cpEnd.SetName( UniqueString( "arc_cannon_beam_cpEnd" ) ) + cpEnd.SetOrigin( endPos ) + DispatchSpawn( cpEnd, false ) + + local zapBeam = CreateEntity( "info_particle_system" ) + zapBeam.kv.cpoint1 = cpEnd.GetName() + + zapBeam.kv.effect_name = GetBeamEffect( weapon ) + + zapBeam.kv.start_active = 0 + zapBeam.SetOwner( player ) + zapBeam.SetOrigin( startPos ) + if ( firstBeam ) + { + zapBeam.kv.VisibilityFlags = 6 // everyone but owner + zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 ) + } + DispatchSpawn( zapBeam ) + + zapBeam.Fire( "Start" ) + zapBeam.Fire( "StopPlayEndCap", "", lifeDuration ) + zapBeam.Kill( lifeDuration ) + cpEnd.Kill( lifeDuration ) +} + +function GetBeamEffect( weapon ) +{ + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + return ARC_CANNON_BEAM_EFFECT_MOD + + return ARC_CANNON_BEAM_EFFECT +} + +function CreateClientArcBeam( weapon, endPos, lifeDuration, target ) +{ + Assert( IsClient() ) + + local beamEffect = GetBeamEffect( weapon ) + + weapon.PlayWeaponEffect( beamEffect, null, "muzzle_flash" ) + local handle = weapon.AllocateHandleForViewmodelEffect( beamEffect ) + if ( !EffectDoesExist( handle ) ) + return + + EffectSetControlPointVector( handle, 1, endPos ) + + if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) + lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN + + wait( lifeDuration ) + + if ( IsValid( weapon ) ) + weapon.StopWeaponEffect( beamEffect, null ) +} + +function ClientDestroyCallback_ArcCannon_Stop( entity ) +{ + ArcCannon_Stop( entity ) +} + +function GetArcCannonChargeFraction( weapon ) +{ + if ( IsValid( weapon ) ) + { + local chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO + if( weapon.HasModDefined( "capacitor" ) && weapon.HasMod( "capacitor" ) ) + chargeRatio = ARC_CANNON_CAPACITOR_CHARGE_RATIO + if( weapon.GetWeaponModSetting( "is_burn_mod" ) ) + chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN + return chargeRatio + } + + return 0 +} \ No newline at end of file -- cgit v1.2.3 From 0a20aaeda227ab35b18b651dc7325c34588faa8b Mon Sep 17 00:00:00 2001 From: Respawn Date: Sun, 16 Jul 2023 23:00:14 +0200 Subject: Add mp_titanweapon_arc_cannon.nut from englishclient_mp_common --- .../vscripts/weapons/mp_titanweapon_arc_cannon.nut | 119 +++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut new file mode 100644 index 00000000..09faafa5 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut @@ -0,0 +1,119 @@ +ArcCannon_PrecacheFX( self ) + +function OnWeaponActivate( activateParams ) +{ + local weaponOwner = self.GetWeaponOwner() + thread DelayedArcCannonStart( self, weaponOwner ) + if( !("weaponOwner" in self.s) ) + self.s.weaponOwner <- weaponOwner +} + +function DelayedArcCannonStart( weapon, weaponOwner ) +{ + weapon.EndSignal( "WeaponDeactivateEvent" ) + + wait 0 + + if ( IsValid( weapon ) && IsValid( weaponOwner ) && weapon == weaponOwner.GetActiveWeapon() ) + { + if( weaponOwner.IsPlayer() ) + { + local modelEnt = weaponOwner.GetViewModelEntity() + if( IsValid( modelEnt ) && EntHasModelSet( modelEnt ) ) + ArcCannon_Start( weapon ) + } + else + { + ArcCannon_Start( weapon ) + } + } +} + +function OnWeaponDeactivate( deactivateParams ) +{ + ArcCannon_ChargeEnd( self, self.s.weaponOwner ) + ArcCannon_Stop( self ) +} + +function OnWeaponReload( reloadParams ) +{ + local reloadTime = self.GetWeaponInfoFileKeyField( "reload_time" ) + thread ArcCannon_HideIdleEffect( self, reloadTime ) //constant seems to help it sync up better +} + +function OnWeaponOwnerChanged( changeParams ) +{ + if ( IsClient() ) + { + local viewPlayer = GetLocalViewPlayer() + if ( changeParams.oldOwner != null && changeParams.oldOwner == viewPlayer ) + { + ArcCannon_ChargeEnd( self, changeParams.oldOwner ) + ArcCannon_Stop( self, changeParams.oldOwner ) + } + if ( changeParams.newOwner != null && changeParams.newOwner == viewPlayer ) + thread ArcCannon_HideIdleEffect( self, 0.25 ) + } + else + { + if ( changeParams.oldOwner != null ) + { + ArcCannon_ChargeEnd( self, changeParams.oldOwner ) + ArcCannon_Stop( self, changeParams.oldOwner ) + } + if ( changeParams.newOwner != null ) + thread ArcCannon_HideIdleEffect( self, 0.25 ) + } +} + +function OnWeaponChargeBegin( chargeParams ) +{ + ArcCannon_ChargeBegin( self ) +} + +function OnWeaponChargeEnd( chargeParams ) +{ + ArcCannon_ChargeEnd( self ) +} + +function OnWeaponPrimaryAttack( attackParams ) +{ + if ( self.HasMod( "capacitor" ) && self.GetWeaponChargeFraction() < GetArcCannonChargeFraction( self ) ) + return 0 + + if ( !attackParams.firstTimePredicted ) + return + + local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" ) + thread ArcCannon_HideIdleEffect( self, (1 / fireRate) ) + return FireArcCannon( self, attackParams ) +} + +function OnWeaponNpcPrimaryAttack( attackParams ) +{ + local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" ) + thread ArcCannon_HideIdleEffect( self, fireRate ) + return FireArcCannon( self, attackParams ) +} + +function OnWeaponStartZoomIn() +{ + HandleWeaponSoundZoomIn( self, "Weapon_Titan_ArcCannon.ADS_In" ) +} + +function OnWeaponStartZoomOut() +{ + HandleWeaponSoundZoomOut( self, "Weapon_Titan_ArcCannon.ADS_Out" ) +} + +/* +function OnWeaponPrimaryAttackVMActivityToUse() +{ + local baseCharge = self.GetWeaponChargeFraction() + local charge = clamp ( baseCharge * ( 1 / 0.7 ), 0.0, 1.0 ) + + if ( charge > 0.25 ) + return 1 + else + return 0 +}*/ -- cgit v1.2.3 From 6cd9b2312bca0f4568c47568962a0601f36c8fd7 Mon Sep 17 00:00:00 2001 From: Respawn Date: Sun, 16 Jul 2023 23:00:23 +0200 Subject: Add mp_titanweapon_arc_cannon.txt from englishclient_mp_common --- .../scripts/weapons/mp_titanweapon_arc_cannon.txt | 355 +++++++++++++++++++++ 1 file changed, 355 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt new file mode 100644 index 00000000..58bba152 --- /dev/null +++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt @@ -0,0 +1,355 @@ +WeaponData +{ + // General + "printname" "#WPN_TITAN_ARC_CANNON" + "shortprintname" "#WPN_TITAN_ARC_CANNON_SHORT" + "description" "#WPN_TITAN_ARC_CANNON_DESC" + "longdesc" "#WPN_TITAN_ARC_CANNON_LONGDESC" + "weaponClass" "titan" + "fire_mode" "semi-auto" + "server_vscript" "weapons/mp_titanweapon_arc_cannon" + "client_vscript" "weapons/mp_titanweapon_arc_cannon" + "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]" + "pickup_press_prompt" "[USE] [WEAPONNAME]" + "minimap_reveal_distance" "32000" + + // Menu Stats + "stat_damage" "85" + "stat_range" "35" + "stat_accuracy" "80" + "stat_rof" "20" + + // Models + "viewmodel" "models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl" + "playermodel" "models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl" + "anim_prefix" "ar2" + + // Effects + //"tracer_effect" "weapon_tracers_xo16" + //Impact Table used for visuals at the top of arc_cannon.nut + "impact_effect_table" "exp_arc_cannon_whiz_by" + "adjust_to_gun_barrel" "1" + + // Damage - When Used by Players + "damage_type" "bullet" + "damage_near_distance" "200" + "damage_far_distance" "2500" + "damage_near_value" "220" + "damage_far_value" "170" + "damage_near_value_titanarmor" "1800" + "damage_far_value_titanarmor" "100" + + // Damage - When Used by NPCs + + "critical_hit" "0" + + // Ammo + "ammo_stockpile_max" "1000" + "ammo_clip_size" "1000" + "ammo_default_total" "1000" + + // Behavior + "fire_rate" "1" + "zoom_time_in" "0.1" + "zoom_time_out" "0.1" + "zoom_fov" "33" + "reload_time" "3.5" + "reloadempty_time" "3.5" + "holster_time" ".45" + "deploy_time" ".85" + "lower_time" ".1" + "raise_time" ".4" + "charge_time" "3.7" + "charge_end_forces_fire" "0" + "allow_empty_fire" "0" + "reload_enabled" "1" + "allow_empty_click" "1" + "empty_reload_only" "0" + "trigger_snipercam" "1" + "allow_headshots" "0" + "bypass_semiauto_hold_protection" "1" + "vortex_drain" ".15" + + // Spread + "spread_stand_hip" "10" + "spread_npc" "2" + + + // View Kick + "viewkick_spring" "titan_arc" + + "viewkick_pitch_base" "-1" + "viewkick_pitch_random" "0.5" + "viewkick_pitch_softScale" "1" + "viewkick_pitch_hardScale" "0" + + "viewkick_yaw_base" "0" + "viewkick_yaw_random" "0.5" + "viewkick_yaw_softScale" "1" + "viewkick_yaw_hardScale" "0" + + "viewkick_roll_base" "0.0" + "viewkick_roll_randomMin" "0.3" + "viewkick_roll_randomMax" "0.45" + "viewkick_roll_softScale" "0.2" + "viewkick_roll_hardScale" "1.5" + + "viewkick_hipfire_weaponFraction" "0.5" + "viewkick_hipfire_weaponFraction_vmScale" "0.75" + "viewkick_ads_weaponFraction" "0.6" + "viewkick_ads_weaponFraction_vmScale" "0.2" + + + // Bob + "bob_cycle_time" "0.7" + "bob_vert_dist" "0.5" + "bob_horz_dist" "1" + "bob_max_speed" "150" + "bob_pitch" "1" + "bob_yaw" "1" + "bob_roll" "-0.75" + + // View Drift + + // Rumble + "fire_rumble" "titan_arc_cannon" + + // Sway + "sway_rotate_attach" "SWAY_ROTATE" + "sway_min_x" "-0.3" + "sway_min_y" "-0.5" + "sway_min_z" "-0.5" + "sway_max_x" "0.3" + "sway_max_y" "0.5" + "sway_max_z" "0.1" + "sway_min_pitch" "-3" + "sway_min_yaw" "-3.5" + "sway_min_roll" "-1" + "sway_max_pitch" "3" + "sway_max_yaw" "3.5" + "sway_max_roll" "2" + "sway_translate_gain" "10" + "sway_rotate_gain" "12" + "sway_move_forward_translate_x" "0" + "sway_move_forward_translate_z" "-0.5" + "sway_move_back_translate_x" "-2" + "sway_move_back_translate_z" "-1" + "sway_move_left_translate_y" "-1" + "sway_move_left_translate_z" "-0.5" + "sway_move_left_rotate_roll" "-1" + "sway_move_right_translate_y" "1" + "sway_move_right_translate_z" "-0.5" + "sway_move_right_rotate_roll" "2" + "sway_move_up_translate_z" "-1" + "sway_move_down_translate_z" "1" + "sway_turn_left_rotate_yaw" "-1" + "sway_turn_right_rotate_yaw" "1" + "sway_turn_up_rotate_pitch" "1" + "sway_turn_down_rotate_pitch" "-1" + + // NPC + "proficiency_poor_spreadscale" "5.0" + "proficiency_poor_bias" "1.0" + "proficiency_average_spreadscale" "4.0" + "proficiency_average_bias" "1.0" + "proficiency_good_spreadscale" "3.0" + "proficiency_good_bias" "1.0" + "proficiency_very_good_spreadscale" "2.3" + "proficiency_very_good_bias" "1.0" + "proficiency_perfect_spreadscale" "1.7" + "proficiency_perfect_bias" "1.0" + + "npc_min_range" "0" + "npc_max_range" "2500" + "npc_min_range_secondary" "0" + "npc_max_range_secondary" "2500" + "npc_min_burst" "1" + "npc_max_burst" "1" + "rest_time_between_bursts_min" "2.5" + "rest_time_between_bursts_max" "3.0" + + // WeaponED Unhandled Key/Values and custom script Key/Values + "sound_dryfire" "titan_dryfire" + "viewdrift_hipfire_stand_scale_pitch" "0.1" + "viewdrift_hipfire_crouch_scale_pitch" "0.1" + "viewdrift_hipfire_air_scale_pitch" "0.1" + "viewdrift_hipfire_stand_scale_yaw" "0.075" + "viewdrift_hipfire_crouch_scale_yaw" "0.075" + "viewdrift_hipfire_air_scale_yaw" "0.075" + "viewdrift_hipfire_speed_pitch" "0.6" + "viewdrift_hipfire_speed_yaw" "1.22" + "viewdrift_ads_stand_scale_pitch" "0.05" + "viewdrift_ads_crouch_scale_pitch" "0.05" + "viewdrift_ads_air_scale_pitch" "0.05" + "viewdrift_ads_stand_scale_yaw" "0.037" + "viewdrift_ads_crouch_scale_yaw" "0.037" + "viewdrift_ads_air_scale_yaw" "0.037" + "viewdrift_ads_speed_pitch" "0.6" + "viewdrift_ads_speed_yaw" "1.22" + "npc_reload_enabled" "0" + "npc_vortex_block" "1" + + // Crosshair + "red_crosshair_range" "2500" + + Mods + { + overcharge + { + //overcharge + } + capacitor + { + "charge_time" "2.5" //for reference was 3 in 10/15 evening playtest + "charge_cooldown_time" "1.0" + "charge_cooldown_delay" "0.0" + "crosshair_index" "1" + "spread_stand_hip" "15" + "damage_far_distance" "2700" + "damage_near_value_titanarmor" "2000" + } + splitter + { + "damage_near_value_titanarmor" "1900" + "damage_far_value_titanarmor" "100" + } + burn_mod_titan_arc_cannon + { + "crosshair_index" "2" + + "damage_near_value" "*1.1" + "damage_far_value" "*1.1" + "damage_near_value_titanarmor" "*1.1" + "damage_far_value_titanarmor" "*1.1" + "is_burn_mod" "1" + } + } + + CrosshairData + { + BaseWeapon + { + DefaultElementBehavior + { + "fade_while_sprinting" "1" + "fade_while_reloading" "1" + "stationary" "1" + } + Element0 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_charge" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element1 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element2 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single" + "size_x" "16" + "size_y" "16" + "scale_ads" "2.2" + } + Element3 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" + "size_x" "16" + "size_y" "16" + "scale_ads" "2.2" + } + } + CapacitorWeapon + { + DefaultElementBehavior + { + "fade_while_sprinting" "1" + "fade_while_reloading" "1" + "stationary" "1" + } + Element0 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_charge" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element1 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element2 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single" + "size_x" "24" + "size_y" "24" + "scale_ads" "2.2" + } + Element3 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" + "size_x" "24" + "size_y" "24" + "scale_ads" "2.2" + } + } + Burn_Card_Mod + { + DefaultElementBehavior + { + "fade_while_sprinting" "1" + "fade_while_reloading" "1" + "stationary" "1" + "default_color" "246 134 40 255" + } + Element0 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_charge" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element1 + { + "type" "static" + "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" + "size_x" "80" + "size_y" "80" + "scale_ads" "1.5" + } + Element2 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single" + "size_x" "16" + "size_y" "16" + "scale_ads" "2.2" + } + Element3 + { + "type" "static" + "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" + "size_x" "16" + "size_y" "16" + "scale_ads" "2.2" + } + } + } +} -- cgit v1.2.3 From 4c5cd0bf73b4672b0a5682aa2039fa16d7341893 Mon Sep 17 00:00:00 2001 From: Masterliberty <94194459+Masterliberty@users.noreply.github.com> Date: Sun, 16 Jul 2023 17:08:43 -0400 Subject: Add Arc cannon (#600) Adds the Arc Cannon from Titanfall1 --- Northstar.Custom/mod.json | 4 + .../titan_arc_rifle/atpov_titan_arc_rifle.mdl | Bin 0 -> 932128 bytes .../weapons/titan_arc_rifle/w_titan_arc_rifle.mdl | Bin 0 -> 726231 bytes .../vscripts/sh_northstar_custom_precache.gnut | 1 + .../mod/scripts/vscripts/weapons/_arc_cannon.nut | 1085 ++++++++++---------- .../vscripts/weapons/mp_titanweapon_arc_cannon.nut | 223 ++-- .../scripts/weapons/mp_titanweapon_arc_cannon.txt | 208 ++-- 7 files changed, 831 insertions(+), 690 deletions(-) create mode 100644 Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl create mode 100644 Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index ca33fa22..5fcdb0fd 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -38,6 +38,10 @@ "Path": "weapons/mp_weapon_peacekraber.nut", "RunOn": "( CLIENT || SERVER ) && MP" }, + { + "Path": "weapons/mp_titanweapon_arc_cannon.nut", + "RunOn": "( CLIENT || SERVER ) && MP" + }, { "Path": "gamemodes/sh_gamemode_chamber.nut", "RunOn": "( CLIENT || SERVER ) && MP", diff --git a/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl new file mode 100644 index 00000000..ec920318 Binary files /dev/null and b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl differ diff --git a/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl new file mode 100644 index 00000000..498cf0e8 Binary files /dev/null and b/Northstar.Custom/mod/models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl differ diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut index 79e64684..b8d4b1ba 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_custom_precache.gnut @@ -4,6 +4,7 @@ void function NorthstarCustomPrecache() { PrecacheWeapon( "mp_weapon_peacekraber" ) PrecacheWeapon( "mp_titanweapon_triplethreat" ) + PrecacheWeapon( "mp_titanweapon_arc_cannon" ) PrecacheWeapon( "melee_pilot_kunai" ) RegisterWeaponDamageSources( diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut index 4268422e..cd58ef06 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -1,257 +1,218 @@ +untyped + +global function ArcCannon_Init + +global function ArcCannon_PrecacheFX +global function ArcCannon_Start +global function ArcCannon_Stop +global function ArcCannon_ChargeBegin +global function ArcCannon_ChargeEnd +global function FireArcCannon +global function ArcCannon_HideIdleEffect +#if SERVER + global function AddToArcCannonTargets + global function RemoveArcCannonTarget + global function ConvertTitanShieldIntoBonusCharge +#endif +global function GetArcCannonChargeFraction + +global function IsEntANeutralMegaTurret +global function CreateArcCannonBeam + // Aiming & Range -const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain -const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency ) -const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another -const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another -const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge -const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge -const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon -const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets -const ARC_CANNON_FORK_DELAY = 0.1 - -const ARC_CANNON_RANGE_CHAIN_BURN = 400 -const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900 -const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge -const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge -const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon -const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets -const ARC_CANNON_BEAM_LIFETIME_BURN = 1 +global const DEFAULT_ARC_CANNON_FOVDOT = 0.98 // First target must be within this dot to be zapped and start a chain +global const DEFAULT_ARC_CANNON_FOVDOT_MISSILE = 0.95 // First target must be within this dot to be zapped and start a chain ( if it's a missile, we allow more leaniency ) +global const ARC_CANNON_RANGE_CHAIN = 400 // Max distance we can arc from one target to another +global const ARC_CANNON_TITAN_RANGE_CHAIN = 900 // Max distance we can arc from one target to another +global const ARC_CANNON_CHAIN_COUNT_MIN = 5 // Max number of chains at no charge +global const ARC_CANNON_CHAIN_COUNT_MAX = 5 // Max number of chains at full charge +global const ARC_CANNON_CHAIN_COUNT_NPC = 2 // Number of chains when an NPC fires the weapon +global const ARC_CANNON_FORK_COUNT_MAX = 1 // Number of forks that can come out of one target to other targets +global const ARC_CANNON_FORK_DELAY = 0.1 + +global const ARC_CANNON_RANGE_CHAIN_BURN = 400 +global const ARC_CANNON_TITAN_RANGE_CHAIN_BURN = 900 +global const ARC_CANNON_CHAIN_COUNT_MIN_BURN = 100 // Max number of chains at no charge +global const ARC_CANNON_CHAIN_COUNT_MAX_BURN = 100 // Max number of chains at full charge +global const ARC_CANNON_CHAIN_COUNT_NPC_BURN = 10 // Number of chains when an NPC fires the weapon +global const ARC_CANNON_FORK_COUNT_MAX_BURN = 10 // Number of forks that can come out of one target to other targets +global const ARC_CANNON_BEAM_LIFETIME_BURN = 1 // Visual settings -const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol ) -const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol ) -const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge -const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge -const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC -const ARC_CANNON_BEAM_COLOR = "150 190 255" -const ARC_CANNON_BEAM_LIFETIME = 0.75 +global const ARC_CANNON_BOLT_RADIUS_MIN = 32 // Bolt radius at no charge ( not actually sure what this does to the beam lol ) +global const ARC_CANNON_BOLT_RADIUS_MAX = 640 // Bold radius at full charge ( not actually sure what this does to the beam lol ) +global const ARC_CANNON_BOLT_WIDTH_MIN = 1 // Bolt width at no charge +global const ARC_CANNON_BOLT_WIDTH_MAX = 26 // Bolt width at full charge +global const ARC_CANNON_BOLT_WIDTH_NPC = 8 // Bolt width when used by NPC +global const ARC_CANNON_BEAM_COLOR = "150 190 255" +global const ARC_CANNON_BEAM_LIFETIME = 0.75 // Player Effects -const ARC_CANNON_TITAN_SCREEN_SFX = "Weapon_R1_LaserMine.Activate" -const ARC_CANNON_PILOT_SCREEN_SFX = "Weapon_R1_LaserMine.Activate" -const ARC_CANNON_EMP_DURATION_MIN = 0.1 -const ARC_CANNON_EMP_DURATION_MAX = 1.8 -const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4 -const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.025 -const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.075 -const ARC_CANNON_SCREEN_THRESHOLD = 0.3385 -const ARC_CANNON_SLOW_SCALE_MIN = 0.8 -const ARC_CANNON_SLOW_SCALE_MAX = 0.7 -const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2 - -// Rumble -const ARC_CANNON_RUMBLE_CHARGE_MIN = 5 -const ARC_CANNON_RUMBLE_CHARGE_MAX = 50 -const ARC_CANNON_RUMBLE_TYPE_INDEX = 14 // These are defined in code, 14 = RUMBLE_FLAT_BOTH +global const ARC_CANNON_TITAN_SCREEN_SFX = "Null_Remove_SoundHook" +global const ARC_CANNON_PILOT_SCREEN_SFX = "Null_Remove_SoundHook" +global const ARC_CANNON_EMP_DURATION_MIN = 0.1 +global const ARC_CANNON_EMP_DURATION_MAX = 1.8 +global const ARC_CANNON_EMP_FADEOUT_DURATION = 0.4 +global const ARC_CANNON_SCREEN_EFFECTS_MIN = 0.01 +global const ARC_CANNON_SCREEN_EFFECTS_MAX = 0.02 +global const ARC_CANNON_SCREEN_THRESHOLD = 0.3385 +global const ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION = 0.2 // Damage -const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep -const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage. -const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage. -const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0 +global const ARC_CANNON_DAMAGE_FALLOFF_SCALER = 0.75 // Amount of damage carried on to the next target in the chain lightning. If 0.75, then a target that would normally take 100 damage will take 75 damage if they are one chain deep, or 56 damage if 2 levels deep +global const ARC_CANNON_DAMAGE_CHARGE_RATIO = 0.85 // What amount of charge is required for full damage. +global const ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN = 0.676 // What amount of charge is required for full damage. +global const ARC_CANNON_CAPACITOR_CHARGE_RATIO = 1.0 // Options -const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon +global const ARC_CANNON_TARGETS_MISSILES = 1 // 1 = arc cannon zaps missiles that are active, 0 = missiles are ignored by arc cannon //Mods -const OVERCHARGE_MAX_SHIELD_DECAY = 0.2 -const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04 -const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05 - -const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6 -const SPLITTER_FORK_COUNT_MAX = 10 - -const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated" -RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED ) - -const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd" -RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND ) - -const ARC_CANNON_BEAM_EFFECT = "wpn_arc_cannon_beam" -PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT ) - -const ARC_CANNON_BEAM_EFFECT_MOD = "wpn_arc_cannon_beam_mod" -PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD ) +global const OVERCHARGE_MAX_SHIELD_DECAY = 0.2 +global const OVERCHARGE_SHIELD_DECAY_MULTIPLIER = 0.04 +global const OVERCHARGE_BONUS_CHARGE_FRACTION = 0.05 + +global const SPLITTER_DAMAGE_FALLOFF_SCALER = 0.6 +global const SPLITTER_FORK_COUNT_MAX = 10 + +global const ARC_CANNON_SIGNAL_DEACTIVATED = "ArcCannonDeactivated" +global const ARC_CANNON_SIGNAL_CHARGEEND = "ArcCannonChargeEnd" + +global const ARC_CANNON_BEAM_EFFECT = $"wpn_arc_cannon_beam" +global const ARC_CANNON_BEAM_EFFECT_MOD = $"wpn_arc_cannon_beam_mod" + +global const ARC_CANNON_FX_TABLE = "exp_arc_cannon" + +global const ArcCannonTargetClassnames = { + [ "npc_drone" ] = true, + [ "npc_dropship" ] = true, + [ "npc_marvin" ] = true, + [ "npc_prowler" ] = true, + [ "npc_soldier" ] = true, + [ "npc_soldier_heavy" ] = true, + [ "npc_soldier_shield" ] = true, + [ "npc_spectre" ] = true, + [ "npc_stalker" ] = true, + [ "npc_super_spectre" ] = true, + [ "npc_titan" ] = true, + [ "npc_turret_floor" ] = true, + [ "npc_turret_mega" ] = true, + [ "npc_turret_sentry" ] = true, + [ "npc_frag_drone" ] = true, + [ "player" ] = true, + [ "prop_dynamic" ] = true, + [ "prop_script" ] = true, + [ "grenade_frag" ] = true, + [ "rpg_missile" ] = true, + [ "script_mover" ] = true, + [ "turret" ] = true, +} -const ARC_CANNON_FX_TABLE = "exp_arc_cannon" -PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE ) +struct { + array missileCheckTargetnames = [ + // "Arc Pylon", + "Arc Ball" + ] +} file; -if ( !reloadingScripts ) +function ArcCannon_Init() { - // Valid Arc Cannon Target Classnames - level.arcCannonTargetClassnames <- {} - level.arcCannonTargetClassnames[ "npc_turret_floor" ] <- true - level.arcCannonTargetClassnames[ "npc_spectre" ] <- true - level.arcCannonTargetClassnames[ "npc_soldier_shield" ] <- true - level.arcCannonTargetClassnames[ "npc_soldier_heavy" ] <- true - level.arcCannonTargetClassnames[ "npc_soldier" ] <- true - level.arcCannonTargetClassnames[ "npc_cscanner" ] <- true - level.arcCannonTargetClassnames[ "npc_titan" ] <- true - level.arcCannonTargetClassnames[ "npc_marvin" ] <- true - level.arcCannonTargetClassnames[ "player" ] <- true - level.arcCannonTargetClassnames[ "script_mover" ] <- true - level.arcCannonTargetClassnames[ "npc_grenade_frag" ] <- true - level.arcCannonTargetClassnames[ "rpg_missile" ] <- true - level.arcCannonTargetClassnames[ "npc_turret_mega" ] <- true - level.arcCannonTargetClassnames[ "npc_turret_sentry" ] <- true - level.arcCannonTargetClassnames[ "npc_dropship" ] <- true - level.arcCannonTargetClassnames[ "prop_dynamic" ] <- true -} + RegisterSignal( ARC_CANNON_SIGNAL_DEACTIVATED ) + RegisterSignal( ARC_CANNON_SIGNAL_CHARGEEND ) + PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT ) + PrecacheParticleSystem( ARC_CANNON_BEAM_EFFECT_MOD ) + PrecacheImpactEffectTable( ARC_CANNON_FX_TABLE ) -function main() -{ - Globalize( ArcCannon_PrecacheFX ) - Globalize( ArcCannon_Start ) - Globalize( ArcCannon_Stop ) - Globalize( ArcCannon_ChargeBegin ) - Globalize( ArcCannon_ChargeEnd ) - Globalize( FireArcCannon ) - Globalize( ArcCannon_HideIdleEffect ) - Globalize( AddToArcCannonTargets ) - Globalize( ConvertTitanShieldIntoBonusCharge ) - Globalize( GetArcCannonChargeFraction ) - Globalize( StopChargeEffects ) - - if( IsClient() ) - { + #if CLIENT AddDestroyCallback( "mp_titanweapon_arc_cannon", ClientDestroyCallback_ArcCannon_Stop ) - } - else - { + #else level._arcCannonTargetsArrayID <- CreateScriptManagedEntArray() - } + #endif - PrecacheParticleSystem( "impact_arc_cannon_titan" ) + PrecacheParticleSystem( $"impact_arc_cannon_titan" ) } -function ArcCannon_PrecacheFX( weapon ) +function ArcCannon_PrecacheFX() { - if ( WeaponIsPrecached( weapon ) ) - return - - PrecacheParticleSystem( "wpn_arc_cannon_electricity_fp" ) - PrecacheParticleSystem( "wpn_arc_cannon_electricity" ) - - PrecacheParticleSystem( "wpn_ARC_knob_FP" ) - PrecacheParticleSystem( "wpn_ARC_knob" ) + PrecacheParticleSystem( $"wpn_arc_cannon_electricity_fp" ) + PrecacheParticleSystem( $"wpn_arc_cannon_electricity" ) - PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" ) - PrecacheParticleSystem( "wpn_arc_cannon_charge" ) - - PrecacheParticleSystem( "wpn_arc_cannon_charge_fp" ) - PrecacheParticleSystem( "wpn_arc_cannon_charge" ) - - PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon_fp" ) - PrecacheParticleSystem( "wpn_muzzleflash_arc_cannon" ) + PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon_fp" ) + PrecacheParticleSystem( $"wpn_muzzleflash_arc_cannon" ) } function ArcCannon_Start( weapon ) { - weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" ) - weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) + expect entity( weapon ) + if ( !IsPilot( weapon.GetWeaponOwner() ) ) + { + weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" ) + weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) + } + else + { + weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" ) + } } function ArcCannon_Stop( weapon, player = null ) { + expect entity( weapon ) weapon.Signal( ARC_CANNON_SIGNAL_DEACTIVATED ) - StopChargeEffects( weapon, player ) - weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" ) + weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" ) weapon.StopWeaponSound( "arc_cannon_charged_loop" ) - weapon.StopWeaponSound( "arc_cannon_charge" ) } -function ArcCannon_ChargeBegin( weapon ) +function ArcCannon_ChargeBegin( entity weapon ) { - local weaponOwner = weapon.GetWeaponOwner() - local weaponScriptScope = weapon.GetScriptScope() - local useNormalChargeSounds = true - if( weapon.HasMod( "overcharge" ) ) - { - if ( weaponOwner.IsTitan() ) + #if SERVER + if ( weapon.HasMod( "overcharge" ) ) { - local soul = weaponOwner.GetTitanSoul() - if ( soul.GetShieldHealth() > 0 ) + entity weaponOwner = weapon.GetWeaponOwner() + if ( weaponOwner.IsTitan() ) { - weapon.EmitWeaponSound( "arc_cannon_fastcharge" ) - useNormalChargeSounds = false - } - if ( IsServer() ) + entity soul = weaponOwner.GetTitanSoul() thread ConvertTitanShieldIntoBonusCharge( soul, weapon ) + } } - } + #endif - if ( useNormalChargeSounds ) - { - weapon.EmitWeaponSound( "arc_cannon_charge" ) - } - - if( !("maxChargeTime" in weapon.s) ) - weapon.s.maxChargeTime <- weapon.GetWeaponModSetting( "charge_time" ) - - weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge", "muzzle_flash" ) - local chargeTime = weapon.GetWeaponChargeTime() - - if ( IsClient() ) - { + #if CLIENT if ( !weapon.ShouldPredictProjectiles() ) return - if ( weaponOwner.IsPlayer() ) - weaponOwner.StartArcCannon(); - - local handle = weapon.AllocateHandleForViewmodelEffect( "wpn_arc_cannon_charge_fp" ) - if ( handle ) - EffectSkipForwardToTime( handle, chargeTime ) - - thread cl_ChargeRumble( weapon, ARC_CANNON_RUMBLE_TYPE_INDEX, ARC_CANNON_RUMBLE_CHARGE_MIN, ARC_CANNON_RUMBLE_CHARGE_MAX, ARC_CANNON_SIGNAL_CHARGEEND ) - } - thread ChargeEffects( weapon ) + entity weaponOwner = weapon.GetWeaponOwner() + Assert( weaponOwner.IsPlayer() ) + weaponOwner.StartArcCannon(); + #endif } -function ArcCannon_ChargeEnd( weapon, player = null ) +function ArcCannon_ChargeEnd( entity weapon, entity player = null ) { - if ( IsClient() && weapon.GetWeaponOwner() == GetLocalViewPlayer() ) - { - local weaponOwner - if ( player != null ) - weaponOwner = player - else - weaponOwner = weapon.GetWeaponOwner() - - if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() ) - weaponOwner.StopArcCannon() - } - if( IsValid( weapon ) ) - StopChargeEffects( weapon ) -} + #if SERVER + if ( IsValid( weapon ) ) + weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND ) + #endif -function StopChargeEffects( weapon, player = null ) -{ - weapon.Signal( ARC_CANNON_SIGNAL_CHARGEEND ) - - local weaponScriptScope = weapon.GetScriptScope() - weapon.StopWeaponSound( "arc_cannon_charge" ) - weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" ) - weapon.StopWeaponSound( "arc_cannon_fastcharge" ) - //weapon.StopWeaponEffect( "wpn_arc_cannon_charge_fp", "wpn_arc_cannon_charge" ) - weapon.StopWeaponEffect( "wpn_ARC_knob_FP", "wpn_ARC_knob" ) -} - -function ChargeEffects( weapon ) -{ - weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND ) - weapon.EndSignal( "OnDestroy" ) - - local player = weapon.GetWeaponOwner() - - wait ( weapon.s.maxChargeTime * GetArcCannonChargeFraction( weapon ) ) + #if CLIENT + if ( weapon.GetWeaponOwner() == GetLocalViewPlayer() ) + { + entity weaponOwner + if ( player != null ) + weaponOwner = player + else + weaponOwner = weapon.GetWeaponOwner() - weapon.PlayWeaponEffectNoCull( "wpn_ARC_knob_FP", "wpn_ARC_knob", "SPINNING_KNOB" ) + if ( IsValid( weaponOwner ) && weaponOwner.IsPlayer() ) + weaponOwner.StopArcCannon() + } + #endif } -function ConvertTitanShieldIntoBonusCharge( soul, weapon ) +#if SERVER +function ConvertTitanShieldIntoBonusCharge( entity soul, entity weapon ) { weapon.EndSignal( ARC_CANNON_SIGNAL_CHARGEEND ) weapon.EndSignal( "OnDestroy" ) @@ -259,19 +220,19 @@ function ConvertTitanShieldIntoBonusCharge( soul, weapon ) local maxShieldDecay = OVERCHARGE_MAX_SHIELD_DECAY local bonusChargeFraction = OVERCHARGE_BONUS_CHARGE_FRACTION local shieldDecayMultiplier = OVERCHARGE_SHIELD_DECAY_MULTIPLIER - local shieldHealthMax = soul.GetShieldHealthMax() + int shieldHealthMax = soul.GetShieldHealthMax() local chargeRatio = GetArcCannonChargeFraction( weapon ) while( 1 ) { - if( !IsValid( soul ) || !IsValid( weapon ) ) + if ( !IsValid( soul ) || !IsValid( weapon ) ) break - local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction() + local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction() local charge = clamp ( baseCharge * ( 1 / chargeRatio ), 0.0, 1.0 ) - if( charge < 1.0 || maxShieldDecay > 0) + if ( charge < 1.0 || maxShieldDecay > 0) { - local shieldHealth = soul.GetShieldHealth() + int shieldHealth = soul.GetShieldHealth() //Slight inconsistency in server updates, this ensures it never takes too much. if ( shieldDecayMultiplier > maxShieldDecay ) @@ -281,42 +242,27 @@ function ConvertTitanShieldIntoBonusCharge( soul, weapon ) local shieldDecayAmount = shieldHealthMax * shieldDecayMultiplier local newShieldAmount = shieldHealth - shieldDecayAmount soul.SetShieldHealth( max( newShieldAmount, 0 ) ) - soul.s.nextRegenTime = Time() + TITAN_SHIELD_REGEN_DELAY + soul.nextRegenTime = Time() + GetShieldRegenTime( soul ) - if( shieldDecayAmount > shieldHealth ) + if ( shieldDecayAmount > shieldHealth ) bonusChargeFraction = bonusChargeFraction * ( shieldHealth / shieldDecayAmount ) weapon.SetWeaponChargeFraction( baseCharge + bonusChargeFraction ) } wait 0.1 } } +#endif -function FireArcCannon( weapon, attackParams ) +function FireArcCannon( entity weapon, WeaponPrimaryAttackParams attackParams ) { local weaponScriptScope = weapon.GetScriptScope() - local owner = weapon.GetWeaponOwner() - - local baseCharge = weapon.GetWeaponChargeFraction() // + GetOverchargeBonusChargeFraction() - local charge = clamp ( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 ) - local newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 ) - if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) - { - weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot_Amped" ) - weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_fire_BigShot_Amped", newVolume ) - } - else - { - weapon.EmitWeaponSound( "arc_cannon_fire_SmallShot" ) - weaponScriptScope.PlayWeaponSoundWithVolume( "arc_cannon_Fire_BigShot", newVolume ) - } - - weapon.StopWeaponSound( "arc_cannon_charged_loop" ) + local baseCharge = GetWeaponChargeFrac( weapon ) // + GetOverchargeBonusChargeFraction() + local charge = clamp( baseCharge * ( 1 / GetArcCannonChargeFraction( weapon ) ), 0.0, 1.0 ) + float newVolume = GraphCapped( charge, 0.25, 1.0, 0.0, 1.0 ) weapon.EmitWeaponNpcSound( LOUD_WEAPON_AI_SOUND_RADIUS_MP, 0.2 ) - weapon.PlayWeaponEffect( "wpn_muzzleflash_arc_cannon_fp", "wpn_muzzleflash_arc_cannon", "muzzle_flash" ) - - StopChargeEffects( weapon ) + weapon.PlayWeaponEffect( $"wpn_muzzleflash_arc_cannon_fp", $"wpn_muzzleflash_arc_cannon", "muzzle_flash" ) local attachmentName = "muzzle_flash" local attachmentIndex = weapon.LookupAttachment( attachmentName ) @@ -325,7 +271,7 @@ function FireArcCannon( weapon, attackParams ) //printt( "-------- FIRING ARC CANNON --------" ) - local firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams ) + table firstTargetInfo = GetFirstArcCannonTarget( weapon, attackParams ) if ( !IsValid( firstTargetInfo.target ) ) FireArcNoTargets( weapon, attackParams, muzzleOrigin ) else @@ -334,63 +280,71 @@ function FireArcCannon( weapon, attackParams ) return 1 } -function GetFirstArcCannonTarget( weapon, attackParams ) +table function GetFirstArcCannonTarget( entity weapon, WeaponPrimaryAttackParams attackParams ) { - local owner = weapon.GetWeaponOwner() + entity owner = weapon.GetWeaponOwner() local coneHeight = weapon.GetMaxDamageFarDist() - local angleToAxis = 8 // set this too high and auto-titans using it will error on GetVisibleEntitiesInCone - local ignoredEntities = [ owner, weapon ] - local traceMask = TRACE_MASK_SHOT - local flags = VIS_CONE_ENTS_TEST_HITBOXES // | VIS_CONE_ENTS_IGNORE_VORTEX + local angleToAxis = 2 // set this too high and auto-titans using it will error on FindVisibleEntitiesInCone + array ignoredEntities = [ owner, weapon ] + int traceMask = TRACE_MASK_SHOT + int flags = VIS_CONE_ENTS_TEST_HITBOXES local antilagPlayer = null if ( owner.IsPlayer() ) { - angleToAxis = owner.GetAttackSpreadAngle() * 0.095 + angleToAxis = owner.GetAttackSpreadAngle() * 0.11 antilagPlayer = owner } - local results - local ownerTeam = owner.GetTeam() + int ownerTeam = owner.GetTeam() // Get a missile target and a non-missile target in the cone that the player can zap // We do this in a separate check so we can use a wider cone to be more forgiving for targeting missiles - local firstTargetInfo = {} + table firstTargetInfo = {} firstTargetInfo.target <- null firstTargetInfo.hitLocation <- null - for ( local i = 0 ; i < 2 ; i++ ) + + for ( int i = 0; i < 2; i++ ) { local missileCheck = i == 0 local coneAngle = angleToAxis - if ( missileCheck ) - coneAngle *= 3.0 + if ( missileCheck && owner.IsPlayer() ) // missile check only if owner is player + coneAngle *= 8.0 + + coneAngle = clamp( coneAngle, 0.1, 89.9 ) - results = GetVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer, false, false ) - foreach( result in results ) + array results = FindVisibleEntitiesInCone( attackParams.pos, attackParams.dir, coneHeight, coneAngle, ignoredEntities, traceMask, flags, antilagPlayer ) + foreach ( result in results ) { - local visibleEnt = result.entity + entity visibleEnt = result.ent if ( !IsValid( visibleEnt ) ) continue - local classname = IsServer() ? visibleEnt.GetClassname() : visibleEnt.GetSignifierName() + if ( visibleEnt.IsPhaseShifted() ) + continue - if ( !( classname in level.arcCannonTargetClassnames ) ) + local classname = IsServer() ? visibleEnt.GetClassName() : visibleEnt.GetSignifierName() + + if ( !( classname in ArcCannonTargetClassnames ) ) continue if ( "GetTeam" in visibleEnt ) { - local visibleEntTeam = visibleEnt.GetTeam() + int visibleEntTeam = visibleEnt.GetTeam() if ( visibleEntTeam == ownerTeam ) continue if ( IsEntANeutralMegaTurret( visibleEnt, ownerTeam ) ) continue } - if ( missileCheck && classname != "rpg_missile" ) + expect string( classname ) + string targetname = visibleEnt.GetTargetName() + + if ( missileCheck && ( classname != "rpg_missile" && !file.missileCheckTargetnames.contains( targetname ) ) ) continue - if ( !missileCheck && classname == "rpg_missile" ) + if ( !missileCheck && ( classname == "rpg_missile" || file.missileCheckTargetnames.contains( targetname ) ) ) continue firstTargetInfo.target = visibleEnt @@ -399,50 +353,78 @@ function GetFirstArcCannonTarget( weapon, attackParams ) } } //Creating a whiz-by sound. - weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true ) + weapon.FireWeaponBullet_Special( attackParams.pos, attackParams.dir, 1, 0, true, true, true, true, true, false, false ) return firstTargetInfo } -function FireArcNoTargets( weapon, attackParams, muzzleOrigin ) +function FireArcNoTargets( entity weapon, WeaponPrimaryAttackParams attackParams, muzzleOrigin ) { Assert( IsValid( weapon ) ) - local player = weapon.GetWeaponOwner() - local chargeFrac = weapon.GetWeaponChargeFraction() + entity player = weapon.GetWeaponOwner() + local chargeFrac = GetWeaponChargeFrac( weapon ) local beamVec = attackParams.dir * weapon.GetMaxDamageFarDist() local playerEyePos = player.EyePosition() - local traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + TraceResults traceResults = TraceLineHighDetail( playerEyePos, (playerEyePos + beamVec), weapon, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) local beamEnd = traceResults.endPos - local vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd ) + VortexBulletHit ornull vortexHit = VortexBulletHitCheck( player, playerEyePos, beamEnd ) if ( vortexHit ) { - if( IsServer() ) - { - local vortexWeapon = vortexHit.vortex.GetOwnerWeapon() - if( vortexWeapon && vortexWeapon.GetClassname() == "mp_titanweapon_vortex_shield" ) - VortexDrainedByImpact( vortexWeapon, weapon, null, null ) - } + expect VortexBulletHit( vortexHit ) + #if SERVER + entity vortexWeapon = vortexHit.vortex.GetOwnerWeapon() + string className = IsValid( vortexWeapon ) ? vortexWeapon.GetWeaponClassName() : "" + if ( vortexWeapon && ( className == "mp_titanweapon_vortex_shield" || className == "mp_titanweapon_vortex_shield_ion" ) ) + { + float amount = expect float ( chargeFrac ) * weapon.GetWeaponSettingFloat( eWeaponVar.vortex_drain ) + if ( amount <= 0.0 ) + return + + if ( vortexWeapon.GetWeaponClassName() == "mp_titanweapon_vortex_shield_ion" ) + { + entity owner = vortexWeapon.GetWeaponOwner() + int totalEnergy = owner.GetSharedEnergyTotal() + owner.TakeSharedEnergy( int( float( totalEnergy ) * amount ) ) + } + else + { + float frac = min ( vortexWeapon.GetWeaponChargeFraction() + amount, 1.0 ) + vortexWeapon.SetWeaponChargeFraction( frac ) + } + } + else if ( IsVortexSphere( vortexHit.vortex ) ) + { + // do damage to vortex_sphere entities that isn't the titan "vortex shield" + local damageNear = weapon.GetWeaponInfoFileKeyField( "damage_near_value" ) + local damage = damageNear * GraphCapped( chargeFrac, 0, 1, 0.0, 1.0 ) * 10 // do more damage the more charged the weapon is. + VortexSphereDrainHealthForDamage( vortexHit.vortex, damage ) + if ( IsValid( player ) && player.IsPlayer() ) + player.NotifyDidDamage( vortexHit.vortex, 0, vortexHit.hitPos, 0, damage, DF_NO_HITBEEP, 0, null, 0 ) + } + #endif beamEnd = vortexHit.hitPos } - local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) + float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX ) if ( player.IsNPC() ) boltWidth = ARC_CANNON_BOLT_WIDTH_NPC thread CreateArcCannonBeam( weapon, null, muzzleOrigin, beamEnd, player, ARC_CANNON_BEAM_LIFETIME, radius, boltWidth, 2, false, true ) - if( IsServer() ) - CreateExplosion( beamEnd, 0, 0, 1, 1, player, 0, null, -1, false, ARC_CANNON_FX_TABLE ) + + #if SERVER + PlayImpactFXTable( expect vector( beamEnd ), player, ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES ) + #endif } -function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin ) +function FireArcWithTargets( entity weapon, table firstTargetInfo, WeaponPrimaryAttackParams attackParams, muzzleOrigin ) { local beamStart = muzzleOrigin local beamEnd - local player = weapon.GetWeaponOwner() - local chargeFrac = weapon.GetWeaponChargeFraction() - local radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) - local boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX ) + entity player = weapon.GetWeaponOwner() + local chargeFrac = GetWeaponChargeFrac( weapon ) + float radius = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_RADIUS_MIN, ARC_CANNON_BOLT_RADIUS_MAX ) + float boltWidth = Graph( chargeFrac, 0, 1, ARC_CANNON_BOLT_WIDTH_MIN, ARC_CANNON_BOLT_WIDTH_MAX ) local maxChains local minChains @@ -468,7 +450,7 @@ function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin if ( !player.IsNPC() ) maxChains = Graph( chargeFrac, 0, 1, minChains, maxChains ) - local zapInfo = {} + table zapInfo = {} zapInfo.weapon <- weapon zapInfo.player <- player zapInfo.muzzleOrigin <- muzzleOrigin @@ -478,11 +460,12 @@ function FireArcWithTargets( weapon, firstTargetInfo, attackParams, muzzleOrigin zapInfo.chargeFrac <- chargeFrac zapInfo.zappedTargets <- {} zapInfo.zappedTargets[ firstTargetInfo.target ] <- true + zapInfo.dmgSourceID <- weapon.GetDamageSourceID() local chainNum = 1 - thread ZapTargetRecursive( firstTargetInfo.target, zapInfo, zapInfo.muzzleOrigin, firstTargetInfo.hitLocation, chainNum ) + thread ZapTargetRecursive( expect entity( firstTargetInfo.target), zapInfo, zapInfo.muzzleOrigin, expect vector( firstTargetInfo.hitLocation ), chainNum ) } -function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPos = null, chainNum = 1 ) +function ZapTargetRecursive( entity target, table zapInfo, beamStartPos, vector ornull firstTargetBeamEndPos = null, chainNum = 1 ) { if ( !IsValid( target ) ) return @@ -493,28 +476,30 @@ function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPo Assert( target in zapInfo.zappedTargets ) if ( chainNum > zapInfo.maxChains ) return - local beamEndPos + vector beamEndPos if ( firstTargetBeamEndPos == null ) beamEndPos = target.GetWorldSpaceCenter() else - beamEndPos = firstTargetBeamEndPos + beamEndPos = expect vector( firstTargetBeamEndPos ) waitthread ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum ) // Get other nearby targets we can chain to - if ( IsServer() ) - { - if ( !IsValid( target ) ) - return + #if SERVER + if ( !IsValid( zapInfo.weapon ) ) + return + + var noArcing = expect entity( zapInfo.weapon ).GetWeaponInfoFileKeyField( "disable_arc" ) - if ( !IsValid( zapInfo.weapon ) ) - return + if ( noArcing != null && noArcing == 1 ) + return // no chaining on new arc cannon - local chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo ) - foreach( chainTarget in chainTargets ) + // NOTE: 'target' could be invalid at this point (no corpse) + array chainTargets = GetArcCannonChainTargets( beamEndPos, target, zapInfo ) + foreach( entity chainTarget in chainTargets ) { local newChainNum = chainNum - if( !chainTarget.GetClassname() != "rpg_missile" ) + if ( chainTarget.GetClassName() != "rpg_missile" ) newChainNum++ zapInfo.zappedTargets[ chainTarget ] <- true thread ZapTargetRecursive( chainTarget, zapInfo, beamEndPos, null, newChainNum ) @@ -522,203 +507,257 @@ function ZapTargetRecursive( target, zapInfo, beamStartPos, firstTargetBeamEndPo if ( IsValid( zapInfo.player ) && zapInfo.player.IsPlayer() && zapInfo.zappedTargets.len() >= 5 ) { - if ( PlayerProgressionAllowed( zapInfo.player ) ) - zapInfo.player.SetPersistentVar( "ach_multikillArcRifle", true ) + #if HAS_STATS if ( chainNum == 5 ) - UpdatePlayerStat( zapInfo.player, "misc_stats", "arcCannonMultiKills", 1 ) + UpdatePlayerStat( expect entity( zapInfo.player ), "misc_stats", "arcCannonMultiKills", 1 ) + #endif } - } + #endif } function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) { + expect entity( target ) + expect vector( beamStartPos ) + expect vector( beamEndPos ) + //DebugDrawLine( beamStartPos, beamEndPos, 255, 0, 0, true, 5.0 ) local boltWidth = zapInfo.boltWidth if ( zapInfo.player.IsNPC() ) boltWidth = ARC_CANNON_BOLT_WIDTH_NPC local firstBeam = ( chainNum == 1 ) - if( firstBeam && IsServer() ) - CreateExplosion( beamEndPos, 0, 0, 1, 1, zapInfo.player, 0, null, -1, false, ARC_CANNON_FX_TABLE ) + #if SERVER + if ( firstBeam ) + { + PlayImpactFXTable( beamEndPos, expect entity( zapInfo.player ), ARC_CANNON_FX_TABLE, SF_ENVEXPLOSION_INCLUDE_ENTITIES ) + } + #endif + thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam ) - if ( IsClient() ) - return + #if SERVER + local isMissile = ( target.GetClassName() == "rpg_missile" ) + if ( !isMissile ) + wait ARC_CANNON_FORK_DELAY + else + wait 0.05 - local isMissile = ( target.GetClassname() == "rpg_missile" ) - if( !isMissile ) - wait ARC_CANNON_FORK_DELAY - else - wait 0.05 + local deathPackage = damageTypes.arcCannon - local deathPackage = damageTypes.ArcCannon + float damageAmount + int damageMin + int damageMax - local damageAmount - local damageMin - local damageMax + int damageFarValue = eWeaponVar.damage_far_value + int damageNearValue = eWeaponVar.damage_near_value + int damageFarValueTitanArmor = eWeaponVar.damage_far_value_titanarmor + int damageNearValueTitanArmor = eWeaponVar.damage_near_value_titanarmor + if ( zapInfo.player.IsNPC() ) + { + damageFarValue = eWeaponVar.npc_damage_far_value + damageNearValue = eWeaponVar.npc_damage_near_value + damageFarValueTitanArmor = eWeaponVar.npc_damage_far_value_titanarmor + damageNearValueTitanArmor = eWeaponVar.npc_damage_near_value_titanarmor + } - if ( IsValid( target ) && IsValid( zapInfo.player ) ) - { - if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) + if ( IsValid( target ) && IsValid( zapInfo.player ) ) { + bool hasFastPacitor = false + bool noArcing = false + if ( IsValid( zapInfo.weapon ) ) { - damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value_titanarmor" ) - damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value_titanarmor" ) + entity weap = expect entity( zapInfo.weapon ) + hasFastPacitor = weap.GetWeaponInfoFileKeyField( "push_apart" ) != null && weap.GetWeaponInfoFileKeyField( "push_apart" ) == 1 + noArcing = weap.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weap.GetWeaponInfoFileKeyField( "no_arcing" ) == 1 } - else + + if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) { - damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value_titanarmor" ) - damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value_titanarmor" ) + if ( IsValid( zapInfo.weapon ) ) + { + entity weapon = expect entity( zapInfo.weapon ) + damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor ) + damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor ) + } + else + { + damageMin = 100 + damageMax = zapInfo.player.IsNPC() ? 1200 : 800 + } } - - // Due to auto-titans not charging, they do very little damage with this weapon against one another. - if ( zapInfo.player.IsNPC() ) + else { - damageMin *= 7.0 - damageMax *= 7.0 + if ( IsValid( zapInfo.weapon ) ) + { + entity weapon = expect entity( zapInfo.weapon ) + damageMin = weapon.GetWeaponSettingInt( damageFarValue ) + damageMax = weapon.GetWeaponSettingInt( damageNearValue ) + } + else + { + damageMin = 120 + damageMax = zapInfo.player.IsNPC() ? 140 : 275 + } + + if ( target.IsNPC() ) + { + damageMin *= 3 // more powerful against NPC humans so they die easy + damageMax *= 3 + } } - // HACK; temp fix for non titan heavy armor targets (e.g. mega turret) - } - else - { - if ( IsValid( zapInfo.weapon ) ) + + local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon ) + if ( IsValid( zapInfo.weapon ) && !zapInfo.weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) ) { - damageMin = zapInfo.weapon.GetWeaponModSetting( "damage_far_value" ) - damageMax = zapInfo.weapon.GetWeaponModSetting( "damage_near_value" ) + // use distance for damage if the weapon auto-fires + entity weapon = expect entity( zapInfo.weapon ) + float nearDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_near_distance ) + float farDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_far_distance ) + + float dist = Distance( weapon.GetOrigin(), target.GetOrigin() ) + damageAmount = GraphCapped( dist, farDist, nearDist, damageMin, damageMax ) } else { - damageMin = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_far_value" ) - damageMax = GetWeaponInfoFileKeyField_Global( "mp_titanweapon_arc_cannon", "damage_near_value" ) + // Scale damage amount based on how many chains deep we are + damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax ) } + local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER + if ( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) ) + damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER + damageAmount *= pow( damageFalloff, chainNum - 1 ) + + local dmgSourceID = zapInfo.dmgSourceID - if ( target.IsNPC() ) + // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target + // move to Damaged callback instead + if ( damageAmount > 0 ) { - damageMin *= 3.0 // more powerful against NPC humans so they die easy - damageMax *= 3.0 - } - } + float empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX ) + if ( target.IsPlayer() && target.IsTitan() && !hasFastPacitor && !noArcing ) + { + float empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX ) + + if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + { + Remote_CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) + EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX ) + } + else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + { + StatusEffect_AddTimed( target, eStatusEffect.emp, empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) + EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX ) + } + } - // Scale damage amount based on how many chains deep we are - local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon ) - damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax ) - local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER - if( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) ) - damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER - damageAmount *= pow( damageFalloff, chainNum - 1 ) + // Do 3rd person effect on the body + asset effect + string tag + target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = zapInfo.weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) } ) + //vector dir = Normalize( beamEndPos - beamStartPos ) + //vector velocity = dir * 600 + //PushPlayerAway( target, velocity ) + //PushPlayerAway( expect entity( zapInfo.player ), -velocity ) - local dmgSourceID = eDamageSourceId.mp_titanweapon_arc_cannon + if ( IsValid( zapInfo.weapon ) && hasFastPacitor ) + { + if ( IsAlive( target ) && IsAlive( expect entity( zapInfo.player ) ) && target.IsTitan() ) + { + float pushPercent = GraphCapped( damageAmount, damageMin, damageMax, 0.0, 1.0 ) - // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target - // move to Damaged callback instead - if( damageAmount > 0 ) - { - local empDuration = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_EMP_DURATION_MIN, ARC_CANNON_EMP_DURATION_MAX ) + if ( pushPercent > 0.6 ) + PushPlayersApart( target, expect entity( zapInfo.player ), pushPercent * 400.0 ) + } + } - if ( target.IsPlayer() ) - { - local empViewStrength = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SCREEN_EFFECTS_MIN, ARC_CANNON_SCREEN_EFFECTS_MAX ) + if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD ) + empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION + else + empDuration += ARC_CANNON_EMP_FADEOUT_DURATION - if ( target.IsTitan() && zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) { - Remote.CallFunction_Replay( target, "ServerCallback_TitanEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) - EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_TITAN_SCREEN_SFX ) - - local scale = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, ARC_CANNON_SLOW_SCALE_MIN, ARC_CANNON_SLOW_SCALE_MAX ) - thread EMP_SlowPlayer( target, scale, empDuration ) + effect = $"impact_arc_cannon_titan" + tag = "exp_torso_front" } - else if ( zapInfo.chargeFrac >= ARC_CANNON_SCREEN_THRESHOLD ) + else { - Remote.CallFunction_Replay( target, "ServerCallback_PilotEMP", empViewStrength, empDuration, ARC_CANNON_EMP_FADEOUT_DURATION ) - EmitSoundOnEntityOnlyToPlayer( target, target, ARC_CANNON_PILOT_SCREEN_SFX ) + effect = $"P_emp_body_human" + tag = "CHESTFOCUS" } - } - // Do 3rd person effect on the body - local effect = null - local tag = null - target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = zapInfo.player.GetOrigin(), force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID } ) + if ( target.IsPlayer() ) + { + if ( target.LookupAttachment( tag ) != 0 ) + ClientStylePlayFXOnEntity( effect, target, tag, empDuration ) + } - if ( zapInfo.chargeFrac < ARC_CANNON_SCREEN_THRESHOLD ) - empDuration = ARC_CANNON_3RD_PERSON_EFFECT_MIN_DURATION - else - empDuration += ARC_CANNON_EMP_FADEOUT_DURATION + if ( target.IsPlayer() ) + EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" ) + else + EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" ) - if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) - { - effect = "impact_arc_cannon_titan" - tag = "exp_torso_front" + thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 ) } else { - effect = "P_emp_body_human" - tag = "CHESTFOCUS" + //Don't bounce if the beam is set to do 0 damage. + chainNum = zapInfo.maxChains } - if ( target.IsPlayer() && effect != null && tag != null ) + if ( isMissile ) { - if ( target.LookupAttachment( tag ) != 0 ) - ClientStylePlayFXOnEntity( effect, target, tag, empDuration ) + if ( IsValid( zapInfo.player ) ) + target.SetOwner( zapInfo.player ) + target.MissileExplode() } - - if ( target.IsPlayer() ) - EmitSoundOnEntityExceptToPlayer( target, target, "Titan_Blue_Electricity_Cloud" ) - else - EmitSoundOnEntity( target, "Titan_Blue_Electricity_Cloud" ) - - thread FadeOutSoundOnEntityAfterDelay( target, "Titan_Blue_Electricity_Cloud", empDuration * 0.6666, empDuration * 0.3333 ) - } - else - { - //Don't bounce if the beam is set to do 0 damage. - chainNum = zapInfo.maxChains } - - if ( isMissile ) - { - if ( IsValid ( zapInfo.player ) ) - target.SetOwner( zapInfo.player ) - target.Explode() - } - } + #endif // SERVER } -function FadeOutSoundOnEntityAfterDelay( entity, soundAlias, delay, fadeTime ) -{ - - if ( !IsValid( entity ) ) - return +#if SERVER - entity.EndSignal( "OnDestroy" ) - wait delay - FadeOutSoundOnEntity( entity, soundAlias, fadeTime ) +void function PushEntForTime( entity ent, vector velocity, float time ) +{ + ent.EndSignal( "OnDeath" ) + float endTime = Time() + time + float startTime = Time() + for ( ;; ) + { + if ( Time() >= endTime ) + break + float multiplier = Graph( Time(), startTime, endTime, 1.0, 0.0 ) + vector currentVel = ent.GetVelocity() + currentVel += velocity * multiplier + ent.SetVelocity( currentVel ) + WaitFrame() + } } - -function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) +array function GetArcCannonChainTargets( vector fromOrigin, entity fromTarget, table zapInfo ) { - Assert( IsServer() ) - - local results = [] + // NOTE: fromTarget could be null/invalid if it was a drone + array results = [] if ( !IsValid( zapInfo.player ) ) return results - local playerTeam = zapInfo.player.GetTeam() - local allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, zapInfo.weapon ) + int playerTeam = expect entity( zapInfo.player ).GetTeam() + array allTargets = GetArcCannonTargetsInRange( fromOrigin, playerTeam, expect entity( zapInfo.weapon ) ) allTargets = ArrayClosest( allTargets, fromOrigin ) local viewVector if ( zapInfo.player.IsPlayer() ) viewVector = zapInfo.player.GetViewVector() else - viewVector = zapInfo.player.EyeAngles().AnglesToForward() + viewVector = AnglesToForward( zapInfo.player.EyeAngles() ) local eyePosition = zapInfo.player.EyePosition() - foreach( ent in allTargets ) + foreach ( ent in allTargets ) { local forkCount = ARC_CANNON_FORK_COUNT_MAX if ( zapInfo.weapon.HasMod( "splitter" ) ) @@ -729,21 +768,22 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) if ( results.len() >= forkCount ) break + if ( ent.IsPhaseShifted() ) + continue + if ( ent.IsPlayer() ) { - if ( ent.GetPlayerClass() == "operator" ) - continue - - if ( ent.GetPlayerClass() == "dronecontroller" ) - continue - // Ignore players that are passing damage to their parent. This is to address zapping a friendly rodeo player local entParent = ent.GetParent() if ( IsValid( entParent ) && ent.kv.PassDamageToParent.tointeger() ) continue + + // only chains to other titan players for now + if ( !ent.IsTitan() ) + continue } - if ( ent.GetClassname() == "script_mover" ) + if ( ent.GetClassName() == "script_mover" ) continue if ( IsEntANeutralMegaTurret( ent, playerTeam ) ) @@ -759,7 +799,7 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) //Preventing the arc-cannon from firing behind. local vecToEnt = ( ent.GetWorldSpaceCenter() - eyePosition ) vecToEnt.Norm() - local dotVal = vecToEnt.Dot( viewVector ) + local dotVal = DotProduct( vecToEnt, viewVector ) if ( dotVal < 0 ) continue @@ -774,17 +814,21 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) ignoreEnts.append( zappedTarget ) } - local traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + TraceResults traceResult = TraceLineHighDetail( fromOrigin, ent.GetWorldSpaceCenter(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) // Trace failed, lets try an eye to eye trace - if ( traceResult.fraction < 1 && IsValid( fromTarget ) ) - traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + if ( traceResult.fraction < 1 ) + { + // 'fromTarget' may be invalid + if ( IsValid( fromTarget ) ) + traceResult = TraceLineHighDetail( fromTarget.EyePosition(), ent.EyePosition(), ignoreEnts, (TRACE_MASK_PLAYERSOLID_BRUSHONLY | TRACE_MASK_BLOCKLOS), TRACE_COLLISION_GROUP_NONE ) + } if ( traceResult.fraction < 1 ) continue // Enemy is in visible, and within range. - if ( !IsValueInArray( results, ent ) ) + if ( !results.contains( ent ) ) results.append( ent ) } @@ -792,72 +836,85 @@ function GetArcCannonChainTargets( fromOrigin, fromTarget, zapInfo ) return results } -Globalize( GetArcCannonChainTargets ) - +#endif // SERVER -function IsEntANeutralMegaTurret( ent, playerTeam ) +bool function IsEntANeutralMegaTurret( ent, int playerTeam ) { - if ( ent.GetClassname() != "npc_turret_mega" ) + expect entity( ent ) + + if ( ent.GetClassName() != "npc_turret_mega" ) return false - local entTeam = ent.GetTeam() + int entTeam = ent.GetTeam() if ( entTeam == playerTeam ) return false - if ( entTeam != GetOtherTeam( playerTeam ) ) + if ( !IsEnemyTeam( playerTeam, entTeam ) ) return true return false } -Globalize( IsEntANeutralMegaTurret ) -function ArcCannon_HideIdleEffect( weapon, delay ) +function ArcCannon_HideIdleEffect( entity weapon, delay ) { - //printt( "HideIdleEffect" ) + bool weaponOwnerIsPilot = IsPilot( weapon.GetWeaponOwner() ) weapon.EndSignal( ARC_CANNON_SIGNAL_DEACTIVATED ) - weapon.StopWeaponEffect( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity" ) + if ( weaponOwnerIsPilot == false ) + { + weapon.StopWeaponEffect( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity" ) + weapon.StopWeaponSound( "arc_cannon_charged_loop" ) + } wait delay - if( !IsValid( weapon ) ) + if ( !IsValid( weapon ) ) return - local weaponOwner = weapon.GetWeaponOwner() + entity weaponOwner = weapon.GetWeaponOwner() //The weapon can be valid, but the player isn't a Titan during melee execute. // JFS: threads with waits should just end on "OnDestroy" - if ( !IsValid(weaponOwner) ) + if ( !IsValid( weaponOwner ) ) return - if ( !weapon.GetWeaponOwner().IsTitan() || weapon != weaponOwner.GetActiveWeapon() ) + if ( weapon != weaponOwner.GetActiveWeapon() ) return - weapon.PlayWeaponEffectNoCull( "wpn_arc_cannon_electricity_fp", "wpn_arc_cannon_electricity", "muzzle_flash" ) - weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) + if ( weaponOwnerIsPilot == false ) + { + weapon.PlayWeaponEffectNoCull( $"wpn_arc_cannon_electricity_fp", $"wpn_arc_cannon_electricity", "muzzle_flash" ) + weapon.EmitWeaponSound( "arc_cannon_charged_loop" ) + } + else + { + weapon.EmitWeaponSound_1p3p( "Arc_Rifle_charged_Loop_1P", "Arc_Rifle_charged_Loop_3P" ) + } } -function AddToArcCannonTargets( ent ) +#if SERVER +void function AddToArcCannonTargets( entity ent ) { AddToScriptManagedEntArray( level._arcCannonTargetsArrayID, ent ); } -function GetArcCannonTargets( origin, team ) +function RemoveArcCannonTarget( ent ) { - local targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) + RemoveFromScriptManagedEntArray( level._arcCannonTargetsArrayID, ent ) +} - if ( ARC_CANNON_TARGETS_MISSILES ) - { - local enemyTeam = GetEnemyTeam( team ) - targets.extend( GetProjectileArrayEx( "rpg_missile", enemyTeam, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) ) - } +array function GetArcCannonTargets( vector origin, int team, entity weapon ) +{ + array targets = GetScriptManagedEntArrayWithinCenter( level._arcCannonTargetsArrayID, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) + + if ( ARC_CANNON_TARGETS_MISSILES && weapon.GetWeaponChargeFraction() == 1.0 ) + targets.extend( GetProjectileArrayEx( "rpg_missile", TEAM_ANY, team, origin, ARC_CANNON_TITAN_RANGE_CHAIN ) ) return targets } -Globalize( GetArcCannonTargets ) -function GetArcCannonTargetsInRange( origin, team, weapon ) +array function GetArcCannonTargetsInRange( vector origin, int team, entity weapon ) { - local allTargets = GetArcCannonTargets( origin, team ) - local targetsInRange = [] + array allTargets = GetArcCannonTargets( origin, team, weapon ) + array targetsInRange - local titanDistSq - local distSq + float titanDistSq + float distSq if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) { titanDistSq = ARC_CANNON_TITAN_RANGE_CHAIN_BURN * ARC_CANNON_TITAN_RANGE_CHAIN_BURN @@ -871,45 +928,15 @@ function GetArcCannonTargetsInRange( origin, team, weapon ) foreach( target in allTargets ) { - local d = DistanceSqr( target.GetOrigin(), origin ) - local validDist = target.IsTitan() ? titanDistSq : distSq + float d = DistanceSqr( target.GetOrigin(), origin ) + float validDist = target.IsTitan() ? titanDistSq : distSq if ( d <= validDist ) targetsInRange.append( target ) } return targetsInRange } - -function SortArcCannonTargets( weapon, targets ) -{ - Assert( targets.len() > 0 ) - local originalTargetCount = targets.len() - //printt( " sorting", originalTargetCount, "targets" ) - - local sortedTargets = [] - local lastEnt = weapon.GetWeaponOwner() - local closestIndex = null - local closestEnt = null - - while( targets.len() > 0 ) - { - closestEnt = null - closestIndex = null - - closestIndex = GetClosestIndex( targets, lastEnt.GetOrigin() ) - Assert( closestIndex != null ) - closestEnt = targets[ closestIndex ] - Assert( closestEnt != null ) - - sortedTargets.append( closestEnt ) - targets.remove( closestIndex ) - - lastEnt = closestEnt - } - - Assert( sortedTargets.len() == originalTargetCount ) - return sortedTargets -} +#endif // SERVER function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDuration = ARC_CANNON_BEAM_LIFETIME, radius = 256, boltWidth = 4, noiseAmplitude = 5, hasTarget = true, firstBeam = false ) { @@ -922,37 +949,38 @@ function CreateArcCannonBeam( weapon, target, startPos, endPos, player, lifeDura if ( weapon.HasMod( "burn_mod_titan_arc_cannon" ) ) lifeDuration = ARC_CANNON_BEAM_LIFETIME_BURN // If it's the first beam and on client we do a special beam so it's lined up with the muzzle origin - if ( IsClient() && firstBeam ) - thread CreateClientArcBeam( weapon, endPos, lifeDuration, target ) - - if ( IsClient() ) - return - - // Control point sets the end position of the effect - local cpEnd = CreateEntity( "info_placement_helper" ) - cpEnd.SetName( UniqueString( "arc_cannon_beam_cpEnd" ) ) - cpEnd.SetOrigin( endPos ) - DispatchSpawn( cpEnd, false ) - - local zapBeam = CreateEntity( "info_particle_system" ) - zapBeam.kv.cpoint1 = cpEnd.GetName() - - zapBeam.kv.effect_name = GetBeamEffect( weapon ) - - zapBeam.kv.start_active = 0 - zapBeam.SetOwner( player ) - zapBeam.SetOrigin( startPos ) - if ( firstBeam ) - { - zapBeam.kv.VisibilityFlags = 6 // everyone but owner - zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 ) - } - DispatchSpawn( zapBeam ) + #if CLIENT + if ( firstBeam ) + thread CreateClientArcBeam( weapon, endPos, lifeDuration, target ) + #endif + + #if SERVER + // Control point sets the end position of the effect + entity cpEnd = CreateEntity( "info_placement_helper" ) + SetTargetName( cpEnd, UniqueString( "arc_cannon_beam_cpEnd" ) ) + cpEnd.SetOrigin( endPos ) + DispatchSpawn( cpEnd ) + + entity zapBeam = CreateEntity( "info_particle_system" ) + zapBeam.kv.cpoint1 = cpEnd.GetTargetName() + + zapBeam.SetValueForEffectNameKey( GetBeamEffect( weapon ) ) + + zapBeam.kv.start_active = 0 + zapBeam.SetOwner( player ) + zapBeam.SetOrigin( startPos ) + if ( firstBeam ) + { + zapBeam.kv.VisibilityFlags = (ENTITY_VISIBLE_TO_FRIENDLY | ENTITY_VISIBLE_TO_ENEMY) // everyone but owner + zapBeam.SetParent( player.GetActiveWeapon(), "muzzle_flash", false, 0.0 ) + } + DispatchSpawn( zapBeam ) - zapBeam.Fire( "Start" ) - zapBeam.Fire( "StopPlayEndCap", "", lifeDuration ) - zapBeam.Kill( lifeDuration ) - cpEnd.Kill( lifeDuration ) + zapBeam.Fire( "Start" ) + zapBeam.Fire( "StopPlayEndCap", "", lifeDuration ) + zapBeam.Kill_Deprecated_UseDestroyInstead( lifeDuration ) + cpEnd.Kill_Deprecated_UseDestroyInstead( lifeDuration ) + #endif } function GetBeamEffect( weapon ) @@ -963,14 +991,19 @@ function GetBeamEffect( weapon ) return ARC_CANNON_BEAM_EFFECT } +#if CLIENT function CreateClientArcBeam( weapon, endPos, lifeDuration, target ) { Assert( IsClient() ) local beamEffect = GetBeamEffect( weapon ) - weapon.PlayWeaponEffect( beamEffect, null, "muzzle_flash" ) - local handle = weapon.AllocateHandleForViewmodelEffect( beamEffect ) + // HACK HACK HACK HACK + string tag = "muzzle_flash" + if ( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) != null ) + tag = expect string( weapon.GetWeaponInfoFileKeyField( "client_tag_override" ) ) + + local handle = weapon.PlayWeaponEffectReturnViewEffectHandle( beamEffect, $"", tag ) if ( !EffectDoesExist( handle ) ) return @@ -982,25 +1015,33 @@ function CreateClientArcBeam( weapon, endPos, lifeDuration, target ) wait( lifeDuration ) if ( IsValid( weapon ) ) - weapon.StopWeaponEffect( beamEffect, null ) + weapon.StopWeaponEffect( beamEffect, $"" ) } -function ClientDestroyCallback_ArcCannon_Stop( entity ) +void function ClientDestroyCallback_ArcCannon_Stop( entity ent ) { - ArcCannon_Stop( entity ) + ArcCannon_Stop( ent ) } +#endif // CLIENT function GetArcCannonChargeFraction( weapon ) { if ( IsValid( weapon ) ) { local chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO - if( weapon.HasModDefined( "capacitor" ) && weapon.HasMod( "capacitor" ) ) + if ( weapon.HasMod( "capacitor" ) ) chargeRatio = ARC_CANNON_CAPACITOR_CHARGE_RATIO - if( weapon.GetWeaponModSetting( "is_burn_mod" ) ) + if ( weapon.GetWeaponSettingBool( eWeaponVar.is_burn_mod ) ) chargeRatio = ARC_CANNON_DAMAGE_CHARGE_RATIO_BURN return chargeRatio } return 0 +} + +function GetWeaponChargeFrac( weapon ) +{ + if ( weapon.IsChargeWeapon() ) + return weapon.GetWeaponChargeFraction() + return 1.0 } \ No newline at end of file diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut index 09faafa5..78879393 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/mp_titanweapon_arc_cannon.nut @@ -1,24 +1,50 @@ -ArcCannon_PrecacheFX( self ) +untyped -function OnWeaponActivate( activateParams ) +global function MpTitanweaponArcCannon_Init + +global function OnWeaponActivate_titanweapon_arc_cannon +global function OnWeaponDeactivate_titanweapon_arc_cannon +global function OnWeaponReload_titanweapon_arc_cannon +global function OnWeaponOwnerChanged_titanweapon_arc_cannon +global function OnWeaponChargeBegin_titanweapon_arc_cannon +global function OnWeaponChargeEnd_titanweapon_arc_cannon +global function OnWeaponPrimaryAttack_titanweapon_arc_cannon + +const FX_EMP_BODY_HUMAN = $"P_emp_body_human" +const FX_EMP_BODY_TITAN = $"P_emp_body_titan" + +#if SERVER +global function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon +#endif // #if SERVER + +void function MpTitanweaponArcCannon_Init() +{ + ArcCannon_PrecacheFX() + + #if SERVER + AddDamageCallbackSourceID( eDamageSourceId.mp_titanweapon_arc_cannon, ArcRifleOnDamage ) + #endif +} + +void function OnWeaponActivate_titanweapon_arc_cannon( entity weapon ) { - local weaponOwner = self.GetWeaponOwner() - thread DelayedArcCannonStart( self, weaponOwner ) - if( !("weaponOwner" in self.s) ) - self.s.weaponOwner <- weaponOwner + entity weaponOwner = weapon.GetWeaponOwner() + thread DelayedArcCannonStart( weapon, weaponOwner ) + if( !("weaponOwner" in weapon.s) ) + weapon.s.weaponOwner <- weaponOwner } -function DelayedArcCannonStart( weapon, weaponOwner ) +function DelayedArcCannonStart( entity weapon, entity weaponOwner ) { weapon.EndSignal( "WeaponDeactivateEvent" ) - wait 0 + WaitFrame() if ( IsValid( weapon ) && IsValid( weaponOwner ) && weapon == weaponOwner.GetActiveWeapon() ) { if( weaponOwner.IsPlayer() ) { - local modelEnt = weaponOwner.GetViewModelEntity() + entity modelEnt = weaponOwner.GetViewModelEntity() if( IsValid( modelEnt ) && EntHasModelSet( modelEnt ) ) ArcCannon_Start( weapon ) } @@ -29,91 +55,172 @@ function DelayedArcCannonStart( weapon, weaponOwner ) } } -function OnWeaponDeactivate( deactivateParams ) +void function OnWeaponDeactivate_titanweapon_arc_cannon( entity weapon ) { - ArcCannon_ChargeEnd( self, self.s.weaponOwner ) - ArcCannon_Stop( self ) + ArcCannon_ChargeEnd( weapon, expect entity( weapon.s.weaponOwner ) ) + ArcCannon_Stop( weapon ) } -function OnWeaponReload( reloadParams ) +void function OnWeaponReload_titanweapon_arc_cannon( entity weapon, int milestoneIndex ) { - local reloadTime = self.GetWeaponInfoFileKeyField( "reload_time" ) - thread ArcCannon_HideIdleEffect( self, reloadTime ) //constant seems to help it sync up better + local reloadTime = weapon.GetWeaponInfoFileKeyField( "reload_time" ) + thread ArcCannon_HideIdleEffect( weapon, reloadTime ) //constant seems to help it sync up better } -function OnWeaponOwnerChanged( changeParams ) +void function OnWeaponOwnerChanged_titanweapon_arc_cannon( entity weapon, WeaponOwnerChangedParams changeParams ) { - if ( IsClient() ) - { - local viewPlayer = GetLocalViewPlayer() + #if CLIENT + entity viewPlayer = GetLocalViewPlayer() if ( changeParams.oldOwner != null && changeParams.oldOwner == viewPlayer ) { - ArcCannon_ChargeEnd( self, changeParams.oldOwner ) - ArcCannon_Stop( self, changeParams.oldOwner ) + ArcCannon_ChargeEnd( weapon, changeParams.oldOwner ) + ArcCannon_Stop( weapon) } + if ( changeParams.newOwner != null && changeParams.newOwner == viewPlayer ) - thread ArcCannon_HideIdleEffect( self, 0.25 ) - } - else - { + thread ArcCannon_HideIdleEffect( weapon, 0.25 ) + #else if ( changeParams.oldOwner != null ) { - ArcCannon_ChargeEnd( self, changeParams.oldOwner ) - ArcCannon_Stop( self, changeParams.oldOwner ) + ArcCannon_ChargeEnd( weapon, changeParams.oldOwner ) + ArcCannon_Stop( weapon ) } + if ( changeParams.newOwner != null ) - thread ArcCannon_HideIdleEffect( self, 0.25 ) - } + thread ArcCannon_HideIdleEffect( weapon, 0.25 ) + #endif } -function OnWeaponChargeBegin( chargeParams ) +bool function OnWeaponChargeBegin_titanweapon_arc_cannon( entity weapon ) { - ArcCannon_ChargeBegin( self ) + local stub = "this is here to suppress the untyped message. This can go away when the .s. usage is removed from this file." + #if SERVER + //if ( weapon.HasMod( "fastpacitor_push_apart" ) ) + // weapon.GetWeaponOwner().StunMovementBegin( weapon.GetWeaponSettingFloat( eWeaponVar.charge_time ) ) + #endif + + ArcCannon_ChargeBegin( weapon ) + + return true } -function OnWeaponChargeEnd( chargeParams ) +void function OnWeaponChargeEnd_titanweapon_arc_cannon( entity weapon ) { - ArcCannon_ChargeEnd( self ) + ArcCannon_ChargeEnd( weapon, weapon ) } -function OnWeaponPrimaryAttack( attackParams ) +var function OnWeaponPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams ) { - if ( self.HasMod( "capacitor" ) && self.GetWeaponChargeFraction() < GetArcCannonChargeFraction( self ) ) + if ( weapon.HasMod( "capacitor" ) && weapon.GetWeaponChargeFraction() < GetArcCannonChargeFraction( weapon ) ) return 0 if ( !attackParams.firstTimePredicted ) return - local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" ) - thread ArcCannon_HideIdleEffect( self, (1 / fireRate) ) - return FireArcCannon( self, attackParams ) -} + local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" ) + thread ArcCannon_HideIdleEffect( weapon, (1 / fireRate) ) -function OnWeaponNpcPrimaryAttack( attackParams ) -{ - local fireRate = self.GetWeaponInfoFileKeyField( "fire_rate" ) - thread ArcCannon_HideIdleEffect( self, fireRate ) - return FireArcCannon( self, attackParams ) + return FireArcCannon( weapon, attackParams ) } -function OnWeaponStartZoomIn() +#if SERVER +var function OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon( entity weapon, WeaponPrimaryAttackParams attackParams ) { - HandleWeaponSoundZoomIn( self, "Weapon_Titan_ArcCannon.ADS_In" ) -} + local fireRate = weapon.GetWeaponInfoFileKeyField( "fire_rate" ) + thread ArcCannon_HideIdleEffect( weapon, fireRate ) -function OnWeaponStartZoomOut() -{ - HandleWeaponSoundZoomOut( self, "Weapon_Titan_ArcCannon.ADS_Out" ) + return FireArcCannon( weapon, attackParams ) } -/* -function OnWeaponPrimaryAttackVMActivityToUse() +void function ArcRifleOnDamage( entity ent, var damageInfo ) { - local baseCharge = self.GetWeaponChargeFraction() - local charge = clamp ( baseCharge * ( 1 / 0.7 ), 0.0, 1.0 ) + vector pos = DamageInfo_GetDamagePosition( damageInfo ) + entity attacker = DamageInfo_GetAttacker( damageInfo ) - if ( charge > 0.25 ) - return 1 + EmitSoundOnEntity( ent, ARC_CANNON_TITAN_SCREEN_SFX ) + + if ( ent.IsPlayer() || ent.IsNPC() ) + { + entity entToSlow = ent + entity soul = ent.GetTitanSoul() + + if ( soul != null ) + entToSlow = soul + + StatusEffect_AddTimed( entToSlow, eStatusEffect.move_slow, 0.5, 2.0, 1.0 ) + StatusEffect_AddTimed( entToSlow, eStatusEffect.dodge_speed_slow, 0.5, 2.0, 1.0 ) + } + + string tag = "" + asset effect + + if ( ent.IsTitan() ) + { + tag = "exp_torso_front" + effect = FX_EMP_BODY_TITAN + } + else if ( ChestFocusTarget( ent ) ) + { + tag = "CHESTFOCUS" + effect = FX_EMP_BODY_HUMAN + } + else if ( IsAirDrone( ent ) ) + { + tag = "HEADSHOT" + effect = FX_EMP_BODY_HUMAN + } + else if ( IsGunship( ent ) ) + { + tag = "ORIGIN" + effect = FX_EMP_BODY_TITAN + } + + if ( tag != "" ) + { + float duration = 2.0 + //thread EMP_FX( effect, ent, tag, duration ) + } + + if ( ent.IsTitan() ) + { + if ( ent.IsPlayer() ) + { + EmitSoundOnEntityOnlyToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_1p" ) + EmitSoundOnEntityExceptToPlayer( ent, ent, "titan_energy_bulletimpact_3p_vs_3p" ) + } + else + { + EmitSoundOnEntity( ent, "titan_energy_bulletimpact_3p_vs_3p" ) + } + } else - return 0 -}*/ + { + if ( ent.IsPlayer() ) + { + EmitSoundOnEntityOnlyToPlayer( ent, ent, "flesh_lavafog_deathzap_3p" ) + EmitSoundOnEntityExceptToPlayer( ent, ent, "flesh_lavafog_deathzap_1p" ) + } + else + { + EmitSoundOnEntity( ent, "flesh_lavafog_deathzap_1p" ) + } + } + +} + +bool function ChestFocusTarget( entity ent ) +{ + if ( IsSpectre( ent ) ) + return true + if ( IsStalker( ent ) ) + return true + if ( IsSuperSpectre( ent ) ) + return true + if ( IsGrunt( ent ) ) + return true + if ( IsPilot( ent ) ) + return true + + return false +} +#endif // #if SERVER diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt index 58bba152..11d87a4d 100644 --- a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt +++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt @@ -7,8 +7,6 @@ WeaponData "longdesc" "#WPN_TITAN_ARC_CANNON_LONGDESC" "weaponClass" "titan" "fire_mode" "semi-auto" - "server_vscript" "weapons/mp_titanweapon_arc_cannon" - "client_vscript" "weapons/mp_titanweapon_arc_cannon" "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]" "pickup_press_prompt" "[USE] [WEAPONNAME]" "minimap_reveal_distance" "32000" @@ -23,12 +21,30 @@ WeaponData "viewmodel" "models/weapons/titan_arc_rifle/atpov_titan_arc_rifle.mdl" "playermodel" "models/weapons/titan_arc_rifle/w_titan_arc_rifle.mdl" "anim_prefix" "ar2" + + "OnWeaponActivate" "OnWeaponActivate_titanweapon_arc_cannon" + "OnWeaponDeactivate" "OnWeaponDeactivate_titanweapon_arc_cannon" + "OnWeaponReload" "OnWeaponReload_titanweapon_arc_cannon" + "OnWeaponOwnerChanged" "OnWeaponOwnerChanged_titanweapon_arc_cannon" + "OnWeaponChargeBegin" "OnWeaponChargeBegin_titanweapon_arc_cannon" + "OnWeaponChargeEnd" "OnWeaponChargeEnd_titanweapon_arc_cannon" + "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_titanweapon_arc_cannon" + "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_titanweapon_arc_cannon" +// "OnWeaponCooldown" "OnWeaponCooldown_titanweapon_particle_accelerator" + + + // Effects //"tracer_effect" "weapon_tracers_xo16" //Impact Table used for visuals at the top of arc_cannon.nut - "impact_effect_table" "exp_arc_cannon_whiz_by" + "tracer_effect" "P_wpn_arcball_beam" + "tracer_effect_first_person" "P_wpn_arcball_beam" + "impact_effect_table" "exp_arc_cannon" "adjust_to_gun_barrel" "1" + "fx_muzzle_flash_view" "wpn_arc_cannon_electricity_fp" + "fx_muzzle_flash_world" "wpn_arc_cannon_electricity" + "fx_muzzle_flash_attach" "muzzle_flash" // Damage - When Used by Players "damage_type" "bullet" @@ -42,14 +58,22 @@ WeaponData // Damage - When Used by NPCs "critical_hit" "0" + "critical_hit_damage_scale" "1.5" // Ammo - "ammo_stockpile_max" "1000" - "ammo_clip_size" "1000" - "ammo_default_total" "1000" + "ammo_min_to_fire" "1" + "ammo_no_remove_from_stockpile" "1" // Behavior "fire_rate" "1" +// "rechamber_time" "0.25" //"1.30" + "cooldown_time" "0.6" + "reloadempty_time" "6.03" + "reloadempty_time_late1" "4.7" + "reloadempty_time_late2" "3.5" + "reloadempty_time_late3" "2.5" + "reloadempty_time_late4" "1.43" + "reloadempty_time_late5" "0.56" "zoom_time_in" "0.1" "zoom_time_out" "0.1" "zoom_fov" "33" @@ -60,20 +84,27 @@ WeaponData "lower_time" ".1" "raise_time" ".4" "charge_time" "3.7" + "charge_cooldown_time" "1.0" "charge_end_forces_fire" "0" - "allow_empty_fire" "0" - "reload_enabled" "1" + "allow_empty_fire" "1" + "reload_enabled" "0" "allow_empty_click" "1" "empty_reload_only" "0" "trigger_snipercam" "1" "allow_headshots" "0" "bypass_semiauto_hold_protection" "1" "vortex_drain" ".15" + "charge_effect_1p" "wpn_arc_cannon_charge_fp" + "charge_effect_3p" "wpn_arc_cannon_charge" + "charge_effect_attachment" "muzzle_flash" + + // Spread "spread_stand_hip" "10" "spread_npc" "2" + "ammo_suck_behavior" "primary_weapons" // View Kick "viewkick_spring" "titan_arc" @@ -203,7 +234,7 @@ WeaponData "charge_time" "2.5" //for reference was 3 in 10/15 evening playtest "charge_cooldown_time" "1.0" "charge_cooldown_delay" "0.0" - "crosshair_index" "1" + //"crosshair_index" "1" "spread_stand_hip" "15" "damage_far_distance" "2700" "damage_near_value_titanarmor" "2000" @@ -215,8 +246,9 @@ WeaponData } burn_mod_titan_arc_cannon { - "crosshair_index" "2" - + //"crosshair_index" "2" + "tracer_effect" "wpn_arc_cannon_beam_mod" + "tracer_effect_first_person" "wpn_arc_cannon_beam_mod" "damage_near_value" "*1.1" "damage_far_value" "*1.1" "damage_near_value_titanarmor" "*1.1" @@ -225,131 +257,87 @@ WeaponData } } - CrosshairData + active_crosshair_count "2" +// rui_crosshair_index "1" + "ui1_enable" "1" + "ui1_draw_cloaked" "0" + UiData1 + { + "ui" "ui/crosshair_charge_rifle" + "mesh" "models/weapons/attachments/alternator_rui_upper" + Args + { + adjustedSpread weapon_spread + adsFrac player_zoomFrac + isSprinting player_is_sprinting + isReloading weapon_is_reloading + readyFrac progress_ready_to_fire_frac + teamColor crosshair_team_color + isAmped weapon_is_amped + chargeFrac player_chargeFrac + crosshairMovementX crosshair_movement_x + crosshairMovementY crosshair_movement_y + } + } + RUI_CrosshairData { - BaseWeapon + DefaultArgs { - DefaultElementBehavior + adjustedSpread weapon_spread + adsFrac player_zoomFrac + isSprinting player_is_sprinting + isReloading weapon_is_reloading + readyFrac progress_ready_to_fire_frac + teamColor crosshair_team_color + isAmped weapon_is_amped + chargeFrac player_chargeFrac + crosshairMovementX crosshair_movement_x + crosshairMovementY crosshair_movement_y + } + + Crosshair_1 + { + "ui" "ui/crosshair_charge_rifle" +// "ui" "ui/alternator_reticle" + "base_spread" "10.0" + Args { - "fade_while_sprinting" "1" - "fade_while_reloading" "1" - "stationary" "1" + isFiring weapon_is_firing } Element0 - { - "type" "static" - "material" "/hud/crosshairs/arc_cannon_charge" - "size_x" "80" - "size_y" "80" - "scale_ads" "1.5" - } - Element1 - { - "type" "static" - "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" - "size_x" "80" - "size_y" "80" - "scale_ads" "1.5" - } - Element2 - { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single" - "size_x" "16" - "size_y" "16" - "scale_ads" "2.2" - } - Element3 - { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" - "size_x" "16" - "size_y" "16" - "scale_ads" "2.2" - } - } - CapacitorWeapon - { - DefaultElementBehavior { "fade_while_sprinting" "1" "fade_while_reloading" "1" "stationary" "1" - } - Element0 - { + "default_color" "246 134 40 255" "type" "static" - "material" "/hud/crosshairs/arc_cannon_charge" + "material" $"vgui/hud/arc_cannon_charge/arc_cannon_charge" "size_x" "80" "size_y" "80" "scale_ads" "1.5" } Element1 - { - "type" "static" - "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" - "size_x" "80" - "size_y" "80" - "scale_ads" "1.5" - } - Element2 - { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single" - "size_x" "24" - "size_y" "24" - "scale_ads" "2.2" - } - Element3 - { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" - "size_x" "24" - "size_y" "24" - "scale_ads" "2.2" - } - } - Burn_Card_Mod - { - DefaultElementBehavior { "fade_while_sprinting" "1" "fade_while_reloading" "1" "stationary" "1" "default_color" "246 134 40 255" - } - Element0 - { "type" "static" - "material" "/hud/crosshairs/arc_cannon_charge" + "material" "vgui/hud/arc_cannon_charge/arc_cannon_shadow_horizontal" "size_x" "80" "size_y" "80" "scale_ads" "1.5" } - Element1 - { - "type" "static" - "material" "/hud/crosshairs/arc_cannon_shadow_horizontal" - "size_x" "80" - "size_y" "80" - "scale_ads" "1.5" - } - Element2 - { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single" - "size_x" "16" - "size_y" "16" - "scale_ads" "2.2" - } - Element3 + } + + Crosshair_2 + { + "ui" "ui/crosshair_circle2" + "base_spread" "0.0" + Args { - "type" "static" - "material" "hud/crosshairs/titan_shotgun_circle_single_shadow" - "size_x" "16" - "size_y" "16" - "scale_ads" "2.2" + isFiring weapon_is_firing } } } -} +} \ No newline at end of file -- cgit v1.2.3 From ea6dea0ef1789498ee11202e48d1c1072dbdbb4f Mon Sep 17 00:00:00 2001 From: Respawn Date: Mon, 17 Jul 2023 00:45:22 +0200 Subject: Add mp_weapon_shotgun_doublebarrel.txt from englishclient_mp_common --- .../weapons/mp_weapon_shotgun_doublebarrel.txt | 287 +++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt diff --git a/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt new file mode 100644 index 00000000..30acf0e3 --- /dev/null +++ b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt @@ -0,0 +1,287 @@ +WeaponData +{ + // General + "printname" "#WPN_SHOTGUN_DBLBARREL" + "shortprintname" "#WPN_SHOTGUN_DBLBARREL_SHORT" + "description" "#WPN_SHOTGUN_DBLBARREL_DESC" + "longdesc" "#WPN_SHOTGUN_DBLBARREL_LONGDESC" + "weaponClass" "human" + "weaponSubClass" "projectile_shotgun" + "body_type" "close_quarters" + "fire_mode" "semi-auto" + "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]" + "pickup_press_prompt" "[USE] [WEAPONNAME]" + "aimassist_adspull_weaponclass" "broad" + "minimap_reveal_distance" "32000" + "leveled_pickup" "0" + + "viewmodel" "models/weapons/mastiff_stgn/ptpov_mastiff.mdl" + "playermodel" "models/weapons/mastiff_stgn/w_mastiff.mdl" + + "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_shotgun_doublebarrel" + "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_shotgun_doublebarrel" + + "projectilemodel" "models/dev/empty_model.mdl" + "projectile_trail_effect_0" "P_mastiff_proj" + "projectile_ricochet_max_count" "2" + + "viewmodel_offset_ads" "0 -3 0" + + // Menu + "menu_category" "special" + "menu_anim_class" "medium" + "stat_damage" "98" + "stat_range" "15" + "stat_accuracy" "15" + "stat_rof" "20" + + "ammo_display" "bar" + "impulse_force" "10000" + + "impact_effect_table" "titan_shotgun_bullet" + + // Spread + "spread_stand_hip" "7" + "spread_stand_hip_run" "7" + "spread_stand_hip_sprint" "7" + "spread_stand_ads" "7" + "spread_crouch_hip" "7" + "spread_crouch_ads" "7" + "spread_air_hip" "7" + "spread_air_ads" "7" + + // Damage - When Used by Players + "damage_type" "bullet" + "damage_near_distance" "500" + "damage_far_distance" "1000" + "damage_near_value" "16" + "damage_far_value" "10" + "damage_near_value_titanarmor" "20" + "damage_far_value_titanarmor" "15" + + // Ammo + "ammo_stockpile_max" "500" + "ammo_default_total" "500" + "ammo_clip_size" "10" + "ammo_size_segmented_reload" "2" + "ammo_display_as_clips" "0" + "reload_is_segmented" "1" + + "reload_time" "2" + "reload_time_late1" "0" + "reload_time_late2" "0" + "reloadempty_time" "2" + "reloadempty_time_late1" "0" + "reloadempty_time_late2" "0" + + + "vortex_absorb_effect" "wpn_vortex_projectile_40mm_FP" + "vortex_absorb_effect_third_person" "wpn_vortex_projectile_40mm" + "vortex_absorb_sound" "Vortex_Shield_AbsorbBulletLarge" + "vortex_absorb_sound_1p_vs_3p" "Vortex_Shield_AbsorbBulletLarge_1P_VS_3P" + + "sound_dryfire" "shotgun_dryfire" + "fire_sound_1_player_1p" "Weapon_Leadwall_Fire_1P" + "fire_sound_1_player_3p" "Weapon_Leadwall_Fire_3P" + "fire_sound_1_npc" "Weapon_Leadwall_Fire_3P" + "sound_zoom_in" "Weapon_EVA8_ADS_In" + "sound_zoom_out" "Weapon_EVA8_ADS_Out" + + "fx_shell_eject_view" "wpn_shelleject_shotshell_FP" + "fx_shell_eject_world" "wpn_shelleject_shotshell" + "fx_shell_eject_attach" "shell" + + "fx_muzzle_flash_view" "wpn_muzzleflash_40mm_fp" + "fx_muzzle_flash_world" "wpn_muzzleflash_40mm" + "fx_muzzle_flash_attach" "muzzle_flash" + + "critical_hit_damage_scale" "1.3" + "critical_hit" "1" + "projectile_inherit_owner_velocity_scale" "0.2" + + "bolt_hitsize" "0.5" + "bolt_hitsize_grow1_time" "0.075" + "bolt_hitsize_grow1_size" "4.0" + "bolt_hitsize_grow2_time" "0.075" + "bolt_hitsize_grow2_size" "4.0" + "bolt_hitsize_growfinal_lerptime" "0.18" + "bolt_hitsize_growfinal_size" "6.0" + "bolt_bounce_frac" "1.0" + + + "bolt_gravity_enabled" "1" + + // Behavior + "fire_rate" "2.5" + "zoom_time_in" "0.2" + "zoom_time_out" "0.2" + "zoom_fov" "50" + "holster_time" "0.5" + "deploy_time" "0.8" + "lower_time" "0.25" + "raise_time" "0.3" + "vortex_refire_behavior" "bullet" + "allow_empty_fire" "0" + "reload_enabled" "1" + "allow_empty_click" "1" + "empty_reload_only" "0" + "trigger_snipercam" "0" + "allow_headshots" "0" + "primary_fire_does_not_block_sprint" "0" + "ads_move_speed_scale" "0.5" + "aimassist_disable_hipfire" "0" + "aimassist_disable_ads" "0" + "aimassist_disable_hipfire_titansonly" "1" + "aimassist_disable_ads_titansonly" "1" + + "ammo_suck_behavior" "primary_weapons" + + // View Kick + "viewkick_spring" "shotgun" + + "viewkick_pitch_base" "-2.25" + "viewkick_pitch_random" "1" + "viewkick_pitch_softScale" "0.4" + "viewkick_pitch_hardScale" "2.0" + + "viewkick_yaw_base" "-0.95" + "viewkick_yaw_random" "0.5" + "viewkick_yaw_softScale" "0.5" + "viewkick_yaw_hardScale" "2.0" + + "viewkick_roll_base" "0" + "viewkick_roll_randomMin" "0.6" + "viewkick_roll_randomMax" "0.8" + "viewkick_roll_softScale" "0.2" + "viewkick_roll_hardScale" "2.75" + + "viewkick_hipfire_weaponFraction" "0.1" + "viewkick_hipfire_weaponFraction_vmScale" "0.0" + "viewkick_ads_weaponFraction" "1.0" + "viewkick_ads_weaponFraction_vmScale" "0.15" + + "viewkick_perm_pitch_base" "0" + "viewkick_perm_pitch_random" "0.0" + + // + "viewmodel_shake_forward" "0.5" + "viewmodel_shake_up" "0.2" + "viewmodel_shake_right" "0.0" + + // Bob + //"bob_cycle_time" "0.45" + //"bob_vert_dist" "0.1" + //"bob_horz_dist" "0.1" + //"bob_max_speed" "150" + //"bob_pitch" "0.75" + //"bob_yaw" "0.5" + //"bob_roll" "-0.75" + + + // Rumble + "fire_rumble" "pilot_singleshot_strong_fire" + + // Sway + "sway_rotate_attach" "SWAY_ROTATE" + "sway_min_x" "-0.5" + "sway_min_y" "-0.4" + "sway_min_z" "-0.6" + "sway_max_x" "0.5" + "sway_max_y" "0.4" + "sway_max_z" "0.6" + "sway_min_pitch" "-3" + "sway_min_yaw" "-2.5" + "sway_min_roll" "-4" + "sway_max_pitch" "3" + "sway_max_yaw" "2.5" + "sway_max_roll" "4" + "sway_translate_gain" "2.5" + "sway_rotate_gain" "7" + "sway_move_forward_translate_x" "-0.1" + "sway_move_forward_translate_z" "-0.5" + "sway_move_back_translate_x" "0.2" + "sway_move_back_translate_z" "-0.2" + "sway_move_left_translate_y" "-1" + "sway_move_left_translate_z" "-0.5" + "sway_move_left_rotate_roll" "-4" + "sway_move_right_translate_y" "1" + "sway_move_right_translate_z" "-0.5" + "sway_move_right_rotate_roll" "4" + "sway_move_up_translate_z" "-1" + "sway_move_down_translate_z" "1" + "sway_turn_left_rotate_yaw" "1" + "sway_turn_right_rotate_yaw" "-1" + + "sway_turn_left_translate_y" "-.2" + "sway_turn_right_translate_y" ".2" + "sway_turn_up_translate_z" "-.2" + "sway_turn_down_translate_z" ".2" + "sway_turn_up_translate_x" "-.1" + "sway_turn_down_translate_x" ".1" + + "sway_turn_left_rotate_roll" "-4" + "sway_turn_right_rotate_roll" "4" + "sway_turn_up_rotate_pitch" "-3" + "sway_turn_down_rotate_pitch" "3" + "sway_turn_up_rotate_roll" "0.8" + "sway_turn_down_rotate_roll" "-0.8" + + // Zoomed Sway + "sway_rotate_attach_zoomed" "SWAY_ROTATE_ZOOMED" + "sway_rotate_attach_blend_time_zoomed" "0.2" + "sway_rotate_gain_zoomed" "5" + + "sway_min_yaw_zoomed" "-0.04" + "sway_max_yaw_zoomed" "0.04" + "sway_turn_left_rotate_yaw_zoomed" "-0.085" + "sway_turn_right_rotate_yaw_zoomed" "0.085" + + "sway_min_roll_zoomed" "-1" + "sway_max_roll_zoomed" "1" + "sway_turn_left_rotate_roll_zoomed" "-1" + "sway_turn_right_rotate_roll_zoomed" "1" + + "sway_move_right_rotate_roll_zoomed" "0.2" + "sway_move_left_rotate_roll_zoomed" "-0.2" + + "sway_min_pitch_zoomed" "-0.01" + "sway_max_pitch_zoomed" "0.01" + "sway_turn_up_rotate_pitch_zoomed" "0.09" + "sway_turn_down_rotate_pitch_zoomed" "-0.09" + + // NPC + "proficiency_poor_spreadscale" "7.0" + "proficiency_average_spreadscale" "5.0" + "proficiency_good_spreadscale" "3.33333" + "proficiency_very_good_spreadscale" "3.66667" + + "npc_min_range" "0" + "npc_max_range" "1250" + + "npc_min_burst" "1" + "npc_max_burst" "1" + "npc_rest_time_between_bursts_min" "1.25" + "npc_rest_time_between_bursts_max" "1.75" + + // WeaponED Unhandled Key/Values and custom script Key/Values + "bob_tilt_angle" "0.5" + "sway_turn_angle_factor" "-0.5" + "sway_turn_origin_factor" "0" + "sway_turn_angle_factor_zoomed" "0" + "sway_turn_origin_factor_zoomed" "0.05" + "sway_move_angle_factor" "0.15" + "sway_move_origin_factor" "0.15" + "sway_move_angle_factor_zoomed" "0" + "sway_move_origin_factor_zoomed" "0.03" + "sway_gain" "10.0" + "deployfirst_time" "1.0" + "deploycatch_time" "1.33" + "sprintcycle_time" ".55" + + "projectile_lifetime" "0.5" + "projectile_damage_reduction_per_bounce" "0.0" + "projectile_damages_owner" "0" + + // Crosshair + "red_crosshair_range" "300" +} \ No newline at end of file -- cgit v1.2.3 From b951cae3d2bcf581bf9b6d8fece0d6b9bc66c67b Mon Sep 17 00:00:00 2001 From: FourthVolt <87427011+EM4Volts@users.noreply.github.com> Date: Wed, 19 Jul 2023 01:41:45 +0200 Subject: Add cut Doublebarrel shotgun by using model from Titanfall Online (#660) --- .../ptpov_shotgun_doublebarrel.mdl | Bin 0 -> 1268987 bytes .../w_shotgun_doublebarrel.mdl | Bin 0 -> 743828 bytes .../weapons/mp_weapon_shotgun_doublebarrel.txt | 692 ++++++++++++--------- .../paks/mp_weapon_shotgun_doublebarrel.rpak | Bin 0 -> 264566 bytes .../paks/mp_weapon_shotgun_doublebarrel.starpak | Bin 0 -> 16539736 bytes Northstar.Custom/paks/rpak.json | 5 + .../client_mp_northstar_common.bsp.pak000_000.vpk | Bin 86104271 -> 86805541 bytes ...shclient_mp_northstar_common.bsp.pak000_dir.vpk | Bin 5374 -> 5905 bytes 8 files changed, 410 insertions(+), 287 deletions(-) create mode 100644 Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl create mode 100644 Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl create mode 100644 Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak create mode 100644 Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak create mode 100644 Northstar.Custom/paks/rpak.json diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl new file mode 100644 index 00000000..2fcc3439 Binary files /dev/null and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl new file mode 100644 index 00000000..137d985d Binary files /dev/null and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt index 30acf0e3..2bc8b094 100644 --- a/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt +++ b/Northstar.Custom/mod/scripts/weapons/mp_weapon_shotgun_doublebarrel.txt @@ -1,287 +1,405 @@ -WeaponData -{ - // General - "printname" "#WPN_SHOTGUN_DBLBARREL" - "shortprintname" "#WPN_SHOTGUN_DBLBARREL_SHORT" - "description" "#WPN_SHOTGUN_DBLBARREL_DESC" - "longdesc" "#WPN_SHOTGUN_DBLBARREL_LONGDESC" - "weaponClass" "human" - "weaponSubClass" "projectile_shotgun" - "body_type" "close_quarters" - "fire_mode" "semi-auto" - "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]" - "pickup_press_prompt" "[USE] [WEAPONNAME]" - "aimassist_adspull_weaponclass" "broad" - "minimap_reveal_distance" "32000" - "leveled_pickup" "0" - - "viewmodel" "models/weapons/mastiff_stgn/ptpov_mastiff.mdl" - "playermodel" "models/weapons/mastiff_stgn/w_mastiff.mdl" - - "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_shotgun_doublebarrel" - "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_shotgun_doublebarrel" - - "projectilemodel" "models/dev/empty_model.mdl" - "projectile_trail_effect_0" "P_mastiff_proj" - "projectile_ricochet_max_count" "2" - - "viewmodel_offset_ads" "0 -3 0" - - // Menu - "menu_category" "special" - "menu_anim_class" "medium" - "stat_damage" "98" - "stat_range" "15" - "stat_accuracy" "15" - "stat_rof" "20" - - "ammo_display" "bar" - "impulse_force" "10000" - - "impact_effect_table" "titan_shotgun_bullet" - - // Spread - "spread_stand_hip" "7" - "spread_stand_hip_run" "7" - "spread_stand_hip_sprint" "7" - "spread_stand_ads" "7" - "spread_crouch_hip" "7" - "spread_crouch_ads" "7" - "spread_air_hip" "7" - "spread_air_ads" "7" - - // Damage - When Used by Players - "damage_type" "bullet" - "damage_near_distance" "500" - "damage_far_distance" "1000" - "damage_near_value" "16" - "damage_far_value" "10" - "damage_near_value_titanarmor" "20" - "damage_far_value_titanarmor" "15" - - // Ammo - "ammo_stockpile_max" "500" - "ammo_default_total" "500" - "ammo_clip_size" "10" - "ammo_size_segmented_reload" "2" - "ammo_display_as_clips" "0" - "reload_is_segmented" "1" - - "reload_time" "2" - "reload_time_late1" "0" - "reload_time_late2" "0" - "reloadempty_time" "2" - "reloadempty_time_late1" "0" - "reloadempty_time_late2" "0" - - - "vortex_absorb_effect" "wpn_vortex_projectile_40mm_FP" - "vortex_absorb_effect_third_person" "wpn_vortex_projectile_40mm" - "vortex_absorb_sound" "Vortex_Shield_AbsorbBulletLarge" - "vortex_absorb_sound_1p_vs_3p" "Vortex_Shield_AbsorbBulletLarge_1P_VS_3P" - - "sound_dryfire" "shotgun_dryfire" - "fire_sound_1_player_1p" "Weapon_Leadwall_Fire_1P" - "fire_sound_1_player_3p" "Weapon_Leadwall_Fire_3P" - "fire_sound_1_npc" "Weapon_Leadwall_Fire_3P" - "sound_zoom_in" "Weapon_EVA8_ADS_In" - "sound_zoom_out" "Weapon_EVA8_ADS_Out" - - "fx_shell_eject_view" "wpn_shelleject_shotshell_FP" - "fx_shell_eject_world" "wpn_shelleject_shotshell" - "fx_shell_eject_attach" "shell" - - "fx_muzzle_flash_view" "wpn_muzzleflash_40mm_fp" - "fx_muzzle_flash_world" "wpn_muzzleflash_40mm" - "fx_muzzle_flash_attach" "muzzle_flash" - - "critical_hit_damage_scale" "1.3" - "critical_hit" "1" - "projectile_inherit_owner_velocity_scale" "0.2" - - "bolt_hitsize" "0.5" - "bolt_hitsize_grow1_time" "0.075" - "bolt_hitsize_grow1_size" "4.0" - "bolt_hitsize_grow2_time" "0.075" - "bolt_hitsize_grow2_size" "4.0" - "bolt_hitsize_growfinal_lerptime" "0.18" - "bolt_hitsize_growfinal_size" "6.0" - "bolt_bounce_frac" "1.0" - - - "bolt_gravity_enabled" "1" - - // Behavior - "fire_rate" "2.5" - "zoom_time_in" "0.2" - "zoom_time_out" "0.2" - "zoom_fov" "50" - "holster_time" "0.5" - "deploy_time" "0.8" - "lower_time" "0.25" - "raise_time" "0.3" - "vortex_refire_behavior" "bullet" - "allow_empty_fire" "0" - "reload_enabled" "1" - "allow_empty_click" "1" - "empty_reload_only" "0" - "trigger_snipercam" "0" - "allow_headshots" "0" - "primary_fire_does_not_block_sprint" "0" - "ads_move_speed_scale" "0.5" - "aimassist_disable_hipfire" "0" - "aimassist_disable_ads" "0" - "aimassist_disable_hipfire_titansonly" "1" - "aimassist_disable_ads_titansonly" "1" - - "ammo_suck_behavior" "primary_weapons" - - // View Kick - "viewkick_spring" "shotgun" - - "viewkick_pitch_base" "-2.25" - "viewkick_pitch_random" "1" - "viewkick_pitch_softScale" "0.4" - "viewkick_pitch_hardScale" "2.0" - - "viewkick_yaw_base" "-0.95" - "viewkick_yaw_random" "0.5" - "viewkick_yaw_softScale" "0.5" - "viewkick_yaw_hardScale" "2.0" - - "viewkick_roll_base" "0" - "viewkick_roll_randomMin" "0.6" - "viewkick_roll_randomMax" "0.8" - "viewkick_roll_softScale" "0.2" - "viewkick_roll_hardScale" "2.75" - - "viewkick_hipfire_weaponFraction" "0.1" - "viewkick_hipfire_weaponFraction_vmScale" "0.0" - "viewkick_ads_weaponFraction" "1.0" - "viewkick_ads_weaponFraction_vmScale" "0.15" - - "viewkick_perm_pitch_base" "0" - "viewkick_perm_pitch_random" "0.0" - - // - "viewmodel_shake_forward" "0.5" - "viewmodel_shake_up" "0.2" - "viewmodel_shake_right" "0.0" - - // Bob - //"bob_cycle_time" "0.45" - //"bob_vert_dist" "0.1" - //"bob_horz_dist" "0.1" - //"bob_max_speed" "150" - //"bob_pitch" "0.75" - //"bob_yaw" "0.5" - //"bob_roll" "-0.75" - - - // Rumble - "fire_rumble" "pilot_singleshot_strong_fire" - - // Sway - "sway_rotate_attach" "SWAY_ROTATE" - "sway_min_x" "-0.5" - "sway_min_y" "-0.4" - "sway_min_z" "-0.6" - "sway_max_x" "0.5" - "sway_max_y" "0.4" - "sway_max_z" "0.6" - "sway_min_pitch" "-3" - "sway_min_yaw" "-2.5" - "sway_min_roll" "-4" - "sway_max_pitch" "3" - "sway_max_yaw" "2.5" - "sway_max_roll" "4" - "sway_translate_gain" "2.5" - "sway_rotate_gain" "7" - "sway_move_forward_translate_x" "-0.1" - "sway_move_forward_translate_z" "-0.5" - "sway_move_back_translate_x" "0.2" - "sway_move_back_translate_z" "-0.2" - "sway_move_left_translate_y" "-1" - "sway_move_left_translate_z" "-0.5" - "sway_move_left_rotate_roll" "-4" - "sway_move_right_translate_y" "1" - "sway_move_right_translate_z" "-0.5" - "sway_move_right_rotate_roll" "4" - "sway_move_up_translate_z" "-1" - "sway_move_down_translate_z" "1" - "sway_turn_left_rotate_yaw" "1" - "sway_turn_right_rotate_yaw" "-1" - - "sway_turn_left_translate_y" "-.2" - "sway_turn_right_translate_y" ".2" - "sway_turn_up_translate_z" "-.2" - "sway_turn_down_translate_z" ".2" - "sway_turn_up_translate_x" "-.1" - "sway_turn_down_translate_x" ".1" - - "sway_turn_left_rotate_roll" "-4" - "sway_turn_right_rotate_roll" "4" - "sway_turn_up_rotate_pitch" "-3" - "sway_turn_down_rotate_pitch" "3" - "sway_turn_up_rotate_roll" "0.8" - "sway_turn_down_rotate_roll" "-0.8" - - // Zoomed Sway - "sway_rotate_attach_zoomed" "SWAY_ROTATE_ZOOMED" - "sway_rotate_attach_blend_time_zoomed" "0.2" - "sway_rotate_gain_zoomed" "5" - - "sway_min_yaw_zoomed" "-0.04" - "sway_max_yaw_zoomed" "0.04" - "sway_turn_left_rotate_yaw_zoomed" "-0.085" - "sway_turn_right_rotate_yaw_zoomed" "0.085" - - "sway_min_roll_zoomed" "-1" - "sway_max_roll_zoomed" "1" - "sway_turn_left_rotate_roll_zoomed" "-1" - "sway_turn_right_rotate_roll_zoomed" "1" - - "sway_move_right_rotate_roll_zoomed" "0.2" - "sway_move_left_rotate_roll_zoomed" "-0.2" - - "sway_min_pitch_zoomed" "-0.01" - "sway_max_pitch_zoomed" "0.01" - "sway_turn_up_rotate_pitch_zoomed" "0.09" - "sway_turn_down_rotate_pitch_zoomed" "-0.09" - - // NPC - "proficiency_poor_spreadscale" "7.0" - "proficiency_average_spreadscale" "5.0" - "proficiency_good_spreadscale" "3.33333" - "proficiency_very_good_spreadscale" "3.66667" - - "npc_min_range" "0" - "npc_max_range" "1250" - - "npc_min_burst" "1" - "npc_max_burst" "1" - "npc_rest_time_between_bursts_min" "1.25" - "npc_rest_time_between_bursts_max" "1.75" - - // WeaponED Unhandled Key/Values and custom script Key/Values - "bob_tilt_angle" "0.5" - "sway_turn_angle_factor" "-0.5" - "sway_turn_origin_factor" "0" - "sway_turn_angle_factor_zoomed" "0" - "sway_turn_origin_factor_zoomed" "0.05" - "sway_move_angle_factor" "0.15" - "sway_move_origin_factor" "0.15" - "sway_move_angle_factor_zoomed" "0" - "sway_move_origin_factor_zoomed" "0.03" - "sway_gain" "10.0" - "deployfirst_time" "1.0" - "deploycatch_time" "1.33" - "sprintcycle_time" ".55" - - "projectile_lifetime" "0.5" - "projectile_damage_reduction_per_bounce" "0.0" - "projectile_damages_owner" "0" - - // Crosshair - "red_crosshair_range" "300" -} \ No newline at end of file +WeaponData +{ + // General + "printname" "#WPN_SHOTGUN_DBLBARREL" + "shortprintname" "#WPN_SHOTGUN_DBLBARREL_SHORT" + "description" "#WPN_SHOTGUN_DBLBARREL_DESC" + "longdesc" "#WPN_SHOTGUN_DBLBARREL_LONGDESC" + "menu_icon" "rui/weapon_icons/mp_weapon_shotgun_doublebarrel" + "hud_icon" "rui/weapon_icons/mp_weapon_shotgun_doublebarrel" + "viewmodel_offset_hip" "2 -2 -2" + "weaponClass" "human" + "weaponSubClass" "shotgun" + "body_type" "light" + "fire_mode" "semi-auto" + "pickup_hold_prompt" "Hold [USE] [WEAPONNAME]" + "pickup_press_prompt" "[USE] [WEAPONNAME]" + "aimassist_adspull_weaponclass" "broad" + "minimap_reveal_distance" "32000" + "leveled_pickup" "0" + + // Models + "viewmodel" "models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl" + "playermodel" "models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl" + + "OnWeaponPrimaryAttack" "OnWeaponPrimaryAttack_weapon_shotgun" + "OnWeaponNpcPrimaryAttack" "OnWeaponNpcPrimaryAttack_weapon_shotgun" + + + "viewmodel_offset_ads" "0 0 0" + "dof_zoom_nearDepthStart" "2.000" + "dof_zoom_nearDepthEnd" "4.750" + "dof_nearDepthStart" "3.683" + "dof_nearDepthEnd" "5.300" + + // Menu + "menu_category" "shotgun" + "menu_anim_class" "large" + "stat_damage" "50" + "stat_range" "70" + "stat_accuracy" "65" + "stat_rof" "30" + + "impulse_force" "800" + + "impact_effect_table" "inc_bullet" + + // Spread + "spread_stand_hip" "8.5" + "spread_stand_hip_run" "8.5" + "spread_stand_hip_sprint" "8.5" + "spread_crouch_hip" "8.5" + "spread_air_hip" "8.5" + "spread_stand_ads" "8.5" + "spread_crouch_ads" "8.5" + "spread_air_ads" "8.5" + "spread_wallrunning" "8.5" + "spread_wallhanging" "8.5" + + // Damage - When Used by Players + "damage_type" "bullet" + "damage_near_distance" "300" + "damage_far_distance" "700" + "damage_near_value" "220" + "damage_far_value" "25" + "damage_near_value_titanarmor" "130" + "damage_far_value_titanarmor" "10" + + "damage_rodeo" "700" + "damage_falloff_type" "inverse" + "damage_inverse_distance" "130" + "damage_falloff_type" "inverse" + "damage_inverse_distance" "100" + "damage_flags" "DF_SHOTGUN | DF_BULLET | DF_KNOCK_BACK | DF_DISMEMBERMENT" + + "damage_headshot_scale" "1.25" + + "red_crosshair_range" "750" + + // Damage - When Used by NPCs + "npc_damage_near_value" "25" + "npc_damage_far_value" "13" + "npc_damage_near_value_titanarmor" "40" + "npc_damage_far_value_titanarmor" "0" + + "enable_highlight_networking_on_creation" "1" + + "damage_heavyarmor_nontitan_scale" "0.35" + + + // Ammo + "ammo_stockpile_max" "40" + "ammo_default_total" "40" + "ammo_clip_size" "2" + "ammo_no_remove_from_stockpile" "1" + "ammo_min_to_fire" "1" + + "reload_time" "1.85" + "reload_time_late1" "1.15" + "reloadempty_time" "1.85" + "reloadempty_time_late1" "1.15" + + + // Effects + "tracer_effect" "weapon_tracers_shotgun" + "vortex_absorb_effect" "wpn_vortex_projectile_shotgun_FP" + "vortex_absorb_effect_third_person" "wpn_vortex_projectile_shotgun" + "vortex_absorb_sound" "Vortex_Shield_AbsorbBulletSmall" + "vortex_absorb_sound_1p_vs_3p" "Vortex_Shield_AbsorbBulletSmall_1P_VS_3P" + "projectile_adjust_to_gun_barrel" "1" + + "sound_dryfire" "shotgun_dryfire" + "sound_pickup" "wpn_pickup_Rifle_1P" + "fire_sound_1_player_1p" "Weapon_EVA8_AutoFire_1P" + "fire_sound_1_player_3p" "Weapon_EVA8_AutoFire_3P" + "fire_sound_1_npc" "Weapon_EVA8_AutoFire_NPC" + "sound_zoom_in" "Weapon_EVA8_ADS_In" + "sound_zoom_out" "Weapon_EVA8_ADS_Out" + + "low_ammo_sound_name_1" "EVA8_LowAmmo_Shot1" + "low_ammo_sound_name_2" "EVA8_LowAmmo_Shot2" + "low_ammo_sound_name_3" "EVA8_LowAmmo_Shot3" + + "fx_shell_eject_view" "wpn_shelleject_shotshell_FP" + "fx_shell_eject_world" "wpn_shelleject_shotshell" + "fx_shell_eject_attach" "shell" + + "fx_muzzle_flash_view" "mflash_shotgun_fp_FULL" + "fx_muzzle_flash_world" "mflash_shotgun_FULL" + "fx_muzzle_flash_attach" "muzzle_flash" + + + + "critical_hit_damage_scale" "1" + "critical_hit" "1" + + dof_zoom_focusArea_horizontal 0.036 + dof_zoom_focusArea_top 0.070 + dof_zoom_focusArea_bottom -0.023 + + + "titanarmor_critical_hit_required" "1" + + + // Behavior + "fire_rate" "2.75" + "zoom_time_in" "0.25" + "zoom_time_out" "0.2" + "zoom_fov" "55" + "holster_time" "0.5" + "deploy_time" "0.66" + "lower_time" "0.25" + "raise_time" "0.3" + "vortex_refire_behavior" "bullet" + "allow_empty_fire" "0" + "reload_enabled" "1" + "allow_empty_click" "1" + "empty_reload_only" "0" + "trigger_snipercam" "0" + "allow_headshots" "1" + "primary_fire_does_not_block_sprint" "0" + "ads_move_speed_scale" "0.75" + "aimassist_disable_hipfire" "0" + "aimassist_disable_ads" "0" + "aimassist_disable_hipfire_titansonly" "1" + "aimassist_disable_ads_titansonly" "1" + "headshot_distance" "500" + + + "sprint_fractional_anims" "0" + + + + "ammo_suck_behavior" "primary_weapons" + + // View Kick + "viewkick_spring" "shotgun" + + "viewkick_pitch_base" "-1.75" + "viewkick_pitch_random" "0.75" + "viewkick_pitch_softScale" "0.3" + "viewkick_pitch_hardScale" "1.5" + + "viewkick_yaw_base" "-0.65" + "viewkick_yaw_random" "0.38" + "viewkick_yaw_softScale" "0.38" + "viewkick_yaw_hardScale" "1.5" + + "viewkick_roll_base" "0" + "viewkick_roll_randomMin" "0.6" + "viewkick_roll_randomMax" "0.8" + "viewkick_roll_softScale" "0.2" + "viewkick_roll_hardScale" "2.75" + + "viewkick_hipfire_weaponFraction" "0.1" + "viewkick_hipfire_weaponFraction_vmScale" "0.0" + "viewkick_ads_weaponFraction" "0.35" + "viewkick_ads_weaponFraction_vmScale" "0.25" + + "viewkick_perm_pitch_base" "-0.5" + "viewkick_perm_pitch_random" "1.1" + "viewkick_perm_pitch_random_innerexclude" "0.5" + "viewkick_perm_yaw_base" "0.0" + "viewkick_perm_yaw_random" "1.5" + "viewkick_perm_yaw_random_innerexclude" "0.5" + + // + "viewmodel_shake_forward" "0.5" + "viewmodel_shake_up" "0.2" + "viewmodel_shake_right" "0.0" + + // Bob + "bob_cycle_time" "0.45" + "bob_vert_dist" "0.1" + "bob_horz_dist" "0.1" + "bob_max_speed" "150" + "bob_pitch" "0.75" + "bob_yaw" "0.5" + "bob_roll" "-0.75" + + // Bob_Zoomed + "bob_cycle_time_zoomed" "0.4" + "bob_vert_dist_zoomed" "0.01" + "bob_horz_dist_zoomed" "0.01" + "bob_max_speed_zoomed" "150" + //"bob_pitch_zoomed" "0.002" + //"bob_yaw_zoomed" "-.002" + //"bob_roll_zoomed" ".002" + + // Rumble + "fire_rumble" "rumble_shotgun" + + // Sway + "sway_rotate_attach" "SWAY_ROTATE" + "sway_min_x" "-0.5" + "sway_min_y" "-0.5" + "sway_min_z" "-0.6" + "sway_max_x" "0.5" + "sway_max_y" "0.5" + "sway_max_z" "0.6" + "sway_min_pitch" "-3" + "sway_min_yaw" "-2.5" + "sway_min_roll" "-4" + "sway_max_pitch" "3" + "sway_max_yaw" "2.5" + "sway_max_roll" "4" + "sway_translate_gain" "2.5" + "sway_rotate_gain" "7" + "sway_move_forward_translate_x" "-0.1" + "sway_move_forward_translate_z" "-0.5" + "sway_move_back_translate_x" "0.2" + "sway_move_back_translate_z" "-0.2" + "sway_move_left_translate_y" "-1" + "sway_move_left_translate_z" "-0.5" + "sway_move_left_rotate_roll" "-4" + "sway_move_right_translate_y" "1" + "sway_move_right_translate_z" "-0.5" + "sway_move_right_rotate_roll" "4" + "sway_move_up_translate_z" "-1" + "sway_move_down_translate_z" "1" + "sway_turn_left_rotate_yaw" "-2.5" + "sway_turn_right_rotate_yaw" "2.5" + + "sway_turn_left_translate_y" ".5" + "sway_turn_right_translate_y" "-.5" + "sway_turn_up_translate_z" ".2" + "sway_turn_down_translate_z" "-.2" + "sway_turn_up_translate_x" ".1" + "sway_turn_down_translate_x" "-.1" + + "sway_turn_left_rotate_roll" "4" + "sway_turn_right_rotate_roll" "-4" + "sway_turn_up_rotate_pitch" "3" + "sway_turn_down_rotate_pitch" "-3" + "sway_turn_up_rotate_roll" "-0.8" + "sway_turn_down_rotate_roll" "0.8" + + // Zoomed Sway + "sway_rotate_attach_zoomed" "SWAY_ROTATE_ZOOMED" + "sway_rotate_attach_blend_time_zoomed" "0.2" + "sway_rotate_gain_zoomed" "5" + + "sway_min_yaw_zoomed" "-0.045" + "sway_max_yaw_zoomed" "0.045" + "sway_turn_left_rotate_yaw_zoomed" "-0.085" + "sway_turn_right_rotate_yaw_zoomed" "0.085" + + "sway_min_roll_zoomed" "-4" + "sway_max_roll_zoomed" "4" + "sway_turn_left_rotate_roll_zoomed" "0" + "sway_turn_right_rotate_roll_zoomed" "0" + + "sway_move_right_rotate_roll_zoomed" "0.2" + "sway_move_left_rotate_roll_zoomed" "-0.2" + + "sway_min_pitch_zoomed" "-0.03" + "sway_max_pitch_zoomed" "0.03" + "sway_turn_up_rotate_pitch_zoomed" "0.07" + "sway_turn_down_rotate_pitch_zoomed" "-0.07" + + // NPC + "proficiency_poor_spreadscale" "7.0" + "proficiency_average_spreadscale" "5.0" + "proficiency_good_spreadscale" "4.5" + "proficiency_very_good_spreadscale" "3.7" + + "npc_min_engage_range" "0" + "npc_max_engage_range" "800" + "npc_min_engage_range_heavy_armor" "500" + "npc_max_engage_range_heavy_armor" "800" + "npc_min_range" "0" + "npc_max_range" "800" + + "npc_min_burst" "1" + "npc_max_burst" "1" + "npc_rest_time_between_bursts_min" "0.5" + "npc_rest_time_between_bursts_max" "0.7" + + // WeaponED Unhandled Key/Values and custom script Key/Values + "bob_tilt_angle" "0.5" + "sway_turn_angle_factor" "-0.5" + "sway_turn_origin_factor" "0" + "sway_turn_angle_factor_zoomed" "0" + "sway_turn_origin_factor_zoomed" "0.05" + "sway_move_angle_factor" "0.15" + "sway_move_origin_factor" "0.15" + "sway_move_angle_factor_zoomed" "0" + "sway_move_origin_factor_zoomed" "0.03" + "sway_gain" "10.0" + "deployfirst_time" "1.25" + "deploycatch_time" "1.33" + "sprintcycle_time" ".55" + + + "clip_bodygroup" "twinbshotgun_magazine" + "clip_bodygroup_index_shown" "0" + "clip_bodygroup_index_hidden" "1" + "clip_bodygroup_show_for_milestone_0" "1" + "clip_bodygroup_show_for_milestone_1" "0" + "clip_bodygroup_show_for_milestone_2" "1" + "clip_bodygroup_show_for_milestone_3" "1" + Mods + { + iron_sights + { + } + pas_run_and_gun + { + "primary_fire_does_not_block_sprint" "1" + "crosshair_force_sprint_fade_disabled" "1" + } + pas_fast_ads + { + //Fast ADS + "zoom_time_in" "*0.5" + "zoom_time_out" "*0.6" + } + pas_fast_swap + { + //Fast Swap + "fast_swap_to" "1" + } + burn_mod_shotgun + { + "is_burn_mod" "1" + "fx_muzzle_flash_view" "P_wpn_muz_shotgun_amp_FP" + "fx_muzzle_flash_world" "P_wpn_muz_shotgun_amp" + "fx_muzzle_flash_attach" "muzzle_flash" + "tracer_effect" "P_wpn_tracer_shotgun_BC" + + "damage_near_value" "250" + "damage_far_value" "20" + "damage_near_value_titanarmor" "400" + "damage_far_value_titanarmor" "20" + } + } + + + active_crosshair_count "1" + rui_crosshair_index "0" + + RUI_CrosshairData + { + DefaultArgs + { + adjustedSpread weapon_spread + adsFrac player_zoomFrac + isSprinting player_is_sprinting + isReloading weapon_is_reloading + teamColor crosshair_team_color + isAmped weapon_is_amped + crosshairMovementX crosshair_movement_x + crosshairMovementY crosshair_movement_y + } + + Crosshair_1 + { + "ui" "ui/crosshair_shotgun" + "base_spread" "-4.0" + Args + { + isFiring weapon_is_firing + } + } + } +} diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak new file mode 100644 index 00000000..3a714d3b Binary files /dev/null and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak differ diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak new file mode 100644 index 00000000..3bd34467 Binary files /dev/null and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak differ diff --git a/Northstar.Custom/paks/rpak.json b/Northstar.Custom/paks/rpak.json new file mode 100644 index 00000000..743468b4 --- /dev/null +++ b/Northstar.Custom/paks/rpak.json @@ -0,0 +1,5 @@ +{ + "Postload": { + "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak" + } +} \ No newline at end of file diff --git a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk index 036dd8ab..dd8fe7d0 100644 Binary files a/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk and b/Northstar.Custom/vpk/client_mp_northstar_common.bsp.pak000_000.vpk differ diff --git a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk index 4c36af3e..1aff9ac3 100644 Binary files a/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk and b/Northstar.Custom/vpk/englishclient_mp_northstar_common.bsp.pak000_dir.vpk differ -- cgit v1.2.3 From 2cce2943b50952ff7eea36bba529b6ce62ec5ba1 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Sat, 22 Jul 2023 23:04:33 +0300 Subject: Safe IO script part (#595) * Safe IO script part * Fix compile-check * Apply suggestions from code review * Fix compile-check... again... * Apply suggestions from code review :( * Apply suggestions from code review * stuff :) * :D * Add optional failure callback * fix :) * he forgot forgor * Fix memory leak :) * gah * oops :) * Use failed callback if the json file is invalid --------- Co-authored-by: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> --- .github/nativefuncs.json | 144 +++++++++++++++++++++ Northstar.Custom/mod.json | 4 + .../mod/scripts/vscripts/sh_northstar_safe_io.gnut | 83 ++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 751b4893..6f46095f 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -179,6 +179,54 @@ "helpText":"Whether or not HTTP requests can be made to a private network address. You can enable this by starting the game with -allowlocalhttp.", "returnTypeString":"bool", "argTypes":"" + }, + { + "name":"NS_InternalLoadFile", + "helpText":"Loads a file asynchronously.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSSaveFile", + "helpText":"Saves a file.", + "returnTypeString":"void", + "argTypes":"string file, string data" + }, + { + "name":"NSSaveJSONFile", + "helpText":"Converts a squirrel table to a json string, then saves it to a file.", + "returnTypeString":"void", + "argTypes":"string file, table data" + }, + { + "name":"NSDoesFileExist", + "helpText":"Checks whether or not a file exists.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NSDeleteFile", + "helpText":"Deletes a file.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NS_InternalGetAllFiles", + "helpText":"Returns an array of all files in a mod's save folder.", + "returnTypeString":"array", + "argTypes":"string path" + }, + { + "name":"NSGetFileSize", + "helpText":"Returns the size of a file, in KB, rounded down.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSIsFolder", + "helpText":"Returns whether or not a given path leads to a folder.", + "returnTypeString":"bool", + "argTypes":"string path" } ], "CLIENT":[ @@ -327,6 +375,54 @@ "argTypes":"" }, { + "name":"NS_InternalLoadFile", + "helpText":"Loads a file asynchronously.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSSaveFile", + "helpText":"Saves a file.", + "returnTypeString":"void", + "argTypes":"string file, string data" + }, + { + "name":"NSSaveJSONFile", + "helpText":"Converts a squirrel table to a json string, then saves it to a file.", + "returnTypeString":"void", + "argTypes":"string file, table data" + }, + { + "name":"NSDoesFileExist", + "helpText":"Checks whether or not a file exists.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NSDeleteFile", + "helpText":"Deletes a file.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NS_InternalGetAllFiles", + "helpText":"Returns an array of all files in a mod's save folder.", + "returnTypeString":"array", + "argTypes":"string path" + }, + { + "name":"NSGetFileSize", + "helpText":"Returns the size of a file, in KB, rounded down.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSIsFolder", + "helpText":"Returns whether or not a given path leads to a folder.", + "returnTypeString":"bool", + "argTypes":"string path" + }, + { "name":"NSPushGameStateData", "helpText":"", "returnTypeString":"void", @@ -581,6 +677,54 @@ "argTypes":"" }, { + "name":"NS_InternalLoadFile", + "helpText":"Loads a file asynchronously.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSSaveFile", + "helpText":"Saves a file.", + "returnTypeString":"void", + "argTypes":"string file, string data" + }, + { + "name":"NSSaveJSONFile", + "helpText":"Converts a squirrel table to a json string, then saves it to a file.", + "returnTypeString":"void", + "argTypes":"string file, table data" + }, + { + "name":"NSDoesFileExist", + "helpText":"Checks whether or not a file exists.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NSDeleteFile", + "helpText":"Deletes a file.", + "returnTypeString":"bool", + "argTypes":"string file" + }, + { + "name":"NS_InternalGetAllFiles", + "helpText":"Returns an array of all files in a mod's save folder.", + "returnTypeString":"array", + "argTypes":"string path" + }, + { + "name":"NSGetFileSize", + "helpText":"Returns the size of a file, in KB, rounded down.", + "returnTypeString":"int", + "argTypes":"string file" + }, + { + "name":"NSIsFolder", + "helpText":"Returns whether or not a given path leads to a folder.", + "returnTypeString":"bool", + "argTypes":"string path" + }, + { "name":"NSPushUIPresence", "helpText":"", "returnTypeString":"void", diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 5fcdb0fd..22f9c45f 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -430,6 +430,10 @@ { "Path": "sh_northstar_http_requests.gnut", "RunOn": "CLIENT || SERVER || UI" + }, + { + "Path": "sh_northstar_safe_io.gnut", + "RunOn": "CLIENT || SERVER || UI" } ], diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut new file mode 100644 index 00000000..f7b31cc2 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/sh_northstar_safe_io.gnut @@ -0,0 +1,83 @@ +globalize_all_functions + +table< int, void functionref( string ) > pendingCallbacks +table< int, void functionref( table ) > pendingJSONCallbacks +table< int, void functionref() > failedCallbacks + + +void function NSLoadFile( string file, void functionref( string ) onSuccess, void functionref() onFailure = null ) +{ + int handle = NS_InternalLoadFile( file ) + + pendingCallbacks[handle] <- onSuccess + if (onFailure != null) + failedCallbacks[handle] <- onFailure +} + +void function NSLoadJSONFile( string file, void functionref( table ) onSuccess, void functionref() onFailure = null ) +{ + int handle = NS_InternalLoadFile( file ) + + pendingJSONCallbacks[handle] <- onSuccess + if (onFailure != null) + failedCallbacks[handle] <- onFailure +} + +void function NSHandleLoadResult( int handle, bool success, string result ) +{ + bool hasFailedCallback = handle in failedCallbacks + bool isJSONRequest = handle in pendingJSONCallbacks + bool isValid = isJSONRequest || handle in pendingCallbacks + + if (!isValid) + throw "Invalid IO callback handle" + + if (success) + { + if (isJSONRequest) + { + try + { + table result = DecodeJSON(result, true) + pendingJSONCallbacks[handle](result) + } + catch (ex) + { + print(ex) + // parsing failed, setting 'success' to false, since we + // consider this a failure. + success = false + } + } + else + { + pendingCallbacks[handle](result) + } + } + // don't use 'else', json might fail parsing and set 'success' to false. + if (!success) + { + if (hasFailedCallback) + failedCallbacks[handle]() + else + { + if (isJSONRequest) + pendingJSONCallbacks[handle]({}) + else + pendingCallbacks[handle]("") + } + } + + if (isJSONRequest) + delete pendingJSONCallbacks[handle] + else + delete pendingCallbacks[handle] + + if (hasFailedCallback) + delete failedCallbacks[handle] +} + +array function NSGetAllFiles( string path = "" ) +{ + return NS_InternalGetAllFiles(path) +} -- cgit v1.2.3 From 281850f63719e88a7a32d623f0e03719f61352bb Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 23 Jul 2023 13:55:47 +0200 Subject: Translations update from Weblate (#668) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 36 ++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index d90cea05..d5881d6c 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -64,7 +64,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "earn_meter_pilot_multiplier" "Multiplicateur de boost pilote" "earn_meter_titan_multiplier" "Multiplicateur de boost titan" - "aegis_upgrades" "Aegis Upgrades" + "aegis_upgrades" "Upgrades Aegis" "infinite_doomed_state" "Etat condamné infini" "titan_shield_regen" "Régénération des boucliers" @@ -86,13 +86,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Bac à sable" - "PL_sbox_lobby" "Lobby: Bac à sable" - "PL_sbox_desc" "GMod, mais en pire..." + "PL_sbox_lobby" "Lobby : Bac à sable" + "PL_sbox_desc" "GMod, mais en pire" "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Bac à sable" "PL_gg" "Gun game" - "PL_gg_lobby" "Lobby: Gun game" + "PL_gg_lobby" "Lobby : Gun game" "PL_gg_desc" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner." "PL_gg_hint" "Obtenez une nouvelle arme à chaque frag.\nTuez un pilote avec chaque arme pour gagner." "PL_gg_abbr" "GG" @@ -102,21 +102,21 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "gg_execution_reward" "Récompense pourcentage d'exécutions" "PL_tt" "Titan tag" - "PL_tt_lobby" "Lobby: Titan tag" + "PL_tt_lobby" "Lobby : Titan tag" "PL_tt_desc" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre." "PL_tt_hint" "Gagnez des points lorsque vous êtes dans votre titan.\nDétruisez un titan pour obtenir le vôtre." "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan tag" "PL_chamber" "Le professionnel" - "PL_chamber_lobby" "Lobby: Le professionnel" + "PL_chamber_lobby" "Lobby : Le professionnel" "PL_chamber_desc" "Un tir, un mort.\nObtenez une balle en tuant un pilote." "PL_chamber_hint" "Un tir, un mort.\nObtenez une balle en tuant un pilote." "PL_chamber_abbr" "CHAMBER" "GAMEMODE_CHAMBER" "Le professionnel" "PL_hidden" "Chasse" - "PL_hidden_lobby" "Lobby: Chasse" + "PL_hidden_lobby" "Lobby : Chasse" "PL_hidden_desc" "Un pilote est invisible et chasse les autres." "PL_hidden_hint" "Un pilote est invisible et chasse les autres." "PL_hidden_abbr" "HIDDEN" @@ -126,7 +126,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "HIDDEN_FIRST_HIDDEN" "%s1 est le chasseur." "PL_sns" "Sticks and Stones" - "PL_sns_lobby" "Lobby: Sticks and Stones" + "PL_sns_lobby" "Lobby : Sticks and Stones" "PL_sns_desc" "Chacun pour soi.\nLes exécutions et les lames à impulsions réinitialisent le score de vos ennemis." "PL_sns_abbr" "SNS" "GAMEMODE_SNS" "Sticks and Stones" @@ -144,7 +144,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "sns_softball_enabled" "Softball activé" "PL_inf" "Infection" - "PL_inf_lobby" "Lobby: Infection" + "PL_inf_lobby" "Lobby : Infection" "PL_inf_desc" "Les pilotes survivants deviennent infectés lorsque tués." "PL_inf_hint" "Les pilotes survivants deviennent infectés lorsque tués." "PL_inf_abbr" "INF" @@ -158,14 +158,14 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "INFECTION_SURVIVE_LAST_SURVIVOR" "Survivez." "PL_tffa" "Chacun pour soi (titans)" - "PL_tffa_lobby" "Lobby: Chacun pour soi (titans)" + "PL_tffa_lobby" "Lobby : Chacun pour soi (titans)" "PL_tffa_desc" "Chacun pour soi.\nDétruisez les titans ennemis." "PL_tffa_hint" "Chacun pour soi.\nDétruisez les titans ennemis." "PL_tffa_abbr" "TFFA" "GAMEMODE_TFFA" "Chacun pour soi (titans)" "PL_hs" "Cache-cache" - "PL_hs_lobby" "Lobby: Cache-cache" + "PL_hs_lobby" "Lobby : Cache-cache" "PL_hs_desc" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux." "PL_hs_hint" "Les pilotes doivent se cacher pour ne pas être trouvés par l'un d'eux." "PL_hs_abbr" "HS" @@ -185,13 +185,13 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development "GAMEMODE_fw" "Guerre pour la Frontière" "PL_fw" "Guerre pour la Frontière" - "PL_fw_lobby" "Lobby: Guerre pour la Frontière" + "PL_fw_lobby" "Lobby : Guerre pour la Frontière" "PL_fw_desc" "Détruisez le collecteur ennemi et protégez le vôtre." "PL_fw_abbr" "FW" "GAMEMODE_kr" "Course aux frags" "PL_kr" "Course aux frags" - "PL_kr_lobby" "Lobby: Course aux frags" + "PL_kr_lobby" "Lobby : Course aux frags" "PL_kr_desc" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte." "PL_kr_hint" "Capturez le drapeau pour devenir le prédateur.\nFaites des victimes pour établir un nouveau record de frags.\nLe pilote ayant le plus de frags à la fin de la partie l'emporte." "PL_kr_abbr" "KR" @@ -207,12 +207,12 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "GAMEMODE_fastball" "Fastball" "PL_fastball" "Fastball" - "PL_fastball_lobby" "Lobby: Fastball" + "PL_fastball_lobby" "Lobby : Fastball" "PL_fastball_desc" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers." "PL_fastball_hint" "Mort permanente.\nPiratez les panneaux de contrôle pour faire réapparaître vos équipiers." "PL_fastball_abbr" "FB" "FASTBALL_PANEL_CAPTURED" "%s1 a piraté le panneau de contrôle %s2 !" - "SCOREBOARD_FASTBALL_HACKS" "Panneaux de\ncontrôle capturés" + "SCOREBOARD_FASTBALL_HACKS" "Panneaux de contrôle capturés" "GAMEMODE_ctf_comp" "Capture de drapeau - Compétitif" @@ -239,7 +239,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst // coop stuff "PL_sp_coop" "(ALPHA) Campagne (coop)" - "PL_sp_coop_lobby" "Lobby: Campagne (coop)" + "PL_sp_coop_lobby" "Lobby : Campagne (coop)" "PL_sp_coop_desc" "Jouez la campagne avec des amis." "PL_sp_coop_hint" "Jouez la campagne avec des amis." "PL_sp_coop_abbr" "SP" @@ -337,5 +337,9 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "MOD_SETTINGS_SERVER" "Serveur" "MOD_SETTINGS_RESET" "Réinitialiser" "MOD_SETTINGS_RESET_ALL" "Tout réinitialiser" + "SHOW_ONLY_REQUIRED" "Afficher les mods requis" + "SHOW_ONLY_NOT_REQUIRED" "Uniquement les mods optionnels" + "NO_RESULTS" "Aucun résultat." + "NO_MODS" "Aucun paramètre trouvé ! Installez d'autres mods depuis ^5588FF00northstar.thunderstore.io^0." } } -- cgit v1.2.3 From 5fb567743e5a5b72d8de486de3296063740dceca Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 24 Jul 2023 13:05:01 +0200 Subject: Translations update from Weblate (#669) * Translated using Weblate (Portuguese) Currently translated at 99.6% (274 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (275 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ --------- Co-authored-by: William Miller --- .../northstar_client_localisation_portuguese.txt | 106 ++++++++++++++------- 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 51854726..b6364db4 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -15,14 +15,14 @@ "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Obrigado por instalar Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para o Northstar funcionar é necessário autenticar com o servidor mestre Northstar. Isso requer enviar seu token da Origin para o servidor, ele não será utilizado pra outros propósitos. Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momento no menu de mods." - "BACK_AUTHENTICATION_AGREEMENT" "Aceitação de autorização" - "AUTHENTICATION_AGREEMENT" "Aceitação de autorização" + "BACK_AUTHENTICATION_AGREEMENT" "Acordo de Autenticação" + "AUTHENTICATION_AGREEMENT" "Acordo de Autenticação" "AUTHENTICATION_AGREEMENT_RESTART" "Você precisa reiniciar o Titanfall 2 para esta mudança ter efeito." "DIALOG_AUTHENTICATING_MASTERSERVER" "Autenticando com o servidor mestre." - "AUTHENTICATIONAGREEMENT_NO" "Você não autorizou a autenticação com Northstar. Troque a configuração no menu de mods." + "AUTHENTICATIONAGREEMENT_NO" "Você escolheu não autenticar com Northstar. Você pode ver o acordo no menu de Mods." - "MENU_TITLE_SERVER_BROWSER" "Servidores" + "MENU_TITLE_SERVER_BROWSER" "Lista de Servidores" "NS_SERVERBROWSER_NOSERVERS" "Nenhum servidor encontrado" "NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconhecido" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Aguardando servidores..." @@ -52,9 +52,9 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "classic_mp" "MP Clássico" "run_epilogue" "Executar epílogo" "scorelimit" "Limite de pontos" - "roundscorelimit" "Limite de pontos (por round)" + "roundscorelimit" "Limite de pontos (por rodada)" "timelimit" "Tempo limite" - "roundtimelimit" "Tempo limite (por round)" + "roundtimelimit" "Tempo limite (por rodada)" "respawnprotection" "Proteção de reaparecimento" "pilot_health_multiplier" "Multiplicador de vida" @@ -64,16 +64,16 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "earn_meter_pilot_multiplier" "Multiplicador de bônus" "earn_meter_titan_multiplier" "Multiplicador de bônus do titã" - "aegis_upgrades" "Upgrades Aegis" + "aegis_upgrades" "Melhorias de Égide" "infinite_doomed_state" "Estado condenado infinito" "titan_shield_regen" "Escudos regeneradores" - "riff_floorislava" "Deadly Ground" - "featured_mode_all_holopilot" "The Great Bamboozle" - "featured_mode_all_grapple" "Attack on Titanfall" - "featured_mode_all_phase" "The Otherside" - "featured_mode_all_ticks" "Spicy" - "featured_mode_tactikill" "Tactikill" + "riff_floorislava" "Terreno Mortal" + "featured_mode_all_holopilot" "A Grande Enganação" + "featured_mode_all_grapple" "Ataque aos Titãs" + "featured_mode_all_phase" "O Outro Lado" + "featured_mode_all_ticks" "Picante" + "featured_mode_tactikill" "Mortático" "featured_mode_amped_tacticals" "Habilidades táticas melhoradas" "featured_mode_rocket_arena" "Arena Foguete" "featured_mode_shotguns_snipers" "Armado e perigoso" @@ -89,14 +89,14 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_sbox_abbr" "SBOX" "GAMEMODE_SBOX" "Sandbox" - "PL_gg" "Gun Game" - "PL_gg_lobby" "Saguão de Gun Game" - "PL_gg_desc" "Mate com todas as armas para vencer" - "PL_gg_hint" "Mate com todas as armas para vencer" + "PL_gg" "Jogo de Armas" + "PL_gg_lobby" "Saguão de Jogo de Armas" + "PL_gg_desc" "Mate com cada arma para vencer." + "PL_gg_hint" "Mate com cada arma para vencer." "PL_gg_abbr" "GG" - "GAMEMODE_GG" "Gun Game" + "GAMEMODE_GG" "Jogo de Armas" "gg_kill_reward" "% recompensa/morte" - "gg_assist_reward" "% recompensa/assist" + "gg_assist_reward" "% recompensa/assistência" "gg_execution_reward" "% recompensa/execução" "PL_tt" "Titan Tag" @@ -106,20 +106,20 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan Tag" - "PL_chamber" "One in the Chamber" - "PL_chamber_lobby" "Saguão de One in the Chamber" - "PL_chamber_desc" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo." - "PL_chamber_hint" "Um tiro, uma morte. Ganhe outra munição ao abater um inimigo." - "PL_chamber_abbr" "CHAMBER" - "GAMEMODE_CHAMBER" "One in the Chamber" + "PL_chamber" "Um na Câmara" + "PL_chamber_lobby" "Saguão de Um na Câmara" + "PL_chamber_desc" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo." + "PL_chamber_hint" "Um tiro, uma morte. Ganhe uma bala no pente ao abater um inimigo." + "PL_chamber_abbr" "CÂMARA" + "GAMEMODE_CHAMBER" "Um na Câmara" - "PL_hidden" "O Fantasma" - "PL_hidden_lobby" "Saguão de O Fantasma" + "PL_hidden" "O Oculto" + "PL_hidden_lobby" "Saguão de O Oculto" "PL_hidden_desc" "Um jogador se torna invisível enquanto o resto o caça." "PL_hidden_hint" "Um jogador se torna invisível enquanto o resto o caça." "PL_hidden_abbr" "HIDDEN" - "GAMEMODE_HIDDEN" "The Hidden" - "HIDDEN_YOU_ARE_HIDDEN" "Você é o fantasma!" + "GAMEMODE_HIDDEN" "O Oculto" + "HIDDEN_YOU_ARE_HIDDEN" "Você é o ocultado!" "HIDDEN_KILL_SURVIVORS" "Mate todos os sobreviventes." "HIDDEN_FIRST_HIDDEN" "%s1 é O Fantasma." @@ -155,12 +155,12 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "INFECTION_YOU_ARE_LAST_SURVIVOR" "Você é o último sobrevivente!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sobreviva." - "PL_tffa" "Free for All Titã" - "PL_tffa_lobby" "Saguão de Free for All Titã" + "PL_tffa" "Cada Titã por si" + "PL_tffa_lobby" "Saguão de Cada Titã por si" "PL_tffa_desc" "Cada um por si, destrua todos os titãs inimigos." "PL_tffa_hint" "Cada um por si, destrua todos os titãs inimigos." "PL_tffa_abbr" "TFFA" - "GAMEMODE_TFFA" "Free for All Titã" + "GAMEMODE_TFFA" "Cada Titã por si" "PL_hs" "Esconde-esconde" "PL_hs_lobby" "Saguão de Esconde-esconde" @@ -168,7 +168,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "PL_hs_hint" "Jogo clássico de esconde-esconde." "PL_hs_abbr" "HS" "GAMEMODE_hs" "Esconde-esconde" - "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA!" + "HIDEANDSEEK_YOU_ARE_SEEKER" "VOCÊ PEGA" "HIDEANDSEEK_SEEKER_DESC" "Ache os outros e bata neles.\nVocê reaparecerá em %s1 segundos" "HIDEANDSEEK_YOU_ARE_HIDER" "VOCÊ ESCONDE" "HIDEANDSEEK_HIDER_DESC" "Esconda-se." @@ -203,8 +203,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "KR_YOUR_KILLRACE_OVER" "Sua matança acabou" "KR_YOUR_KILLRACE_SCORE" "Você conseguiu %s1 mortes." - "GAMEMODE_fastball" "Fastball" - "PL_fastball" "Fastball" + "GAMEMODE_fastball" "Travessia Impulsionada" + "PL_fastball" "Travessia Impulsionada" "PL_fastball_lobby" "Saguão de Fastball" "PL_fastball_desc" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados." "PL_fastball_hint" "Sem reaparecimento. Invada painéis de controle para ganhar rounds e reaparecer seus aliados." @@ -236,8 +236,8 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "player_bleedout_aiBleedingPlayerMissChance" "Chance de erro da IA ao cair" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Saguão de Singleplayer em grupo" + "PL_sp_coop" "(NÃO-TERMINADO) Campanha Cooperativa" + "PL_sp_coop_lobby" "Saguão de Campanha Cooperativa" "PL_sp_coop_desc" "Jogue através da campanha com seus amigos" "PL_sp_coop_hint" "Jogue através da campanha com seus amigos" "PL_sp_coop_abbr" "SP" @@ -306,5 +306,37 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen // In-game chat "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "ONLY_HOST_MATCH_SETTINGS" "Somente o Host pode mudar as configurações da Partida Privada" + "ONLY_HOST_CAN_START_MATCH" "Somente o Host pode Iniciar a Partida" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar Comandos desconhecidos de Clientes" + "DISALLOWED_TACTICALS" "Táticos Proibidos" + "TACTICAL_REPLACEMENT" "Tático Substituto" + "DISALLOWED_WEAPONS" "Armas Proibidas" + "REPLACEMENT_WEAPON" "Armas Substitutas" + "ARE_YOU_SURE" "Tem certeza?" + "WILL_RESET_ALL_SETTINGS" "Isso irá resetar TODAS as configurações que pertecem a essa categoria.\n\nAção não reversível." + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET" "Resetar" + "MOD_SETTINGS_RESET_ALL" "Resetar Tudo" + "NO_RESULTS" "Sem resultados." + "NO_MODS" "Sem configurações disponíveis. Instale mais mods em ^5588FF00northstar.thunderstore.io^0." + "SHOW_ONLY_NOT_REQUIRED" "Somente Mods Opcionais" + "NO_GAMESERVER_RESPONSE" "Não foi possível alcançar o servidor da partida" + "BAD_GAMESERVER_RESPONSE" "Servidor da partida sem resposta válida" + "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" + "UNAUTHORIZED_PWD" "Senha inválida" + "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido" + "JSON_PARSE_ERROR" "Erro ao ler a resposta json" + "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" + "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" + "STRYDER_RESPONSE" "Não foi possível ler a resposta do Stryder" + "UNSUPPORTED_VERSION" "A versão que você está usando não é mais suportada" + "MOD_SETTINGS" "Configurações de Mod" + "NORTHSTAR_BASE_SETTINGS" "Configurações Base do Northstar" + "MATCH_COUNTDOWN_LENGTH" "Duração da contagem da Partida Privada" + "SHOULD_RETURN_TO_LOBBY" "Retornar ao saguão após término de Partida" + "WILL_RESET_SETTING" "Isso irá resetar a configuração %s1 ao valor padrão.\n\nAção não reversível." + "aitdm_archer_grunts" "Soldados com Archer" } } -- cgit v1.2.3 From 75dc032a8184e770360c6bd3acc1e9b6f37da13f Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 24 Jul 2023 20:49:36 +0200 Subject: Translations update from Weblate (#670) Translated using Weblate (German) Currently translated at 89.8% (247 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ Co-authored-by: GeckoEidechse --- Northstar.Client/mod/resource/northstar_client_localisation_german.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index f5c814f5..f1994a24 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -311,5 +311,6 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "JSON_PARSE_ERROR" "Fehler beim Verarbeiten der JSON-Antwort" "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" + "SNS_BANKRUPT_SUB" "Dein Punkestand wurde von %s1 zurückgesetzt" } } -- cgit v1.2.3 From 18298d266cea088f777a59ef94ec8fafdd78d339 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 25 Jul 2023 21:40:30 +0100 Subject: Fix Arc Cannon not dealing damage when used by NPCs (#666) Fixes NPCs using mp_titanweapon_arc_cannon not dealing damage to other entities --- Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut | 10 +++++++--- .../mod/scripts/weapons/mp_titanweapon_arc_cannon.txt | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut index cd58ef06..01138967 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -552,12 +552,16 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) int damageNearValue = eWeaponVar.damage_near_value int damageFarValueTitanArmor = eWeaponVar.damage_far_value_titanarmor int damageNearValueTitanArmor = eWeaponVar.damage_near_value_titanarmor + int damageFarDistance = eWeaponVar.damage_far_distance + int damageNearDistance = eWeaponVar.damage_near_distance if ( zapInfo.player.IsNPC() ) { damageFarValue = eWeaponVar.npc_damage_far_value damageNearValue = eWeaponVar.npc_damage_near_value damageFarValueTitanArmor = eWeaponVar.npc_damage_far_value_titanarmor damageNearValueTitanArmor = eWeaponVar.npc_damage_near_value_titanarmor + damageFarDistance = eWeaponVar.npc_damage_far_distance + damageNearDistance = eWeaponVar.npc_damage_near_distance } if ( IsValid( target ) && IsValid( zapInfo.player ) ) @@ -613,8 +617,8 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) { // use distance for damage if the weapon auto-fires entity weapon = expect entity( zapInfo.weapon ) - float nearDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_near_distance ) - float farDist = weapon.GetWeaponSettingFloat( eWeaponVar.damage_far_distance ) + float nearDist = weapon.GetWeaponSettingFloat( damageNearDistance ) + float farDist = weapon.GetWeaponSettingFloat( damageFarDistance ) float dist = Distance( weapon.GetOrigin(), target.GetOrigin() ) damageAmount = GraphCapped( dist, farDist, nearDist, damageMin, damageMax ) @@ -1044,4 +1048,4 @@ function GetWeaponChargeFrac( weapon ) if ( weapon.IsChargeWeapon() ) return weapon.GetWeaponChargeFraction() return 1.0 -} \ No newline at end of file +} diff --git a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt index 11d87a4d..2672dca9 100644 --- a/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt +++ b/Northstar.Custom/mod/scripts/weapons/mp_titanweapon_arc_cannon.txt @@ -56,6 +56,12 @@ WeaponData "damage_far_value_titanarmor" "100" // Damage - When Used by NPCs + "npc_damage_near_distance" "200" + "npc_damage_far_distance" "2500" + "npc_damage_near_value" "220" + "npc_damage_far_value" "170" + "npc_damage_near_value_titanarmor" "1800" + "npc_damage_far_value_titanarmor" "100" "critical_hit" "0" "critical_hit_damage_scale" "1.5" @@ -340,4 +346,4 @@ WeaponData } } } -} \ No newline at end of file +} -- cgit v1.2.3 From efdf780a8e8645b854c43683cc366e4db63dcae0 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 30 Jul 2023 11:52:16 +0200 Subject: Translations update from Weblate (#675) Translated using Weblate (Russian) Currently translated at 94.9% (261 of 275 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../northstar_client_localisation_russian.txt | 152 +++++++++++++++------ 1 file changed, 111 insertions(+), 41 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index fe7cf2b3..d26017b8 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -17,7 +17,7 @@ "MENU_TITLE_SERVER_BROWSER" "Список серверов" "NS_SERVERBROWSER_NOSERVERS" "Серверов не найдено" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Ожидание серверов..." - "NS_SERVERBROWSER_CONNECTIONFAILED" "Соединение провалено!" + "NS_SERVERBROWSER_CONNECTIONFAILED" "Не удалось подключиться!" "REFRESH_SERVERS" "Обновить" "MENU_TITLE_CONNECT_PASSWORD" "Подключиться с помощью пароля" @@ -41,7 +41,7 @@ "MODE_SETTING_CATEGORY_MATCH" "Матч" "classic_mp" "Классический мультиплеер" - "run_epilogue" "Запустить эпилог" + "run_epilogue" "Показывать эпилог" "scorelimit" "Лимит очков" "roundscorelimit" "Лимит очков (по раундам)" "timelimit" "Лимит времени" @@ -58,19 +58,19 @@ "infinite_doomed_state" "Бесконечное обречённое состояние" "titan_shield_regen" "Регенерация щитов" - "riff_floorislava" "Смертельная Земля" + "riff_floorislava" "Пол это лава" "featured_mode_all_holopilot" "Великий обманщик" - "featured_mode_all_grapple" "Зацепщик" - "featured_mode_all_phase" "Альтернативное пространство" - "featured_mode_all_ticks" "Острый" + "featured_mode_all_grapple" "Зацепер" + "featured_mode_all_phase" "Мир иной" + "featured_mode_all_ticks" "Горячие парни" "featured_mode_tactikill" "Тактический удар" "featured_mode_amped_tacticals" "Усиленные тактики" "featured_mode_rocket_arena" "Ракетная Арена" "featured_mode_shotguns_snipers" "Вооружён и опасен" "iron_rules" "Правила Железного Титана" - "cp_amped_capture_points" "Усиленные точки опоры" - "coliseum_loadouts_enabled" "Выгрузка коллизея" + "cp_amped_capture_points" "Усиленные опорные пункты" + "coliseum_loadouts_enabled" "Экипировка Колизея" // northstar.custom localisation is just deciding not to work, so putting it here for now "PL_sbox" "Песочница" @@ -81,9 +81,9 @@ "PL_gg" "Гонка вооружений" "PL_gg_lobby" "Лобби гонки вооружений" - "PL_gg_desc" "Уничтожьте противника из всех видов оружия чтобы победить." - "PL_gg_hint" "Уничтожьте противника из всех видов оружия чтобы победить." - "PL_gg_abbr" "GG" + "PL_gg_desc" "Убейте по одному противнику из каждого вида оружия." + "PL_gg_hint" "Убейте по одному противнику из каждого вида оружия." + "PL_gg_abbr" "ГВ" "GAMEMODE_GG" "Гонка вооружений" "PL_tt" "Разборки Титанов" @@ -99,10 +99,10 @@ "PL_inf_hint" "Переживите инфекцию. Выжившие становятся заражёнными при убийстве." "PL_inf_abbr" "INF" "GAMEMODE_INF" "Заражение" - "INFECTION_YOU_ARE_INFECTED" "Вы были заражены!" + "INFECTION_YOU_ARE_INFECTED" "Вас заразили!" "INFECTION_KILL_SURVIVORS" "Заразите всех оставшихся выживших." "INFECTION_FIRST_INFECTED" "%s1 был заражён первым." - "INFECTION_LAST_SURVIVOR" "%s1 выжил последним!" + "INFECTION_LAST_SURVIVOR" "%s1 — последний выживший!" "INFECTION_KILL_LAST_SURVIVOR" "Зарази их, пока время не вышло!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "Вы последний выживший!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Выживите." @@ -116,19 +116,19 @@ "HIDEANDSEEK_YOU_ARE_SEEKER" "ВЫ ИЩЕТЕ" "HIDEANDSEEK_SEEKER_DESC" "Найдите прячущихся и ударьте их.\nВы появитесь через %s1 секунд(у)" "HIDEANDSEEK_YOU_ARE_HIDER" "ВЫ ПРЯЧЕТЕСЬ" - "HIDEANDSEEK_HIDER_DESC" "Спрятайтесь." + "HIDEANDSEEK_HIDER_DESC" "Спрячьтесь." "HIDEANDSEEK_SEEKERS_INCOMING" "ИЩУЩИЕ ВЫДВИГАЮТСЯ" "HIDEANDSEEK_DONT_GET_FOUND" "Не дайте себя найти!" "HIDEANDSEEK_GET_LAST_HIDER" "%s1 ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ" "HIDEANDSEEK_YOU_ARE_LAST_HIDER" "ВЫ ПОСЛЕДНИЙ СПРЯТАВШИЙСЯ" - "HIDEANDSEEK_GOT_STIM" "Вас остановили! Не попадитесь!" + "HIDEANDSEEK_GOT_STIM" "Применён стим! Не попадитесь!" "hideandseek_balance_teams" "Автобаланс обеих сторон" "hideandseek_hiding_time" "Время спрятаться" // these are defined in r1_english but titan war is a shit name so i'm changing it to another one that was referenced in development - "GAMEMODE_fw" "Пограничная война" - "PL_fw" "Пограничная война" - "PL_fw_lobby" "Лобби пограничной войны" + "GAMEMODE_fw" "Война за Фронтир" + "PL_fw" "Война за Фронтир" + "PL_fw_lobby" "Лобби Войны за Фронтир" "PL_fw_desc" "Уничтожьте харвестер противника и защитите свой" "PL_fw_abbr" "FW" @@ -136,22 +136,22 @@ "PL_kr" "Усиленные гонки убийств" "PL_kr_lobby" "Лобби усиленных гонок убийств" - "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить." - "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать его. Установите рекорд убийств, чтобы победить." + "PL_kr_desc" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить." + "PL_kr_hint" "Получайте убийства, чтобы увеличить продолжительность вашей гонки за убийствами. Соберите флаг, чтобы начать её. Установите рекорд убийств, чтобы победить." "PL_kr_abbr" "KR" "SCOREBOARD_KR_RECORD" "Рекорд убийств" "KR_NEW_RACER" "%s1 усиленный гонщик за убийства" "KR_YOU_ARE_NEW_RACER" "Вы усиленный гонщик за убийства" "KR_YOU_SET_NEW_RECORD" "Установите новый рекорд убийств!" "KR_FLAG_INCOMING" "Флаг прибывает" - "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убиства!" + "KR_COLLECT_FLAG" "Возьмите его чтобы стать гонщиком за убийства!" "KR_ENEMY_KILLRACE_OVER" "Гонки убийств у %s1 закончились" "KR_YOUR_KILLRACE_OVER" "Ваши гонки убийств кончились" "KR_YOUR_KILLRACE_SCORE" "У вас %s1 убийств." - "GAMEMODE_fastball" "Фастболл" - "PL_fastball" "Фастболл" - "PL_fastball_lobby" "Лобби фастболла" + "GAMEMODE_fastball" "Фастбол" + "PL_fastball" "Фастбол" + "PL_fastball_lobby" "Лобби фастбола" "PL_fastball_desc" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды." "PL_fastball_hint" "Перманентная смерть. Взломайте панели управления чтобы побеждать в раундах и возродить своих членов команды." "PL_fastball_abbr" "FB" @@ -161,20 +161,20 @@ "GAMEMODE_ctf_comp" "Соревновательное CTF" // mode settings - "MODE_SETTING_CATEGORY_PROMODE" "Продвинутое оружие" + "MODE_SETTING_CATEGORY_PROMODE" "Режим про" "MODE_SETTING_CATEGORY_BLEEDOUT" "Кровотечение пилота" "custom_air_accel_pilot" "Ускорение в воздухе" - "promode_enable" "Продвинутое оружие" - "fp_embark_enabled" "Отправления/Казни от первого лица" + "promode_enable" "Оружие из режима про" + "fp_embark_enabled" "Казни/посадки в титана от первого лица" "classic_rodeo" "Классическое родео" "oob_timer_enabled" "Таймер уничтожения за пределами карты" "riff_instagib" "Моментальная смерть при попадании" "riff_player_bleedout" "Кровотечение пилота" - "player_bleedout_forceHolster" "Использовать оружие из кобуры при кровотечении" + "player_bleedout_forceHolster" "Убирать оружие при кровотечении" "player_bleedout_forceDeathOnTeamBleedout" "Смерть при кровотечении во всей команде" - "player_bleedout_bleedoutTime" "Кремя кровотечения" + "player_bleedout_bleedoutTime" "Время кровотечения" "player_bleedout_firstAidTime" "Время оказания первой помощи" "player_bleedout_firstAidTimeSelf" "Время оказания помощи самому себе" "player_bleedout_firstAidHealPercent" "Процент здоровья после лечения" @@ -187,8 +187,8 @@ "PL_sp_coop_hint" "Сыграть в кампанию с друзьями" "PL_sp_coop_abbr" "SP" - "SP_TRAINING" "Тренировачная полоса пилотов" - "SP_TRAINING_CLASSIC_DESC" "Тренировачная имитация капитана Ластимозы." + "SP_TRAINING" "Полоса препятствий" + "SP_TRAINING_CLASSIC_DESC" "Симуляция капитана Ластимозы." "SP_CRASHSITE" "БT-7274" "SP_CRASHSITE_CLASSIC_DESC" "Джек Купер встречает BT-7274." @@ -200,7 +200,7 @@ "SP_BOOMTOWN_START_CLASSIC_DESC" "Подземная срезка приводит к неожиданным последствиям." "SP_HUB_TIMESHIFT" "Следствие и Причина" - "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местополжении Майора Андерсена." + "SP_HUB_TIMESHIFT_CLASSIC_DESC" "Странный феномен был обнаружен на местоположении Майора Андерсена." "SP_BEACON" "Маяк" "SP_BEACON_CLASSIC_DESC" "Купер и БТ пытаются известить оставшийся флот о планах IMC." @@ -229,7 +229,7 @@ "SERVER_DESCRIPTION" "Описание" "SERVER_MODS" "Моды" "CLEAR_FILTERS" "ОЧИСТИТЬ" - "JOIN_BUTTON" "ПРИСОЕДИНИТЬСЯ" + "JOIN_BUTTON" "ЗАЙТИ" "SWITCH_YES" "Да" "SWITCH_NO" "Нет" @@ -240,24 +240,94 @@ "TOTAL_SERVERS" "Серверов: ^C46C6C00%s1" // In-game chat - "HUD_CHAT_WHISPER_PREFIX" "[WHISPER]" - "HUD_CHAT_SERVER_PREFIX" "[SERVER]" + "HUD_CHAT_WHISPER_PREFIX" "[ЛИЧНОЕ]" + "HUD_CHAT_SERVER_PREFIX" "[СЕРВЕР]" "NO_GAMESERVER_RESPONSE" "Игровой сервер не отвечает" - "BAD_GAMESERVER_RESPONSE" "Игровой сервер не дал правильного ответа" + "BAD_GAMESERVER_RESPONSE" "Игровой сервер вернул некорректный ответ" "UNAUTHORIZED_GAMESERVER" "Игровой сервер не авторизирован чтобы сделать данный запрос" - "UNAUTHORIZED_GAME" "Не удалось найти Titanfall 2 на этом аккаунте" + "UNAUTHORIZED_GAME" "Stryder не смог найти Titanfall 2 на этом аккаунте" "UNAUTHORIZED_PWD" "Неправильный пароль" - "STRYDER_RESPONSE" "Не удалось разобрать ответ stryder" + "STRYDER_RESPONSE" "Не удалось разобрать ответ Stryder" "PLAYER_NOT_FOUND" "Не удалось найти аккаунт игрока" - "INVALID_MASTERSERVER_TOKEN" "Срок действия жетона главного сервера истек или не является правильным" - "JSON_PARSE_ERROR" "Ошибка разбора ответа json" + "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера" + "JSON_PARSE_ERROR" "Ошибка разбора json-ответа" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" "DISABLE" "Выключить" "DIALOG_AUTHENTICATING_MASTERSERVER" "Аутентификация на главном сервере." "WARNING" "Предупреждение" - "CORE_MOD_DISABLE_WARNING" "Выключение главных модов может сломать ваш клиент!" + "CORE_MOD_DISABLE_WARNING" "Выключение основных модов может сломать ваш клиент!" "AUTHENTICATIONAGREEMENT_NO" "Вы выбрали не аутентифицироваться с Northstar-ом. Вы можете посмотреть соглашение в меню модов." "NS_SERVERBROWSER_UNKNOWNMODE" "Неизвестный режим" + "SNS_BANKRUPT" "Банкрот!" + "MOD_SETTINGS" "Настройки модов" + "NORTHSTAR_BASE_SETTINGS" "Основные настройки Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Только создатель матча может изменять настройки" + "ONLY_HOST_CAN_START_MATCH" "Только создатель матча может его начать" + "MATCH_COUNTDOWN_LENGTH" "Длительность обратного отсчёта частного матча" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Записывать в лог неизвестные команды" + "DISALLOWED_TACTICALS" "Запрещённое спецоружие" + "TACTICAL_REPLACEMENT" "Заменять запрещённое спецоружие на" + "DISALLOWED_WEAPONS" "Запрещённое оружие" + "REPLACEMENT_WEAPON" "Заменять запрещённое оружие на" + "SHOULD_RETURN_TO_LOBBY" "Возвращаться в лобби после матча" + "ARE_YOU_SURE" "Вы уверены?" + "WILL_RESET_ALL_SETTINGS" "ВСЕ настройки этой категории будут сброшены.\n\nЭто действие нельзя будет откатить." + "WILL_RESET_SETTING" "Это сбросит значение настройки %s1.\n\nЭто действие нельзя будет откатить." + "MOD_SETTINGS_SERVER" "Сервер" + "MOD_SETTINGS_RESET" "Сброс" + "MOD_SETTINGS_RESET_ALL" "Сбросить все" + "NO_RESULTS" "Нет результатов." + "NO_MODS" "Нечего настраивать! Загрузите моды с ^5588FF00northstar.thunderstore.io^0." + "respawnprotection" "Длит. защиты после возрождения" + "SNS_BANKRUPT_SUB" "Вас обнулил %s1" + "PL_hidden" "Невидимка" + "PL_hidden_lobby" "Невидимка — лобби" + "GAMEMODE_HIDDEN" "Невидимка" + "HIDDEN_YOU_ARE_HIDDEN" "Вы — Невидимка!" + "HIDDEN_KILL_SURVIVORS" "Убейте всех." + "aitdm_archer_grunts" "Пехотинцы со Стрельцами" + "PL_chamber" "Последний патрон" + "PL_chamber_lobby" "Последний патрон — лобби" + "PL_chamber_abbr" "ПАТРОН" + "GAMEMODE_CHAMBER" "Последний патрон" + "PL_sns" "Камни и палки" + "PL_sns_lobby" "Камни и палки — лобби" + "PL_sns_desc" "Все против всех. Убийства пульс. клинком и казни сбрасывают очки противника" + "PL_sns_abbr" "КИП" + "GAMEMODE_SNS" "Камни и палки" + "PL_hidden_hint" "Один из игроков невидим." + "PL_hidden_abbr" "НЕВИД" + "SCOREBOARD_BANKRUPTS" "Врагов обанкрочено" + "SNS_LEADER_BANKRUPT" "Лидер обанкрочен!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 был обнулён игроком %s2" + "gg_kill_reward" "Множитель награды за убийство" + "gg_execution_reward" "Множитель награды за казнь" + "PL_tffa" "Все против всех на титанах" + "PL_tffa_lobby" "Все против всех на титанах — лобби" + "PL_tffa_desc" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов." + "PL_tffa_abbr" "ТВПВ" + "sns_wme_kill_value" "Очков за убийство Элитным ведомым" + "sns_offhand_kill_value" "Очков за убийство спецоружием" + "sns_reset_kill_value" "Очков за убийство пульс./казнь" + "sns_melee_kill_value" "Очков за убийство врукопашную" + "sns_softball_enabled" "Включить Софтбол" + "no_pilot_collision" "Столкновения между пилотами" + "SHOW" "Показать" + "SHOW_ALL" "Все" + "SHOW_ONLY_ENABLED" "Только включенные" + "SHOW_ONLY_NOT_REQUIRED" "Только необязательные" + "SHOW_ONLY_REQUIRED" "Только обязательные" + "HIDDEN_FIRST_HIDDEN" "%s1 — Невидимка." + "GAMEMODE_TFFA" "Все против всех на титанах" + "SHOW_ONLY_DISABLED" "Только выключенные" + "HIDE_LOCKED" "Скрыть недоступные" + "PL_chamber_desc" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым." + "PL_chamber_hint" "Один выстрел — один труп. Заработайте ещё один патрон, убив врага первым." + "PL_hidden_desc" "Один из игроков невидим." + "PL_tffa_hint" "Каждый пилот сам за себя. Уничтожьте всех вражеских титанов." + "sns_softball_kill_value" "Очков за убийство Софтболом" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" + "gg_assist_reward" "Множитель награды за помощь в убийстве" } } -- cgit v1.2.3 From 2b263286512ebb1b59980f8c1f442576992323bd Mon Sep 17 00:00:00 2001 From: William Miller Date: Tue, 1 Aug 2023 20:58:10 -0300 Subject: Add missing strings for Double Barrel and Arc Cannon (#671) --- .../mod/resource/northstar_custom_english.txt | Bin 6446 -> 7376 bytes .../mod/resource/northstar_custom_portuguese.txt | Bin 5338 -> 6250 bytes .../mod/scripts/vscripts/sh_damage_types.nut | 6 ++++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Northstar.Custom/mod/resource/northstar_custom_english.txt b/Northstar.Custom/mod/resource/northstar_custom_english.txt index dbd3b106..56f56e8d 100644 Binary files a/Northstar.Custom/mod/resource/northstar_custom_english.txt and b/Northstar.Custom/mod/resource/northstar_custom_english.txt differ diff --git a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt index 0a7b19d2..85e915f6 100644 Binary files a/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt and b/Northstar.Custom/mod/resource/northstar_custom_portuguese.txt differ diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut index c66fc857..4987ee01 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut @@ -630,7 +630,9 @@ void function DamageTypes_Init() [ eDamageSourceId.melee_titan_punch_fighter ] = "#DEATH_TITAN_MELEE", [ eDamageSourceId.melee_titan_punch_vanguard ] = "#DEATH_TITAN_MELEE", [ eDamageSourceId.melee_titan_sword ] = "#DEATH_TITAN_SWORD", - [ eDamageSourceId.melee_titan_sword_aoe ] = "#DEATH_TITAN_SWORD" + [ eDamageSourceId.melee_titan_sword_aoe ] = "#DEATH_TITAN_SWORD", + [ eDamageSourceId.mp_titanweapon_arc_cannon ] = "#WPN_TITAN_ARC_CANNON_SHORT", + [ eDamageSourceId.mp_weapon_shotgun_doublebarrel ] = "#WPN_SHOTGUN_DBLBARREL_SHORT" } #if DEV @@ -773,4 +775,4 @@ void function ReceiveNewDamageSourceIDs( array args ) for ( int i = 0; i < args.len(); i += 3 ) RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " " ) ) } -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From f16af287534fceeb466bbd474d1ab3d94c19d1a3 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 2 Sep 2023 17:49:26 +0100 Subject: Force player respawn to match vanilla (#554) Automatically respawns dead players after 5 seconds unless set otherwise --- .../northstar_client_localisation_english.txt | 1 + Northstar.CustomServers/keyvalues/playlists_v2.txt | 13 +++++++++++ .../lobby/sh_private_lobby_modes_init.gnut | 1 + .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 25 ++++++++++++++++++++++ 4 files changed, 40 insertions(+) create mode 100644 Northstar.CustomServers/keyvalues/playlists_v2.txt diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 5dabd539..b2608331 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -227,6 +227,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "classic_rodeo" "Classic Rodeo" "oob_timer_enabled" "Out of Bounds Timer" "riff_instagib" "Instagib Mode" + "player_force_respawn" "Forced Respawn" "riff_player_bleedout" "Pilot Bleedout" "player_bleedout_forceHolster" "Holster weapons when downed" diff --git a/Northstar.CustomServers/keyvalues/playlists_v2.txt b/Northstar.CustomServers/keyvalues/playlists_v2.txt new file mode 100644 index 00000000..c49fb0e9 --- /dev/null +++ b/Northstar.CustomServers/keyvalues/playlists_v2.txt @@ -0,0 +1,13 @@ +playlists +{ + Gamemodes + { + defaults + { + vars + { + player_force_respawn 5 + } + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut index ccccefaf..d2be2ab4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/sh_private_lobby_modes_init.gnut @@ -17,6 +17,7 @@ void function PrivateMatchModesInit() AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "boosts_enabled", [ "#SETTING_DEFAULT", "#SETTING_DISABLED" ], "1" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_overdrive", [ "#SETTING_DISABLED", "#SETTING_ENABLED", "Only" ], "1" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "earn_meter_pilot_multiplier", "1.0" ) + AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_PILOT", "player_force_respawn", "5" ) AddPrivateMatchModeSettingArbitrary( "#MODE_SETTING_CATEGORY_TITAN", "earn_meter_titan_multiplier", "1.0" ) AddPrivateMatchModeSettingEnum( "#MODE_SETTING_CATEGORY_TITAN", "aegis_upgrades", [ "#SETTING_DISABLED", "#SETTING_ENABLED" ], "0" ) 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 ec426754..3bd0cd69 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -274,6 +274,9 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga ClearRespawnAvailable( player ) + // reset this so that we default to pilot spawn + player.SetPersistentVar( "spawnAsTitan", false ) + OnThreadEnd( function() : ( player ) { if ( !IsValid( player ) ) @@ -379,6 +382,13 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga SetRespawnAvailable( player ) wait respawnDelay + + int forceRespawn = GetCurrentPlaylistVarInt( "player_force_respawn", -1 ) + + // -1 is disabled, anything over is the time we wait in seconds + // before respawning the player + if( forceRespawn >= 0 ) + thread ForceRespawnMeSignalAfterDelay( player, forceRespawn ) player.WaitSignal( "RespawnMe" ) // set in base_gametype: ClientCommand_RespawnPlayer @@ -398,6 +408,21 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga } } +// idk if this is a good delay or if it matches vanilla +void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 ) +{ + player.EndSignal( "RespawnMe" ) + player.EndSignal( "OnDestroy" ) + + if( player.IsWatchingKillReplay() ) + player.WaitSignal( "KillCamOver" ) + + wait delay + + printt( format( "Forcing player respawn for player %s (took >%d seconds to respawn)", player.GetPlayerName(), delay ) ) + player.Signal( "RespawnMe" ) +} + void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) { player.EndSignal( "RespawnMe" ) -- cgit v1.2.3 From c7e50b28fe31e20b064f812758d8a0f5e889ea74 Mon Sep 17 00:00:00 2001 From: fvnkhead <98965760+fvnkhead@users.noreply.github.com> Date: Sat, 2 Sep 2023 19:50:28 +0300 Subject: Prefer not to spawn within 20 meters of enemy (#512) It indeed can't hurt Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index 5bf150c0..4956375b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -261,9 +261,12 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } - array projectiles = GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), 600 ) - foreach ( entity projectile in projectiles ) - if ( projectile.GetTeam() != team ) + const minEnemyDist = 1000.0 // about 20 meters? + // in rsquirrel extend returns null unlike in vanilla squirrel + array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) + spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) ) + foreach ( entity blocker in spawnBlockers ) + if ( blocker.GetTeam() != team ) return false // los check -- cgit v1.2.3 From 1d95b7d5f3a4b7176456c94b147f0382de04f18e Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 2 Sep 2023 17:52:06 +0100 Subject: Progression system (#655) This also can't hurt right? --------- Co-authored-by: uniboi <64006268+uniboi@users.noreply.github.com> --- .../northstar_client_localisation_english.txt | 18 + .../mod/scripts/vscripts/ui/menu_lobby.nut | 53 + Northstar.CustomServers/mod.json | 18 + .../mod/cfg/autoexec_ns_server.cfg | 5 +- .../mod/scripts/vscripts/_items.nut | 8 +- .../mod/scripts/vscripts/_menu_callbacks.gnut | 2 + .../mod/scripts/vscripts/_xp.gnut | 39 +- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 2 + .../mod/scripts/vscripts/evac/_evac.gnut | 45 + .../mod/scripts/vscripts/faction_xp.gnut | 3 + .../mod/scripts/vscripts/lobby/_lobby.gnut | 12 + .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 9 + .../mod/scripts/vscripts/mp/_changemap.nut | 4 +- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 2 + .../mod/scripts/vscripts/mp/_score.nut | 11 +- .../mod/scripts/vscripts/mp/_stats.nut | 1043 ++++++++++++++++++- .../mod/scripts/vscripts/sh_loadouts.nut | 4 +- .../mod/scripts/vscripts/sh_progression.nut | 1091 ++++++++++++++++++++ .../mod/scripts/vscripts/sh_utility_all.gnut | 6 +- .../mod/scripts/vscripts/titan_xp.gnut | 3 + .../mod/scripts/vscripts/weapon_xp.gnut | 5 +- 21 files changed, 2337 insertions(+), 46 deletions(-) create mode 100644 Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index b2608331..8c7bab3a 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -343,5 +343,23 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "MOD_SETTINGS_RESET_ALL" "Reset All" "NO_RESULTS" "No results." "NO_MODS" "No settings available! Install more mods at ^5588FF00northstar.thunderstore.io^0." + + // Toggleable progression + "TOGGLE_PROGRESSION" "Toggle Progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Toggle Progression" + + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disable Progression?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Enable Progression?" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby.\n\n^CC000000Warning: if you have currently equipped any items that you do not have unlocked, they will be reset!" + + "PROGRESSION_ENABLED_HEADER" "Progression Enabled!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Progression has been enabled.^\n\nTitans, Weapons, Factions, Skins, etc. will need to be unlocked by levelling up, or bought with Merits.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_DISABLED_HEADER" "Progression Disabled!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." + + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time." } } diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index 2bef0e20..e4cc5687 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -178,6 +178,8 @@ void function InitLobbyMenu() AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) AddMenuFooterOption( menu, BUTTON_BACK, "#BACK_BUTTON_POSTGAME_REPORT", "#POSTGAME_REPORT", OpenPostGameMenu, IsPostGameMenuValid ) AddMenuFooterOption( menu, BUTTON_TRIGGER_RIGHT, "#R_TRIGGER_CHAT", "", null, IsVoiceChatPushToTalk ) + // Client side progression toggle + AddMenuFooterOption( menu, BUTTON_Y, "#Y_BUTTON_TOGGLE_PROGRESSION", "#TOGGLE_PROGRESSION", ShowToggleProgressionDialog ) InitChatroom( menu ) @@ -226,6 +228,57 @@ void function InitLobbyMenu() RegisterSignal( "LeaveParty" ) } +void function ShowToggleProgressionDialog( var button ) +{ + bool enabled = Progression_GetPreference() + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = enabled ? "#PROGRESSION_TOGGLE_ENABLED_HEADER" : "#PROGRESSION_TOGGLE_DISABLED_HEADER" + dialogData.message = enabled ? "#PROGRESSION_TOGGLE_ENABLED_BODY" : "#PROGRESSION_TOGGLE_DISABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#NO" ) + AddDialogButton( dialogData, "#YES", enabled ? DisableProgression : EnableProgression ) + + OpenDialog( dialogData ) +} + +void function EnableProgression() +{ + Progression_SetPreference( true ) + + // update the cache just in case something changed + UpdateCachedLoadouts_Delayed() + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#PROGRESSION_ENABLED_HEADER" + dialogData.message = "#PROGRESSION_ENABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#OK" ) + + EmitUISound( "UI_Menu_Item_Purchased_Stinger" ) + + OpenDialog( dialogData ) +} + +void function DisableProgression() +{ + Progression_SetPreference( false ) + + DialogData dialogData + dialogData.menu = GetMenu( "AnnouncementDialog" ) + dialogData.header = "#PROGRESSION_DISABLED_HEADER" + dialogData.message = "#PROGRESSION_DISABLED_BODY" + dialogData.image = $"ui/menu/common/dialog_announcement_1" + + AddDialogButton( dialogData, "#OK" ) + + OpenDialog( dialogData ) +} + void function SetupComboButtonTest( var menu ) { ComboStruct comboStruct = ComboButtons_Create( menu ) diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 4f19307d..8f5508c8 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -53,6 +53,11 @@ { "Name": "ns_allow_kill_commands", "DefaultValue": "0" + }, + { + "Name": "ns_progression_enabled", + "DefaultValue": "0", + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ @@ -150,6 +155,19 @@ "ServerCallback": { "After": "AiTurretSentry_Init" } + }, + { + "Path": "sh_progression.nut", + "RunOn": "UI || SERVER || CLIENT", + "ServerCallback": { + "Before": "Progression_Init" + }, + "ClientCallback": { + "Before": "Progression_Init" + }, + "UICallback": { + "Before": "Progression_Init" + } } ] } diff --git a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg index f28f601b..bd422783 100644 --- a/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg +++ b/Northstar.CustomServers/mod/cfg/autoexec_ns_server.cfg @@ -21,4 +21,7 @@ sv_updaterate_mp 20 // default updaterate: 20 tick sv_minupdaterate 20 // unsure if this actually works, but if it does, should set minimum client updaterate sv_max_snapshots_multiplayer 300 // this needs to be updaterate * 15, or clients will dc in killreplay net_data_block_enabled 0 // not really sure on this, have heard datablock could have security issues? doesn't seem to have any adverse effects being disabled -host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit \ No newline at end of file +host_skip_client_dll_crc 1 // allow people to run modded client dlls, this is mainly so people running pilot visor colour mods can keep those, since they use a client.dll edit + +announcementVersion 1 +announcement #PROGRESSION_ANNOUNCEMENT_BODY \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index 539b72bc..5878da13 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -5698,7 +5698,7 @@ bool function IsUnlockValid( string ref, string parentRef = "" ) bool function IsSubItemLocked( entity player, string ref, string parentRef ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false if ( IsItemInEntitlementUnlock( ref, parentRef ) ) @@ -5817,7 +5817,7 @@ bool function IsSubItemLocked( entity player, string ref, string parentRef ) bool function IsItemLocked( entity player, string ref ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false if ( IsItemInEntitlementUnlock( ref ) ) @@ -5906,7 +5906,7 @@ bool function IsItemLockedForEntitlement( entity player, string ref, string pare bool function IsSubItemOwned( entity player, string ref, string parentRef ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false Assert( IsValid( player ) ) @@ -5990,7 +5990,7 @@ bool function IsSubItemOwned( entity player, string ref, string parentRef ) bool function IsItemOwned( entity player, string ref ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return false Assert( IsValid( player ) ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut index 1092bf2d..6499faa2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_menu_callbacks.gnut @@ -65,6 +65,8 @@ bool function ClientCommandCallback_GenUp( entity player, array args ) player.GenChanged() player.XPChanged() } + + RegenPersistentLoadouts(player) return true } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 6f044b7a..2b95d1a8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -1,6 +1,7 @@ global function SvXP_Init global function PlayerProgressionAllowed global function HandleXPGainForScoreEvent +global function AddXP void function SvXP_Init() { @@ -29,46 +30,38 @@ bool function PlayerProgressionAllowed( entity player ) void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) { // note: obviously all xp stuff can be cheated in if people want to on customs, this is mainly just here for fun for those who want it and feature completeness - // most score events don't have this, so we'll set this to the xp value of other categories later if needed + int xpValue = ScoreEvent_GetXPValue( event ) int weaponXp = ScoreEvent_GetXPValueWeapon( event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) - - if ( xpValue < weaponXp ) - xpValue = weaponXp - else if ( xpValue < titanXp ) - xpValue = titanXp + int factionXp = ScoreEvent_GetXPValueFaction( event ) entity weapon = player.GetActiveWeapon() - if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) ) - AddWeaponXP( player, xpValue ) + if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 ) + AddWeaponXP( player, weaponXp ) // if we specifically gain titan xp, then give titan xp no matter what, otherwise only give it when we're in a titan - if ( titanXp != 0 || player.IsTitan() ) - AddTitanXP( player, xpValue ) - - // most events don't have faction xp but almost everything should give it - int factionXp = ScoreEvent_GetXPValueFaction( event ) - if ( xpValue > factionXp ) - factionXp = xpValue - else if ( xpValue < factionXp ) - xpValue = factionXp + if ( titanXp != 0 ) + AddTitanXP( player, titanXp ) if ( factionXp != 0 ) AddFactionXP( player, factionXp ) - if ( xpValue == 0 ) - return - // global xp + if ( xpValue != 0 ) + AddXP( player, xpValue ) +} + +void function AddXP( entity player, int amount ) +{ int oldXp = player.GetPersistentVarAsInt( "xp" ) - if(oldXp<0) oldXp = 0 + if( oldXp < 0 ) oldXp = 0 int oldLevel = GetLevelForXP( oldXp ) - player.SetPersistentVar( "xp", min( oldXp + xpValue, PlayerGetMaxXPPerGen() ) ) + player.SetPersistentVar( "xp", min( oldXp + amount, PlayerGetMaxXPPerGen() ) ) player.XPChanged() // network xp change to client, gen can't change here int newXp = player.GetPersistentVarAsInt( "xp" ) int newLevel = GetLevelForXP( newXp ) if ( newLevel != oldLevel ) Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel ) -} \ No newline at end of file +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 5821d015..56750352 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -265,6 +265,8 @@ void function UseBurnCardWeapon( entity weapon, entity player ) PlayerEarnMeter_SetRewardUsed( player ) thread PlayerInventory_PopInventoryItem( player ) + + UpdatePlayerStat( player, "misc_stats", "boostsActivated" ) } void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index f23c841d..af074689 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -422,6 +422,40 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa foreach ( entity otherPlayer in GetPlayerArray() ) Remote_CallFunction_NonReplay( otherPlayer, "ServerCallback_EvacObit", player.GetEncodedEHandle() ) } + + // award player score to evacing team + int evacCount = 0 + array evacingPlayers = GetPlayerArrayOfTeam( dropship.GetTeam() ) // all players that are supposed to evac in the dropship + + // count how many players are in the dropship + foreach ( entity player in evacingPlayers ) + { + if ( !PlayerInDropship( player, dropship ) ) + continue + + evacCount++ + } + + bool allEvac = evacCount == evacingPlayers.len() + + foreach(entity player in evacingPlayers) + { + if ( !PlayerInDropship( player, dropship ) ) + continue + + AddPlayerScore( player, "HotZoneExtract" ) + UpdatePlayerStat( player, "misc_stats", "evacsSurvived" ) + + if ( allEvac ) + AddPlayerScore( player, "TeamBonusFullEvac" ) + } + + // sole survivor (but not the only one on the team) + if ( evacCount == 1 && !allEvac ) + { + // we can assume there is one player in the array because otherwise evacCount wouldn't be 1 + AddPlayerScore( evacingPlayers[0], "SoleSurvivor" ) + } } void function AddPlayerToEvacDropship( entity dropship, entity player ) @@ -442,6 +476,8 @@ void function AddPlayerToEvacDropship( entity dropship, entity player ) if ( !PlayerInDropship( player, dropship ) ) return + UpdatePlayerStat( player, "misc_stats", "evacsAttempted" ) + // need to cancel if the dropship dies dropship.EndSignal( "OnDeath", "OnDestroy" ) @@ -507,6 +543,15 @@ void function CheckIfAnyPlayerLeft( int evacTeam ) SetTeamActiveObjective( evacTeam, "EG_DropshipExtractEvacPlayersKilled" ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtractEvacPlayersKilled" ) thread EvacEpilogueCompleted( null ) + + // score for killing the entire evacing team + foreach ( entity player in GetPlayerArray() ) + { + if ( player.GetTeam() == evacTeam ) + continue + + AddPlayerScore( player, "TeamBonusKilledAll") + } } ) while( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 5fd7d101..6555c875 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -3,8 +3,11 @@ global function AddFactionXP void function AddFactionXP( entity player, int amount ) { string faction = GetFactionChoice( player ) + int oldLevel = FactionGetLevel( player, faction ) // increment xp player.SetPersistentVar( "factionXP[" + faction + "]", min( FactionGetXP( player, faction ) + amount, FactionGetMaxXP( faction ) ) ) // note: no notif for faction level up + if ( FactionGetLevel( player, faction ) != oldLevel ) + AddPlayerScore( player, "FactionLevelUp" ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut index ae933b71..8b65ec93 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/lobby/_lobby.gnut @@ -14,6 +14,7 @@ void function Lobby_Init() { // non-private lobby clientcommands AddClientCommandCallback( "StartPrivateMatchSearch", ClientCommandCallback_StartPrivateMatchSearch ) + AddClientCommandCallback( "SetAnnouncementVersionSeen", ClientCommandCallback_SetAnnouncementVersionSeen ) } } @@ -37,3 +38,14 @@ bool function ClientCommandCallback_StartPrivateMatchSearch( entity player, arra return true } + +bool function ClientCommandCallback_SetAnnouncementVersionSeen( entity player, array args ) +{ + if ( args.len() < 1 ) + return false + + int version = int( args[0] ) + + player.SetPersistentVar( "announcementVersionSeen", version ) + return true +} 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 3bd0cd69..bab7eaed 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -134,6 +134,15 @@ void function CodeCallback_OnClientConnectionCompleted( entity player ) Lobby_OnClientConnectionCompleted( player ) return } + else if ( !IsFDMode( GAMETYPE ) ) + { + // reset this for non-fd modes + // for some reason the postgame scoreboard uses this to + // determine if it should show the FD aegis rank one + // FD should either set this in their own mode, or add an else + // to this if statement when it releases + player.SetPersistentVar( "lastFDTitanRef", "" ) + } player.hasConnected = true diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut index 16a3ce92..0ababfc7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_changemap.nut @@ -58,7 +58,9 @@ void function CodeCallback_MatchIsOver() #if MP void function PopulatePostgameData() { - // something's busted here because this isn't showing automatically on match end, ag + // show the postgame scoreboard summary + SetUIVar( level, "showGameSummary", true ) + foreach ( entity player in GetPlayerArray() ) { int teams = GetCurrentPlaylistVarInt( "max_teams", 2 ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 46b39ebc..3426cec5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -800,6 +800,8 @@ void function SetWinner( int team, string winningReason = "", string losingReaso } else SetGameState( eGameState.WinnerDetermined ) + + ScoreEvent_MatchComplete( team ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index dacd43b0..0b55e9ff 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -7,6 +7,7 @@ global function ScoreEvent_PlayerKilled global function ScoreEvent_TitanDoomed global function ScoreEvent_TitanKilled global function ScoreEvent_NPCKilled +global function ScoreEvent_MatchComplete global function ScoreEvent_SetEarnMeterValues global function ScoreEvent_SetupEarnMeterValuesForMixedModes @@ -230,7 +231,15 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn catch ( ex ) {} } - +void function ScoreEvent_MatchComplete( int winningTeam ) +{ + foreach( entity player in GetPlayerArray() ) + { + AddPlayerScore( player, "MatchComplete" ) + if ( player.GetTeam() == winningTeam ) + AddPlayerScore( player, "MatchVictory" ) + } +} void function ScoreEvent_SetEarnMeterValues( string eventName, float earned, float owned, float coreScale = 1.0 ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 0e8b58f4..92c0f401 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -1,3 +1,5 @@ +untyped // because entity.s + global function Stats_Init global function AddStatCallback global function Stats_SaveStatDelayed @@ -12,67 +14,1084 @@ global function PreScoreEventUpdateStats global function PostScoreEventUpdateStats global function Stats_OnPlayerDidDamage +struct { + table< string, array > refs + table< string, array< void functionref( entity, float, string ) > > callbacks + + table< entity, table< string, int > > cachedIntStatChanges + table< table< string, float > > cachedFloatStatChanges + + table< entity, float > playerKills + table< entity, float > playerKillsPvp + table< entity, float > playerDeaths + table< entity, float > playerDeathsPvp + + bool isFirstStrike = true +} file + void function Stats_Init() { + AddCallback_OnPlayerKilled( OnPlayerOrNPCKilled ) + AddCallback_OnNPCKilled( OnPlayerOrNPCKilled ) + AddCallback_OnPlayerRespawned( OnPlayerRespawned ) + AddCallback_OnClientConnected( OnClientConnected ) + AddCallback_OnClientDisconnected( OnClientDisconnected ) + AddCallback_GameStateEnter( eGameState.Epilogue, OnEpilogueStarted ) + thread HandleDistanceAndTimeStats_Threaded() + thread SaveStatsPeriodically_Threaded() } -void function AddStatCallback(string statCategory, string statAlias, string statSubAlias, void functionref(entity, float, string) callback, string subRef) +void function AddStatCallback( string statCategory, string statAlias, string statSubAlias, void functionref( entity, float, string ) callback, string subRef ) { + if ( !IsValidStat( statCategory, statAlias, statSubAlias ) ) + throw format( "INVALID STAT: %s : %s : %s", statCategory, statAlias, statSubAlias ) + + + string statVar = GetStatVar( statCategory, statAlias, statSubAlias ) + if ( statVar in file.refs ) + { + file.refs[ statVar ].append( subRef ) + file.callbacks[ statVar ].append( callback ) + } + else + { + file.refs[ statVar ] <- [ subRef ] + file.callbacks[ statVar ] <- [ callback ] + } } -void function Stats_SaveStatDelayed(entity player, string statCategory, string statAlias, string statSubAlias) +// a lot of this file seems to be doing caching of stats in some way +void function Stats_SaveStatDelayed( entity player, string statCategory, string statAlias, string statSubAlias, float delay = 0.1 ) { + // idk how long the delay is meant to be but whatever + wait delay + + if ( !IsValid( player ) ) + return + + Stats_SaveStat( player, statCategory, statAlias, statSubAlias ) +} + +void function Stats_SaveAllStats( entity player ) +{ + if ( player in file.cachedIntStatChanges ) + { + foreach( string key, int val in file.cachedIntStatChanges[ player ] ) + { + player.SetPersistentVar( key, player.GetPersistentVarAsInt( key ) + val ) + } + + delete file.cachedIntStatChanges[ player ] + } + // save cached float stat change + if ( player in file.cachedFloatStatChanges ) + { + foreach( string key, float val in file.cachedFloatStatChanges[ player ] ) + { + player.SetPersistentVar( key, expect float( player.GetPersistentVar( key ) ) + val ) + } + delete file.cachedFloatStatChanges[ player ] + } } -int function PlayerStat_GetCurrentInt(entity player, string statCategory, string statAlias, string statSubAlias) +void function Stats_SaveStat( entity player, string statCategory, string statAlias, string statSubAlias ) { + string stat = GetStatVar( statCategory, statAlias, statSubAlias ) + // save cached int stat change + if ( player in file.cachedIntStatChanges && stat in file.cachedIntStatChanges[ player ] ) + { + player.SetPersistentVar( stat, player.GetPersistentVarAsInt( stat ) + file.cachedIntStatChanges[ player ][ stat ] ) + delete file.cachedIntStatChanges[ player ][ stat ] + return + } + // save cached float stat change + if ( player in file.cachedFloatStatChanges && stat in file.cachedFloatStatChanges[ player ] ) + { + player.SetPersistentVar( stat, expect float( player.GetPersistentVar( stat ) ) + file.cachedFloatStatChanges[ player ][ stat ] ) + delete file.cachedFloatStatChanges[ player ][ stat ] + return + } +} + +// this gets the cached change, not the actual value +int function PlayerStat_GetCurrentInt( entity player, string statCategory, string statAlias, string statSubAlias ) +{ + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + + if ( player in file.cachedIntStatChanges && str in file.cachedIntStatChanges[ player ] ) + return file.cachedIntStatChanges[ player ][ str ] return 0 } -float function PlayerStat_GetCurrentFloat(entity player, string statCategory, string statAlias, string statSubAlias) +// this gets the cached change, not the actual value +float function PlayerStat_GetCurrentFloat( entity player, string statCategory, string statAlias, string statSubAlias ) { + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + + if ( player in file.cachedFloatStatChanges && str in file.cachedFloatStatChanges[ player ] ) + return file.cachedFloatStatChanges[ player ][ str ] return 0 } -void function UpdatePlayerStat(entity player, string statCategory, string subStat, int count = 0) +void function UpdatePlayerStat( entity player, string statCategory, string subStat, int count = 1 ) { + if ( !IsValid( player ) ) + return + + Stats_IncrementStat( player, statCategory, subStat, "", count.tofloat() ) +} + +void function IncrementPlayerDidPilotExecutionWhileCloaked( entity player ) +{ + UpdatePlayerStat( player, "kills_stats", "pilotExecutePilotWhileCloaked" ) +} + +void function UpdateTitanDamageStat( entity attacker, float savedDamage, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + Stats_IncrementStat( attacker, "titan_stats", "titanDamage", GetTitanCharacterName( attacker ), savedDamage ) +} + +void function UpdateTitanWeaponDamageStat( entity attacker, float savedDamage, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + string weaponName = GetPersistenceRefFromDamageInfo( damageInfo ) + if ( weaponName == "" ) + return + + Stats_IncrementStat( attacker, "weapon_stats", "titanDamage", weaponName, savedDamage ) +} + +void function UpdateTitanCoreEarnedStat( entity player, entity titan, int count = 1 ) +{ + if ( !IsValid( player ) ) + return + + if ( !IsValid( titan ) ) + return + + Stats_IncrementStat( player, "titan_stats", "coresEarned", GetTitanCharacterName( titan ), count.tofloat() ) +} + +void function PreScoreEventUpdateStats( entity attacker, entity ent ) +{ + // used to track kill streaks ending i think ( that stuff gets reset during score event update ) +} + +void function PostScoreEventUpdateStats( entity attacker, entity ent ) +{ + if ( !attacker.IsPlayer() ) + return + // used to track kill streaks starting maybe + if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT ) + { + // killingSpressAs_ + if ( attacker.IsTitan() ) + Stats_IncrementStat( attacker, "kills_stats", "killingSpressAs_" + GetTitanCharacterName( attacker ), "", 1.0 ) + + entity weapon = attacker.GetActiveWeapon() + // I guess if you dont have a valid active weapon when you get awarded a killing spree + // you dont get the stat. Too bad! + if ( !IsValid( weapon ) ) + return + Stats_IncrementStat( attacker, "weapon_kill_stats", "killingSprees", weapon.GetWeaponClassName(), 1.0 ) + } +} + +void function Stats_OnPlayerDidDamage( entity victim, var damageInfo ) +{ + // try and get the player + entity attacker = DamageInfo_GetAttacker( damageInfo ) + // get the player from their titan + if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + attacker = attacker.GetTitanSoul().GetBossPlayer() + + if ( !attacker.IsPlayer() ) + return + + string weaponName = GetPersistenceRefFromDamageInfo( damageInfo ) + if ( weaponName == "" ) + return + + Stats_IncrementStat( attacker, "weapon_stats", "shotsHit", weaponName, 1.0 ) + + if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_CRITICAL ) + Stats_IncrementStat( attacker, "weapon_stats", "critHits", weaponName, 1.0 ) + if ( DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) + Stats_IncrementStat( attacker, "weapon_stats", "headshots", weaponName, 1.0 ) +} + +void function Stats_IncrementStat( entity player, string statCategory, string statAlias, string statSubAlias, float amount ) +{ + if ( !IsValidStat( statCategory, statAlias, statSubAlias ) ) + { + printt( "invalid stat: " + statCategory + " : " + statAlias + " : " + statSubAlias ) + return + } + + string str = GetStatVar( statCategory, statAlias, statSubAlias ) + int type = GetStatVarType( statCategory, statAlias, statSubAlias ) + + // stupid exception because respawn set this up as an int in script + // but it is actually a float, so the game will crash if we don't fix it somewhere + // i dont feel like committing all of sh_stats.gnut so im doing this instead + if ( str == "mapStats[%mapname%].hoursPlayed[%gamemode%]" ) + type = ePlayerStatType.FLOAT + + // this is rather hacky + string mode = GAMETYPE + int difficulty = GetDifficultyLevel() + if ( difficulty >= 5 ) + return + + string saveVar = Stats_GetFixedSaveVar( str, GetMapName(), mode, difficulty.tostring() ) + // check if the map and mode exist in persistence + try + { + PersistenceGetEnumIndexForItemName( "gamemodes", mode ) + PersistenceGetEnumIndexForItemName( "maps", GetMapName() ) + } + catch( ex ) + { + // if we have an invalid mode or map for persistence, and it is used in the + // persistence string, we can't save the persistence so we have to just return + if ( str != saveVar ) + { + printt( ex ) + return + } + } + str = saveVar + + switch ( type ) + { + case ePlayerStatType.INT: + // populate table if needed + if ( !( player in file.cachedIntStatChanges ) ) + file.cachedIntStatChanges[ player ] <- {} + if ( !( str in file.cachedIntStatChanges[ player ] ) ) + file.cachedIntStatChanges[ player ][ str ] <- 0 + + file.cachedIntStatChanges[ player ][ str ] += amount.tointeger() + break + case ePlayerStatType.FLOAT: + // populate table if needed + if ( !( player in file.cachedFloatStatChanges ) ) + file.cachedFloatStatChanges[ player ] <- {} + if ( !( str in file.cachedFloatStatChanges[ player ] ) ) + file.cachedFloatStatChanges[ player ][ str ] <- 0.0 + + file.cachedFloatStatChanges[ player ][ str ] += amount + break + default: + throw "UNIMPLEMENTED STAT TYPE: " + type + } + + // amount here is never used + Stats_RunCallbacks( str, player, amount ) +} + +void function Stats_RunCallbacks( string statVar, entity player, float change ) +{ + if ( !( statVar in file.refs ) ) + return + + for( int i = 0; i < file.refs[ statVar ].len(); i++ ) + { + string ref = file.refs[ statVar ][ i ] + void functionref( entity, float, string ) callback = file.callbacks[ statVar ][ i ] + + callback( player, change, ref ) + } +} + +void function OnClientConnected( entity player ) +{ + Stats_IncrementStat( player, "game_stats", "game_joined", "", 1.0 ) +} + +void function OnClientDisconnected( entity player ) +{ + Stats_SaveAllStats( player ) + // maybe we can save this stuff, but idk if we can access persistence in this callback + if ( player in file.cachedIntStatChanges ) + delete file.cachedIntStatChanges[ player ] + + if ( player in file.cachedFloatStatChanges ) + delete file.cachedFloatStatChanges[ player ] +} + +void function OnPlayerOrNPCKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim.IsPlayer() ) + thread SetLastPosForDistanceStatValid_Threaded( victim, false ) + + HandleDeathStats( victim, attacker, damageInfo ) + HandleKillStats( victim, attacker, damageInfo ) + HandleWeaponKillStats( victim, attacker, damageInfo ) + HandleTitanStats( victim, attacker, damageInfo ) +} + +void function HandleDeathStats( entity player, entity attacker, var damageInfo ) +{ + if ( !IsValid( player ) || !player.IsPlayer() ) + return + + if ( player in file.playerDeaths ) + file.playerDeaths[ player ]++ + else + file.playerDeaths[ player ] <- 1.0 + // total + Stats_IncrementStat( player, "deaths_stats", "total", "", 1.0 ) + + // these all rely on the attacker being valid + if ( IsValid( attacker ) ) + { + // totalPVP + // note: I'm not sure if owned entities count towards totalPVP + // such as auto-titans, turrets, etc. + if ( attacker.IsPlayer() || attacker.GetBossPlayer() ) + { + if ( player in file.playerDeathsPvp ) + file.playerDeathsPvp[ player ]++ + else + file.playerDeathsPvp[ player ] <- 1.0 + Stats_IncrementStat( player, "deaths_stats", "totalPVP", "", 1.0 ) + } + + // byPilots + if ( IsPilot( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "byPilots", "", 1.0 ) + + // byTitan_ + if ( attacker.IsTitan() && attacker.IsPlayer() ) + Stats_IncrementStat( player, "deaths_stats", "byTitan_" + GetTitanCharacterName( attacker ), "", 1.0 ) + + // bySpectres + if ( IsSpectre( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "bySpectres", "", 1.0 ) + + // byGrunts + if ( IsGrunt( attacker ) ) + Stats_IncrementStat( player, "deaths_stats", "byGrunts", "", 1.0 ) + + // byNPCTitans_ + if ( attacker.IsTitan() && attacker.IsNPC() ) + Stats_IncrementStat( player, "deaths_stats", "byNPCTitans_" + GetTitanCharacterName( attacker ), "", 1.0 ) + } + + // asPilot + if ( IsPilot( player ) ) + Stats_IncrementStat( player, "deaths_stats", "asPilot", "", 1.0 ) + + // asTitan_ + if ( player.IsTitan() ) + Stats_IncrementStat( player, "deaths_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 ) + + // suicides + if ( IsSuicide( attacker, player, DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) ) + Stats_IncrementStat( player, "deaths_stats", "suicides", "", 1.0 ) + + // whileEjecting + if ( player.p.pilotEjecting ) + Stats_IncrementStat( player, "deaths_stats", "whileEjecting", "", 1.0 ) +} + +void function HandleWeaponKillStats( entity victim, entity attacker, var damageInfo ) +{ + if ( !IsValid( attacker ) ) + return + + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + string damageSourceStr = GetPersistenceRefFromDamageInfo( damageInfo ) + // cant do weapon stats for no weapon + if ( damageSourceStr == "" ) + return + + // check things once, for performance + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + + // total + Stats_IncrementStat( player, "weapon_kill_stats", "total", damageSourceStr, 1.0 ) + + // pilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "weapon_kill_stats", "pilots", damageSourceStr, 1.0 ) + + // ejecting_pilots + if ( victimIsPilot && victim.p.pilotEjecting ) + Stats_IncrementStat( player, "weapon_kill_stats", "ejecting_pilots", damageSourceStr, 1.0 ) + + // titansTotal + if ( victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "titansTotal", damageSourceStr, 1.0 ) + // spectres + if ( IsSpectre( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "spectres", damageSourceStr, 1.0 ) + + // marvins + if ( IsMarvin( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "marvins", damageSourceStr, 1.0 ) + + // grunts + if ( IsGrunt( victim ) ) + Stats_IncrementStat( player, "weapon_kill_stats", "grunts", damageSourceStr, 1.0 ) + + // ai + if ( victimIsNPC ) + Stats_IncrementStat( player, "weapon_kill_stats", "ai", damageSourceStr, 1.0 ) + + // titans_ + if ( victimIsPlayer && victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "titans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 ) + + // npcTitans_ + if ( victimIsNPC && victimIsTitan ) + Stats_IncrementStat( player, "weapon_kill_stats", "npcTitans_" + GetTitanCharacterName( victim ), damageSourceStr, 1.0 ) } -void function IncrementPlayerDidPilotExecutionWhileCloaked(entity player) +void function HandleKillStats( entity victim, entity attacker, var damageInfo ) { + if ( !IsValid( attacker ) ) + return + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + // check things once, for performance + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + + if ( player in file.playerKills ) + file.playerKills[ player ]++ + else + file.playerKills[ player ] <- 1.0 + // total + Stats_IncrementStat( player, "kills_stats", "total", "", 1.0 ) + + // totalPVP + if ( victimIsPlayer ) + { + if ( player in file.playerKillsPvp ) + file.playerKillsPvp[ player ]++ + else + file.playerKillsPvp[ player ] <- 1.0 + Stats_IncrementStat( player, "kills_stats", "totalPVP", "", 1.0 ) + } + + // pilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "kills_stats", "pilots", "", 1.0 ) + + // spectres + if ( IsSpectre( victim ) ) + Stats_IncrementStat( player, "kills_stats", "spectres", "", 1.0 ) + + // marvins + if ( IsMarvin( victim ) ) + Stats_IncrementStat( player, "kills_stats", "marvins", "", 1.0 ) + + // grunts + if ( IsGrunt( victim ) ) + Stats_IncrementStat( player, "kills_stats", "grunts", "", 1.0 ) + + // totalTitans + if ( victimIsTitan ) + Stats_IncrementStat( player, "kills_stats", "totalTitans", "", 1.0 ) + + // totalPilots + if ( victimIsPilot ) + Stats_IncrementStat( player, "kills_stats", "totalPilots", "", 1.0 ) + + // totalNPC + if ( victimIsNPC ) + Stats_IncrementStat( player, "kills_stats", "totalNPC", "", 1.0 ) + + // totalTitansWhileDoomed + if ( victimIsTitan && attacker.IsTitan() && GetDoomedState( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "totalTitansWhileDoomed", "", 1.0 ) + + // asPilot + if ( IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "asPilot", "", 1.0 ) + + // totalAssists + // assistsTotal ( weapon_kill_stats ) + // note: eww + table alreadyAssisted + foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) + { + if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim ) + continue + + bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false + if( attackerInfo.attacker != attacker && !exists ) + { + alreadyAssisted[ attackerInfo.attacker.GetEncodedEHandle() ] <- true + Stats_IncrementStat( attackerInfo.attacker, "kills_stats", "totalAssists", "", 1.0 ) + + string source = DamageSourceIDToString( attackerInfo.damageSourceId ) + + if ( IsValidStatItemString( source ) ) + Stats_IncrementStat( attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 ) + } + } + + // asTitan_ + if ( player.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "asTitan_" + GetTitanCharacterName( player ), "", 1.0 ) + + // firstStrikes + if ( file.isFirstStrike && attacker.IsPlayer() && victimIsPlayer ) + { + Stats_IncrementStat( player, "kills_stats", "firstStrikes", "", 1.0 ) + file.isFirstStrike = false + } + + // ejectingPilots + if ( victimIsPilot && victim.p.pilotEjecting ) + Stats_IncrementStat( player, "kills_stats", "ejectingPilots", "", 1.0 ) + + // whileEjecting + if ( attacker.IsPlayer() && attacker.p.pilotEjecting ) + Stats_IncrementStat( player, "kills_stats", "whileEjecting", "", 1.0 ) + + // cloakedPilots + if ( victimIsPilot && IsCloaked( victim ) ) + Stats_IncrementStat( player, "kills_stats", "cloakedPilots", "", 1.0 ) + + // whileCloaked + if ( attacker == player && IsCloaked( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "whileCloaked", "", 1.0 ) + + // wallrunningPilots + if ( victimIsPilot && victim.IsWallRunning() ) + Stats_IncrementStat( player, "kills_stats", "wallrunningPilots", "", 1.0 ) + + // whileWallrunning + if ( attacker == player && attacker.IsWallRunning() ) + Stats_IncrementStat( player, "kills_stats", "whileWallrunning", "", 1.0 ) + + // wallhangingPilots + if ( victimIsPilot && victim.IsWallHanging() ) + Stats_IncrementStat( player, "kills_stats", "wallhangingPilots", "", 1.0 ) + + // whileWallhanging + if ( attacker == player && attacker.IsWallHanging() ) + Stats_IncrementStat( player, "kills_stats", "whileWallhanging", "", 1.0 ) + + // pilotExecution + if ( damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecution", "", 1.0 ) + + // pilotExecutePilot + if ( victimIsPilot && damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecutePilot", "", 1.0 ) + + // pilotKillsWithHoloPilotActive + if ( victimIsPilot && GetDecoyActiveCountForPlayer( player ) > 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWithHoloPilotActive", "", 1.0 ) + + // pilotKillsWithAmpedWallActive + if ( victimIsPilot && GetAmpedWallsActiveCountForPlayer( player ) > 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWithAmpedWallActive", "", 1.0 ) + + // pilotExecutePilotUsing_ + if ( victimIsPilot && damageSource == eDamageSourceId.human_execution ) + Stats_IncrementStat( player, "kills_stats", "pilotExecutePilotUsing_" + player.p.lastExecutionUsed, "", 1.0 ) + + // pilotKickMelee + if ( damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "pilotKickMelee", "", 1.0 ) + + // pilotKickMeleePilot + if ( victimIsPilot && damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "pilotKickMeleePilot", "", 1.0 ) + + // titanMelee + if ( DamageIsTitanMelee( damageSource ) ) + Stats_IncrementStat( player, "kills_stats", "titanMelee", "", 1.0 ) + + // titanMeleePilot + if ( victimIsPilot && DamageIsTitanMelee( damageSource ) ) + Stats_IncrementStat( player, "kills_stats", "titanMeleePilot", "", 1.0 ) + + // titanStepCrush + if ( IsTitanCrushDamage( damageInfo ) ) + Stats_IncrementStat( player, "kills_stats", "titanStepCrush", "", 1.0 ) + + // titanStepCrushPilot + if ( victimIsPilot && IsTitanCrushDamage( damageInfo ) ) + Stats_IncrementStat( player, "kills_stats", "titanStepCrushPilot", "", 1.0 ) + + // titanExocution + // note: RESPAWN WHY? EXPLAIN + if ( damageSource == eDamageSourceId.titan_execution ) + { + string titanName = GetTitanCharacterName( player ) + titanName = titanName.slice( 0, 1 ).toupper() + titanName.slice( 1, titanName.len() ) + Stats_IncrementStat( player, "kills_stats", "titanExocution" + titanName, "", 1.0 ) + } + + // titanFallKill + if ( damageSource == eDamageSourceId.damagedef_titan_fall ) + Stats_IncrementStat( player, "kills_stats", "titanFallKill", "", 1.0 ) + + // petTitanKillsFollowMode + if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.FOLLOW ) + Stats_IncrementStat( player, "kills_stats", "petTitanKillsFollowMode", "", 1.0 ) + + // petTitanKillsGuardMode + if ( attacker == playerPetTitan && player.GetPetTitanMode() == eNPCTitanMode.STAY ) + Stats_IncrementStat( player, "kills_stats", "petTitanKillsGuardMode", "", 1.0 ) + + // rodeo_total + if ( damageSource == eDamageSourceId.rodeo_battery_removal ) + Stats_IncrementStat( player, "kills_stats", "rodeo_total", "", 1.0 ) + + // pilot_headshots_total + if ( victimIsPilot && DamageInfo_GetCustomDamageType( damageInfo ) & DF_HEADSHOT ) + Stats_IncrementStat( player, "kills_stats", "pilot_headshots_total", "", 1.0 ) + + // evacShips + if ( IsEvacDropship( victim ) ) + Stats_IncrementStat( player, "kills_stats", "evacShips", "", 1.0 ) + + // nuclearCore + if ( damageSource == eDamageSourceId.damagedef_nuclear_core ) + Stats_IncrementStat( player, "kills_stats", "nuclearCore", "", 1.0 ) + + // meleeWhileCloaked + if ( IsCloaked( attacker ) && damageSource == eDamageSourceId.human_melee ) + Stats_IncrementStat( player, "kills_stats", "meleeWhileCloaked", "", 1.0 ) + + // titanKillsAsPilot + if ( victimIsTitan && IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "titanKillsAsPilot", "", 1.0 ) + + // pilotKillsWhileStimActive + if ( victimIsPilot && StatusEffect_Get( attacker, eStatusEffect.stim_visual_effect ) <= 0 ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsWhileStimActive", "", 1.0 ) + + // pilotKillsAsTitan + if ( victimIsPilot && attacker.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsAsTitan", "", 1.0 ) + + // pilotKillsAsPilot + if ( victimIsPilot && IsPilot( attacker ) ) + Stats_IncrementStat( player, "kills_stats", "pilotKillsAsPilot", "", 1.0 ) + + // titanKillsAsTitan + if ( victimIsTitan && attacker.IsTitan() ) + Stats_IncrementStat( player, "kills_stats", "titanKillsAsTitan", "", 1.0 ) } -void function UpdateTitanDamageStat(entity attacker, float savedDamage, var damageInfo) +void function HandleTitanStats( entity victim, entity attacker, var damageInfo ) { + if ( !IsValid( attacker ) ) + return + + // get the player and it's pet titan + entity player + entity playerPetTitan + if ( attacker.IsPlayer() ) + { + // the player is just the attacker + player = attacker + playerPetTitan = player.GetPetTitan() + } + else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + { + // the attacker is the player's auto titan + player = attacker.GetTitanSoul().GetBossPlayer() + playerPetTitan = attacker + } + else + { + // attacker could be something like an NPC, or worldspawn + return + } + + int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) + bool victimIsPlayer = victim.IsPlayer() + bool victimIsNPC = victim.IsNPC() + bool victimIsPilot = IsPilot( victim ) + bool victimIsTitan = victim.IsTitan() + bool titanIsPrime = IsTitanPrimeTitan( player ) + // pilots + if ( victimIsPilot && attacker.IsTitan() ) + Stats_IncrementStat( player, "titan_stats", "pilots", GetTitanCharacterName( attacker ), 1.0 ) + + // titansTotal + if ( victimIsTitan && attacker.IsTitan() ) + Stats_IncrementStat( player, "titan_stats", "titansTotal", GetTitanCharacterName( attacker ), 1.0 ) + + // pilotsAsPrime + if ( victimIsPilot && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "pilotsAsPrime", GetTitanCharacterName( attacker ), 1.0 ) + + // titansAsPrime + if ( victimIsTitan && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "titansAsPrime", GetTitanCharacterName( attacker ), 1.0 ) + + // executionsAsPrime + if ( damageSource == eDamageSourceId.titan_execution && attacker.IsTitan() && titanIsPrime ) + Stats_IncrementStat( player, "titan_stats", "executionsAsPrime", GetTitanCharacterName( attacker ), 1.0 ) } -void function UpdateTitanWeaponDamageStat(entity attacker, float savedDamage, var damageInfo) +void function OnPlayerRespawned( entity player ) { + thread SetLastPosForDistanceStatValid_Threaded( player, true ) +} + +void function OnEpilogueStarted() +{ + // award players for match completed, wins, and losses + foreach ( entity player in GetPlayerArray() ) + { + Stats_IncrementStat( player, "game_stats", "game_completed", "", 1.0 ) + + if ( player.GetTeam() == GetWinningTeam() ) + Stats_IncrementStat( player, "game_stats", "game_won", "", 1.0 ) + else + Stats_IncrementStat( player, "game_stats", "game_lost", "", 1.0 ) + } + + if ( IsValidGamemodeString( GAMETYPE ) ) + { + // award players with matches played on the mode + foreach ( entity player in GetPlayerArray() ) + { + Stats_IncrementStat( player, "game_stats", "mode_played", GAMETYPE, 1.0 ) + + if ( player.GetTeam() == GetWinningTeam() ) + Stats_IncrementStat( player, "game_stats", "mode_won", GAMETYPE, 1.0 ) + } + } + + // update player's KD + foreach ( entity player in GetPlayerArray() ) + { + // kd stats + // index 0 is most recent game + // index 9 is least recent game + float playerKills = ( player in file.playerKills ) ? file.playerKills[ player ] : 0.0 + float playerDeaths = ( player in file.playerDeaths ) ? file.playerDeaths[ player ] : 0.0 + float kdratio_match + if ( playerDeaths == 0.0 ) + kdratio_match = playerKills + else + kdratio_match = playerKills / playerDeaths + + float playerKillsPvp = ( player in file.playerKillsPvp ) ? file.playerKillsPvp[ player ] : 0.0 + float playerDeathsPvp = ( player in file.playerDeathsPvp ) ? file.playerDeathsPvp[ player ] : 0.0 + float kdratiopvp_match + if ( playerDeathsPvp == 0.0 ) + kdratiopvp_match = playerKillsPvp + else + kdratiopvp_match = playerKillsPvp / playerDeathsPvp + + float totalDeaths = player.GetPersistentVarAsInt( "deathStats.total" ).tofloat() + float totalKills = player.GetPersistentVarAsInt( "killStats.total" ).tofloat() + float totalDeathsPvp = player.GetPersistentVarAsInt( "deathStats.totalPVP" ).tofloat() + float totalKillsPvp = player.GetPersistentVarAsInt( "killStats.totalPVP" ).tofloat() + float kdratio_lifetime + if ( totalDeaths == 0.0 ) + kdratio_lifetime = totalKills + else + kdratio_lifetime = totalKills / totalDeaths + float kdratio_lifetimepvp + if ( totalDeathsPvp == 0.0 ) + kdratio_lifetimepvp = totalKillsPvp + else + kdratio_lifetimepvp = totalKillsPvp / totalDeathsPvp + + // shift stats by 1 to make room for new game data + for ( int i = NUM_GAMES_TRACK_KDRATIO - 2; i >= 0; --i ) + { + player.SetPersistentVar( format( "kdratio_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format("kdratio_match[%i]", i ) ) ) + player.SetPersistentVar( format( "kdratiopvp_match[%i]", ( i + 1 ) ), player.GetPersistentVar( format( "kdratiopvp_match[%i]", i ) ) ) + } + // add new game data + player.SetPersistentVar( "kdratio_match[0]", kdratio_match ) + player.SetPersistentVar( "kdratiopvp_match[0]", kdratiopvp_match ) + player.SetPersistentVar( "kdratio_lifetime", kdratio_lifetime ) + player.SetPersistentVar( "kdratio_lifetime_pvp", kdratio_lifetimepvp ) + } + + // award mvp and top 3 in each team + if ( !IsFFAGame() ) + { + string gamemode = GameRules_GetGameMode() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( gamemode ) + + for( int team = 0; team < MAX_TEAMS; team++ ) + { + array players = GetPlayerArrayOfTeam( team ) + if ( compareFunc == null ) + { + printt( "gamemode doesn't have a compare func to get the top 3" ) + return + } + players.sort( compareFunc ) + int maxAwards = int( min( players.len(), 3 ) ) + for ( int i = 0; i < maxAwards; i++ ) + { + if ( i == 0 ) + Stats_IncrementStat( players[ i ], "game_stats", "mvp", "", 1.0 ) + Stats_IncrementStat( players[ i ], "game_stats", "top3OnTeam", "", 1.0 ) + } + } + + } +} +void function SetLastPosForDistanceStatValid_Threaded( entity player, bool val ) +{ + WaitFrame() + if ( !IsValid( player ) ) + return + player.p.lastPosForDistanceStatValid = val } -void function UpdateTitanCoreEarnedStat( entity player, entity titan ) +// Respawn did this through stuff found in _entitystructs.gnut (stuff like stats_wallrunTime) +// but their implementation seems kinda bad. The advantage it has over this method is not polling +// every 0.25 seconds, and using movement callbacks and stuff instead. However, since i can't find +// callbacks for things like changing weapon, i would have to poll for that *anyway* and thus, +// there is no point in doing things Respawn's way here +void function HandleDistanceAndTimeStats_Threaded() { + // just to be safe + if ( IsLobby() ) + return + + while ( GetGameState() < eGameState.Playing ) + WaitFrame() + + float lastTickTime = Time() + + while( true ) + { + // track distance stats + foreach ( entity player in GetPlayerArray() ) + { + if ( player.p.lastPosForDistanceStatValid ) + { + // not 100% sure on using Distance2D over Distance tbh + float distInches = Distance2D( player.p.lastPosForDistanceStat, player.GetOrigin() ) + float distMiles = distInches / 63360.0 + + // more generic distance stats + Stats_IncrementStat( player, "distance_stats", "total", "", distMiles ) + if ( player.IsTitan() ) + { + Stats_IncrementStat( player, "distance_stats", "asTitan_" + GetTitanCharacterName( player ), "", distMiles ) + Stats_IncrementStat( player, "distance_stats", "asTitan", "", distMiles ) + } + else + Stats_IncrementStat( player, "distance_stats", "asPilot", "", distMiles ) + + + string state = "" + // specific distance stats + if ( player.IsWallRunning() ) + state = "wallrunning" + else if ( PlayerIsRodeoingTitan( player ) ) + { + if ( player.GetTitanSoulBeingRodeoed().GetTeam() == player.GetTeam() ) + state = "onFriendlyTitan" + else + state = "onEnemyTitan" + } + else if ( player.IsZiplining() ) + state = "ziplining" + else if ( !player.IsOnGround() ) + state = "inAir" + + if ( state != "" ) + Stats_IncrementStat( player, "distance_stats", state, "", distMiles ) + } + + player.p.lastPosForDistanceStat = player.GetOrigin() + } + + float timeSeconds = Time() - lastTickTime + float timeHours = timeSeconds / 3600.0 + + // track time stats + foreach ( entity player in GetPlayerArray() ) + { + // first tick i dont count + if ( timeSeconds == 0 ) + break + + // more generic time stats + Stats_IncrementStat( player, "time_stats", "hours_total", "", timeHours ) + if ( player.IsTitan() ) + { + Stats_IncrementStat( player, "time_stats", "hours_as_titan_" + GetTitanCharacterName( player ), "", timeHours ) + Stats_IncrementStat( player, "time_stats", "hours_as_titan", "", timeHours ) + } + else + Stats_IncrementStat( player, "time_stats", "hours_as_pilot", "", timeHours ) + + string state = "" + // specific time stats + if ( !IsAlive( player ) ) + state = "hours_dead" + else if ( player.IsWallHanging() ) + state = "hours_wallhanging" + else if ( player.IsWallRunning() ) + state = "hours_wallrunning" + else if ( !player.IsOnGround() ) + state = "hours_inAir" + if ( state != "" ) + Stats_IncrementStat( player, "time_stats", state, "", timeHours ) + + // weapon time stats + entity activeWeapon = player.GetActiveWeapon() + if ( IsValid( activeWeapon ) ) + { + if ( IsValidStatItemString( activeWeapon.GetWeaponClassName() ) ) + Stats_IncrementStat( player, "weapon_stats", "hoursUsed", activeWeapon.GetWeaponClassName(), timeHours ) + + foreach( entity weapon in player.GetMainWeapons() ) + { + if ( IsValidStatItemString( weapon.GetWeaponClassName() ) ) + Stats_IncrementStat( player, "weapon_stats", "hoursEquipped", weapon.GetWeaponClassName(), timeHours ) + } + } + + // map time stats + Stats_IncrementStat( player, "game_stats", "hoursPlayed", "", timeHours ) + } + + lastTickTime = Time() + // not rly worth doing this every frame, just a couple of times per second should be fine + wait 0.25 + } +} + +// this is kinda shit +void function SaveStatsPeriodically_Threaded() +{ + while( true ) + { + foreach( entity player in GetPlayerArray() ) + Stats_SaveAllStats( player ) + wait 5 + } } -void function PreScoreEventUpdateStats(entity attacker, entity ent) +bool function IsValidGamemodeString( string mode ) { + int gameModeCount = PersistenceGetEnumCount( "gameModes" ) + for ( int modeIndex = 0; modeIndex < gameModeCount; modeIndex++ ) + { + string gameModeName = PersistenceGetEnumItemNameForIndex( "gameModes", modeIndex ) + + if ( gameModeName == mode ) + return true + } + return false } -void function PostScoreEventUpdateStats(entity attacker, entity ent) +bool function IsValidStatItemString( string item ) { + foreach( str in shGlobalMP.statsItemsList ) + { + if ( str == item ) + return true + } + return false } -void function Stats_OnPlayerDidDamage(entity player, var damageInfo) +string function GetPersistenceRefFromDamageInfo( var damageInfo ) { + string damageSourceString = DamageSourceIDToString( DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + + foreach( str in shGlobalMP.statsItemsList ) + { + if ( str == damageSourceString ) + return damageSourceString + } + return "" +} + +bool function DamageIsTitanMelee( int damageSourceId ) +{ + switch( damageSourceId ) + { + case eDamageSourceId.melee_titan_punch: + case eDamageSourceId.melee_titan_punch_ion: + case eDamageSourceId.melee_titan_punch_legion: + case eDamageSourceId.melee_titan_punch_tone: + case eDamageSourceId.melee_titan_punch_scorch: + case eDamageSourceId.melee_titan_punch_northstar: + case eDamageSourceId.melee_titan_punch_fighter: + case eDamageSourceId.melee_titan_sword: + case eDamageSourceId.melee_titan_sword_aoe: + return true + default: + return false + } + unreachable } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut index 85f5aa05..7a7498b8 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_loadouts.nut @@ -785,7 +785,7 @@ bool function IsSettingPrimeTitanWithoutSetFile( entity player, string loadoutTy bool function SkipItemLockedCheck( entity player, string ref, string parentRef, string loadoutProperty ) //Hack: Skip entitlement related unlock checks for now. Can fail. { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return true //if ( IsItemInEntitlementUnlock( ref ) && IsLobby() ) //TODO: Look into restricting this to lobby only? But entitlement checks can fail randomly... @@ -3993,7 +3993,7 @@ bool function IsValidTitanLoadoutIndex( int loadoutIndex ) bool function HasPrimeToMatchExecutionType( entity player, int itemType ) { - if ( DevEverythingUnlocked() ) + if ( DevEverythingUnlocked( player ) ) return true switch( itemType ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut new file mode 100644 index 00000000..00bdff60 --- /dev/null +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -0,0 +1,1091 @@ +global function Progression_Init +global function ProgressionEnabledForPlayer +#if CLIENT || UI +global function Progression_SetPreference +global function Progression_GetPreference +global function UpdateCachedLoadouts_Delayed +#endif + +// SO FOR SOME GOD DAMN REASON, PUTTING THESE INTO ONE STRUCT +// AND PUTTING THE #if STUFF AROUND THE VARS CAUSES A COMPILE +// ERROR, SO I HAVE TO DO THIS AWFULNESS + +#if SERVER +struct { + table progressionEnabled +} file +#else // UI || CLIENT +struct { + bool isUpdatingCachedLoadouts = false +} file +#endif + + +void function Progression_Init() +{ + #if SERVER + AddCallback_OnClientDisconnected( OnClientDisconnected ) + AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression ) + AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) + #elseif CLIENT + AddCallback_OnClientScriptInit( OnClientScriptInit ) + #endif +} + +bool function ProgressionEnabledForPlayer( entity player ) +{ + #if SERVER + if ( player in file.progressionEnabled ) + return file.progressionEnabled[player] + + return false + #else // CLIENT || UI + return GetConVarBool( "ns_progression_enabled" ) + #endif +} + +#if SERVER +void function OnPlaying() +{ + SetUIVar( level, "penalizeDisconnect", false ) // dont show the "you will lose merits thing" +} + +void function OnClientDisconnected( entity player ) +{ + // cleanup table when player leaves + if ( player in file.progressionEnabled ) + delete file.progressionEnabled[player] +} + +bool function ClientCommand_SetProgression( entity player, array args ) +{ + if ( args.len() != 1 ) + return false + if ( args[0] != "0" && args[0] != "1" ) + return false + + file.progressionEnabled[player] <- args[0] == "1" + + // loadout validation when progression is turned on + if ( file.progressionEnabled[player] ) + ValidateEquippedItems( player ) + + return true +} +#endif + +#if CLIENT +void function OnClientScriptInit( entity player ) +{ + // unsure if this is needed, just being safe + if ( player != GetLocalClientPlayer() ) + return + + Progression_SetPreference( GetConVarBool( "ns_progression_enabled" ) ) + UpdateCachedLoadouts_Delayed() +} +#endif + +#if CLIENT || UI +void function Progression_SetPreference( bool enabled ) +{ + SetConVarBool( "ns_progression_enabled", enabled ) + + #if CLIENT + GetLocalClientPlayer().ClientCommand( "ns_progression " + enabled.tointeger() ) + #else // UI + ClientCommand( "ns_progression " + enabled.tointeger() ) + #endif +} + +bool function Progression_GetPreference() +{ + return GetConVarBool( "ns_progression_enabled" ) +} + +void function UpdateCachedLoadouts_Delayed() +{ + if ( file.isUpdatingCachedLoadouts ) + return + + file.isUpdatingCachedLoadouts = true + + #if UI + RunClientScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced + #else // CLIENT + RunUIScript( "UpdateCachedLoadouts_Delayed" ) // keep client and UI synced + #endif + + thread UpdateCachedLoadouts_Threaded() +} + +void function UpdateCachedLoadouts_Threaded() +{ + wait 1.0 // give the server time to network our new persistence + + UpdateCachedLoadouts() + + // below here is just making all the menu models update properly and such + + #if UI + uiGlobal.pilotSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "pilot" ) + uiGlobal.titanSpawnLoadoutIndex = GetPersistentSpawnLoadoutIndex( GetUIPlayer(), "titan" ) + #endif + + #if CLIENT + entity player = GetLocalClientPlayer() + ClearAllTitanPreview( player ) + ClearAllPilotPreview( player ) + UpdateTitanModel( player, GetPersistentSpawnLoadoutIndex( player, "titan" ) ) + UpdatePilotModel( player, GetPersistentSpawnLoadoutIndex( player, "pilot" ) ) + #endif + + file.isUpdatingCachedLoadouts = false +} +#endif + +#if SERVER +void function ValidateEquippedItems( entity player ) +{ + printt( "VALIDATING EQUIPPED ITEMS FOR PLAYER: " + player.GetPlayerName() ) + + // banner + CallingCard card = PlayerCallingCard_GetActive( player ) + if ( IsItemLocked( player, card.ref ) ) + { + printt( "- BANNER CARD IS LOCKED, RESETTING" ) + PlayerCallingCard_SetActiveByRef( player, "callsign_16_col" ) // copied from _persistentdata.gnut + } + + // patch + CallsignIcon icon = PlayerCallsignIcon_GetActive( player ) + if ( IsItemLocked( player, icon.ref ) ) + { + printt( "- BANNER PATCH IS LOCKED, RESETTING" ) + PlayerCallsignIcon_SetActiveByRef( player, "gc_icon_titanfall" ) // copied from _persistentdata.gnut + } + + // faction + int factionIndex = player.GetPersistentVarAsInt( "factionChoice" ) + string factionRef = PersistenceGetEnumItemNameForIndex( "faction", factionIndex ) + if ( IsItemLocked( player, factionRef ) ) + { + printt( "- FACTION IS LOCKED, RESETTING" ) + player.SetPersistentVar( "factionChoice", "faction_marauder" ) // im so sorry that i am setting you to use sarah, you don't deserve this + } + + // boost + BurnReward reward = BurnReward_GetById( player.GetPersistentVarAsInt( "burnmeterSlot" ) ) + if ( IsItemLocked( player, reward.ref ) ) + { + printt( "- BOOST IS LOCKED, RESETTING" ) + player.SetPersistentVar( "burnmeterSlot", BurnReward_GetByRef( "burnmeter_amped_weapons" ).id ) + } + + // titan loadouts + for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ ) + { + printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex ) + + bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) + TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex ) + TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex] + + printt( " - CHASSIS: " + loadout.titanClass ) + + // passive1 - "Titan Kit" (things like overcore) + if ( loadout.passive1 != defaultLoadout.passive1 && IsSubItemLocked( player, loadout.passive1, loadout.titanClass ) ) + { + printt( " - TITAN KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + + // passive2 - " Kit" (things like zero point tripwire) + if ( loadout.passive2 != defaultLoadout.passive2 && IsSubItemLocked( player, loadout.passive2, loadout.titanClass ) ) + { + printt( " - CHASSIS KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + + // passive3 - "Titanfall Kit" (warpfall/dome shield) + if ( loadout.passive3 != defaultLoadout.passive3 && IsSubItemLocked( player, loadout.passive3, loadout.titanClass ) ) + { + printt( " - TITANFALL KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive3", defaultLoadout.passive3 ) + } + + // passive4 - monarch core 1 + if ( loadout.passive4 != defaultLoadout.passive4 && IsSubItemLocked( player, loadout.passive4, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 1 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive4", defaultLoadout.passive4 ) + } + + // passive5 - monarch core 2 + if ( loadout.passive5 != defaultLoadout.passive5 && IsSubItemLocked( player, loadout.passive5, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 2 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive5", defaultLoadout.passive5 ) + } + + // passive6 - monarch core 3 + if ( loadout.passive6 != defaultLoadout.passive6 && IsSubItemLocked( player, loadout.passive6, loadout.titanClass ) ) + { + printt( " - MONARCH CORE 3 KIT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].passive6", defaultLoadout.passive6 ) + } + + // titanExecution + if ( !IsRefValid( loadout.titanExecution ) || !IsValidTitanExecution( titanLoadoutIndex, "titanExecution", "", loadout.titanExecution ) ) + { + printt( " - TITAN EXECUTION IS INVALID FOR CHASSIS, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + else if ( IsItemLocked( player, loadout.titanExecution ) ) + { + printt( " - TITAN EXECUTION EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + else if ( GetItemData( loadout.titanExecution ).reqPrime && IsItemLocked( player, loadout.primeTitanRef ) ) + { + printt( " - PRIME TITAN EXECUTION EQUIPPED WHEN PRIME TITAN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].titanExecution", defaultLoadout.titanExecution ) + } + + // skinIndex + // camoIndex + if ( loadout.skinIndex == TITAN_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.camoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + } + else if ( loadout.skinIndex == 0 ) + { + if ( loadout.camoIndex != 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + else + { + string ref = GetSkinRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.skinIndex ) + if ( ref == INVALID_REF ) + { + printt( " - INVALID TITAN WARPAINT, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else if ( IsSubItemLocked( player, ref, loadout.titanClass ) ) + { + printt( " - TITAN WARPAINT EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + + // decalIndex + string noseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.decalIndex ) + if ( loadout.decalIndex != defaultLoadout.decalIndex && IsSubItemLocked( player, noseArtRef, loadout.titanClass ) ) + { + printt( " - NOSE ART EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].decalIndex", defaultLoadout.decalIndex ) + } + + // primarySkinIndex + // primaryCamoIndex + if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 ) + { + printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + } + else if ( loadout.primarySkinIndex == 0 && loadout.primaryCamoIndex != 0 ) + { + // titan weapons do not have skins, if we ever do add them lots of stuff will + //need a refactor outside of here so with that being said, i cannot be bothered + printt( " - INVALID WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + + + // isPrime + if ( loadout.isPrime == "titan_is_prime" && IsItemLocked( player, loadout.primeTitanRef ) ) + { + printt( " - PRIME TITAN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].isPrime", defaultLoadout.isPrime ) + } + + // primeSkinIndex + // primeCamoIndex + if ( loadout.primeSkinIndex == TITAN_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primeCamoIndex >= camoSkins.len() || loadout.primeCamoIndex < 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primeCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.titanClass ) ) + { + printt( " - TITAN CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + } + } + else if ( loadout.primeSkinIndex == 0 ) + { + if ( loadout.primeCamoIndex != 0 ) + { + printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + } + else + { + printt( " - INVALID PRIME TITAN SKIN, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeSkinIndex", defaultLoadout.primeSkinIndex ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeCamoIndex", defaultLoadout.primeCamoIndex ) + } + + // primeDecalIndex + string primeNoseArtRef = GetNoseArtRefFromTitanClassAndPersistenceValue( loadout.titanClass, loadout.primeDecalIndex ) + if ( loadout.primeDecalIndex != defaultLoadout.primeDecalIndex && IsSubItemLocked( player, primeNoseArtRef, loadout.titanClass ) ) + { + printt( " - PRIME NOSE ART EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].primeDecalIndex", defaultLoadout.primeDecalIndex ) + } + + // showArmBadge - equipped and shouldnt be able to + if ( loadout.showArmBadge && !CanEquipArmBadge( player, loadout.titanClass ) ) + { + printt( " - ARM BADGE EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "titanLoadouts[" + titanLoadoutIndex + "].showArmBadge", defaultLoadout.showArmBadge ) + } + + // equipped titan loadout - equipped titan class is locked + if ( isSelected && IsItemLocked( player, loadout.titanClass ) ) + { + printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" ) + player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 ) + } + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) ) + + // pilot loadouts + for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ ) + { + printt( "- VALIDATING PILOT LOADOUT: " + pilotLoadoutIndex ) + + bool isSelected = pilotLoadoutIndex == player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" ) + PilotLoadoutDef loadout = GetPilotLoadout( player, pilotLoadoutIndex ) + PilotLoadoutDef defaultLoadout = shGlobal.defaultPilotLoadouts[pilotLoadoutIndex] + + // note: for readability, I have added {} around the different items, + // so that you can collapse them in visual studio code (and other good IDEs) + + // tactical + { + if ( !IsRefValid( loadout.suit ) ) + { + printt( " - TACTICAL IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit ) + } + else if ( IsItemLocked( player, loadout.suit ) ) + { + printt( " - TACTICAL IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].suit", defaultLoadout.suit ) + } + } + + // ordnance + { + if ( !IsRefValid( loadout.ordnance ) ) + { + printt( " - ORDNANCE IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance ) + } + else if ( IsItemLocked( player, loadout.ordnance ) ) + { + printt( " - ORDNANCE IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].ordnance", defaultLoadout.ordnance ) + } + } + + // race ( gender ) + { + if ( !IsRefValid( loadout.race ) ) + { + printt( " - GENDER IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race ) + } + else if ( IsItemLocked( player, loadout.race ) ) + { + printt( " - GENDER IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].race", defaultLoadout.race ) + } + } + + // camoIndex + // skinIndex + { + if ( loadout.skinIndex == PILOT_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_PILOT ) + if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 ) + { + printt( " - INVALID PILOT CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.camoIndex] + if ( IsItemLocked( player, camoSkin.ref ) ) + { + printt( " - PILOT CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + } + else if ( loadout.skinIndex == 0 ) + { + if ( loadout.camoIndex != 0 ) + { + printt( " - INVALID PILOT CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + else + { + // pilots can't have skins other than 0 and 1 right? + printt( " - INVALID PILOT SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].skinIndex", defaultLoadout.skinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].camoIndex", defaultLoadout.camoIndex ) + } + } + + // primary weapon + { + if ( !IsRefValid( loadout.primary ) || GetItemType( loadout.primary ) != eItemTypes.PILOT_PRIMARY ) + { + printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary ) + } + else if ( IsItemLocked( player, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primary", defaultLoadout.primary ) + } + } + + // primary weapon mods + { + // mod1 + if ( loadout.primaryMod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.primary, loadout.primaryMod1 ) ) + { + printt( " - PRIMARY WEAPON MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod1, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod1", defaultLoadout.primaryMod1 ) + } + // mod2 + if ( loadout.primaryMod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "primarymod2", loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( !HasSubitem( loadout.primary, loadout.primaryMod2 ) ) + { + printt( " - PRIMARY WEAPON MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod2, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( loadout.primaryMod2 == loadout.primaryMod1 && loadout.primaryMod2 != "" ) + { + printt( " - PRIMARY WEAPON MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + else if ( loadout.primaryAttachment == "threat_scope" ) + { + printt( " - PRIMARY WEAPON MOD 2 IS SET WITH THREAT SCOPE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod2", defaultLoadout.primaryMod2 ) + } + // attachment + if ( loadout.primaryAttachment == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.primary, loadout.primaryAttachment ) ) + { + printt( " - PRIMARY WEAPON ATTACHMENT IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment ) + } + else if ( IsSubItemLocked( player, loadout.primaryAttachment, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON ATTACHMENT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryAttachment", defaultLoadout.primaryAttachment ) + } + // mod3 (pro screen) + if ( loadout.primaryMod3 == "" ) + { + // do nothing + } + else if ( loadout.primaryMod3 == "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - PRIMARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 ) + } + else if ( IsSubItemLocked( player, loadout.primaryMod3, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryMod3", defaultLoadout.primaryMod3 ) + } + } + + // primary weapon camoIndex + // primary weapon skinIndex + { + if ( loadout.primarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.primaryCamoIndex >= camoSkins.len() || loadout.primaryCamoIndex < 0 ) + { + printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.primaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + } + else if ( loadout.primarySkinIndex == 0 ) + { + if ( loadout.primaryCamoIndex != 0 ) + { + printt( " - INVALID PRIMARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.primarySkinIndex, loadout.primary ), loadout.primary ) ) + { + printt( " - PRIMARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } + } + + // secondary weapon + { + if ( !IsRefValid( loadout.secondary ) || GetItemType( loadout.secondary ) != eItemTypes.PILOT_SECONDARY ) + { + printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.secondary + if ( loadout.secondary == ref ) // item dupes swap + { + ref = defaultLoadout.weapon3 + } + else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.weapon3 + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref ) + } + else if ( IsItemLocked( player, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.secondary + if ( loadout.weapon3 == ref ) // item dupes swap + { + ref = defaultLoadout.weapon3 + } + else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.weapon3 + } + + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondary", ref ) + } + } + + // secondary weapon mods + { + // mod1 + if ( loadout.secondaryMod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod1 ) ) + { + printt( " - SECONDARY WEAPON MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 ) + } + else if ( IsSubItemLocked( player, loadout.secondaryMod1, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod1", defaultLoadout.secondaryMod1 ) + } + // mod2 + if ( loadout.secondaryMod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "secondarymod2", loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( !HasSubitem( loadout.secondary, loadout.secondaryMod2 ) ) + { + printt( " - SECONDARY WEAPON MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( IsSubItemLocked( player, loadout.secondaryMod2, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + else if ( loadout.secondaryMod2 == loadout.secondaryMod1 && loadout.secondaryMod2 != "" ) + { + printt( " - SECONDARY WEAPON MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod2", defaultLoadout.secondaryMod2 ) + } + // mod3 (pro screen) + if ( loadout.secondaryMod3 == "" ) + { + // do nothing + } + else if ( loadout.secondaryMod3 == "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - SECONDARY WEAPON PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 ) + } + else if ( IsSubItemLocked( player, "secondarymod3", loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryMod3", defaultLoadout.secondaryMod3 ) + } + } + + // secondary weapon camoIndex + // secondary weapon skinIndex + { + if ( loadout.secondarySkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.secondaryCamoIndex >= camoSkins.len() || loadout.secondaryCamoIndex < 0 ) + { + printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.secondaryCamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + } + else if ( loadout.secondarySkinIndex == 0 ) + { + if ( loadout.secondaryCamoIndex != 0 ) + { + printt( " - INVALID SECONDARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.secondarySkinIndex, loadout.secondary ), loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } + } + + // weapon3 + // note: these are always eItemTypes.PILOT_SECONDARY + { + if ( !IsRefValid( loadout.weapon3 ) || GetItemType( loadout.weapon3 ) != eItemTypes.PILOT_SECONDARY ) + { + printt( " - WEAPON3 WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.weapon3 + if ( loadout.weapon3 == ref ) // item dupes swap + { + ref = defaultLoadout.secondary + } + else if ( ItemsInSameMenuCategory( loadout.weapon3, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.secondary + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref ) + } + else if ( IsItemLocked( player, loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON IS LOCKED, RESETTING" ) + string ref = defaultLoadout.weapon3 + if ( loadout.secondary == ref ) // item dupes swap + { + ref = defaultLoadout.secondary + } + else if ( ItemsInSameMenuCategory( loadout.secondary, ref ) ) // category dupes assign value to other slot and swap + { + ref = defaultLoadout.secondary + } + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3", ref ) + } + } + + // weapon3 mods + { + // mod1 + if ( loadout.weapon3Mod1 == "" ) + { + // do nothing + } + else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod1 ) ) + { + printt( " - WEAPON3 MOD 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 ) + } + else if ( IsSubItemLocked( player, loadout.weapon3Mod1, loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod1", defaultLoadout.weapon3Mod1 ) + } + // mod2 + if ( loadout.weapon3Mod2 == "" ) + { + // do nothing + } + else if ( IsSubItemLocked( player, "secondarymod2", loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 2 SLOT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( !HasSubitem( loadout.weapon3, loadout.weapon3Mod2 ) ) + { + printt( " - WEAPON3 MOD 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( IsSubItemLocked( player, loadout.weapon3Mod2, loadout.weapon3 ) ) + { + printt( " - WEAPON3 MOD 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + else if ( loadout.weapon3Mod2 == loadout.weapon3Mod1 && loadout.weapon3Mod2 != "" ) + { + printt( " - WEAPON3 MOD 2 IS DUPLICATE, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod2", defaultLoadout.weapon3Mod2 ) + } + // mod3 (pro screen) + if ( loadout.weapon3Mod3 == "" ) + { + // do nothing + } + else if ( loadout.weapon3Mod3 != "pro_screen" ) + { + // fuck you and your three mod slot stuff + printt( " - WEAPON3 PRO SCREEN IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 ) + } + else if ( IsSubItemLocked( player, "secondarymod3", loadout.weapon3 ) ) + { + printt( " - WEAPON3 PRO SCREEN IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3Mod3", defaultLoadout.weapon3Mod3 ) + } + } + + // weapon3 camoIndex + // weapon3 skinIndex + { + if ( loadout.weapon3SkinIndex == WEAPON_SKIN_INDEX_CAMO ) + { + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + if ( loadout.weapon3CamoIndex >= camoSkins.len() || loadout.weapon3CamoIndex < 0 ) + { + printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + else + { + ItemData camoSkin = camoSkins[loadout.weapon3CamoIndex] + if ( IsSubItemLocked( player, camoSkin.ref, loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON CAMO/SKIN EQUIPPED WHEN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + } + else if ( loadout.weapon3SkinIndex == 0 ) + { + if ( loadout.weapon3CamoIndex != 0 ) + { + printt( " - INVALID TERTIARY WEAPON CAMO/SKIN, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.weapon3SkinIndex, loadout.weapon3 ), loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON SKIN LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } + } + + // kit 1 + { + if ( !IsRefValid( loadout.passive1 ) || GetItemType( loadout.passive1 ) != eItemTypes.PILOT_PASSIVE1 ) + { + printt( " - KIT 1 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + else if ( IsItemLocked( player, loadout.passive1 ) ) + { + printt( " - KIT 1 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive1", defaultLoadout.passive1 ) + } + } + + // kit 2 + { + if ( !IsRefValid( loadout.passive2 ) || GetItemType( loadout.passive2 ) != eItemTypes.PILOT_PASSIVE2 ) + { + printt( " - KIT 2 IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + else if ( IsItemLocked( player, loadout.passive2 ) ) + { + printt( " - KIT 2 IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].passive2", defaultLoadout.passive2 ) + } + } + + // execution + // note: not sure why defaultLoadout has this set to "", but neck snap should be default + { + if ( !IsRefValid( loadout.execution ) || GetItemType( loadout.execution ) != eItemTypes.PILOT_EXECUTION ) + { + printt( " - EXECUTION IS INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" ) + } + else if ( IsItemLocked( player, loadout.execution ) ) + { + printt( " - EXECUTION IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].execution", "execution_neck_snap" ) + } + } + + // equipped pilot loadout + { + if ( isSelected && IsItemLocked( player, "pilot_loadout_" + ( pilotLoadoutIndex + 1 ) ) ) + { + printt( " - SELECTED PILOT LOADOUT IS LOCKED, RESETTING" ) + player.SetPersistentVar( "pilotSpawnLoadout.index", 0 ) + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", 0 ) + } + } + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdatePilotModel", player.GetPersistentVarAsInt( "pilotSpawnLoadout.index" ) ) + + printt( "ITEM VALIDATION COMPLETE FOR PLAYER: " + player.GetPlayerName() ) +} + +// basically just PopulateTitanLoadoutFromPersistentData but without validation, we are doing the validation in a better way +// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need +TitanLoadoutDef function GetTitanLoadout( entity player, int loadoutIndex ) +{ + TitanLoadoutDef loadout + + loadout.name = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "name" ) + loadout.titanClass = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanClass" ) + loadout.primaryMod = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "primaryMod" ) + loadout.special = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "special" ) + loadout.antirodeo = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "antirodeo" ) + loadout.passive1 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive1" ) + loadout.passive2 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive2" ) + loadout.passive3 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive3" ) + loadout.passive4 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive4" ) + loadout.passive5 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive5" ) + loadout.passive6 = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "passive6" ) + loadout.camoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "camoIndex" ) + loadout.skinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.decalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "decalIndex" ) + loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primaryCamoIndex" ) + loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.titanExecution = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "titanExecution" ) + loadout.showArmBadge = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "showArmBadge" ) + + //Prime Titan related vars + loadout.isPrime = GetPersistentLoadoutValue( player, "titan", loadoutIndex, "isPrime" ) + loadout.primeCamoIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeCamoIndex" ) + loadout.primeSkinIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeSkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.primeDecalIndex = GetPersistentLoadoutValueInt( player, "titan", loadoutIndex, "primeDecalIndex" ) + + UpdateDerivedTitanLoadoutData( loadout ) + OverwriteLoadoutWithDefaultsForSetFile( loadout ) + + return loadout +} + +// basically just PopulatePilotLoadoutFromPersistentData but without validation, we are doing the validation in a better way +// that doesnt just kick the player and reset the entire loadout, since we want to only reset parts of the loadout that we need +PilotLoadoutDef function GetPilotLoadout( entity player, int loadoutIndex ) +{ + PilotLoadoutDef loadout + + loadout.name = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "name" ) + loadout.suit = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "suit" ) + loadout.race = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "race" ) + loadout.execution = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "execution" ) + loadout.primary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primary" ) + loadout.primaryAttachment = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryAttachment" ) + loadout.primaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod1" ) + loadout.primaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod2" ) + loadout.primaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "primaryMod3" ) + loadout.secondary = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondary" ) + loadout.secondaryMod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod1" ) + loadout.secondaryMod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod2" ) + loadout.secondaryMod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "secondaryMod3" ) + loadout.weapon3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3" ) + loadout.weapon3Mod1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod1" ) + loadout.weapon3Mod2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod2" ) + loadout.weapon3Mod3 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "weapon3Mod3" ) + loadout.ordnance = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "ordnance" ) + loadout.passive1 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive1" ) + loadout.passive2 = GetPersistentLoadoutValue( player, "pilot", loadoutIndex, "passive2" ) + loadout.camoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "camoIndex" ) + loadout.skinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "skinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.primaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primaryCamoIndex" ) + loadout.primarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "primarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.secondaryCamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondaryCamoIndex" ) + loadout.secondarySkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "secondarySkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + loadout.weapon3CamoIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3CamoIndex" ) + loadout.weapon3SkinIndex = GetPersistentLoadoutValueInt( player, "pilot", loadoutIndex, "weapon3SkinIndex" ) //Important: Skin index needs to be gotten after camoIndex for loadout validation purposes + + UpdateDerivedPilotLoadoutData( loadout ) + + return loadout +} + +bool function CanEquipArmBadge( entity player, string titanClass ) +{ + string skinRef + switch ( titanClass ) + { + case "ion": + skinRef = "ion_skin_fd" + break + case "scorch": + skinRef = "scorch_skin_fd" + break + case "northstar": + skinRef = "northstar_skin_fd" + break + case "ronin": + skinRef = "ronin_skin_fd" + break + case "tone": + skinRef = "tone_skin_fd" + break + case "legion": + skinRef = "legion_skin_fd" + break + case "vanguard": + skinRef = "monarch_skin_fd" + break + } + + return !IsSubItemLocked( player, skinRef, titanClass ) +} + +string function GetWeaponWarpaintRefByIndex( int skinIndex, string parentRef ) +{ + ItemData parentItem = GetItemData( parentRef ) + foreach ( subItem in parentItem.subitems ) + { + if ( GetSubitemType( parentRef, subItem.ref ) != eItemTypes.WEAPON_SKIN ) + continue + if ( subItem.i.skinIndex != skinIndex ) + continue + + return subItem.ref + } + + return INVALID_REF +} +#endif \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index 7f356a18..a2de9913 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -386,8 +386,12 @@ float function RoundToNearestMultiplier( float value, float multiplier ) return value } -function DevEverythingUnlocked() +function DevEverythingUnlocked( entity player = null ) { + // check if player has opted into progression or not + if ( player != null && ProgressionEnabledForPlayer( player ) ) + return false + return EverythingUnlockedConVarEnabled() } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut index 4bfeb4f8..0436a393 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut @@ -10,5 +10,8 @@ void function AddTitanXP( entity player, int amount ) // level up notif if ( TitanGetLevel( player, titan ) != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_TitanLeveledUp", shTitanXP.titanClasses.find( titan ), TitanGetGen( player, titan ), TitanGetLevel( player, titan ) ) + AddPlayerScore( player, "TitanLevelUp" ) + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut index 8e100257..4e25e301 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut @@ -12,8 +12,11 @@ void function AddWeaponXP( entity player, int amount ) // level up notif if ( WeaponGetLevel( player, weaponClassname ) != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponLeveledUp", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetGen( player, weaponClassname ), WeaponGetLevel( player, weaponClassname ) ) - + AddPlayerScore( player, "WeaponLevelUp" ) + } + // proscreen if ( player == activeWeapon.GetProScreenOwner() ) { -- cgit v1.2.3 From 9e9d7b7517e4af8df9879302d34deb93cadd9bc5 Mon Sep 17 00:00:00 2001 From: Klemmbaustein <83748124+Klemmbaustein@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:53:06 +0200 Subject: Changed TriggerConnectToServerCallbacks to take in an optional server for which the callback was triggered (#688) What's the point of this --- .../mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index c4046132..efc8d66c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1274,10 +1274,16 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call file.connectCallbacks.fastremovebyvalue( callback ) } -void function TriggerConnectToServerCallbacks() +void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { + ServerInfo server; + if (targetServer == null) + { + targetServer = file.lastSelectedServer + } + foreach( callback in file.connectCallbacks ) { - callback( file.lastSelectedServer ) + callback( expect ServerInfo( targetServer ) ) } } -- cgit v1.2.3 From 97d34dea1ba6c6623dc8174214062e6a79c93b7d Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Sat, 2 Sep 2023 12:53:52 -0400 Subject: Change Harvester to use Titan Health, support for mod damage balancing, and bug fixes (#579) Frontier War balancing, generally makes harvester code not suck --- .../scripts/vscripts/gamemodes/_gamemode_fw.nut | 127 +++++++++++++-------- .../vscripts/gamemodes/sh_gamemode_fw_custom.nut | 4 +- .../mod/scripts/vscripts/_harvester.gnut | 4 +- 3 files changed, 82 insertions(+), 53 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut index 850aa7b3..fa66c2f7 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_fw.nut @@ -13,8 +13,12 @@ global function FW_ReplaceMegaTurret global function FW_IsPlayerInFriendlyTerritory global function FW_IsPlayerInEnemyTerritory +// Callbacks for mods to reduce harvester damage of modded weapons +global function FW_AddHarvesterDamageSourceModifier +global function FW_RemoveHarvesterDamageSourceModifier + // you need to deal this much damage to trigger "FortWarTowerDamage" score event -const int FW_HARVESTER_DAMAGE_SEGMENT = 1500 +const int FW_HARVESTER_DAMAGE_SEGMENT = 5250 // basically needs to match "waves count - bosswaves count" const int FW_MAX_LEVELS = 3 @@ -85,6 +89,9 @@ struct CampSpawnStruct struct { array harvesters + + // Stores damage source IDs and the modifier applied to them when they damage a harvester + table< int, float > harvesterDamageSourceMods // save camp's info_target, we spawn camps after game starts, or player's first life won't show up correct camp icons array camps @@ -1738,13 +1745,14 @@ void function FW_createHarvester() { // imc havester spawn fw_harvesterImc = SpawnHarvester( file.harvesterImc_info.GetOrigin(), file.harvesterImc_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_IMC ) + fw_harvesterImc.harvester.SetArmorType( ARMOR_TYPE_HEAVY ) fw_harvesterImc.harvester.Minimap_SetAlignUpright( true ) fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) fw_harvesterImc.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null ) fw_harvesterImc.harvester.Minimap_SetHeightTracking( true ) fw_harvesterImc.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) fw_harvesterImc.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) - AddEntityCallback_OnDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged ) + AddEntityCallback_OnFinalDamaged( fw_harvesterImc.harvester, OnHarvesterDamaged ) AddEntityCallback_OnPostDamaged( fw_harvesterImc.harvester, OnHarvesterPostDamaged ) // imc havester settings @@ -1763,13 +1771,14 @@ void function FW_createHarvester() // mlt havester spawn fw_harvesterMlt = SpawnHarvester( file.harvesterMlt_info.GetOrigin(), file.harvesterMlt_info.GetAngles(), GetCurrentPlaylistVarInt( "fw_harvester_health", FW_DEFAULT_HARVESTER_HEALTH ), GetCurrentPlaylistVarInt( "fw_harvester_shield", FW_DEFAULT_HARVESTER_SHIELD ), TEAM_MILITIA ) + fw_harvesterMlt.harvester.SetArmorType( ARMOR_TYPE_HEAVY ) fw_harvesterMlt.harvester.Minimap_SetAlignUpright( true ) fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_IMC, null ) fw_harvesterMlt.harvester.Minimap_AlwaysShow( TEAM_MILITIA, null ) fw_harvesterMlt.harvester.Minimap_SetHeightTracking( true ) fw_harvesterMlt.harvester.Minimap_SetZOrder( MINIMAP_Z_OBJECT ) fw_harvesterMlt.harvester.Minimap_SetCustomState( eMinimapObject_prop_script.FD_HARVESTER ) - AddEntityCallback_OnDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged ) + AddEntityCallback_OnFinalDamaged( fw_harvesterMlt.harvester, OnHarvesterDamaged ) AddEntityCallback_OnPostDamaged( fw_harvesterMlt.harvester, OnHarvesterPostDamaged ) // mlt havester settings @@ -1784,6 +1793,53 @@ void function FW_createHarvester() // scores starts from 100, TeamScore means harvester health; TeamScore2 means shield bar GameRules_SetTeamScore( TEAM_IMC , 100 ) GameRules_SetTeamScore2( TEAM_IMC , 100 ) + + InitHarvesterDamageMods() +} + +void function FW_AddHarvesterDamageSourceModifier( int id, float mod ) +{ + if ( !( id in file.harvesterDamageSourceMods ) ) + file.harvesterDamageSourceMods[id] <- 1.0 + + file.harvesterDamageSourceMods[id] *= mod +} + +void function FW_RemoveHarvesterDamageSourceModifier( int id, float mod ) +{ + if ( !( id in file.harvesterDamageSourceMods ) ) + return + + file.harvesterDamageSourceMods[id] /= mod + + if ( file.harvesterDamageSourceMods[id] == 1.0 ) + delete file.harvesterDamageSourceMods[id] +} + +void function InitHarvesterDamageMods() +{ + // Damage balancing + const float CORE_DAMAGE_FRAC = 0.67 + const float NUKE_EJECT_DAMAGE_FRAC = 0.25 + const float DOT_DAMAGE_FRAC = 0.5 + + // Core balancing + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_laser_cannon, CORE_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_salvo_core, CORE_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_flightcore_rockets, CORE_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_shift_core, CORE_DAMAGE_FRAC ) + // Flame Core is not included since its single target damage is low compared to the others + + // Nuke eject balancing + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.damagedef_nuclear_core, NUKE_EJECT_DAMAGE_FRAC ) + + // Damage over time balancing + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_dumbfire_rockets, DOT_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_meteor_thermite, DOT_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_flame_wall, DOT_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanability_slow_trap, DOT_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titancore_flame_wave_secondary, DOT_DAMAGE_FRAC ) + FW_AddHarvesterDamageSourceModifier( eDamageSourceId.mp_titanweapon_heat_shield, DOT_DAMAGE_FRAC ) } // this function can't handle specific damageSourceID, such as plasma railgun, but is the best to scale both shield and health damage @@ -1792,6 +1848,21 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo ) if ( !IsValid( harvester ) ) return + // Entities (non-Players and non-NPCs) don't consider damaged entity lists, which makes ground attacks (e.g. Arc Wave) and thermite hit more than they should + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + if ( IsValid( inflictor ) && ( inflictor.e.onlyDamageEntitiesOnce || inflictor.e.onlyDamageEntitiesOncePerTick ) ) + { + if ( inflictor.e.damagedEntities.contains( harvester ) ) + { + DamageInfo_SetDamage( damageInfo, 0 ) + return + } + else + { + inflictor.e.damagedEntities.append( harvester ) + } + } + int friendlyTeam = harvester.GetTeam() int enemyTeam = GetOtherTeam( friendlyTeam ) int damageSourceID = DamageInfo_GetDamageSourceIdentifier( damageInfo ) @@ -1816,52 +1887,9 @@ void function OnHarvesterDamaged( entity harvester, var damageInfo ) // always reset harvester's recharge delay harvesterstruct.lastDamage = Time() - - // done damage adjustments here, since harvester prop's health is setting manually through damageAmount - if ( damageSourceID == eDamageSourceId.mp_titancore_laser_cannon ) - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 50 ) // laser core shreds super well for some reason - - // plasma railgun can always do no-charge shots and deal same damage - if ( damageSourceID == eDamageSourceId.mp_titanweapon_sniper ) // nerf northstar - { - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) - entity inflictor = DamageInfo_GetInflictor( damageInfo ) - if( IsValid( inflictor ) && inflictor.IsProjectile() ) - { - inflictor.s.extraDamagePerBullet = expect int( inflictor.s.extraDamagePerBullet ) / 3 - } - } - - // leadwall have high pilot damage so works really well aginst harvester - if ( damageSourceID == eDamageSourceId.mp_titanweapon_leadwall ) // nerf ronin - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) - - // missiles mostly have high pilot damage so works really well aginst harvester - if ( damageSourceID == eDamageSourceId.mp_titanweapon_salvo_rockets || - damageSourceID == eDamageSourceId.mp_titanweapon_shoulder_rockets || - damageSourceID == eDamageSourceId.mp_titancore_salvo_core - ) // titan missiles - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 3 ) - - if ( damageSourceID == eDamageSourceId.mp_titanweapon_sticky_40mm ) // 40mm trakcer cannon - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 2 ) - - if ( damageSourceID == eDamageSourceId.mp_titanweapon_flightcore_rockets ) // flight core shreds well - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) - - // cluster missle is very effective against non-moving targets - if ( damageSourceID == eDamageSourceId.mp_titanweapon_dumbfire_rockets ) // cluster missile shreds super well - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 10 ) - - // scorch's thermites is very effective against non-moving targets - if ( damageSourceID == eDamageSourceId.mp_titanweapon_heat_shield || - damageSourceID == eDamageSourceId.mp_titanweapon_meteor_thermite || - damageSourceID == eDamageSourceId.mp_titanweapon_flame_wall || - damageSourceID == eDamageSourceId.mp_titanability_slow_trap || - damageSourceID == eDamageSourceId.mp_titancore_flame_wave_secondary - ) // scorch's thermite damages, nerf scorch - DamageInfo_SetDamage( damageInfo, DamageInfo_GetDamage( damageInfo ) / 5 ) - + // Should be moved to a final damage callback once those are added + if ( damageSourceID in file.harvesterDamageSourceMods ) + DamageInfo_ScaleDamage( damageInfo, file.harvesterDamageSourceMods[ damageSourceID ] ) } void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) { @@ -1977,7 +2005,6 @@ void function OnHarvesterPostDamaged( entity harvester, var damageInfo ) } } - // harvester down! if ( harvester.GetHealth() == 0 ) { diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut index be93193d..c295d596 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/sh_gamemode_fw_custom.nut @@ -7,8 +7,8 @@ global function SHCreateGamemodeFW_Init // object settings, changable through playlist vars // default havester settings -global const int FW_DEFAULT_HARVESTER_HEALTH = 25000 -global const int FW_DEFAULT_HARVESTER_SHIELD = 5000 +global const int FW_DEFAULT_HARVESTER_HEALTH = 87500 +global const int FW_DEFAULT_HARVESTER_SHIELD = 17500 global const float FW_DEFAULT_HARVESTER_REGEN_DELAY = 12.0 global const float FW_DEFAULT_HARVESTER_REGEN_TIME = 10.0 // default turret settings diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut index 542db4d5..3bdb1d8a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_harvester.gnut @@ -28,7 +28,9 @@ HarvesterStruct function SpawnHarvester( vector origin, vector angles, int healt harvester.SetShieldHealthMax( shieldHealth ) harvester.SetShieldHealth( shieldHealth ) harvester.EnableAttackableByAI( 30, 0, AI_AP_FLAG_NONE ) - SetObjectCanBeMeleed( harvester, false ) + SetCustomSmartAmmoTarget( harvester, true ) + SetObjectCanBeMeleed( harvester, true ) + SetVisibleEntitiesInConeQueriableEnabled( harvester, true ) SetTeam(harvester,team) DispatchSpawn( harvester ) -- cgit v1.2.3 From 43d238aa41b85345266f1c35fe1d42ef88610f1e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 3 Sep 2023 16:24:30 +0200 Subject: Translations update from Weblate (#697) Translated using Weblate (Russian) Currently translated at 95.4% (274 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../resource/northstar_client_localisation_russian.txt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index d26017b8..514e4fd1 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -62,7 +62,7 @@ "featured_mode_all_holopilot" "Великий обманщик" "featured_mode_all_grapple" "Зацепер" "featured_mode_all_phase" "Мир иной" - "featured_mode_all_ticks" "Горячие парни" + "featured_mode_all_ticks" "Крутые перцы" "featured_mode_tactikill" "Тактический удар" "featured_mode_amped_tacticals" "Усиленные тактики" "featured_mode_rocket_arena" "Ракетная Арена" @@ -211,7 +211,7 @@ "SP_S2S" "Ковчег" "SP_S2S_CLASSIC_DESC" "Купер и БТ перемещаются по кораблям, преследуя Ковчег." - "SP_SKYWAY_V1" "Сложенное оружие" + "SP_SKYWAY_V1" "Искажающее орудие" "SP_SKYWAY_V1_CLASSIC_DESC" "БT и Купер были захвачены Кубеном Блиском." // Better.Serverbrowser @@ -329,5 +329,17 @@ "sns_softball_kill_value" "Очков за убийство Софтболом" "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" "gg_assist_reward" "Множитель награды за помощь в убийстве" + "TOGGLE_PROGRESSION" "Вкл/выкл прогресс" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Вкл/выкл прогресс" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Включить прогресс?" + "PROGRESSION_ENABLED_HEADER" "Прогресс включён!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Прогресс включён.^\n\nНедоступных титанов, оружие, фракции, раскраски, и т.п. теперь нужно разблокировать, или купить за Заслуги.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "PROGRESSION_DISABLED_HEADER" "Прогресс выключен!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000Прогресс выключен.^\n\nВсе титаны, оружие, фракции, раскраски, и т.п. теперь доступны.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "player_force_respawn" "Принудительное возрождение" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Отключить прогресс?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Все титаны, оружие, фракции, раскраски, и т.п. станут разблокированы.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Будут доступны только разблокированные или купленные вами титаны, оружие, фракции, раскраски, и т.п.\n\nЭту настройку всегда можно изменить в лобби сетевой игры.\n\n^CC000000Внимание: недоступные предметы в экипировке будут заменены на доступные!" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Прогресс!^\n\nВ Northstar теперь работает оригинальная система прогресса разблокировок. Титанов, оружие, фракции, раскраски, и т.п. теперь можно разблокировать через получение новых уровней и прохождение испытаний.\n\nПрогресс можно включить с помощью кнопки внизу меню лобби.\n\nЭту настройку всегда можно изменить." } } -- cgit v1.2.3 From 0068720fe91307c1e538b6a104dc308204fcf400 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 17 Sep 2023 01:38:49 +0100 Subject: Fix a crash with IsPetTitan (#701) --- Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut index c5887f2b..47dd9294 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_utility_shared.nut @@ -1601,6 +1601,9 @@ float function GetPulseFrac( rate = 1, startTime = 0 ) bool function IsPetTitan( titan ) { Assert( titan.IsTitan() ) + + if ( !titan.GetTitanSoul() ) + return false return titan.GetTitanSoul().GetBossPlayer() != null } -- cgit v1.2.3 From 578cb2bea79c8440b5870a1557d1c6a870620f53 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 17 Sep 2023 12:55:55 +0200 Subject: Translations update from Weblate (#703) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (Spanish) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ * Translated using Weblate (French) Currently translated at 98.9% (284 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ * Translated using Weblate (French) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ --------- Co-authored-by: FÁ_monkey Co-authored-by: Andrés Co-authored-by: Lorin-lab Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 12 +++ .../northstar_client_localisation_spanish.txt | 103 ++++++++++++++------- 2 files changed, 80 insertions(+), 35 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index d5881d6c..45abcfc5 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -341,5 +341,17 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "SHOW_ONLY_NOT_REQUIRED" "Uniquement les mods optionnels" "NO_RESULTS" "Aucun résultat." "NO_MODS" "Aucun paramètre trouvé ! Installez d'autres mods depuis ^5588FF00northstar.thunderstore.io^0." + "player_force_respawn" "Réapparition forcée" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Désactiver la progression ?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Les Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Activer la progression ?" + "PROGRESSION_ENABLED_HEADER" "Progression activée !" + "PROGRESSION_DISABLED_HEADER" "Progression désactivée !" + "PROGRESSION_DISABLED_BODY" "^CCCC0000La progression a été désactivée.^\n\nLes Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" + "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." + "TOGGLE_PROGRESSION" "Activer la progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Activer la progression" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 0dc82570..43ee412f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -9,10 +9,10 @@ "MENU_TITLE_MODS" "Mods" "RELOAD_MODS" "Recargar Mods" "WARNING" "Advertencia" - "CORE_MOD_DISABLE_WARNING" "Puedes romper el cliente si deshabilitas los mods principales!" + "CORE_MOD_DISABLE_WARNING" "¡Puedes romper el cliente si deshabilitas los mods principales!" "DISABLE" "Deshabilitar" - "DIALOG_TITLE_INSTALLED_NORTHSTAR" "Gracias por instalar Northstar!." + "DIALOG_TITLE_INSTALLED_NORTHSTAR" "¡Gracias por instalar Northstar!" "AUTHENTICATION_AGREEMENT_DIALOG_TEXT" "Para que Northstar funcione, necesita autentificarse con el servidor maestro Northstar. Esto requiere enviar tu token Origin al servidor maestro, no se guardará ni se usará para cualquier otro fin. Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mods en cualquier momento." "BACK_AUTHENTICATION_AGREEMENT" "Acuerdo de autentificación" @@ -26,7 +26,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "NS_SERVERBROWSER_NOSERVERS" "No se encontraron servidores" "NS_SERVERBROWSER_UNKNOWNMODE" "Modo desconocido" "NS_SERVERBROWSER_WAITINGFORSERVERS" "Esperando por servidores..." - "NS_SERVERBROWSER_CONNECTIONFAILED" "Connexión fallida!" + "NS_SERVERBROWSER_CONNECTIONFAILED" "¡Conexión fallida!" "REFRESH_SERVERS" "Recargar" "MENU_TITLE_CONNECT_PASSWORD" "Conectar con contraseña" @@ -36,7 +36,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PRIVATE_MATCH_PAGE_NEXT" "Página siguiente" "MENU_MATCH_SETTINGS" "Configuración de partida" - "MENU_MATCH_SETTINGS_SUBMENU" "%s1 Configuraciones" + "MENU_MATCH_SETTINGS_SUBMENU" "Configuración de %s1" "PRIVATE_MATCH_SINGLEPLAYER_LEVEL" "%s1 (Un jugador)" @@ -46,16 +46,16 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo // mode settings "MODE_SETTING_CATEGORY_PILOT" "Piloto" "MODE_SETTING_CATEGORY_TITAN" "Titán" - "MODE_SETTING_CATEGORY_RIFF" "Riffs" + "MODE_SETTING_CATEGORY_RIFF" "Fragmento" "MODE_SETTING_CATEGORY_MATCH" "Partida" "classic_mp" "Multijugador Clasico" "run_epilogue" "Habilitar Epílogo" "scorelimit" "Limite de puntuación" - "roundscorelimit" "Puntaje limite (rondas)" - "timelimit" "Tiempo limite" - "roundtimelimit" "Tiempo limite (rondas)" - "respawnprotection" "Tiempo de proteccion en reaparición" + "roundscorelimit" "Límite de punataje (rondas)" + "timelimit" "Límite de tiempo" + "roundtimelimit" "Límite de tiempo (rondas)" + "respawnprotection" "Tiempo de protección en reaparición" "pilot_health_multiplier" "Multiplicador de salúd" "respawn_delay" "Retraso de aparición" @@ -73,7 +73,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "featured_mode_all_grapple" "Ataque a los titanes" "featured_mode_all_phase" "El otro lado" "featured_mode_all_ticks" "Picante" - "featured_mode_tactikill" "Eliminación tactica" + "featured_mode_tactikill" "Eliminación con tactica" "featured_mode_amped_tacticals" "Tacticas mejoradas" "featured_mode_rocket_arena" "Arena de cohetes" "featured_mode_shotguns_snipers" "Armado y peligroso" @@ -85,11 +85,11 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "aitdm_archer_grunts" "Soldado Archer" // northstar.custom localisation is just deciding not to work, so putting it here for now - "PL_sbox" "Sandbox" - "PL_sbox_lobby" "Vestíbulo de Sandbox" - "PL_sbox_desc" "como gmod pero peor" + "PL_sbox" "Custom" + "PL_sbox_lobby" "Vestíbulo de juego abierto" + "PL_sbox_desc" "Como \"gmod\" pero peor" "PL_sbox_abbr" "SBOX" - "GAMEMODE_SBOX" "Sandbox" + "GAMEMODE_SBOX" "CUstom" "PL_gg" "Carrera armamentística" "PL_gg_lobby" "Vestíbulo de Carrera armamentística" @@ -103,37 +103,37 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PL_tt" "Titan Tag" "PL_tt_lobby" "Vestíbulo de Titan Tag" - "PL_tt_desc" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo." - "PL_tt_hint" "Obtén puntos en tu titán. Destruye un titán para obtener el tuyo." + "PL_tt_desc" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo." + "PL_tt_hint" "Obtén puntos estando en tu titán. Destruye un titán para obtener el tuyo." "PL_tt_abbr" "TT" "GAMEMODE_TT" "Titan Tag" "PL_chamber" "Uno en la recamara" "PL_chamber_lobby" "Vestíbulo de uno en la recamara" - "PL_chamber_desc" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien." - "PL_chamber_hint" "Un disparo, Una eliminación. Obtén otra bala en tu cargador eliminando a alguien." - "PL_chamber_abbr" "CHAMBER" - "GAMEMODE_CHAMBER" "Uno en la recamara" + "PL_chamber_desc" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien." + "PL_chamber_hint" "Un disparo, una eliminación. Obtén otra bala en tu cargador eliminando a alguien." + "PL_chamber_abbr" "RECÁMARA" + "GAMEMODE_CHAMBER" "Uno en la recámara" "PL_hidden" "El escondido" "PL_hidden_lobby" "Vestíbulo de El escondido" "PL_hidden_desc" "Un jugador es invisible. El escondido caza." "PL_hidden_hint" "Un jugador es invisible. El escondido caza." - "PL_hidden_abbr" "HIDDEN" + "PL_hidden_abbr" "OCULTO" "GAMEMODE_HIDDEN" "El escondido" - "HIDDEN_YOU_ARE_HIDDEN" "Eres el escondido!" + "HIDDEN_YOU_ARE_HIDDEN" "¡Eres el escondido!" "HIDDEN_KILL_SURVIVORS" "Mata a todos los supervivientes." "HIDDEN_FIRST_HIDDEN" "%s1 es El Escondido." - "PL_sns" "Piedras y palos" - "PL_sns_lobby" "Vestíbulo de Piedras y palos" + "PL_sns" "Palos y Piedras" + "PL_sns_lobby" "Vestíbulo de Palos y Piedras" "PL_sns_desc" "Todos contra todos. Usa cuchillas de pulso y ejecucciones para reestablecer el puntaje del enemigo" "PL_sns_abbr" "SNS" - "GAMEMODE_SNS" "Piedras y palos" + "GAMEMODE_SNS" "Palos y Piedras" "SCOREBOARD_BANKRUPTS" "Eliminaciones de bancarrota" - "SNS_LEADER_BANKRUPT" "Lider de puntaje en bancarrota!" - "SNS_LEADER_BANKRUPT_SUB" "%s1 Fue reseteado por %s2" - "SNS_BANKRUPT" "Arruinado!" + "SNS_LEADER_BANKRUPT" "¡Lider de puntaje en bancarrota!" + "SNS_LEADER_BANKRUPT_SUB" "%s1 fue reseteado por %s2" + "SNS_BANKRUPT" "¡Arruinado!" "SNS_BANKRUPT_SUB" "Tu puntaje fue reseteado por %s1" "sns_wme_kill_value" "Valor por eliminacion con Wingman Elite" "sns_softball_kill_value" "Valor por eliminacion con Softball" @@ -152,7 +152,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "INFECTION_YOU_ARE_INFECTED" "Has sido infectado!" "INFECTION_KILL_SURVIVORS" "Infecta a todos los supervivientes restantes." "INFECTION_FIRST_INFECTED" "%s1 es el primer Infectado." - "INFECTION_LAST_SURVIVOR" "%s1 es el ultimo superviviente!" + "INFECTION_LAST_SURVIVOR" "¡%s1 es el ultimo superviviente!" "INFECTION_KILL_LAST_SURVIVOR" "Infectalo antes de que el tiempo se acabe!" "INFECTION_YOU_ARE_LAST_SURVIVOR" "Eres el ultimo superviviente!" "INFECTION_SURVIVE_LAST_SURVIVOR" "Sobrevive." @@ -186,7 +186,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "GAMEMODE_fw" "Guerra fronteriza" "PL_fw" "Guerra fronteriza" "PL_fw_lobby" "Vestíbulo de Guerra fronteriza" - "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo." + "PL_fw_desc" "Destruye el cosechador del enemigo y protege el tuyo" "PL_fw_abbr" "FW" "GAMEMODE_kr" "Carrera por muertes" @@ -205,8 +205,8 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "KR_YOUR_KILLRACE_OVER" "Tu carrera ha acabado" "KR_YOUR_KILLRACE_SCORE" "Has obtenido %s1 bajas." - "GAMEMODE_fastball" "Fastball" - "PL_fastball" "Fastball" + "GAMEMODE_fastball" "Lanzamiento" + "PL_fastball" "Lanzamiento" "PL_fastball_lobby" "Vestíbulo de Fastball" "PL_fastball_desc" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo." "PL_fastball_hint" "Muerte permanente. Piratea paneles de control para ganar rondas y hacer reaparecer a tus compañeros de equipo." @@ -263,7 +263,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "SP_BEACON_CLASSIC_DESC" "Cooper y BT intentan contactar con lo que queda de la flota para alertar de los planes de IMC." "SP_TDAY" "Prueba de fuego" - "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca." + "SP_TDAY_CLASSIC_DESC" "Las habilidades de Cooper al mando de su titán se ponen a prueba en una batalla total para capturar el Arca" "SP_S2S" "El Arca" "SP_S2S_CLASSIC_DESC" "Cooper y BT van de nave en nave en busca del Arca." @@ -284,7 +284,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "HIDE_EMPTY_FILTER" "Esconder servidores vacios" "HIDE_PROT_FILTER" "Esconder servidores protegidos" "SERVER_DESCRIPTION" "Descripción" - "SERVER_MODS" "Mods" + "SERVER_MODS" "Modificaciones" "CLEAR_FILTERS" "LIMPIAR" "JOIN_BUTTON" "UNIR" @@ -318,6 +318,39 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PLAYER_NOT_FOUND" "No se encontró la cuenta del jugador" "INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido" "JSON_PARSE_ERROR" "Error procesando respuesta json" - "UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada" + "UNSUPPORTED_VERSION" "La versión que estás usando ya no está siendo mantenida" + "MATCH_COUNTDOWN_LENGTH" "Duración cronometrada de la partida privada" + "ONLY_HOST_MATCH_SETTINGS" "Sólo el anfitrión puede cambiar las configuraciones de la partida" + "ONLY_HOST_CAN_START_MATCH" "Sólo el anfitrión puede iniciar la partida" + "DISALLOWED_WEAPONS" "Armas prohibidas" + "REPLACEMENT_WEAPON" "Arma de reemplazo" + "MOD_SETTINGS" "Configuración de Mods" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registrar comandos no reconocidos desde el cliente" + "DISALLOWED_TACTICALS" "Tácticas prohibidas" + "TACTICAL_REPLACEMENT" "Reemplazo de la táctica" + "SHOULD_RETURN_TO_LOBBY" "Regresar a la sala de espera después de la partida" + "ARE_YOU_SURE" "¿Segur@?" + "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las opciones de ésta categoría.\n\nNo se podrá revertir el proceso." + "NORTHSTAR_BASE_SETTINGS" "Opciones de Northstar por defecto" + "NO_RESULTS" "No hay resultados." + "MOD_SETTINGS_RESET" "Reiniciar" + "SHOW_ONLY_NOT_REQUIRED" "Mostrar sólo mods opcionales" + "SHOW_ONLY_REQUIRED" "Mostrar sólo mods obligatorios" + "NO_MODS" "¡No hay configuraciones disponibles! Instala más mods desde ^5588FF00northstar.thunderstore.io^0." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "¿Habilitar progreso?" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "¿Deshabilitar progresión?" + "PROGRESSION_ENABLED_HEADER" "¡Progreso habilitado!" + "PROGRESSION_DISABLED_HEADER" "¡Progreso deshabilitado!" + "TOGGLE_PROGRESSION" "Cambiar modo de progresión" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Cambiar modo de progresión" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados sólo al subir de nivel, o a través de Logros.\n\nÉsta opción puede ser cambiada cuando quieras en la sala de espera.\n\n^CC000000Advertencia: ¡Cualquier equipamiento o utensilio será reiniciado si no lo tienes desbloqueado!" + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET_ALL" "Reiniciar completamente" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Los Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados y permanecerán utilizables.\n\nÉsta opción puede ser cambiada cuando quieras desde la sala de espera." + "PROGRESSION_ENABLED_BODY" "^CCCC0000El modo de progreso ha sido habilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros se desbloquearán al subir de nivel o por Logros.\n\nPuedes cambiar ésta opción cuando quieras en la sala de espera." + "PROGRESSION_DISABLED_BODY" "^CCCC0000El modo de progreso ha sido deshabilitado.^\n\nLos Titanes, Armas, Facciones, Aspectos y otros están desbloqueados y puedes utilizarlos cuando quieras.\n\nPuedes cambiar ésta opción cuando quieras desde la sala de espera." + "WILL_RESET_SETTING" "Ésta acción reiniciará %s1 a su valor por defecto.\n\nNo se podrá revertir el proceso." + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000El progreso puede ser habilitado desde ahora^\n\nNorthstar ahora es compatible con el progreso normal del juego, esto significa que puedes elegir desbloquear Armas, Aspectos, Titanes y otros a través de desafíos y subiendo de nivel.\n\nPuedes habilitar el progreso normal del juego en la opción ubicada al final de la pantalla de la sala de espera.\n\nÉsta opción puede ser cambiada en cualquier momento." + "player_force_respawn" "Reaparición Forzada" } } -- cgit v1.2.3 From afdadc6f897df342f882e0f98b2fccaa9e140289 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:58:00 +0200 Subject: Translations update from Weblate (#712) Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (287 of 287 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/zh_Hant/ Co-authored-by: zxcPandora <81985226+zxcPandora@users.noreply.github.com> --- .../mod/resource/northstar_client_localisation_tchinese.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index e543f711..003ca28a 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -344,5 +344,17 @@ "REPLACEMENT_WEAPON" "替换的武器" "WILL_RESET_ALL_SETTINGS" "這將會重置所有屬於改條目的設置.\n\n此操作不可復原." "NO_MODS" "無可用模組! 前往 ^5588FF00northstar.thunderstore.io^0 下載更多." + "player_force_respawn" "強制重生" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "啟用個人進度?" + "PROGRESSION_ENABLED_HEADER" "個人進度已開啟!" + "PROGRESSION_TOGGLE_DISABLED_BODY" "泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。\n\n^CC000000警告:如果您已經裝備了尚未解鎖的物品,它們將會被重置!" + "PROGRESSION_TOGGLE_ENABLED_BODY" "泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品都將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" + "TOGGLE_PROGRESSION" "遊戲進度" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% 遊戲進度" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "停用個人進度?" + "PROGRESSION_DISABLED_HEADER" "個人進度已關閉!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000個人進度已停用^\n\n泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" + "PROGRESSION_ENABLED_BODY" "^CCCC0000個人進度已啟用^\n\n泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000現在可以隨時開啟個人進度!^\n\nNorthstar 現在支持類似官服的進度系統, 这意味着你可以选择通过升级和完成挑战来解锁武器、皮肤、泰坦等。\n\n您可以通過多人大廳底部的“遊戲進度”按鈕來進行開啟。\n\n您可以隨時在多人大廳中更改此項。" } } -- cgit v1.2.3 From a2c0d6c0d4a666b60fabfcb3672953bbd6c73b3b Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 18 Sep 2023 20:02:03 +0100 Subject: Use `WinnerDetermined` instead of `Epilogue` to grant stats (#713) Use `WinnerDetermined` instead of `Epilogue` to grant stats as some modes (like LTS) don't go into `eGameState.Epilogue` apparently. `eGameState.WinnerDetermined` should be better --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 92c0f401..010184ff 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -36,7 +36,7 @@ void function Stats_Init() AddCallback_OnPlayerRespawned( OnPlayerRespawned ) AddCallback_OnClientConnected( OnClientConnected ) AddCallback_OnClientDisconnected( OnClientDisconnected ) - AddCallback_GameStateEnter( eGameState.Epilogue, OnEpilogueStarted ) + AddCallback_GameStateEnter( eGameState.WinnerDetermined, OnWinnerDetermined ) thread HandleDistanceAndTimeStats_Threaded() thread SaveStatsPeriodically_Threaded() @@ -798,7 +798,7 @@ void function OnPlayerRespawned( entity player ) thread SetLastPosForDistanceStatValid_Threaded( player, true ) } -void function OnEpilogueStarted() +void function OnWinnerDetermined() { // award players for match completed, wins, and losses foreach ( entity player in GetPlayerArray() ) -- cgit v1.2.3 From 6bfd52bd3e246d07a8219e065e2f7b4071973e41 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 18 Sep 2023 22:17:22 +0100 Subject: Fix script compile error for progression in SP (#714) --- .../mod/scripts/vscripts/sh_progression.nut | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 00bdff60..22354349 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -6,6 +6,18 @@ global function Progression_GetPreference global function UpdateCachedLoadouts_Delayed #endif +#if SP // literally just stub the global functions and call it a day + +void function Progression_Init() {} +bool function ProgressionEnabledForPlayer( entity player ) { return false } +#if CLIENT || UI +void function Progression_SetPreference( bool enabled ) {} +bool function Progression_GetPreference() { return false } +void function UpdateCachedLoadouts_Delayed() {} +#endif // CLIENT || UI + +#else // MP || UI basically + // SO FOR SOME GOD DAMN REASON, PUTTING THESE INTO ONE STRUCT // AND PUTTING THE #if STUFF AROUND THE VARS CAUSES A COMPILE // ERROR, SO I HAVE TO DO THIS AWFULNESS @@ -1088,4 +1100,6 @@ string function GetWeaponWarpaintRefByIndex( int skinIndex, string parentRef ) return INVALID_REF } -#endif \ No newline at end of file +#endif // SERVER + +#endif // MP -- cgit v1.2.3 From c7149b7b14832497bd704ed2207cb3c11947fab1 Mon Sep 17 00:00:00 2001 From: Respawn Date: Tue, 3 Oct 2023 00:07:26 +0200 Subject: Add mp_complex3_script.ent from client_mp_complex3 --- .../mod/maps/mp_complex3_script.ent | 13313 +++++++++++++++++++ 1 file changed, 13313 insertions(+) create mode 100644 Northstar.CustomServers/mod/maps/mp_complex3_script.ent diff --git a/Northstar.CustomServers/mod/maps/mp_complex3_script.ent b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent new file mode 100644 index 00000000..ce8b0bff --- /dev/null +++ b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent @@ -0,0 +1,13313 @@ +ENTITIES01 +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 -12.363 0" +"origin" "-3966.17 -2563 748" +"targetname" "info_player_start_7" +"classname" "info_player_start" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_at" "0" +"origin" "-6248 -1288 520" +"link_to_guid_0" "3148974f" +"link_guid" "e2596db6" +"hardpointGroup" "p" +"gamemode_tday" "1" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_at" "0" +"origin" "-3688 -2288 720" +"link_to_guid_0" "5bdcb1bf" +"link_guid" "9ef44891" +"hardpointGroup" "p" +"gamemode_tday" "1" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_at" "0" +"origin" "-896 -2880 520" +"link_to_guid_0" "a6716741" +"link_guid" "f137536f" +"hardpointGroup" "p" +"gamemode_tday" "1" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_at" "0" +"origin" "-3624 -4216 640" +"link_to_guid_0" "c9c2695" +"link_guid" "24221b55" +"hardpointGroup" "p" +"gamemode_tday" "1" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_at" "0" +"origin" "-3752 -96 560" +"link_to_guid_0" "17679895" +"link_guid" "bf771060" +"hardpointGroup" "p" +"gamemode_tday" "1" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"classname" "info_hardpoint" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 69.653 0" +"origin" "-8484.94 -2690.44 603.359" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 74.349 0" +"origin" "-8474.32 -2693.28 603.359" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8442.56 -2694.55 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 35.353 0" +"origin" "-8428.26 -2695.27 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 140.285 0" +"origin" "-8435.99 -2693.2 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 162.106 0" +"origin" "-8448.62 -2693.96 585.359" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -95.139 0" +"origin" "-8445.15 -2704.21 585.359" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8432.59 -2707.57 585.359" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -13.747 0" +"origin" "-8477.69 -2690.31 651.359" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8472.39 -2693.8 585.359" +"targetname" "func_model_242" +"model" "models/containers/styrofoam_box_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -30.172 0" +"origin" "-8446.78 -2698.6 651.359" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8461.88 -2689.37 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 35.353 0" +"origin" "-8447.58 -2690.1 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 140.285 0" +"origin" "-8455.31 -2688.02 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8485.06 -2683.16 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 35.353 0" +"origin" "-8470.76 -2683.88 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 140.285 0" +"origin" "-8478.49 -2681.81 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8434.97 -2704.86 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -15 0" +"origin" "-8465.88 -2696.58 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 140.285 0" +"origin" "-8455.45 -2696.27 627.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 35.353 0" +"origin" "-8472.83 -2691.61 627.359" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -13.747 0" +"origin" "-8439.05 -2700.67 603.359" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "-2.2039e-006 140.285 1.12504e-006" +"origin" "-8454.93 -2694.34 603.639" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "2.4724e-006 -15 0" +"origin" "-8452.22 -2691.96 603.639" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 89.4372 0" +"origin" "-8463.43 -2695.17 603.359" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 119.849 0" +"origin" "-8397.44 -2748.86 585.86" +"targetname" "func_model_287" +"model" "models/containers/crate_blue_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -60.1509 0" +"origin" "-8380.52 -2778.35 585.86" +"targetname" "func_model_287" +"model" "models/containers/crate_blue_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 116.955 0" +"origin" "-8384.52 -2763.35 628.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -151.236 0" +"origin" "-8370.71 -2785.4 628.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -151.236 0" +"origin" "-8384.12 -2778.11 628.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 120.523 0" +"origin" "-8397.78 -2735.22 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 121.152 0" +"origin" "-8408.19 -2741.19 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 121.152 0" +"origin" "-8401.72 -2752.46 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 120.523 0" +"origin" "-8391.31 -2746.49 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 120.523 0" +"origin" "-8384.34 -2758.63 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 94.0521 0" +"origin" "-8381.52 -2776.61 652.36" +"targetname" "func_model_224" +"spawnflags" "4" +"model" "models/hardware/paint_container_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -19.5849 0" +"origin" "-8398.65 -2766.85 580.86" +"targetname" "func_model_297" +"model" "models/containers/styrofoam_lid_dirty.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 119.849 0" +"origin" "-8382.2 -2776.43 604.36" +"targetname" "prop_static_3" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/box_mini_plastic.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1200" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "-0.6507 -21.8879 -90" +"origin" "-8346.46 -2848.61 607.86" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -150.802 0" +"origin" "-8357.11 -2814.72 604.36" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -155.498 0" +"origin" "-8351.13 -2825.12 604.36" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 31.4211 0" +"origin" "-8336.32 -2856.97 604.36" +"targetname" "prop_static_83" +"spawnflags" "4" +"solid" "6" +"model" "models/containers/gas_tank.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.8" +"angles" "0 119.849 180" +"origin" "-8357.91 -2816.33 662.235" +"targetname" "func_model_287" +"model" "models/containers/crate_blue_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 122.844 0" +"origin" "-8359.79 -2822.08 627.36" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 130.405 0" +"origin" "-8357.34 -2822.34 586.36" +"targetname" "prop_static_3" +"solid" "6" +"model" "models/hardware/paint_container_metal.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -83.9714 0" +"origin" "-8336.39 -2847.8 586.36" +"targetname" "prop_static_3" +"solid" "6" +"model" "models/hardware/paint_container_metal.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -150.151 0" +"origin" "-8361.71 -2808.71 586.36" +"targetname" "prop_static_3" +"solid" "6" +"model" "models/hardware/paint_container_metal.mdl" +"luxelsize" "16" +"lightingMethod" "0" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -69.2394 0" +"origin" "-8342.32 -2848.36 627.36" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 28.2831 0" +"origin" "-8322.86 -2875.99 586.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -61.7169 0" +"origin" "-8313.16 -2888.88 586.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -151.717 0" +"origin" "-8304.44 -2908.08 586.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -137.524 0" +"origin" "-8296.97 -2921.09 586.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 31.9871 0" +"origin" "-8321.86 -2877.73 604.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 27.1071 0" +"origin" "-8314.89 -2889.87 604.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -80.9149 0" +"origin" "-8303.94 -2908.95 604.36" +"targetname" "func_model_895" +"spawnflags" "4" +"model" "models/containers/crate_orange_plastic.mdl" +"forcetoenablemotion" "10" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 114.489 0" +"origin" "-8317.92 -2884.58 652.36" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -59.5809 0" +"origin" "-8297.61 -2917.99 628.36" +"targetname" "func_model_225" +"spawnflags" "4" +"model" "models/containers/styrofoam_box_short_dirty.mdl" +"forcetoenablemotion" "10" +"fadedist" "1500" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 20.8021 0" +"origin" "-8300.88 -2922.38 604.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -82.5729 0" +"origin" "-8294.08 -2926.26 604.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -99.5309 0" +"origin" "-8315.2 -2901.47 604.36" +"targetname" "func_model_240" +"spawnflags" "4" +"model" "models/hardware/paint_spraycan_closed.mdl" +"forcetoenablemotion" "5" +"fadedist" "1000" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 119.849 0" +"origin" "-8302.32 -2913.79 652.36" +"targetname" "func_model_218" +"model" "models/containers/styrofoam_box_long_dirty.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "4.26799e-006 -145.253 6.43766e-008" +"origin" "-4448.12 -4514.19 666.181" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "4.26799e-006 64.3103 6.43766e-008" +"origin" "-6668.7 -636.537 545.181" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "-2.53273e-006 -107.57 -1.67088e-006" +"origin" "-6664.16 -937.235 545.181" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "4.26799e-006 32.1242 6.43766e-008" +"origin" "-5892.35 775.76 872.583" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "4.26799e-006 32.1242 6.43766e-008" +"origin" "-5615.16 -881.698 600.583" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 32.8045 2.59711e-006" +"origin" "-8307.97 -1570.87 872.582" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 149.842 0" +"origin" "-8655.45 -2144.56 586" +"targetname" "func_static_1" +"physicsmode" "1" +"model" "models/containers/barrel.mdl" +"forcetoenablemotion" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -135 0" +"origin" "-8631.4 -2171.43 586" +"targetname" "func_static_1" +"physicsmode" "1" +"model" "models/containers/barrel.mdl" +"forcetoenablemotion" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -78.0148 0" +"origin" "-8600.29 -2114.86 586" +"targetname" "func_static_1" +"physicsmode" "1" +"model" "models/containers/barrel.mdl" +"forcetoenablemotion" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -135 0" +"origin" "-8638.48 -2161.53 656" +"targetname" "func_static_1" +"solid" "6" +"model" "models/containers/box_large_plastic.mdl" +"forcetoenablemotion" "1" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -135 0" +"origin" "-8596.76 -2119.81 656" +"targetname" "func_static_1" +"solid" "6" +"model" "models/containers/box_large_plastic.mdl" +"forcetoenablemotion" "1" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -45 0" +"origin" "-8516.15 -2300.83 586" +"targetname" "func_static_1" +"solid" "6" +"model" "models/containers/box_large_plastic.mdl" +"forcetoenablemotion" "1" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -45 0" +"origin" "-8570.59 -2246.38 586" +"targetname" "func_static_1" +"solid" "6" +"model" "models/containers/box_large_plastic.mdl" +"forcetoenablemotion" "1" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "0 -45 0" +"origin" "-8594.63 -2222.34 586" +"targetname" "func_static_1" +"solid" "6" +"model" "models/containers/box_large_plastic.mdl" +"forcetoenablemotion" "1" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "1.40406e-006 59.3433 -2.16305e-006" +"origin" "-7348.92 -477.003 596.582" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.98919" +"angles" "89.9558 0 -36.2377" +"origin" "-7993.88 -1240.76 576.988" +"targetname" "prop_physics_1" +"spawnflags" "4" +"model" "models/containers/can_red_soda.mdl" +"collide_titan" "0" +"collide_sight" "0" +"collide_human" "0" +"collide_bullet" "0" +"collide_ai" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.98919" +"angles" "89.9558 0 -126.238" +"origin" "-7996 -1194.28 577.489" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.876748" +"angles" "89.9558 0 -134.246" +"origin" "-7463.83 -1274.32 588.877" +"targetname" "prop_physics_1" +"spawnflags" "4" +"model" "models/containers/can_red_soda.mdl" +"collide_titan" "0" +"collide_sight" "0" +"collide_human" "0" +"collide_bullet" "0" +"collide_ai" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.876748" +"angles" "89.9558 0 135.754" +"origin" "-7504.36 -1281.92 589.321" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1.19801" +"angles" "89.9558 0 -128.72" +"origin" "-6799.69 -346.635 581.197" +"targetname" "prop_physics_1" +"spawnflags" "4" +"model" "models/containers/can_red_soda.mdl" +"collide_titan" "0" +"collide_sight" "0" +"collide_human" "0" +"collide_bullet" "0" +"collide_ai" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1.19801" +"angles" "89.9558 0 141.28" +"origin" "-6855.82 -351.639 581.804" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.892666" +"angles" "89.9558 0 94.2158" +"origin" "-7214.96 -435.646 576.893" +"targetname" "prop_physics_1" +"spawnflags" "4" +"model" "models/containers/can_red_soda.mdl" +"collide_titan" "0" +"collide_sight" "0" +"collide_human" "0" +"collide_bullet" "0" +"collide_ai" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "0.892666" +"angles" "89.9558 0 4.2156" +"origin" "-7181.8 -461.404 577.346" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "89.9558 0 -70.039" +"origin" "-6909.78 -873.816 524.998" +"targetname" "prop_physics_1" +"spawnflags" "4" +"model" "models/containers/can_red_soda.mdl" +"collide_titan" "0" +"collide_sight" "0" +"collide_human" "0" +"collide_bullet" "0" +"collide_ai" "0" +"classname" "prop_physics" +} +{ +"spawnflags" "1" +"skin" "0" +"shadowcastdist" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"pressuredelay" "0" +"physicsmode" "0" +"physdamagescale" "0.1" +"PerformanceMode" "0" +"nodamageforces" "0" +"minhealthdmg" "0" +"mingpulevel" "0" +"mincpulevel" "0" +"maxgpulevel" "0" +"maxcpulevel" "0" +"massScale" "0" +"inertiaScale" "1.0" +"forcetoenablemotion" "0" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"Damagetype" "0" +"damagetoenablemotion" "0" +"allowfunnel" "1" +"scale" "1" +"angles" "89.9558 0 -160.039" +"origin" "-6937.7 -835.964 525.505" +"targetname" "func_static_1428" +"model" "models/containers/can_blue_soda.mdl" +"classname" "prop_physics" +} +{ +"editorclass" "trigger_fw_territory" +"origin" "-6879.19 -581.853 796" +"wait" "0" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "1" +"StartDisabled" "0" +"spawnflags" "64" +"triggerFilterUseNew" "1" +"link_guid" "25060c9d8d9" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 -223.44238" +"*trigger_brush_0_plane_1" "1 0 0 2033.6353" +"*trigger_brush_0_plane_2" "0 -1 0 -114.55118" +"*trigger_brush_0_plane_3" "0 1 0 2275.4695" +"*trigger_brush_0_plane_4" "0 0 -1 296" +"*trigger_brush_0_plane_5" "0 0 1 296" +"*trigger_brush_0_plane_6" "0.70710683 0.70710671 0 2026.9972" +"*trigger_brush_0_plane_7" "0.99972111 -0.023614977 0 2013.3975" +"*trigger_brush_0_plane_8" "-0.70710683 -0.70710677 -0 -1506.9976" +"*trigger_brush_0_plane_9" "-0.70710701 0.70710653 0 1191.0017" +"*trigger_brush_0_plane_10" "0.70710689 0.70710677 0 2026.9973" +"*trigger_brush_0_plane_11" "0.99972117 -0.023614977 0 2013.3977" +"*trigger_brush_0_plane_12" "-0.70710683 -0.70710683 0 -1506.9976" +"*trigger_brush_0_plane_13" "-0.70710707 0.70710659 0 1191.0018" +"*trigger_brush_0_plane_14" "0.92833394 0.37174723 0 2197.5474" +"*trigger_brush_0_plane_15" "0.37174726 -0.92833406 0 643.34802" +"*trigger_brush_1_plane_0" "-1 -0 -0 -591.1377" +"*trigger_brush_1_plane_1" "1 0 0 2361.7329" +"*trigger_brush_1_plane_2" "-0 -1 -0 -889.54016" +"*trigger_brush_1_plane_3" "0 1 0 2660.1355" +"*trigger_brush_1_plane_4" "0 0 -1 296" +"*trigger_brush_1_plane_5" "0 0 1 296" +"*trigger_brush_1_plane_6" "-0.70710683 -0.70710671 -0 -2026.9973" +"*trigger_brush_1_plane_7" "0.70710683 -0.70710671 0 768.99762" +"*trigger_brush_1_plane_8" "0.70710677 0.70710677 0 2570.9971" +"*trigger_brush_1_plane_9" "-0.70710677 0.70710677 0 1191.0024" +"*trigger_brush_1_plane_10" "0.70710689 -0.70710671 0 768.99786" +"*trigger_brush_1_plane_11" "0.70710683 0.70710683 0 2570.9976" +"*trigger_brush_1_plane_12" "-0.70710665 0.70710689 0 1191.0029" +"*trigger_brush_2_plane_0" "-1 -0 -0 1043.6934" +"*trigger_brush_2_plane_1" "1 -0 -0 -446.89502" +"*trigger_brush_2_plane_2" "0 -1 0 2660.1357" +"*trigger_brush_2_plane_3" "0 1 0 -2094.4504" +"*trigger_brush_2_plane_4" "0 0 -1 296" +"*trigger_brush_2_plane_5" "0 0 1 296" +"*trigger_brush_2_plane_6" "-0.26079348 -0.96539462 -0 2684.6282" +"*trigger_brush_2_plane_7" "0.9750666 0.22191244 -0 -1026.0696" +"*trigger_brush_2_plane_8" "0.35897923 0.93334556 0 -2293.9731" +"*trigger_brush_2_plane_9" "-0.97132921 0.23773833 0 419.68182" +"*trigger_brush_2_plane_10" "-0.26079351 -0.96539462 -0 2684.6282" +"*trigger_brush_2_plane_11" "0.9750666 0.22191243 0 -1026.0696" +"*trigger_brush_2_plane_12" "-0.97132933 0.23773836 0 419.68188" +"*trigger_brush_2_plane_13" "-0.86105388 -0.50851375 0 2169.4092" +"*trigger_brush_2_plane_14" "0.69279945 -0.72113037 -0 1608.696" +"*trigger_brush_2_plane_15" "0.75594574 0.65463442 0 -1881.3237" +"*trigger_brush_2_plane_16" "-0.46336862 0.88616568 0 -1418.2866" +"*trigger_brush_3_plane_0" "-1 0 0 2361.7397" +"*trigger_brush_3_plane_1" "1 0 0 1920.4985" +"*trigger_brush_3_plane_2" "0 -1 0 2250.0139" +"*trigger_brush_3_plane_3" "0 1 0 1907.7739" +"*trigger_brush_3_plane_4" "0 0 -1 296" +"*trigger_brush_3_plane_5" "0 0 1 296" +"*trigger_brush_3_plane_6" "-0.35897923 -0.93334556 -0 2293.9731" +"*trigger_brush_3_plane_7" "0.70710677 0.70710677 -0 1506.9974" +"*trigger_brush_3_plane_8" "0.70710677 -0.70710683 0 1208.9976" +"*trigger_brush_3_plane_9" "-0.70710689 -0.70710665 0 2149.0024" +"*trigger_brush_3_plane_10" "-0.70710683 0.70710677 0 1191.0022" +"*trigger_brush_3_plane_11" "0.70710683 0.70710683 0 1506.9976" +"*trigger_brush_3_plane_12" "0.70710671 -0.70710683 0 1208.9976" +"*trigger_brush_3_plane_13" "-0.70710695 -0.70710671 0 2149.0027" +"*trigger_brush_3_plane_14" "-0.70710689 0.70710677 0 1191.0023" +"*trigger_brush_3_plane_15" "0.2075914 -0.97821563 0 2088.8511" +"*trigger_bounds_mins" "-2361.7397 -2660.1357 -296" +"*trigger_bounds_maxs" "2361.7329 2660.1355 296" +} +{ +"model" "*1" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-7273.76 -262.241 830" +"startDisconnected" "0" +"link_guid" "250c09f3be6" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_team_tower" +"teamnumber" "3" +"spawnflags" "0" +"model" "models/props/generator_coop/generator_coop_medium.mdl" +"scale" "1" +"angles" "0 45.1013 0" +"origin" "-7274.49 -264.029 640" +"radius" "1" +"link_to_guid_1" "250c09f3be6" +"link_to_guid_0" "25060c9d8d9" +"link_guid" "250f840be54" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "16.3574 55.7916 -1.02973e-015" +"origin" "-9592.83 -5363.1 1083.69" +"targetname" "spec_cam2" +"target" "escape_node2" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 32.194 0" +"origin" "-9424.58 -4026.32 688" +"targetname" "escape_node2" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 90 0" +"origin" "-640 1856 704" +"targetname" "escape_node3" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0.0015841 -78.187 0.31054" +"origin" "-1510.63 2845.77 1260.03" +"targetname" "spec_cam3" +"target" "escape_node3" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 129.018 0" +"origin" "-1449.94 395.183 680" +"targetname" "escape_node1" +"classname" "info_target" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 -50.606 0" +"origin" "-2105.68 1100.57 1024" +"targetname" "spec_cam1" +"target" "escape_node1" +"classname" "info_target" +} +{ +"origin" "-8108 -3596 784" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "nonphaseshift" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "3" +"triggerFilterUseNew" "1" +"targetname" "trigger_hardpoint_A1" +"classname" "trigger_capture_point" +"*trigger_brush_0_plane_0" "-1 0 0 948" +"*trigger_brush_0_plane_1" "1 0 0 948" +"*trigger_brush_0_plane_2" "0 -1 0 764" +"*trigger_brush_0_plane_3" "0 1 0 764" +"*trigger_brush_0_plane_4" "-0 0 -1 304" +"*trigger_brush_0_plane_5" "-0 -0 1 304" +"*trigger_brush_0_plane_6" "-0.86514002 -0.50153041 -0 757.96295" +"*trigger_brush_0_plane_7" "0.95562351 -0.29459071 0 817.55389" +"*trigger_brush_0_plane_8" "0.26159054 0.96517897 0 537.5415" +"*trigger_brush_0_plane_9" "-0.25997347 -0.96561575 -0 576.54688" +"*trigger_brush_0_plane_10" "-0.96106929 0.27630743 0 945.35583" +"*trigger_brush_0_plane_11" "-0.86513996 -0.50153041 0 757.96295" +"*trigger_brush_0_plane_12" "-0.2599735 -0.96561587 -0 576.54694" +"*trigger_brush_0_plane_13" "-0.96106935 0.27630743 0 945.3559" +"*trigger_brush_0_plane_14" "0.48327103 -0.87547076 0 968.48773" +"*trigger_brush_0_plane_15" "0.87587523 0.48253766 0 975.091" +"*trigger_brush_0_plane_16" "-0.49087024 0.87123269 0 1040.6466" +"*trigger_bounds_mins" "-948 -764 -304" +"*trigger_bounds_maxs" "948 763.99994 304" +} +{ +"origin" "-1056 184 832" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "nonphaseshift" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "3" +"triggerFilterUseNew" "1" +"targetname" "trigger_hardpoint_C1" +"classname" "trigger_capture_point" +"*trigger_brush_0_plane_0" "-1 -0 -0 704" +"*trigger_brush_0_plane_1" "1 -0 -0 704" +"*trigger_brush_0_plane_2" "-0 -1 -0 824" +"*trigger_brush_0_plane_3" "0 1 0 824" +"*trigger_brush_0_plane_4" "0 0 -1 384" +"*trigger_brush_0_plane_5" "0 0 1 384" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1080.4592" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 1080.4592" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 1080.4592" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1080.4592" +"*trigger_bounds_mins" "-704 -824 -384" +"*trigger_bounds_maxs" "704 824 384" +} +{ +"origin" "-4552 -1864 768" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "nonphaseshift" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "3" +"triggerFilterUseNew" "1" +"targetname" "trigger_hardpoint_B1" +"classname" "trigger_capture_point" +"*trigger_brush_0_plane_0" "-1 -0 -0 376" +"*trigger_brush_0_plane_1" "1 0 0 376" +"*trigger_brush_0_plane_2" "-0 -1 -0 520" +"*trigger_brush_0_plane_3" "0 1 0 520" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "0 -0.0033803894 -0.99999428 94.241646" +"*trigger_brush_0_plane_7" "-0.70710677 0.70710677 0 633.56763" +"*trigger_brush_0_plane_8" "-0.70710677 -0.70710677 -0 633.56763" +"*trigger_brush_0_plane_9" "0.70710677 -0.70710677 0 633.56763" +"*trigger_brush_0_plane_10" "0.70710677 0.70710677 0 633.56763" +"*trigger_bounds_mins" "-376 -520 -96" +"*trigger_bounds_maxs" "376 520 96" +} +{ +"editorclass" "info_bomb_mode_pilot_defuse_point" +"spawnflags" "0" +"origin" "-6258.77 -506.916 588" +"teamnumber" "3" +"classname" "info_target" +} +{ +"editorclass" "info_bomb_mode_pilot_defuse_point" +"spawnflags" "0" +"origin" "-16 -2528 528" +"teamnumber" "2" +"classname" "info_target" +} +{ +"editorclass" "info_bomb_mode_bomb" +"spawnflags" "0" +"origin" "-3733.81 -73.9383 553.108" +"classname" "info_target" +} +{ +"editorclass" "info_bomb_mode_bomb" +"spawnflags" "0" +"origin" "-4263.48 -4642.26 652.991" +"classname" "info_target" +} +{ +"editorclass" "info_bomb_mode_base" +"spawnflags" "0" +"origin" "-759.944 -2094.34 519.999" +"teamnumber" "2" +"classname" "info_target" +} +{ +"editorclass" "info_bomb_mode_base" +"spawnflags" "0" +"origin" "-6937.51 -1231.18 523.996" +"teamnumber" "3" +"classname" "info_target" +} +{ +"scale" "1" +"angles" "0 90 0" +"origin" "-11520 10880 10536" +"script_name" "menu_camera_target" +"classname" "info_target_clientside" +} +{ +"scale" "1" +"angles" "0 -90 0" +"origin" "-11520 11136 10496" +"script_name" "menu_scene_ref" +"classname" "info_target_clientside" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-6576 -6864 -104" +"targetname" "at_hardpoint_blackbox" +"link_to_guid_0" "27528a1afab" +"link_guid" "2758215f435" +"hardpointGroup" "p" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"origin" "-6576 -6864 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "27528a1afab" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 128" +"*trigger_brush_0_plane_1" "1 -0 -0 128" +"*trigger_brush_0_plane_2" "-0 -1 -0 128" +"*trigger_brush_0_plane_3" "0 1 0 128" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933" +"*trigger_bounds_mins" "-128 -128 -128" +"*trigger_bounds_maxs" "128 128 128" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-6256 -6864 -104" +"targetname" "at_hardpoint_blackbox1" +"link_to_guid_0" "2759b6c10ad" +"link_guid" "275ca0c34a7" +"hardpointGroup" "p" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"origin" "-6256 -6864 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "2759b6c10ad" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 128" +"*trigger_brush_0_plane_1" "1 -0 -0 128" +"*trigger_brush_0_plane_2" "-0 -1 -0 128" +"*trigger_brush_0_plane_3" "0 1 0 128" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933" +"*trigger_bounds_mins" "-128 -128 -128" +"*trigger_bounds_maxs" "128 128 128" +} +{ +"origin" "-6256 -7184 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "275da28a532" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 128" +"*trigger_brush_0_plane_1" "1 -0 -0 128" +"*trigger_brush_0_plane_2" "-0 -1 -0 128" +"*trigger_brush_0_plane_3" "0 1 0 128" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933" +"*trigger_bounds_mins" "-128 -128 -128" +"*trigger_bounds_maxs" "128 128 128" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-6256 -7184 -104" +"targetname" "at_hardpoint_blackbox2" +"link_to_guid_0" "275da28a532" +"link_guid" "275edb69c4d" +"hardpointGroup" "p" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-6576 -7184 -104" +"targetname" "at_hardpoint_blackbox3" +"link_to_guid_0" "275cd46eda5" +"link_guid" "2751884002b" +"hardpointGroup" "p" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"origin" "-6576 -7184 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "275cd46eda5" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 128" +"*trigger_brush_0_plane_1" "1 -0 -0 128" +"*trigger_brush_0_plane_2" "-0 -1 -0 128" +"*trigger_brush_0_plane_3" "0 1 0 128" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 181.01933" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 181.01933" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 181.01933" +"*trigger_bounds_mins" "-128 -128 -128" +"*trigger_bounds_maxs" "128 128 128" +} +{ +"origin" "-5840 -6864 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "275e36af485" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 192" +"*trigger_brush_0_plane_1" "1 -0 0 192" +"*trigger_brush_0_plane_2" "-0 -1 -0 192" +"*trigger_brush_0_plane_3" "0 1 0 192" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899" +"*trigger_bounds_mins" "-192 -192 -128" +"*trigger_bounds_maxs" "192 192 128" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-5840 -6864 -104" +"targetname" "at_hardpoint_blackbox4" +"link_to_guid_0" "275e36af485" +"link_guid" "275fa2f4f04" +"hardpointGroup" "s" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-5392 -6864 -104" +"targetname" "at_hardpoint_blackbox5" +"link_to_guid_0" "275ddde673b" +"link_guid" "2753df97a78" +"hardpointGroup" "s" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"origin" "-5392 -6864 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "275ddde673b" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 192" +"*trigger_brush_0_plane_1" "1 -0 0 192" +"*trigger_brush_0_plane_2" "-0 -1 -0 192" +"*trigger_brush_0_plane_3" "0 1 0 192" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899" +"*trigger_bounds_mins" "-192 -192 -128" +"*trigger_bounds_maxs" "192 192 128" +} +{ +"origin" "-5392 -7312 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "275ac23c51f" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 192" +"*trigger_brush_0_plane_1" "1 -0 0 192" +"*trigger_brush_0_plane_2" "-0 -1 -0 192" +"*trigger_brush_0_plane_3" "0 1 0 192" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899" +"*trigger_bounds_mins" "-192 -192 -128" +"*trigger_bounds_maxs" "192 192 128" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-5392 -7312 -104" +"targetname" "at_hardpoint_blackbox6" +"link_to_guid_0" "275ac23c51f" +"link_guid" "275cbcacf82" +"hardpointGroup" "s" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"model" "models/communication/terminal_com_station_tall.mdl" +"hardpointName" "random" +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"origin" "-5840 -7312 -104" +"targetname" "at_hardpoint_blackbox7" +"link_to_guid_0" "2759e570221" +"link_guid" "27590ba1b72" +"hardpointGroup" "s" +"gamemode_sur" "0" +"gamemode_lh" "0" +"gamemode_cp" "0" +"gamemode_at" "1" +"classname" "info_hardpoint" +} +{ +"origin" "-5840 -7312 -40" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"triggerFilterUseNew" "1" +"link_guid" "2759e570221" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 192" +"*trigger_brush_0_plane_1" "1 -0 0 192" +"*trigger_brush_0_plane_2" "-0 -1 -0 192" +"*trigger_brush_0_plane_3" "0 1 0 192" +"*trigger_brush_0_plane_4" "0 0 -1 128" +"*trigger_brush_0_plane_5" "-0 -0 1 128" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 271.52899" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 271.52899" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 271.52899" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 271.52899" +"*trigger_bounds_mins" "-192 -192 -128" +"*trigger_bounds_maxs" "192 192 128" +} +{ +"origin" "-5009.8 -4210.14 671.526" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 21.77832" +"*trigger_brush_0_plane_1" "1 0 0 21.771973" +"*trigger_brush_0_plane_2" "0 -1 0 20.042969" +"*trigger_brush_0_plane_3" "0 1 0 20.052246" +"*trigger_brush_0_plane_4" "0.00016665296 6.251569e-005 -1 18.119028" +"*trigger_brush_0_plane_5" "-0.00016378085 -5.835561e-005 1 18.118982" +"*trigger_brush_0_plane_6" "0.17627637 -0.98434073 -4.0189021e-005 19.384438" +"*trigger_brush_0_plane_7" "0.98433661 0.17629911 0.00015777189 20.173597" +"*trigger_brush_0_plane_8" "-0.17627142 0.98434162 2.4551438e-005 19.05201" +"*trigger_brush_0_plane_9" "-0.98956627 0.14407825 -0.00013696289 20.649738" +"*trigger_brush_0_plane_10" "0.82067442 -0.57139605 9.4199539e-005 21.93189" +"*trigger_brush_0_plane_11" "-0.57138246 -0.8206839 -0.0001399785 17.561274" +"*trigger_brush_0_plane_12" "-0.82069337 0.57136887 -0.00010190317 20.345854" +"*trigger_brush_0_plane_13" "0.57139683 0.82067388 0.00014767883 18.677172" +"*trigger_brush_0_plane_14" "0.17627637 -0.98434073 0 19.385166" +"*trigger_brush_0_plane_15" "0.17627141 -0.98434162 0 19.383736" +"*trigger_brush_0_plane_16" "0.98433489 0.17630903 0 20.170713" +"*trigger_brush_0_plane_17" "0.98433667 0.17629911 -0 20.176456" +"*trigger_brush_0_plane_18" "-0.17626645 0.98434252 0 19.052406" +"*trigger_brush_0_plane_19" "-0.17627141 0.98434162 0 19.051565" +"*trigger_brush_0_plane_20" "-0.98956412 0.14409372 0 20.647114" +"*trigger_brush_0_plane_21" "-0.98956639 0.14407825 0 20.652224" +"*trigger_brush_0_plane_22" "0.8206687 -0.57140434 0 21.930241" +"*trigger_brush_0_plane_23" "0.82067454 -0.57139611 0 21.933601" +"*trigger_brush_0_plane_24" "-0.57138246 -0.82068402 -0 17.563808" +"*trigger_brush_0_plane_25" "-0.82070088 0.57135814 0 20.343922" +"*trigger_brush_0_plane_26" "-0.82069343 0.57136881 0 20.3477" +"*trigger_brush_0_plane_27" "0.57139134 0.82067776 -0 18.679781" +"*trigger_brush_0_plane_28" "0.57140237 0.82067001 0 18.674438" +"*trigger_brush_0_plane_29" "-0.91751391 -0.39770368 -0.00016278407 22.460146" +"*trigger_bounds_mins" "-21.77832 -20.042969 -18.123047" +"*trigger_bounds_maxs" "21.771973 20.052345 18.12262" +} +{ +"origin" "-4979.47 -4239.79 669.121" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 22.675781" +"*trigger_brush_0_plane_1" "1 0 0 22.670898" +"*trigger_brush_0_plane_2" "0 -1 0 21.022461" +"*trigger_brush_0_plane_3" "0 1 0 21.017578" +"*trigger_brush_0_plane_4" "0 0 -1 19.994141" +"*trigger_brush_0_plane_5" "0 0 1 19.994568" +"*trigger_brush_0_plane_6" "-0.79023558 0.61255193 -0.017547544 19.368935" +"*trigger_brush_0_plane_7" "-0.61217505 -0.7877965 0.067958973 19.915857" +"*trigger_brush_0_plane_8" "0.79024911 -0.61253446 0.017546039 19.839951" +"*trigger_brush_0_plane_9" "0.83065367 0.55366367 -0.058915287 21.821468" +"*trigger_brush_0_plane_10" "0.0277991 0.064444266 0.99753404 18.568161" +"*trigger_brush_0_plane_11" "-0.12590383 0.99019819 -0.060462583 18.096422" +"*trigger_brush_0_plane_12" "0.9916538 0.12390357 -0.035645492 21.509848" +"*trigger_brush_0_plane_13" "-0.027795117 -0.064435109 -0.99753475 18.398573" +"*trigger_brush_0_plane_14" "0.12591469 -0.99019766 0.060449135 18.870047" +"*trigger_brush_0_plane_15" "-0.99164891 -0.12394232 0.035647802 21.617529" +"*trigger_brush_0_plane_16" "-0.11031668 0 -0.99389642 20.323952" +"*trigger_brush_0_plane_17" "0 0.085939594 0.99630034 19.237625" +"*trigger_brush_0_plane_18" "-0.78962427 0.61359054 0 19.692518" +"*trigger_brush_0_plane_19" "-0.99961174 0 0.027862126 22.167356" +"*trigger_brush_0_plane_20" "0 0.028639561 0.99958974 19.452505" +"*trigger_brush_0_plane_21" "-0.02220404 0 0.99975342 20.130083" +"*trigger_brush_0_plane_22" "0 -0.99792051 0.064456455 19.89064" +"*trigger_brush_0_plane_23" "-0.61264962 -0.79035473 0 21.120331" +"*trigger_brush_0_plane_24" "0 -0.085925035 -0.99630165 19.084589" +"*trigger_brush_0_plane_25" "0.78964102 -0.61356914 0 20.160496" +"*trigger_brush_0_plane_26" "0.11033292 0 0.9938947 20.542135" +"*trigger_brush_0_plane_27" "0.99961174 0 -0.027862221 22.156351" +"*trigger_brush_0_plane_28" "0 -0.045882083 -0.99894691 19.118061" +"*trigger_brush_0_plane_29" "0.068414442 0 -0.99765694 20.797762" +"*trigger_brush_0_plane_30" "0.83084786 0.5564996 0 22.878237" +"*trigger_brush_0_plane_31" "0 0.99791962 -0.064470463 19.885517" +"*trigger_brush_0_plane_32" "-0 0.060945805 0.99814111 19.166637" +"*trigger_brush_0_plane_33" "-0.1239908 0.99228328 0 19.186661" +"*trigger_brush_0_plane_34" "0.99201429 0.12612571 -0 22.159206" +"*trigger_brush_0_plane_35" "0.035918012 -0 0.99935478 19.754478" +"*trigger_brush_0_plane_36" "-0.035910171 0 -0.99935496 19.534838" +"*trigger_brush_0_plane_37" "0 -0.060938403 -0.99814153 18.994009" +"*trigger_brush_0_plane_38" "-0.99200934 -0.12616478 -0 22.260799" +"*trigger_brush_0_plane_39" "0.12399895 -0.99228233 0 19.948387" +"*trigger_brush_0_plane_40" "0.41424116 0.90745842 -0.070168488 23.463116" +"*trigger_bounds_mins" "-22.675793 -21.022488 -19.994152" +"*trigger_bounds_maxs" "22.67091 21.017591 19.994577" +} +{ +"origin" "-6630.51 -3874.89 545.789" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 23.161621" +"*trigger_brush_0_plane_1" "1 0 0 23.152832" +"*trigger_brush_0_plane_2" "0 -1 0 18.999268" +"*trigger_brush_0_plane_3" "0 1 0 18.994873" +"*trigger_brush_0_plane_4" "0 0 -1 20.728516" +"*trigger_brush_0_plane_5" "0 0 1 20.728699" +"*trigger_brush_0_plane_6" "0.072347663 -0.99576795 -0.056674022 18.008764" +"*trigger_brush_0_plane_7" "0.97601706 0.082389019 -0.20150122 19.375139" +"*trigger_brush_0_plane_8" "-0.07234402 0.99576789 0.05668062 17.779463" +"*trigger_brush_0_plane_9" "-0.94880831 0.23674069 0.20908532 18.678394" +"*trigger_brush_0_plane_10" "0.20531863 -0.040751129 0.97784638 17.118582" +"*trigger_brush_0_plane_11" "-0.63899124 -0.76236641 0.10240906 15.904586" +"*trigger_brush_0_plane_12" "-0.74129868 0.64586955 0.1825617 18.554268" +"*trigger_brush_0_plane_13" "-0.20530531 0.040738355 -0.97784972 16.622938" +"*trigger_brush_0_plane_14" "0.63898653 0.76237053 -0.10240788 17.836845" +"*trigger_brush_0_plane_15" "0.74129188 -0.6458807 -0.18254977 20.810663" +"*trigger_brush_0_plane_16" "-0.20217523 -0 -0.97934932 17.345173" +"*trigger_brush_0_plane_17" "0 -0.99913335 -0.041623548 18.290937" +"*trigger_brush_0_plane_18" "0.084106304 -0.99645674 0 18.969072" +"*trigger_brush_0_plane_19" "0.97865915 0 -0.20549038 20.138351" +"*trigger_brush_0_plane_20" "0.99737042 0.072472855 0 22.431414" +"*trigger_brush_0_plane_21" "0 0.05682518 -0.99838412 20.255196" +"*trigger_brush_0_plane_22" "-0.084103674 0.99645692 0 18.711605" +"*trigger_brush_0_plane_23" "0 0.99913311 0.041630547 18.28121" +"*trigger_brush_0_plane_24" "0.20219001 -0 0.97934633 17.831245" +"*trigger_brush_0_plane_25" "-0.97865975 0 0.20548709 20.146931" +"*trigger_brush_0_plane_26" "-0.9707675 0.24002215 0 21.741335" +"*trigger_brush_0_plane_27" "0 -0.27201349 0.96229345 21.163248" +"*trigger_brush_0_plane_28" "-0 0.13312577 0.99109912 21.450081" +"*trigger_brush_0_plane_29" "0.15823317 0 0.98740178 18.252949" +"*trigger_brush_0_plane_30" "0.23913115 0 0.97098726 18.046215" +"*trigger_brush_0_plane_31" "0.65689623 0.75398088 -0 19.52286" +"*trigger_brush_0_plane_32" "0.7663759 -0.6423924 0 23.598701" +"*trigger_brush_0_plane_33" "-0.23910885 -0 -0.97099274 17.447922" +"*trigger_brush_0_plane_34" "-0.65690094 -0.75397676 0 17.549532" +"*trigger_brush_0_plane_35" "-0.76638836 0.64237756 0 21.289915" +"*trigger_brush_0_plane_36" "-0 -0.13313271 -0.99109828 21.574442" +"*trigger_brush_0_plane_37" "-0.15824135 0 -0.98740047 17.899864" +"*trigger_brush_0_plane_38" "0 0.27198976 -0.96230012 21.282295" +"*trigger_brush_0_plane_39" "-0.93328655 -0.30895549 0.18309207 20.327454" +"*trigger_bounds_mins" "-23.161669 -18.999268 -20.728502" +"*trigger_bounds_maxs" "23.152775 18.994848 20.728708" +} +{ +"origin" "-6752.38 -3850.29 591.335" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 29.717285" +"*trigger_brush_0_plane_1" "1 0 0 29.714844" +"*trigger_brush_0_plane_2" "0 -1 0 27.994873" +"*trigger_brush_0_plane_3" "0 1 0 27.990967" +"*trigger_brush_0_plane_4" "0 0 -1 28.347107" +"*trigger_brush_0_plane_5" "0 0 1 28.34668" +"*trigger_brush_0_plane_6" "-0.35651442 0.88672775 0.29429817 22.655819" +"*trigger_brush_0_plane_7" "-0.90868795 -0.40231937 0.11146893 22.658901" +"*trigger_brush_0_plane_8" "0.35651633 -0.88672686 -0.29429838 22.658344" +"*trigger_brush_0_plane_9" "0.97479039 0.10128918 -0.19880684 25.473263" +"*trigger_brush_0_plane_10" "0.21724674 -0.22769055 0.9491896 21.361078" +"*trigger_brush_0_plane_11" "0.39044589 0.91150326 0.129282 21.358908" +"*trigger_brush_0_plane_12" "0.89463139 -0.34251106 -0.28691611 24.921045" +"*trigger_brush_0_plane_13" "-0.21725486 0.22769006 -0.94918787 21.361015" +"*trigger_brush_0_plane_14" "-0.3904449 -0.9115029 -0.1292876 21.363583" +"*trigger_brush_0_plane_15" "-0.89462113 0.3425425 0.2869105 24.921858" +"*trigger_brush_0_plane_16" "-0.40486702 0.9143756 0 27.965538" +"*trigger_brush_0_plane_17" "0 0.97241479 0.23325837 23.848343" +"*trigger_brush_0_plane_18" "0.12175279 -0 0.99256045 26.3246" +"*trigger_brush_0_plane_19" "-0.92782265 -0.37302157 0 24.995735" +"*trigger_brush_0_plane_20" "-0.97479403 0 0.22310717 25.834534" +"*trigger_brush_0_plane_21" "0 -0.31499946 0.94909179 26.044333" +"*trigger_brush_0_plane_22" "-0.12176256 -0 -0.99255919 26.325142" +"*trigger_brush_0_plane_23" "0 -0.97241485 -0.23325837 23.8522" +"*trigger_brush_0_plane_24" "0.40485916 -0.91437912 0 27.967974" +"*trigger_brush_0_plane_25" "0.97479415 0 -0.22310589 25.83219" +"*trigger_brush_0_plane_26" "0.99862283 0.052462563 0 29.311333" +"*trigger_brush_0_plane_27" "0 0.2442729 -0.96970654 26.390877" +"*trigger_brush_0_plane_28" "-0.35755318 -0.93389279 0 24.051094" +"*trigger_brush_0_plane_29" "0 -0.14042859 0.99009079 26.638908" +"*trigger_brush_0_plane_30" "0.30539426 0 0.95222604 25.900644" +"*trigger_brush_0_plane_31" "0.91922188 -0.39373985 0 30.03582" +"*trigger_brush_0_plane_32" "0.35755575 0.93389171 -0 24.04635" +"*trigger_brush_0_plane_33" "0 0.14043257 -0.99009031 26.638762" +"*trigger_brush_0_plane_34" "-0.3053968 0 -0.95222515 25.901608" +"*trigger_brush_0_plane_35" "-0.91921216 0.39376283 0 30.036396" +"*trigger_brush_0_plane_36" "0.80246222 0.59530187 -0.040865496 27.527145" +"*trigger_bounds_mins" "-29.717148 -27.994802 -28.347107" +"*trigger_bounds_maxs" "29.714777 27.990847 28.34668" +} +{ +"origin" "-6863.43 -3565.73 649.505" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 22.392578" +"*trigger_brush_0_plane_1" "1 0 0 22.38623" +"*trigger_brush_0_plane_2" "0 -1 0 23.695801" +"*trigger_brush_0_plane_3" "0 1 0 23.701904" +"*trigger_brush_0_plane_4" "0 0 -1 22.756958" +"*trigger_brush_0_plane_5" "0 0 1 22.756592" +"*trigger_brush_0_plane_6" "-0.79363966 0.59335631 0.13440391 19.363192" +"*trigger_brush_0_plane_7" "-0.60828322 -0.76986647 -0.19312474 19.924692" +"*trigger_brush_0_plane_8" "0.79365343 -0.59333885 -0.13439952 19.84547" +"*trigger_brush_0_plane_9" "0.82803267 0.54273474 0.14071582 21.814674" +"*trigger_brush_0_plane_10" "-0.011122293 -0.23502477 0.97192574 18.448565" +"*trigger_brush_0_plane_11" "-0.13108115 0.96393937 0.23160015 18.086199" +"*trigger_brush_0_plane_12" "0.99130905 0.12482663 0.041529257 21.507544" +"*trigger_brush_0_plane_13" "0.011131484 0.23503047 -0.97192425 18.517982" +"*trigger_brush_0_plane_14" "0.13107763 -0.96394128 -0.23159409 18.880201" +"*trigger_brush_0_plane_15" "-0.99130905 -0.12482665 -0.04152919 21.619696" +"*trigger_brush_0_plane_16" "-0.78463531 0.61995769 0 21.717289" +"*trigger_brush_0_plane_17" "-0.3026042 0 0.9531163 24.282679" +"*trigger_brush_0_plane_18" "0 0.22091037 -0.97529411 18.879345" +"*trigger_brush_0_plane_19" "-0.16696684 -0 -0.98596251 23.528826" +"*trigger_brush_0_plane_20" "-0.59878683 -0.80090845 -0 23.1381" +"*trigger_brush_0_plane_21" "-0 -0.97198671 -0.23503631 19.936106" +"*trigger_brush_0_plane_22" "0.78464919 -0.61994004 0 22.185463" +"*trigger_brush_0_plane_23" "0.30263686 0 -0.95310599 24.525101" +"*trigger_brush_0_plane_24" "0.31883568 -0 0.94781005 25.59812" +"*trigger_brush_0_plane_25" "-0 0.97198439 0.23504555 19.941891" +"*trigger_brush_0_plane_26" "0.82108754 0.57080221 -0 24.242928" +"*trigger_brush_0_plane_27" "-0.99087983 -0.13474874 0 22.387548" +"*trigger_brush_0_plane_28" "-0.041856475 0 0.99912369 22.207701" +"*trigger_brush_0_plane_29" "0.12492958 -0.99216563 0 22.642241" +"*trigger_brush_0_plane_30" "-0.12493286 0.99216515 0 21.886036" +"*trigger_brush_0_plane_31" "0.99087977 0.13474873 -0 22.278454" +"*trigger_brush_0_plane_32" "0.04186533 0 -0.99912328 22.463369" +"*trigger_brush_0_plane_33" "0.40965781 0.88560075 0.21884184 23.453144" +"*trigger_bounds_mins" "-22.392578 -23.695826 -22.756931" +"*trigger_bounds_maxs" "22.38623 23.701887 22.756578" +} +{ +"origin" "-5083.35 -3813.92 658.865" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_1_easy" "1" +"damagemodel" "0" +"damagecap" "20" +"triggerFilterUseNew" "1" +"mobility_2_normal" "0" +"damageSourceName" "burn" +"damage" "10" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 22.353027" +"*trigger_brush_0_plane_1" "1 0 0 22.356445" +"*trigger_brush_0_plane_2" "0 -1 0 20.129639" +"*trigger_brush_0_plane_3" "0 1 0 20.134277" +"*trigger_brush_0_plane_4" "0 0 -1 20.002502" +"*trigger_brush_0_plane_5" "0 0 1 20.002197" +"*trigger_brush_0_plane_6" "0.092027478 -0.99034268 -0.10369346 18.011898" +"*trigger_brush_0_plane_7" "0.98560303 0.075766191 0.15114939 19.300398" +"*trigger_brush_0_plane_8" "-0.092014894 0.99034363 0.10369541 17.776217" +"*trigger_brush_0_plane_9" "-0.96412814 0.24129748 -0.11060037 18.7479" +"*trigger_brush_0_plane_10" "-0.14183062 -0.11611505 0.98305714 16.76276" +"*trigger_brush_0_plane_11" "-0.63186896 -0.75383621 -0.18020141 15.959561" +"*trigger_brush_0_plane_12" "-0.76200849 0.64669693 -0.03355841 18.604645" +"*trigger_brush_0_plane_13" "0.14184251 0.11611181 -0.98305583 16.9785" +"*trigger_brush_0_plane_14" "0.63186169 0.75384116 0.18020649 17.781702" +"*trigger_brush_0_plane_15" "0.76199979 -0.6467073 0.033555906 20.760326" +"*trigger_brush_0_plane_16" "0 -0.99309695 -0.11729673 18.357685" +"*trigger_brush_0_plane_17" "0.07664188 -0.99705875 0 19.670906" +"*trigger_brush_0_plane_18" "0.15159363 0 -0.9884429 18.960403" +"*trigger_brush_0_plane_19" "0.9897514 -0 0.14280061 20.011522" +"*trigger_brush_0_plane_20" "0 -0.10413853 0.9945628 19.340891" +"*trigger_brush_0_plane_21" "0.99570972 0.092532285 -0 21.656448" +"*trigger_brush_0_plane_22" "-0.076628812 0.9970597 0 19.459202" +"*trigger_brush_0_plane_23" "0 0.99309695 0.11729673 18.384413" +"*trigger_brush_0_plane_24" "-0.15158319 0 0.98844451 18.718756" +"*trigger_brush_0_plane_25" "-0.98975176 0 -0.14279857 20.243675" +"*trigger_brush_0_plane_26" "0 0.14999454 -0.9886868 19.526537" +"*trigger_brush_0_plane_27" "-0.97394067 0.22680272 0 20.504448" +"*trigger_brush_0_plane_28" "-0.6470865 -0.7624166 0 18.720362" +"*trigger_brush_0_plane_29" "-0.27426073 0 0.96165532 19.786783" +"*trigger_brush_0_plane_30" "-0.76640385 0.6423589 0 19.165703" +"*trigger_brush_0_plane_31" "0 0.051804371 0.99865729 20.25021" +"*trigger_brush_0_plane_32" "-0.043983713 0 0.9990322 19.274397" +"*trigger_brush_0_plane_33" "0 -0.23249318 0.97259808 20.278576" +"*trigger_brush_0_plane_34" "-0 -0.05182166 -0.99865639 20.061886" +"*trigger_brush_0_plane_35" "0.043999169 0 -0.99903154 19.21018" +"*trigger_brush_0_plane_36" "0 0.23250006 -0.97259635 20.0965" +"*trigger_brush_0_plane_37" "0.27426839 0 -0.96165317 20.379969" +"*trigger_brush_0_plane_38" "0.76639473 -0.64236981 0 21.327457" +"*trigger_brush_0_plane_39" "0.64707154 0.76242924 0 20.551546" +"*trigger_brush_0_plane_40" "-0.93809688 -0.30126056 -0.17092778 20.400368" +"*trigger_bounds_mins" "-22.353048 -20.129639 -20.002504" +"*trigger_bounds_maxs" "22.356396 20.134279 20.002209" +} +{ +"SuppressAnimSounds" "0" +"StartDisabled" "0" +"spawnflags" "0" +"solid" "6" +"skin" "0" +"SetBodyGroup" "0" +"rendermode" "0" +"renderfx" "0" +"rendercolor" "255 255 255" +"renderamt" "255" +"RandomAnimation" "0" +"pressuredelay" "0" +"PerformanceMode" "0" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"mingpulevel" "0" +"mincpulevel" "0" +"MinAnimTime" "5" +"maxgpulevel" "0" +"maxcpulevel" "0" +"MaxAnimTime" "10" +"HoldAnimation" "0" +"gamemode_tdm" "1" +"gamemode_sur" "1" +"gamemode_lts" "1" +"gamemode_lh" "1" +"gamemode_fd" "1" +"gamemode_ctf" "1" +"gamemode_cp" "1" +"fadedist" "-1" +"ExplodeRadius" "0" +"ExplodeDamage" "0" +"drawinfastreflection" "0" +"disableX360" "0" +"disableshadows" "0" +"disablereceiveshadows" "0" +"DisableBoneFollowers" "0" +"collide_titan" "1" +"collide_ai" "1" +"ClientSide" "0" +"scale" "1" +"angles" "0 90 0" +"origin" "-784 7760 2304" +"script_name" "rings_pristine" +"model" "models/props/timeshift_rings_animated.mdl" +"classname" "prop_dynamic" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "0 90 0" +"origin" "-1270.75 -1694.72 647.999" +"targetname" "intermission" +"classname" "info_target" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -44.724 0" +"origin" "-5903.3 1066.05 724.634" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -44.724 0" +"origin" "-5943.3 1026.05 724.634" +"classname" "info_node_cover_stand" +} +{ +"origin" "-1692.96 -828.384 1487" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"triggerFilterUseNew" "1" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamBeast" "1" +"targetname" "trigger_nessy" +"classname" "trigger_once" +"*trigger_brush_0_plane_0" "-1 0 0 22.049438" +"*trigger_brush_0_plane_1" "1 0 0 22.049194" +"*trigger_brush_0_plane_2" "0 -1 0 22.049194" +"*trigger_brush_0_plane_3" "0 1 0 22.049255" +"*trigger_brush_0_plane_4" "6.4687615e-006 -4.0451205e-006 -1 16" +"*trigger_brush_0_plane_5" "-6.4687406e-006 4.0451073e-006 1 16" +"*trigger_brush_0_plane_6" "0.84787196 -0.53020108 8.4913063e-006 15.999903" +"*trigger_brush_0_plane_7" "-0.53020018 -0.8478725 -8.1072972e-007 16.000036" +"*trigger_brush_0_plane_8" "-0.84787196 0.53020108 -8.4913063e-006 16.000143" +"*trigger_brush_0_plane_9" "0.53020018 0.8478725 8.1072972e-007 15.99996" +"*trigger_brush_0_plane_10" "0.84787196 -0.53020108 0 15.999767" +"*trigger_brush_0_plane_11" "-0.53020018 -0.8478725 -0 16.00005" +"*trigger_brush_0_plane_12" "-0.84787196 0.53020108 0 16.000006" +"*trigger_brush_0_plane_13" "0.53020018 0.8478725 -0 15.99997" +"*trigger_brush_0_plane_14" "0.22462773 -0.97444457 5.4309844e-006 22.627359" +"*trigger_brush_0_plane_15" "0.97444463 0.22462772 6.5775362e-006 22.627329" +"*trigger_brush_0_plane_16" "-0.97444463 -0.22462772 -6.5775362e-006 22.627554" +"*trigger_brush_0_plane_17" "-0.22462773 0.97444457 -5.4309844e-006 22.627476" +"*trigger_bounds_mins" "-22.049438 -22.049194 -16.000122" +"*trigger_bounds_maxs" "22.049194 22.049255 16.000122" +} +{ +"origin" "-3680 -4240 1320" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 -0 -0 -256" +"*trigger_brush_0_plane_1" "1 -0 -0 1504" +"*trigger_brush_0_plane_2" "-0 -1 -0 1712" +"*trigger_brush_0_plane_3" "0 1 0 -152" +"*trigger_brush_0_plane_4" "0 -0 -1 80" +"*trigger_brush_0_plane_5" "0 0 1 80" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 -288.49957" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 1029.5475" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2274.0552" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 956.0083" +"*trigger_brush_1_plane_0" "-1 -0 -0 2096" +"*trigger_brush_1_plane_1" "1 0 0 256" +"*trigger_brush_1_plane_2" "-0 -1 -0 1712" +"*trigger_brush_1_plane_3" "0 1 0 -1544" +"*trigger_brush_1_plane_4" "0 -0 -1 80" +"*trigger_brush_1_plane_5" "0 0 1 80" +"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 390.323" +"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 0 2692.6626" +"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 1391.5861" +"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 -910.75348" +"*trigger_brush_2_plane_0" "-1 0 0 -1504" +"*trigger_brush_2_plane_1" "1 -0 0 2096" +"*trigger_brush_2_plane_2" "-0 -1 -0 1712" +"*trigger_brush_2_plane_3" "-0 1 -0 624" +"*trigger_brush_2_plane_4" "0 -0 -1 80" +"*trigger_brush_2_plane_5" "0 0 1 80" +"*trigger_brush_2_plane_6" "-0.70710677 0.70710677 0 -622.25391" +"*trigger_brush_2_plane_7" "-0.70710677 -0.70710677 0 147.07825" +"*trigger_brush_2_plane_8" "0.70710677 -0.70710677 0 2692.6626" +"*trigger_brush_2_plane_9" "0.70710677 0.70710677 0 1923.3304" +"*trigger_brush_3_plane_0" "-1 -0 -0 -256" +"*trigger_brush_3_plane_1" "1 -0 -0 1504" +"*trigger_brush_3_plane_2" "0 -1 0 20" +"*trigger_brush_3_plane_3" "0 1 0 1712" +"*trigger_brush_3_plane_4" "0 -0 -1 80" +"*trigger_brush_3_plane_5" "0 0 1 80" +"*trigger_brush_3_plane_6" "-0.70710677 0.70710677 0 1029.5475" +"*trigger_brush_3_plane_7" "-0.70710677 -0.70710677 0 -166.8772" +"*trigger_brush_3_plane_8" "0.70710677 -0.70710677 0 1077.6306" +"*trigger_brush_3_plane_9" "0.70710677 0.70710677 0 2274.0552" +"*trigger_brush_4_plane_0" "-1 -0 -0 -256" +"*trigger_brush_4_plane_1" "1 -0 -0 1504" +"*trigger_brush_4_plane_2" "-0 -1 -0 152" +"*trigger_brush_4_plane_3" "-0 1 -0 -20" +"*trigger_brush_4_plane_4" "0 -0 -1 80" +"*trigger_brush_4_plane_5" "0 0 1 80" +"*trigger_brush_4_plane_6" "-0.7288481 0.68467546 0 -290.65579" +"*trigger_brush_4_plane_7" "0.70710677 -0.70710677 -0 1170.9688" +"*trigger_brush_4_plane_8" "0.70710677 0.70710677 -0 1049.3464" +"*trigger_brush_4_plane_9" "-0.91778958 -0.39706707 0 -174.59995" +"*trigger_brush_4_plane_10" "-0.3970671 0.91778958 0 -169.24129" +"*trigger_bounds_mins" "-2096 -1712 -80" +"*trigger_bounds_maxs" "2096 1712 80" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-8259.93 -3898.29 768" +"link_to_guid_0" "8d5c25db" +"link_guid" "20bff3cf" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 1676.9395" +"*trigger_brush_0_plane_1" "1 0 0 1676.9297" +"*trigger_brush_0_plane_2" "0 -1 0 1431.5415" +"*trigger_brush_0_plane_3" "0 1 0 1431.54" +"*trigger_brush_0_plane_4" "0 0 -1 384" +"*trigger_brush_0_plane_5" "0 0 1 384" +"*trigger_brush_0_plane_6" "0.86856514 -0.49557504 0 1230.6445" +"*trigger_brush_0_plane_7" "0.32101053 0.94707561 -0 969.97974" +"*trigger_brush_0_plane_8" "-0.97844875 0.20648976 0 1471.5179" +"*trigger_brush_0_plane_9" "-0.25945646 -0.96575481 -0 1226.8235" +"*trigger_brush_0_plane_10" "0.8685652 -0.4955751 0 1230.6445" +"*trigger_brush_0_plane_11" "0.32101053 0.94707572 -0 969.97986" +"*trigger_brush_0_plane_12" "-0.97844887 0.20648979 0 1471.5182" +"*trigger_brush_0_plane_13" "0.38473445 -0.92302728 0 1552.2231" +"*trigger_brush_0_plane_14" "0.93492395 0.35484812 0 1729.538" +"*trigger_brush_0_plane_15" "-0.49514958 0.86880779 0 1838.814" +"*trigger_brush_0_plane_16" "-0.85243279 -0.5228368 0 1858.1025" +"*trigger_bounds_mins" "-1676.9395 -1431.5415 -384" +"*trigger_bounds_maxs" "1676.9297 1431.54 384" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-1096 -1064 836" +"link_to_guid_0" "7a915f75" +"link_guid" "376be52c" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 -0 792" +"*trigger_brush_0_plane_1" "1 0 0 792" +"*trigger_brush_0_plane_2" "-0 -1 -0 728" +"*trigger_brush_0_plane_3" "0 1 0 728" +"*trigger_brush_0_plane_4" "-0 0 -1 316" +"*trigger_brush_0_plane_5" "0 0 1 316" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1074.8022" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 1074.8022" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 1074.8022" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1074.8022" +"*trigger_bounds_mins" "-792 -728 -316" +"*trigger_bounds_maxs" "792 728 316" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-3344 -32 832" +"link_guid" "c73b1ba0" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 -528" +"*trigger_brush_0_plane_1" "1 -0 0 1456" +"*trigger_brush_0_plane_2" "-0 -1 -0 1120" +"*trigger_brush_0_plane_3" "0 1 0 96" +"*trigger_brush_0_plane_4" "-0 0 -1 320" +"*trigger_brush_0_plane_5" "0 0 1 320" +"*trigger_brush_0_plane_6" "0.61887223 0.7854917 0 402.17172" +"*trigger_brush_0_plane_7" "0.61887223 0.78549176 -0 402.17175" +"*trigger_brush_0_plane_8" "-0.43653622 0.89968669 0 -144.1212" +"*trigger_brush_0_plane_9" "-0.70710677 -0.70710677 0 418.60721" +"*trigger_brush_0_plane_10" "0.70710677 -0.70710677 0 1821.5071" +"*trigger_brush_0_plane_11" "0.89968669 0.43653628 0 1032.6772" +"*trigger_brush_1_plane_0" "-1 0 -0 1456" +"*trigger_brush_1_plane_1" "1 -0 -0 528" +"*trigger_brush_1_plane_2" "-0 -1 -0 1120" +"*trigger_brush_1_plane_3" "-0 1 0 1120" +"*trigger_brush_1_plane_4" "-0 0 -1 320" +"*trigger_brush_1_plane_5" "0 0 1 320" +"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 1323.7039" +"*trigger_brush_1_plane_7" "-0.70710683 0.70710683 0 1323.7039" +"*trigger_brush_1_plane_8" "-0.70710677 -0.70710677 -0 1821.5071" +"*trigger_brush_1_plane_9" "0.70710677 -0.70710677 -0 1165.312" +"*trigger_brush_1_plane_10" "0.70710677 0.70710677 0 1165.312" +"*trigger_bounds_mins" "-1456 -1120 -320" +"*trigger_bounds_maxs" "1456 1120 320" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-7140.16 -1396.14 772" +"link_guid" "e620fcf0" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 2224.2539" +"*trigger_brush_0_plane_1" "1 0 0 2224.2637" +"*trigger_brush_0_plane_2" "0 -1 0 2217.8926" +"*trigger_brush_0_plane_3" "0 1 0 2217.8877" +"*trigger_brush_0_plane_4" "0 -0 -1 380" +"*trigger_brush_0_plane_5" "0 0 1 380" +"*trigger_brush_0_plane_6" "0.72732341 -0.68629485 0 1703.6879" +"*trigger_brush_0_plane_7" "0.68394107 0.72953725 -0 1429.9221" +"*trigger_brush_0_plane_8" "-0.70123887 -0.71292639 -0 1406.1461" +"*trigger_brush_0_plane_9" "-0.71656835 0.69751686 0 1744.0974" +"*trigger_brush_0_plane_10" "0.72732347 -0.68629491 0 1703.688" +"*trigger_brush_0_plane_11" "0.68394113 0.72953725 -0 1429.9222" +"*trigger_brush_0_plane_12" "-0.71656841 0.69751692 0 1744.0975" +"*trigger_bounds_mins" "-2224.2539 -2217.8926 -380" +"*trigger_bounds_maxs" "2224.2637 2217.8877 380" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-1312 -3120 836" +"link_to_guid_0" "e620fcf0" +"link_guid" "8d5c25db" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 1712" +"*trigger_brush_0_plane_1" "1 0 -0 1712" +"*trigger_brush_0_plane_2" "-0 -1 -0 1328" +"*trigger_brush_0_plane_3" "0 1 0 1328" +"*trigger_brush_0_plane_4" "-0 0 -1 316" +"*trigger_brush_0_plane_5" "0 0 1 316" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 2149.6045" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 2149.6045" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2149.6045" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 2149.6045" +"*trigger_bounds_mins" "-1712 -1328 -316" +"*trigger_bounds_maxs" "1712 1328 316" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-5934.88 798.942 772" +"link_guid" "7a915f75" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 1485.8599" +"*trigger_brush_0_plane_1" "1 0 0 1485.8623" +"*trigger_brush_0_plane_2" "0 -1 0 1490.5747" +"*trigger_brush_0_plane_3" "0 1 0 1490.5756" +"*trigger_brush_0_plane_4" "0 -0 -1 380" +"*trigger_brush_0_plane_5" "0 0 1 380" +"*trigger_brush_0_plane_6" "-0.68394113 -0.72953719 -0 989.97607" +"*trigger_brush_0_plane_7" "0.70748007 0.70673329 0 1003.9444" +"*trigger_brush_0_plane_8" "0.72732341 -0.68629485 0 1126.6088" +"*trigger_brush_0_plane_9" "-0.71656853 0.69751674 0 1089.8322" +"*trigger_brush_0_plane_10" "-0.68394113 -0.72953725 -0 989.97614" +"*trigger_brush_0_plane_11" "0.72732347 -0.68629491 0 1126.6089" +"*trigger_bounds_mins" "-1485.8599 -1490.5747 -380" +"*trigger_bounds_maxs" "1485.8622 1490.5756 380" +} +{ +"editorclass" "trigger_mp_spawn_zone" +"origin" "-4848 -4232 836" +"link_to_guid_0" "c73b1ba0" +"link_guid" "891ea354" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 -0 1824" +"*trigger_brush_0_plane_1" "1 0 0 1824" +"*trigger_brush_0_plane_2" "0 -1 0 1240" +"*trigger_brush_0_plane_3" "0 1 0 1240" +"*trigger_brush_0_plane_4" "-0 0 -1 316" +"*trigger_brush_0_plane_5" "0 0 1 316" +"*trigger_brush_0_plane_6" "0.70710677 0.70710677 -0 1861.105" +"*trigger_brush_0_plane_7" "0.70710683 0.70710683 0 1861.1052" +"*trigger_brush_0_plane_8" "-0.70710677 0.70710677 0 2166.5752" +"*trigger_brush_0_plane_9" "-0.70710677 -0.70710677 0 2166.5752" +"*trigger_brush_0_plane_10" "0.70710677 -0.70710677 0 2166.5752" +"*trigger_bounds_mins" "-1824 -1240 -316" +"*trigger_bounds_maxs" "1824 1240 316" +} +{ +"spawnflags" "0" +"scale" "1" +"angles" "-5 69 3.06941e-016" +"origin" "-2120 -2960 -6692" +"targetname" "spacenode" +"collide_titan" "0" +"classname" "info_target" +} +{ +"origin" "-1504 160 -516" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damage" "10000" +"triggerFilterUseNew" "1" +"targetname" "trigger_hurt_1" +"damagecap" "90000" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 13184" +"*trigger_brush_0_plane_1" "1 0 0 13184" +"*trigger_brush_0_plane_2" "-0 -1 -0 15648" +"*trigger_brush_0_plane_3" "0 1 0 15648" +"*trigger_brush_0_plane_4" "0 0 -1 764" +"*trigger_brush_0_plane_5" "0 0 1 764" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 20387.303" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 20387.303" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 20387.303" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 20387.303" +"*trigger_bounds_mins" "-13184 -15648 -764" +"*trigger_bounds_maxs" "13184 15648 764" +} +{ +"editorclass" "info_attrition_camp" +"origin" "-716 728 560" +"radius" "2000" +"phase_9" "0" +"phase_8" "0" +"phase_7" "0" +"phase_6" "0" +"phase_5" "0" +"phase_4" "0" +"phase_3" "1" +"phase_2" "1" +"phase_1" "0" +"height" "500" +"gamemode_fw" "0" +"classname" "info_target" +} +{ +"editorclass" "info_attrition_camp" +"origin" "-8544 -3920 580.002" +"radius" "1700" +"phase_9" "0" +"phase_8" "0" +"phase_7" "0" +"phase_6" "0" +"phase_5" "0" +"phase_4" "0" +"phase_3" "1" +"phase_2" "1" +"phase_1" "0" +"height" "500" +"gamemode_fw" "0" +"classname" "info_target" +} +{ +"editorclass" "info_attrition_camp" +"origin" "-3888 -2308 725.73" +"radius" "1800" +"phase_9" "0" +"phase_8" "0" +"phase_7" "0" +"phase_6" "0" +"phase_5" "0" +"phase_4" "0" +"phase_3" "1" +"phase_2" "0" +"phase_1" "1" +"height" "500" +"gamemode_fw" "0" +"classname" "info_target" +} +{ +"editorclass" "info_attrition_bank" +"radius" "256" +"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl" +"height" "256" +"scale" "1" +"angles" "-2.44662 -0.1162 -6.31668" +"origin" "-3728.92 -249.347 570.834" +"classname" "info_target" +} +{ +"editorclass" "info_attrition_bank" +"radius" "256" +"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl" +"height" "256" +"scale" "1" +"angles" "-0.0219147 45 -0.000732113" +"origin" "-4634.46 -4318.01 643.997" +"classname" "info_target" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "3.31448 90.4263 0.0792013" +"origin" "-3792.41 -260.96 570.401" +"powerUpType" "mp_loot_titan_build_credit" +"classname" "script_ref" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "-5.19204e-005 90.4217 5.11617e-005" +"origin" "-4133.64 -4605.58 644.989" +"powerUpType" "mp_loot_titan_build_credit" +"classname" "script_ref" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0.0002205 90.4217 -0.000274384" +"origin" "-9398.19 -4025.82 578.673" +"powerUpType" "mp_loot_titan_build_credit" +"classname" "script_ref" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0.00735007 136.844 -0.00725995" +"origin" "-1248.99 839.02 752.045" +"powerUpType" "mp_loot_titan_build_credit" +"classname" "script_ref" +} +{ +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"gamemode_sur" "1" +"gamemode_lh" "1" +"gamemode_cp" "1" +"gamemode_at" "0" +"scale" "1" +"angles" "0 167.628 0" +"origin" "-8154.63 -3522 580.361" +"link_guid" "dfc2c4f3" +"triggerTarget" "trigger_hardpoint_A1" +"targetname" "info_hardpoint_1" +"target" "assault_hardpoint_far_A*" +"nearTarget" "assault_hardpoint_near_A*" +"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl" +"hardpointName" "titangarage" +"hardpointGroup" "A" +"classname" "info_hardpoint" +} +{ +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"gamemode_sur" "1" +"gamemode_lh" "1" +"gamemode_cp" "1" +"gamemode_at" "0" +"scale" "1" +"angles" "0 -138.254 0" +"origin" "-4333.02 -2155.06 695.002" +"link_guid" "7749b115" +"triggerTarget" "trigger_hardpoint_B1" +"targetname" "info_hardpoint_3" +"target" "assault_hardpoint_far_B*" +"nearTarget" "assault_hardpoint_near_B*" +"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl" +"hardpointName" "dogwhistle" +"hardpointGroup" "B" +"classname" "info_hardpoint" +} +{ +"hardpointFrontlineYaw" "0" +"hardpointFrontlineOverride" "0" +"gamemode_tday" "0" +"gamemode_sur" "1" +"gamemode_lh" "1" +"gamemode_cp" "1" +"gamemode_at" "0" +"scale" "1" +"angles" "0 -114.836 0" +"origin" "-1390.34 2.709 520.001" +"link_guid" "2a84a088" +"triggerTarget" "trigger_hardpoint_C1" +"targetname" "info_hardpoint_2" +"target" "assault_hardpoint_far_C*" +"nearTarget" "assault_hardpoint_near_C*" +"model" "models/Robots/mobile_hardpoint/mobile_hardpoint.mdl" +"hardpointName" "market" +"hardpointGroup" "C" +"classname" "info_hardpoint" +} +{ +"editorclass" "info_bomb_mode_bomb" +"spawnflags" "0" +"origin" "-4470.68 -2688.15 724.001" +"classname" "info_target" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 90 2.53193e-006" +"origin" "-4612.01 -2544.57 716.025" +"powerUpType" "mp_loot_titan_build_credit" +"classname" "script_ref" +} +{ +"editorclass" "info_lts_bomb_site" +"teamnumber" "2" +"spawnflags" "0" +"model" "models/props/generator_coop/generator_coop_medium.mdl" +"origin" "-3798.73 -258.059 587.091" +"bombSiteLocation" "0" +"classname" "info_target" +} +{ +"editorclass" "info_lts_bomb_site" +"teamnumber" "2" +"spawnflags" "0" +"model" "models/props/generator_coop/generator_coop_medium.mdl" +"origin" "-2614.51 -3454.96 644" +"bombSiteLocation" "1" +"classname" "info_target" +} +{ +"origin" "-6248 -1288 616" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"link_guid" "3148974f" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 316.78223" +"*trigger_brush_0_plane_1" "1 0 0 316.78223" +"*trigger_brush_0_plane_2" "0 -1 0 316.78247" +"*trigger_brush_0_plane_3" "0 1 0 316.78241" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "-0.7049914 -0.70921588 -0 224.00005" +"*trigger_brush_0_plane_7" "-0.70921636 0.70499092 0 223.99983" +"*trigger_brush_0_plane_8" "0.70499128 0.70921594 0 224" +"*trigger_brush_0_plane_9" "0.70921642 -0.7049908 0 223.99986" +"*trigger_brush_0_plane_10" "-0.70921636 0.70499086 0 223.99983" +"*trigger_brush_0_plane_11" "0.70921648 -0.70499086 0 223.99988" +"*trigger_bounds_mins" "-316.78223 -316.78247 -96" +"*trigger_bounds_maxs" "316.78223 316.78241 96" +} +{ +"origin" "-3688 -2288 816" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"link_guid" "5bdcb1bf" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 316.78223" +"*trigger_brush_0_plane_1" "1 0 0 316.78223" +"*trigger_brush_0_plane_2" "0 -1 0 316.78247" +"*trigger_brush_0_plane_3" "0 1 0 316.78241" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "-0.7049908 -0.70921642 -0 224.00003" +"*trigger_brush_0_plane_7" "-0.70921642 0.7049908 0 224.00003" +"*trigger_brush_0_plane_8" "0.7049908 0.70921642 0 224.00003" +"*trigger_brush_0_plane_9" "0.70921642 -0.7049908 0 223.99986" +"*trigger_brush_0_plane_10" "-0.70499086 -0.70921648 -0 224.00005" +"*trigger_brush_0_plane_11" "-0.70921648 0.70499086 0 224.00005" +"*trigger_brush_0_plane_12" "0.70499086 0.70921648 -0 224.00005" +"*trigger_brush_0_plane_13" "0.70921648 -0.70499086 0 223.99988" +"*trigger_bounds_mins" "-316.78247 -316.78235 -96" +"*trigger_bounds_maxs" "316.78235 316.78247 96" +} +{ +"origin" "-896 -2880 616" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"link_guid" "a6716741" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 225.83789" +"*trigger_brush_0_plane_1" "1 0 0 225.83783" +"*trigger_brush_0_plane_2" "0 -1 0 225.83789" +"*trigger_brush_0_plane_3" "0 1 0 225.83789" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "-0.99996608 -0.0082386546 -0 224.00003" +"*trigger_brush_0_plane_7" "-0.0082386546 0.99996608 0 224.00005" +"*trigger_brush_0_plane_8" "0.99996608 0.0082385186 0 224" +"*trigger_brush_0_plane_9" "0.0082386564 -0.99996608 0 224.00003" +"*trigger_brush_0_plane_10" "-0.99996614 -0.0082386555 0 224.00005" +"*trigger_brush_0_plane_11" "-0.0082386555 0.99996614 0 224.00005" +"*trigger_brush_0_plane_12" "0.99996614 0.0082385195 0 224.00002" +"*trigger_brush_0_plane_13" "0.0082386564 -0.99996614 0 224.00006" +"*trigger_brush_0_plane_14" "-0.71290839 0.70125717 0 316.78387" +"*trigger_brush_0_plane_15" "-0.70125717 -0.71290839 0 316.78387" +"*trigger_brush_0_plane_16" "0.70125723 0.71290833 0 316.78387" +"*trigger_brush_0_plane_17" "0.71290827 -0.70125717 0 316.78381" +"*trigger_bounds_mins" "-225.83789 -225.83789 -96" +"*trigger_bounds_maxs" "225.83783 225.83789 96" +} +{ +"origin" "-3624 -4216 736" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"link_guid" "c9c2695" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 316.78223" +"*trigger_brush_0_plane_1" "1 0 0 316.78223" +"*trigger_brush_0_plane_2" "0 -1 0 316.78247" +"*trigger_brush_0_plane_3" "0 1 0 316.78241" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "-0.70880991 -0.70539957 -0 223.99986" +"*trigger_brush_0_plane_7" "-0.70539927 0.70881015 0 224.00011" +"*trigger_brush_0_plane_8" "0.70881015 0.70539927 0 223.99994" +"*trigger_brush_0_plane_9" "0.70539904 -0.70881045 0 224.00003" +"*trigger_brush_0_plane_10" "0.70881021 0.70539927 0 223.99997" +"*trigger_bounds_mins" "-316.78296 -316.78271 -96" +"*trigger_bounds_maxs" "316.78296 316.78296 96" +} +{ +"origin" "-3752 -96 656" +"wait" "1" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "0" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "none" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4097" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"link_guid" "17679895" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 0 0 316.78223" +"*trigger_brush_0_plane_1" "1 0 0 316.78223" +"*trigger_brush_0_plane_2" "0 -1 0 316.78247" +"*trigger_brush_0_plane_3" "0 1 0 316.78241" +"*trigger_brush_0_plane_4" "-0 0 -1 96" +"*trigger_brush_0_plane_5" "-0 -0 1 96" +"*trigger_brush_0_plane_6" "-0.70880991 -0.70539957 -0 223.99986" +"*trigger_brush_0_plane_7" "-0.70539945 0.70880997 0 224.00002" +"*trigger_brush_0_plane_8" "0.70880991 0.70539957 0 224" +"*trigger_brush_0_plane_9" "0.70539951 -0.70880997 0 224.00003" +"*trigger_brush_0_plane_10" "-0.70539945 0.70881003 0 224.00003" +"*trigger_brush_0_plane_11" "0.70539945 -0.70880997 0 224.00003" +"*trigger_bounds_mins" "-316.78284 -316.78284 -96" +"*trigger_bounds_maxs" "316.78296 316.7829 96" +} +{ +"spawnflags" "0" +"origin" "-3824 -72 640" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3824 88 624" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3664 -72 656" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3824 -248 624" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-4000 -72 736" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-4610.47 -4408.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-4522.47 -4504.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-4306.47 -4712.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-4138.47 -4712.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3930.47 -4680.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3754.47 -4520.71 676.989" +"classname" "info_node" +} +{ +"spawnflags" "0" +"origin" "-3418.47 -4184.71 676.989" +"classname" "info_node" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 135 0" +"origin" "-6522 -1025 533" +"link_to_guid_1" "cd6e529e" +"link_to_guid_0" "1e132096" +"link_guid" "1e3bbebe" +"turretId" "7" +"teamnumber" "3" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "-0.0980319 -171.596 -0.00220506" +"origin" "-6239.68 -4216.72 521.118" +"link_to_guid_1" "ee670072" +"link_to_guid_0" "4b6be066" +"link_guid" "237cf48f" +"turretId" "0" +"teamnumber" "4" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"teamnumber" "4" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3818.28 -319.059 613.368" +"link_to_guid_1" "c86bd441" +"link_to_guid_0" "6668019f" +"link_guid" "c9f7aad1" +"turretId" "2" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"teamnumber" "4" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 90 -8.60438e-006" +"origin" "-4384 -2680 756" +"link_to_guid_1" "3b7f5395" +"link_to_guid_0" "2365c1c9" +"link_guid" "394a1d3c" +"turretId" "1" +"classname" "info_target" +} +{ +"editorclass" "info_fw_team_tower" +"spawnflags" "0" +"model" "models/props/generator_coop/generator_coop_medium.mdl" +"scale" "1" +"angles" "-2.48038e-006 90 0" +"origin" "-454.381 -2886.73 520.827" +"link_to_guid_1" "63693a5c" +"link_to_guid_0" "128fc74f" +"link_guid" "a2589c18" +"teamnumber" "2" +"radius" "1" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "3.35337e-006 90 0" +"origin" "-760 -3872 521" +"link_to_guid_1" "feb9084e" +"link_to_guid_0" "bcd0f203" +"link_guid" "868d19d2" +"turretId" "3" +"teamnumber" "2" +"classname" "info_target" +} +{ +"editorclass" "info_fw_camp" +"spawnflags" "0" +"model" "models/vehicle/escape_pod/escape_pod.mdl" +"height" "256" +"origin" "-1248 448 656" +"link_to_guid_8" "ffdb91c1" +"link_to_guid_7" "fc571b81" +"link_to_guid_6" "f983fcd0" +"link_to_guid_5" "de85a29e" +"link_to_guid_4" "ccdc3db0" +"link_to_guid_3" "bdc38ac8" +"link_to_guid_2" "563b6eff" +"link_to_guid_1" "4359bf3d" +"link_to_guid_0" "2f988812" +"link_guid" "a9394e76" +"radius" "900" +"classname" "info_target" +} +{ +"editorclass" "info_fw_camp" +"spawnflags" "0" +"model" "models/vehicle/escape_pod/escape_pod.mdl" +"height" "256" +"origin" "-4368 -2136 700" +"link_to_guid_11" "f57064db" +"link_to_guid_10" "df5a7c37" +"link_to_guid_9" "a1a2ede5" +"link_to_guid_8" "9c0be084" +"link_to_guid_7" "7c9125e7" +"link_to_guid_6" "436573d6" +"link_to_guid_5" "36aeef28" +"link_to_guid_4" "2639b847" +"link_to_guid_3" "234799c3" +"link_to_guid_2" "1b61f1e1" +"link_to_guid_1" "194727c5" +"link_to_guid_0" "5496c0f" +"link_guid" "df7be002" +"radius" "800" +"classname" "info_target" +} +{ +"editorclass" "info_fw_camp" +"spawnflags" "0" +"model" "models/vehicle/escape_pod/escape_pod.mdl" +"height" "256" +"origin" "-8064 -3544 667.01" +"link_to_guid_8" "d982b5e0" +"link_to_guid_7" "d57a2bb3" +"link_to_guid_6" "d284dc2c" +"link_to_guid_5" "a7db3193" +"link_to_guid_4" "9503c7f8" +"link_to_guid_3" "88df464c" +"link_to_guid_2" "3adb10c9" +"link_to_guid_1" "388cbaa5" +"link_to_guid_0" "2266d6e2" +"link_guid" "539c61dc" +"radius" "900" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 65.8114 0" +"origin" "-7869.5 -1013.15 681" +"link_to_guid_1" "9b60b1b0" +"link_to_guid_0" "7491589" +"link_guid" "7070a0e2" +"turretId" "6" +"teamnumber" "3" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 135 0" +"origin" "-6649 362 585" +"link_to_guid_1" "9b6a7479" +"link_to_guid_0" "6c2dd43f" +"link_guid" "ef8ee88b" +"turretId" "8" +"teamnumber" "3" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0.603044 90 -1.33634" +"origin" "-949.577 -2882.28 533.149" +"link_to_guid_1" "ce6e0c03" +"link_to_guid_0" "436209f5" +"link_guid" "f4757f6f" +"turretId" "4" +"teamnumber" "2" +"classname" "info_target" +} +{ +"editorclass" "info_fw_turret_site" +"spawnflags" "0" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "-1.1511e-005 90 -5.58721e-005" +"origin" "-957.242 -1445.11 520.999" +"link_to_guid_1" "3566e2c0" +"link_to_guid_0" "263c3de7" +"link_guid" "6c185b79" +"turretId" "5" +"teamnumber" "2" +"classname" "info_target" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 90 -1.52373e-006" +"origin" "-4384 -2534 725.88" +"link_guid" "3b7f5395" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2642 716" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2718 716" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2642 716" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2718 716" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4384 -2534 716" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2718 726" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2642 726" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2642 726" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2718 726" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2718 736" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2642 736" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2718 736" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2642 736" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2642 746" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2718 746" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4346 -2718 746" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-4422 -2642 746" +"classname" "script_ref" +} +{ +"model" "*2" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-4384 -2626 886" +"link_guid" "2365c1c9" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3726 -65 530" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -281 564" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -357 564" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -357 564" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -281 564" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 90 -1.52373e-006" +"origin" "-3726 -65 549.88" +"link_guid" "6668019f" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3726 -65 540" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -357 574" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -357 574" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -281 574" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -281 574" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -357 584" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -357 584" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -281 584" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -281 584" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -281 594" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -281 594" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -357 594" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -357 594" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -281 604" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -281 604" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3856 -357 604" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-3780 -357 604" +"classname" "script_ref" +} +{ +"model" "*3" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-3790.5 -210 722" +"link_guid" "c86bd441" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 97.0737 0" +"origin" "-6197.48 -4250.06 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 97.0737 0" +"origin" "-6282.25 -4183.92 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 45.0117 -1.52373e-006" +"origin" "-6081.35 -4053.12 545.88" +"link_guid" "ee670072" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 97.0737 0" +"origin" "-6272.91 -4259.4 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45.0117 0" +"origin" "-6081.35 -4053.12 536" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 97.0737 0" +"origin" "-6206.85 -4174.57 512" +"classname" "script_ref" +} +{ +"model" "*4" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-6177.5 -4151 678" +"link_guid" "4b6be066" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45.0117 0" +"origin" "-6081.35 -4053.12 526" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-722 -3834 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-798 -3834 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-722 -3910 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-608 -3870 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-798 -3910 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 90 -1.52373e-006" +"origin" "-608 -3870 521.88" +"link_guid" "feb9084e" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-912 -2920 522" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-912 -2844 522" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-988 -2844 522" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-988 -2920 522" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-834 -2880 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 90 -1.52373e-006" +"origin" "-834 -2880 521.88" +"link_guid" "ce6e0c03" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-919 -1623 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-995 -1483 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 90 -1.52373e-006" +"origin" "-919 -1623 521.88" +"link_guid" "263c3de7" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-995 -1407 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-919 -1407 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-919 -1483 512" +"classname" "script_ref" +} +{ +"model" "*5" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-702.5 -3872 686" +"link_guid" "bcd0f203" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"model" "*6" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-911.5 -2880 686" +"link_guid" "436209f5" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"model" "*7" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-955.5 -1515 686" +"link_guid" "3566e2c0" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6702.86 362.291 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6649.12 416.031 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 45 -1.52373e-006" +"origin" "-6766.12 247.122 585.88" +"link_guid" "6c2dd43f" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6649.11 308.55 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6595.37 362.29 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6766.12 247.122 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6468.37 -1024.71 524" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 45 -1.52373e-006" +"origin" "-6799.12 -875.88 533.88" +"link_guid" "cd6e529e" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6522.11 -1078.45 524" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6522.12 -970.969 524" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6799.12 -875.88 524" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6575.86 -1024.71 524" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6522.11 -1078.45 514" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6575.86 -1024.71 514" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7819.05 -993.456 632" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7888.55 -962.627 632" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 11.1616 0" +"origin" "-7927.69 -782.723 576" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7919.35 -1032.1 632" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7849.92 -1062.91 632" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_battery_port" +"spawnflags" "0" +"model" "models/props/battery_port/battery_port_animated.mdl" +"scale" "1" +"angles" "3.10056e-006 11.1616 -1.52373e-006" +"origin" "-7927.69 -782.723 585.88" +"link_guid" "7491589" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7819.05 -993.456 642" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7849.92 -1062.91 642" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7919.35 -1032.1 642" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7888.55 -962.627 642" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7819.05 -993.456 652" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7919.35 -1032.1 652" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7849.92 -1062.91 652" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7888.55 -962.627 652" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7849.92 -1062.91 662" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7888.55 -962.627 662" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7919.35 -1032.1 662" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7819.05 -993.456 662" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7819.05 -993.456 672" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7919.35 -1032.1 672" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7888.55 -962.627 672" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 66.0615 0" +"origin" "-7849.92 -1062.91 672" +"classname" "script_ref" +} +{ +"model" "*8" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-6680.75 331.983 750" +"link_guid" "9b6a7479" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"model" "*9" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-6633.75 -977.05 686" +"link_guid" "1e132096" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"model" "*10" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-7869.28 -925.873 774" +"link_guid" "9b60b1b0" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"model" "*11" +"triangle_collision" "1" +"editorclass" "func_brush_navmesh_separator" +"origin" "-452 -2886 732" +"link_guid" "63693a5c" +"startDisconnected" "0" +"classname" "func_brush" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-912 -2920 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-988 -2920 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-988 -2844 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 90 0" +"origin" "-912 -2844 512" +"classname" "script_ref" +} +{ +"editorclass" "info_fw_foundation_plate" +"spawnflags" "0" +"model" "models/industrial/grate_mod.mdl" +"scale" "1" +"angles" "0 45 0" +"origin" "-6468.37 -1024.71 514" +"classname" "script_ref" +} +{ +"editorclass" "trigger_fw_territory" +"origin" "-728 -2828 885" +"wait" "0" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "0" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "0" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "1" +"StartDisabled" "0" +"spawnflags" "64" +"link_guid" "128fc74f" +"triggerFilterUseNew" "1" +"classname" "trigger_multiple" +"*trigger_brush_0_plane_0" "-1 -0 -0 904" +"*trigger_brush_0_plane_1" "1 0 0 1336" +"*trigger_brush_0_plane_2" "-0 -1 -0 1588" +"*trigger_brush_0_plane_3" "-0 1 0 996" +"*trigger_brush_0_plane_4" "0 0 -1 395" +"*trigger_brush_0_plane_5" "0 0 1 395" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 1343.5029" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 -0 1762.1101" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 2067.5801" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 1648.9729" +"*trigger_brush_1_plane_0" "-1 -0 -0 1336" +"*trigger_brush_1_plane_1" "1 0 0 1336" +"*trigger_brush_1_plane_2" "0 -1 -0 -996" +"*trigger_brush_1_plane_3" "-0 1 -0 1588" +"*trigger_brush_1_plane_4" "0 0 -1 395" +"*trigger_brush_1_plane_5" "0 0 1 395" +"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 -0 2067.5801" +"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 -0 240.41632" +"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 240.41632" +"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 2067.5801" +"*trigger_bounds_mins" "-1336 -1588 -395" +"*trigger_bounds_maxs" "1336 1588 395" +} +{ +"model" "*12" +"triangle_collision" "1" +"editorclass" "func_brush_fw_territory_border" +"origin" "-1051 -2171 728" +"VisibilityFlags" "2" +"useNonLocalWorldLights" "0" +"startdisabled" "0" +"solidity" "1" +"solidbsp" "0" +"gamemode_tdm" "0" +"gamemode_lh" "0" +"gamemode_fw" "1" +"gamemode_ffa" "0" +"gamemode_ctf" "0" +"gamemode_cp" "0" +"gamemode_at" "0" +"drawinfastreflection" "0" +"disableshadows" "0" +"bakedSunFraction" "-1.0" +"teamnumber" "2" +"classname" "func_brush" +} +{ +"model" "*13" +"triangle_collision" "1" +"editorclass" "func_brush_fw_territory_border" +"origin" "-6613 -1533.5 674" +"useNonLocalWorldLights" "0" +"teamnumber" "3" +"startdisabled" "0" +"solidity" "1" +"solidbsp" "0" +"gamemode_tdm" "0" +"gamemode_lh" "0" +"gamemode_fw" "1" +"gamemode_ffa" "0" +"gamemode_ctf" "0" +"gamemode_cp" "0" +"gamemode_at" "0" +"drawinfastreflection" "0" +"disableshadows" "0" +"bakedSunFraction" "-1.0" +"VisibilityFlags" "4" +"classname" "func_brush" +} +{ +"model" "*14" +"triangle_collision" "1" +"editorclass" "func_brush_fw_territory_border" +"origin" "-1051 -2170.5 728" +"useNonLocalWorldLights" "0" +"startdisabled" "0" +"solidity" "1" +"solidbsp" "0" +"gamemode_tdm" "0" +"gamemode_lh" "0" +"gamemode_fw" "1" +"gamemode_ffa" "0" +"gamemode_ctf" "0" +"gamemode_cp" "0" +"gamemode_at" "0" +"drawinfastreflection" "0" +"disableshadows" "0" +"bakedSunFraction" "-1.0" +"teamnumber" "2" +"VisibilityFlags" "4" +"classname" "func_brush" +} +{ +"model" "*15" +"triangle_collision" "1" +"editorclass" "func_brush_fw_territory_border" +"origin" "-6614 -1533.5 674" +"VisibilityFlags" "2" +"useNonLocalWorldLights" "0" +"teamnumber" "3" +"startdisabled" "0" +"solidity" "1" +"solidbsp" "0" +"gamemode_tdm" "0" +"gamemode_lh" "0" +"gamemode_fw" "1" +"gamemode_ffa" "0" +"gamemode_ctf" "0" +"gamemode_cp" "0" +"gamemode_at" "0" +"drawinfastreflection" "0" +"disableshadows" "0" +"bakedSunFraction" "-1.0" +"classname" "func_brush" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -70.647 0" +"origin" "-1398.96 873.896 574.188" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-4448 -1480 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-4448 -1536 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-4448 -1592 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4600 -1568 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4712 -1568 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4656 -1568 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4768 -1568 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-4604 -1368 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-4220 -1782 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-4540 -1784 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4792 -1724 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-4844 -1784 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-4844 -2152 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4792 -2100 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4488 -2100 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 180 0" +"origin" "-4436 -2152 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4648 -1924 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 174.242 0" +"origin" "-3516.01 -2612.4 736" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -134.404 0" +"origin" "-4005.21 -2549.17 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -134.404 0" +"origin" "-3969.21 -2585.17 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-3363.85 -2041.39 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 180 0" +"origin" "-3364.24 -2092.28 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 180 0" +"origin" "-2396.24 -2092.28 656" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-2395.85 -2041.39 656" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 45 0" +"origin" "-3612.05 -2210.29 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 45 0" +"origin" "-3647.46 -2175.76 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-4258 -2710 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-4258 -2660 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-5034 -2714 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-5034 -2664 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-4758 -2662 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 180 0" +"origin" "-4758 -2712 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 124.91 0" +"origin" "-5305.57 -2280.73 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 124.91 0" +"origin" "-5346.53 -2309.39 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -55.09 0" +"origin" "-5463.47 -2054.61 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -55.09 0" +"origin" "-5504.43 -2083.27 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 90 0" +"origin" "-4822 -2766 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -90 0" +"origin" "-4970 -2610 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 90 0" +"origin" "-4200 -2766 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 137.849 0" +"origin" "-3978.23 -2674.54 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 135.697 0" +"origin" "-3527.69 -2204.18 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -55.171 0" +"origin" "-5292.38 -1858.66 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 49.7768 0" +"origin" "-4953.45 -3057.54 720" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -45.163 0" +"origin" "-6104.11 -1467.31 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -45.163 0" +"origin" "-6068.72 -1432.03 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -45.163 0" +"origin" "-5880.11 -1255.31 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -45.163 0" +"origin" "-6282.72 -1650.03 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.2765 0" +"origin" "-6525.59 -1797.7 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.2765 0" +"origin" "-6485.59 -1837.7 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-6592.69 -1784.11 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-6656.69 -1716.11 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-6819.31 -1879.89 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-6675.31 -2023.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-6616.69 -1416.11 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-7161.31 -2245.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-7383.31 -2023.89 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-7372.69 -1516.11 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.724 0" +"origin" "-5710.41 -974.3 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-5745.31 -889.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.724 0" +"origin" "-5836.41 -898.3 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.724 0" +"origin" "-6372.41 -690.3 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.724 0" +"origin" "-6420.41 -650.3 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.724 0" +"origin" "-6460.41 -610.3 592" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-6305.31 -725.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-6481.31 -555.89 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-6090.69 -350.11 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 44.837 0" +"origin" "-5666.69 33.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.163 0" +"origin" "-6045.31 -305.89 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -20.865 0" +"origin" "-5194.72 232.223 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 159.135 0" +"origin" "-5075.28 189.78 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-4882 184 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-4882 -306 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -25.868 0" +"origin" "-5272.05 6.83351 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -134.691 0" +"origin" "-6613.74 55.0701 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -134.691 0" +"origin" "-6895.74 339.07 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -45.061 0" +"origin" "-5494.43 573.319 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -25.868 0" +"origin" "-5784.05 154.834 592" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -44.691 0" +"origin" "-7145.07 -729.74 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 75.477 0" +"origin" "-7936.67 -3117.23 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 67.9382 0" +"origin" "-8116.76 -3943.04 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -22.062 0" +"origin" "-8131.04 -3881.24 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 74.9241 0" +"origin" "-8443.99 -4197.42 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 75.0976 0" +"origin" "-8591.52 -2940.22 596.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -14.449 0" +"origin" "-8625.64 -2878.83 596.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -14.902 0" +"origin" "-8646.22 -3144.48 588.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -14.902 0" +"origin" "-8186.22 -3268.48 588.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -14.902 0" +"origin" "-7738.22 -3388.48 588.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -14.411 0" +"origin" "-7861.12 -3839.65 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 75.098 0" +"origin" "-7821.52 -3916.22 588.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 44.4931 0" +"origin" "-8843.46 -4036.85 588.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 11.4796 0" +"origin" "-9137.74 -3522.5 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -23.152 0" +"origin" "-6910.97 -3776.88 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 24.3059 0" +"origin" "-7612.21 -4206.92 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -135.244 0" +"origin" "-5389.49 -3299.08 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -135.244 0" +"origin" "-5428.86 -3259.31 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.26 0" +"origin" "-5311.26 -3375.59 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.26 0" +"origin" "-5271.21 -3414.68 720" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 45.6407 0" +"origin" "-5198.86 -3069.67 720" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -106.038 0" +"origin" "-2273.51 -2344.4 656" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -70.647 0" +"origin" "-2784.97 -2332.36 656" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -90 0" +"origin" "-2606.61 -1979.85 656" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -90 0" +"origin" "-2451.72 -1980.24 656" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -2.2529 0" +"origin" "-8502.15 -4125.32 612.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -83.909 0" +"origin" "-1470.54 649.606 574.188" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -70.647 0" +"origin" "-1646.96 681.896 574.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -47.145 0" +"origin" "-1909.06 268.227 574.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-1188.89 -5.46055 534.188" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-1128.89 -5.4606 534.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.361 0" +"origin" "-1702.89 389.442 574.188" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -50.123 0" +"origin" "-1915.84 473.333 574.185" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-664 608 608" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-432 332 616" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-432 1192 592" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -106.195 0" +"origin" "-640.812 -190.785 591.967" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -73.007 0" +"origin" "-1373.04 -230.614 536.005" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -89.666 0" +"origin" "-1300.89 -605.461 534.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -106.195 0" +"origin" "-612.868 1338.66 586.157" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -82.54 0" +"origin" "-1021.68 1162.37 574.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -121.825 0" +"origin" "-1467.78 -599.512 534.188" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -143.868 0" +"origin" "-167.517 1018.96 595.376" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 75.8469 0" +"origin" "-7529.91 -2887.76 592" +"classname" "info_node_cover_stand" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-4581.92 -1857.53 755.998" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-3202.13 -2679.22 772" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-4996.1 848.459 640" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "3.20383 -2583.9 584" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-4126.89 -3645.28 708.992" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-8254.52 -4383.02 668.36" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-8468.17 -2480.01 644.36" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-7833.18 -1925.19 644.125" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-8326.67 -1573.78 644" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-5844.11 -121.301 644" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-6128.37 -720.44 644" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-6707.37 -1812.42 643.999" +"classname" "info_node_safe_hint" +} +{ +"spawnflags" "0" +"nodeFOV" "360" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "102" +"origin" "-5257.23 -3233.01 775.998" +"classname" "info_node_safe_hint" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 180 0" +"origin" "-707.71 -2674.11 543.997" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-704 -3212 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -178.666 0" +"origin" "-617.141 -2875.04 543.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-460 -3100 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -125.081 0" +"origin" "-833.472 -2284.29 543.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 90 0" +"origin" "-832.73 -3601.05 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -1.40334e-014 0" +"origin" "-1399.71 -2731.27 671.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -6.4689 0" +"origin" "-1399.62 -2638.84 671.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-1480 -3028 672" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-1720 -3100 676" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-1720 -2660 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-1992 -2828 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-1992 -2936 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-2180 -2984 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-2016 -2576 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 56.2721 0" +"origin" "-1949.45 -3509.17 676" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0 0" +"origin" "-2812.8 -2664.66 740" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 25.6162 0" +"origin" "-2812.01 -3011.4 740" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -32.531 0" +"origin" "-2828.86 -3205.67 740" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -6.2179 0" +"origin" "-3032 -3416.73 740" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 0.0768 0" +"origin" "-3104.63 -3485.69 740" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 0 0" +"origin" "-2861.49 -2863.76 740" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 180 0" +"origin" "-2704 -2396 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.33 0" +"origin" "-2761.52 -3471.39 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -134.33 0" +"origin" "-2684.26 -3546.82 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -134.639 0" +"origin" "-3202.47 -3376.52 740" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -134.859 0" +"origin" "-3200.63 -4278.03 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -134.639 0" +"origin" "-3550.71 -3621.72 676.992" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 155.979 0" +"origin" "-3463.88 -4643.98 804.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 133.053 0" +"origin" "-3741.32 -4907.18 805" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 166.354 0" +"origin" "-3675.16 -4826.35 805" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 114.473 0" +"origin" "-3983 -4975.73 805" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 88.2126 0" +"origin" "-4256.72 -4967.88 805" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 46.6407 0" +"origin" "-4512.85 -4891.3 805" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 41.8151 0" +"origin" "-4563.67 -4841.39 805.001" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 42.579 0" +"origin" "-4859.07 -4548.38 805" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -120.962 0" +"origin" "-3986.54 -3549.94 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -113.45 0" +"origin" "-4188.01 -3705.29 676.991" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 66.5706 0" +"origin" "-4238.87 -3829.87 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 62.3857 0" +"origin" "-4364.49 -4336.36 677.088" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 44.8382 0" +"origin" "-4309.25 -4380.65 677.117" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 37.7505 0" +"origin" "-4071.07 -4137.88 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 139.865 0" +"origin" "-4222.27 -4375.36 677.088" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 167.789 0" +"origin" "-3955.13 -4117.21 677.088" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 80.8422 0" +"origin" "-4411.09 -4892.87 805" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 89.7471 0" +"origin" "-4326.31 -4894.97 805" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 70.1256 0" +"origin" "-3910.69 -4912.43 805" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.67 0" +"origin" "-2818.48 -3682.61 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.67 0" +"origin" "-2885.74 -3615.18 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 36.5559 0" +"origin" "-2609.52 -3780.17 676" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 31.9057 0" +"origin" "-3696.58 -3757.97 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -23.621 0" +"origin" "-7441.27 -898.424 612.001" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -23.621 0" +"origin" "-8041.74 -1434.98 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 37.0224 0" +"origin" "-7080.78 161.468 615.988" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 53.6677 0" +"origin" "-6786.92 -124.946 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -33.427 0" +"origin" "-6075.92 526.058 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -35.245 0" +"origin" "-6677.06 -1246.48 547.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 138.638 0" +"origin" "-2417.65 -1009.07 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 141.758 0" +"origin" "-2332.31 -564.011 544.001" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 160.837 0" +"origin" "-2624.02 -519.857 544.001" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 169.628 0" +"origin" "-2689.16 -113.007 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 133.483 0" +"origin" "-2829.19 -642.056 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 149.3 0" +"origin" "-1979.57 -1001.11 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 134.155 0" +"origin" "-2184.13 -999.64 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 149.3 0" +"origin" "-1686.79 -1189.54 551.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 171.47 0" +"origin" "-1357.28 -1042.66 543.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -179.666 0" +"origin" "-1235.46 -715.11 534.188" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -34.978 0" +"origin" "-2730.88 -458.32 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -35.71 0" +"origin" "-2775.54 -520.54 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -9.6773 0" +"origin" "-2266.83 -844.802 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 3.901 0" +"origin" "-2043.38 -1151.14 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -64.026 0" +"origin" "-2482.02 -350.092 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -30.214 0" +"origin" "-2714.15 -751.932 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -45.244 0" +"origin" "-5714.85 -3386.19 631.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -45.244 0" +"origin" "-5778.85 -3454.19 631.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -45.162 0" +"origin" "-5143.75 -3664.94 683.684" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -28.251 0" +"origin" "-5595.25 -3691.11 631.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 28.2911 0" +"origin" "-6336.37 -3733.64 583.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 43.454 0" +"origin" "-6046.74 -4089.17 567.998" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 45.5625 0" +"origin" "-6442.85 -4307.03 596.727" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 43.454 0" +"origin" "-6411.68 -3979.16 544.059" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -135.616 0" +"origin" "-5636.21 -3055.44 743.998" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -134.748 0" +"origin" "-5911.06 -3640.23 615.998" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -158.587 0" +"origin" "-5575.21 -3991.75 616.151" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -135.047 0" +"origin" "-5652.33 -3892.95 616.263" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -109.894 0" +"origin" "-6004.29 -3569.17 615.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 47.6708 0" +"origin" "-6118.64 -4004.42 567.998" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 47.6708 0" +"origin" "-5953.49 -4363.76 551.998" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 166.432 0" +"origin" "-5926.31 -4057.69 583.998" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -142.99 0" +"origin" "-6006.69 -3895.67 591.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 44.8896 0" +"origin" "-6334.8 -4509.46 596.59" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 169.812 0" +"origin" "-4504.9 -4068.47 676.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 134.202 0" +"origin" "-4950.18 -4283.5 691.021" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 141.776 0" +"origin" "-4755.07 -3956.47 706.986" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 136.692 0" +"origin" "-4788.98 -4236.91 677.36" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 142.275 0" +"origin" "-4860.91 -4054.94 689.753" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 145.937 0" +"origin" "-4658.05 -4180.44 677.005" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 135.456 0" +"origin" "-4556.96 -4489.46 676.997" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 141.59 0" +"origin" "-4368.02 -4659.16 677.095" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 50.3557 0" +"origin" "-3067.86 -4140.96 676.992" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 31.9057 0" +"origin" "-3220.18 -3619.63 676.991" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 128.27 0" +"origin" "-6730.49 -4096.46 596.637" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 144.639 0" +"origin" "-7016.04 -3992.89 615.352" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 144.639 0" +"origin" "-6970.05 -3936.68 613.751" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 137.753 0" +"origin" "-6828.88 -3835.72 613.356" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 127.562 0" +"origin" "-6906.02 -4206.28 621.319" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -30.354 0" +"origin" "-7229.86 -3833.26 628.919" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -30.354 0" +"origin" "-7189.66 -3781.25 615.588" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 1.4328 0" +"origin" "-7652.91 -3868.36 613.737" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 169.997 0" +"origin" "-3390.69 -409.783 628.126" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 145.444 0" +"origin" "-3539.24 -628.953 653.85" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 170.226 0" +"origin" "-3422.48 163.181 678.375" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 153.366 0" +"origin" "-3977.6 -507.186 620.654" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -87.59 0" +"origin" "-4051.64 -1031.06 642.338" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -106.967 0" +"origin" "-3654.05 -1080.95 691.825" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 12.1599 0" +"origin" "-4318.36 -436.306 653.563" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 36.0196 0" +"origin" "-4284.9 -513.31 662.829" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -11.207 0" +"origin" "-4220.42 -156.665 650.563" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -1.414 0" +"origin" "-4181.35 -321.315 624.302" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -1.414 0" +"origin" "-4146.35 640.5 599.621" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -1.414 0" +"origin" "-4251.01 554.427 604.121" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 178.584 0" +"origin" "-3355.36 -264.48 591.022" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 178.584 0" +"origin" "-3434.78 494.689 570.717" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 178.584 0" +"origin" "-3370.48 572.305 569.7" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 169.186 0" +"origin" "-3338.88 371.23 595.424" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -87.59 0" +"origin" "-3826.48 103.86 556.936" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -94.751 0" +"origin" "-3612.14 -8.40236 573.338" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -100.359 0" +"origin" "-3683.58 -455.71 633.426" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -93.066 0" +"origin" "-3761.73 -451.058 623.982" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -94.751 0" +"origin" "-3613.3 411.581 580.228" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -119.661 0" +"origin" "-4356.36 485.86 609.257" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -67.568 0" +"origin" "-3133.43 306.76 585.95" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -41.623 0" +"origin" "-3233.32 119.493 660.132" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -52.608 0" +"origin" "-3168.23 169.574 666.278" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -3.2097 0" +"origin" "-3645.72 -387.85 633.759" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -15.827 0" +"origin" "-5718.78 266.283 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 149.723 0" +"origin" "-6117.19 -1016.82 548" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 134.837 0" +"origin" "-6511.07 -1400.55 548" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 149.723 0" +"origin" "-6988.63 -863.72 556" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -121.753 0" +"origin" "-7241.91 -1372.73 556" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -134.726 0" +"origin" "-6574.62 -1243.04 547.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -59.767 0" +"origin" "-4954.64 413.425 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -147.04 0" +"origin" "-5435.04 961.184 608" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -152.864 0" +"origin" "-5958.78 512.058 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -137.45 0" +"origin" "-6242.19 758.578 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -116.477 0" +"origin" "-7831.51 -202.67 628" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 52.7583 0" +"origin" "-7270.91 -2360.21 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -85.297 0" +"origin" "-4082.07 -369.953 635.191" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 36.0196 0" +"origin" "-4220.19 -580.09 662.354" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -62.22 0" +"origin" "-4760.92 -245.885 605.061" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -106.967 0" +"origin" "-3491.43 -947.177 682.578" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.642 0" +"origin" "-3806.81 -915.8 630.794" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.642 0" +"origin" "-3941.86 -835.906 621.134" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 65.2752 0" +"origin" "-4196.32 -1418.68 747.066" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 91.358 0" +"origin" "-3929.93 -1441.03 756.15" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 91.358 0" +"origin" "-3775.94 -1462.05 754.149" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 91.358 0" +"origin" "-3842.78 -1503.14 752.756" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.827 0" +"origin" "-6790.89 -742.16 556" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.827 0" +"origin" "-6766.08 -864.268 556" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.827 0" +"origin" "-6587.41 -782.693 556.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -6.8311 0" +"origin" "-7206.05 -1215.3 556.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.827 0" +"origin" "-6327.11 -1407.17 547.996" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.827 0" +"origin" "-6088.45 -1240.85 547.997" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 177.117 0" +"origin" "-6528.74 -915.604 555.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 134.344 0" +"origin" "-6842.1 -1983.31 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -172.091 0" +"origin" "-2720.74 -3872.36 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -104.654 0" +"origin" "-7818.54 -2545.53 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -106.009 0" +"origin" "-7399.23 -2652.41 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -104.654 0" +"origin" "-7682.55 -2236.73 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -103.491 0" +"origin" "-7539.35 -2731.02 612.361" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -106.182 0" +"origin" "-7556.15 -2515.44 612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -103.272 0" +"origin" "-7677.14 -2555.86 608" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 47.2903 0" +"origin" "-7227.17 -1653.07 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 68.2386 0" +"origin" "-7138.14 -1745.69 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -35.745 0" +"origin" "-7295.84 -854.727 611.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 163.129 0" +"origin" "-1079.54 -1393.29 543.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 164.256 0" +"origin" "-644.283 -1287.47 551.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 163.129 0" +"origin" "-608.017 -1548.47 543.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 121.938 0" +"origin" "-1044.76 -1919.15 551.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -96.65 0" +"origin" "-837.209 -1825.28 543.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -96.65 0" +"origin" "-903.926 -1817.26 544" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 88.1533 0" +"origin" "-912.089 -1918.1 543.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 109.373 0" +"origin" "-773.872 -1925.72 543.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -96.65 0" +"origin" "-652.95 -1876.11 544.306" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 146.327 0" +"origin" "-671.199 -1642.57 543.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 138.57 0" +"origin" "-562.81 -1962.17 545.867" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 158.674 0" +"origin" "-498.6 -2227.35 551.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 90.7323 0" +"origin" "-620.521 -2460.53 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 90.6667 0" +"origin" "-560.453 -2459.98 545.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 90.7323 0" +"origin" "-894.677 -2483.51 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 90.6667 0" +"origin" "-1112.58 -2730.83 551.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 90.6667 0" +"origin" "-664.477 -3024.61 544" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -89.333 0" +"origin" "-741.66 -2149.92 544.001" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -92.033 0" +"origin" "-1111.41 -2322.08 552" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -44.455 0" +"origin" "-1293.77 -1707.54 551.999" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -45.719 0" +"origin" "-1251.96 -1672.37 551.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -44.385 0" +"origin" "-1455.92 -1275.27 551.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -45.719 0" +"origin" "-1489.37 -964.045 544" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -44.385 0" +"origin" "-1578.43 -999.334 544" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -90.518 0" +"origin" "-1084.1 -953.878 546.075" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -96.65 0" +"origin" "-732.146 -1010.05 552" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -1.2453 0" +"origin" "-1537.71 -2839.76 676" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 3.1461 0" +"origin" "-1517.71 -2924.2 676" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 139.352 0" +"origin" "-2670.74 -602.656 543.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 149.245 0" +"origin" "-1335.03 -1348.38 551.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 163.141 0" +"origin" "-1032.31 -1085.11 543.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 74.4128 0" +"origin" "-7853.43 -3034.08 612.36" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 74.4128 0" +"origin" "-7751.29 -3071.42 612.36" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 167.629 0" +"origin" "-5558.09 239.798 608" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 166.842 0" +"origin" "-5227.33 360.85 613.635" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 135.208 0" +"origin" "-5036.83 -214.626 613.635" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -150.455 0" +"origin" "-5086.52 870.636 608" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -72.328 0" +"origin" "-7478.87 -1322.08 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -49.23 0" +"origin" "-7623.01 -1502.26 620" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -65.552 0" +"origin" "-7408.93 -1568.43 619.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 129.387 0" +"origin" "-7336.82 -1684.9 620.003" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 98.3354 0" +"origin" "-7571.35 -1622.74 620" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 42.8562 0" +"origin" "-7656.57 -851.33 608.001" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 50.9043 0" +"origin" "-7387.3 -708.065 610.848" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -43.957 0" +"origin" "-7396.13 -598.89 607.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -135.93 0" +"origin" "-7294.09 -599.115 608.001" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -91.508 0" +"origin" "-7590.79 -518.696 608" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -44.973 0" +"origin" "-8232.15 -1676.94 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -44.973 0" +"origin" "-8297.91 -2135.64 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -44.973 0" +"origin" "-7915.97 -2454.28 612" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -45.665 0" +"origin" "-7837.14 -2371.42 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -57.871 0" +"origin" "-7613.43 -2143.64 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -44.634 0" +"origin" "-8221.14 -1858.24 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -44.634 0" +"origin" "-8328.48 -1787.78 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -44.634 0" +"origin" "-8105.31 -1568.36 612" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 135.07 0" +"origin" "-7298.37 -1518.83 620" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 98.8941 0" +"origin" "-7408.47 -2129.94 620" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 75.1534 0" +"origin" "-8007.74 -1160.66 608" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 44.2621 0" +"origin" "-7462.92 -338.168 608" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 62.0431 0" +"origin" "-7068.96 -645.363 611.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 60.7599 0" +"origin" "-7127.36 -397.457 608.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 60.7599 0" +"origin" "-6927.11 -247.45 607.997" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 48.9231 0" +"origin" "-7026.65 -5.52116 608.269" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 44.1453 0" +"origin" "-6898.84 -14.349 608.002" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 15.7763 0" +"origin" "-7300.53 28.8221 615.989" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 15.7763 0" +"origin" "-7312.08 -81.1711 615.989" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -142.622 0" +"origin" "-6235.65 488.89 608" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -142.622 0" +"origin" "-6285.76 583.541 608" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -93.005 0" +"origin" "-7723.87 -317.694 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -110.578 0" +"origin" "-7905.4 -806.484 608" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -110.545 0" +"origin" "-8213.91 -1169.36 615.987" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -45.24 0" +"origin" "-7779.74 -1457.22 620.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -118.793 0" +"origin" "-7262.46 -2112.76 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 134.921 0" +"origin" "-7069.4 -2059.8 619.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 134.921 0" +"origin" "-6965.36 -2039.65 619.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 134.921 0" +"origin" "-7067.73 -2181.29 620" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 134.438 0" +"origin" "-7030.15 -1103.6 548.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 136.86 0" +"origin" "-6958.79 -1023.52 548.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -122.915 0" +"origin" "-6945.45 -1438.47 556.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -122.915 0" +"origin" "-7076.89 -1356.67 547.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -27.741 0" +"origin" "-6712.3 -1092.64 548.002" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -134.322 0" +"origin" "-5838.37 -3486.14 623.998" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -134.322 0" +"origin" "-5496.42 -3821.66 631.422" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -140.821 0" +"origin" "-5635.04 -3386.63 639.998" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 44.8896 0" +"origin" "-6389.73 -4358.61 596.68" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 45.8775 0" +"origin" "-6190.79 -4504.95 596.59" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 39.1821 0" +"origin" "-6138.37 -4365.84 543.997" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 49.869 0" +"origin" "-6376.99 -4116.28 544.057" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 27.2854 0" +"origin" "-6635.28 -4149.75 596.612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 65.6465 0" +"origin" "-5782.65 -4230.55 583.998" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 26.5723 0" +"origin" "-6314.25 -3798.62 575.997" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 127.22 0" +"origin" "-3975.97 -999.631 640.261" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 92.9475 0" +"origin" "-3872.5 -954.094 635.842" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 39.1837 0" +"origin" "-3746.29 -970.234 648.015" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 46.5053 0" +"origin" "-3724.16 -1060.16 683.97" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 161.034 0" +"origin" "-4931.75 -34.5351 612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 167.601 0" +"origin" "-4781.9 31.9081 609.512" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.88 0" +"origin" "-3746.59 -1326.22 758.167" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.88 0" +"origin" "-3862.17 -1403.46 755.403" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.88 0" +"origin" "-4003.82 -1376.79 756.963" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.88 0" +"origin" "-3818.67 -1310.57 736.729" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -88.88 0" +"origin" "-3934.48 -1329.37 736.936" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 37.525 0" +"origin" "-3261.78 -3825.89 676.991" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 42.1465 0" +"origin" "-3004.11 -3943.44 676.99" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 29.8149 0" +"origin" "-3785.85 -3979.67 676.99" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 146.092 0" +"origin" "-7418.79 -3618.09 613.878" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 172.826 0" +"origin" "-7497.34 -3881.1 613.738" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 164.11 0" +"origin" "-7547.81 -3444.96 613.877" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 157.092 0" +"origin" "-7382.1 -3382.33 613.951" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 171.98 0" +"origin" "-7485.88 -4015.78 613.548" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 157.092 0" +"origin" "-7068.7 -3627.8 630.557" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 135.409 0" +"origin" "-7242 -3626.56 613.868" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 172.826 0" +"origin" "-8034.04 -3907.92 612.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -16.281 0" +"origin" "-8775.36 -3606.64 612.36" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -21.388 0" +"origin" "-8728.06 -3723.08 612.36" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -16.725 0" +"origin" "-8815.03 -3338.83 612.36" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -16.725 0" +"origin" "-8472.9 -3035.34 612.361" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -16.725 0" +"origin" "-8565.71 -3076.37 612.361" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -14.902 0" +"origin" "-8536.68 -3642.07 612.36" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 150.096 0" +"origin" "-6212.22 -1136.77 547.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 150.096 0" +"origin" "-6376.93 -1153.07 548.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 150.096 0" +"origin" "-6414.51 -1276.82 548.001" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 150.096 0" +"origin" "-6223.32 -1303.52 547.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 169.832 0" +"origin" "-5966.13 -1125.8 547.999" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -38.38 0" +"origin" "-5580.96 453.289 612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -11.798 0" +"origin" "-5505.55 126.512 608" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -23.195 0" +"origin" "-5691.8 369.818 608" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 179.146 0" +"origin" "-5036.52 317.736 612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 168.352 0" +"origin" "-5023.53 106.622 611.999" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 139.991 0" +"origin" "-4948.58 -138.127 612" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 175.641 0" +"origin" "-4429.96 -6.77726 602.128" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -174.096 0" +"origin" "-4064.05 -2378.34 745.168" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 0 0" +"origin" "-5046.06 -2380.52 745.707" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 133.798 0" +"origin" "-2495.17 -3816.94 676" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 177.129 0" +"origin" "-2066.1 -3675.86 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 179.93 0" +"origin" "-2192.01 -2920.02 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 88.3595 0" +"origin" "-2666.73 -3245.09 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -99.291 0" +"origin" "-2636.56 -2930.83 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -99.69 0" +"origin" "-2271.33 -2856.08 676" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -99.291 0" +"origin" "-2536.56 -2538.83 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 93.3102 0" +"origin" "-2538.32 -2696.92 676" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 121.451 0" +"origin" "-2235.09 -2639.19 675.999" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "98" +"scale" "1" +"angles" "0 -4.3496 0" +"origin" "-4401.73 -4281.28 677.088" +"classname" "info_node_cover_left" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "80" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "99" +"scale" "1" +"angles" "0 -19.849 0" +"origin" "-4269.17 -4009.47 676.992" +"classname" "info_node_cover_right" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 12.1031 0" +"origin" "-4586.41 -4582 677.095" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 12.1031 0" +"origin" "-4728.61 -4679.2 805" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -17.189 0" +"origin" "-4572.98 -4366.2 676.992" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.1009 0" +"origin" "-3993.2 -4718.89 676.992" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 45.1009 0" +"origin" "-3937.2 -4774.89 676.992" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -138.479 0" +"origin" "-3158.38 -3881.2 676.992" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "100" +"scale" "1" +"angles" "0 -138.479 0" +"origin" "-3102.38 -3937.2 676.992" +"classname" "info_node_cover_stand" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 46.1752 0" +"origin" "-3862.58 -4359.17 676.991" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 -133.625 0" +"origin" "-3489.45 -4008.82 676.991" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 135.596 0" +"origin" "-3206.01 -4144.01 676.991" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 135.596 0" +"origin" "-3781.91 -4714.67 676.994" +"classname" "info_node_cover_crouch" +} +{ +"TargetNode" "-1" +"spawnflags" "0" +"nodeFOV" "120" +"MinimumState" "1" +"MaximumState" "3" +"IgnoreFacing" "2" +"hinttype" "101" +"scale" "1" +"angles" "0 135.596 0" +"origin" "-3669.82 -4608.87 676.989" +"classname" "info_node_cover_crouch" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 90 2.53193e-006" +"origin" "-5243 -3233 712" +"powerUpType" "mp_loot_titan_build_credit_lts" +"classname" "script_ref" +} +{ +"editorclass" "script_power_up_other" +"model" "models/communication/flag_base_red.mdl" +"scale" "1" +"angles" "0 90 2.53193e-006" +"origin" "-4492.01 -1536.57 692.025" +"powerUpType" "mp_loot_titan_build_credit_lts" +"classname" "script_ref" +} +{ +"origin" "-6146 -1892 -110" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 -0 -0 -2618" +"*trigger_brush_0_plane_1" "1 -0 -0 3002" +"*trigger_brush_0_plane_2" "0 -1 0 -2132" +"*trigger_brush_0_plane_3" "-0 1 0 3824" +"*trigger_brush_0_plane_4" "-0 -0 -1 618" +"*trigger_brush_0_plane_5" "-0 0 1 618" +"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 852.77075" +"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 -3358.7573" +"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 615.18298" +"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 4826.7109" +"*trigger_brush_1_plane_0" "-1 -0 -0 -2618" +"*trigger_brush_1_plane_1" "1 -0 -0 3002" +"*trigger_brush_1_plane_2" "0 -1 0 3824" +"*trigger_brush_1_plane_3" "0 1 0 1844" +"*trigger_brush_1_plane_4" "-0 -0 -1 618" +"*trigger_brush_1_plane_5" "-0 0 1 618" +"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 -547.30066" +"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 0 852.77075" +"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 4826.7109" +"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 3426.6396" +"*trigger_brush_2_plane_0" "-1 0 0 -3002" +"*trigger_brush_2_plane_1" "1 -0 0 4578" +"*trigger_brush_2_plane_2" "0 -1 0 3824" +"*trigger_brush_2_plane_3" "-0 1 0 3824" +"*trigger_brush_2_plane_4" "-0 -0 -1 618" +"*trigger_brush_2_plane_5" "-0 0 1 618" +"*trigger_brush_2_plane_6" "-0.70710677 0.70710677 0 581.2417" +"*trigger_brush_2_plane_7" "-0.70710677 -0.70710677 0 581.2417" +"*trigger_brush_2_plane_8" "0.70710677 -0.70710677 0 5941.1113" +"*trigger_brush_2_plane_9" "0.70710677 0.70710677 0 5941.1113" +"*trigger_brush_3_plane_0" "-1 -0 -0 4578" +"*trigger_brush_3_plane_1" "1 0 0 2618" +"*trigger_brush_3_plane_2" "0 -1 0 3824" +"*trigger_brush_3_plane_3" "-0 1 0 3824" +"*trigger_brush_3_plane_4" "-0 -0 -1 618" +"*trigger_brush_3_plane_5" "-0 0 1 618" +"*trigger_brush_3_plane_6" "-0.70710677 0.70710677 0 5941.1113" +"*trigger_brush_3_plane_7" "-0.70710677 -0.70710677 0 5941.1113" +"*trigger_brush_3_plane_8" "0.70710677 -0.70710677 0 4555.1816" +"*trigger_brush_3_plane_9" "0.70710677 0.70710677 0 4555.1816" +"*trigger_brush_4_plane_0" "-1 -0 -0 -2618" +"*trigger_brush_4_plane_1" "1 -0 -0 3002" +"*trigger_brush_4_plane_2" "-0 -1 -0 -1844" +"*trigger_brush_4_plane_3" "-0 1 -0 2132" +"*trigger_brush_4_plane_4" "-0 -0 -1 618" +"*trigger_brush_4_plane_5" "0 -0 1 594" +"*trigger_brush_4_plane_6" "-0.70710677 0.70710677 -0 -343.65393" +"*trigger_brush_4_plane_7" "-0.70710677 -0.70710677 -0 -3155.1104" +"*trigger_brush_4_plane_8" "0.70710677 -0.70710677 -0 818.82971" +"*trigger_brush_4_plane_9" "0.70710677 0.70710677 -0 3630.2861" +"*trigger_bounds_mins" "-4578 -3824 -618" +"*trigger_bounds_maxs" "4578 3824 618" +} +{ +"origin" "-7697.6 -3277.22 2118" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 455.62012" +"*trigger_brush_0_plane_1" "1 0 0 455.61328" +"*trigger_brush_0_plane_2" "0 -1 0 513.23438" +"*trigger_brush_0_plane_3" "0 1 0 513.2417" +"*trigger_brush_0_plane_4" "0 -0 -1 182" +"*trigger_brush_0_plane_5" "-0 -0 1 182" +"*trigger_brush_0_plane_6" "-0.98972714 0.14296904 0 393.67426" +"*trigger_brush_0_plane_7" "0.14312822 0.98970413 0 461.63812" +"*trigger_brush_0_plane_8" "0.98972714 -0.14296904 0 393.66644" +"*trigger_brush_0_plane_9" "-0.14312822 -0.98970413 -0 461.63187" +"*trigger_brush_0_plane_10" "-0.98972714 0.14296903 0 393.67426" +"*trigger_brush_0_plane_11" "0.14312823 0.98970425 -0 461.63818" +"*trigger_brush_0_plane_12" "0.98972714 -0.14296903 0 393.66644" +"*trigger_brush_0_plane_13" "-0.14312823 -0.98970425 -0 461.6319" +"*trigger_brush_0_plane_14" "-0.59868395 0.80098528 0 604.84576" +"*trigger_brush_0_plane_15" "-0.80098528 -0.59868395 0 604.74408" +"*trigger_brush_0_plane_16" "0.80098528 0.59868395 0 604.74304" +"*trigger_brush_0_plane_17" "0.59868395 -0.80098528 0 604.83582" +"*trigger_bounds_mins" "-455.62012 -513.23438 -182" +"*trigger_bounds_maxs" "455.61328 513.2417 182" +} +{ +"origin" "-10901 -6447.86 1272" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 3209.627" +"*trigger_brush_0_plane_1" "1 0 0 3209.6821" +"*trigger_brush_0_plane_2" "0 -1 0 1600.1504" +"*trigger_brush_0_plane_3" "0 1 0 1600.1563" +"*trigger_brush_0_plane_4" "0 0 -1 2132" +"*trigger_brush_0_plane_5" "-0 0 1 2132" +"*trigger_brush_0_plane_6" "-0.93357444 0.35838348 0 3260.9895" +"*trigger_brush_0_plane_7" "0.35853338 0.93351692 0 461.64783" +"*trigger_brush_0_plane_8" "0.93357444 -0.35838348 0 3261.0391" +"*trigger_brush_0_plane_9" "-0.35853338 -0.93351692 -0 461.62238" +"*trigger_brush_0_plane_10" "-0.93357456 0.35838351 0 3260.99" +"*trigger_brush_0_plane_11" "0.93357456 -0.35838351 0 3261.0396" +"*trigger_brush_0_plane_12" "-0.40664804 0.91358483 0 2632.5132" +"*trigger_brush_0_plane_13" "-0.91358477 -0.40664807 0 2632.0728" +"*trigger_brush_0_plane_14" "0.91358477 0.40664807 0 2632.1255" +"*trigger_brush_0_plane_15" "0.40664804 -0.91358483 0 2632.5305" +"*trigger_bounds_mins" "-3209.627 -1600.1503 -2132" +"*trigger_bounds_maxs" "3209.6821 1600.1563 2132" +} +{ +"origin" "-12224.3 -2684.64 1302" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 1919.71" +"*trigger_brush_0_plane_1" "1 0 0 1919.6924" +"*trigger_brush_0_plane_2" "0 -1 0 2792.1941" +"*trigger_brush_0_plane_3" "0 1 0 2792.1877" +"*trigger_brush_0_plane_4" "0 0 -1 2162" +"*trigger_brush_0_plane_5" "0 -0 1 2162" +"*trigger_brush_0_plane_6" "0.35838318 0.93357456 0 2582.3491" +"*trigger_brush_0_plane_7" "0.93351686 -0.35853344 0 1064.5466" +"*trigger_brush_0_plane_8" "-0.3583833 -0.93357456 -0 2582.3618" +"*trigger_brush_0_plane_9" "-0.93351692 0.35853329 0 1064.5614" +"*trigger_brush_0_plane_10" "0.93351698 -0.35853344 0 1064.5468" +"*trigger_brush_0_plane_11" "-0.35838333 -0.93357462 -0 2582.3618" +"*trigger_brush_0_plane_12" "-0.93351704 0.35853329 0 1064.5614" +"*trigger_brush_0_plane_13" "0.91358483 0.40664819 0 2578.9524" +"*trigger_brush_0_plane_14" "-0.40664828 0.91358477 0 2578.5479" +"*trigger_brush_0_plane_15" "0.4066481 -0.91358483 0 2578.5464" +"*trigger_brush_0_plane_16" "-0.91358471 -0.40664825 0 2578.9709" +"*trigger_bounds_mins" "-1919.7101 -2792.1941 -2162" +"*trigger_bounds_maxs" "1919.6924 2792.1877 2162" +} +{ +"origin" "-9678.93 1486.6 1272" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 1984.2383" +"*trigger_brush_0_plane_1" "1 0 0 1984.2451" +"*trigger_brush_0_plane_2" "0 -1 0 2092.8115" +"*trigger_brush_0_plane_3" "0 1 0 2092.8159" +"*trigger_brush_0_plane_4" "0 0 -1 2132" +"*trigger_brush_0_plane_5" "-0 0 1 2132" +"*trigger_brush_0_plane_6" "0.66694921 0.74510318 0 2141.3713" +"*trigger_brush_0_plane_7" "0.74499589 -0.66706908 0 745.94049" +"*trigger_brush_0_plane_8" "-0.66694921 -0.74510318 -0 2141.3635" +"*trigger_brush_0_plane_9" "-0.74499589 0.66706902 0 745.93823" +"*trigger_brush_0_plane_10" "-0.66694921 -0.74510324 -0 2141.3635" +"*trigger_brush_0_plane_11" "-0.74499595 0.66706908 0 745.93829" +"*trigger_bounds_mins" "-1984.2383 -2092.8115 -2132" +"*trigger_bounds_maxs" "1984.2452 2092.8157 2132" +} +{ +"origin" "-6096.88 -6585.13 3646" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 186.99512" +"*trigger_brush_0_plane_1" "1 0 0 187.00488" +"*trigger_brush_0_plane_2" "0 -1 0 195.37012" +"*trigger_brush_0_plane_3" "0 1 0 195.37988" +"*trigger_brush_0_plane_4" "0 0 -1 1534" +"*trigger_brush_0_plane_5" "-0 0 1 1534" +"*trigger_brush_0_plane_6" "-0.93360478 0.35830453 0 140.7215" +"*trigger_brush_0_plane_7" "0.35880053 0.93341428 0 155.19298" +"*trigger_brush_0_plane_8" "0.93355304 -0.35843927 0 140.74951" +"*trigger_brush_0_plane_9" "-0.35841355 -0.93356293 -0 155.23872" +"*trigger_brush_0_plane_10" "-0.93360478 0.35830456 0 140.7215" +"*trigger_brush_0_plane_11" "0.9335531 -0.35843927 0 140.74953" +"*trigger_brush_0_plane_12" "-0.35841355 -0.93356299 -0 155.23874" +"*trigger_brush_0_plane_13" "-0.40655595 0.91362584 0 209.29874" +"*trigger_brush_0_plane_14" "-0.91354162 -0.40674537 0 209.26328" +"*trigger_brush_0_plane_15" "0.91365522 0.40649006 0 209.22247" +"*trigger_brush_0_plane_16" "0.40667942 -0.91357088 0 209.2924" +"*trigger_bounds_mins" "-186.99512 -195.37012 -1534" +"*trigger_bounds_maxs" "187.00488 195.37988 1534" +} +{ +"origin" "-5132.81 -6293.13 3646" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 96.314941" +"*trigger_brush_0_plane_1" "1 0 0 96.310059" +"*trigger_brush_0_plane_2" "0 -1 0 95.370117" +"*trigger_brush_0_plane_3" "0 1 0 95.379883" +"*trigger_brush_0_plane_4" "0 0 -1 1534" +"*trigger_brush_0_plane_5" "-0 0 1 1534" +"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144" +"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734" +"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016" +"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137" +"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734" +"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168" +"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129" +"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502" +"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621" +"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583" +"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292" +"*trigger_bounds_mins" "-96.314941 -95.370117 -1534" +"*trigger_bounds_maxs" "96.310059 95.379883 1534" +} +{ +"origin" "-5816.81 -7577.13 3646" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 96.314941" +"*trigger_brush_0_plane_1" "1 0 0 96.310059" +"*trigger_brush_0_plane_2" "0 -1 0 95.370117" +"*trigger_brush_0_plane_3" "0 1 0 95.379883" +"*trigger_brush_0_plane_4" "0 0 -1 1534" +"*trigger_brush_0_plane_5" "-0 0 1 1534" +"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144" +"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734" +"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016" +"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137" +"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734" +"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168" +"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129" +"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502" +"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621" +"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583" +"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292" +"*trigger_bounds_mins" "-96.314941 -95.370117 -1534" +"*trigger_bounds_maxs" "96.310059 95.379883 1534" +} +{ +"origin" "-7132.81 -7741.13 3646" +"triggerNearbyRadius" "0" +"triggerFilterTeamOther" "1" +"triggerFilterTeamNeutral" "1" +"triggerFilterTeamMilitia" "1" +"triggerFilterTeamIMC" "1" +"triggerFilterTeamBeast" "1" +"triggerFilterPlayer" "all" +"triggerFilterPhaseShift" "any" +"triggerFilterNpcOwnedByPlayer" "any" +"triggerFilterNpcFlip" "0" +"triggerFilterNpc" "all" +"triggerFilterNonCharacter" "0" +"StartDisabled" "0" +"spawnflags" "4099" +"nodmgforce" "1" +"mobility_3_hard" "1" +"mobility_2_normal" "1" +"mobility_1_easy" "1" +"damageSourceName" "fall" +"damagemodel" "0" +"damagecap" "20" +"damage" "10000" +"triggerFilterUseNew" "1" +"classname" "trigger_hurt" +"*trigger_brush_0_plane_0" "-1 0 0 96.314941" +"*trigger_brush_0_plane_1" "1 0 0 96.310059" +"*trigger_brush_0_plane_2" "0 -1 0 95.370117" +"*trigger_brush_0_plane_3" "0 1 0 95.379883" +"*trigger_brush_0_plane_4" "0 0 -1 1534" +"*trigger_brush_0_plane_5" "-0 0 1 1534" +"*trigger_brush_0_plane_6" "-0.93378407 0.35783696 0 75.044144" +"*trigger_brush_0_plane_7" "0.3588675 0.93338853 0 73.302734" +"*trigger_brush_0_plane_8" "0.93338954 -0.35886484 0 75.00016" +"*trigger_brush_0_plane_9" "-0.35842046 -0.93356025 -0 73.376137" +"*trigger_brush_0_plane_10" "0.3588675 0.93338859 -0 73.302734" +"*trigger_brush_0_plane_11" "0.9333896 -0.35886484 0 75.000168" +"*trigger_brush_0_plane_12" "-0.35842046 -0.93356031 -0 73.376129" +"*trigger_brush_0_plane_13" "-0.40675199 0.91353858 0 104.95502" +"*trigger_brush_0_plane_14" "-0.91344124 -0.40697074 0 104.91621" +"*trigger_brush_0_plane_15" "0.91376239 0.40624902 0 104.86583" +"*trigger_brush_0_plane_16" "0.40646777 -0.91366512 0 104.89292" +"*trigger_bounds_mins" "-96.314941 -95.370117 -1534" +"*trigger_bounds_maxs" "96.310059 95.379883 1534" +} + \ No newline at end of file -- cgit v1.2.3 From 9605106b0f0530c5383aa89d3ec884e72c8d7c3e Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 2 Oct 2023 19:12:19 -0300 Subject: Fix players dying when mantling on props or embarking Titans in `mp_complex3` (#709) There's a whole `trigger_hurt` right below the ground in the inner large hallway which whenever a player tries to mantle on any of the props in there either intentionally or by accident they will instantly die. This also applies to when you embark your titan in there. This does not happen on vanilla servers. This commit removes the trigger that kills the player. --- .../mod/maps/mp_complex3_script.ent | 79 ---------------------- 1 file changed, 79 deletions(-) diff --git a/Northstar.CustomServers/mod/maps/mp_complex3_script.ent b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent index ce8b0bff..df26fd80 100644 --- a/Northstar.CustomServers/mod/maps/mp_complex3_script.ent +++ b/Northstar.CustomServers/mod/maps/mp_complex3_script.ent @@ -12869,85 +12869,6 @@ ENTITIES01 "classname" "script_ref" } { -"origin" "-6146 -1892 -110" -"triggerNearbyRadius" "0" -"triggerFilterTeamOther" "1" -"triggerFilterTeamNeutral" "1" -"triggerFilterTeamMilitia" "1" -"triggerFilterTeamIMC" "1" -"triggerFilterTeamBeast" "1" -"triggerFilterPlayer" "all" -"triggerFilterPhaseShift" "any" -"triggerFilterNpcOwnedByPlayer" "any" -"triggerFilterNpcFlip" "0" -"triggerFilterNpc" "all" -"triggerFilterNonCharacter" "0" -"StartDisabled" "0" -"spawnflags" "4099" -"nodmgforce" "1" -"mobility_3_hard" "1" -"mobility_2_normal" "1" -"mobility_1_easy" "1" -"damageSourceName" "fall" -"damagemodel" "0" -"damagecap" "20" -"damage" "10000" -"triggerFilterUseNew" "1" -"classname" "trigger_hurt" -"*trigger_brush_0_plane_0" "-1 -0 -0 -2618" -"*trigger_brush_0_plane_1" "1 -0 -0 3002" -"*trigger_brush_0_plane_2" "0 -1 0 -2132" -"*trigger_brush_0_plane_3" "-0 1 0 3824" -"*trigger_brush_0_plane_4" "-0 -0 -1 618" -"*trigger_brush_0_plane_5" "-0 0 1 618" -"*trigger_brush_0_plane_6" "-0.70710677 0.70710677 0 852.77075" -"*trigger_brush_0_plane_7" "-0.70710677 -0.70710677 0 -3358.7573" -"*trigger_brush_0_plane_8" "0.70710677 -0.70710677 0 615.18298" -"*trigger_brush_0_plane_9" "0.70710677 0.70710677 0 4826.7109" -"*trigger_brush_1_plane_0" "-1 -0 -0 -2618" -"*trigger_brush_1_plane_1" "1 -0 -0 3002" -"*trigger_brush_1_plane_2" "0 -1 0 3824" -"*trigger_brush_1_plane_3" "0 1 0 1844" -"*trigger_brush_1_plane_4" "-0 -0 -1 618" -"*trigger_brush_1_plane_5" "-0 0 1 618" -"*trigger_brush_1_plane_6" "-0.70710677 0.70710677 0 -547.30066" -"*trigger_brush_1_plane_7" "-0.70710677 -0.70710677 0 852.77075" -"*trigger_brush_1_plane_8" "0.70710677 -0.70710677 0 4826.7109" -"*trigger_brush_1_plane_9" "0.70710677 0.70710677 0 3426.6396" -"*trigger_brush_2_plane_0" "-1 0 0 -3002" -"*trigger_brush_2_plane_1" "1 -0 0 4578" -"*trigger_brush_2_plane_2" "0 -1 0 3824" -"*trigger_brush_2_plane_3" "-0 1 0 3824" -"*trigger_brush_2_plane_4" "-0 -0 -1 618" -"*trigger_brush_2_plane_5" "-0 0 1 618" -"*trigger_brush_2_plane_6" "-0.70710677 0.70710677 0 581.2417" -"*trigger_brush_2_plane_7" "-0.70710677 -0.70710677 0 581.2417" -"*trigger_brush_2_plane_8" "0.70710677 -0.70710677 0 5941.1113" -"*trigger_brush_2_plane_9" "0.70710677 0.70710677 0 5941.1113" -"*trigger_brush_3_plane_0" "-1 -0 -0 4578" -"*trigger_brush_3_plane_1" "1 0 0 2618" -"*trigger_brush_3_plane_2" "0 -1 0 3824" -"*trigger_brush_3_plane_3" "-0 1 0 3824" -"*trigger_brush_3_plane_4" "-0 -0 -1 618" -"*trigger_brush_3_plane_5" "-0 0 1 618" -"*trigger_brush_3_plane_6" "-0.70710677 0.70710677 0 5941.1113" -"*trigger_brush_3_plane_7" "-0.70710677 -0.70710677 0 5941.1113" -"*trigger_brush_3_plane_8" "0.70710677 -0.70710677 0 4555.1816" -"*trigger_brush_3_plane_9" "0.70710677 0.70710677 0 4555.1816" -"*trigger_brush_4_plane_0" "-1 -0 -0 -2618" -"*trigger_brush_4_plane_1" "1 -0 -0 3002" -"*trigger_brush_4_plane_2" "-0 -1 -0 -1844" -"*trigger_brush_4_plane_3" "-0 1 -0 2132" -"*trigger_brush_4_plane_4" "-0 -0 -1 618" -"*trigger_brush_4_plane_5" "0 -0 1 594" -"*trigger_brush_4_plane_6" "-0.70710677 0.70710677 -0 -343.65393" -"*trigger_brush_4_plane_7" "-0.70710677 -0.70710677 -0 -3155.1104" -"*trigger_brush_4_plane_8" "0.70710677 -0.70710677 -0 818.82971" -"*trigger_brush_4_plane_9" "0.70710677 0.70710677 -0 3630.2861" -"*trigger_bounds_mins" "-4578 -3824 -618" -"*trigger_bounds_maxs" "4578 3824 618" -} -{ "origin" "-7697.6 -3277.22 2118" "triggerNearbyRadius" "0" "triggerFilterTeamOther" "1" -- cgit v1.2.3 From 9864becc72543206f2d2b1305aed7041b81e1c4b Mon Sep 17 00:00:00 2001 From: EnderBoy9217 <122132914+EnderBoy9217@users.noreply.github.com> Date: Tue, 3 Oct 2023 18:02:03 -0400 Subject: Fix integer functionality for modsettings (#718) Add missing break statement --- Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut index a45082c7..8c13955c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mod_settings.nut @@ -949,6 +949,7 @@ void function SendTextPanelChanges( var textPanel ) ThrowInvalidValue( "This setting is an integer, and only accepts whole numbers." ) Hud_SetText( textPanel, GetConVarString( c.conVar ) ) } + break case "bool": if ( newSetting != "0" && newSetting != "1" ) { -- cgit v1.2.3 From 0dda99e77f9f1d7724a2fec11b4fab48b2f62456 Mon Sep 17 00:00:00 2001 From: Respawn Date: Wed, 4 Oct 2023 00:31:55 +0200 Subject: Add chatroom.nut from englishclient_frontend --- .../mod/scripts/vscripts/ui/chatroom.nut | 902 +++++++++++++++++++++ 1 file changed, 902 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut diff --git a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut new file mode 100644 index 00000000..b474f7a6 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut @@ -0,0 +1,902 @@ +untyped + +global function Chatroom_GlobalInit +global function InitChatroom +global function UpdateChatroomUI +global function UICodeCallback_ShowUserInfo +global function UICodeCallback_RemoteMatchInfoUpdated +global function UICodeCallback_SetChatroomMode +global function UpdateOpenInvites +global function HideOpenInvite +global function ShowOpenInvite +global function FillInUserInfoPanel +global function UpdateChatroomThread +global function IsVoiceChatPushToTalk + +global function bsupdate + +global const LOBBY_MATERIAL_OWNER = $"rui/menu/common/lobby_icon_owner" +global const LOBBY_MATERIAL_ADMIN = $"rui/menu/common/lobby_icon_admin" + +struct RemoteMatchPlayerInfoRow +{ + var playerPanel + var name + var score + var kills + var deaths +} + +struct RemoteMatchInfoPanel +{ + var panel + var PlaylistName + var MapName + var ModeName + var TimeLeft + var ScoreLimit + var Team1Score + var Team2Score + array team1Players + array team2Players +} + +struct OpenInviteUI +{ + var openInviteJoinButton + var openInvitePanel + var openInviteMessage + var openInviteCountdownText + array openInvitePlayerSlots + array openInvitePlaylistSlots +} + +global struct UserInfoPanel +{ + var Panel + var Name + var Kills + var Wins + var Losses + var Deaths + var XP + var callsignCard + array communityLabels + array communityNames +} + +struct ChatroomWidget +{ + var chatroomPanel + var chatroomWidget + var chatroomTextChat + + var chatroomBackground + var chatroomDivider + var chatroomHappyHour + var chatroomMode + + UserInfoPanel userInfoPanel + + RemoteMatchInfoPanel remoteMatchInfoPanelWidgets + + var communityChatroomModeButton + var chatroomHintText + var happyHourTimeLeft + + OpenInviteUI openInviteUI +} + +struct +{ + string userInfoPanel_hardware = "" + string userInfoPanel_userId = "0" + var communityChatroomMode + bool currentUserIsStreaming = false + array chatroomUIs + bool hasFocus +} file + +bool function IsVoiceChatPushToTalk() +{ + if ( GetPartySize() > 1 ) + return true + return DoesCurrentCommunitySupportChat() +} + +void function UICodeCallback_SetChatroomMode( string mode ) +{ + file.communityChatroomMode = mode + UpdateChatroomUI() +} + +void function UpdateChatroomUI() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + if ( file.communityChatroomMode == "chatroom" ) + { + int communityId = GetCurrentCommunityId() + CommunitySettings ornull communitySettings = GetCommunitySettings( communityId ) + + string communityName + if ( communitySettings != null ) + { + expect CommunitySettings( communitySettings ) + communityName = GetCurrentCommunityName() + " [" + communitySettings.clanTag + "]" + } + else + { + communityName = expect string( GetCurrentCommunityName() ) + } + + if ( IsChatroomMuted() ) + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM_MUTED", communityName ) ) + else + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_CHATROOM", communityName ) ) + } + else if ( file.communityChatroomMode == "party" ) + { + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( "#COMMUNITY_PARTY", GetPartyLeaderName() ) ) + } + else + { + SetLabelRuiText( chatroomUI.communityChatroomModeButton, Localize( file.communityChatroomMode ) ) + } + + int meritsLeft = GetHappyHourMeritsLeft() + if ( meritsLeft == 0 ) + { + SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( "#HAPPYHOUR_NOMERITSLEFT", meritsLeft ) ) + SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", "" ) + //SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_ACTIVE_01" ) ) + } + else if ( meritsLeft >= 1 ) + { + SetLabelRuiText( chatroomUI.happyHourTimeLeft, Localize( GetHappyHourStatus() ) ) + SetNamedRuiText( chatroomUI.happyHourTimeLeft, "happyHourHintString", Localize( "#HAPPYHOUR_HINT_MERITS", 5 ) ) + } + UICodeCallback_ShowUserInfo( file.userInfoPanel_hardware, file.userInfoPanel_userId ) + } + + UpdateFooterOptions() +} + +bool function FillInCommunityMembership( UserInfoPanel userInfoPanel, CommunityMembership membershipData, int communityIndex ) +{ + if ( userInfoPanel.communityNames.len() <= communityIndex ) + return false; + + string title + title = "[" + membershipData.communityClantag + "] " + Localize( membershipData.communityName ); + + if ( membershipData.membershipLevel == "owner" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_OWNER" ) + else if ( membershipData.membershipLevel == "admin" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_ADMIN" ) + else if ( membershipData.membershipLevel == "member" ) + Hud_SetText( userInfoPanel.communityLabels[communityIndex], "#COMMUNITY_MEMBERSHIP_MEMBER" ) + else + Assert( false, "Unknown membership level " + membershipData.membershipLevel + " in FillInCommunityMembership" ) + + Hud_SetText( userInfoPanel.communityNames[communityIndex], title ) + Hud_Show( userInfoPanel.communityLabels[communityIndex] ); + Hud_Show( userInfoPanel.communityNames[communityIndex] ); + + return true +} + +void function FillInUserInfoPanel( UserInfoPanel userInfoPanel, CommunityUserInfo userInfo ) +{ + file.currentUserIsStreaming = userInfo.isLivestreaming + + Hud_SetText( userInfoPanel.Name, userInfo.name ) + string killsText = "" + userInfo.kills + Hud_SetText( userInfoPanel.Kills, killsText ) + string winsText = "" + userInfo.wins + Hud_SetText( userInfoPanel.Wins, winsText ) + string lossesText = "" + userInfo.losses + Hud_SetText( userInfoPanel.Losses, lossesText ) + string deathsText = "" + userInfo.deaths + Hud_SetText( userInfoPanel.Deaths, deathsText ) + string xpText = ShortenNumber( userInfo.xp ) + Hud_EnableKeyBindingIcons( userInfoPanel.XP ) + Hud_SetText( userInfoPanel.XP, Localize( "#CREDITSIGN_N", xpText ) ) + + CallingCard callingCard = CallingCard_GetByIndex( userInfo.callingCardIdx ) + CallsignIcon callsignIcon = CallsignIcon_GetByIndex( userInfo.callSignIdx ) + + var card = userInfoPanel.callsignCard + var rui = Hud_GetRui( userInfoPanel.callsignCard ) + RuiSetImage( rui, "cardImage", callingCard.image ) + RuiSetImage( rui, "iconImage", callsignIcon.image ) + RuiSetInt( rui, "layoutType", callingCard.layoutType ) + RuiSetImage( rui, "cardGenImage", GetGenIcon( userInfo.gen, userInfo.lvl ) ) + RuiSetString( rui, "playerLevel", PlayerXPDisplayGenAndLevel( userInfo.gen, userInfo.lvl ) ) + RuiSetString( rui, "playerName", userInfo.name ) + + array ownerCommunities + array adminCommunities + array memberCommunities + + for ( int i = 0; i < userInfo.numCommunities; i++ ) + { + CommunityMembership ornull communityInfo = GetCommunityUserMembershipInfo( userInfo.hardware, userInfo.uid, i ) + if ( !communityInfo ) + continue; + expect CommunityMembership( communityInfo ) + string membershipLevel = communityInfo.membershipLevel + if ( membershipLevel == "owner" ) + { + ownerCommunities.append( communityInfo ) + } + else if ( membershipLevel == "admin" ) + { + adminCommunities.append( communityInfo ) + } + else if ( membershipLevel == "member" ) + { + memberCommunities.append( communityInfo ) + } + else + { + printt( "Unknown membershipLevel " + membershipLevel ) + Assert( false, "Unknown membershipLevel" ) + } + } + + array allCommunities + for ( int i = 0; i < ownerCommunities.len(); i++ ) + allCommunities.append( ownerCommunities[i] ) + for ( int i = 0; i < adminCommunities.len(); i++ ) + allCommunities.append( adminCommunities[i] ) + for ( int i = 0; i < memberCommunities.len(); i++ ) + allCommunities.append( memberCommunities[i] ) + + int currentCommunityIndex = 0 + for ( ; currentCommunityIndex < allCommunities.len(); currentCommunityIndex++ ) + { + if ( !FillInCommunityMembership( userInfoPanel, allCommunities[currentCommunityIndex], currentCommunityIndex ) ) + break; + } + + for ( ; currentCommunityIndex < userInfoPanel.communityNames.len(); currentCommunityIndex++ ) + { + Hud_Hide( userInfoPanel.communityLabels[currentCommunityIndex] ); + Hud_Hide( userInfoPanel.communityNames[currentCommunityIndex] ); + } + + UpdateFooterOptions() +} + +void function GetUserInfoThread( string hardware, string userId ) +{ + EndSignal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + + printt( "getting userinfo for user " + userId ) + + CommunityUserInfo fakeSettings + fakeSettings.name = Localize( "#COMMUNITY_FETCHING" ) + foreach ( chatroomUI in file.chatroomUIs ) + FillInUserInfoPanel( chatroomUI.userInfoPanel, fakeSettings ) + + while ( true ) + { + printt( "asking for userinfo for " + hardware + "=" + userId ) + + CommunityUserInfo ornull userInfo = GetCommunityUserInfo( hardware, userId ) + if ( !userInfo ) + { + wait 0.05 + } + else + { + printt( "Got user info for user " + userId + " on hardware " + hardware ) + expect CommunityUserInfo( userInfo ) + + printt( "User " + userId + " is in " + userInfo.numCommunities + " communities" ) + + foreach ( chatroomUI in file.chatroomUIs ) + FillInUserInfoPanel( chatroomUI.userInfoPanel, userInfo ) + break + } + } +} + + +void function UICodeCallback_ShowUserInfo( string hardware, string userId ) +{ + Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + + printt( "Showing user info for UID " + userId + " on hardware " + hardware ) + + file.userInfoPanel_userId = userId + file.userInfoPanel_hardware = hardware + + if ( hardware == "" && userId == "0" ) + { + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.userInfoPanel.Panel ) + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatrooUI.chatroomHeader, Hud_GetBaseWidth( chatrooUI.chatroomHeader ) ) + // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) ) + #if CONSOLE_PROG + Hud_Show( chatroomUI.chatroomHintText ) + #else + Hud_Show( chatroomUI.chatroomTextChat ) + #endif + } + } + else + { + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Show( chatroomUI.userInfoPanel.Panel ) + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + Hud_Hide( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatroomUI.chatroomHeader, Hud_GetBaseWidth( chatroomUI.chatroomHeader ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + #if CONSOLE_PROG + Hud_Hide( chatroomUI.chatroomHintText ) + #else + Hud_Hide( chatroomUI.chatroomTextChat ) + #endif + } + + thread GetUserInfoThread( hardware, userId ) + } +} + +void function FindRemoteMatchInfoWidgetsInPanel( RemoteMatchInfoPanel infostruct, var panel ) +{ + infostruct.PlaylistName = Hud_GetChild( panel, "PlaylistName" ) + infostruct.MapName = Hud_GetChild( panel, "MapName" ) + infostruct.ModeName = Hud_GetChild( panel, "ModeName" ) + infostruct.TimeLeft = Hud_GetChild( panel, "TimeLeft" ) + infostruct.ScoreLimit = Hud_GetChild( panel, "ScoreLimit" ) + infostruct.Team1Score = Hud_GetChild( panel, "Team1Score" ) + infostruct.Team2Score = Hud_GetChild( panel, "Team2Score" ) + for ( int i = 1; i <= 2; i++ ) + { + array teamPlayers + if ( i == 1 ) + teamPlayers = infostruct.team1Players + else + teamPlayers = infostruct.team2Players + + for ( int j = 1; j <= 8; j++ ) + { + RemoteMatchPlayerInfoRow teamPlayer + string key = "Team" + i + "Player" + j + teamPlayer.playerPanel = Hud_GetChild( panel, key ) + teamPlayer.name = Hud_GetChild( teamPlayer.playerPanel, "Name" ) + teamPlayer.score = Hud_GetChild( teamPlayer.playerPanel, "Score" ) + teamPlayer.kills = Hud_GetChild( teamPlayer.playerPanel, "Kills" ) + teamPlayer.deaths = Hud_GetChild( teamPlayer.playerPanel, "Deaths" ) + teamPlayers.append( teamPlayer ) + } + } +} + +int function RemoteMatchInfoPlayerSort( RemoteClientInfoFromMatchInfo a, RemoteClientInfoFromMatchInfo b ) +{ + return ( b.score - a.score ) +} + +void function FillInRemoteMatchInfoPanel( RemoteMatchInfo info, RemoteMatchInfoPanel panel ) +{ + Hud_Show( panel.panel ) + + Hud_SetText( panel.PlaylistName, GetPlaylistDisplayName( info.playlist ) ) + Hud_SetText( panel.MapName, Localize( "#" + info.map ) ) + + string modeName + + if ( IsFDMode( info.gamemode ) ) + { + modeName = "#GAMEMODE_COOP" + // HACK because fd has multiple gamemodes in playlists + } + else + { + modeName = GAMETYPE_TEXT[ info.gamemode ] + } + + if ( IsFullyConnected() ) + modeName = GetGameModeDisplayName( info.gamemode ) + + Hud_SetText( panel.ModeName, modeName ) + int minsLeft = info.timeLeftSecs / 60 + int secsLeft = info.timeLeftSecs % 60 + string timeLeft = "" + minsLeft + if ( secsLeft < 10 ) + timeLeft = timeLeft + ":0" + secsLeft + else + timeLeft = timeLeft + ":" + secsLeft + Hud_SetText( panel.TimeLeft, timeLeft ) + string scoreLimit = "" + info.maxScore + Hud_SetText( panel.ScoreLimit, scoreLimit ) + string imcScore = "" + info.teamScores[TEAM_IMC] + string milScore = "" + info.teamScores[TEAM_MILITIA] + Hud_SetText( panel.Team1Score, imcScore ) + Hud_SetText( panel.Team2Score, milScore ) + + int team1PlayerCount = 0 + int team2PlayerCount = 0 + + info.clients.sort( RemoteMatchInfoPlayerSort ) + + for ( int i = 0; i < info.clients.len(); i++ ) + { + RemoteMatchPlayerInfoRow teamPlayer + if ( info.clients[i].teamNum == TEAM_IMC ) + { + if ( team1PlayerCount >= panel.team1Players.len() ) + { + printt( "too many team players" ) + continue + } + + teamPlayer = panel.team1Players[team1PlayerCount] + team1PlayerCount++ + } + else if ( info.clients[i].teamNum == TEAM_MILITIA ) + { + if ( team2PlayerCount >= panel.team2Players.len() ) + { + printt( "too many team players" ) + continue + } + + teamPlayer = panel.team2Players[team2PlayerCount] + team2PlayerCount++ + } + else + { + printt( "Unhandled player team " + info.clients[i].teamNum ) + continue + } + string score = "" + info.clients[i].score + string kills = "" + info.clients[i].kills + string deaths = "" + info.clients[i].deaths + + Hud_Hide( teamPlayer.playerPanel ) // not enough room for these + Hud_SetText( teamPlayer.name, info.clients[i].name ) + Hud_SetText( teamPlayer.score, score ) + Hud_SetText( teamPlayer.kills, kills ) + Hud_SetText( teamPlayer.deaths, deaths ) + } + for ( int i = team1PlayerCount; i < panel.team1Players.len(); i++ ) + Hud_Hide( panel.team1Players[i].playerPanel ) + for ( int i = team2PlayerCount; i < panel.team2Players.len(); i++ ) + Hud_Hide( panel.team2Players[i].playerPanel ) + +} + +void function RemoteMatchInfoVisibilityThread() +{ + EndSignal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" ) + wait 2 + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.remoteMatchInfoPanelWidgets.panel ) +} + +void function UICodeCallback_RemoteMatchInfoUpdated() +{ + printt( "Remote Match Info Updated!" ) + + RemoteMatchInfo info = GetRemoteMatchInfo() + foreach ( chatroomUI in file.chatroomUIs ) + FillInRemoteMatchInfoPanel( info, chatroomUI.remoteMatchInfoPanelWidgets ) + + Signal( uiGlobal.signalDummy, "StopRemoteMatchInfoThread" ) + thread RemoteMatchInfoVisibilityThread() +} + +void function Chatroom_GlobalInit() +{ + RegisterSignal( "StopRemoteMatchInfoThread" ) +} + +bool function IsSelectedUserStreaming() +{ + if ( !ChatroomHasFocus() ) + return false + return file.currentUserIsStreaming +} + +void function InitChatroom( var parentMenu ) +{ + RegisterSignal( "StopUserInfoLookups" ) + + file.communityChatroomMode = "chatroom" + + var menu = Hud_GetChild( parentMenu, "ChatroomPanel" ) + + ChatroomWidget chatroomUI + file.chatroomUIs.append( chatroomUI ) + + chatroomUI.chatroomPanel = menu + chatroomUI.chatroomWidget = Hud_GetChild( menu, "ChatRoom" ) + chatroomUI.chatroomTextChat = Hud_GetChild( menu, "ChatRoomTextChat" ) + chatroomUI.chatroomBackground = Hud_GetChild( menu, "ChatbarBackground" ) + chatroomUI.chatroomDivider = Hud_GetChild( menu, "ChatroomHeaderBackground" ) + chatroomUI.chatroomHappyHour = Hud_GetChild( menu, "HappyHourTimeLeft" ) + chatroomUI.chatroomMode = Hud_GetChild( menu, "CommunityChatRoomMode" ) + + var remoteMatchInfoPanel = Hud_GetChild( parentMenu, "MatchDetails" ) + chatroomUI.remoteMatchInfoPanelWidgets.panel = remoteMatchInfoPanel + FindRemoteMatchInfoWidgetsInPanel( chatroomUI.remoteMatchInfoPanelWidgets, remoteMatchInfoPanel ) + + chatroomUI.userInfoPanel.Panel = Hud_GetChild( parentMenu, "UserInfo" ) + chatroomUI.userInfoPanel.Name = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Name" ) + chatroomUI.userInfoPanel.Kills = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Kills" ) + chatroomUI.userInfoPanel.Wins = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Wins" ) + chatroomUI.userInfoPanel.Losses = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Losses" ) + chatroomUI.userInfoPanel.Deaths = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Deaths" ) + chatroomUI.userInfoPanel.XP = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "XP" ) + chatroomUI.userInfoPanel.callsignCard = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "CallsignCard" ) + + // chatroomUI.userInfoPanel.ViewUserCardButton = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "ViewUserCard" ) + + for ( int i = 0; i < 6; i++ ) + { + if ( !Hud_HasChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" ) ) + break; + var communityLabel = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i + "Label" ) + var communityName = Hud_GetChild( chatroomUI.userInfoPanel.Panel, "Community" + i ) + Assert( communityName, "found Community" + i + "Label, but no Community" + i + " in userInfo panel" ); + chatroomUI.userInfoPanel.communityLabels.append( communityLabel ) + chatroomUI.userInfoPanel.communityNames.append( communityName ) + } + + chatroomUI.communityChatroomModeButton = Hud_GetChild( menu, "CommunityChatRoomMode" ) +#if CONSOLE_PROG + chatroomUI.chatroomHintText = Hud_GetChild( menu, "TextChatHintForConsole" ) +#endif + chatroomUI.happyHourTimeLeft = Hud_GetChild( menu, "HappyHourTimeLeft" ) + // Hud_EnableKeyBindingIcons( chatroomUI.communityChatroomModeButton ) + + OpenInviteUI openInviteUI = chatroomUI.openInviteUI + openInviteUI.openInvitePanel = Hud_GetChild( parentMenu, "OpenInvitePanel" ) + openInviteUI.openInviteMessage = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteMessage" ) + openInviteUI.openInviteCountdownText = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteCountdownText" ) + + var openInviteBackground = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInviteBox" ) + RuiSetColorAlpha( Hud_GetRui( openInviteBackground ), "backgroundColor", <0, 0, 0>, 0.9 ) + + int i = 0; + while ( i < 8 ) + { + int count = i + 1 + var widget = Hud_GetChild( openInviteUI.openInvitePanel, "OpenInvitePlayer" + count ) + if ( !widget ) + break + openInviteUI.openInvitePlayerSlots.append( widget ) + i++ + } + for ( int idx = 0; idx < 9; ++idx ) + { + string widgetName = ("OpenInvitePlaylist" + format( "%02d", idx )) + var widget = Hud_GetChild( openInviteUI.openInvitePanel, widgetName ) + openInviteUI.openInvitePlaylistSlots.append( widget ) + i++ + } + + openInviteUI.openInviteJoinButton = Hud_GetChild( openInviteUI.openInvitePanel, "JoinOpenInviteButton" ) + Hud_EnableKeyBindingIcons( openInviteUI.openInviteJoinButton ) + + AddEventHandlerToButton( openInviteUI.openInvitePanel, "JoinOpenInviteButton", UIE_CLICK, JoinOpenInvite_OnClick ) + AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteCountdownText", UIE_CLICK, JoinOpenInvite_OnClick ) + AddEventHandlerToButton( openInviteUI.openInvitePanel, "OpenInviteMessageButtonOverlay", UIE_CLICK, JoinOpenInvite_OnClick ) + + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_MUTEROOM", "#MUTEROOM", MuteRoom, ChatroomIsNotMuted ) + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_LEFT, "#LB_UNMUTEROOM", "#UNMUTEROOM", UnmuteRoom, ChatroomIsMuted ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_DESTROY_FOOTER", "#OPENINVITE_DESTROY", LeaveOpenInviteButton, CanDestroyOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_JOIN_FOOTER", "#OPENINVITE_JOIN", JoinOpenInvite, CanJoinOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_Y, "#Y_BUTTON_OPENINVITE_LEAVE_FOOTER", "#OPENINVITE_LEAVE", LeaveOpenInviteButton, CanLeaveOpenInvite ) + AddMenuFooterOption( parentMenu, BUTTON_A, "#BUTTON_VIEW_PLAYER_PROFILE", "#MOUSE1_VIEW_PROFILE", null, IsChatroomViewProfileValid ) + AddMenuFooterOption( parentMenu, BUTTON_SHOULDER_RIGHT, "#COMMUNITY_RB_CHATROOM_VIEWSTREAM", "#COMMUNITY_CHATROOM_VIEWSTREAM", null, IsSelectedUserStreaming ) + AddMenuFooterOption( parentMenu, BUTTON_X, "#BUTTON_MUTE", "#MOUSE2_MUTE", null, ChatroomHasFocus ) + + UpdateChatroomUI() + + Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_LOSE_FOCUS, LostFocus ) + Hud_AddEventHandler( chatroomUI.chatroomWidget, UIE_GET_FOCUS, GotFocus ) +} + +void function bsupdate() +{ + ShowOpenInvite() + + OpenInvite openInvite + openInvite.amILeader = false + openInvite.amIInThis = false + openInvite.numSlots = 5 + openInvite.numClaimedSlots = 1 + + string inviteString = openInvite.amILeader ? "#OPENINVITE_SENDER_PLAYLIST" : "#OPENINVITE_PLAYLIST" + + float endTime = Time() + 10.0 + while ( Time() < endTime ) + { + openInvite.timeLeft = endTime - Time() + + int remainingTime = int( ceil( endTime - Time() ) ) + UpdateOpenInvites( openInvite, inviteString, "scriptacus", "Bounty Hunt", remainingTime ) + + if ( remainingTime == 8 ) + openInvite.numClaimedSlots = 2 + + if ( remainingTime == 6 ) + openInvite.numClaimedSlots = 4 + + //if ( remainingTime == 5 ) + // openInvite.numClaimedSlots = 5 + // + //if ( remainingTime == 4 ) + // openInvite.numClaimedSlots = 6 + + WaitFrame() + } +} + +void function UpdateOpenInvites( OpenInvite openInvite, string message, string param1, string ornull param2, int countdown ) +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + if ( param2 ) + Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1, param2 ); + else + Hud_SetText( chatroomUI.openInviteUI.openInviteMessage, message, param1 ); + + string countdownText = "" + countdown +// Hud_SetText( chatroomUI.openInviteUI.openInviteCountdownText, "#OPENINVITE_COUNTDOWN", countdownText ) + var countdownRui = Hud_GetRui( chatroomUI.openInviteUI.openInviteCountdownText ) + RuiSetFloat( countdownRui, "timeLeft", openInvite.timeLeft ) + RuiSetFloat( countdownRui, "maxTime", GetConVarFloat( "openinvite_duration_default" ) ) + + bool started = openInvite.timeLeft <= 0 || openInvite.numFreeSlots == 0 + + if ( started ) + { + Hud_Hide( chatroomUI.openInviteUI.openInviteJoinButton ) + } + else if ( CanDestroyOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_DESTROY" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_DESTROY" ) + } + else if ( CanLeaveOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_LEAVE" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_LEAVE" ) + } + else if ( CanJoinOpenInvite() ) + { + Hud_Show( chatroomUI.openInviteUI.openInviteJoinButton ) + if ( IsControllerModeActive() ) + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#Y_BUTTON_OPENINVITE_JOIN" ) + else + SetNamedRuiText( chatroomUI.openInviteUI.openInviteJoinButton, "buttonText", "#OPENINVITE_JOIN" ) + } + + string myUID = GetPlayerUID() + int i = 0 + foreach ( player in chatroomUI.openInviteUI.openInvitePlayerSlots ) + { + var rui = Hud_GetRui( player ) + Hud_Show( player ) + + if ( i >= openInvite.numSlots ) + { + //Hud_Hide( player ) + RuiSetBool( rui, "isEnabled", false ) + RuiSetBool( rui, "hasPlayer", false ) + } + else + { + CallsignIcon callsignIcon + bool isMe = false + // asset playerImage + + if ( i < openInvite.numClaimedSlots ) + { + PartyMember member = openInvite.members[i] + isMe = ( member.uid == myUID ) + if ( isMe ) + { + if ( GetUIPlayer() != null ) // this can happen sometimes after a resolution/windowed mode change + callsignIcon = PlayerCallsignIcon_GetActive( GetUIPlayer() ) + else + callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" ) + } + else + { + callsignIcon = CallsignIcon_GetByIndex( member.callsignIdx ) + } + } + else + { + callsignIcon = CallsignIcon_GetByRef( "gc_icon_happyface" ) + } + + Hud_Show( player ) + RuiSetBool( rui, "isEnabled", true ) + + RuiSetBool( rui, "hasPlayer", i < openInvite.numClaimedSlots ) + RuiSetBool( rui, "isViewPlayer", isMe ) + RuiSetImage( rui, "playerImage", callsignIcon.image ) + + //if ( i < openInvite.numClaimedSlots ) + // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_occupiedslot" ) + //else + // Hud_SetImage( player, $"ui/menu/main_menu/openinvite_emptyslot" ) + } + i++ + } + + array checklistPlaylists = GetChecklistPlaylistsArray() + + if ( Lobby_IsFDMode() ) + checklistPlaylists = GetFDDifficultyArray() + + array invitePlaylists = split( openInvite.playlistName, "," ) + bool shouldShowCheckboxPlaylists = true + if ( !MixtapeMatchmakingIsEnabled() ) + shouldShowCheckboxPlaylists = false + else if ( invitePlaylists.len() == 0 ) + shouldShowCheckboxPlaylists = false + else if ( (invitePlaylists.len() == 1) && (!checklistPlaylists.contains( invitePlaylists[0] )) ) + shouldShowCheckboxPlaylists = false + + int playlistSlotCount = chatroomUI.openInviteUI.openInvitePlaylistSlots.len() + for( int idx = 0; idx < playlistSlotCount; ++idx ) + { + var slot = chatroomUI.openInviteUI.openInvitePlaylistSlots[idx] + + string thisPlaylistName = idx < checklistPlaylists.len() ? checklistPlaylists[idx] : "" + if ( (thisPlaylistName == "") || !shouldShowCheckboxPlaylists ) + { + Hud_Hide( slot ) + continue + } + + Hud_Show( slot ) + var slotRui = Hud_GetRui( slot ) + asset playlistThumbnail = GetPlaylistThumbnailImage( thisPlaylistName ) + RuiSetImage( slotRui, "checkImage", playlistThumbnail ) + + bool isChecked = invitePlaylists.contains( thisPlaylistName ) + RuiSetBool( slotRui, "isChecked", isChecked ) + + string abbr = GetPlaylistVarOrUseValue( thisPlaylistName, "abbreviation", "" ) + RuiSetString( slotRui, "abbreviation", Localize( abbr ) ) + } + } +} + + +void function HideOpenInvite() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + Hud_Hide( chatroomUI.openInviteUI.openInvitePanel ) + } +} + +void function ShowOpenInvite() +{ + foreach ( chatroomUI in file.chatroomUIs ) + { + Hud_Show( chatroomUI.openInviteUI.openInvitePanel ) + } +} + + +void function LostFocus( panel ) +{ + Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) + printt( "Chatroom lost focus" ) + foreach ( chatroomUI in file.chatroomUIs ) + Hud_Hide( chatroomUI.userInfoPanel.Panel ) + file.hasFocus = false + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatrooUI.chatroomWidget, Hud_GetBaseWidth( chatrooUI.chatroomWidget ) ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatrooUI.chatroomMode, Hud_GetBaseWidth( chatrooUI.chatroomBackground ) ) + Hud_Show( chatroomUI.chatroomTextChat ) + } +} + + +void function OnChatroomWidgetGetFocus( var widget ) +{ +} + +void function OnChatroomWidgetLoseFocus( var widget ) +{ +} + +void function GotFocus( panel ) +{ + printt( "Chatroom got focus" ) + file.hasFocus = true + + foreach ( chatroomUI in file.chatroomUIs ) + { + // Hud_SetWidth( chatroomUI.chatroomWidget, Hud_GetBaseWidth( chatroomUI.chatroomWidget ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_SetWidth( chatroomUI.chatroomBackground, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 12 ) + Hud_Hide( chatroomUI.chatroomDivider ) + // Hud_SetWidth( chatroomUI.chatroomMode, Hud_GetBaseWidth( chatroomUI.chatroomBackground ) - Hud_GetBaseWidth( chatroomUI.userInfoPanel.Panel ) - 24 ) + Hud_Hide( chatroomUI.chatroomTextChat ) + } +} + +bool function IsChatroomViewProfileValid() +{ + #if PC_PROG + if ( !Origin_IsOverlayAvailable() ) + return false + #endif // PC_PROG + + return ChatroomHasFocus() +} + +bool function ChatroomHasFocus() +{ + return file.hasFocus +} + +bool function ChatroomIsMuted() +{ + if ( IsControllerModeActive() ) + return ChatroomHasFocus() && IsChatroomMuted() + return IsChatroomMuted() +} + +bool function ChatroomIsNotMuted() +{ + if ( IsControllerModeActive() ) + return ChatroomHasFocus() && !IsChatroomMuted() + return !IsChatroomMuted() +} + +void function MuteRoom( var button ) +{ + printt( "muting the room" ) + ClientCommand( "muteroom" ) +} + +void function UnmuteRoom( var button ) +{ + printt( "unmuting the room" ) + ClientCommand( "unmuteroom" ) +} + +void function UpdateChatroomThread() +{ + EndSignal( uiGlobal.signalDummy, "OnCloseLobbyMenu" ) + while ( true ) + { + UpdateChatroomUI() + wait 30 + } +} -- cgit v1.2.3 From 1226f7599fdfe63a08ee0fbc2b0e3e296f38f2da Mon Sep 17 00:00:00 2001 From: JMM889901 <41163714+JMM889901@users.noreply.github.com> Date: Tue, 3 Oct 2023 23:37:35 +0100 Subject: Remove annoying recurring print from `chatroom.nut` (#676) Commented out instead of fully removing --- Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut index b474f7a6..4e98ee8a 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/chatroom.nut @@ -308,7 +308,7 @@ void function UICodeCallback_ShowUserInfo( string hardware, string userId ) { Signal( uiGlobal.signalDummy, "StopUserInfoLookups" ) - printt( "Showing user info for UID " + userId + " on hardware " + hardware ) + // printt( "Showing user info for UID " + userId + " on hardware " + hardware ) file.userInfoPanel_userId = userId file.userInfoPanel_hardware = hardware -- cgit v1.2.3 From e719d304d20f5f50948a6681b5f4088bbccd2b5d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:43:55 +0200 Subject: Bump mods version to `1.19.0` (#732) --- Northstar.Client/mod.json | 2 +- Northstar.Custom/mod.json | 2 +- Northstar.CustomServers/mod.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 8040c14c..7d695a4b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Client", "Description": "Various ui and client changes to fix bugs and add better support for mods", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 22f9c45f..93f371bd 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.Custom", "Description": "Custom content for Northstar: extra weapons, gamemodes, etc.", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 1, "RequiredOnClient": true, "ConVars": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index 8f5508c8..e6f2c4b7 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -1,7 +1,7 @@ { "Name": "Northstar.CustomServers", "Description": "Attempts to recreate the behaviour of vanilla Titanfall 2 servers, as well as changing some scripts to allow better support for mods", - "Version": "1.16.0", + "Version": "1.19.0", "LoadPriority": 0, "ConVars": [ { -- cgit v1.2.3 From 1c3bafd8efd56c4f0bb11a952fb192f60bcf42c0 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 4 Oct 2023 22:50:11 +0100 Subject: Prevent loadout validation crash due to invalid warpaints (#734) --- .../mod/scripts/vscripts/sh_progression.nut | 36 ++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 22354349..ceb5e837 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -644,11 +644,15 @@ void function ValidateEquippedItems( entity player ) player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) } } - else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.primarySkinIndex, loadout.primary ), loadout.primary ) ) + else { - printt( " - PRIMARY WEAPON SKIN LOCKED, RESETTING" ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.primarySkinIndex, loadout.primary ) + if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.primary ) ) + { + printt( " - PRIMARY WEAPON SKIN LOCKED/INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primarySkinIndex", defaultLoadout.primarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].primaryCamoIndex", defaultLoadout.primaryCamoIndex ) + } } } @@ -777,11 +781,15 @@ void function ValidateEquippedItems( entity player ) player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) } } - else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.secondarySkinIndex, loadout.secondary ), loadout.secondary ) ) + else { - printt( " - SECONDARY WEAPON SKIN LOCKED, RESETTING" ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.secondarySkinIndex, loadout.secondary ) + if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.secondary ) ) + { + printt( " - SECONDARY WEAPON SKIN LOCKED/INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondarySkinIndex", defaultLoadout.secondarySkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].secondaryCamoIndex", defaultLoadout.secondaryCamoIndex ) + } } } @@ -910,11 +918,15 @@ void function ValidateEquippedItems( entity player ) player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) } } - else if ( IsSubItemLocked( player, GetWeaponWarpaintRefByIndex( loadout.weapon3SkinIndex, loadout.weapon3 ), loadout.weapon3 ) ) + else { - printt( " - TERTIARY WEAPON SKIN LOCKED, RESETTING" ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) - player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + string warpaintRef = GetWeaponWarpaintRefByIndex( loadout.weapon3SkinIndex, loadout.weapon3 ) + if ( warpaintRef == INVALID_REF || IsSubItemLocked( player, warpaintRef, loadout.weapon3 ) ) + { + printt( " - TERTIARY WEAPON SKIN LOCKED/INVALID, RESETTING" ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3SkinIndex", defaultLoadout.weapon3SkinIndex ) + player.SetPersistentVar( "pilotLoadouts[" + pilotLoadoutIndex + "].weapon3CamoIndex", defaultLoadout.weapon3CamoIndex ) + } } } -- cgit v1.2.3 From 15b3b65fc4e88fe98ba12b4d7603e396fba91fb3 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 7 Oct 2023 11:40:31 +0100 Subject: Display origin auth failure in a dialog (#648) Currently, we don't do anything with origin auth failure, meaning the next request just fails, and we get not particularly relevant error messages (player not found, invalid masterserver token) --- .github/nativefuncs.json | 6 +++ Northstar.Client/mod.json | 7 +++ .../northstar_client_localisation_english.txt | 5 ++ .../scripts/vscripts/cl_northstar_client_init.nut | 7 +++ .../mod/scripts/vscripts/ui/atlas_auth.nut | 56 ++++++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 6f46095f..13a7edd3 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -729,6 +729,12 @@ "helpText":"", "returnTypeString":"void", "argTypes":"struct presence" + }, + { + "name":"NSGetMasterServerAuthResult", + "helpText":"", + "returnTypeString":"MasterServerAuthResult", + "argTypes":"" } ] } \ No newline at end of file diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 7d695a4b..f7c7c9b5 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -128,6 +128,13 @@ { "Path": "ui/ui_mouse_capture.nut", "RunOn": "UI" + }, + { + "Path": "ui/atlas_auth.nut", + "RunOn": "UI", + "UICallback": { + "After": "AtlasAuthDialog" + } } ], "Localisation": [ diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 8c7bab3a..49e9ee43 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -322,6 +322,11 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" + + "AUTHENTICATION_FAILED_HEADER" "Authentication Failed" + "AUTHENTICATION_FAILED_BODY" "Failed to authenticate with Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Error code: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Help" // Mod Settings "MOD_SETTINGS" "Mod Settings" diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 2a2ed3db..a844478a 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -41,3 +41,10 @@ global struct ServerInfo string region array< RequiredModInfo > requiredMods } + +global struct MasterServerAuthResult +{ + bool success + string errorCode + string errorMessage +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut new file mode 100644 index 00000000..89b7f719 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/atlas_auth.nut @@ -0,0 +1,56 @@ +global function AtlasAuthDialog + +void function AtlasAuthDialog() +{ + thread AtlasAuthDialog_Threaded() +} + +void function AtlasAuthDialog_Threaded() +{ + // wait at least 1 frame so that the main menu can be loaded first + WaitFrame() + + while ( !NSIsMasterServerAuthenticated() || GetConVarBool( "ns_auth_allow_insecure" ) ) + WaitFrame() + + if ( GetConVarBool( "ns_auth_allow_insecure" ) ) + return + + MasterServerAuthResult res = NSGetMasterServerAuthResult() + + // do nothing on successful authentication + if ( res.success ) + return + + EmitUISound( "blackmarket_purchase_fail" ) + + DialogData dialogData + dialogData.image = $"ui/menu/common/dialog_error" + dialogData.header = Localize( "#AUTHENTICATION_FAILED_HEADER" ) + + // if we got a special error message from Atlas, display it + if ( res.errorMessage != "" ) + dialogData.message = res.errorMessage + else + dialogData.message = Localize( "#AUTHENTICATION_FAILED_BODY" ) + + if ( res.errorCode != "" ) + dialogData.message += format( "\n\n%s", Localize( "#AUTHENTICATION_FAILED_ERROR_CODE", res.errorCode ) ) + + string link = "https://r2northstar.gitbook.io/r2northstar-wiki/installing-northstar/troubleshooting" + // link to generic troubleshooting page if we don't have an error code from Atlas + if ( res.errorCode != "" ) + link = format( "%s#%s", link, res.errorCode ) + + CloseAllDialogs() + AddDialogButton( dialogData, "#OK" ) + AddDialogButton( dialogData, Localize( "#AUTHENTICATION_FAILED_HELP" ), void function() : ( dialogData, link ) + { + // todo: get MS to redirect, so i can use an MS link or something? + LaunchExternalWebBrowser( link, WEBBROWSER_FLAG_FORCEEXTERNAL ) + // keep the dialog open + OpenDialog( dialogData ) + } ) + + OpenDialog( dialogData ) +} -- cgit v1.2.3 From 0ee1f3daea0cd1c2badfb7c373fe9d0b14917501 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 8 Oct 2023 16:19:51 +0200 Subject: Translations update from Weblate (#739) Translated using Weblate (Russian) Currently translated at 95.1% (277 of 291 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- .../mod/resource/northstar_client_localisation_russian.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 514e4fd1..f7c6bc6e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -341,5 +341,9 @@ "PROGRESSION_TOGGLE_ENABLED_BODY" "Все титаны, оружие, фракции, раскраски, и т.п. станут разблокированы.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." "PROGRESSION_TOGGLE_DISABLED_BODY" "Будут доступны только разблокированные или купленные вами титаны, оружие, фракции, раскраски, и т.п.\n\nЭту настройку всегда можно изменить в лобби сетевой игры.\n\n^CC000000Внимание: недоступные предметы в экипировке будут заменены на доступные!" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Прогресс!^\n\nВ Northstar теперь работает оригинальная система прогресса разблокировок. Титанов, оружие, фракции, раскраски, и т.п. теперь можно разблокировать через получение новых уровней и прохождение испытаний.\n\nПрогресс можно включить с помощью кнопки внизу меню лобби.\n\nЭту настройку всегда можно изменить." + "AUTHENTICATION_FAILED_BODY" "Не удалось войти в Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Код ошибки: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Справка" + "AUTHENTICATION_FAILED_HEADER" "Ошибка аутентификации" } } -- cgit v1.2.3 From 89c0d98ed62ec32861045852dbbfd295b0859761 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:44:02 +0100 Subject: Fix localisation string for toggling progression on controller (#717) Fix the controller button for toggling progression not showing up. --- Northstar.Client/mod/resource/northstar_client_localisation_english.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_french.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_russian.txt | 2 +- Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt | 2 +- .../mod/resource/northstar_client_localisation_tchinese.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 49e9ee43..c7b25a70 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -351,7 +351,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a // Toggleable progression "TOGGLE_PROGRESSION" "Toggle Progression" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Toggle Progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Toggle Progression" "PROGRESSION_TOGGLE_ENABLED_HEADER" "Disable Progression?" "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 45abcfc5..377f6917 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -351,7 +351,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." "TOGGLE_PROGRESSION" "Activer la progression" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Activer la progression" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." } } diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index f7c6bc6e..cf410ff2 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -330,7 +330,7 @@ "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Сброс перезарядки пульс. клинка при убийстве им" "gg_assist_reward" "Множитель награды за помощь в убийстве" "TOGGLE_PROGRESSION" "Вкл/выкл прогресс" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Вкл/выкл прогресс" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Вкл/выкл прогресс" "PROGRESSION_TOGGLE_DISABLED_HEADER" "Включить прогресс?" "PROGRESSION_ENABLED_HEADER" "Прогресс включён!" "PROGRESSION_ENABLED_BODY" "^CCCC0000Прогресс включён.^\n\nНедоступных титанов, оружие, фракции, раскраски, и т.п. теперь нужно разблокировать, или купить за Заслуги.\n\nЭту настройку всегда можно изменить в лобби сетевой игры." diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 43ee412f..3d9ae4c6 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -342,7 +342,7 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "PROGRESSION_ENABLED_HEADER" "¡Progreso habilitado!" "PROGRESSION_DISABLED_HEADER" "¡Progreso deshabilitado!" "TOGGLE_PROGRESSION" "Cambiar modo de progresión" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% Cambiar modo de progresión" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Cambiar modo de progresión" "PROGRESSION_TOGGLE_DISABLED_BODY" "Titanes, Armas, Facciones, Aspectos y otros serán desbloqueados sólo al subir de nivel, o a través de Logros.\n\nÉsta opción puede ser cambiada cuando quieras en la sala de espera.\n\n^CC000000Advertencia: ¡Cualquier equipamiento o utensilio será reiniciado si no lo tienes desbloqueado!" "MOD_SETTINGS_SERVER" "Servidor" "MOD_SETTINGS_RESET_ALL" "Reiniciar completamente" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt index 003ca28a..500f8a96 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_tchinese.txt @@ -350,7 +350,7 @@ "PROGRESSION_TOGGLE_DISABLED_BODY" "泰坦,武器, 陣營,皮膚以及其他一切需要解鎖的物品將通過升級或是使用點數購買來進行解鎖。.\n\n您可以隨時在多人大廳中更改此項。\n\n^CC000000警告:如果您已經裝備了尚未解鎖的物品,它們將會被重置!" "PROGRESSION_TOGGLE_ENABLED_BODY" "泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品都將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" "TOGGLE_PROGRESSION" "遊戲進度" - "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON]% 遊戲進度" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% 遊戲進度" "PROGRESSION_TOGGLE_ENABLED_HEADER" "停用個人進度?" "PROGRESSION_DISABLED_HEADER" "個人進度已關閉!" "PROGRESSION_DISABLED_BODY" "^CCCC0000個人進度已停用^\n\n泰坦,武器,陣營,皮膚及所有其他一切需要解鎖的物品將隨時可以進行解鎖並使用。\n\n您可以隨時在多人大廳中更改此項。" -- cgit v1.2.3 From 612e6a116990afe15212af917aa8443030d5c3d4 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:45:46 +0100 Subject: Fix titan-only boosts for modes like LTS (#678) Revert back to the original check by Respawn --- Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut index ac9ffab3..37d4356f 100644 --- a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut @@ -188,7 +188,7 @@ BurnReward function BurnReward_GetRandom() string ref = burn.allowedCards.getrandom().ref #if SERVER || CLIENT - if ( !EarnMeterMP_IsTitanEarnGametype() ) + if ( Riff_TitanAvailability() == eTitanAvailability.Never ) ref = BurnMeter_GetNoTitansReplacement( ref ) if ( GetCurrentPlaylistVarInt( "featured_mode_all_ticks", 0 ) >= 1 ) @@ -211,7 +211,7 @@ string function GetSelectedBurnCardRef( entity player ) #endif #if SERVER || CLIENT - if ( !EarnMeterMP_IsTitanEarnGametype() ) + if ( Riff_TitanAvailability() == eTitanAvailability.Never ) ref = BurnMeter_GetNoTitansReplacement( ref ) if ( GetCurrentPlaylistVarInt( "featured_mode_all_ticks", 0 ) >= 1 ) -- cgit v1.2.3 From 9eede6047a18d9936b2d98c1499cc90bd8d091d7 Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 9 Oct 2023 21:35:11 -0300 Subject: Implement `_grunt_chatter_mp.gnut` (#687) Code is adapted from `_grunt_chatter.gnut` which is used in the campaign. File implementation is a vanilla behavior restoration of Grunts being able to chatter about when other grunts nearby are killed, or when an enemy Titan is killed. --- .../vscripts/conversation/_grunt_chatter_mp.gnut | 195 ++++++++++++++++++++- 1 file changed, 194 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut index 1a70c289..4eb423fd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/conversation/_grunt_chatter_mp.gnut @@ -1,11 +1,33 @@ global function GruntChatter_MP_Init global function PlayGruntChatterMPLine +const float CHATTER_FRIENDLY_GRUNT_DOWN_DIST_MAX = 1100.0 +const float CHATTER_SQUAD_DEPLETED_FRIENDLY_NEARBY_DIST = 650.0 // if any other friendly grunt is within this dist, squad deplete chatter won't play +const float CHATTER_ENEMY_TITAN_DOWN_DIST_MAX = 1500.0 +const float CHATTER_NEARBY_GRUNT_TRACEFRAC_MIN = 0.95 // for when we need "LOS" trace + void function GruntChatter_MP_Init() { - //ShGruntChatter_MP_Init() + Assert( IsMultiplayer(), "MP Grunt chatter is restricted to Multiplayer only." ) + + AddCallback_OnPlayerKilled( GruntChatter_OnPlayerOrNPCKilled ) + AddCallback_OnNPCKilled( GruntChatter_OnPlayerOrNPCKilled ) } + + + +/*===================================================================================================================================================== + _____ _ _____ _ _ _ __ __ _ _ _ _ + / ____| | | / ____|| | | | | | | \/ | | || | (_) | | + | | __ _ __ _ _ _ __ | |_ | | | |__ __ _ | |_ | |_ ___ _ __ | \ / | _ _ | || |_ _ _ __ | | __ _ _ _ ___ _ __ + | | |_ || '__|| | | || '_ \ | __| | | | '_ \ / _` || __|| __|/ _ \| '__| | |\/| || | | || || __|| || '_ \ | | / _` || | | | / _ \| '__| + | |__| || | | |_| || | | || |_ | |____ | | | || (_| || |_ | |_| __/| | | | | || |_| || || |_ | || |_) || || (_| || |_| || __/| | + \_____||_| \__,_||_| |_| \__| \_____||_| |_| \__,_| \__| \__|\___||_| |_| |_| \__,_||_| \__||_|| .__/ |_| \__,_| \__, | \___||_| + | | __/ | + |_| |___/ +/*===================================================================================================================================================*/ + void function PlayGruntChatterMPLine( entity grunt, string conversationType ) { #if !GRUNT_CHATTER_MP_ENABLED @@ -15,4 +37,175 @@ void function PlayGruntChatterMPLine( entity grunt, string conversationType ) foreach ( entity player in GetPlayerArray() ) if ( ShouldPlayGruntChatterMPLine( conversationType, player, grunt ) ) Remote_CallFunction_Replay( player, "ServerCallback_PlayGruntChatterMP", GetConversationIndex( conversationType ), grunt.GetEncodedEHandle() ) +} + +void function GruntChatter_OnPlayerOrNPCKilled( entity deadGuy, entity attacker, var damageInfo ) +{ + if ( !IsValid( deadGuy ) || !IsValid( attacker ) ) + return + + if( IsGrunt( attacker ) && IsPilot( deadGuy ) ) + PlayGruntChatterMPLine( attacker, "bc_killenemypilot" ) + else + GruntChatter_TryEnemyTitanDown( deadGuy ) + + if ( IsGrunt( deadGuy ) ) + { + GruntChatter_TryFriendlyDown( deadGuy ) + GruntChatter_TrySquadDepleted( deadGuy ) + } +} + +void function GruntChatter_TryFriendlyDown( entity deadGuy ) +{ + entity closestGrunt = GruntChatter_FindClosestFriendlyHumanGrunt_LOS( deadGuy.GetOrigin(), deadGuy.GetTeam(), CHATTER_FRIENDLY_GRUNT_DOWN_DIST_MAX ) + if ( !closestGrunt ) + return + + if ( !GruntChatter_CanGruntChatterNow( closestGrunt ) ) + return + + PlayGruntChatterMPLine( closestGrunt, "bc_allygruntdown" ) +} + +void function GruntChatter_TrySquadDepleted( entity deadGuy ) +{ + string deadGuySquadName = expect string( deadGuy.kv.squadname ) + if ( deadGuySquadName == "" ) + return + + array squad = GetNPCArrayBySquad( deadGuySquadName ) + entity lastSquadMember + if ( squad.len() == 1 ) + lastSquadMember = squad[0] + + if ( !GruntChatter_CanGruntChatterNow( lastSquadMember ) ) + return + + if ( lastSquadMember.GetNPCState() == "idle" ) + return + + // if another grunt from another squad is nearby, don't chatter about being alone + array nearbyGrunts = GetNearbyFriendlyGrunts( lastSquadMember.GetOrigin(), lastSquadMember.GetTeam(), CHATTER_SQUAD_DEPLETED_FRIENDLY_NEARBY_DIST ) + nearbyGrunts.fastremovebyvalue( lastSquadMember ) + if ( nearbyGrunts.len() ) + return + + PlayGruntChatterMPLine( lastSquadMember, "bc_squaddeplete" ) +} + +void function GruntChatter_TryEnemyTitanDown( entity deadGuy ) +{ + if ( deadGuy.IsTitan() ) + { + entity closestGrunt = GruntChatter_FindClosestEnemyHumanGrunt_LOS( deadGuy.GetOrigin(), deadGuy.GetTeam(), CHATTER_ENEMY_TITAN_DOWN_DIST_MAX ) + if ( !closestGrunt ) + return + + PlayGruntChatterMPLine( closestGrunt, "bc_enemytitandown" ) + } +} + +entity function GruntChatter_FindClosestEnemyHumanGrunt_LOS( vector searchOrigin, int enemyTeam, float searchDist ) +{ + array humanGrunts = GetNearbyEnemyHumanGrunts( searchOrigin, enemyTeam, searchDist ) + return GruntChatter_GetClosestGrunt_LOS( humanGrunts, searchOrigin ) +} + +entity function GruntChatter_FindClosestFriendlyHumanGrunt_LOS( vector searchOrigin, int friendlyTeam, float searchDist ) +{ + array humanGrunts = GetNearbyFriendlyHumanGrunts( searchOrigin, friendlyTeam, searchDist ) + return GruntChatter_GetClosestGrunt_LOS( humanGrunts, searchOrigin ) +} + +entity function GruntChatter_GetClosestGrunt_LOS( array nearbyGrunts, vector searchOrigin ) +{ + entity closestGrunt = null + float closestDist = 10000 + + foreach ( grunt in nearbyGrunts ) + { + vector gruntOrigin = grunt.GetOrigin() + + // CanSee doesn't return true if the target is dead + if ( !GruntChatter_CanGruntTraceToLocation( grunt, searchOrigin ) ) + continue + + if ( !closestGrunt ) + { + closestGrunt = grunt + continue + } + + float distFromSearchOrigin = Distance( grunt.GetOrigin(), searchOrigin ) + + if ( closestDist > distFromSearchOrigin ) + continue + + closestGrunt = grunt + closestDist = distFromSearchOrigin + } + + return closestGrunt +} + +bool function GruntChatter_CanGruntTraceToLocation( entity grunt, vector traceEnd ) +{ + float traceFrac = TraceLineSimple( grunt.GetOrigin(), traceEnd, grunt ) + return traceFrac > CHATTER_NEARBY_GRUNT_TRACEFRAC_MIN +} + +array function GetNearbyFriendlyHumanGrunts( vector searchOrigin, int friendlyTeam, float ornull searchRange = null ) +{ + array nearbyGrunts = GetNearbyFriendlyGrunts( searchOrigin, friendlyTeam, searchRange ) + array humanGrunts = [] + foreach ( grunt in nearbyGrunts ) + { + if ( grunt.IsMechanical() ) + continue + + humanGrunts.append( grunt ) + } + + return humanGrunts +} + +array function GetNearbyEnemyHumanGrunts( vector searchOrigin, int enemyTeam, float ornull searchRange = null ) +{ + array nearbyGrunts = GetNearbyEnemyGrunts( searchOrigin, enemyTeam, searchRange ) + array humanGrunts = [] + foreach ( grunt in nearbyGrunts ) + { + if ( grunt.IsMechanical() ) + continue + + humanGrunts.append( grunt ) + } + + return humanGrunts +} + +bool function GruntChatter_CanGruntChatterNow( entity grunt ) +{ + if ( !IsAlive( grunt ) ) + return false + + if ( !GruntChatter_IsGruntTypeEligibleForChatter( grunt ) ) + return false + + if ( grunt.ContextAction_IsMeleeExecution() ) + return false + + string squadname = expect string( grunt.kv.squadname ) + // we only care about this because the grunt conversation system wants it + return squadname != "" +} + +bool function GruntChatter_IsGruntTypeEligibleForChatter( entity grunt ) +{ + if ( !IsGrunt( grunt ) ) + return false + + // mechanical grunts don't chatter + return !grunt.IsMechanical() } \ No newline at end of file -- cgit v1.2.3 From 70c599a345bf5be16ae76d98de2943ee388e6d07 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:04:47 +0200 Subject: Use string convar flags (#740) Uses string names for convars (been supported since refactor but not yet used) rather than magic numbers Co-authored-by: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> --- Northstar.Client/mod.json | 4 ++-- Northstar.CustomServers/mod.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index f7c7c9b5..a22f49fd 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -36,12 +36,12 @@ { "Name": "modlist_show_convars", "DefaultValue": "0", - "Flags": 16777216 + "Flags": "ARCHIVE_PLAYERPROFILE" }, { "Name": "modlist_reverse", "DefaultValue": "0", - "Flags": 16777216 + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index e6f2c4b7..de3fcd0d 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -20,7 +20,7 @@ { "Name": "ns_allow_spectators", "DefaultValue": "0", - "Flags": 8192 + "Flags": "REPLICATED" }, { "Name": "ns_private_match_last_mode", -- cgit v1.2.3 From add7305318b6fc1fe74389c60c352a19bddd7748 Mon Sep 17 00:00:00 2001 From: BobTheBob <32057864+BobTheBob9@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:41:48 +0100 Subject: Remove unnecessary convars (#530) Removes some convars we don't need at all --- .../mod/scripts/vscripts/ui/menu_lobby.nut | 45 ++++++---------------- .../mod/scripts/vscripts/ui/menu_mode_select.nut | 18 +++------ .../mod/scripts/vscripts/ui/menu_private_match.nut | 19 +-------- .../mod/scripts/vscripts/ui/openinvites.nut | 5 ++- .../mod/scripts/vscripts/ui/panel_mainmenu.nut | 2 - Northstar.CustomServers/mod.json | 9 ----- .../mod/scripts/vscripts/sh_northstar_utils.gnut | 6 --- 7 files changed, 22 insertions(+), 82 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut index e4cc5687..23dae99d 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_lobby.nut @@ -288,44 +288,21 @@ void function SetupComboButtonTest( var menu ) int buttonIndex = 0 file.playHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_PLAY" ) - bool isModded = IsNorthstarServer() - - - // this will be the server browser - if ( isModded ) - { - file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" ) - file.lobbyButtons.append( file.findGameButton ) - Hud_SetLocked( file.findGameButton, true ) - Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser ) - } - else - { - file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_FIND_GAME" ) - file.lobbyButtons.append( file.findGameButton ) - Hud_AddEventHandler( file.findGameButton, UIE_CLICK, BigPlayButton1_Activate ) - } + // server browser + file.findGameButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_SERVER_BROWSER" ) + file.lobbyButtons.append( file.findGameButton ) + Hud_SetLocked( file.findGameButton, true ) + Hud_AddEventHandler( file.findGameButton, UIE_CLICK, OpenServerBrowser ) - // this is used for launching private matches now - if ( isModded ) - { - file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) - Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) - } - else - { - file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_ROOM" ) - Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, DoRoomInviteIfAllowed ) - } + // private match + file.inviteRoomButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#PRIVATE_MATCH" ) + Hud_AddEventHandler( file.inviteRoomButton, UIE_CLICK, StartPrivateMatch ) file.inviteFriendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) Hud_AddEventHandler( file.inviteFriendsButton, UIE_CLICK, InviteFriendsIfAllowed ) - - if ( isModded ) - { - Hud_SetEnabled( file.inviteFriendsButton, false ) - Hud_SetVisible( file.inviteFriendsButton, false ) - } + + Hud_SetEnabled( file.inviteFriendsButton, false ) + Hud_SetVisible( file.inviteFriendsButton, false ) // file.toggleMenuModeButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LOBBY_SWITCH_FD" ) // Hud_AddEventHandler( file.toggleMenuModeButton, UIE_CLICK, ToggleLobbyMode ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut index 52a99b6f..605af383 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_mode_select.nut @@ -18,8 +18,8 @@ void function InitModesMenu() AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) - AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack, IsNorthstarServer ) - AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward, IsNorthstarServer ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_LEFT, "#PRIVATE_MATCH_PAGE_PREV", "#PRIVATE_MATCH_PAGE_PREV", CycleModesBack ) + AddMenuFooterOption( menu, BUTTON_SHOULDER_RIGHT, "#PRIVATE_MATCH_PAGE_NEXT", "#PRIVATE_MATCH_PAGE_NEXT", CycleModesForward ) } void function OnOpenModesMenu() @@ -56,13 +56,7 @@ void function UpdateVisibleModes() if ( !ModeSettings_RequiresAI( modesArray[ modeIndex ] ) || modesArray[ modeIndex ] == "aitdm" || modesArray[ modeIndex ] == "at" ) Hud_SetLocked( buttons[ i ], false ) else - Hud_SetLocked( buttons[ i ], true ) - - if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeIndex ] ) && !IsNorthstarServer() ) - { - Hud_SetLocked( buttons[ i ], true ) - SetButtonRuiText( buttons[ i ], Localize( "#PRIVATE_MATCH_UNAVAILABLE", Localize( GetGameModeDisplayName( modesArray[ modeIndex ] ) ) ) ) - } + Hud_SetLocked( buttons[ i ], true ) } } @@ -90,9 +84,7 @@ void function ModeButton_GetFocus( var button ) string mapName = PrivateMatch_GetSelectedMap() bool mapSupportsMode = PrivateMatch_IsValidMapModeCombo( mapName, modeName ) - if ( !mapSupportsMode && !IsNorthstarServer() ) - Hud_SetText( nextModeDesc, Localize( "#PRIVATE_MATCH_MODE_NO_MAP_SUPPORT", Localize( GetGameModeDisplayName( modeName ) ), Localize( GetMapDisplayName( mapName ) ) ) ) - else if ( IsFDMode( modeName ) ) // HACK! + if ( IsFDMode( modeName ) ) // HACK! Hud_SetText( nextModeDesc, Localize( "#FD_PLAYERS_DESC", Localize( GetGameModeDisplayHint( modeName ) ) ) ) else Hud_SetText( nextModeDesc, GetGameModeDisplayHint( modeName ) ) @@ -114,7 +106,7 @@ void function ModeButton_Click( var button ) // on modded servers set us to the first map for that mode automatically // need this for coliseum mainly which is literally impossible to select without this - if ( IsNorthstarServer() && !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) ) + if ( !PrivateMatch_IsValidMapModeCombo( PrivateMatch_GetSelectedMap(), modesArray[ modeID ] ) ) ClientCommand( "SetCustomMap " + GetPrivateMatchMapsForMode( modeName )[ 0 ] ) // set it diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut index d7c7442f..e3c1f268 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_private_match.nut @@ -247,10 +247,7 @@ void function OnSelectMatchSettings_Activate( var button ) if ( Hud_IsLocked( button ) ) return - if ( !IsNorthstarServer() ) - AdvanceMenu( GetMenu( "MatchSettingsMenu" ) ) - else - AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) ) + AdvanceMenu( GetMenu( "CustomMatchSettingsCategoryMenu" ) ) } void function SetupComboButtons( var menu, var navUpButton, var navDownButton ) @@ -274,13 +271,6 @@ void function SetupComboButtons( var menu, var navUpButton, var navDownButton ) file.matchSettingsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_MATCH_SETTINGS" ) Hud_AddEventHandler( file.matchSettingsButton, UIE_CLICK, OnSelectMatchSettings_Activate ) - if ( !IsNorthstarServer() ) - { - var friendsButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_TITLE_INVITE_FRIENDS" ) - file.inviteFriendsButton = friendsButton - Hud_AddEventHandler( friendsButton, UIE_CLICK, InviteFriendsIfAllowed ) - } - headerIndex++ buttonIndex = 0 file.customizeHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MENU_HEADER_LOADOUTS" ) @@ -575,17 +565,12 @@ function UpdatePrivateMatchButtons() Hud_SetLocked( file.selectMapButton, true ) Hud_SetLocked( file.selectModeButton, true ) Hud_SetLocked( file.matchSettingsButton, true ) - - if ( !IsNorthstarServer() ) - Hud_SetLocked( file.inviteFriendsButton, true ) } else { RHud_SetText( file.startMatchButton, "#START_MATCH" ) Hud_SetLocked( file.selectMapButton, false ) Hud_SetLocked( file.selectModeButton, false ) - if ( !IsNorthstarServer() ) - Hud_SetLocked( file.inviteFriendsButton, false ) string modeName = PrivateMatch_GetSelectedMode() bool settingsLocked = IsFDMode( modeName ) @@ -648,7 +633,7 @@ function UpdateLobby() { float varOrigVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, false ) ) float varOverrideVal = float( GetCurrentPlaylistGamemodeByIndexVar( gamemodeIdx, varName, true ) ) - if ( varOrigVal == varOverrideVal && !IsNorthstarServer() ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist + if ( varOrigVal == varOverrideVal ) // stuff seems to break outside of northstar servers since we dont always use private_match playlist continue string label = Localize( MatchSettings_PlaylistVarLabels[varName] ) + ": " diff --git a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut index 4b3d0f55..f91231b6 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/openinvites.nut @@ -202,7 +202,10 @@ void function UpdateOpenInvite_Thread() void function UICodeCallback_OpenInviteUpdated() { - if ( file.openInviteVisible || IsNorthstarServer() ) + // don't support on northstar + return + + if ( file.openInviteVisible ) return int currentPartySize = GetPartySize() diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index eef19b5e..c97c8cdc 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -531,7 +531,6 @@ void function OnPlayFDButton_Activate( var button ) // repurposed for launching { if ( !Hud_IsLocked( button ) ) { - SetConVarBool( "ns_is_modded_server", true ) SetConVarString( "communities_hostname", "" ) // disable communities due to crash exploits that are still possible through it NSTryAuthWithLocalServer() thread TryAuthWithLocalServer() @@ -601,7 +600,6 @@ void function OnPlayMPButton_Activate( var button ) { Lobby_SetAutoFDOpen( false ) // Lobby_SetFDMode( false ) - SetConVarBool( "ns_is_modded_server", false ) thread file.mpButtonActivateFunc() } } diff --git a/Northstar.CustomServers/mod.json b/Northstar.CustomServers/mod.json index de3fcd0d..fa51f4d4 100644 --- a/Northstar.CustomServers/mod.json +++ b/Northstar.CustomServers/mod.json @@ -4,15 +4,6 @@ "Version": "1.19.0", "LoadPriority": 0, "ConVars": [ - { - "Name": "ns_lobby_type", - "DefaultValue": "0" - }, - { - "Name": "ns_is_modded_server", - "DefaultValue": "1", - "Flags": 8192 - }, { "Name": "ns_should_return_to_lobby", "DefaultValue": "1" diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut index b26e48ca..f8597744 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_northstar_utils.gnut @@ -1,11 +1,5 @@ globalize_all_functions -// whether the server is a modded, northstar server -bool function IsNorthstarServer() -{ - return GetConVarBool( "ns_is_modded_server" ) -} - // whether the game should return to the lobby on GameRules_EndMatch() bool function ShouldReturnToLobby() { -- cgit v1.2.3 From 3714f23edde5a48aa29560dc74fc5a59ce2ca85a Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:57:00 +0100 Subject: Fix `StringReplace` looping forever when replacing character when replacing same character as match (#736) Find the next replacement starting from the end of the last one, instead of from the start of the string --- Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index a2de9913..9e762985 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -362,7 +362,7 @@ string function StringReplace( string baseString, string searchString, string re source = part1 + replaceString + part2 loopedOnce = true - findResult = source.find( searchString ) + findResult = source.find( searchString, findResult + replaceString.len() ) } return baseString -- cgit v1.2.3 From bdb2fa3ca291101dc861d19e8979077bf8fdf57a Mon Sep 17 00:00:00 2001 From: William Miller Date: Wed, 11 Oct 2023 18:00:11 -0300 Subject: Unlock paid items with progression enabled (#726) When turning on progression now, items that should be purchased from the store will remain unlocked. These items contain among others the prime versions of the various Titans. Some mods make explicit use of prime Titans to switch to alternate loadouts (Brute, Archon, ...) Some players would like to opt into progression but decide against it due to losing access to prime Titans As such we should keep them unlocked, even when progression is enabled as they cannot be obtained through progression alone anyway. --- Northstar.CustomServers/mod/scripts/vscripts/_items.nut | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index 5878da13..a5c3e270 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -5700,6 +5700,12 @@ bool function IsSubItemLocked( entity player, string ref, string parentRef ) { if ( DevEverythingUnlocked( player ) ) return false + + if ( IsItemPurchasableEntitlement( ref, parentRef ) ) + return false + + if ( GetItemType( ref ) == eItemTypes.PRIME_TITAN || GetSubitemType( parentRef, ref ) == eItemTypes.PRIME_TITAN ) + return false if ( IsItemInEntitlementUnlock( ref, parentRef ) ) { @@ -5819,6 +5825,12 @@ bool function IsItemLocked( entity player, string ref ) { if ( DevEverythingUnlocked( player ) ) return false + + if ( IsItemPurchasableEntitlement( ref ) ) + return false + + if ( GetItemType( ref ) == eItemTypes.PRIME_TITAN ) + return false if ( IsItemInEntitlementUnlock( ref ) ) { -- cgit v1.2.3 From 7893a11faa5a9f3d13b241b1269b169ae8c519d3 Mon Sep 17 00:00:00 2001 From: Respawn Date: Thu, 12 Oct 2023 02:22:29 +0200 Subject: Add menu_edit_pilot_loadouts.nut from englishclient_frontend --- .../vscripts/ui/menu_edit_pilot_loadouts.nut | 165 +++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut new file mode 100644 index 00000000..e785b067 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut @@ -0,0 +1,165 @@ +untyped + +global function InitEditPilotLoadoutsMenu + +struct +{ + var menu + var loadoutPanel + var[NUM_PERSISTENT_PILOT_LOADOUTS] loadoutHeaders + var[NUM_PERSISTENT_PILOT_LOADOUTS] activateButtons + bool enteringEdit = false + var unlockReq +} file + +void function InitEditPilotLoadoutsMenu() +{ + file.menu = GetMenu( "EditPilotLoadoutsMenu" ) + var menu = file.menu + + AddMenuEventHandler( menu, eUIEvent.MENU_OPEN, OnPilotLoadoutsMenu_Open ) + AddMenuEventHandler( menu, eUIEvent.MENU_CLOSE, OnPilotLoadoutsMenu_Close ) + AddMenuEventHandler( menu, eUIEvent.MENU_INPUT_MODE_CHANGED, OnPilotLoadoutsMenu_InputModeChanged ) + + for ( int i = 0; i < NUM_PERSISTENT_PILOT_LOADOUTS; i++ ) + { + var activateButton = Hud_GetChild( menu, "Button" + i ) + activateButton.s.rowIndex <- i + Hud_SetVisible( activateButton, true ) + Hud_AddEventHandler( activateButton, UIE_CLICK, OnLoadoutButton_Activate ) + Hud_AddEventHandler( activateButton, UIE_GET_FOCUS, OnLoadoutButton_Focused ) + Hud_AddEventHandler( activateButton, UIE_LOSE_FOCUS, OnLoadoutButton_LostFocus ) + file.activateButtons[i] = activateButton + } + + Hud_SetFocused( file.activateButtons[0] ) + + file.loadoutPanel = Hud_GetChild( menu, "PilotLoadoutDisplay" ) + file.unlockReq = Hud_GetChild( menu, "UnlockReq" ) + + AddMenuFooterOption( menu, BUTTON_A, "#A_BUTTON_SELECT" ) + AddMenuFooterOption( menu, BUTTON_B, "#B_BUTTON_BACK", "#BACK" ) +} + +void function OnPilotLoadoutsMenu_Open() +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + RunMenuClientFunction( "ClearEditingPilotLoadoutIndex" ) + + int loadoutIndex = uiGlobal.pilotSpawnLoadoutIndex + UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons ) + UpdatePilotLoadoutPanel( file.loadoutPanel, GetCachedPilotLoadout( loadoutIndex ) ) + UI_SetPresentationType( ePresentationType.PILOT ) + + RefreshCreditsAvailable() +} + +void function OnPilotLoadoutsMenu_Close() +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + foreach ( i, button in file.activateButtons ) + { + string pilotLoadoutRef = "pilot_loadout_" + ( i + 1 ) + if ( !IsItemNew( player, pilotLoadoutRef ) ) + continue + + ClearNewStatus( button, pilotLoadoutRef ) + } +} + +void function OnPilotLoadoutsMenu_InputModeChanged() +{ + UpdatePilotLoadoutPanelBinds( file.loadoutPanel ) +} + +void function OnLoadoutButton_Focused( var button ) +{ + int index = expect int( button.s.rowIndex ) + + UpdatePilotLoadout( index ) + + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + string unlockReq = GetItemUnlockReqText( pilotLoadoutRef ) + RHud_SetText( file.unlockReq, unlockReq ) +} + +void function UpdatePilotLoadout( int loadoutIndex ) +{ + PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex ) + + UpdatePilotLoadoutPanel( file.loadoutPanel, loadout ) + RunMenuClientFunction( "UpdatePilotModel", loadoutIndex ) +} + +void function OnLoadoutButton_Activate( var button ) +{ + if ( !IsFullyConnected() ) + return + + if ( Hud_IsLocked( button ) ) + { + int index = expect int ( button.s.rowIndex ) + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + + array buttons + foreach ( button in file.activateButtons ) + { + buttons.append( button ) + } + + OpenBuyItemDialog( buttons, button, GetItemName( pilotLoadoutRef ), pilotLoadoutRef ) + return + } + + int loadoutIndex = expect int ( button.s.rowIndex ) + SetEditLoadout( "pilot", loadoutIndex ) + + if ( EDIT_LOADOUT_SELECTS ) + { + bool indexChanged = loadoutIndex != uiGlobal.pilotSpawnLoadoutIndex + + if ( indexChanged ) + { + EmitUISound( "Menu_LoadOut_Pilot_Select" ) + + if ( !IsLobby() ) + uiGlobal.updatePilotSpawnLoadout = true + } + + uiGlobal.pilotSpawnLoadoutIndex = loadoutIndex + ClientCommand( "RequestPilotLoadout " + loadoutIndex ) + } + + if ( PRE_RELEASE_DEMO && loadoutIndex < 3 ) + { + UpdatePilotLoadoutButtons( loadoutIndex, file.activateButtons ) + return + } + + RunMenuClientFunction( "SetEditingPilotLoadoutIndex", loadoutIndex ) + AdvanceMenu( GetMenu( "EditPilotLoadoutMenu" ) ) +} + +void function OnLoadoutButton_LostFocus( var button ) +{ + entity player = GetUIPlayer() + if ( !IsValid( player ) ) + return + + int loadoutIndex = expect int ( button.s.rowIndex ) + string pilotLoadoutRef = "pilot_loadout_" + ( loadoutIndex + 1 ) + ClearNewStatus( button, pilotLoadoutRef ) + + if ( IsItemLocked( player, pilotLoadoutRef ) ) + return + + PilotLoadoutDef loadout = GetCachedPilotLoadout( loadoutIndex ) + if ( (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) ) + Hud_SetNew( button, true ) +} -- cgit v1.2.3 From c2716db187ce1e896031ac75e097f96754dc92cf Mon Sep 17 00:00:00 2001 From: Respawn Date: Thu, 12 Oct 2023 02:23:02 +0200 Subject: Add menu_pilot_loadouts_shared.nut from englishclient_frontend --- .../vscripts/ui/menu_pilot_loadouts_shared.nut | 284 +++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut new file mode 100644 index 00000000..122403a3 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut @@ -0,0 +1,284 @@ + +global function UpdatePilotLoadoutPanel +global function UpdatePilotLoadoutPanelBinds +global function UpdatePilotLoadoutButtons +global function UpdatePilotItemButton + +void function UpdatePilotLoadoutButtons( int selectedIndex, var[NUM_PERSISTENT_PILOT_LOADOUTS] buttons, bool focusSelected = true ) +{ + entity player = GetUIPlayer() + if ( player == null ) + return + + int numLoadouts = GetAllCachedPilotLoadouts().len() + + // HACK: num_pilot_loadouts is just used to disable certain loadouts for FNF + int numLoadoutsForPlaylist = GetCurrentPlaylistVarInt( "num_pilot_loadouts", 0 ) + if ( numLoadoutsForPlaylist > 0 ) + numLoadouts = numLoadoutsForPlaylist + + foreach ( index, button in buttons ) + { + PilotLoadoutDef loadout = GetCachedPilotLoadout( index ) + RHud_SetText( button, GetPilotLoadoutName( loadout ) ) + Hud_SetPanelAlpha( button, 0 ) + + bool isSelected = ( index == selectedIndex ) ? true : false + Hud_SetSelected( button, isSelected ) + + string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) + Hud_SetLocked( button, IsItemLocked( player, pilotLoadoutRef ) ) + + bool shouldShowNew = ButtonShouldShowNew( eItemTypes.FEATURE, pilotLoadoutRef ) + if ( !shouldShowNew && (RefHasAnyNewSubitem( player, loadout.primary ) || RefHasAnyNewSubitem( player, loadout.secondary ) || RefHasAnyNewSubitem( player, loadout.weapon3 )) ) + shouldShowNew = true + + if ( IsItemLocked( player, pilotLoadoutRef ) ) + shouldShowNew = false + + Hud_SetNew( button, shouldShowNew ) + + RefreshButtonCost( button, pilotLoadoutRef ) + } + + if ( focusSelected ) + Hud_SetFocused( buttons[ selectedIndex ] ) +} + +void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout ) +{ + SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalName" ), Localize( GetItemName( loadout.special ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryName" ), Localize( GetItemName( loadout.primary ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryName" ), Localize( GetItemName( loadout.secondary ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Name" ), Localize( GetItemName( loadout.weapon3 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceName" ), Localize( GetItemName( loadout.ordnance ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit1Name" ), Localize( GetItemName( loadout.passive1 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Kit2Name" ), Localize( GetItemName( loadout.passive2 ) ) ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "ExecutionName" ), Localize( GetItemName( loadout.execution ) ) ) + + UpdatePilotLoadoutPanelBinds( loadoutPanel ) + + var menu = Hud_GetParent( loadoutPanel ) + array buttons = GetElementsByClassname( menu, "PilotLoadoutPanelButtonClass" ) + + /*if ( button ) + { + // TEMP disabled since Hud_GetChild( menu, "ButtonTooltip" ) will fail + //if ( HandleLockedMenuItem( menu, button ) ) + // return + }*/ + bool isEdit + if ( Hud_GetHudName( loadoutPanel ) == "PilotLoadoutButtons" ) // Edit menu + isEdit = true + else // Select menu + isEdit = false + + foreach ( button in buttons ) + UpdatePilotItemButton( button, loadout, isEdit ) + + var renameEditBox = Hud_GetChild( loadoutPanel, "RenameEditBox" ) + + asset pilotAppearanceImage = loadout.camoIndex > 0 ? CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.camoIndex ) ) : $"rui/menu/common/appearance_button_swatch" + + asset primaryAppearanceImage + if ( loadout.primarySkinIndex == 0 ) // default skin + primaryAppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.primarySkinIndex == 1 ) // camo + primaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.primaryCamoIndex ) ) + else // warpaint skin + primaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex ) ) + + asset secondaryAppearanceImage + if ( loadout.secondarySkinIndex == 0 ) // default skin + secondaryAppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.secondarySkinIndex == 1 ) // camo + secondaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.secondaryCamoIndex ) ) + else // warpaint skin + secondaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex ) ) + + asset weapon3AppearanceImage + if ( loadout.weapon3SkinIndex == 0 ) // default skin + weapon3AppearanceImage = $"rui/menu/common/appearance_button_swatch" + else if ( loadout.weapon3SkinIndex == 1 ) // camo + weapon3AppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.weapon3CamoIndex ) ) + else // warpaint skin + weapon3AppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex ) ) + + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ), "camoImage", pilotAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ), "camoImage", primaryAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) ), "camoImage", secondaryAppearanceImage ) + RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) ), "camoImage", weapon3AppearanceImage ) + + array nonItemElements + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonGender" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonSecondarySkin" ) ) + nonItemElements.append( Hud_GetChild( loadoutPanel, "ButtonWeapon3Skin" ) ) + nonItemElements.append( renameEditBox ) + + foreach ( elem in nonItemElements ) + { + if ( isEdit ) + Hud_Show( elem ) + else + Hud_Hide( elem ) + } + Hud_SetEnabled( renameEditBox, isEdit ) +} + +void function UpdatePilotItemButton( var button, PilotLoadoutDef loadout, bool isEdit ) +{ + string propertyName = Hud_GetScriptID( button ) + string itemRef = GetPilotLoadoutValue( loadout, propertyName ) + int itemType = GetItemTypeFromPilotLoadoutProperty( propertyName ) + asset image + + ItemDisplayData parentItem + + if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT || itemType == eItemTypes.PILOT_PRIMARY_MOD || itemType == eItemTypes.PILOT_SECONDARY_MOD || itemType == eItemTypes.PILOT_WEAPON_MOD3 ) + { + string parentProperty = GetParentLoadoutProperty( "pilot", propertyName ) + Assert( parentProperty == "primary" || parentProperty == "secondary" || parentProperty == "weapon3" ) + + if ( parentProperty == "primary" ) + parentItem = GetItemDisplayData( loadout.primary ) + else if ( parentProperty == "secondary" ) + parentItem = GetItemDisplayData( loadout.secondary ) + else + parentItem = GetItemDisplayData( loadout.weapon3 ) + + bool isHiddenAttachment = false + + if ( itemType == eItemTypes.PILOT_PRIMARY_ATTACHMENT ) + { + // Disable attachment option for "special" primary weapons + if ( "menuCategory" in parentItem.i && ( expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.SPECIAL || expect int( parentItem.i.menuCategory ) == ePrimaryWeaponCategory.HANDGUN ) ) + { + isHiddenAttachment = true + + Hud_SetWidth( button, 0 ) + Hud_SetPos( button, 0, 0 ) // Clear sibling offset + } + else + { + int defaultButtonWidth = int( ContentScaledX( 72 ) ) + int defaultOffsetX = int( ContentScaledX( 6 ) ) + + Hud_SetWidth( button, defaultButtonWidth ) + Hud_SetPos( button, defaultOffsetX, 0 ) + } + } + + if ( !isHiddenAttachment ) + image = GetImage( itemType, parentItem.ref, itemRef ) + } + else + { + image = GetImage( itemType, itemRef ) + } + + if ( itemType == eItemTypes.PILOT_PRIMARY || itemType == eItemTypes.PILOT_SECONDARY ) + { + //if ( isEdit ) + //{ + // RuiSetString( Hud_GetRui( button ), "subText", "" ) + // RuiSetFloat( Hud_GetRui( button ), "numSegments", 0 ) + // RuiSetFloat( Hud_GetRui( button ), "filledSegments", 0 ) + //} + //else + { + int currentXP = WeaponGetXP( GetLocalClientPlayer(), itemRef ) + int numPips = WeaponGetNumPipsForXP( itemRef, currentXP ) + int filledPips = WeaponGetFilledPipsForXP( itemRef, currentXP ) + RuiSetString( Hud_GetRui( button ), "subText", WeaponGetDisplayGenAndLevelForXP( itemRef, currentXP ) ) + RuiSetFloat( Hud_GetRui( button ), "numSegments", float( numPips ) ) + RuiSetFloat( Hud_GetRui( button ), "filledSegments", float( filledPips ) ) + } + } + + var rui = Hud_GetRui( button ) + + if ( image == $"" ) + { + RuiSetBool( rui, "isVisible", false ) + Hud_SetEnabled( button, false ) + } + else + { + RuiSetBool( rui, "isVisible", true ) + RuiSetImage( rui, "buttonImage", image ) + + Hud_SetEnabled( button, true ) + } + + bool isLocked = false + bool shouldShowNew = false + + // For unlock and subitem checks below, treat weapon3 as secondary + if ( propertyName == "weapon3Mod1" ) + propertyName = "secondaryMod1" + else if ( propertyName == "weapon3Mod2" ) + propertyName = "secondaryMod2" + else if ( propertyName == "weapon3Mod3" ) + propertyName = "secondaryMod3" + + string propertyRef = propertyName.tolower() + + if ( !IsSubItemType( itemType ) ) + { + if ( IsUnlockValid( propertyRef ) && IsItemLocked( GetUIPlayer(), propertyRef ) ) + { + RefreshButtonCost( button, propertyRef ) + isLocked = true + } + shouldShowNew = ButtonShouldShowNew( itemType, itemRef ) + } + else + { + if ( IsUnlockValid( propertyRef, parentItem.ref ) && IsSubItemLocked( GetUIPlayer(), propertyRef, parentItem.ref ) ) + { + RefreshButtonCost( button, propertyRef ) + isLocked = true + } + shouldShowNew = ButtonShouldShowNew( itemType, itemRef, parentItem.ref ) + } + + Hud_SetLocked( button, isLocked ) + + if ( !shouldShowNew && IsUnlockValid( propertyRef, parentItem.ref ) ) + shouldShowNew = ButtonShouldShowNew( GetSubitemType( parentItem.ref, propertyRef ), propertyRef, parentItem.ref ) + Hud_SetNew( button, shouldShowNew ) + +#if HAS_THREAT_SCOPE_SLOT_LOCK + if ( propertyName == "primaryMod2" ) + { + string attatchmentRef = GetPilotLoadoutValue( loadout, "primaryAttachment" ) + if ( attatchmentRef == "threat_scope" ) + { + Hud_SetLocked( button, true ) + RefreshButtonCost( button, propertyRef, "", 0, 0 ) + Hud_SetNew( button, false ) + } + } +#endif +} + +void function UpdatePilotLoadoutPanelBinds( var loadoutPanel ) +{ + if ( IsControllerModeActive() ) + { + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponCycle%" ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponCycle%" ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_HOLD_HINT" ) ) + } + else + { + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "PrimaryBind" ), "%weaponSelectPrimary0%" ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "SecondaryBind" ), "%weaponSelectPrimary1%" ) + SetLabelRuiText( Hud_GetChild( loadoutPanel, "Weapon3Bind" ), Localize( "#WEAPON3_PRESS_HINT" ) ) + } + + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalBind" ), Localize( "%offhand1%" ) ) + //SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceBind" ), Localize( "%offhand0%" ) ) +} -- cgit v1.2.3 From 407c5ce39c3124658a869c387e4308e6b72e4c23 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 12 Oct 2023 01:29:31 +0100 Subject: Fix INVALID_REF errors caused by mods (#657) `INVALID_REF` errors were being caused by trying to get the item image for weapon skins. If a mod (e.g. moreskins) added new skins, the client equipped one, and then the mod is disabled, the client now has bad persistence. This is mostly handled fine by the game, except for weapon skins. This PR prevents the crash, and resets the bad persistence to default. --- .../vscripts/ui/menu_edit_pilot_loadouts.nut | 5 +++++ .../vscripts/ui/menu_pilot_loadouts_shared.nut | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut index e785b067..89479a76 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_edit_pilot_loadouts.nut @@ -82,6 +82,11 @@ void function OnLoadoutButton_Focused( var button ) { int index = expect int( button.s.rowIndex ) + // update the editingLoadoutIndex on focus so that it always matches + // with the pilot loadout panel + uiGlobal.editingLoadoutIndex = index + uiGlobal.editingLoadoutType = "pilot" + UpdatePilotLoadout( index ) string pilotLoadoutRef = "pilot_loadout_" + ( index + 1 ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut index 122403a3..f0139e04 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_pilot_loadouts_shared.nut @@ -86,7 +86,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.primarySkinIndex == 1 ) // camo primaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.primaryCamoIndex ) ) else // warpaint skin - primaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex ) ) + primaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.primary, loadout.primarySkinIndex, "primarySkinIndex" ) asset secondaryAppearanceImage if ( loadout.secondarySkinIndex == 0 ) // default skin @@ -94,7 +94,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.secondarySkinIndex == 1 ) // camo secondaryAppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.secondaryCamoIndex ) ) else // warpaint skin - secondaryAppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex ) ) + secondaryAppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.secondary, loadout.secondarySkinIndex, "secondarySkinIndex" ) asset weapon3AppearanceImage if ( loadout.weapon3SkinIndex == 0 ) // default skin @@ -102,7 +102,7 @@ void function UpdatePilotLoadoutPanel( var loadoutPanel, PilotLoadoutDef loadout else if ( loadout.weapon3SkinIndex == 1 ) // camo weapon3AppearanceImage = CamoSkin_GetImage( CamoSkins_GetByIndex( loadout.weapon3CamoIndex ) ) else // warpaint skin - weapon3AppearanceImage = GetItemImage( GetSkinRefFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex ) ) + weapon3AppearanceImage = GetItemImageFromWeaponRefAndPersistenceValue( loadout.weapon3, loadout.weapon3SkinIndex, "weapon3SkinIndex" ) RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPilotCamo" ) ), "camoImage", pilotAppearanceImage ) RuiSetImage( Hud_GetRui( Hud_GetChild( loadoutPanel, "ButtonPrimarySkin" ) ), "camoImage", primaryAppearanceImage ) @@ -282,3 +282,19 @@ void function UpdatePilotLoadoutPanelBinds( var loadoutPanel ) //SetLabelRuiText( Hud_GetChild( loadoutPanel, "TacticalBind" ), Localize( "%offhand1%" ) ) //SetLabelRuiText( Hud_GetChild( loadoutPanel, "OrdnanceBind" ), Localize( "%offhand0%" ) ) } + +asset function GetItemImageFromWeaponRefAndPersistenceValue(string weaponRef, int persistenceValue, string loadoutProperty) +{ + string skinRef = GetSkinRefFromWeaponRefAndPersistenceValue( weaponRef, persistenceValue ) + if (!IsRefValid(skinRef)) + { + if (uiGlobal.editingLoadoutIndex != -1) + { + printt( "Resetting invalid " + loadoutProperty + " for weapon " + weaponRef ) + SetCachedLoadoutValue(GetUIPlayer(), "pilot", uiGlobal.editingLoadoutIndex, loadoutProperty, "0") + } + return $"rui/menu/common/appearance_button_swatch" + } + + return GetItemImage( skinRef ) +} -- cgit v1.2.3 From 2bb9216939a8bfd9fcd300893cb0626890a18a44 Mon Sep 17 00:00:00 2001 From: William Miller Date: Thu, 12 Oct 2023 18:54:27 -0300 Subject: Expose extra optional arg in `UpdatePlayerStat` function (#742) Exposes the previously hidden string argument in the `UpdatePlayerStat` function, that is needed to track some things more easily when hooking stats. --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 010184ff..208e6da1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -136,12 +136,12 @@ float function PlayerStat_GetCurrentFloat( entity player, string statCategory, s return 0 } -void function UpdatePlayerStat( entity player, string statCategory, string subStat, int count = 1 ) +void function UpdatePlayerStat( entity player, string statCategory, string subStat, int count = 1, string statAlias = "" ) { if ( !IsValid( player ) ) return - Stats_IncrementStat( player, statCategory, subStat, "", count.tofloat() ) + Stats_IncrementStat( player, statCategory, subStat, statAlias, count.tofloat() ) } void function IncrementPlayerDidPilotExecutionWhileCloaked( entity player ) -- cgit v1.2.3 From a7d40aac072c6725548c2ba6d6a9ab649191594f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 14 Oct 2023 21:41:01 +0100 Subject: Add workflow for adding PRs and Issues to the project board (#696) Automatically adds all opened issues and pull requests to the project board. --- .github/workflows/add-to-project.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/add-to-project.yml diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml new file mode 100644 index 00000000..3a1d1c9a --- /dev/null +++ b/.github/workflows/add-to-project.yml @@ -0,0 +1,19 @@ +name: add-to-project + +on: + issues: + types: + - opened + pull_request: + types: + - opened + +jobs: + add-to-project: + name: Add to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@v0.5.0 + with: + project-url: "https://github.com/orgs/R2Northstar/projects/3" + github-token: "${{ secrets.ADD_TO_PROJECT_PAT }}" -- cgit v1.2.3 From 8dfc1b9a0749c35c9f53745400718188cf6fe6f6 Mon Sep 17 00:00:00 2001 From: GeckoEidechse Date: Sun, 15 Oct 2023 02:18:18 +0200 Subject: Only run `add-to-project` action on issues PRs from forks are triggered from that fork which means that they don't have access to the necessary token --- .github/workflows/add-to-project.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml index 3a1d1c9a..556672e9 100644 --- a/.github/workflows/add-to-project.yml +++ b/.github/workflows/add-to-project.yml @@ -4,9 +4,6 @@ on: issues: types: - opened - pull_request: - types: - - opened jobs: add-to-project: -- cgit v1.2.3 From 6df399f251bbaf8b43629ba023061eea67a37656 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 16 Oct 2023 13:53:02 +0100 Subject: Make dropships immune to Titan step damage (#737) Currently dropships take damage from titans stepping on them, this prevents that Co-authored-by: William Miller --- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 4 ++++ 1 file changed, 4 insertions(+) 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 bab7eaed..c11ca36f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -628,6 +628,10 @@ void function SetRecalculateRespawnAsTitanStartPointCallback( entity functionref bool function ShouldEntTakeDamage_SPMP( entity ent, var damageInfo ) { + // dropships are immune to being crushed + if ( ( IsDropship( ent ) || IsEvacDropship( ent ) ) && IsTitanCrushDamage( damageInfo ) ) + return false + return true } -- cgit v1.2.3 From 327e40edf85e9ad12b85256382123049d55fd07f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:27:37 +0100 Subject: Award titan assist stats based on titan soul damage history (#746) Titans stores damage history in their Soul component, not the NPC itself, probably due to how game handles pilot/auto-titan interaction with the Titan entities. This means that we weren't awarding assist stats properly for titan assists --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 208e6da1..dbfcea61 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -571,9 +571,11 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo ) // assistsTotal ( weapon_kill_stats ) // note: eww table alreadyAssisted - foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) + // titans store their recentDamageHistory in the soul + entity assistVictim = ( victim.IsTitan() && IsValid( victim.GetTitanSoul() ) ) ? victim.GetTitanSoul() : victim + foreach( DamageHistoryStruct attackerInfo in assistVictim.e.recentDamageHistory ) { - if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim ) + if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == assistVictim ) continue bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false -- cgit v1.2.3 From bc4e4263e714f9b1eff58f2c39bb714a3564b2e6 Mon Sep 17 00:00:00 2001 From: GalacticMoblin <100473309+GalacticMoblin@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:36:46 +0100 Subject: Fix a crash related to Arc Cannon (#681) Fixes an issue where dying while the Arc Cannon beam is hurting someone would cause an error. Co-authored-by: Dinorush <62536724+Dinorush@users.noreply.github.com> --- .../mod/scripts/vscripts/weapons/_arc_cannon.nut | 62 ++++++++-------------- 1 file changed, 22 insertions(+), 40 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut index 01138967..defb1a56 100644 --- a/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut +++ b/Northstar.Custom/mod/scripts/vscripts/weapons/_arc_cannon.nut @@ -536,12 +536,6 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) thread CreateArcCannonBeam( zapInfo.weapon, target, beamStartPos, beamEndPos, zapInfo.player, ARC_CANNON_BEAM_LIFETIME, zapInfo.radius, boltWidth, 5, true, firstBeam ) #if SERVER - local isMissile = ( target.GetClassName() == "rpg_missile" ) - if ( !isMissile ) - wait ARC_CANNON_FORK_DELAY - else - wait 0.05 - local deathPackage = damageTypes.arcCannon float damageAmount @@ -569,40 +563,20 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) bool hasFastPacitor = false bool noArcing = false - if ( IsValid( zapInfo.weapon ) ) - { - entity weap = expect entity( zapInfo.weapon ) - hasFastPacitor = weap.GetWeaponInfoFileKeyField( "push_apart" ) != null && weap.GetWeaponInfoFileKeyField( "push_apart" ) == 1 - noArcing = weap.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weap.GetWeaponInfoFileKeyField( "no_arcing" ) == 1 - } + entity weapon = expect entity( zapInfo.weapon ) + hasFastPacitor = weapon.GetWeaponInfoFileKeyField( "push_apart" ) != null && weapon.GetWeaponInfoFileKeyField( "push_apart" ) == 1 + noArcing = weapon.GetWeaponInfoFileKeyField( "no_arcing" ) != null && weapon.GetWeaponInfoFileKeyField( "no_arcing" ) == 1 + float critScale = weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) if ( target.GetArmorType() == ARMOR_TYPE_HEAVY ) { - if ( IsValid( zapInfo.weapon ) ) - { - entity weapon = expect entity( zapInfo.weapon ) - damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor ) - damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor ) - } - else - { - damageMin = 100 - damageMax = zapInfo.player.IsNPC() ? 1200 : 800 - } + damageMin = weapon.GetWeaponSettingInt( damageFarValueTitanArmor ) + damageMax = weapon.GetWeaponSettingInt( damageNearValueTitanArmor ) } else { - if ( IsValid( zapInfo.weapon ) ) - { - entity weapon = expect entity( zapInfo.weapon ) - damageMin = weapon.GetWeaponSettingInt( damageFarValue ) - damageMax = weapon.GetWeaponSettingInt( damageNearValue ) - } - else - { - damageMin = 120 - damageMax = zapInfo.player.IsNPC() ? 140 : 275 - } + damageMin = weapon.GetWeaponSettingInt( damageFarValue ) + damageMax = weapon.GetWeaponSettingInt( damageNearValue ) if ( target.IsNPC() ) { @@ -612,11 +586,10 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) } - local chargeRatio = GetArcCannonChargeFraction( zapInfo.weapon ) - if ( IsValid( zapInfo.weapon ) && !zapInfo.weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) ) + local chargeRatio = GetArcCannonChargeFraction( weapon ) + if ( !weapon.GetWeaponSettingBool( eWeaponVar.charge_require_input ) ) { // use distance for damage if the weapon auto-fires - entity weapon = expect entity( zapInfo.weapon ) float nearDist = weapon.GetWeaponSettingFloat( damageNearDistance ) float farDist = weapon.GetWeaponSettingFloat( damageFarDistance ) @@ -629,10 +602,19 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) damageAmount = GraphCapped( zapInfo.chargeFrac, 0, chargeRatio, damageMin, damageMax ) } local damageFalloff = ARC_CANNON_DAMAGE_FALLOFF_SCALER - if ( IsValid( zapInfo.weapon ) && zapInfo.weapon.HasMod( "splitter" ) ) + if ( weapon.HasMod( "splitter" ) ) damageFalloff = SPLITTER_DAMAGE_FALLOFF_SCALER damageAmount *= pow( damageFalloff, chainNum - 1 ) + local isMissile = ( target.GetClassName() == "rpg_missile" ) + if ( !isMissile ) + wait ARC_CANNON_FORK_DELAY + else + wait 0.05 + + if ( !IsValid( target ) || !IsValid( zapInfo.player ) ) + return + local dmgSourceID = zapInfo.dmgSourceID // Update Later - This shouldn't be done here, this is not where we determine if damage actually happened to the target @@ -660,13 +642,13 @@ function ZapTarget( zapInfo, target, beamStartPos, beamEndPos, chainNum = 1 ) // Do 3rd person effect on the body asset effect string tag - target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = zapInfo.weapon.GetWeaponSettingFloat( eWeaponVar.critical_hit_damage_scale ) } ) + target.TakeDamage( damageAmount, zapInfo.player, zapInfo.player, { origin = beamEndPos, force = Vector(0,0,0), scriptType = deathPackage, weapon = zapInfo.weapon, damageSourceId = dmgSourceID,criticalHitScale = critScale } ) //vector dir = Normalize( beamEndPos - beamStartPos ) //vector velocity = dir * 600 //PushPlayerAway( target, velocity ) //PushPlayerAway( expect entity( zapInfo.player ), -velocity ) - if ( IsValid( zapInfo.weapon ) && hasFastPacitor ) + if ( IsValid( weapon ) && hasFastPacitor ) { if ( IsAlive( target ) && IsAlive( expect entity( zapInfo.player ) ) && target.IsTitan() ) { -- cgit v1.2.3 From aa79ad4b924d838904169b4e251c27c5f09557db Mon Sep 17 00:00:00 2001 From: William Miller Date: Tue, 17 Oct 2023 21:41:01 -0300 Subject: Fix Titan Assist not tracking properly (#744) Titan Assist medals aren't given to players who assisted damage when someone kills a titan, that is due the fact that Titans stores damage history in their Soul component, not the NPC itself. --- .../mod/scripts/vscripts/mp/_score.nut | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index 0b55e9ff..df7577aa 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -202,18 +202,23 @@ void function ScoreEvent_TitanKilled( entity victim, entity attacker, var damage AddPlayerScore( attacker, "KillTitan" ) } - table alreadyAssisted - foreach( DamageHistoryStruct attackerInfo in victim.e.recentDamageHistory ) + entity soul = victim.GetTitanSoul() + if ( IsValid( soul ) ) { - if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == victim ) - continue - - bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false - if( attackerInfo.attacker != attacker && !exists ) + table alreadyAssisted + + foreach( DamageHistoryStruct attackerInfo in soul.e.recentDamageHistory ) { - alreadyAssisted[attackerInfo.attacker.GetEncodedEHandle()] <- true - AddPlayerScore(attackerInfo.attacker, "TitanAssist" ) - Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), victim.GetEncodedEHandle(), attackerInfo.time ) + if ( !IsValid( attackerInfo.attacker ) || !attackerInfo.attacker.IsPlayer() || attackerInfo.attacker == soul ) + continue + + bool exists = attackerInfo.attacker.GetEncodedEHandle() in alreadyAssisted ? true : false + if( attackerInfo.attacker != attacker && !exists ) + { + alreadyAssisted[attackerInfo.attacker.GetEncodedEHandle()] <- true + AddPlayerScore(attackerInfo.attacker, "TitanAssist" ) + Remote_CallFunction_NonReplay( attackerInfo.attacker, "ServerCallback_SetAssistInformation", attackerInfo.damageSourceId, attacker.GetEncodedEHandle(), soul.GetEncodedEHandle(), attackerInfo.time ) + } } } -- cgit v1.2.3 From d84d875347b54e87dfada23f516f89cf507be610 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 18 Oct 2023 19:34:47 +0100 Subject: Stop logging invalid map/mode exception in progression (#750) Some game modes like Gun Game or Infection are not considered valid yet, causing the warning message to be spammed in the logs. Necessary work should be done to add the modes to the list of valid modes. Until we will just comment out the print statement in order to prevent log spam. Co-authored-by: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index dbfcea61..63841f7a 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -264,7 +264,7 @@ void function Stats_IncrementStat( entity player, string statCategory, string st // persistence string, we can't save the persistence so we have to just return if ( str != saveVar ) { - printt( ex ) + //printt( ex, str, GetMapName(), mode ) // Commented out due to spamming logs on invalid modes (e.g. Gun Game, Infection, ...) return } } -- cgit v1.2.3 From 640d3915c1a2c76ce4ff6d0c2cf7868c6d2e4f4f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 21 Oct 2023 17:39:21 +0100 Subject: Make add to project workflow work on PRs (#753) Fix the add to project workflow so that it works on PRs from forks, securely by running it in the context of the target. --- .github/workflows/add-to-project.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml index 556672e9..773a52b8 100644 --- a/.github/workflows/add-to-project.yml +++ b/.github/workflows/add-to-project.yml @@ -4,6 +4,9 @@ on: issues: types: - opened + pull_request_target: + types: + - opened jobs: add-to-project: -- cgit v1.2.3 From 82f87121da416de0f6feab1fe2aa775c9c5b3088 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sat, 28 Oct 2023 20:22:41 +0100 Subject: Change gun game score limit setting (#735) Gun game was never set up to properly use the playlistvars for setting guns, and relied on playlistvaroverrides to set the score limit, this caused the change to persist to other modes --- Northstar.Custom/keyvalues/playlists_v2.txt | 2 -- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut | 8 -------- 2 files changed, 10 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index 21934b31..c22e2174 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -47,8 +47,6 @@ playlists max_teams 12 classic_mp 1 - scorelimit 21 // temp until we have a way of dynamically setting non-default scorelimit in code - gamemode_score_hint #GAMEMODE_SCORE_HINT_FFA gamemode_bullet_001 #GAMEMODE_BULLET_FFA_001 gamemode_bullet_002 #GAMEMODE_BULLET_FFA_002 diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut index 8f34541b..ad46b42e 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_gg.gnut @@ -18,14 +18,6 @@ void function GamemodeGG_Init() AddCallback_GameStateEnter( eGameState.WinnerDetermined, OnWinnerDetermined ) AddCallback_GGEarnMeterFull( OnGGEarnMeterFilled ) - - // set scorelimit if it's wrong, sort of a jank way to do it but best i've got rn - try - { - if ( GetCurrentPlaylistVarInt( "scorelimit", GetGunGameWeapons().len() ) != GetGunGameWeapons().len() ) - SetPlaylistVarOverride( "scorelimit", GetGunGameWeapons().len().tostring() ) - } - catch ( ex ) {} } void function OnPlayerDisconnected(entity player) -- cgit v1.2.3 From faff062f6cbdac84803ced8a7c6e69dd7731af57 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:10:40 +0000 Subject: Don't mark items as new if progression is disabled (#752) Also doesn't show the challenge completion notifications in game as a nice side effect --- Northstar.CustomServers/mod/scripts/vscripts/_items.nut | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index a5c3e270..a23a68b0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -10231,6 +10231,10 @@ void function StatUnlock_Unlocked( entity player, string itemRef, string parentR if ( IsItemNew( player, itemRef, parentRef ) ) return + // early out if the player has progression disabled + if ( !ProgressionEnabledForPlayer( player ) ) + return + int refGuid = file.itemRefToGuid[itemRef] int parentRefGuid = parentRef == "" ? 0 : file.itemRefToGuid[parentRef] -- cgit v1.2.3 From dfeaba7208deff89de67f32271c0d5c5a44746f1 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 3 Nov 2023 13:15:42 -0300 Subject: Fix wrong Item Type for Titan Camos (#728) Small fix which the wrong item type was being addressed to check for Titan Camos, allowing players to use any camo without fallback to default if they didn't own that item previously when enabling progression. --- Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index ceb5e837..496e8b42 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -268,7 +268,7 @@ void function ValidateEquippedItems( entity player ) // camoIndex if ( loadout.skinIndex == TITAN_SKIN_INDEX_CAMO ) { - array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_TITAN ) if ( loadout.camoIndex >= camoSkins.len() || loadout.camoIndex < 0 ) { printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) @@ -363,7 +363,7 @@ void function ValidateEquippedItems( entity player ) // primeCamoIndex if ( loadout.primeSkinIndex == TITAN_SKIN_INDEX_CAMO ) { - array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN ) + array camoSkins = GetAllItemsOfType( eItemTypes.CAMO_SKIN_TITAN ) if ( loadout.primeCamoIndex >= camoSkins.len() || loadout.primeCamoIndex < 0 ) { printt( " - INVALID TITAN CAMO/SKIN, RESETTING" ) -- cgit v1.2.3 From 54fae18d727aa84fb6eb45de4f9479aba3361158 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 3 Nov 2023 13:17:34 -0300 Subject: Fix wrong attacker receiving progression stat updates (#755) Fixes wrong attacker receiving stat updates --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 63841f7a..bd64e4ca 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -587,7 +587,7 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo ) string source = DamageSourceIDToString( attackerInfo.damageSourceId ) if ( IsValidStatItemString( source ) ) - Stats_IncrementStat( attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 ) + Stats_IncrementStat( attackerInfo.attacker, "weapon_kill_stats", "assistsTotal", source, 1.0 ) } } -- cgit v1.2.3 From 5076bea54cfb2f88d5420ede0c207fb77dc5be05 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 5 Nov 2023 12:26:59 +0000 Subject: Remove "Launch Multiplayer" button (#719) As currently Northstar does not support launching into vanilla. --- Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut index c97c8cdc..2f1bcf02 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/panel_mainmenu.nut @@ -81,8 +81,9 @@ void function InitMainMenuPanel() headerIndex++ buttonIndex = 0 var multiplayerHeader = AddComboButtonHeader( comboStruct, headerIndex, "#MULTIPLAYER_ALLCAPS" ) - file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" ) - Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate ) + // "Launch Multiplayer" button removed because we don't support vanilla yet :clueless: + //file.mpButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MULTIPLAYER_LAUNCH" ) + //Hud_AddEventHandler( file.mpButton, UIE_CLICK, OnPlayMPButton_Activate ) file.fdButton = AddComboButton( comboStruct, headerIndex, buttonIndex++, "#MENU_LAUNCH_NORTHSTAR" ) Hud_AddEventHandler( file.fdButton, UIE_CLICK, OnPlayFDButton_Activate ) Hud_SetLocked( file.fdButton, true ) @@ -169,7 +170,8 @@ void function OnShowMainMenuPanel() #endif // PS4_PROG UpdateSPButtons() - thread UpdatePlayButton( file.mpButton ) + // dont try and update the launch multiplayer button, because it doesn't exist + //thread UpdatePlayButton( file.mpButton ) thread UpdatePlayButton( file.fdButton ) thread MonitorTrialVersionChange() @@ -459,7 +461,8 @@ void function UpdatePlayButton( var button ) message = "" } - ComboButton_SetText( file.mpButton, buttonText ) + // dont try and update the launch multiplayer button, because it doesn't exist + //ComboButton_SetText( file.mpButton, buttonText ) ComboButton_SetText( file.fdButton, "#MENU_LAUNCH_NORTHSTAR" ) //Hud_SetEnabled( file.fdButton, false ) -- cgit v1.2.3 From 318561f5a6a1f965bca5caaef962ea1deb6f6b31 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 5 Nov 2023 12:31:30 +0000 Subject: Re-implement projectile kill replays (#723) Adds a new callback: `SetCallback_TryUseProjectileReplay` so that servers can write logic to enable/disable this behaviour on a case by case basis --- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 10 +++++-- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 34 ++++++++++++++++++++-- 2 files changed, 38 insertions(+), 6 deletions(-) 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 c11ca36f..9288f75e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -295,6 +295,10 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga }) entity attacker = DamageInfo_GetAttacker( damageInfo ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + int eHandle = attacker.GetEncodedEHandle() + if ( inflictor && ShouldTryUseProjectileReplay( player, attacker, damageInfo, false ) ) + eHandle = inflictor.GetEncodedEHandle() int methodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) table alreadyAssisted @@ -374,7 +378,7 @@ void function PostDeathThread_MP( entity player, var damageInfo ) // based on ga if ( "respawnTime" in attacker.s ) respawnTime = Time() - expect float ( attacker.s.respawnTime ) - thread PlayerWatchesKillReplayWrapper( player, attacker, respawnTime, timeOfDeath, beforeTime, replayTracker ) + thread PlayerWatchesKillReplayWrapper( player, attacker, eHandle, respawnTime, timeOfDeath, beforeTime, replayTracker ) } player.SetPlayerSettings( "spectator" ) // prevent a crash with going from titan => pilot on respawn @@ -432,7 +436,7 @@ void function ForceRespawnMeSignalAfterDelay( entity player, int delay = 5 ) player.Signal( "RespawnMe" ) } -void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) +void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, int eHandle, float timeSinceAttackerSpawned, float timeOfDeath, float beforeTime, table replayTracker ) { player.EndSignal( "RespawnMe" ) player.EndSignal( "OnRespawned" ) @@ -455,7 +459,7 @@ void function PlayerWatchesKillReplayWrapper( entity player, entity attacker, fl }) player.SetPredictionEnabled( false ) - PlayerWatchesKillReplay( player, attacker.GetEncodedEHandle(), attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker ) + PlayerWatchesKillReplay( player, eHandle, attacker.GetIndexForEntity(), timeSinceAttackerSpawned, timeOfDeath, beforeTime, replayTracker ) } void function DecideRespawnPlayer( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 3426cec5..4c52a9bf 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -13,6 +13,8 @@ global function SetTimerBased global function SetShouldUseRoundWinningKillReplay global function SetRoundWinningKillReplayKillClasses global function SetRoundWinningKillReplayAttacker +global function SetCallback_TryUseProjectileReplay +global function ShouldTryUseProjectileReplay global function SetWinner global function SetTimeoutWinnerDecisionFunc global function AddTeamScore @@ -48,13 +50,28 @@ struct { float roundWinningKillReplayTime entity roundWinningKillReplayVictim entity roundWinningKillReplayAttacker + int roundWinningKillReplayInflictorEHandle // this is either the inflictor or the attacker int roundWinningKillReplayMethodOfDeath float roundWinningKillReplayTimeOfDeath float roundWinningKillReplayHealthFrac array roundEndCleanupCallbacks + bool functionref( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) shouldTryUseProjectileReplayCallback } file +void function SetCallback_TryUseProjectileReplay( bool functionref( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) callback ) +{ + file.shouldTryUseProjectileReplayCallback = callback +} + +bool function ShouldTryUseProjectileReplay( entity victim, entity attacker, var damageInfo, bool isRoundEnd ) +{ + if ( file.shouldTryUseProjectileReplayCallback != null ) + return file.shouldTryUseProjectileReplayCallback( victim, attacker, damageInfo, isRoundEnd ) + // default to true (vanilla behaviour) + return true +} + void function PIN_GameStart() { // todo: using the pin telemetry function here, weird and was done veeery early on before i knew how this all worked, should use a different one @@ -319,6 +336,7 @@ void function GameStateEnter_WinnerDetermined_Threaded() WaitFrame() // prevent a race condition with PlayerWatchesRoundWinningKillReplay file.roundWinningKillReplayAttacker = null // clear this + file.roundWinningKillReplayInflictorEHandle = -1 if ( killcamsWereEnabled ) SetKillcamsEnabled( true ) @@ -394,7 +412,7 @@ void function PlayerWatchesRoundWinningKillReplay( entity player, float replayLe if ( IsValid( attacker ) ) { player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) - player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() ) + player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle ) player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) player.SetViewIndex( attacker.GetIndexForEntity() ) player.SetIsReplayRoundWinning( true ) @@ -460,6 +478,7 @@ void function GameStateEnter_SwitchingSides_Threaded() svGlobal.levelEnt.Signal( "RoundEnd" ) // might be good to get a new signal for this? not 100% necessary tho i think SetServerVar( "switchedSides", 1 ) file.roundWinningKillReplayAttacker = null // reset this after replay + file.roundWinningKillReplayInflictorEHandle = -1 if ( file.usePickLoadoutScreen ) SetGameState( eGameState.PickLoadout ) @@ -483,7 +502,7 @@ void function PlayerWatchesSwitchingSidesKillReplay( entity player, bool doRepla entity attacker = file.roundWinningKillReplayAttacker player.SetKillReplayDelay( Time() - replayLength, THIRD_PERSON_KILL_REPLAY_ALWAYS ) - player.SetKillReplayInflictorEHandle( attacker.GetEncodedEHandle() ) + player.SetKillReplayInflictorEHandle( file.roundWinningKillReplayInflictorEHandle ) player.SetKillReplayVictim( file.roundWinningKillReplayVictim ) player.SetViewIndex( attacker.GetIndexForEntity() ) player.SetIsReplayRoundWinning( true ) @@ -578,6 +597,9 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) return } + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, attacker, damageInfo, true ) + // set round winning killreplay info here if we're tracking pilot kills // todo: make this not count environmental deaths like falls, unsure how to prevent this if ( file.roundWinningKillReplayTrackPilotKills && victim != attacker && attacker != svGlobal.worldspawn && IsValid( attacker ) ) @@ -587,6 +609,7 @@ void function OnPlayerKilled( entity victim, entity attacker, var damageInfo ) file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim file.roundWinningKillReplayAttacker = attacker + file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle() file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) file.roundWinningKillReplayTimeOfDeath = Time() file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) @@ -637,6 +660,9 @@ void function OnTitanKilled( entity victim, var damageInfo ) return } + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + bool shouldUseInflictor = IsValid( inflictor ) && ShouldTryUseProjectileReplay( victim, DamageInfo_GetAttacker( damageInfo ), damageInfo, true ) + // set round winning killreplay info here if we're tracking titan kills // todo: make this not count environmental deaths like falls, unsure how to prevent this entity attacker = DamageInfo_GetAttacker( damageInfo ) @@ -647,6 +673,7 @@ void function OnTitanKilled( entity victim, var damageInfo ) file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayVictim = victim file.roundWinningKillReplayAttacker = attacker + file.roundWinningKillReplayInflictorEHandle = ( shouldUseInflictor ? inflictor : attacker ).GetEncodedEHandle() file.roundWinningKillReplayMethodOfDeath = DamageInfo_GetDamageSourceIdentifier( damageInfo ) file.roundWinningKillReplayTimeOfDeath = Time() file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) @@ -761,11 +788,12 @@ void function SetRoundWinningKillReplayKillClasses( bool pilot, bool titan ) file.roundWinningKillReplayTrackTitanKills = titan // player kills in titans should get tracked anyway, might be worth renaming this } -void function SetRoundWinningKillReplayAttacker( entity attacker ) +void function SetRoundWinningKillReplayAttacker( entity attacker, int inflictorEHandle = -1 ) { file.roundWinningKillReplayTime = Time() file.roundWinningKillReplayHealthFrac = GetHealthFrac( attacker ) file.roundWinningKillReplayAttacker = attacker + file.roundWinningKillReplayInflictorEHandle = inflictorEHandle == -1 ? attacker.GetEncodedEHandle() : inflictorEHandle file.roundWinningKillReplayTimeOfDeath = Time() } -- cgit v1.2.3 From c0e8a9084846a12e549851aa9b734c5b1c8498b8 Mon Sep 17 00:00:00 2001 From: cat_or_not <41955154+catornot@users.noreply.github.com> Date: Sun, 5 Nov 2023 20:23:45 -0500 Subject: Plugins v3 (#652) Script component of plugins v3. See launcher PR for more info. https://github.com/R2Northstar/NorthstarLauncher/pull/472 --- .github/nativefuncs.json | 14 +------------- .../scripts/vscripts/cl_northstar_client_init.nut | 13 +++++++++---- .../mod/scripts/vscripts/presence/cl_presence.nut | 11 ++++------- .../mod/scripts/vscripts/presence/ui_presence.nut | 20 ++++++++++++-------- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 13a7edd3..8397232d 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -421,13 +421,7 @@ "helpText":"Returns whether or not a given path leads to a folder.", "returnTypeString":"bool", "argTypes":"string path" - }, - { - "name":"NSPushGameStateData", - "helpText":"", - "returnTypeString":"void", - "argTypes":"struct gamestate" - } + } ], "UI":[ { @@ -724,12 +718,6 @@ "returnTypeString":"bool", "argTypes":"string path" }, - { - "name":"NSPushUIPresence", - "helpText":"", - "returnTypeString":"void", - "argTypes":"struct presence" - }, { "name":"NSGetMasterServerAuthResult", "helpText":"", diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index a844478a..765d29c3 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -1,3 +1,11 @@ +global enum eDiscordGameState +{ + LOADING = 0 + MAINMENU + LOBBY + INGAME +} + global struct GameStateStruct { string map @@ -15,10 +23,7 @@ global struct GameStateStruct { } global struct UIPresenceStruct { - bool isLoading - bool isLobby - string loadingLevel - string loadedLevel + int gameState } global struct RequiredModInfo diff --git a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut index c8a8274a..f17216fb 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/cl_presence.nut @@ -1,10 +1,8 @@ untyped globalize_all_functions -void function NorthstarCodeCallback_GenerateGameState() { - - GameStateStruct gs - +GameStateStruct function DiscordRPC_GenerateGameState( GameStateStruct gs ) +{ int highestScore = 0 int secondHighest = 0 @@ -40,6 +38,5 @@ void function NorthstarCodeCallback_GenerateGameState() { gs.timeEnd = expect float(level.nv.roundEndTime - Time()) else gs.timeEnd = expect float(level.nv.gameEndTime - Time()) - - NSPushGameStateData(gs) -} \ No newline at end of file + return gs +} diff --git a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut index cdf1c981..ce5abe86 100644 --- a/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut +++ b/Northstar.Client/mod/scripts/vscripts/presence/ui_presence.nut @@ -1,12 +1,16 @@ untyped globalize_all_functions -void function NorthstarCodeCallback_GenerateUIPresence() { - UIPresenceStruct uis +UIPresenceStruct function DiscordRPC_GenerateUIPresence( UIPresenceStruct uis ) +{ + if ( uiGlobal.isLoading ) + uis.gameState = eDiscordGameState.LOADING; + else if ( uiGlobal.loadedLevel == "" ) + uis.gameState = eDiscordGameState.MAINMENU; + else if ( IsLobby() || uiGlobal.loadedLevel == "mp_lobby" ) + uis.gameState = eDiscordGameState.LOBBY; + else + uis.gameState = eDiscordGameState.INGAME; - uis.isLoading = uiGlobal.isLoading - uis.isLobby = IsLobby() - uis.loadingLevel = uiGlobal.loadingLevel - uis.loadedLevel = uiGlobal.loadedLevel - NSPushUIPresence(uis) -} \ No newline at end of file + return uis +} -- cgit v1.2.3 From a93756633184bba4c4741198e0e452e71a2e108d Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 7 Nov 2023 22:22:48 +0100 Subject: Translations update from Weblate (#760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (291 of 291 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../mod/resource/northstar_client_localisation_french.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 377f6917..b0e579cf 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -353,5 +353,9 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "TOGGLE_PROGRESSION" "Activer la progression" "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Le système de progression peut être activé !^\n\nNorthstar supporte désormais le système de progression du jeu original, vous permettant de choisir si vous souhaitez débloquer les armes, skins, titans etc. en gagnant des niveaux et en complétant des défis.\n\nVous pouvez activer la progression en utilisant le bouton en bas de l'écran d'accueil.\n\nCeci peut être changé à tout moment." + "AUTHENTICATION_FAILED_HEADER" "Échec de l'authentification" + "AUTHENTICATION_FAILED_HELP" "Aide" + "AUTHENTICATION_FAILED_ERROR_CODE" "Code d'erreur : ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." } } -- cgit v1.2.3 From 1486b861c467cc95335d53ffd2532493ec3c9def Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sat, 18 Nov 2023 21:25:15 +0100 Subject: Add translation status indicator badge to README (#758) Add translation status indicator badge to README Add section showing all languages --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 5a180df9..7b6dfaf0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # NorthstarMods + +Translation status + [Squirrel](http://www.squirrel-lang.org/squirreldoc/reference/index.html) scripts used to recreate server-side gamelogic and add [custom content](https://r2northstar.gitbook.io/r2northstar-wiki/using-northstar/gamemodes) to the game. @@ -9,3 +12,11 @@ Issues in this repository should be created if they are related to these domains - `Northstar.Coop` - Soon™. - `Northstar.Custom` - Northstar custom content. - `Northstar.CustomServer` - Server config files and scripts necessary for multiplayer. + +### Translating + +Translations can be submitted via [weblate](https://translate.harmony.tf/projects/northstar/client/). + + +Translation status + -- cgit v1.2.3 From 4e394ce4f7cdf18a4acea8db6ff85fc6f858d45e Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 21 Nov 2023 01:22:45 +0000 Subject: Implement missing Score Events (#700) * use consts for killingspree and rampage score events * add Revenge and Quick Revenge score events * ensure no revenge/quick revenge against non-players * this is OnPlayerKilled i dont need this check * implement mayhem and onslaught --- .../mod/scripts/vscripts/mp/_score.nut | 50 +++++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index df7577aa..be20982d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -28,6 +28,10 @@ void function InitPlayerForScoreEvents( entity player ) player.s.currentKillstreak <- 0 player.s.lastKillTime <- 0.0 player.s.currentTimedKillstreak <- 0 + player.s.lastKillTime_Mayhem <- 0.0 + player.s.currentTimedKillstreak_Mayhem <- 0 + player.s.lastKillTime_Onslaught <- 0.0 + player.s.currentTimedKillstreak_Onslaught <- 0 } void function AddPlayerScore( entity targetPlayer, string scoreEventName, entity associatedEnt = null, string noideawhatthisis = "", int pointValueOverride = -1 ) @@ -93,6 +97,7 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag victim.s.currentTimedKillstreak = 0 victim.p.numberOfDeathsSinceLastKill++ // this is reset on kill + victim.p.lastKiller = attacker // have to do this early before we reset victim's player killstreaks // nemesis when you kill a player that is dominating you @@ -131,12 +136,20 @@ void function ScoreEvent_PlayerKilled( entity victim, entity attacker, var damag attacker.p.numberOfDeathsSinceLastKill = 0 } + // revenge + quick revenge + if ( attacker.p.lastKiller == victim ) + { + if ( Time() - GetPlayerLastRespawnTime( attacker ) < QUICK_REVENGE_TIME_LIMIT ) + AddPlayerScore( attacker, "QuickRevenge" ) + else + AddPlayerScore( attacker, "Revenge" ) + } // untimed killstreaks attacker.s.currentKillstreak++ - if ( attacker.s.currentKillstreak == 3 ) + if ( attacker.s.currentKillstreak == KILLINGSPREE_KILL_REQUIREMENT ) AddPlayerScore( attacker, "KillingSpree" ) - else if ( attacker.s.currentKillstreak == 5 ) + else if ( attacker.s.currentKillstreak == RAMPAGE_KILL_REQUIREMENT ) AddPlayerScore( attacker, "Rampage" ) // increment untimed killstreaks against specific players @@ -234,6 +247,39 @@ void function ScoreEvent_NPCKilled( entity victim, entity attacker, var damageIn AddPlayerScore( attacker, ScoreEventForNPCKilled( victim, damageInfo ), victim ) } catch ( ex ) {} + + if ( !attacker.IsPlayer() ) + return + + // mayhem/onslaught (timed killstreaks vs AI) + + // reset before checking + if ( Time() - attacker.s.lastKillTime_Mayhem > MAYHEM_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Mayhem = 0 + attacker.s.lastKillTime_Mayhem = Time() + } + if ( Time() - attacker.s.lastKillTime_Mayhem <= MAYHEM_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Mayhem++ + + if ( attacker.s.currentTimedKillstreak_Mayhem == MAYHEM_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "Mayhem" ) + } + + // reset before checking + if ( Time() - attacker.s.lastKillTime_Onslaught > ONSLAUGHT_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Onslaught = 0 + attacker.s.lastKillTime_Onslaught = Time() + } + if ( Time() - attacker.s.lastKillTime_Onslaught <= ONSLAUGHT_REQUIREMENT_TIME ) + { + attacker.s.currentTimedKillstreak_Onslaught++ + + if ( attacker.s.currentTimedKillstreak_Onslaught == ONSLAUGHT_REQUIREMENT_KILLS ) + AddPlayerScore( attacker, "Onslaught" ) + } } void function ScoreEvent_MatchComplete( int winningTeam ) -- cgit v1.2.3 From bdb73b1fd5ddd1899adae528ec64b3077b918a61 Mon Sep 17 00:00:00 2001 From: x3Karma Date: Fri, 1 Dec 2023 08:14:41 +0800 Subject: Fix crash when calling for invalid loadout index (#764) Requesting for invalid loadout index using SwapSecondaryAndWeapon3PersistentLoadoutData will cause a crash. This change just adds a check to reset the loadout index. --- Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 76cb4ac4..63756fdc 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -193,6 +193,10 @@ bool function ClientCommandCallback_SwapSecondaryAndWeapon3PersistentLoadoutData // get loadout int index = args[0].tointeger() + + if ( !IsValidPilotLoadoutIndex(index) ) + return false + PilotLoadoutDef loadout = GetPilotLoadoutFromPersistentData( player, index ) // swap loadouts -- cgit v1.2.3 From 0c5c9b1a46dc0078057e40f2e022bcb75b6fe842 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Mon, 4 Dec 2023 14:25:19 +0100 Subject: Add a doc comment to `StringReplace` (#748) This is an initial test to get formatting etc agreed upon to then build on this further --- Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index 9e762985..a97185b5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -348,6 +348,14 @@ string function GetMapDisplayDesc( string mapname ) return "#" + mapname + "_CLASSIC_DESC" } +/// Sends a string message to player +/// * `baseString` - The input string to search through +/// * `searchString` - Find this substring... +/// * `replaceString` - ...and replace with this substring +/// * `replaceAll` - Whether to replace all occurences or just the first +/// * `caseInsensitive` - Whether to consider casing (upper/lower) +/// +/// Returns the updated string string function StringReplace( string baseString, string searchString, string replaceString, bool replaceAll = false, bool caseInsensitive = false ) { bool loopedOnce = false -- cgit v1.2.3 From 7140cce045a94b4d8e02b347bb2e8b6bfc9c7c89 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 13 Dec 2023 01:24:34 +0100 Subject: Treat `.gnut` files as `.nut` for syntax highlighting (#770) Treat `.gnut` files as `.nut` for syntax highlighting on GitHub Their syntax is functionally the same anyway. --- .gitattributes | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index c6a941df..1bb89156 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,4 @@ -/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM \ No newline at end of file +/Northstar.Client/mod/resource/northstar_client_localisation_*.txt text diff working-tree-encoding=UTF-16LE-BOM + +# Highlight `.gnut` like `.nut` files +*.gnut linguist-language=Squirrel -- cgit v1.2.3 From f4df3144adbd45d48d812d102cfaf7cef474824e Mon Sep 17 00:00:00 2001 From: Maya <11448698+RoyalBlue1@users.noreply.github.com> Date: Thu, 14 Dec 2023 01:31:37 +0100 Subject: Add Winter holiday event models to the lobby (#768) Adds decorative models to the lobby map that will only display during winter holiday season. --- Northstar.Custom/mod.json | 19 +++++++++++++++++++ .../models/northstartree/lightsflicker.vmt | 18 ++++++++++++++++++ .../models/northstartree/lightsflicker.vtf | Bin 0 -> 524512 bytes .../models/northstartree/winter_holiday_floor.mdl | Bin 0 -> 311481 bytes .../models/northstartree/winter_holiday_tree.mdl | Bin 0 -> 3029949 bytes .../mod/scripts/vscripts/_event_models.gnut | 21 +++++++++++++++++++++ .../vscripts/ui/ns_custom_mod_settings.gnut | 8 ++++++++ Northstar.Custom/paks/bt.rpak | Bin 0 -> 308606 bytes Northstar.Custom/paks/bt.starpak | Bin 0 -> 19296360 bytes Northstar.Custom/paks/giftwrap.rpak | Bin 0 -> 264704 bytes Northstar.Custom/paks/giftwrap.starpak | Bin 0 -> 1335384 bytes Northstar.Custom/paks/leaves.rpak | Bin 0 -> 265631 bytes Northstar.Custom/paks/leaves.starpak | Bin 0 -> 3956824 bytes Northstar.Custom/paks/rpak.json | 9 +++++++-- Northstar.Custom/paks/snow.rpak | Bin 0 -> 308548 bytes Northstar.Custom/paks/snow.starpak | Bin 0 -> 4616296 bytes Northstar.Custom/paks/tree_stump.rpak | Bin 0 -> 308670 bytes Northstar.Custom/paks/tree_stump.starpak | Bin 0 -> 4616296 bytes 18 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt create mode 100644 Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf create mode 100644 Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl create mode 100644 Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl create mode 100644 Northstar.Custom/mod/scripts/vscripts/_event_models.gnut create mode 100644 Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut create mode 100644 Northstar.Custom/paks/bt.rpak create mode 100644 Northstar.Custom/paks/bt.starpak create mode 100644 Northstar.Custom/paks/giftwrap.rpak create mode 100644 Northstar.Custom/paks/giftwrap.starpak create mode 100644 Northstar.Custom/paks/leaves.rpak create mode 100644 Northstar.Custom/paks/leaves.starpak create mode 100644 Northstar.Custom/paks/snow.rpak create mode 100644 Northstar.Custom/paks/snow.starpak create mode 100644 Northstar.Custom/paks/tree_stump.rpak create mode 100644 Northstar.Custom/paks/tree_stump.starpak diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 93f371bd..399311e4 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -24,6 +24,11 @@ { "Name": "ns_force_melee", "DefaultValue": "" + }, + { + "Name": "ns_show_event_models", + "DefaultValue": "1", + "Flags": "ARCHIVE_PLAYERPROFILE" } ], "Scripts": [ @@ -434,6 +439,20 @@ { "Path": "sh_northstar_safe_io.gnut", "RunOn": "CLIENT || SERVER || UI" + }, + { + "Path": "_event_models.gnut", + "RunOn": "SERVER && LOBBY", + "ServerCallback": { + "Before": "EventModelsInit" + } + }, + { + "Path": "ui/ns_custom_mod_settings.gnut", + "RunOn": "UI", + "UICallback":{ + "Before": "NSCustomModSettings" + } } ], diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt new file mode 100644 index 00000000..22b81e9a --- /dev/null +++ b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vmt @@ -0,0 +1,18 @@ +"UnlitTexture" +{ + $basetexture "models/northstartree/lightsflicker" + $color "[1.5 1.5 1.5]" + + Proxies + { + + TextureScroll + { + texturescrollvar $basetexturetransform + texturescrollrate 0.33 + texturescrollangle 45 + } + + } + +} diff --git a/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf new file mode 100644 index 00000000..227756be Binary files /dev/null and b/Northstar.Custom/mod/materials/models/northstartree/lightsflicker.vtf differ diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl new file mode 100644 index 00000000..aaf70363 Binary files /dev/null and b/Northstar.Custom/mod/models/northstartree/winter_holiday_floor.mdl differ diff --git a/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl new file mode 100644 index 00000000..4690475f Binary files /dev/null and b/Northstar.Custom/mod/models/northstartree/winter_holiday_tree.mdl differ diff --git a/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut new file mode 100644 index 00000000..0802d769 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/_event_models.gnut @@ -0,0 +1,21 @@ +global function EventModelsInit + +void function EventModelsInit() +{ + if( !GetConVarBool( "ns_show_event_models" ) ) + return + + table timeParts = GetUnixTimeParts() + int month = expect int( timeParts[ "month" ] ) + int day = expect int( timeParts[ "day" ] ) + + // 18th December to 6th January + if( ( ( month == 12 ) && ( day >= 18 ) ) || ( ( month == 1 ) && ( day <= 6 ) ) ) + { + PrecacheModel( $"models/northstartee/winter_holiday_tree.mdl" ) + PrecacheModel( $"models/northstartree/winter_holiday_floor.mdl" ) + + CreatePropDynamic( $"models/northstartree/winter_holiday_tree.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 ) + CreatePropDynamic( $"models/northstartree/winter_holiday_floor.mdl", < -60, 740, 30 >, < 0, 0, 0 >, SOLID_VPHYSICS, 1000 ) + } +} diff --git a/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut new file mode 100644 index 00000000..5a7d80b7 --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/ui/ns_custom_mod_settings.gnut @@ -0,0 +1,8 @@ +global function NSCustomModSettings + +void function NSCustomModSettings() +{ + ModSettings_AddModTitle( "Northstar Custom" , 2 ) + ModSettings_AddModCategory( "Event Models" ) + ModSettings_AddEnumSetting( "ns_show_event_models", "Show Event Models", [ "#SETTING_OFF", "#SETTING_ON" ], 2 ) +} diff --git a/Northstar.Custom/paks/bt.rpak b/Northstar.Custom/paks/bt.rpak new file mode 100644 index 00000000..7a4b9e31 Binary files /dev/null and b/Northstar.Custom/paks/bt.rpak differ diff --git a/Northstar.Custom/paks/bt.starpak b/Northstar.Custom/paks/bt.starpak new file mode 100644 index 00000000..70549d51 Binary files /dev/null and b/Northstar.Custom/paks/bt.starpak differ diff --git a/Northstar.Custom/paks/giftwrap.rpak b/Northstar.Custom/paks/giftwrap.rpak new file mode 100644 index 00000000..7b9200b3 Binary files /dev/null and b/Northstar.Custom/paks/giftwrap.rpak differ diff --git a/Northstar.Custom/paks/giftwrap.starpak b/Northstar.Custom/paks/giftwrap.starpak new file mode 100644 index 00000000..46ea6d8d Binary files /dev/null and b/Northstar.Custom/paks/giftwrap.starpak differ diff --git a/Northstar.Custom/paks/leaves.rpak b/Northstar.Custom/paks/leaves.rpak new file mode 100644 index 00000000..b17346dd Binary files /dev/null and b/Northstar.Custom/paks/leaves.rpak differ diff --git a/Northstar.Custom/paks/leaves.starpak b/Northstar.Custom/paks/leaves.starpak new file mode 100644 index 00000000..b37aa523 Binary files /dev/null and b/Northstar.Custom/paks/leaves.starpak differ diff --git a/Northstar.Custom/paks/rpak.json b/Northstar.Custom/paks/rpak.json index 743468b4..522c558b 100644 --- a/Northstar.Custom/paks/rpak.json +++ b/Northstar.Custom/paks/rpak.json @@ -1,5 +1,10 @@ { "Postload": { - "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak" + "mp_weapon_shotgun_doublebarrel.rpak": "common.rpak", + "leaves.rpak": "common.rpak", + "tree_stump.rpak": "common.rpak", + "bt.rpak": "common.rpak", + "giftwrap.rpak": "common.rpak", + "snow.rpak": "common.rpak" } -} \ No newline at end of file +} diff --git a/Northstar.Custom/paks/snow.rpak b/Northstar.Custom/paks/snow.rpak new file mode 100644 index 00000000..4756b6c7 Binary files /dev/null and b/Northstar.Custom/paks/snow.rpak differ diff --git a/Northstar.Custom/paks/snow.starpak b/Northstar.Custom/paks/snow.starpak new file mode 100644 index 00000000..7f3dbf19 Binary files /dev/null and b/Northstar.Custom/paks/snow.starpak differ diff --git a/Northstar.Custom/paks/tree_stump.rpak b/Northstar.Custom/paks/tree_stump.rpak new file mode 100644 index 00000000..3cdf1866 Binary files /dev/null and b/Northstar.Custom/paks/tree_stump.rpak differ diff --git a/Northstar.Custom/paks/tree_stump.starpak b/Northstar.Custom/paks/tree_stump.starpak new file mode 100644 index 00000000..b233176e Binary files /dev/null and b/Northstar.Custom/paks/tree_stump.starpak differ -- cgit v1.2.3 From 6d678ac56b104a5c4aa2a2d9da05b163f2e1d6cd Mon Sep 17 00:00:00 2001 From: William Miller Date: Thu, 14 Dec 2023 10:39:26 -0300 Subject: Add Aegis Rank reset functionality command for Progression (#727) Adds a console command to allow players to reset the Aegis Ranks of their Titans --- .../mod/scripts/vscripts/sh_progression.nut | 23 ++++++++++++++++++++++ .../mod/scripts/vscripts/sh_utility_all.gnut | 16 +++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 496e8b42..2dc88d0d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -38,6 +38,7 @@ void function Progression_Init() #if SERVER AddCallback_OnClientDisconnected( OnClientDisconnected ) AddClientCommandCallback( "ns_progression", ClientCommand_SetProgression ) + AddClientCommandCallback( "ns_resettitanaegis", ClientCommand_ResetTitanAegis ) AddCallback_GameStateEnter( eGameState.Playing, OnPlaying ) #elseif CLIENT AddCallback_OnClientScriptInit( OnClientScriptInit ) @@ -84,6 +85,28 @@ bool function ClientCommand_SetProgression( entity player, array args ) return true } + +/// Resets a specific Titan's Aegis rank back to `0` +/// * `player` - The player entity to perform the action on +/// * `args` - The arguments passed from the client command. `args[0]` should be an integer corresponding to the index of the Titan to reset. +/// +/// Returns `true` on success and `false` on missing args. +bool function ClientCommand_ResetTitanAegis( entity player, array args ) +{ + if ( !args.len() ) + return false + + int suitIndex = args[0].tointeger() + player.SetPersistentVar( "titanFDUnlockPoints[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "previousFDUnlockPoints[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "fdTitanXP[" + suitIndex + "]", 0 ) + player.SetPersistentVar( "fdPreviousTitanXP[" + suitIndex + "]", 0 ) + + // Refresh Highest Aegis Titan since we might get all of them back to 1 if players wants + RecalculateHighestTitanFDLevel( player ) + + return true +} #endif #if CLIENT diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index a97185b5..8751a250 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -1540,6 +1540,22 @@ array function GetAvailableTitanRefs( entity player ) return availableTitanRefs } +/// Gets the highest Titan FD level and stores it in the corresponding persistent var. +/// * `player` - The player entity to perform the action on +void function RecalculateHighestTitanFDLevel( entity player ) +{ + int enumCount = PersistenceGetEnumCount( "titanClasses" ) + int highestAegis = 0 + for ( int i = 0; i < enumCount; i++ ) + { + string enumName = PersistenceGetEnumItemNameForIndex( "titanClasses", i ) + int aegisLevel = FD_TitanGetLevelForXP( enumName, FD_TitanGetXP( player, enumName ) ) + if ( highestAegis < aegisLevel ) + highestAegis = aegisLevel + } + player.SetPersistentVar( "fdStats.highestTitanFDLevel", highestAegis ) +} + #if MP string function GetTitanRefForLoadoutIndex( entity player, int loadoutIndex ) { -- cgit v1.2.3 From e49e7e8321269a3de19f07981c8974e87e9fd938 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Thu, 14 Dec 2023 22:19:08 +0100 Subject: Mod download UI integration (#761) UI integration for the mod downloading feature. Feature activation locked behind a convar. --- .github/nativefuncs.json | 19 ++++ Northstar.Client/mod.json | 8 ++ .../northstar_client_localisation_english.txt | 20 ++++ .../scripts/vscripts/cl_northstar_client_init.nut | 8 ++ .../scripts/vscripts/ui/menu_ns_moddownload.nut | 117 +++++++++++++++++++++ .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 59 +++++++++-- 6 files changed, 221 insertions(+), 10 deletions(-) create mode 100644 Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 8397232d..1148d3e5 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -502,6 +502,25 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSIsModDownloadable", + "helpText": "checks whether a mod is verified and can be auto-downloaded", + "returnTypeString": "bool", + "argTypes": "string name, string version" + + }, + { + "name": "NSDownloadMod", + "helpText": "downloads a given mod from distant API to local game profile", + "returnTypeString": "void", + "argTypes": "string name, string version" + }, + { + "name": "NSGetModInstallState", + "helpText": "get status of the mod currently being installed", + "returnTypeString": "ModInstallState", + "argTypes": "" + }, { "name":"NSReloadMods", "helpText":"", diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index a22f49fd..44937a2b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -5,6 +5,10 @@ "LoadPriority": 0, "InitScript": "cl_northstar_client_init.nut", "ConVars": [ + { + "Name": "allow_mod_auto_download", + "DefaultValue": "0" + }, { "Name": "filter_hide_empty", "DefaultValue": "0" @@ -82,6 +86,10 @@ "After": "NSUpdateGameStateClientStart" } }, + { + "Path": "ui/menu_ns_moddownload.nut", + "RunOn": "UI" + }, { "Path": "ui/menu_ns_serverbrowser.nut", "RunOn": "UI", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index c7b25a70..9bb36940 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -366,5 +366,25 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "PROGRESSION_DISABLED_BODY" "^CCCC0000Progression has been disabled.^\n\nTitans, Weapons, Factions, Skins, etc. will all be unlocked and usable at any time.\n\nThis can be changed at any time in the multiplayer lobby." "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progression can now be enabled!^\n\nNorthstar now supports vanilla progression, meaning you can choose to unlock Weapons, Skins, Titans, etc. through levelling up and completing challenges.\n\nYou can enable progression using the button at the bottom of the lobby screen.\n\nThis can be changed at any time." + + // Mod downloading + "MISSING_MOD" "Missing mod \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" + "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "DOWNLOADING_MOD_TITLE" "Downloading mod" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Downloading %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Checksuming mod" + "CHECKSUMING_TEXT" "Verifying contents of %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extracting mod (%s1%)" + "EXTRACTING_MOD_TEXT" "Extracting %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Failed downloading mod" + "FAILED_READING_ARCHIVE" "An error occurred while reading mod archive." + "FAILED_WRITING_TO_DISK" "An error occurred while extracting mod files to the filesystem." + "MOD_FETCHING_FAILED" "Mod archive could not be downloaded from Thunderstore." + "MOD_CORRUPTED" "Downloaded archive checksum does not match verified signature." + "NO_DISK_SPACE_AVAILABLE" "There is not enough space on your disk." + "MOD_FETCHING_FAILED_GENERAL" "Mod extraction failed. Check logs for more details." } } diff --git a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut index 765d29c3..3560fd56 100644 --- a/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut +++ b/Northstar.Client/mod/scripts/vscripts/cl_northstar_client_init.nut @@ -53,3 +53,11 @@ global struct MasterServerAuthResult string errorCode string errorMessage } + +global struct ModInstallState +{ + int status + int progress + int total + float ratio +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut new file mode 100644 index 00000000..4d299362 --- /dev/null +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -0,0 +1,117 @@ +global function DownloadMod +global function DisplayModDownloadErrorDialog + +global enum eModInstallStatus +{ + DOWNLOADING, + CHECKSUMING, + EXTRACTING, + DONE, + FAILED, + FAILED_READING_ARCHIVE, + FAILED_WRITING_TO_DISK, + MOD_FETCHING_FAILED, + MOD_CORRUPTED, + NO_DISK_SPACE_AVAILABLE, + NOT_FOUND +} + +const int MB = 1024*1000; + +bool function DownloadMod( RequiredModInfo mod ) +{ + // Downloading mod UI + DialogData dialogData + dialogData.header = Localize( "#DOWNLOADING_MOD_TITLE" ) + dialogData.message = Localize( "#DOWNLOADING_MOD_TEXT", mod.name, mod.version ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Save reference to UI elements, to update their content + var menu = GetMenu( "Dialog" ) + var header = Hud_GetChild( menu, "DialogHeader" ) + var body = GetSingleElementByClassname( menu, "DialogMessageClass" ) + + // Start actual mod downloading + NSDownloadMod( mod.name, mod.version ) + + ModInstallState state = NSGetModInstallState() + while ( state.status < eModInstallStatus.DONE ) + { + state = NSGetModInstallState() + UpdateModDownloadDialog( mod, state, menu, header, body ) + WaitFrame() + } + + printt( "Mod status:", state.status ) + + // Close loading dialog + CloseActiveMenu() + + return state.status == eModInstallStatus.DONE +} + +void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState state, var menu, var header, var body ) +{ + switch ( state.status ) + { + case eModInstallStatus.DOWNLOADING: + Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + case eModInstallStatus.CHECKSUMING: + Hud_SetText( header, Localize( "#CHECKSUMING_TITLE" ) ) + Hud_SetText( body, Localize( "#CHECKSUMING_TEXT", mod.name, mod.version ) ) + break + case eModInstallStatus.EXTRACTING: + Hud_SetText( header, Localize( "#EXTRACTING_MOD_TITLE", string( state.ratio ) ) ) + Hud_SetText( body, Localize( "#EXTRACTING_MOD_TEXT", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) + break + default: + break + } +} + +void function DisplayModDownloadErrorDialog( string modName ) +{ + ModInstallState state = NSGetModInstallState() + + DialogData dialogData + dialogData.header = Localize( "#FAILED_DOWNLOADING", modName ) + dialogData.image = $"ui/menu/common/dialog_error" + + switch ( state.status ) + { + case eModInstallStatus.FAILED_READING_ARCHIVE: + dialogData.message = Localize( "#FAILED_READING_ARCHIVE" ) + break + case eModInstallStatus.FAILED_WRITING_TO_DISK: + dialogData.message = Localize( "#FAILED_WRITING_TO_DISK" ) + break + case eModInstallStatus.MOD_FETCHING_FAILED: + dialogData.message = Localize( "#MOD_FETCHING_FAILED" ) + break + case eModInstallStatus.MOD_CORRUPTED: + dialogData.message = Localize( "#MOD_CORRUPTED" ) + break + case eModInstallStatus.NO_DISK_SPACE_AVAILABLE: + dialogData.message = Localize( "#NO_DISK_SPACE_AVAILABLE" ) + break + case eModInstallStatus.NOT_FOUND: + dialogData.message = Localize( "#NOT_FOUND" ) + break + case eModInstallStatus.FAILED: + default: + dialogData.message = Localize( "#MOD_FETCHING_FAILED_GENERAL" ) + break + } + + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) +} diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index efc8d66c..29c7621c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -951,33 +951,65 @@ string function FillInServerModsLabel( array mods ) void function OnServerSelected( var button ) +{ + thread OnServerSelected_Threaded( button ) +} + +void function OnServerSelected_Threaded( var button ) { if ( NSIsRequestingServerList() || NSGetServerCount() == 0 || file.serverListRequestFailed ) return ServerInfo server = file.focusedServer - file.lastSelectedServer = server + // Count mods that have been successfully downloaded + bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) + int downloadedMods = 0; + foreach ( RequiredModInfo mod in server.requiredMods ) { if ( !NSGetModNames().contains( mod.name ) ) { - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = format( "Missing mod \"%s\" v%s", mod.name, mod.version ) - dialogData.image = $"ui/menu/common/dialog_error" + // Check if mod can be auto-downloaded + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display an error message if not + if ( !modIsVerified || !autoDownloadAllowed ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.image = $"ui/menu/common/dialog_error" + + // Specify error (only if autoDownloadAllowed is set) + if ( autoDownloadAllowed ) + { + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + } - #if PC_PROG AddDialogButton( dialogData, "#DISMISS" ) AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - OpenDialog( dialogData ) + OpenDialog( dialogData ) + + return + } - return + else // Launch download + { + if ( DownloadMod( mod ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } } else { @@ -1018,6 +1050,13 @@ void function OnServerSelected( var button ) } } + // Make Northstar aware new mods have been added + if ( downloadedMods > 0 ) + { + print( "Some new mods have been downloaded or enabled, reloading mods." ) + NSReloadMods(); + } + if ( server.requiresPassword ) { OnCloseServerBrowserMenu() -- cgit v1.2.3 From 93b9c734d66af04d6e245216723c93ea49766c5b Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 17 Dec 2023 01:25:30 +0000 Subject: Fix `spec_mode` bind not working (#706) Fixes `spec_mode` bind not working by adding a small spectator replay delay Co-authored-by: DBmaoha <56738369+DBmaoha@users.noreply.github.com> --- .../mod/scripts/vscripts/mp/_spectator.gnut | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut index aa2fc108..510a9b7e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_spectator.gnut @@ -170,6 +170,9 @@ void function SpectatorFunc_Default( entity player ) { player.SetObserverTarget( target ) player.StartObserverMode( OBS_MODE_CHASE ) + // the delay of 0.1 seems to fix the spec_mode command not working + // when using the keybind + player.SetSpecReplayDelay( 0.1 ) } catch ( ex ) { } } @@ -215,9 +218,12 @@ bool function ClientCommandCallback_spec_mode( entity player, array args else if ( player.GetObserverMode() == OBS_MODE_IN_EYE ) { // set to third person spectate - player.SetSpecReplayDelay( 0.0 ) + + // the delay of 0.1 seems to fix the spec_mode command not working + // when using the keybind + player.SetSpecReplayDelay( 0.1 ) player.StartObserverMode( OBS_MODE_CHASE ) } return true -} \ No newline at end of file +} -- cgit v1.2.3 From a169e16508bed6b850450d17056433a234fa29f6 Mon Sep 17 00:00:00 2001 From: William Miller Date: Sun, 17 Dec 2023 22:38:29 -0300 Subject: Fix restricting Aegis Rank reset functionality to MP (#771) Move compiler flag so that `RecalculateHighestTitanFDLevel` is MP only. --- Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut index 8751a250..2ca051cf 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_utility_all.gnut @@ -1542,6 +1542,7 @@ array function GetAvailableTitanRefs( entity player ) /// Gets the highest Titan FD level and stores it in the corresponding persistent var. /// * `player` - The player entity to perform the action on +#if MP void function RecalculateHighestTitanFDLevel( entity player ) { int enumCount = PersistenceGetEnumCount( "titanClasses" ) @@ -1556,7 +1557,6 @@ void function RecalculateHighestTitanFDLevel( entity player ) player.SetPersistentVar( "fdStats.highestTitanFDLevel", highestAegis ) } -#if MP string function GetTitanRefForLoadoutIndex( entity player, int loadoutIndex ) { TitanLoadoutDef loadout = GetTitanLoadoutFromPersistentData( player, loadoutIndex ) -- cgit v1.2.3 From bbd4ced1eaffb7f7471ef9ea47724daa05811a93 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Tue, 19 Dec 2023 01:10:39 +0000 Subject: Make `RequiredOnClient` text clearer (#720) Also makes that text get localised as it was hardcoded before. --- .../mod/resource/northstar_client_localisation_english.txt | 1 + Northstar.Client/mod/resource/ui/menus/modlist.menu | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 9bb36940..98d5bfc7 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -304,6 +304,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "SHOW_ONLY_DISABLED" "Only Disabled" "SHOW_ONLY_NOT_REQUIRED" "Only Optional Mods" "SHOW_ONLY_REQUIRED" "Only Required Mods" + "MOD_REQUIRED_WARNING" " : This mod may get (un)loaded when joining a server" // Maps menu "HIDE_LOCKED" "Hide locked" diff --git a/Northstar.Client/mod/resource/ui/menus/modlist.menu b/Northstar.Client/mod/resource/ui/menus/modlist.menu index da59bcdd..bd350a33 100644 --- a/Northstar.Client/mod/resource/ui/menus/modlist.menu +++ b/Northstar.Client/mod/resource/ui/menus/modlist.menu @@ -488,8 +488,8 @@ resource/ui/menus/modlist.menu { ControlName Label - labelText " : This mod gets (un)loaded automatically" - wide 500 + labelText "#MOD_REQUIRED_WARNING" + auto_wide_tocontents 1 tall 50 visible 0 -- cgit v1.2.3 From d90a9867f02d2860742f30f75ea05c965c92825c Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 20 Dec 2023 16:20:43 +0100 Subject: Add Action to add label to PR on merge conflict (#772) Adds a GitHub Action that auto-adds a label to a PR in case there are merge conflicts. --- .github/workflows/merge-conflict-auto-label.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/merge-conflict-auto-label.yml diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml new file mode 100644 index 00000000..e237726a --- /dev/null +++ b/.github/workflows/merge-conflict-auto-label.yml @@ -0,0 +1,16 @@ +name: Merge Conflict Auto Label +on: + push: + branches: + - main + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: mschilde/auto-label-merge-conflicts@master + with: + CONFLICT_LABEL_NAME: "merge conflicts" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAX_RETRIES: 5 + WAIT_MS: 5000 -- cgit v1.2.3 From feee261dd2269a9f2e13f30d890bc38c6e50351c Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Wed, 20 Dec 2023 21:14:57 +0000 Subject: Add missing server browser localisation for `WRONG_MOD_VERSION` (#710) --- Northstar.Client/mod/resource/northstar_client_localisation_english.txt | 1 + Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index 98d5bfc7..e6518feb 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -370,6 +370,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a // Mod downloading "MISSING_MOD" "Missing mod \"%s1\" v%s2" + "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3" "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" "DOWNLOADING_MOD_TITLE" "Downloading mod" diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 29c7621c..1bc8e405 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1033,7 +1033,7 @@ void function OnServerSelected_Threaded( var button ) { DialogData dialogData dialogData.header = "#ERROR" - dialogData.message = format( "Server has mod \"%s\" v%s while we have v%s", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) + dialogData.message = Localize( "#WRONG_MOD_VERSION", mod.name, mod.version, NSGetModVersionByModName( mod.name ) ) dialogData.image = $"ui/menu/common/dialog_error" #if PC_PROG -- cgit v1.2.3 From 00a4bb6fb5e107788ea77cad51c8c8004a9537f1 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:55:33 +0100 Subject: Translations update from Weblate (#776) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (Spanish (Mexico)) Currently translated at 91.3% (284 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es_MX/ Co-authored-by: Andrés --- .../northstar_client_localisation_mspanish.txt | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt index 18634668..50d1ef17 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_mspanish.txt @@ -319,5 +319,35 @@ Si estas de acuerdo con esto, presiona SI. Esta decision puede ser cambiada en e "INVALID_MASTERSERVER_TOKEN" "Token de jugador expirado o invalido" "JSON_PARSE_ERROR" "Error procesando respuesta json" "UNSUPPORTED_VERSION" "La versión que estas usando ya no esta soportada" + "SHOW_ONLY_REQUIRED" "Solo Mods requeridos" + "player_force_respawn" "Reaparición Forzada" + "TOGGLE_PROGRESSION" "Alternar Progreso" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Desactivar Progreso?" + "NO_RESULTS" "No hay resultados." + "NO_MODS" "No hay configuraciones disponibles! Instala mas mods en: ^5588FF00northstar.thunderstore.io^0." + "AUTHENTICATION_FAILED_HEADER" "Verificacion fallida" + "AUTHENTICATION_FAILED_BODY" "Autenticación fallada con Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Codigo de error: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Ayuda" + "WILL_RESET_ALL_SETTINGS" "Esto reiniciará TODAS las configuraciones de categoría\nEsto no es reversible" + "WILL_RESET_SETTING" "Esto revertirá %s1 a la configuracion por defecto. \n \nEsto no es revertible." + "MOD_SETTINGS_SERVER" "Servidor" + "MOD_SETTINGS_RESET" "Reiniciar" + "MOD_SETTINGS_RESET_ALL" "Reiniciar todo" + "MOD_REQUIRED_WARNING" " Este mod puede ser deshabilitado al entrar a un servidor" + "MOD_SETTINGS" "Configuracion de Mods" + "NORTHSTAR_BASE_SETTINGS" "Configuracion base de Northstar" + "ONLY_HOST_MATCH_SETTINGS" "Solo el Host puede cambiar ajustes de partida" + "ONLY_HOST_CAN_START_MATCH" "Solo el host puede iniciar la partida" + "MATCH_COUNTDOWN_LENGTH" "Cuenta Atrás de partida privada" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Registro desconocido de comandos de cliente" + "DISALLOWED_TACTICALS" "Tactica Prohibida" + "TACTICAL_REPLACEMENT" "Reemplazo de Tactica" + "DISALLOWED_WEAPONS" "Arma Prohibida" + "REPLACEMENT_WEAPON" "Arma de Reemplazo" + "SHOULD_RETURN_TO_LOBBY" "Volver al lobby al finalizar partida" + "ARE_YOU_SURE" "Seguro?" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Alternar Progreso" + "SHOW_ONLY_NOT_REQUIRED" "Solo Mods Opcionales" } } -- cgit v1.2.3 From fd02b453d3ada42d4fd1774737fca9559d971956 Mon Sep 17 00:00:00 2001 From: Casper Talvio Date: Tue, 2 Jan 2024 23:22:08 +0200 Subject: Add validity check to `SaveStatsPeriodically_Threaded` (#769) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index bd64e4ca..f3180214 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -1035,7 +1035,10 @@ void function SaveStatsPeriodically_Threaded() while( true ) { foreach( entity player in GetPlayerArray() ) - Stats_SaveAllStats( player ) + { + if ( IsValid( player ) ) + Stats_SaveAllStats( player ) + } wait 5 } } -- cgit v1.2.3 From af84c42f714484e196cf0d82f9c296e3567b5f35 Mon Sep 17 00:00:00 2001 From: Casper Talvio Date: Tue, 2 Jan 2024 23:24:14 +0200 Subject: Add validity check to `HandleDistanceAndTimeStats_Threaded` to prevent crash (#767) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index f3180214..101d5e4e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -931,6 +931,9 @@ void function HandleDistanceAndTimeStats_Threaded() // track distance stats foreach ( entity player in GetPlayerArray() ) { + if ( !IsValid( player ) ) + continue + if ( player.p.lastPosForDistanceStatValid ) { // not 100% sure on using Distance2D over Distance tbh -- cgit v1.2.3 From 0e153649396355f8d726bad233992725633edea6 Mon Sep 17 00:00:00 2001 From: Aibek <35672535+L1ghtman2k@users.noreply.github.com> Date: Tue, 2 Jan 2024 17:18:18 -0500 Subject: Fix spectating for LTS (#774) Adds missing spectator initialisation Co-authored-by: Khalmee <87766895+Khalmee@users.noreply.github.com> --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 4c52a9bf..e2bb36d2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -201,6 +201,14 @@ void function GameStateEnter_Prematch() if ( !GetClassicMPMode() && !ClassicMP_ShouldTryIntroAndEpilogueWithoutClassicMP() ) thread StartGameWithoutClassicMP() + + // Initialise any spectators. Hopefully they are all initialised already in CodeCallback_OnClientConnectionCompleted + // (_base_gametype_mp.gnut) but for modes like LTS this doesn't seem to happen late enough to work properly. + foreach ( player in GetPlayerArray() ) + { + if ( IsPrivateMatchSpectator( player ) ) + InitialisePrivateMatchSpectatorPlayer( player ) + } } void function StartGameWithoutClassicMP() -- cgit v1.2.3 From 44505833b1fb686c614e75d8269f23f0bc3173c4 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Thu, 4 Jan 2024 00:26:31 +0000 Subject: Prevent crash when selecting first infected (#731) End match early if there are no players when trying to select infected --- .../mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index fef4c8b6..c7175e74 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -45,6 +45,15 @@ void function SelectFirstInfectedDelayed() wait 10.0 + RandomFloat( 5.0 ) array players = GetPlayerArray() + + // End game if server empty on selecting infected + if ( !players.len() ) + { + printt( "Couldn't select first infected: player array was empty" ) + SetWinner( INFECTION_TEAM_SURVIVOR ) + return + } + entity infected = players[ RandomInt( players.len() ) ] InfectPlayer( infected ) -- cgit v1.2.3 From 76582b6890294d2a53163a4be1b806c454aba90e Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 4 Jan 2024 01:32:45 +0100 Subject: Use `getrandom()` instead of random int from player array (#778) Use `getrandom()` instead of random int from player array to select infected Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com> --- Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut index c7175e74..02f0799a 100644 --- a/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/gamemodes/_gamemode_inf.gnut @@ -54,7 +54,7 @@ void function SelectFirstInfectedDelayed() return } - entity infected = players[ RandomInt( players.len() ) ] + entity infected = players.getrandom() InfectPlayer( infected ) RespawnInfected( infected ) -- cgit v1.2.3 From 8847f70ac698a8865842cecd8f0354cdcaac29e1 Mon Sep 17 00:00:00 2001 From: Maya <11448698+RoyalBlue1@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:30:06 +0100 Subject: Fix mod reloading for MAD (#780) Use the proper function instead of NSReloadMods on join --- .../mod/scripts/vscripts/ui/menu_ns_connect_password.nut | 2 +- .../mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index 1e10aa45..b89e665b 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -56,6 +56,6 @@ void function ConnectWithPassword( var button ) if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 1bc8e405..4f17dedf 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1050,13 +1050,6 @@ void function OnServerSelected_Threaded( var button ) } } - // Make Northstar aware new mods have been added - if ( downloadedMods > 0 ) - { - print( "Some new mods have been downloaded or enabled, reloading mods." ) - NSReloadMods(); - } - if ( server.requiresPassword ) { OnCloseServerBrowserMenu() @@ -1065,12 +1058,12 @@ void function OnServerSelected_Threaded( var button ) else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer() + thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) } } -void function ThreadedAuthAndConnectToServer( string password = "" ) +void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1098,8 +1091,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged = false - // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { -- cgit v1.2.3 From 0e5bf9e64a861a1027d572cc334fc7696d493d65 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Tue, 9 Jan 2024 00:48:24 +0100 Subject: Enable MAD by default (#782) Co-authored-by: Maya <11448698+RoyalBlue1@users.noreply.github.com> Co-authored-by: ASpoonPlaysGames <66967891+ASpoonPlaysGames@users.noreply.github.com> Co-authored-by: Alystrasz --- Northstar.Client/mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index 44937a2b..cbd0f64c 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -7,7 +7,7 @@ "ConVars": [ { "Name": "allow_mod_auto_download", - "DefaultValue": "0" + "DefaultValue": "1" }, { "Name": "filter_hide_empty", -- cgit v1.2.3 From 7edb0f2e726221d99db56c434ab6757f3428651f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Sun, 21 Jan 2024 00:20:33 +0000 Subject: Prevent client side crash in MFD when marked target dies out of bounds. (#705) --- .../mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index 659dbb7a..d36045a6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -188,10 +188,15 @@ void function UpdateMarksForKill( entity victim, entity attacker, var damageInfo { if ( victim == GetMarked( victim.GetTeam() ) ) { - MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, attacker.GetEncodedEHandle() ) + // handle suicides. Not sure what the actual message is that vanilla shows for this + // but this will prevent crashing for now + bool isSuicide = IsSuicide( victim, attacker, DamageInfo_GetDamageSourceIdentifier( damageInfo ) ) + entity actualAttacker = isSuicide ? victim : attacker + + MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, actualAttacker.GetEncodedEHandle() ) svGlobal.levelEnt.Signal( "MarkKilled", { mark = victim } ) - - if ( attacker.IsPlayer() ) + + if ( !isSuicide && attacker.IsPlayer() ) attacker.SetPlayerGameStat( PGS_ASSAULT_SCORE, attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + 1 ) } } \ No newline at end of file -- cgit v1.2.3 From 51ed7763f70273603a45dec1ca611ad3eba7f5f6 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 26 Jan 2024 18:44:31 -0300 Subject: Change Aegis Reset Functionality to use titan chassis ref instead of raw index (#788) The previous index passed to the method did not correspond properly with the persistent data index. Instead pass their class reference and then use that to grab the correct index. --- .../mod/scripts/vscripts/sh_progression.nut | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 2dc88d0d..5098dd32 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -88,7 +88,8 @@ bool function ClientCommand_SetProgression( entity player, array args ) /// Resets a specific Titan's Aegis rank back to `0` /// * `player` - The player entity to perform the action on -/// * `args` - The arguments passed from the client command. `args[0]` should be an integer corresponding to the index of the Titan to reset. +/// * `args` - The arguments passed from the client command. `args[0]` should be a string corresponding to the chassis name of the Titan to reset. +/// Valid chassis are: ion, tone, vanguard, northstar, ronin, legion, and scorch. /// /// Returns `true` on success and `false` on missing args. bool function ClientCommand_ResetTitanAegis( entity player, array args ) @@ -96,7 +97,12 @@ bool function ClientCommand_ResetTitanAegis( entity player, array args ) if ( !args.len() ) return false - int suitIndex = args[0].tointeger() + string titanRef = args[0].tolower() + if( !PersistenceEnumValueIsValid( "titanClasses", titanRef ) ) + return false + + int suitIndex = PersistenceGetEnumIndexForItemName( "titanClasses", titanRef ) + player.SetPersistentVar( "titanFDUnlockPoints[" + suitIndex + "]", 0 ) player.SetPersistentVar( "previousFDUnlockPoints[" + suitIndex + "]", 0 ) player.SetPersistentVar( "fdTitanXP[" + suitIndex + "]", 0 ) -- cgit v1.2.3 From 14561cf90f3f80ad844803bdb621c6bd720bdc55 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 26 Jan 2024 18:47:24 -0300 Subject: Unlock remaining DLC items while progression is enabled (#786) As they cannot be unlocked by levelling up and some players may still want to use them while having progression enabled, we simply keep them unlocked when progression is enabled. --- Northstar.CustomServers/mod/scripts/vscripts/_items.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut index a23a68b0..96623086 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_items.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_items.nut @@ -10094,7 +10094,7 @@ void function InitUnlockAsEntitlement( string itemRef, string parentRef, int ent unlock = file.entitlementUnlocks[fullRef] } - unlock.entitlementIds.append( entitlementId ) + unlock.entitlementIds.append( 1 ) // Using `1` here instead of the huge DLC check I did previously. Having the `1` seems to keep all paid cosmetics unlocked with progression enabled. } array function GetEntitlementIds( string itemRef, string parentRef = "" ) -- cgit v1.2.3 From c8193f64ff169441ef9a359af126a99121040224 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:12:10 +0000 Subject: Scale pilot kill core gain properly for mixed modes (#702) Closes #682 --- Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index be20982d..aba1d540 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -304,7 +304,7 @@ void function ScoreEvent_SetupEarnMeterValuesForMixedModes() // mixed modes in t { // todo needs earn/overdrive values // player-controlled stuff - ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15 ) + ScoreEvent_SetEarnMeterValues( "KillPilot", 0.07, 0.15, 0.33 ) // 5% for titan cores ScoreEvent_SetEarnMeterValues( "KillTitan", 0.0, 0.15 ) ScoreEvent_SetEarnMeterValues( "TitanKillTitan", 0.0, 0.0 ) // unsure ScoreEvent_SetEarnMeterValues( "PilotBatteryStolen", 0.0, 0.35 ) // this actually just doesn't have overdrive in vanilla even -- cgit v1.2.3 From 06fd34d87db022cfb646528a5502b07f2cc4efe7 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 4 Feb 2024 02:50:20 +0100 Subject: Disable MAD by default (#787) Disables MAD by default again by flipping the value of the corresponding convar by reverting #782 --- Northstar.Client/mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod.json b/Northstar.Client/mod.json index cbd0f64c..44937a2b 100644 --- a/Northstar.Client/mod.json +++ b/Northstar.Client/mod.json @@ -7,7 +7,7 @@ "ConVars": [ { "Name": "allow_mod_auto_download", - "DefaultValue": "1" + "DefaultValue": "0" }, { "Name": "filter_hide_empty", -- cgit v1.2.3 From 343051c9014207f8785d2194a52ec2f082657ca2 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Fri, 9 Feb 2024 21:05:36 +0100 Subject: Translations update from Weblate (#790) Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../northstar_client_localisation_portuguese.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6364db4..5570b047 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -338,5 +338,41 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "SHOULD_RETURN_TO_LOBBY" "Retornar ao saguão após término de Partida" "WILL_RESET_SETTING" "Isso irá resetar a configuração %s1 ao valor padrão.\n\nAção não reversível." "aitdm_archer_grunts" "Soldados com Archer" + "player_force_respawn" "Resurgimento Forçado" + "PROGRESSION_ENABLED_HEADER" "Progressão Habilitada!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Progressão foi habilitada.^\n\nTitãs, Armas, Facções, Cosméticos, etc. serão destravados ao ganhar níveis, ou comprados com Méritos.\n\nIsso pode ser alterado a qualquer momento no menu de multijogador." + "PROGRESSION_DISABLED_HEADER" "Progressão Desabilitada!" + "TOGGLE_PROGRESSION" "Habilitar Progressão" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Desabilitar Progressão?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titãs, Armas, Facções, Cosméticos etc. serão todos destravados e usáveis a qualquer momento.\n\nIsso pode ser alterado a qualquer hora no menu de multijogador." + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Habilitar Progressão?" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titãs, Armas, Facções, Cosméticos, etc. terão que ser destravados ao ganhar níveis, ou comprados com Méritos.\n\nIsso pode ser alterado a qualquer momento no menu de multijogador.\n\n^CC000000Aviso: Se você atualmente tem qualquer item equipado que não foi préviamente destravado, ele será resetado!" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Alternar Progressão" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Baixando mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Baixando %s1 v%s2..." + "MISSING_MOD" "Mod em falta \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(o mod não é verificado, e não pode ser baixado automaticamente)" + "MOD_DL_DISABLED" "(download automático de mod está desabilitado)" + "DOWNLOADING_MOD_TITLE" "Baixando mod" + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Baixando %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Verificando o mod" + "CHECKSUMING_TEXT" "Verificando conteúdo de %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extraíndo mod (%s1%)" + "MOD_REQUIRED_WARNING" " Este mod pode ser desativado quando entrar em um servidor" + "AUTHENTICATION_FAILED_HEADER" "Autenticação Falhou" + "AUTHENTICATION_FAILED_BODY" "Falha ao autenticar com Atlas!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Código de Erro: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Ajuda" + "EXTRACTING_MOD_TEXT" "Extraíndo %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Falha ao baixar mod" + "FAILED_READING_ARCHIVE" "Um erro ocorreu ao ler o aqruivo do mod." + "MOD_FETCHING_FAILED" "O arquivo do mod não pode ser baixado da Thunderstore." + "MOD_CORRUPTED" "O aquivo baixado não condiz com a assinatura de verificação registrada." + "NO_DISK_SPACE_AVAILABLE" "Não há espaço suficiente no disco." + "PROGRESSION_DISABLED_BODY" "^CCCC0000Progressão foi desabilitada.^\n\nTitãs, Facções, Armas, Cosméticos, etc. estarão disponíveis para uso a qualquer momento.\n\nIsso pode ser alterado a qualquer hora no menu de multijogador." + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Progressão agora pode ser habilitada!^\n\nNorthstar agora suporta a progressão original, o que significa que você pode optar por destravar Armas, Cosméticos, Titãs e outros através do ganho de níveis e completando os desafios.\n\nVocê pode habilitar a progressão usando o botão no rodapé do menu de multijogador.\n\nIsso pode ser alterado a qualquer momento." + "WRONG_MOD_VERSION" "O servidor tem o mod \"%s1\" v%s2 enquanto você possui v%s3" + "FAILED_WRITING_TO_DISK" "Um erro ocorreu enquanto se extraía o conteúdo do mod para o sistema." + "MOD_FETCHING_FAILED_GENERAL" "Extração do mod falhou. Verifique os logs para mais detalhes." } } -- cgit v1.2.3 From 77aefb01fb641af47aa5f855333844835e27047d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:16:08 +0100 Subject: Remove duplicate entries of `mp_lf_stacks` (#793) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index c22e2174..ac638b06 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -395,7 +395,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -449,7 +448,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -498,7 +496,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -747,7 +744,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 @@ -795,7 +791,6 @@ playlists mp_colony02 1 mp_glitch 1 mp_lf_stacks 1 - mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 -- cgit v1.2.3 From cc8df6a8748176cd24f4bb122386a2424e89cd13 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:18:47 +0100 Subject: Fix indentation in `playlist_v2.txt` (#794) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index ac638b06..74169600 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -824,18 +824,18 @@ playlists { maps { - mp_forwardbase_kodai 1 - mp_grave 1 - mp_homestead 1 - mp_thaw 1 - mp_black_water_canal 1 - mp_eden 1 - mp_drydock 1 - mp_crashsite3 1 - mp_complex3 1 - mp_angel_city 1 - mp_colony02 1 - mp_glitch 1 + mp_forwardbase_kodai 1 + mp_grave 1 + mp_homestead 1 + mp_thaw 1 + mp_black_water_canal 1 + mp_eden 1 + mp_drydock 1 + mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_relic02 1 mp_wargames 1 mp_rise 1 -- cgit v1.2.3 From 0982cb08e92bd2d64d8bbc421c34f08a82901155 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Fri, 23 Feb 2024 01:46:34 +0100 Subject: Fix map rotation for CTF and remove duplicate entries (#795) Co-authored-by: Bobbyperson12 <23128094+Bobbyperson12@users.noreply.github.com> --- Northstar.Custom/keyvalues/playlists_v2.txt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index 74169600..e6258edd 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -623,35 +623,27 @@ playlists { maps { - mp_complex3 1 - mp_drydock 1 - mp_glitch 1 - mp_homestead 2 - mp_eden 1 mp_forwardbase_kodai 1 - mp_black_water_canal 1 - mp_glitch 1 - mp_angel_city 1 - mp_colony02 1 - mp_relic02 1 mp_grave 1 mp_homestead 1 - mp_drydock 1 - mp_glitch 1 mp_thaw 1 - mp_eden 2 mp_black_water_canal 1 - mp_glitch 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 + mp_eden 1 + mp_drydock 1 mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 } } } -- cgit v1.2.3 From f2041fbb144707e68c8c772d418479b6ac53bf07 Mon Sep 17 00:00:00 2001 From: Austin Rollfing Date: Thu, 22 Feb 2024 19:50:48 -0500 Subject: Fix map rotation for Hide-and-Seek and remove duplicate entries (#792) --- Northstar.Custom/keyvalues/playlists_v2.txt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Northstar.Custom/keyvalues/playlists_v2.txt b/Northstar.Custom/keyvalues/playlists_v2.txt index e6258edd..d60a24e5 100644 --- a/Northstar.Custom/keyvalues/playlists_v2.txt +++ b/Northstar.Custom/keyvalues/playlists_v2.txt @@ -670,35 +670,27 @@ playlists { maps { - mp_complex3 1 - mp_drydock 1 - mp_glitch 1 - mp_homestead 2 - mp_eden 1 mp_forwardbase_kodai 1 - mp_black_water_canal 1 - mp_glitch 1 - mp_angel_city 1 - mp_colony02 1 - mp_relic02 1 mp_grave 1 mp_homestead 1 - mp_drydock 1 - mp_glitch 1 mp_thaw 1 - mp_eden 2 mp_black_water_canal 1 - mp_glitch 1 - mp_relic02 1 - mp_wargames 1 - mp_rise 1 + mp_eden 1 + mp_drydock 1 mp_crashsite3 1 + mp_complex3 1 + mp_angel_city 1 + mp_colony02 1 + mp_glitch 1 mp_lf_stacks 1 mp_lf_deck 1 mp_lf_meadow 1 mp_lf_traffic 1 mp_lf_township 1 mp_lf_uma 1 + mp_relic02 1 + mp_wargames 1 + mp_rise 1 } } } -- cgit v1.2.3 From 51eb5eade9aedd69b64a293e95c008a8a8d1f908 Mon Sep 17 00:00:00 2001 From: NoCatt <86153630+NoCatt@users.noreply.github.com> Date: Thu, 29 Feb 2024 00:37:57 +0100 Subject: Add weapon dropped callback Adds a callback for when a weapon is dropped. In the progress this also fixes weapons still dropping unintentionally in certain case. --- .../mod/scripts/vscripts/_loadouts_mp.gnut | 20 ++++------------- .../mod/scripts/vscripts/mp/_base_gametype_mp.gnut | 2 ++ .../mod/scripts/vscripts/mp/_codecallbacks.gnut | 25 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut index 63756fdc..141cfe15 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_loadouts_mp.gnut @@ -51,8 +51,6 @@ void function SvLoadoutsMP_Init() AddClientCommandCallback( "InGameMPMenuClosed", ClientCommandCallback_InGameMPMenuClosed ) AddClientCommandCallback( "LoadoutMenuClosed", ClientCommandCallback_LoadoutMenuClosed ) } - - AddCallback_OnPlayerKilled( DestroyDroppedWeapon ) } void function SetLoadoutGracePeriodEnabled( bool enabled ) @@ -62,20 +60,10 @@ void function SetLoadoutGracePeriodEnabled( bool enabled ) void function SetWeaponDropsEnabled( bool enabled ) { - file.weaponDropsEnabled = enabled -} - -void function DestroyDroppedWeapon( entity victim, entity attacker, var damageInfo ) -{ - if ( !file.weaponDropsEnabled && IsValid( victim.GetActiveWeapon() ) ) - thread DelayDestroyDroppedWeapon( victim.GetActiveWeapon() ) -} - -void function DelayDestroyDroppedWeapon( entity weapon ) -{ - WaitEndFrame() - if ( IsValid( weapon ) ) - weapon.Destroy() + if( enabled ) + FlagSet( "WeaponDropsAllowed" ) + else + FlagClear( "WeaponDropsAllowed" ) } void function AddCallback_OnTryGetTitanLoadout( TryGetTitanLoadoutCallbackType callback ) 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 9288f75e..b77a37b2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_base_gametype_mp.gnut @@ -43,6 +43,8 @@ void function BaseGametype_Init_MPSP() AddCallback_OnPlayerKilled( CheckForAutoTitanDeath ) RegisterSignal( "PlayerRespawnStarted" ) RegisterSignal( "KillCamOver" ) + + FlagInit( "WeaponDropsAllowed", true ) } void function SetIntermissionCamera( entity camera ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index ff281d6e..8644296e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -18,6 +18,8 @@ global function CodeCallback_OnProjectileGrappled global function DamageInfo_ScaleDamage global function CodeCallback_CheckPassThroughAddsMods global function SetTitanMeterGainScale +global function CodeCallback_WeaponDropped +global function AddCallback_OnWeaponDropped #if MP global function CodeCallback_OnServerAnimEvent @@ -43,6 +45,7 @@ struct ] table playerAccumulatedDamageData + array< void functionref( entity ) > weaponDroppedCallbacks } file void function CodeCallback_Init() @@ -1030,4 +1033,26 @@ void function CodeCallback_OnServerAnimEvent( entity ent, string eventName ) PerfEnd( PerfIndexServer.CB_OnServerAnimEvent ) } + +void function AddCallback_OnWeaponDropped( void functionref( entity ) callback ) +{ + file.weaponDroppedCallbacks.append( callback ) +} + +void function CodeCallback_WeaponDropped( entity weapon ) +{ + // shamelessly taken form SP + if ( !IsValid( weapon ) ) + return + + // Might look a bit hacky to put it here, but thats how SP does it + if ( !Flag( "WeaponDropsAllowed" ) ) + { + weapon.Destroy() + return + } + + foreach( callback in file.weaponDroppedCallbacks ) + callback( weapon ) +} #endif // #if MP \ No newline at end of file -- cgit v1.2.3 From a8c0653b25616a4b3b5cf224ae7eddc856fad7cc Mon Sep 17 00:00:00 2001 From: Cyn <70904206+itscynxx@users.noreply.github.com> Date: Tue, 26 Mar 2024 07:52:16 -0500 Subject: Fix weapon drop callback breaking SP (#797) Move weapon drop callback globalization to `#if MP` --- Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut index 8644296e..0d1b42b7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_codecallbacks.gnut @@ -18,11 +18,11 @@ global function CodeCallback_OnProjectileGrappled global function DamageInfo_ScaleDamage global function CodeCallback_CheckPassThroughAddsMods global function SetTitanMeterGainScale -global function CodeCallback_WeaponDropped -global function AddCallback_OnWeaponDropped #if MP global function CodeCallback_OnServerAnimEvent +global function CodeCallback_WeaponDropped +global function AddCallback_OnWeaponDropped #endif struct AccumulatedDamageData -- cgit v1.2.3 From 11787b3896b8242ac8f7e583d72cabf68f9161a9 Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:50:38 +0100 Subject: Validate selected Titan loadout index better (#762) Seemingly there are cases where mods can set an invalid Titan loadout index, which then causes the progression checks to attempt to set the player's Titan model to an invalid index. This commit adds a check to ensure that it is within the bounds of the titan loadout array. --- .../mod/scripts/vscripts/sh_progression.nut | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut index 5098dd32..3297643e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/sh_progression.nut @@ -224,11 +224,12 @@ void function ValidateEquippedItems( entity player ) } // titan loadouts + int selectedTitanLoadoutIndex = player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) for ( int titanLoadoutIndex = 0; titanLoadoutIndex < NUM_PERSISTENT_TITAN_LOADOUTS; titanLoadoutIndex++ ) { printt( "- VALIDATING TITAN LOADOUT: " + titanLoadoutIndex ) - bool isSelected = titanLoadoutIndex == player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) + bool isSelected = titanLoadoutIndex == selectedTitanLoadoutIndex TitanLoadoutDef loadout = GetTitanLoadout( player, titanLoadoutIndex ) TitanLoadoutDef defaultLoadout = shGlobal.defaultTitanLoadouts[titanLoadoutIndex] @@ -446,11 +447,18 @@ void function ValidateEquippedItems( entity player ) { printt( " - SELECTED TITAN CLASS IS LOCKED, RESETTING" ) player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) - Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", 0 ) + selectedTitanLoadoutIndex = 0 } } - Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", player.GetPersistentVarAsInt( "titanSpawnLoadout.index" ) ) + if ( selectedTitanLoadoutIndex < 0 || selectedTitanLoadoutIndex >= NUM_PERSISTENT_TITAN_LOADOUTS ) + { + printt( "- SELECTED TITAN CLASS IS INVALID, RESETTING" ) + player.SetPersistentVar( "titanSpawnLoadout.index", 0 ) + selectedTitanLoadoutIndex = 0 + } + + Remote_CallFunction_NonReplay( player, "ServerCallback_UpdateTitanModel", selectedTitanLoadoutIndex ) // pilot loadouts for ( int pilotLoadoutIndex = 0; pilotLoadoutIndex < NUM_PERSISTENT_PILOT_LOADOUTS; pilotLoadoutIndex++ ) -- cgit v1.2.3 From f427583ec497f80aa2f80ac4d34dc44b7e23643f Mon Sep 17 00:00:00 2001 From: Jack <66967891+ASpoonPlaysGames@users.noreply.github.com> Date: Fri, 12 Apr 2024 00:52:53 +0100 Subject: Add initial unit testing logic (#708) Adds initial logic to allow for some form of basic unit testing. --- Northstar.Custom/mod.json | 13 + Northstar.Custom/mod/scripts/vscripts/_testing.nut | 302 +++++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 Northstar.Custom/mod/scripts/vscripts/_testing.nut diff --git a/Northstar.Custom/mod.json b/Northstar.Custom/mod.json index 399311e4..69432f49 100644 --- a/Northstar.Custom/mod.json +++ b/Northstar.Custom/mod.json @@ -440,6 +440,19 @@ "Path": "sh_northstar_safe_io.gnut", "RunOn": "CLIENT || SERVER || UI" }, + { + "Path": "_testing.nut", + "RunOn": "CLIENT || SERVER || UI", + "ClientCallback": { + "Before": "Testing_Init" + }, + "ServerCallback": { + "Before": "Testing_Init" + }, + "UICallback": { + "Before": "Testing_Init" + } + }, { "Path": "_event_models.gnut", "RunOn": "SERVER && LOBBY", diff --git a/Northstar.Custom/mod/scripts/vscripts/_testing.nut b/Northstar.Custom/mod/scripts/vscripts/_testing.nut new file mode 100644 index 00000000..15bcf18b --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/_testing.nut @@ -0,0 +1,302 @@ +global function Testing_Init +global function RunAllTests +global function RunAllTests_SaveToFile +global function RunTestsByCategory +global function RunTestByCategoryAndName + +global function AddTest + +struct TestInfo +{ + string testName + var functionref() callback + // whether the test completed successfully + // if this is true, actualResult is valid + bool completed + // var not string because then i can just set it to an exception + // which print can then handle + var error + // whether the test is considered successful + var expectedResult + var actualResult + bool passed +} + +struct { + table< string, array< TestInfo > > tests = {} +} file + +void function Testing_Init() +{ + // tests for the testing functions :) + //AddTest( "Example Tests", "example succeeding test", ExampleTest_ReturnsTrue, true ) + //AddTest( "Example Tests", "example failing test", ExampleTest_ReturnsFalse, true ) + //AddTest( "Example Tests", "example erroring test", ExampleTest_ThrowsError, true ) + //AddTest( "Example Tests", "example test with args", var function() { + // return ExampleTest_HasArgs_ReturnsNonVar( 2, 3 ) + //}, 6 ) +} + +int function ExampleTest_HasArgs_ReturnsNonVar( int first, int second ) +{ + return first * second +} + +var function ExampleTest_ReturnsFalse() +{ + return false +} + +var function ExampleTest_ReturnsTrue() +{ + return true +} + +var function ExampleTest_ThrowsError() +{ + throw "Example exception" + return null +} + +void function RunAllTests_SaveToFile() +{ + RunAllTests() + + #if UI + string fileName = "ns-unit-tests-UI.json" + #elseif CLIENT + string fileName = "ns-unit-tests-CLIENT.json" + #elseif SERVER + string fileName = "ns-unit-tests-SERVER.json" + #endif + + // cant encode structs so have to reconstruct a table manually from the structs + table out = {} + foreach ( category, tests in file.tests ) + { + array categoryResults = [] + foreach ( test in tests ) + { + table testTable = {} + testTable[ "name" ] <- test.testName + testTable[ "completed" ] <- test.completed + testTable[ "passed" ] <- test.passed + if ( !test.completed ) + testTable[ "error" ] <- test.error + else if ( !test.passed ) + { + testTable[ "expectedResult" ] <- test.expectedResult + testTable[ "actualResult" ] <- test.actualResult + } + + categoryResults.append( testTable ) + } + out[ category ] <- categoryResults + } + + NSSaveJSONFile( fileName, out ) +} + +void function RunAllTests() +{ + printt( "Running all tests!" ) + + foreach ( category, categoryTests in file.tests ) + { + foreach ( test in categoryTests ) + { + RunTest( test ) + } + } + + PrintAllTestResults() +} + +void function RunTestsByCategory( string category ) +{ + if ( !( category in file.tests ) ) + { + printt( format( "Category '%s' has no tests registered", category ) ) + return + } + + foreach ( categoryTest in file.tests[ category ] ) + { + RunTest( categoryTest ) + } +} + +void function RunTestByCategoryAndName( string category, string testName ) +{ + // find test + if ( !( category in file.tests ) ) + { + printt( format( "Category '%s' has no tests registered", category ) ) + return + } + + TestInfo ornull foundTest = null + foreach ( categoryTest in file.tests[ category ] ) + { + if ( categoryTest.testName == testName ) + { + foundTest = categoryTest + break + } + } + + if ( !foundTest ) + { + printt( format( "Category '%s' does not contain a test with name '%s'", category, testName ) ) + return + } + + expect TestInfo( foundTest ) + + printt( "Running test!" ) + // run test + RunTest( foundTest ) + // print result + PrintTestResult( foundTest ) +} + +void function RunTest( TestInfo test ) +{ + test.completed = false + test.passed = false + test.actualResult = null + test.error = "" + + try + { + test.actualResult = test.callback() + test.completed = true + test.passed = test.actualResult == test.expectedResult + } + catch ( exception ) + { + test.completed = false + test.error = exception + } +} + +void function PrintAllTestResults() +{ + int totalSucceeded = 0 + int totalFailed = 0 + int totalErrored = 0 + + foreach ( category, categoryTests in file.tests ) + { + int categorySucceeded = 0 + int categoryFailed = 0 + int categoryErrored = 0 + + printt( format( "Results for category: '%s'", category ) ) + foreach ( test in categoryTests ) + { + if ( test.completed ) + { + if ( test.passed ) + { + printt( "\t", test.testName, "- Passed!" ) + categorySucceeded++ + } + else + { + printt( "\t", test.testName, "- Failed!" ) + printt( "\t\tExpected:", test.expectedResult ) + printt( "\t\tActual: ", test.actualResult ) + categoryFailed++ + } + } + else + { + printt( "\t", test.testName, "- Errored!" ) + printt( "\t\tError:", test.error ) + categoryErrored++ + } + } + + printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored ) + + totalSucceeded += categorySucceeded + totalFailed += categoryFailed + totalErrored += categoryErrored + } + + printt( "TOTAL SUCCEEDED:", totalSucceeded, "TOTAL FAILED:", totalFailed, "TOTAL ERRORED:", totalErrored ) +} + +void function PrintCategoryResults( string category ) +{ + int categorySucceeded = 0 + int categoryFailed = 0 + int categoryErrored = 0 + + printt( format( "Results for category: '%s'", category ) ) + foreach ( test in file.tests[ category ] ) + { + if ( test.completed ) + { + if ( test.passed ) + { + printt( "\t", test.testName, "- Passed!" ) + categorySucceeded++ + } + else + { + printt( "\t", test.testName, "- Failed!" ) + printt( "\t\tExpected:", test.expectedResult ) + printt( "\t\tActual: ", test.actualResult ) + categoryFailed++ + } + } + else + { + printt( "\t", test.testName, "- Errored!" ) + printt( "\t\tError:", test.error ) + categoryErrored++ + } + } + + printt( "Succeeded:", categorySucceeded, "Failed:", categoryFailed, "Errored:", categoryErrored ) +} + +void function PrintTestResult( TestInfo test ) +{ + string resultString = test.testName + + if ( test.completed ) + { + if ( test.passed ) + resultString += " - Passed!" + else + { + resultString += " - Failed!" + resultString += "\n\tExpected: " + test.expectedResult + resultString += "\n\tActual: " + test.actualResult + } + } + else + { + resultString += " - Not completed!" + resultString += "\n\tError: " + test.error + } + + printt( resultString ) +} + +void function AddTest( string testCategory, string testName, var functionref() testFunc, var expectedResult ) +{ + TestInfo newTest + newTest.testName = testName + newTest.callback = testFunc + newTest.expectedResult = expectedResult + + // create the test category if it doesn't exist + if ( !( testCategory in file.tests ) ) + file.tests[ testCategory ] <- [ newTest ] + else + file.tests[ testCategory ].append( newTest ) +} -- cgit v1.2.3 From 9661372712f47f3c5d3ef83f1c7776484eeab52f Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 12 Apr 2024 20:54:55 -0300 Subject: Move all owned NPCs together with player on Team Switching (#789) Uses a call back that is triggered when the player switches team to update their own entities accordingly. --- .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index e2bb36d2..5cc096f2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -96,6 +96,7 @@ void function PIN_GameStart() AddCallback_OnPlayerKilled( OnPlayerKilled ) AddDeathCallback( "npc_titan", OnTitanKilled ) + AddCallback_EntityChangedTeam( "player", OnPlayerChangedTeam ) RegisterSignal( "CleanUpEntitiesForRoundEnd" ) } @@ -1017,3 +1018,21 @@ void function DialoguePlayWinnerDetermined() PlayFactionDialogueToTeam( "scoring_lost", losingTeam ) } } + +/// This is to move all NPCs that a player owns from one team to the other during a match +/// Auto-Titans, Turrets, Ticks and Hacked Spectres will all move along together with the player to the new Team +/// Also possibly prevents mods that spawns other types of NPCs that players can own from breaking when switching (i.e Drones, Hacked Reapers) +void function OnPlayerChangedTeam( entity player ) +{ + if ( !player.hasConnected ) // Prevents players who just joined to trigger below code, as server always pre setups their teams + return + + NotifyClientsOfTeamChange( player, GetOtherTeam( player.GetTeam() ), player.GetTeam() ) + + foreach( npc in GetNPCArray() ) + { + entity bossPlayer = npc.GetBossPlayer() + if ( IsValidPlayer( bossPlayer ) && bossPlayer == player && IsAlive( npc ) ) + SetTeam( npc, player.GetTeam() ) + } +} -- cgit v1.2.3 From 76ba7bf0bae819040a966ea81598f8906d1126b8 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 13 Apr 2024 02:06:44 +0200 Subject: Translations update from Weblate (#801) Translated using Weblate (Spanish) Currently translated at 92.6% (288 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/es/ Co-authored-by: NachosChipeados --- Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt index 3d9ae4c6..d4172232 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_spanish.txt @@ -352,5 +352,6 @@ Presiona Sí al estar de acuerdo. Esta opcion se puede cambiar en el menú de mo "WILL_RESET_SETTING" "Ésta acción reiniciará %s1 a su valor por defecto.\n\nNo se podrá revertir el proceso." "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000El progreso puede ser habilitado desde ahora^\n\nNorthstar ahora es compatible con el progreso normal del juego, esto significa que puedes elegir desbloquear Armas, Aspectos, Titanes y otros a través de desafíos y subiendo de nivel.\n\nPuedes habilitar el progreso normal del juego en la opción ubicada al final de la pantalla de la sala de espera.\n\nÉsta opción puede ser cambiada en cualquier momento." "player_force_respawn" "Reaparición Forzada" + "MOD_REQUIRED_WARNING" " : Esta modificacion puede ser desactivada al entrar a un servidor" } } -- cgit v1.2.3 From 8037da592fa508a07e56811438a55a8b27e4b478 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 29 May 2024 16:22:43 +0200 Subject: Translations update from Weblate (#804) * Translated using Weblate (German) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ * Translated using Weblate (German) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/de/ --------- Co-authored-by: justplus Co-authored-by: GeckoEidechse --- .../northstar_client_localisation_german.txt | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt index f1994a24..996a3e2b 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_german.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_german.txt @@ -312,5 +312,69 @@ Drücke Ja, um zuzustimmen. Du kannst diese Entscheidung jederzeit im Modmenü "UNSUPPORTED_VERSION" "Die Version die du benutzt ist nicht länger unterstützt" "SNS_LEADER_BANKRUPT_SUB" "%s1 Wurde Von %s2 Zurückgesetzt" "SNS_BANKRUPT_SUB" "Dein Punkestand wurde von %s1 zurückgesetzt" + "respawnprotection" "Respawn Schutzdauer" + "SNS_BANKRUPT" "Bankrott!" + "SNS_LEADER_BANKRUPT" "Punktzahlführer Bankrott!" + "sns_reset_pulse_blade_cooldown_on_pulse_blade_kill" "Kill Cooldown Zurücksetzungen" + "player_force_respawn" "Erzwungener Respawn" + "SHOW_ONLY_NOT_REQUIRED" "Nur optionale Mods" + "SHOW_ONLY_REQUIRED" "Nur notwendige Mods" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "Fortschritt aktivieren?" + "TOGGLE_PROGRESSION" "Fortschritt zuschalten" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "Fortschritt deaktivieren?" + "PROGRESSION_TOGGLE_ENABLED_BODY" "Titans, Waffen, Fraktionen, Skins, usw werden freigeschaltet und sind zu jeder Zeit verfügbar .\n\nDies kann in der Mehrspielerlobby zu jedem Zeitpunkt geändert werden." + "MATCH_COUNTDOWN_LENGTH" "Countdown für privates Match" + "LOG_UNKNOWN_CLIENTCOMMANDS" "Unbekannte Clientbefehle loggen" + "DISALLOWED_TACTICALS" "Verbotene Taktiken" + "TACTICAL_REPLACEMENT" "Taktischer Austausch" + "AUTHENTICATION_FAILED_HEADER" "Authentifizierung fehlgeschlagen" + "AUTHENTICATION_FAILED_BODY" "Authentifizierung mit Atlas fehlgeschlagen!" + "AUTHENTICATION_FAILED_ERROR_CODE" "Fehlercode: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_HELP" "Hilfe" + "NORTHSTAR_BASE_SETTINGS" "Northstar Grundeinstellungen" + "ONLY_HOST_MATCH_SETTINGS" "Nur der Host kann die Einstellungen eines privaten Matches ändern" + "ONLY_HOST_CAN_START_MATCH" "Nur der Host kann das Match starten" + "MISSING_MOD" "Fehlender Mod \"%s1\" v%s2" + "MOD_DL_DISABLED" "(automatisches Herunterladen ist deaktiviert)" + "DOWNLOADING_MOD_TITLE" "Lade Mod herunter" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Lade Mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Lade %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Lade %s1 v%s2...\n(%s3/%s4 MB)" + "CHECKSUMING_TITLE" "Überprüfe Mod Prüfsumme" + "MOD_NOT_VERIFIED" "(mod ist nicht verifiziert und kann nicht automatisch herunterladen werden)" + "MOD_REQUIRED_WARNING" " : Dieser Mod könnte Sie (un)ausgestattet hinterlassen, sobald Sie einem Server beitreten" + "MOD_SETTINGS" "Mod Einstellungen" + "DISALLOWED_WEAPONS" "Verbotene Waffen" + "REPLACEMENT_WEAPON" "Austausch Waffen" + "SHOULD_RETURN_TO_LOBBY" "Zur Lobby nach Matchende zurückkehren" + "ARE_YOU_SURE" "Sind Sie sich sicher?" + "MOD_SETTINGS_SERVER" "Server" + "MOD_SETTINGS_RESET" "Zurücksetzen" + "MOD_SETTINGS_RESET_ALL" "Alles zurücksetzen" + "NO_RESULTS" "Keine Ergebnisse." + "NO_MODS" "Keine Einstellungen verfügbar! Installieren sie weitere Mods über^5588FF00northstar.thunderstore.io^0." + "PROGRESSION_ENABLED_HEADER" "Fortschritt aktiviert!" + "PROGRESSION_DISABLED_HEADER" "Fortschritt deaktiviert!" + "WILL_RESET_ALL_SETTINGS" "Dadurch werden ALLE Einstellungen, die zu dieser Kategorie gehören, zurückgesetzt.\n\nDies kann nicht rückgängig gemacht werden." + "WILL_RESET_SETTING" "Dies setzten die Einstellungen %s1 auf deren Ursprungeswert zurück.\n\nDies kann nicht rückgängig gemacht werden." + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Fortschritt zuschalten." + "PROGRESSION_TOGGLE_DISABLED_BODY" "Titans, Waffen, Fraktionen, Skins usw. müssen durch Levelaufstieg freigeschaltet oder mit Verdiensten gekauft werden.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden.\n\n^CC000000Warnung: Wenn Sie derzeit ausgerüstete Gegenstände besitzen, die Sie nicht freigeschaltet haben, werden diese zurückgesetzt!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000Fortschritt wurde aktiviert.^\n\nTitans, Waffen, Fraktionen, Skins usw. müssen durch Levelaufstieg freigeschaltet oder mit Verdiensten gekauft werden.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden." + "PROGRESSION_DISABLED_BODY" "^CCCC0000Fortschritt wurde deaktiviert.^\n\nTitans, Waffen, Fraktionen, Skins usw. werden alle freigeschaltet und jederzeit nutzbar sein.\n\nDies kann jederzeit in der Mehrspieler-Lobby geändert werden." + "CHECKSUMING_TEXT" "Verifiziere Inhalte von %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Extrahiere Mod (%s1%)" + "EXTRACTING_MOD_TEXT" "Extrahiere %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_DOWNLOADING" "Herunterladen der Mod fehlgeschlagen" + "FAILED_READING_ARCHIVE" "Während des Lesens der Mod Archivs ist ein Fehler aufgetreten." + "FAILED_WRITING_TO_DISK" "Während des Extrahierens der Mod in das Dateisysteme ist ein Fehler aufgetreten." + "WRONG_MOD_VERSION" "Der Server verfügt über Mod \"%s1\" v%s2 während Sie v%s3 haben" + "MOD_FETCHING_FAILED" "Mod Archiv konnte nicht von Thunderstore heruntergeladen werden." + "MOD_CORRUPTED" "Prüfsumme des heruntergeladenen Archivs stimmt nicht mit der verifizierten Signatur überein." + "NO_DISK_SPACE_AVAILABLE" "Sie verfügen nicht über ausreichend Speicherplatz auf ihrer Festplatte." + "MOD_FETCHING_FAILED_GENERAL" "Mod Extraktion fehlgeschlagen. Überprüfen Sie die Logs für weitere Details." + "gg_assist_reward" "Assist Anteilige Belohnung" + "SCOREBOARD_BANKRUPTS" "Bankrott Kills" + "sns_offhand_kill_value" "Freihand Killwert" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000Fortschritt kann jetzt aktiviert werden!^\n\nNorthstar unterstützt nun den standardmäßigen Fortschritt, was bedeutet, dass Sie Waffen, Skins, Titans usw. durch Levelaufstieg und das Abschließen von Herausforderungen freischalten können.\n\nSie können den Fortschritt mit dem Button am unteren Rand des Lobbybildschirms aktivieren.\n\nDies kann jederzeit geändert werden." } } -- cgit v1.2.3 From 83e97763b3421e59d13e9a40bf20c0d987da9129 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Mon, 24 Jun 2024 14:29:40 +0200 Subject: Bump Actions Ubuntu version to 22.04 (#805) Bump the Ubuntu version used for encoding and missing translations check from `20.04` to `22.04`. --- .github/workflows/encoding.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/encoding.yml b/.github/workflows/encoding.yml index a88e3961..5a730c20 100644 --- a/.github/workflows/encoding.yml +++ b/.github/workflows/encoding.yml @@ -3,7 +3,7 @@ on: [push, pull_request] jobs: check-loc-encoding: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 @@ -12,7 +12,7 @@ jobs: files=$(ls Northstar.Client/mod/resource/northstar_client_localisation_*.txt) IFS=$'\n'; files=($files); unset IFS; ! file --mime "${files[@]}" | grep -v "charset=utf-16le" check-missing-translations: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v3 -- cgit v1.2.3 From 6581c4e800e5cec0e4d6f5b3f87b80bd6989233c Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 28 Jun 2024 15:10:45 -0300 Subject: Implement Match Goals menu and XP tracking (#756) for vanilla parity when it comes to the progression system. See PR description for full details --- .../mod/scripts/vscripts/_xp.gnut | 16 ++ .../mod/scripts/vscripts/evac/_evac.gnut | 10 + .../mod/scripts/vscripts/faction_xp.gnut | 9 + .../scripts/vscripts/gamemodes/_gamemode_aitdm.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_at.nut | 6 + .../scripts/vscripts/gamemodes/_gamemode_cp.nut | 41 +++- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 19 ++ .../scripts/vscripts/gamemodes/_gamemode_fra.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_lts.nut | 33 +++ .../scripts/vscripts/gamemodes/_gamemode_mfd.nut | 15 +- .../scripts/vscripts/gamemodes/_gamemode_ps.nut | 1 + .../vscripts/gamemodes/_gamemode_speedball.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_tdm.nut | 1 + .../scripts/vscripts/gamemodes/_gamemode_ttdm.nut | 31 +++ .../mod/scripts/vscripts/mp/_challenges.gnut | 268 +++++++++++++++++++++ .../mod/scripts/vscripts/mp/_gamestate_mp.nut | 38 ++- .../mod/scripts/vscripts/mp/_score.nut | 17 ++ .../mod/scripts/vscripts/titan_xp.gnut | 22 ++ .../mod/scripts/vscripts/weapon_xp.gnut | 7 + 19 files changed, 533 insertions(+), 4 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut index 2b95d1a8..97d993e6 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/_xp.gnut @@ -16,7 +16,10 @@ void function SetupPlayerPreviousXPValues( entity player ) player.SetPersistentVar( "previousFactionXP[" + xpFaction + "]", FactionGetXP( player, xpFaction ) ) foreach ( string xpTitan in shTitanXP.titanClasses ) + { player.SetPersistentVar( "previousTitanXP[" + xpTitan + "]", TitanGetXP( player, xpTitan ) ) + player.SetPersistentVar( "fdPreviousTitanXP[" + xpTitan + "]", FD_TitanGetXP( player, xpTitan ) ) + } foreach ( string xpWeapon in shWeaponXP.weaponClassNames ) player.SetPersistentVar( GetItemPersistenceStruct( xpWeapon ) + ".previousWeaponXP", WeaponGetXP( player, xpWeapon ) ) @@ -35,6 +38,14 @@ void function HandleXPGainForScoreEvent( entity player, ScoreEvent event ) int weaponXp = ScoreEvent_GetXPValueWeapon( event ) int titanXp = ScoreEvent_GetXPValueTitan( event ) int factionXp = ScoreEvent_GetXPValueFaction( event ) + + if ( player.GetPlayerNetInt( "xpMultiplier" ) > 0 || GetCurrentPlaylistVarInt( "double_xp_enabled", 0 ) == 1 ) + { + xpValue *= 2 + weaponXp *= 2 + titanXp *= 2 + factionXp *= 2 + } entity weapon = player.GetActiveWeapon() if ( IsValid( weapon ) && ShouldTrackXPForWeapon( weapon.GetWeaponClassName() ) && weaponXp != 0 ) @@ -63,5 +74,10 @@ void function AddXP( entity player, int amount ) int newXp = player.GetPersistentVarAsInt( "xp" ) int newLevel = GetLevelForXP( newXp ) if ( newLevel != oldLevel ) + { Remote_CallFunction_NonReplay( player, "ServerCallback_PlayerLeveledUp", player.GetPersistentVarAsInt( "gen" ), newLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForPlayerLevels( player, player.GetPersistentVarAsInt( "gen" ), newLevel ) + } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut index af074689..760daef0 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/evac/_evac.gnut @@ -246,6 +246,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa SetTeamActiveObjective( evacTeam, "EG_DropshipExtract", Time() + arrivalTime, file.evacIcon ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_StopExtract", Time() + arrivalTime, file.evacIcon ) + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) //Show the Evac Match Goal for players of the team that lost the match + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 0 ) + // would've liked to use cd_dropship_rescue_side_start length here, but can't since this is done before dropship spawn, can't wait arrivalTime - 4.33333 @@ -280,6 +283,9 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa { SetTeamActiveObjective( evacTeam, "EG_DropshipExtractDropshipDestroyed" ) SetTeamActiveObjective( GetOtherTeam( evacTeam ), "EG_DropshipExtractDropshipDestroyed" ) + + foreach( entity player in GetPlayerArrayOfTeam( evacTeam ) ) + SetPlayerChallengeEvacState( player, 0 ) } foreach ( entity player in dropship.s.evacSlots ) @@ -402,7 +408,10 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa if ( !PlayerInDropship( player, dropship ) ) { if ( player.GetTeam() == dropship.GetTeam() ) + { SetPlayerActiveObjective( player, "EG_DropshipExtractFailedEscape" ) + SetPlayerChallengeEvacState( player, 2 ) + } continue } @@ -417,6 +426,7 @@ void function Evac( int evacTeam, float initialWait, float arrivalTime, float wa Remote_CallFunction_NonReplay( player, "ServerCallback_DisableHudForEvac" ) Remote_CallFunction_NonReplay( player, "ServerCallback_SetClassicSkyScale", dropship.GetEncodedEHandle(), 0.7 ) Remote_CallFunction_NonReplay( player, "ServerCallback_SetMapSettings", 4.0, false, 0.4, 0.125 ) + SetPlayerChallengeEvacState( player, 1 ) // display player [Evacuated] in killfeed foreach ( entity otherPlayer in GetPlayerArray() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut index 6555c875..5aee1104 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/faction_xp.gnut @@ -4,10 +4,19 @@ void function AddFactionXP( entity player, int amount ) { string faction = GetFactionChoice( player ) int oldLevel = FactionGetLevel( player, faction ) + int FactionXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]" ) + // increment xp player.SetPersistentVar( "factionXP[" + faction + "]", min( FactionGetXP( player, faction ) + amount, FactionGetMaxXP( faction ) ) ) // note: no notif for faction level up if ( FactionGetLevel( player, faction ) != oldLevel ) + { AddPlayerScore( player, "FactionLevelUp" ) + IncrementPlayerChallengeFactionLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.FACTION_LEVELED + "]", FactionXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFactionLevels( player, faction, oldLevel, FactionGetLevel( player, faction ) ) + } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut index f47ee90f..7d73c926 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_aitdm.nut @@ -60,6 +60,7 @@ void function GamemodeAITdm_Init() } ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericTDMChallenge() } // add settings diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut index 93a3aa16..9cf0021d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_at.nut @@ -178,6 +178,12 @@ void function AT_PlayerTitleThink( entity player ) { // Set player money count player.SetTitle( "$" + string( AT_GetPlayerBonusPoints( player ) ) ) + + if( AT_GetPlayerBonusPoints( player ) >= 600 && !HasPlayerCompletedMeritScore( player ) ) //Challenge is: "Earn $600." + { + AddPlayerScore( player, "ChallengeATAssault" ) + SetPlayerChallengeMeritScore( player ) + } } else if ( GetGameState() >= eGameState.WinnerDetermined ) { diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut index c5765300..d8b0c9bd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_cp.nut @@ -29,6 +29,8 @@ struct { array hardpoints array players + table playerAssaultPoints + table playerDefensePoints } file void function GamemodeCP_Init() @@ -112,11 +114,13 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointDefense", victim ) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_DEFENSE) } else if((victimCP.hardpoint.GetTeam()==victim.GetTeam())||(GetHardpointCappingTeam(victimCP)==victim.GetTeam())) { AddPlayerScore( attacker, "HardpointAssault", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_ASSAULT) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_ASSAULT,0) } } } @@ -127,10 +131,12 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama { AddPlayerScore( attacker , "HardpointSnipe", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SNIPE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SNIPE,0) } else{ AddPlayerScore( attacker , "HardpointSiege", victim ) attacker.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_SIEGE) + UpdatePlayerScoreForChallenge(attacker,POINTVALUE_HARDPOINT_SIEGE,0) } } else if(attackerCP.hardpoint!=null)//Perimeter Defense @@ -138,6 +144,7 @@ void function GamemodeCP_OnPlayerKilled(entity victim, entity attacker, var dama if(attackerCP.hardpoint.GetTeam()==attacker.GetTeam()) AddPlayerScore( attacker , "HardpointPerimeterDefense", victim) attacker.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) + UpdatePlayerScoreForChallenge(attacker,0,POINTVALUE_HARDPOINT_PERIMETER_DEFENSE) } foreach(CP_PlayerStruct player in file.players) //Reset Victim Holdtime Counter @@ -308,6 +315,7 @@ void function CapturePointForTeam(HardpointStruct hardpoint, int Team) if(player.IsPlayer()){ AddPlayerScore(player,"ControlPointCapture") player.AddToPlayerGameStat(PGS_ASSAULT_SCORE,POINTVALUE_HARDPOINT_CAPTURE) + UpdatePlayerScoreForChallenge(player,POINTVALUE_HARDPOINT_CAPTURE,0) } } } @@ -319,12 +327,17 @@ void function GamemodeCP_InitPlayer(entity player) playerStruct.timeOnPoints = [0.0,0.0,0.0] playerStruct.isOnHardpoint = false file.players.append(playerStruct) + file.playerAssaultPoints[player] <- 0 + file.playerDefensePoints[player] <- 0 thread PlayerThink(playerStruct) } void function GamemodeCP_RemovePlayer(entity player) { - + if(player in file.playerAssaultPoints) + delete file.playerAssaultPoints[player] + if(player in file.playerDefensePoints) + delete file.playerDefensePoints[player] foreach(index,CP_PlayerStruct playerStruct in file.players) { if(playerStruct.player==player) @@ -376,11 +389,13 @@ void function PlayerThink(CP_PlayerStruct player) { AddPlayerScore(player.player,"ControlPointAmpedHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_AMPED_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_AMPED_HOLD) } else { AddPlayerScore(player.player,"ControlPointHold") player.player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, POINTVALUE_HARDPOINT_HOLD ) + UpdatePlayerScoreForChallenge(player.player,0,POINTVALUE_HARDPOINT_HOLD) } } break @@ -574,6 +589,7 @@ void function HardpointThink( HardpointStruct hardpoint ) { AddPlayerScore(player,"ControlPointAmped") player.AddToPlayerGameStat(PGS_DEFENSE_SCORE,POINTVALUE_HARDPOINT_AMPED) + UpdatePlayerScoreForChallenge(player,0,POINTVALUE_HARDPOINT_AMPED) } } } @@ -714,3 +730,26 @@ string function GetHardpointGroup(entity hardpoint) //Hardpoint Entity B on Home return string(hardpoint.kv.hardpointGroup) } + +void function UpdatePlayerScoreForChallenge(entity player,int assaultpoints = 0,int defensepoints = 0) +{ + if(player in file.playerAssaultPoints) + { + file.playerAssaultPoints[player] += assaultpoints + if( file.playerAssaultPoints[player] >= 1000 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPAssault") + SetPlayerChallengeMeritScore(player) + } + } + + if(player in file.playerDefensePoints) + { + file.playerDefensePoints[player] += defensepoints + if( file.playerDefensePoints[player] >= 500 && !HasPlayerCompletedMeritScore(player) ) + { + AddPlayerScore(player,"ChallengeCPDefense") + SetPlayerChallengeMeritScore(player) + } + } +} diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index 9b05c3d4..fefdbcdd 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -421,8 +421,15 @@ void function CaptureFlag( entity player, entity flag ) assistList = file.militiaCaptureAssistList foreach( entity assistPlayer in assistList ) + { if ( player != assistPlayer ) AddPlayerScore( assistPlayer, "FlagCaptureAssist", player ) + if( !HasPlayerCompletedMeritScore( assistPlayer ) ) + { + AddPlayerScore( assistPlayer, "ChallengeCTFCapAssist" ) + SetPlayerChallengeMeritScore( assistPlayer ) + } + } assistList.clear() @@ -430,6 +437,12 @@ void function CaptureFlag( entity player, entity flag ) MessageToPlayer( player, eEventNotifications.YouCapturedTheEnemyFlag ) EmitSoundOnEntityOnlyToPlayer( player, player, "UI_CTF_1P_PlayerScore" ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( team, eEventNotifications.PlayerCapturedEnemyFlag, player, player ) EmitSoundOnEntityToTeamExceptPlayer( flag, "UI_CTF_3P_TeamScore", player.GetTeam(), player ) @@ -503,6 +516,12 @@ void function TryReturnFlag( entity player, entity flag ) AddPlayerScore( player, "FlagReturn", player ) player.AddToPlayerGameStat( PGS_DEFENSE_SCORE, 1 ) + if( !HasPlayerCompletedMeritScore( player ) ) + { + AddPlayerScore( player, "ChallengeCTFRetAssist" ) + SetPlayerChallengeMeritScore( player ) + } + MessageToTeam( flag.GetTeam(), eEventNotifications.PlayerReturnedFriendlyFlag, null, player ) EmitSoundOnEntityToTeam( flag, "UI_CTF_3P_TeamReturnsFlag", flag.GetTeam() ) PlayFactionDialogueToTeam( "ctf_flagReturnedFriendly", flag.GetTeam() ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut index 9d8f84b5..6d0fd3c7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_fra.nut @@ -17,6 +17,7 @@ void function GamemodeFRA_Init() ScoreEvent_SetEarnMeterValues( "PilotBatteryPickup", 0.0, 0.34 ) EarnMeterMP_SetPassiveMeterGainEnabled( false ) PilotBattery_SetMaxCount( 3 ) + SetupGenericFFAChallenge() AddCallback_OnPlayerKilled( FRARemoveEarnMeter ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut index 31c85a57..8999231d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_lts.nut @@ -8,6 +8,8 @@ struct { float lastDamageInfoTime bool shouldDoHighlights + + table< entity, int > pilotstreak } file void function GamemodeLts_Init() @@ -34,6 +36,37 @@ void function GamemodeLts_Init() ClassicMP_SetCustomIntro( ClassicMP_DefaultNoIntro_Setup, ClassicMP_DefaultNoIntro_GetLength() ) ClassicMP_ForceDisableEpilogue( true ) AddCallback_GameStateEnter( eGameState.Playing, WaitForThirtySecondsLeft ) + + AddCallback_OnClientConnected( SetupPlayerLTSChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerLTSChallenges ) //Safety removal of data to prevent crashes + AddCallback_OnPlayerKilled( LTSChallengeForPlayerKilled ) +} + +void function SetupPlayerLTSChallenges( entity player ) +{ + file.pilotstreak[ player ] <- 0 +} + +void function RemovePlayerLTSChallenges( entity player ) +{ + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function LTSChallengeForPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeLTS" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } void function WaitForThirtySecondsLeft() diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut index d36045a6..768bbde1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_mfd.nut @@ -180,6 +180,12 @@ void function MarkPlayers( entity imcMark, entity militiaMark ) entity livingMark = GetMarked( GetOtherTeam( deadMark.GetTeam() ) ) livingMark.SetPlayerGameStat( PGS_DEFENSE_SCORE, livingMark.GetPlayerGameStat( PGS_DEFENSE_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( livingMark ) ) + { + AddPlayerScore( livingMark, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( livingMark ) + } + // thread this so we don't kill our own thread thread AddTeamScore( livingMark.GetTeam(), 1 ) } @@ -195,8 +201,15 @@ void function UpdateMarksForKill( entity victim, entity attacker, var damageInfo MessageToAll( eEventNotifications.MarkedForDeathKill, null, victim, actualAttacker.GetEncodedEHandle() ) svGlobal.levelEnt.Signal( "MarkKilled", { mark = victim } ) - + if ( !isSuicide && attacker.IsPlayer() ) + { attacker.SetPlayerGameStat( PGS_ASSAULT_SCORE, attacker.GetPlayerGameStat( PGS_ASSAULT_SCORE ) + 1 ) + if( !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeMFD" ) + SetPlayerChallengeMeritScore( attacker ) + } + } } } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut index 57355ad8..c91c27d1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ps.nut @@ -19,6 +19,7 @@ void function GamemodePs_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericFFAChallenge() // spawnzone stuff SetShouldCreateMinimapSpawnZones( true ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut index cb277b00..4617476e 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_speedball.nut @@ -18,6 +18,7 @@ void function GamemodeSpeedball_Init() Riff_ForceTitanAvailability( eTitanAvailability.Never ) Riff_ForceSetEliminationMode( eEliminationMode.Pilots ) ScoreEvent_SetupEarnMeterValuesForMixedModes() + SetupGenericFFAChallenge() AddSpawnCallbackEditorClass( "script_ref", "info_speedball_flag", CreateFlag ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut index 5c0e6fec..61ede2d4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_tdm.nut @@ -6,6 +6,7 @@ void function GamemodeTdm_Init() AddCallback_OnPlayerKilled( GiveScoreForPlayerKill ) ScoreEvent_SetupEarnMeterValuesForMixedModes() SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + SetupGenericTDMChallenge() } void function GiveScoreForPlayerKill( entity victim, entity attacker, var damageInfo ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut index 6b30a399..3ba84394 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ttdm.nut @@ -2,6 +2,11 @@ global function GamemodeTTDM_Init const float TTDMIntroLength = 15.0 +struct +{ + table< entity, int > challengeCount +} file + void function GamemodeTTDM_Init() { Riff_ForceSetSpawnAsTitan( eSpawnAsTitan.Always ) @@ -14,6 +19,8 @@ void function GamemodeTTDM_Init() ClassicMP_ForceDisableEpilogue( true ) SetTimeoutWinnerDecisionFunc( CheckScoreForDraw ) + AddCallback_OnClientConnected( SetupPlayerTTDMChallenges ) //Just to make up the Match Goals tracking + AddCallback_OnClientDisconnected( RemovePlayerTTDMChallenges ) //Safety removal of data to prevent crashes AddCallback_OnPlayerKilled( AddTeamScoreForPlayerKilled ) // dont have to track autotitan kills since you cant leave your titan in this mode // probably needs scoreevent earnmeter values @@ -56,6 +63,17 @@ void function TTDMIntroShowIntermissionCam( entity player ) thread PlayerWatchesTTDMIntroIntermissionCam( player ) } +void function SetupPlayerTTDMChallenges( entity player ) +{ + file.challengeCount[ player ] <- 0 +} + +void function RemovePlayerTTDMChallenges( entity player ) +{ + if( player in file.challengeCount ) + delete file.challengeCount[ player ] +} + void function PlayerWatchesTTDMIntroIntermissionCam( entity player ) { player.EndSignal( "OnDestroy" ) @@ -79,6 +97,19 @@ void function AddTeamScoreForPlayerKilled( entity victim, entity attacker, var d if ( victim == attacker || !victim.IsPlayer() || !attacker.IsPlayer() && GetGameState() == eGameState.Playing ) return + if( victim in file.challengeCount ) + file.challengeCount[victim] = 0 + + if( attacker in file.challengeCount ) + { + file.challengeCount[attacker]++ + if( file.challengeCount[attacker] >= 2 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + AddTeamScore( GetOtherTeam( victim.GetTeam() ), 1 ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 466a5042..4b866a40 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -1,6 +1,274 @@ global function InitChallenges +global function SetPlayerChallengeEvacState //Hooked in _evac.gnut +global function SetPlayerChallengeMatchWon //Hooked in _score.nut +global function SetPlayerChallengeMatchComplete //Hooked in _score.nut +global function SetPlayerChallengeMeritScore //Up to gamemodes to use this directly if needed +global function IncrementPlayerChallengeTitanLeveledUp //Hooked in titan_xp.gnut +global function IncrementPlayerChallengeWeaponLeveledUp //Hooked in weapon_xp.gnut +global function IncrementPlayerChallengeFactionLeveledUp //Hooked in faction_xp.gnut (invisible but necessary for post-summary menu) +global function RegisterChallenges_OnMatchEnd //Hooked in _gamestate_mp.gnut + +global function HasPlayerCompletedMeritScore //Check from gamemodes to not reapply SetPlayerChallengeMeritScore +global function SetupGenericTDMChallenge //Used by gamemodes which simply adopts the: "Kill 3 Pilots without dying." Challenge +global function SetupGenericFFAChallenge //Used by gamemodes which simply adopts the: "Kill 5 Pilots." Challenge + +struct +{ + table< entity, int > playerTotalMeritCount + table< entity, bool > playerChallenge + table< entity, int > pilotstreak + bool isHappyHourActive +} file + + + + + + +/*============================================================================================================= + __ __ _ _ ____ _ _ _ + | \/ | __ _ | |_ ___ | |__ / ___|| |__ __ _ | || | ___ _ __ __ _ ___ ___ + | |\/| | / _` || __|/ __|| '_ \ | | | '_ \ / _` || || | / _ \| '_ \ / _` | / _ \/ __| + | | | || (_| || |_| (__ | | | | | |___ | | | || (_| || || || __/| | | || (_| || __/\__ \ + |_| |_| \__,_| \__|\___||_| |_| \____||_| |_| \__,_||_||_| \___||_| |_| \__, | \___||___/ + |___/ +=============================================================================================================*/ void function InitChallenges() { +#if (UI && CLIENT) + + SCB_SetCompleteMeritState( 4 ) + SCB_SetEvacMeritState( 4 ) + SCB_SetMeritCount( 4 ) + SCB_SetScoreMeritState( 4 ) + SCB_SetWinMeritState( 4 ) + SCB_SetWeaponMeritCount( -1 ) + SCB_SetTitanMeritCount( -1 ) + +#elseif (SERVER && MP) + + AddCallback_OnClientConnected( SetupPlayerMenuChallenges ) + AddCallback_OnClientDisconnected( RemovePlayerFromChallengePool ) + +#endif +} + +void function SetupPlayerMenuChallenges( entity player ) +{ + file.playerTotalMeritCount[ player ] <- 0 + file.pilotstreak[ player ] <- 0 + file.playerChallenge[ player ] <- false + + thread SetupChallenges_Threaded( player ) +} +void function SetupChallenges_Threaded( entity player ) +{ + WaitFrame() + + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it + Remote_CallFunction_UI( player, "SCB_SetMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 0 ) + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", 0 ) + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", 0 ) +} + +void function SetupGenericTDMChallenge() +{ + AddCallback_OnPlayerKilled( TDMChallenges_OnPlayerKilled ) +} + +void function SetupGenericFFAChallenge() +{ + AddCallback_OnPlayerKilled( FFAChallenges_OnPlayerKilled ) +} + +void function RemovePlayerFromChallengePool( entity player ) +{ + if( player in file.playerChallenge ) + delete file.playerChallenge[ player ] + if( player in file.playerTotalMeritCount ) + delete file.playerTotalMeritCount[ player ] + if( player in file.pilotstreak ) + delete file.pilotstreak[ player ] +} + +void function RegisterChallenges_OnMatchEnd() +{ + bool eliteWarpaintRNG = false + + if( RandomIntRange( 0, 100 ) <= 30 ) //30% Chance to trigger akin to vanilla, apply always since all players have paid cosmetics unlocked + eliteWarpaintRNG = true + + foreach( player in GetPlayerArray() ) + { + player.SetPersistentVar( "isPostGameScoreboardValid", true ) + player.SetPersistentVar( "isFDPostGameScoreboardValid", false ) //FD itself overrides this right after when match ends + SetUIVar( level, "showGameSummary", true ) + + if( eliteWarpaintRNG ) + SetPlayerChallengeSquadLeader( player ) + + if( ShouldAwardHappyHourBonus( player ) ) + { + AddPlayerScore( player, "HappyHourBonus" ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.HAPPY_HOUR + "]", 5 ) //The XP Given from Happy Hour Score is 5 merits + } + } +} + +void function TDMChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() ) + { + if( victim in file.pilotstreak ) + file.pilotstreak[victim] = 0 + if( attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 3 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengeTDM" ) + SetPlayerChallengeMeritScore( attacker ) + } + } + } +} + +void function FFAChallenges_OnPlayerKilled( entity victim, entity attacker, var damageInfo ) +{ + if ( victim == attacker || !attacker.IsPlayer() || GetGameState() != eGameState.Playing ) + return + + if ( victim.IsPlayer() && attacker in file.pilotstreak ) + { + file.pilotstreak[attacker]++ + if( file.pilotstreak[attacker] >= 5 && !HasPlayerCompletedMeritScore( attacker ) ) + { + AddPlayerScore( attacker, "ChallengePVPKillCount" ) + SetPlayerChallengeMeritScore( attacker ) + } + } +} + +bool function HasPlayerCompletedMeritScore( entity player ) +{ + Assert( player in file.playerChallenge, player + " is not registered in the challenge pool hooks." ) + return file.playerChallenge[ player ] +} + + + + + + + +/*============================================================================================================= + ____ _ _ _ _ + / ___| __ _ _ __ ___ ___ _ __ ___ ___ __| | ___ | | | | ___ ___ | | __ ___ + | | _ / _` || '_ ` _ \ / _ \| '_ ` _ \ / _ \ / _` | / _ \ | |_| | / _ \ / _ \ | |/ // __| + | |_| || (_| || | | | | || __/| | | | | || (_) || (_| || __/ | _ || (_) || (_) || < \__ \ + \____| \__,_||_| |_| |_| \___||_| |_| |_| \___/ \__,_| \___| |_| |_| \___/ \___/ |_|\_\|___/ + +=============================================================================================================*/ + +void function SetPlayerChallengeEvacState( entity player, int successEvac = 0 ) +{ + if( successEvac == 0 ) //Evac Ship destroyed + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 2 ) + + else if( successEvac == 1 ) //Player itself managed to evac + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.EVAC + "]", 1 ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + + else if( successEvac == 2 ) //Team managed to evac + Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 3 ) +} + +void function SetPlayerChallengeMatchWon( entity player, bool playerWon ) +{ + if( playerWon ) + { + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_VICTORY + "]", 1 ) + player.SetPersistentVar( "matchWin", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } + else + Remote_CallFunction_UI( player, "SCB_SetWinMeritState", -1 ) +} + +void function SetPlayerChallengeMatchComplete( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.MATCH_COMPLETED + "]", 1 ) + player.SetPersistentVar( "matchComplete", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function SetPlayerChallengeSquadLeader( entity player ) +{ + if( !ProgressionEnabledForPlayer( player ) ) + return + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderDoubleXP" ) + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", player.GetEncodedEHandle() ) + player.SetPersistentVar( "matchSquadBonus", true ) + Player_GiveDoubleXP( player, 1 ) + foreach( entity teamplayer in GetPlayerArrayOfTeam( player.GetTeam() ) ) + { + if( teamplayer == player ) + continue + + Remote_CallFunction_NonReplay( player, "ServerCallback_SquadLeaderBonus", teamplayer.GetEncodedEHandle() ) + } +} + +void function SetPlayerChallengeMeritScore( entity player ) +{ + if( !HasPlayerCompletedMeritScore( player ) ) + { + file.playerChallenge[ player ] = true + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetScoreMeritState", 1 ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.SCORE_MILESTONE + "]", 1 ) + player.SetPersistentVar( "matchScoreEvent", true ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) + } +} + +void function IncrementPlayerChallengeTitanLeveledUp( entity player ) +{ + player.p.meritData.titanMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetTitanMeritCount", player.p.meritData.titanMerits++ ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeWeaponLeveledUp( entity player ) +{ + player.p.meritData.weaponMerits++ + file.playerTotalMeritCount[ player ]++ + + Remote_CallFunction_UI( player, "SCB_SetWeaponMeritCount", player.p.meritData.weaponMerits ) + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) +} + +void function IncrementPlayerChallengeFactionLeveledUp( entity player ) +{ + file.playerTotalMeritCount[ player ]++ + Remote_CallFunction_UI( player, "SCB_SetMeritCount", file.playerTotalMeritCount[ player ] ) } \ 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 5cc096f2..5eba24ac 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -396,6 +396,7 @@ void function GameStateEnter_WinnerDetermined_Threaded() } else { + RegisterChallenges_OnMatchEnd() if ( ClassicMP_ShouldRunEpilogue() ) { ClassicMP_SetupEpilogue() @@ -834,11 +835,44 @@ void function SetWinner( int team, string winningReason = "", string losingReaso } SetGameState( eGameState.WinnerDetermined ) + ScoreEvent_RoundComplete( team ) } else + { SetGameState( eGameState.WinnerDetermined ) - - ScoreEvent_MatchComplete( team ) + ScoreEvent_MatchComplete( team ) + + array players = GetPlayerArray() + int functionref( entity, entity ) compareFunc = GameMode_GetScoreCompareFunc( GAMETYPE ) + if ( compareFunc != null ) + { + players.sort( compareFunc ) + int playerCount = players.len() + int currentPlace = 1 + for ( int i = 0; i < 3; i++ ) + { + if ( i >= playerCount ) + continue + + if ( i > 0 && compareFunc( players[i - 1], players[i] ) != 0 ) + currentPlace += 1 + + switch( currentPlace ) + { + case 1: + UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 2: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + case 3: + UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) + break + } + } + } + } } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut index aba1d540..2a4c4282 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_score.nut @@ -8,6 +8,7 @@ global function ScoreEvent_TitanDoomed global function ScoreEvent_TitanKilled global function ScoreEvent_NPCKilled global function ScoreEvent_MatchComplete +global function ScoreEvent_RoundComplete global function ScoreEvent_SetEarnMeterValues global function ScoreEvent_SetupEarnMeterValuesForMixedModes @@ -287,8 +288,24 @@ void function ScoreEvent_MatchComplete( int winningTeam ) foreach( entity player in GetPlayerArray() ) { AddPlayerScore( player, "MatchComplete" ) + SetPlayerChallengeMatchComplete( player ) if ( player.GetTeam() == winningTeam ) + { AddPlayerScore( player, "MatchVictory" ) + SetPlayerChallengeMatchWon( player, true ) + } + else + SetPlayerChallengeMatchWon( player, false ) + } +} + +void function ScoreEvent_RoundComplete( int winningTeam ) +{ + foreach( entity player in GetPlayerArray() ) + { + AddPlayerScore( player, "RoundComplete" ) + if ( player.GetTeam() == winningTeam ) + AddPlayerScore( player, "RoundVictory" ) } } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut index 0436a393..847881b5 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/titan_xp.gnut @@ -1,17 +1,39 @@ global function AddTitanXP +global function AddFDTitanXP void function AddTitanXP( entity player, int amount ) { string titan = GetActiveTitanLoadout( player ).titanClass int oldLevel = TitanGetLevel( player, titan ) + int TitanXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]" ) // increment xp player.SetPersistentVar( "titanXP[" + titan + "]", min( TitanGetXP( player, titan ) + amount, TitanGetMaxXP( titan ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_TitanXPAdded", shTitanXP.titanClasses.find( titan ), TitanGetXP( player, titan ), amount ) // level up notif if ( TitanGetLevel( player, titan ) != oldLevel ) { Remote_CallFunction_NonReplay( player, "ServerCallback_TitanLeveledUp", shTitanXP.titanClasses.find( titan ), TitanGetGen( player, titan ), TitanGetLevel( player, titan ) ) AddPlayerScore( player, "TitanLevelUp" ) + IncrementPlayerChallengeTitanLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.TITAN_LEVELED + "]", TitanXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForTitanLevels( player, titan, oldLevel, TitanGetLevel( player, titan ) ) } +} + +void function AddFDTitanXP( entity player, int fdXPamount ) +{ + string titanRef = GetActiveTitanLoadout( player ).titanClass + + player.SetPersistentVar( "fdTitanXP[" + titanRef + "]", FD_TitanGetPreviousXP( player, titanRef ) + fdXPamount ) + int startingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetPreviousXP( player, titanRef ) ) + int endingLevel = FD_TitanGetLevelForXP( titanRef, FD_TitanGetXP( player, titanRef ) ) + + Player_GiveFDUnlockPoints( player, endingLevel - startingLevel ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForFDTitanLevels( player, titanRef, startingLevel, endingLevel ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut index 4e25e301..0b0084b3 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/weapon_xp.gnut @@ -6,15 +6,22 @@ void function AddWeaponXP( entity player, int amount ) entity activeWeapon = player.GetActiveWeapon() string weaponClassname = activeWeapon.GetWeaponClassName() int oldLevel = WeaponGetLevel( player, weaponClassname ) + int WeaponXPMatch = player.GetPersistentVarAsInt( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]" ) // increment xp player.SetPersistentVar( GetItemPersistenceStruct( weaponClassname ) + ".weaponXP", min( WeaponGetXP( player, weaponClassname ) + amount, WeaponGetMaxXP( weaponClassname ) ) ) + Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponXPAdded", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetXP( player, weaponClassname ), amount ) // level up notif if ( WeaponGetLevel( player, weaponClassname ) != oldLevel ) { Remote_CallFunction_NonReplay( player, "ServerCallback_WeaponLeveledUp", shWeaponXP.weaponClassNames.find( weaponClassname ), WeaponGetGen( player, weaponClassname ), WeaponGetLevel( player, weaponClassname ) ) AddPlayerScore( player, "WeaponLevelUp" ) + IncrementPlayerChallengeWeaponLeveledUp( player ) + player.SetPersistentVar( "xp_match[" + XP_TYPE.WEAPON_LEVELED + "]", WeaponXPMatch + 1 ) + + if( ProgressionEnabledForPlayer( player ) ) + AwardRandomItemsForWeaponLevels( player, weaponClassname, oldLevel, WeaponGetLevel( player, weaponClassname ) ) } // proscreen -- cgit v1.2.3 From 35318c3b1496fe7dc162f51a73617d399d38cbb2 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:28:21 +0200 Subject: Translations update from Weblate (#806) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 94.2% (293 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- Northstar.Client/mod/resource/northstar_client_localisation_french.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index b0e579cf..52009f4f 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -357,5 +357,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "AUTHENTICATION_FAILED_HELP" "Aide" "AUTHENTICATION_FAILED_ERROR_CODE" "Code d'erreur : ^DB6F2C00%s1^" "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." + "MISSING_MOD" "Mod manquant \"%s1\" v%s2" + "MOD_REQUIRED_WARNING" " : Ce mod peut être (dé)chargé automatiquement en rejoignant un serveur" } } -- cgit v1.2.3 From 8181dd7e0726883e335d09df637487f61dcbbb11 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:56:30 +0200 Subject: Translations update from Weblate (#807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../northstar_client_localisation_french.txt | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 52009f4f..0bb6b328 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -348,7 +348,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "PROGRESSION_ENABLED_HEADER" "Progression activée !" "PROGRESSION_DISABLED_HEADER" "Progression désactivée !" "PROGRESSION_DISABLED_BODY" "^CCCC0000La progression a été désactivée.^\n\nLes Titans, Armes, Factions, Skins, et autres seront débloqués et utilisables en tout temps.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." - "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équiper des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" + "PROGRESSION_TOGGLE_DISABLED_BODY" "Les Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs.\n\n^CC000000Warning : Si vous équipez des objets que vous n'avez pas encore débloqués, ils seront déséquipés !" "PROGRESSION_ENABLED_BODY" "^CCCC0000La progression a été activée.^\n\nLes Titans, Armes, Factions, Skins et autres seront débloqués par la monté en niveau ou par leur achats en mérites.\n\nPeut être changé à n'importe que moment dans le salon multijoueurs." "TOGGLE_PROGRESSION" "Activer la progression" "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% Activer la progression" @@ -359,5 +359,23 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "AUTHENTICATION_FAILED_BODY" "L'authentification avec Atlas a échoué." "MISSING_MOD" "Mod manquant \"%s1\" v%s2" "MOD_REQUIRED_WARNING" " : Ce mod peut être (dé)chargé automatiquement en rejoignant un serveur" + "EXTRACTING_MOD_TITLE" "Extraction du mod (%s1%)" + "MOD_NOT_VERIFIED" "(ce mod n'est pas vérifié, et n'a donc pas pu être automatiquement téléchargé)" + "MOD_DL_DISABLED" "(le téléchargement automatique de mods est désactivé)" + "DOWNLOADING_MOD_TITLE" "Téléchargement du mod" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Téléchargement du mod (%s1%)" + "DOWNLOADING_MOD_TEXT" "Téléchargement de %s1 v%s2..." + "WRONG_MOD_VERSION" "Le serveur requiert la version v%s2 du mod \"%s1\" (vous avez la version v%s3)" + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Téléchargement de %s1 v%s2...\n(%s3/%s4 Mo)" + "CHECKSUMING_TITLE" "Vérification de la somme de contrôle du mod" + "CHECKSUMING_TEXT" "Vérification du contenu de %s1 v%s2..." + "EXTRACTING_MOD_TEXT" "Extraction de %s1 v%s2...\n(%s3/%s4 Mo)" + "FAILED_DOWNLOADING" "Echec du téléchargement du mod" + "FAILED_READING_ARCHIVE" "Une erreur est survenue lors de la lecture de l'archive." + "FAILED_WRITING_TO_DISK" "Une erreur est survenue lors de l'extraction des fichiers." + "MOD_FETCHING_FAILED" "L'archive n'a pas pu être téléchargée depuis Thunderstore." + "MOD_CORRUPTED" "La somme de contrôle de l'archive ne correspond pas à la signature vérifiée." + "NO_DISK_SPACE_AVAILABLE" "L'espace restant sur votre disque est insuffisant." + "MOD_FETCHING_FAILED_GENERAL" "L'extraction du mod a échoué. Consultez le journal pour plus d'informations." } } -- cgit v1.2.3 From 0198d3f99c40ab641c85fff62b62276407e0dfc3 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 5 Jul 2024 19:02:11 -0300 Subject: Unfuck the Spawns (#808) 1. Get rid of the odd logic of limiting the algorithm to 3 spawn points 2. Changes the specific CTF algorithm to calculate the spawn points from the flag bases themselves rather than the initial spawn points which was causing severe inconsistencies. 3. Remove some checks in regards to map side swapping when matches reaches half-times due to odd behaviour in native code 4. Mitigate usage of `GetOtherTeam` for certain checks since that function might return Unreachable when it's a gamemode with more than 2 Teams and intentionally script crash the server. --- .../scripts/vscripts/gamemodes/_gamemode_ctf.nut | 31 ++++++-------- .../mod/scripts/vscripts/mp/spawn.nut | 48 +++++++++------------- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut index fefdbcdd..97addc24 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/gamemodes/_gamemode_ctf.nut @@ -75,27 +75,20 @@ void function RateSpawnpoints_CTF( int checkClass, array spawnpoints, in bool function VerifyCTFSpawnpoint( entity spawnpoint, int team ) { // ensure spawnpoints aren't too close to enemy base + vector allyFlagSpot + vector enemyFlagSpot + foreach ( entity spawn in GetEntArrayByClass_Expensive( "info_spawnpoint_flag" ) ) + { + if( spawn.GetTeam() == team ) + allyFlagSpot = spawn.GetOrigin() + else + enemyFlagSpot = spawn.GetOrigin() + } - if ( HasSwitchedSides() ) - team = GetOtherTeam( team ) - - array startSpawns = SpawnPoints_GetPilotStart( team ) - array enemyStartSpawns = SpawnPoints_GetPilotStart( GetOtherTeam( team ) ) - - vector averageFriendlySpawns - vector averageEnemySpawns - - foreach ( entity spawn in startSpawns ) - averageFriendlySpawns += spawn.GetOrigin() - - averageFriendlySpawns /= startSpawns.len() - - foreach ( entity spawn in enemyStartSpawns ) - averageEnemySpawns += spawn.GetOrigin() - - averageEnemySpawns /= startSpawns.len() + if( Distance2D( spawnpoint.GetOrigin(), allyFlagSpot ) > Distance2D( spawnpoint.GetOrigin(), enemyFlagSpot ) ) + return false - return Distance2D( spawnpoint.GetOrigin(), averageEnemySpawns ) / Distance2D( averageFriendlySpawns, averageEnemySpawns ) > 0.35 + return true } void function CTFInitPlayer( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut index 4956375b..d64e3a5b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/spawn.nut @@ -130,7 +130,7 @@ entity function FindSpawnPoint( entity player, bool isTitan, bool useStartSpawnp { int team = player.GetTeam() if ( HasSwitchedSides() ) - team = GetOtherTeam( team ) + team = ( team == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA array spawnpoints if ( useStartSpawnpoint ) @@ -181,29 +181,19 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) foreach ( entity spawnpoint in spawnpoints ) { if ( IsSpawnpointValid( spawnpoint, player.GetTeam() ) ) - { validSpawns.append( spawnpoint ) - - if ( validSpawns.len() == 3 ) // arbitrary small sample size - break - } } - if ( validSpawns.len() == 0 ) + if ( !validSpawns.len() ) { // no valid spawns, very bad, so dont care about spawns being valid anymore print( "found no valid spawns! spawns may be subpar!" ) foreach ( entity spawnpoint in spawnpoints ) - { validSpawns.append( spawnpoint ) - - if ( validSpawns.len() == 3 ) // arbitrary small sample size - break - } } // last resort - if ( validSpawns.len() == 0 ) + if ( !validSpawns.len() ) { print( "map has literally 0 spawnpoints, as such everything is fucked probably, attempting to use info_player_start if present" ) entity start = GetEnt( "info_player_start" ) @@ -215,7 +205,7 @@ entity function GetBestSpawnpoint( entity player, array spawnpoints ) } } - return validSpawns[ RandomInt( validSpawns.len() ) ] // slightly randomize it + return validSpawns.getrandom() // slightly randomize it } bool function IsSpawnpointValid( entity spawnpoint, int team ) @@ -232,15 +222,18 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } + if( IsFFAGame() && !spawnpoint.IsVisibleToEnemies( team ) ) + return true + int compareTeam = spawnpoint.GetTeam() - if ( HasSwitchedSides() && ( compareTeam == TEAM_MILITIA || compareTeam == TEAM_IMC ) ) - compareTeam = GetOtherTeam( compareTeam ) - + if ( HasSwitchedSides() ) + compareTeam = ( compareTeam == TEAM_MILITIA ) ? TEAM_IMC : TEAM_MILITIA + foreach ( bool functionref( entity, int ) customValidationRule in file.customSpawnpointValidationRules ) if ( !customValidationRule( spawnpoint, team ) ) return false - if ( spawnpoint.GetTeam() > 0 && compareTeam != team && !IsFFAGame() ) + if ( spawnpoint.GetTeam() > 0 && compareTeam != team ) return false if ( spawnpoint.IsOccupied() ) @@ -261,13 +254,12 @@ bool function IsSpawnpointValid( entity spawnpoint, int team ) return false } - const minEnemyDist = 1000.0 // about 20 meters? - // in rsquirrel extend returns null unlike in vanilla squirrel - array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) - spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, TEAM_ANY, spawnpoint.GetOrigin(), minEnemyDist ) ) - foreach ( entity blocker in spawnBlockers ) - if ( blocker.GetTeam() != team ) - return false + const minEnemyDist = 1200.0 + array< entity > spawnBlockers = GetPlayerArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) + spawnBlockers.extend( GetProjectileArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) + spawnBlockers.extend( GetNPCArrayEx( "any", TEAM_ANY, spawnpoint.GetTeam(), spawnpoint.GetOrigin(), minEnemyDist ) ) + if ( spawnBlockers.len() ) + return false // los check return !spawnpoint.IsVisibleToEnemies( team ) @@ -399,11 +391,9 @@ void function InitPreferSpawnNodes() // frontline void function RateSpawnpoints_Frontline( int checkClass, array spawnpoints, int team, entity player ) { + float rating = RandomFloatRange( 0.0, 100.0 ) foreach ( entity spawnpoint in spawnpoints ) - { - float rating = spawnpoint.CalculateFrontlineRating() - spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating > 0 ? rating * 0.25 : rating ) - } + spawnpoint.CalculateRating( checkClass, player.GetTeam(), rating, rating ) } // spawnzones -- cgit v1.2.3 From f3fa134ff6508f88cf966b92f6690b6f8b58fea1 Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Sat, 6 Jul 2024 17:30:01 -0400 Subject: Fix `cl_earn_meter` crash when Core does not exist during Core Active state (#494) Fix crash when getting core weapon --- Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut b/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut index 16908362..3971d2be 100644 --- a/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut +++ b/Northstar.Custom/mod/scripts/vscripts/earn_meter/cl_earn_meter.gnut @@ -335,7 +335,11 @@ void function EarnMeter_Update() break entity soul = player.GetTitanSoul() - entity core = player.GetOffhandWeapons()[3] + entity core = player.GetOffhandWeapon( OFFHAND_EQUIPMENT ) + + if ( !IsValid( core ) ) + break + string coreName = core.GetWeaponClassName() array coreMods = core.GetMods() -- cgit v1.2.3 From 852f3bcb04f7dfbf8f41676d47c01d4d6fbf084e Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:02:53 -0300 Subject: Rework Intro Dropship Script to avoid player overlap (#809) This overhaul makes the Dropships behave consistently now like vanilla and players will only start overlapping each other when both Dropships are full, otherwise code will always attempt to populate them properly instead. --- .../vscripts/mp/_classic_mp_dropship_intro.gnut | 177 ++++++++++----------- 1 file changed, 86 insertions(+), 91 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 23ae37a1..7b6c7e9f 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -26,18 +26,9 @@ const int MAX_DROPSHIP_PLAYERS = 4 global const float DROPSHIP_INTRO_LENGTH = 15.0 // TODO tweak this -struct IntroDropship -{ - entity dropship - - int playersInDropship - entity[MAX_DROPSHIP_PLAYERS] players -} - struct { - // these used to be IntroDropship[2]s but i wanted to be able to use array.getrandom so they have to be actual arrays - array militiaDropships - array imcDropships + table< entity, array > militiaDropships + table< entity, array > imcDropships float introStartTime } file @@ -52,7 +43,12 @@ void function ClassicMP_DefaultDropshipIntro_Setup() void function DropshipIntro_OnClientConnected( entity player ) { if ( GetGameState() == eGameState.Prematch ) - thread SpawnPlayerIntoDropship( player ) + { + if( PlayerCanSpawn( player ) ) + DoRespawnPlayer( player, null ) + + PutPlayerInDropship( player ) + } } void function OnPrematchStart() @@ -62,11 +58,11 @@ void function OnPrematchStart() print( "starting dropship intro!" ) file.introStartTime = Time() - // make 2 empty dropship structs per team - IntroDropship emptyDropship + // Clear Dropship arrays of Teams for Match Restarts (i.e Half-Times) file.militiaDropships.clear() file.imcDropships.clear() + // Try to gather all possible Dropship spawn points for Team array validDropshipSpawns array dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" ) foreach ( entity dropshipSpawn in dropshipSpawns ) @@ -78,47 +74,47 @@ void function OnPrematchStart() validDropshipSpawns.append( dropshipSpawn ) } - // if no dropship spawns for this mode, just allow any dropship spawns + // Use any spawn point if not enough valid for this Gamemode exists if ( validDropshipSpawns.len() < 2 ) validDropshipSpawns = dropshipSpawns // spawn dropships foreach ( entity dropshipSpawn in validDropshipSpawns ) { - // todo: possibly make this only spawn dropships if we've got enough players to need them int createTeam = HasSwitchedSides() ? GetOtherTeam( dropshipSpawn.GetTeam() ) : dropshipSpawn.GetTeam() - array teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships + table< entity, array > teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships if ( teamDropships.len() >= 2 ) - continue + break - // create entity entity dropship = CreateDropship( createTeam, dropshipSpawn.GetOrigin(), dropshipSpawn.GetAngles() ) - - teamDropships.append( clone emptyDropship ) - teamDropships[ teamDropships.len() - 1 ].dropship = dropship - AddAnimEvent( dropship, "dropship_warpout", WarpoutEffect ) + dropship.SetValueForModelKey( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + if ( dropshipSpawn.GetTeam() == TEAM_IMC ) + dropship.SetValueForModelKey( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) DispatchSpawn( dropship ) - // have to do this after dispatch otherwise it won't work for some reason - // weirdly enough, tf2 actually does use different dropships for imc and militia, despite these concepts not really being a thing for players in tf2 - // probably was just missed by devs, but keeping it in for accuracy + dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) if ( dropshipSpawn.GetTeam() == TEAM_IMC ) dropship.SetModel( $"models/vehicle/goblin_dropship/goblin_dropship_hero.mdl" ) - else - dropship.SetModel( $"models/vehicle/crow_dropship/crow_dropship_hero.mdl" ) + + teamDropships[ dropship ] <- [ null, null, null, null ] thread PlayAnim( dropship, "dropship_classic_mp_flyin" ) } + // Populate Dropships foreach ( entity player in GetPlayerArray() ) { if ( !IsPrivateMatchSpectator( player ) ) - thread SpawnPlayerIntoDropship( player ) + { + if( PlayerCanSpawn( player ) ) + DoRespawnPlayer( player, null ) + + PutPlayerInDropship( player ) + } else RespawnPrivateMatchSpectator( player ) } @@ -128,68 +124,69 @@ void function OnPrematchStart() void function EndIntroWhenFinished() { - wait 15.0 + wait DROPSHIP_INTRO_LENGTH ClassicMP_OnIntroFinished() } -void function SpawnPlayerIntoDropship( entity player ) +void function PutPlayerInDropship( entity player ) { - player.EndSignal( "OnDestroy" ) + //Find the player's dropship and seat + table< entity, array > teamDropships + if ( player.GetTeam() == TEAM_MILITIA ) + teamDropships = file.militiaDropships + else + teamDropships = file.imcDropships + + entity playerDropship + array< int > availableShipSlots + array< entity > introDropships + int playerDropshipIndex = RandomInt( MAX_DROPSHIP_PLAYERS ) + foreach( dropship, playerslot in teamDropships ) + { + introDropships.append( dropship ) + for ( int i = 0; i < MAX_DROPSHIP_PLAYERS; i++ ) + { + if ( !IsValidPlayer( playerslot[i] ) ) + availableShipSlots.append( i ) + } + + if( !availableShipSlots.len() ) + continue + + int slotPick = availableShipSlots.getrandom() + playerslot[slotPick] = player + playerDropship = dropship + playerDropshipIndex = slotPick + break + } + + if( !IsAlive( playerDropship ) ) //If we're at this point, we have more players than we do dropships, so just pick a random one + playerDropship = introDropships.getrandom() + + thread SpawnPlayerIntoDropship( player, playerDropshipIndex, playerDropship ) +} - if ( IsAlive( player ) ) - player.Die() // kill them so we don't have any issues respawning them later +void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, entity playerDropship ) +{ + player.EndSignal( "OnDestroy" ) + player.EndSignal( "OnDeath" ) - player.s.dropshipIntroIsJumping <- false - OnThreadEnd( function() : ( player ) + OnThreadEnd( function() : ( player, playerDropshipIndex, playerDropship ) { if ( IsValid( player ) ) { player.ClearParent() ClearPlayerAnimViewEntity( player ) - - if ( !player.s.dropshipIntroIsJumping ) - { - player.MovementEnable() - player.EnableWeaponViewModel() - RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) - } + } + if( IsAlive( playerDropship ) ) + { + if ( playerDropship.GetTeam() == TEAM_MILITIA ) + file.militiaDropships[ playerDropship ][ playerDropshipIndex ] = null + else + file.imcDropships[ playerDropship ][ playerDropshipIndex ] = null } }) - WaitFrame() - - player.EndSignal( "OnDeath" ) - - // find the player's dropship and seat - array teamDropships - if ( player.GetTeam() == TEAM_MILITIA ) - teamDropships = file.militiaDropships - else - teamDropships = file.imcDropships - - IntroDropship playerDropship - int playerDropshipIndex = -1 - foreach ( IntroDropship dropship in teamDropships ) - for ( int i = 0; i < dropship.players.len(); i++ ) - if ( dropship.players[ i ] == null ) - { - playerDropship = dropship - playerDropshipIndex = i - - dropship.players[ i ] = player - break - } - - if ( playerDropship.dropship == null ) - { - // if we're at this point, we have more players than we do dropships, so just pick a random one - playerDropship = teamDropships.getrandom() - playerDropshipIndex = RandomInt( MAX_DROPSHIP_PLAYERS ) - } - - // respawn player and holster their weapons so they aren't out - if ( !IsAlive( player ) ) - player.RespawnPlayer( null ) HolsterAndDisableWeapons(player) player.DisableWeaponViewModel() @@ -208,9 +205,7 @@ void function SpawnPlayerIntoDropship( entity player ) idleSequence.viewConeFunction = ViewConeRampFree idleSequence.hideProxy = true idleSequence.setInitialTime = Time() - file.introStartTime - thread FirstPersonSequence( idleSequence, player, playerDropship.dropship ) - WaittillAnimDone( player ) - + waitthread FirstPersonSequence( idleSequence, player, playerDropship ) // todo: possibly rework this to actually get the time the idle anim takes and start the starttime of the jump sequence for very late joiners using that // jump sequence @@ -218,13 +213,12 @@ void function SpawnPlayerIntoDropship( entity player ) jumpSequence.firstPersonAnim = DROPSHIP_JUMP_ANIMS_POV[ playerDropshipIndex ] jumpSequence.thirdPersonAnim = DROPSHIP_JUMP_ANIMS[ playerDropshipIndex ] jumpSequence.attachment = "ORIGIN" + jumpSequence.viewConeFunction = ViewConeFree jumpSequence.setInitialTime = max( 0.0, Time() - ( file.introStartTime + 11.0 ) ) // pretty sure you should do this with GetScriptedAnimEventCycleFrac? // idk unsure how to use that, all i know is getsequenceduration > the length it actually should be - thread FirstPersonSequence( jumpSequence, player, playerDropship.dropship ) - WaittillAnimDone( player ) // somehow this is better than just waiting for the blocking FirstPersonSequence call? + waitthread FirstPersonSequence( jumpSequence, player, playerDropship ) - player.s.dropshipIntroIsJumping <- true thread PlayerJumpsFromDropship( player ) } @@ -244,16 +238,17 @@ void function PlayerJumpsFromDropship( entity player ) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) - - // wait for intro timer to be fully done - wait ( file.introStartTime + DROPSHIP_INTRO_LENGTH ) - Time() - player.MovementDisable() // disable all movement but let them look around still - player.ConsumeDoubleJump() // movementdisable doesn't prevent double jumps // wait for player to hit the ground - wait 0.1 // assume players will never actually hit ground before this + player.ClearParent() + WaitFrame() + player.SetVelocity( < 0, 0, -100 > ) // Toss players a bit down so it makes a smoother transition when jumping off the Dropship + player.MovementDisable() // Disable all movement but let them look around still + player.ConsumeDoubleJump() // MovementDisable doesn't prevent double jumps + WaitFrame() while ( !player.IsOnGround() && !player.IsWallRunning() && !player.IsWallHanging() ) // todo this needs tweaking WaitFrame() - TryGameModeAnnouncement( player ) + if ( GetRoundsPlayed() == 0 ) //Intro is announced only for the first round in Vanilla as certain gamemodes have different announcements for rounds restarts + TryGameModeAnnouncement( player ) } -- cgit v1.2.3 From 2849218b47666c5611e3de591fc5f77a77a807eb Mon Sep 17 00:00:00 2001 From: Zanieon Date: Sun, 7 Jul 2024 00:06:51 +0200 Subject: Fix formatting in dropship intro taken from #809 --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 7b6c7e9f..8b75a982 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -187,7 +187,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e } }) - HolsterAndDisableWeapons(player) + HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() // hide hud and fade screen out from black @@ -234,7 +234,7 @@ void function PlayerJumpsFromDropship( entity player ) // show weapon viewmodel and hud and let them move again player.MovementEnable() player.EnableWeaponViewModel() - DeployAndEnableWeapons(player) + DeployAndEnableWeapons( player ) RemoveCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) } }) -- cgit v1.2.3 From dc0074d24923ec2e9cc3e4b9129c53730f338dd7 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:12:30 +0200 Subject: Play battle chatter during dropship intro (#810) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 8b75a982..22dc1e67 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -217,6 +217,11 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e jumpSequence.setInitialTime = max( 0.0, Time() - ( file.introStartTime + 11.0 ) ) // pretty sure you should do this with GetScriptedAnimEventCycleFrac? // idk unsure how to use that, all i know is getsequenceduration > the length it actually should be + #if BATTLECHATTER_ENABLED + if( playerDropshipIndex == 0 ) + PlayBattleChatterLine( player, "bc_pIntroChat" ) + #endif + waitthread FirstPersonSequence( jumpSequence, player, playerDropship ) thread PlayerJumpsFromDropship( player ) -- cgit v1.2.3 From 34bd1b1ae6b9b232ce85e2ff3b7192c141a31853 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:15:39 +0200 Subject: Mitigate muted audio during dropship intro (#811) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 22dc1e67..3d8abd9d 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -189,6 +189,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() + UnMuteAll( player ) // hide hud and fade screen out from black AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) -- cgit v1.2.3 From 1c54129e11b496f049764d0bc7feed53a6341a57 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Sun, 7 Jul 2024 00:19:21 +0200 Subject: Mitigate muted audio during dropship intro (#812) Co-authored-by: Zanieon --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 3d8abd9d..5ab14121 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -190,6 +190,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e HolsterAndDisableWeapons( player ) player.DisableWeaponViewModel() UnMuteAll( player ) + StopSoundOnEntity( player, "Duck_For_FrontierDefenseTitanSelectScreen" ) // hide hud and fade screen out from black AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) -- cgit v1.2.3 From e898b0a17d817bf36189ed9c5499ded4cefdbb26 Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:49:01 -0300 Subject: Prevent suicides registering progression stats (#813) Prevent suicides registering stats --- Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 101d5e4e..674923e7 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -334,6 +334,10 @@ void function OnPlayerOrNPCKilled( entity victim, entity attacker, var damageInf thread SetLastPosForDistanceStatValid_Threaded( victim, false ) HandleDeathStats( victim, attacker, damageInfo ) + + if( victim == attacker ) //Suicides are registering stats, afaik vanilla ignores them + return + HandleKillStats( victim, attacker, damageInfo ) HandleWeaponKillStats( victim, attacker, damageInfo ) HandleTitanStats( victim, attacker, damageInfo ) -- cgit v1.2.3 From de01dc34c66a57eb77b68e1403f5503e84802df8 Mon Sep 17 00:00:00 2001 From: William Miller Date: Sat, 6 Jul 2024 19:53:51 -0300 Subject: Fix oversight in "Total MVP" not registering in regards to progression (#814) The game have an extra stat especifically to count the total amount of times a player has been MVP in all matches, while the other mvp stat which i previously thought to be absolutely is only registered per map, not globally. --- Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut | 1 + 1 file changed, 1 insertion(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut index 5eba24ac..f7c398d9 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_gamestate_mp.nut @@ -861,6 +861,7 @@ void function SetWinner( int team, string winningReason = "", string losingReaso { case 1: UpdatePlayerStat( players[i], "game_stats", "mvp" ) + UpdatePlayerStat( players[i], "game_stats", "mvp_total" ) UpdatePlayerStat( players[i], "game_stats", "top3OnTeam" ) break case 2: -- cgit v1.2.3 From bfadbc4d598d595aef02034c1b63e614b164567e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Mon, 8 Jul 2024 09:20:55 +0200 Subject: Translations update from Weblate (#815) * Translated using Weblate (English) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/en/ * Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ * Translated using Weblate (Russian) Currently translated at 95.1% (296 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ * Translated using Weblate (English) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/en/ --------- Co-authored-by: William Miller Co-authored-by: WofWca Co-authored-by: GeckoEidechse --- .../northstar_client_localisation_english.txt | 2 +- .../northstar_client_localisation_portuguese.txt | 2 +- .../northstar_client_localisation_russian.txt | 22 +++++++++++++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index e6518feb..eaec0cc7 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -320,7 +320,7 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "UNAUTHORIZED_PWD" "Wrong password" "STRYDER_RESPONSE" "Couldn't parse stryder response" "PLAYER_NOT_FOUND" "Couldn't find player account" - "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token" + "INVALID_MASTERSERVER_TOKEN" "Invalid or expired masterserver token, try restarting EA App." "JSON_PARSE_ERROR" "Error parsing json response" "UNSUPPORTED_VERSION" "The version you are using is no longer supported" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 5570b047..457779eb 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -326,7 +326,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" "UNAUTHORIZED_PWD" "Senha inválida" "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" - "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido" + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, por favor reinicie o EA App para atualizar o Token." "JSON_PARSE_ERROR" "Erro ao ler a resposta json" "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index cf410ff2..56402ca9 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -250,7 +250,7 @@ "UNAUTHORIZED_PWD" "Неправильный пароль" "STRYDER_RESPONSE" "Не удалось разобрать ответ Stryder" "PLAYER_NOT_FOUND" "Не удалось найти аккаунт игрока" - "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера" + "INVALID_MASTERSERVER_TOKEN" "Некорректный или истёкший токен главного сервера. Перезапустите EA App, чтобы обновить токен." "JSON_PARSE_ERROR" "Ошибка разбора json-ответа" "UNSUPPORTED_VERSION" "Используемая вами версия больше не поддерживается" "DISABLE" "Выключить" @@ -345,5 +345,25 @@ "AUTHENTICATION_FAILED_ERROR_CODE" "Код ошибки: ^DB6F2C00%s1^" "AUTHENTICATION_FAILED_HELP" "Справка" "AUTHENTICATION_FAILED_HEADER" "Ошибка аутентификации" + "MISSING_MOD" "Отсутствует мод \"%s1\" v%s2" + "MOD_NOT_VERIFIED" "(мод не был загружен автоматически, т.к. он не проверенный)" + "MOD_DL_DISABLED" "(автоматическая загрузка модов не включена)" + "DOWNLOADING_MOD_TITLE" "Загрузка мода" + "DOWNLOADING_MOD_TEXT" "Загружаем %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "Загружаем %s1 v%s2...\n(%s3/%s4 МБ)" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Загрузка мода (%s1%)" + "CHECKSUMING_TITLE" "Проверка целостности" + "MOD_REQUIRED_WARNING" " : Этот мод может автоматически включиться / отключиться при подключении к серверу" + "WRONG_MOD_VERSION" "Версии мода \"%s1\" не совпадают. На сервере: v%s2. У вас: v%s3" + "CHECKSUMING_TEXT" "Проверяем целостность %s1 v%s2..." + "EXTRACTING_MOD_TITLE" "Распаковка мода (%s1%)" + "EXTRACTING_MOD_TEXT" "Распаковываем %s1 v%s2...\n(%s3/%s4 МБ)" + "FAILED_DOWNLOADING" "Ошибка загрузки мода" + "FAILED_READING_ARCHIVE" "Ошибка чтения архива мода." + "FAILED_WRITING_TO_DISK" "Ошибка распаковки файлов мода." + "MOD_FETCHING_FAILED" "Ошибка скачивания мода с Thunderstore." + "MOD_CORRUPTED" "Файл архива мода повреждён: контрольная сумма не совпадает." + "NO_DISK_SPACE_AVAILABLE" "Недостаточно места на диске." + "MOD_FETCHING_FAILED_GENERAL" "Ошибка распаковки мода. Проверьте файл лога, чтобы узнать подробности." } } -- cgit v1.2.3 From e76789be99d43242bb06e148c1e32485217ce79a Mon Sep 17 00:00:00 2001 From: William Miller Date: Mon, 8 Jul 2024 05:52:50 -0300 Subject: Hotfix for Intro Dropship (#816) to fix script error --- .../mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut index 5ab14121..c3bdf01c 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_classic_mp_dropship_intro.gnut @@ -196,7 +196,7 @@ void function SpawnPlayerIntoDropship( entity player, int playerDropshipIndex, e AddCinematicFlag( player, CE_FLAG_CLASSIC_MP_SPAWNING ) ScreenFadeFromBlack( player, 0.5, 0.5 ) // faction leaders are done clientside, spawn them here - Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.dropship.GetEncodedEHandle(), file.introStartTime ) + Remote_CallFunction_NonReplay( player, "ServerCallback_SpawnFactionCommanderInDropship", playerDropship.GetEncodedEHandle(), file.introStartTime ) // do firstperson sequence FirstPersonSequenceStruct idleSequence -- cgit v1.2.3 From 52e007ac0634ee5dd9376bd82ae76af6fd5f44d7 Mon Sep 17 00:00:00 2001 From: fvnkhead <98965760+fvnkhead@users.noreply.github.com> Date: Thu, 11 Jul 2024 20:31:29 +0300 Subject: Check player validity in `SetupChallenges_Threaded` (#819) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index 4b866a40..ffefc3b4 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -66,6 +66,9 @@ void function SetupPlayerMenuChallenges( entity player ) void function SetupChallenges_Threaded( entity player ) { WaitFrame() + + if ( !IsValid( player ) ) + return Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it -- cgit v1.2.3 From f586107e62dc0dfa09f1b08cbf418d31d0346886 Mon Sep 17 00:00:00 2001 From: William Miller Date: Fri, 12 Jul 2024 17:45:49 -0300 Subject: Change `IsValid()` check to `EndSignal()` (#820) --- Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut index ffefc3b4..016097f2 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_challenges.gnut @@ -65,10 +65,9 @@ void function SetupPlayerMenuChallenges( entity player ) void function SetupChallenges_Threaded( entity player ) { + player.EndSignal( "OnDestroy" ) + WaitFrame() - - if ( !IsValid( player ) ) - return Remote_CallFunction_UI( player, "SCB_SetCompleteMeritState", 0 ) Remote_CallFunction_UI( player, "SCB_SetEvacMeritState", 4 ) //4 tells RUI to hide it -- cgit v1.2.3 From 26d649fa7bf53e83758dd824297f402c8b9d174e Mon Sep 17 00:00:00 2001 From: William Miller Date: Wed, 17 Jul 2024 06:10:06 -0300 Subject: Fix "Kills by Auto-Titan" not registering at all (#817) This is a quick fix that will redirect the attacker entity to a proper NPC owned by the player. By default behavior of the game, attackers are always the final entity in the owning hiearchy, which is always a player if owned NPCs kills enemies. This change properly redirects the code to the correct NPC whenever they have an owning player. --- .../mod/scripts/vscripts/mp/_stats.nut | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut index 674923e7..74a9088b 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut +++ b/Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut @@ -493,23 +493,32 @@ void function HandleKillStats( entity victim, entity attacker, var damageInfo ) // get the player and it's pet titan entity player entity playerPetTitan - if ( attacker.IsPlayer() ) + entity inflictor = DamageInfo_GetInflictor( damageInfo ) + + if ( IsValid( inflictor ) ) { - // the player is just the attacker - player = attacker - playerPetTitan = player.GetPetTitan() + if ( inflictor.IsProjectile() && IsValid( inflictor.GetOwner() ) ) // Attackers are always the final entity in the owning hierarchy, projectile owners though migh be a player's NPC minion (i.e Auto-Titans) + attacker = inflictor.GetOwner() + + else if ( inflictor.IsNPC() ) // NPCs are bypassed as Attackers if they are owned by players, instead they become just inflictors + attacker = inflictor } - else if ( attacker.IsTitan() && IsPetTitan( attacker ) ) + + if ( attacker.IsNPC() ) { - // the attacker is the player's auto titan + if ( !attacker.IsTitan() ) // Normal NPCs case + return + + if ( !IsPetTitan( attacker ) ) // NPC Titans case + return + player = attacker.GetTitanSoul().GetBossPlayer() playerPetTitan = attacker } + else if ( attacker.IsPlayer() ) // Still checks this because worldspawn might be the attacker + player = attacker else - { - // attacker could be something like an NPC, or worldspawn return - } // check things once, for performance int damageSource = DamageInfo_GetDamageSourceIdentifier( damageInfo ) -- cgit v1.2.3 From 278eaf2bf5de61cf705974317909a1f521bf0948 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Fri, 19 Jul 2024 19:36:50 +0200 Subject: Translations update from Weblate (#822) Translated using Weblate (Portuguese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../mod/resource/northstar_client_localisation_portuguese.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index 457779eb..b6f5ba26 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -326,7 +326,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "UNAUTHORIZED_GAMESERVER" "Servidor da partida não está autorizado a fazer tal requisição" "UNAUTHORIZED_PWD" "Senha inválida" "PLAYER_NOT_FOUND" "Não foi possível encontrar conta do jogador" - "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, por favor reinicie o EA App para atualizar o Token." + "INVALID_MASTERSERVER_TOKEN" "Token do servidor mestre inválido ou vencido, tente reiniciar o EA App." "JSON_PARSE_ERROR" "Erro ao ler a resposta json" "SHOW_ONLY_REQUIRED" "Somente Mods Mandatórios" "UNAUTHORIZED_GAME" "Stryder não pode confirmar que esta conta possui Titanfall 2" -- cgit v1.2.3 From 0e8990f1d2272587e19df0de367e9a839b9ebc97 Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Sat, 27 Jul 2024 20:58:00 +0200 Subject: Translations update from Weblate (#823) * Translated using Weblate (Japanese) Currently translated at 96.1% (299 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ja/ * Translated using Weblate (Japanese) Currently translated at 100.0% (311 of 311 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ja/ --------- Co-authored-by: IROHASTUDIO --- .../northstar_client_localisation_japanese.txt | 73 +++++++++++++++++++--- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt index b7fadeaf..798d603e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_japanese.txt @@ -233,8 +233,8 @@ "GAMEMODE_fastball" "ファストボール" "PL_fastball" "ファストボール" "PL_fastball_lobby" "ファストボール ロビー" - "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる" - "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる" + "PL_fastball_desc" "ライブファイア。パネルをハックし、味方を蘇生できる。" + "PL_fastball_hint" "ライブファイア。パネルをハックし、味方を蘇生できる。" "PL_fastball_abbr" "FB" "FASTBALL_PANEL_CAPTURED" "%s1 がパネル%s2を制圧した" "SCOREBOARD_FASTBALL_HACKS" "制圧パネル" @@ -265,10 +265,10 @@ "player_bleedout_aiBleedingPlayerMissChance" "ダウン時のAI命中率" // coop stuff - "PL_sp_coop" "(UNFINISHED) Singleplayer Coop" - "PL_sp_coop_lobby" "Singleplayer Coop Lobby" - "PL_sp_coop_desc" "Play through the singleplayer campaign with friends" - "PL_sp_coop_hint" "Play through the singleplayer campaign with friends" + "PL_sp_coop" "(未完成) シングルプレイヤー 協力モード" + "PL_sp_coop_lobby" "シングルプレイヤー 協力モード ロビー" + "PL_sp_coop_desc" "シングルプレイヤーのキャンペーンモードをフレンドと一緒にプレイできる" + "PL_sp_coop_hint" "シングルプレイヤーのキャンペーンモードをフレンドと一緒にプレイできる" "PL_sp_coop_abbr" "SP" "SP_TRAINING" "パイロット・ガントレット" @@ -340,13 +340,70 @@ "NO_GAMESERVER_RESPONSE" "ゲームサーバーに接続できません\n(Couldn't reach game server)" "BAD_GAMESERVER_RESPONSE" "ゲームサーバーが不明なレスポンスを返しました\n(Game server gave an invalid response)" "UNAUTHORIZED_GAMESERVER" "ゲームサーバーにそのリクエストを作成する許可がありません\n(Game server is not authorized to make that request)" - "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\nStryder couldn't confirm that this account owns Titanfall 2" + "UNAUTHORIZED_GAME" "StryderはこのアカウントがTitanfall 2を所持しているかどうかを確認できませんでした\n(Stryder couldn't confirm that this account owns Titanfall 2)" "UNAUTHORIZED_PWD" "パスワードが間違っています\n(Wrong password)" "STRYDER_RESPONSE" "Stryderからのレスポンスの処理に失敗しました\n(Couldn't parse stryder response)" "PLAYER_NOT_FOUND" "プレイヤーのアカウントが見つかりません\n(Couldn't find player account)" - "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです\n(Invalid or expired masterserver token)" + "INVALID_MASTERSERVER_TOKEN" "マスターサーバーのトークンが不明か期限切れです。EAアプリの再起動をお試しください。\n(Invalid or expired masterserver token, try restarting EA App.)" "JSON_PARSE_ERROR" "JSONレスポンスの処理に失敗しました\n(Error parsing json response)" "UNSUPPORTED_VERSION" "現在使用しているバージョンはサポートされていません\n(The version you are using is no longer supported)" + "player_force_respawn" "強制リスポーン" + "SHOW_ONLY_REQUIRED" "必須のModのみ" + "Y_BUTTON_TOGGLE_PROGRESSION" "%[Y_BUTTON|]% 進行システム切り替え" + "TOGGLE_PROGRESSION" "進行システム切り替え" + "AUTHENTICATION_FAILED_HEADER" "認証に失敗" + "DOWNLOADING_MOD_TITLE" "Modをダウンロード中" + "PROGRESSION_TOGGLE_ENABLED_BODY" "タイタン、武器、勢力、スキンなどが全てアンロックされ、いつでも使えるようになる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "PROGRESSION_TOGGLE_DISABLED_HEADER" "進行システムを有効にしますか?" + "PROGRESSION_TOGGLE_ENABLED_HEADER" "進行システムを無効にしますか?" + "PROGRESSION_DISABLED_HEADER" "進行システムが無効になりました!" + "PROGRESSION_ENABLED_HEADER" "進行システムが有効になりました!" + "PROGRESSION_DISABLED_BODY" "^CCCC0000進行システムが無効化された。^\n\nタイタン、武器、勢力、スキンなどが全てアンロックされ、いつでも使えるようになる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "SHOULD_RETURN_TO_LOBBY" "マッチ終了後にロビーへ戻る" + "REPLACEMENT_WEAPON" "武器の置き換え" + "TACTICAL_REPLACEMENT" "戦術の置き換え" + "DISALLOWED_TACTICALS" "戦術の禁止" + "DISALLOWED_WEAPONS" "武器の禁止" + "ONLY_HOST_CAN_START_MATCH" "マッチを開始できるのはホストのみ" + "ONLY_HOST_MATCH_SETTINGS" "プライベートマッチの設定を変更できるのはホストのみ" + "AUTHENTICATION_FAILED_HELP" "ヘルプ" + "MATCH_COUNTDOWN_LENGTH" "プライベートマッチのカウントダウン時間" + "ARE_YOU_SURE" "よろしいですか?" + "MOD_SETTINGS_SERVER" "サーバー" + "MOD_SETTINGS_RESET" "リセット" + "MOD_SETTINGS_RESET_ALL" "全てリセット" + "NO_RESULTS" "リザルトなし。" + "MOD_SETTINGS" "Modの設定" + "NORTHSTAR_BASE_SETTINGS" "Northstarの基本設定" + "NO_DISK_SPACE_AVAILABLE" "ディスクに十分な領域がありません。" + "FAILED_DOWNLOADING" "Modのダウンロードに失敗" + "FAILED_READING_ARCHIVE" "Modアーカイブの読込中にエラーが発生しました。" + "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Modをダウンロード中 (%s1%)" + "DOWNLOADING_MOD_TEXT" "ダウンロード中 %s1 v%s2..." + "DOWNLOADING_MOD_TEXT_W_PROGRESS" "ダウンロード中 %s1 v%s2...\n(%s3/%s4 MB)" + "MOD_FETCHING_FAILED" "ThunderstoreからModアーカイブをダウンロードできませんでした。" + "EXTRACTING_MOD_TITLE" "Modを抽出中 (%s1%)" + "EXTRACTING_MOD_TEXT" "抽出中 %s1 v%s2...\n(%s3/%s4 MB)" + "FAILED_WRITING_TO_DISK" "Modファイルをファイルシステムに抽出する際にエラーが発生しました。" + "MOD_FETCHING_FAILED_GENERAL" "Modの抽出に失敗。詳細はログを確認してください。" + "MOD_CORRUPTED" "ダウンロードしたアーカイブのチェックサムが検証済み署名と一致しませんでした。" + "CHECKSUMING_TITLE" "Modをチェックサム中" + "CHECKSUMING_TEXT" "コンテンツを検証中 %s1 v%s2..." + "MOD_DL_DISABLED" "(自動Modダウンロードは無効です)" + "PROGRESSION_TOGGLE_DISABLED_BODY" "タイタン、武器、勢力、スキンなどのアンロックにレベル上げやメリットが必要になる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。\n\n^CC000000警告: 現在装備しているアイテムがロック中の場合、装備状況は初期化されます!" + "PROGRESSION_ENABLED_BODY" "^CCCC0000進行システムが有効化された。^\n\nタイタン、武器、勢力、スキンなどのアンロックにレベル上げやメリットが必要になる。\n\nこの設定は、マルチプレイヤーロビーでいつでも変更可能だ。" + "LOG_UNKNOWN_CLIENTCOMMANDS" "不明なクライアントコマンドを記録する" + "SHOW_ONLY_NOT_REQUIRED" "任意のModのみ" + "AUTHENTICATION_FAILED_ERROR_CODE" "エラーコード: ^DB6F2C00%s1^" + "AUTHENTICATION_FAILED_BODY" "Atlasの認証に失敗しました!\n(Failed to authenticate with Atlas!)" + "MISSING_MOD" "Mod消失 \"%s1\" v%s2" + "MOD_REQUIRED_WARNING" " :このModはサーバーに参加した際に読み込まる(または読み込まれない)ことがあります" + "WILL_RESET_ALL_SETTINGS" "カテゴリー内の全設定をリセットしようとしています。\n\nこの操作は取り消せません。" + "WILL_RESET_SETTING" "%s1 の設定を初期値に戻そうとしています。\n\nこの操作は取り消せません。" + "NO_MODS" "設定が利用できません!Modのインストールはこちらから: ^5588FF00northstar.thunderstore.io^0" + "PROGRESSION_ANNOUNCEMENT_BODY" "^CCCC0000進行システムが開放されました!^\n\nNorthstarはバニラの進行システム、つまり武器、スキン、タイタン等をレベルアップやチャレンジ達成で解除する機能をサポートしています。\n\nこの進行システムは、ロビー画面下のボタンから有効にできます。\n\nこの設定はいつでも変更可能です。" + "MOD_NOT_VERIFIED" "(Modが検証されていないため、自動ダウンロードできませんでした)" + "WRONG_MOD_VERSION" "サーバーはMod\"%s1\"v%s2 を要求していますが、あなたのModバージョンは%s3です" // Translation done by Zetryox and CYakigasi } -- cgit v1.2.3 From 7abae6cf8326a768729cc314805606b6a0344f33 Mon Sep 17 00:00:00 2001 From: EladNLG Date: Sun, 28 Jul 2024 09:35:46 +0300 Subject: Move fontfiletable.txt to keyvalues (#612) This is done so mods using keyvalues folders to add custom fonts to the game don't revert the changes done by Northstar --- .../keyvalues/resource/fontfiletable.txt | 10 ++++++ Northstar.Client/mod/resource/fontfiletable.txt | 40 ---------------------- 2 files changed, 10 insertions(+), 40 deletions(-) create mode 100644 Northstar.Client/keyvalues/resource/fontfiletable.txt delete mode 100644 Northstar.Client/mod/resource/fontfiletable.txt diff --git a/Northstar.Client/keyvalues/resource/fontfiletable.txt b/Northstar.Client/keyvalues/resource/fontfiletable.txt new file mode 100644 index 00000000..f0b91c07 --- /dev/null +++ b/Northstar.Client/keyvalues/resource/fontfiletable.txt @@ -0,0 +1,10 @@ +FontFileTable +{ + "arial unicode ms" "resource/Lato-Regular.ttf" + + "lucida console" "resource/NorthstarMono.ttf" [$PC] + + "arial" "resource/Lato-Regular.ttf" + "arial bold" "resource/Lato-Regular.ttf" + "arial narrow" "resource/Lato-Regular.ttf" +} diff --git a/Northstar.Client/mod/resource/fontfiletable.txt b/Northstar.Client/mod/resource/fontfiletable.txt deleted file mode 100644 index b4238134..00000000 --- a/Northstar.Client/mod/resource/fontfiletable.txt +++ /dev/null @@ -1,40 +0,0 @@ -FontFileTable -{ - "Default" "resource/MetronicPro-Regular.vfont" [!$JAPANESE && !$TCHINESE] - "Default" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "Default" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - - "DefaultBold" "resource/MetronicPro-SemiBold.vfont" [!$JAPANESE && !$TCHINESE] - "DefaultBold" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "DefaultBold" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - - "Titanfall" "resource/Titanfall-Regular.vfont" [!$JAPANESE && !$TCHINESE && !$RUSSIAN] - "Titanfall" "resource/NotoSansJP-Regular.vfont" [$JAPANESE] - "Titanfall" "resource/NotoSansTC-Regular.vfont" [$TCHINESE] - "Titanfall" "resource/MetronicPro-SemiBold.vfont" [$RUSSIAN] - - "marlett" "vgui/fonts/marlett.ttf" - - // Everything below is DONOTSHIP / Dev only - - "arial unicode ms" "resource/Lato-Regular.ttf" - - "lucida console" "resource/NorthstarMono.ttf" [$PC] - "lucida console" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] - - "tahoma" "fonts\\tahoma.ttf" [$PC] - "tahoma" "resource/MetronicPro-Regular.vfont" [$GAMECONSOLE] - - "tahoma bold" "fonts\\tahomabd.ttf" [$PC] - "tahoma bold" "resource/MetronicPro-SemiBold.vfont" [$GAMECONSOLE] - - "courier new" "fonts\\cour.ttf" [$PC] - "courier new" "vgui/fonts/cour.ttf" [$GAMECONSOLE] - - "times new roman" "fonts\\times.ttf" [$PC] - "times new roman" "vgui/fonts/times.ttf" [$GAMECONSOLE] - - "arial" "resource/Lato-Regular.ttf" - "arial bold" "resource/Lato-Regular.ttf" - "arial narrow" "resource/Lato-Regular.ttf" -} -- cgit v1.2.3 From d5b35ee69a1ad7f9c6515ed70474babfb33519f7 Mon Sep 17 00:00:00 2001 From: Rémy Raes Date: Tue, 30 Jul 2024 00:41:10 +0200 Subject: Only fetch MAD manifesto on server join (#821) Previously, the verified mods manifesto was fetched on game start without checking if the verified mod feature is enabled Squirrel-side; with this, the manifesto is only fetched when the user wants to download a mod (meaning they enabled the feature beforehand). --- .github/nativefuncs.json | 7 ++ .../northstar_client_localisation_english.txt | 2 + .../scripts/vscripts/ui/menu_ns_moddownload.nut | 37 ++++++++- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 96 ++++++++++++++++------ 4 files changed, 115 insertions(+), 27 deletions(-) diff --git a/.github/nativefuncs.json b/.github/nativefuncs.json index 1148d3e5..889432d7 100644 --- a/.github/nativefuncs.json +++ b/.github/nativefuncs.json @@ -502,6 +502,13 @@ "returnTypeString":"array", "argTypes":"string modName" }, + { + "name": "NSFetchVerifiedModsManifesto", + "helpText": "Retrieves the verified mods list from the central authority (GitHub).", + "returnTypeString": "void", + "argTypes": "" + + }, { "name": "NSIsModDownloadable", "helpText": "checks whether a mod is verified and can be auto-downloaded", diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt index eaec0cc7..baceed22 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_english.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_english.txt @@ -373,6 +373,8 @@ Press Yes if you agree to this. This choice can be changed in the mods menu at a "WRONG_MOD_VERSION" "Server has mod \"%s1\" v%s2 while you have v%s3" "MOD_NOT_VERIFIED" "(mod is not verified, and couldn't be downloaded automatically)" "MOD_DL_DISABLED" "(automatic mod downloading is disabled)" + "MANIFESTO_FETCHING_TITLE" "Setting up mod download" + "MANIFESTO_FETCHING_TEXT" "Retrieving the list of verified mods..." "DOWNLOADING_MOD_TITLE" "Downloading mod" "DOWNLOADING_MOD_TITLE_W_PROGRESS" "Downloading mod (%s1%)" "DOWNLOADING_MOD_TEXT" "Downloading %s1 v%s2..." diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut index 4d299362..3b81c7f9 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -1,8 +1,10 @@ global function DownloadMod global function DisplayModDownloadErrorDialog +global function FetchVerifiedModsManifesto global enum eModInstallStatus { + MANIFESTO_FETCHING, DOWNLOADING, CHECKSUMING, EXTRACTING, @@ -18,7 +20,36 @@ global enum eModInstallStatus const int MB = 1024*1000; -bool function DownloadMod( RequiredModInfo mod ) + +void function FetchVerifiedModsManifesto() +{ + print("Start fetching verified mods manifesto from the Internet") + + // Fetching UI + DialogData dialogData + dialogData.header = Localize( "#MANIFESTO_FETCHING_TITLE" ) + dialogData.message = Localize( "#MANIFESTO_FETCHING_TEXT" ) + dialogData.showSpinner = true; + + // Prevent user from closing dialog + dialogData.forceChoice = true; + OpenDialog( dialogData ) + + // Do the actual fetching + NSFetchVerifiedModsManifesto() + + ModInstallState state = NSGetModInstallState() + while ( state.status == eModInstallStatus.MANIFESTO_FETCHING ) + { + state = NSGetModInstallState() + WaitFrame() + } + + // Close dialog when manifesto has been received + CloseActiveMenu() +} + +bool function DownloadMod( RequiredModInfo mod, string serverName ) { // Downloading mod UI DialogData dialogData @@ -58,6 +89,10 @@ void function UpdateModDownloadDialog( RequiredModInfo mod, ModInstallState stat { switch ( state.status ) { + case eModInstallStatus.MANIFESTO_FETCHING: + Hud_SetText( header, Localize( "#MANIFESTO_FETCHING_TITLE" ) ) + Hud_SetText( body, Localize( "#MANIFESTO_FETCHING_TEXT" ) ) + break case eModInstallStatus.DOWNLOADING: Hud_SetText( header, Localize( "#DOWNLOADING_MOD_TITLE_W_PROGRESS", string( state.ratio ) ) ) Hud_SetText( body, Localize( "#DOWNLOADING_MOD_TEXT_W_PROGRESS", mod.name, mod.version, floor( state.progress / MB ), floor( state.total / MB ) ) ) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 4f17dedf..22cdffcf 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -967,49 +967,93 @@ void function OnServerSelected_Threaded( var button ) bool autoDownloadAllowed = GetConVarBool( "allow_mod_auto_download" ) int downloadedMods = 0; + // Check out if there's any server-required mod that is not locally installed + array modNames = NSGetModNames() + bool uninstalledModFound = false + foreach ( requiredModInfo in server.requiredMods ) + { + // Tolerate core mods having different versions + if ( requiredModInfo.name.len() > 10 && requiredModInfo.name.slice(0, 10) == "Northstar." ) + continue + + if ( !modNames.contains( requiredModInfo.name ) ) + { + print( format ( "\"%s\" was not found locally, triggering manifesto fetching.", requiredModInfo.name ) ) + uninstalledModFound = true + break + } else if ( NSGetModVersionByModName( requiredModInfo.name ) != requiredModInfo.version ) { + print( format ( "\"%s\" was found locally but has version \"%s\" while server requires \"%s\", triggering manifesto fetching.", requiredModInfo.name, NSGetModVersionByModName( requiredModInfo.name ), requiredModInfo.version ) ) + uninstalledModFound = true + break + } + } + + // If yes, we fetch the verified mods manifesto, to check whether uninstalled + // mods can be installed through auto-download + if ( uninstalledModFound && autoDownloadAllowed ) + { + print("Auto-download is allowed, checking if missing mods can be installed automatically.") + FetchVerifiedModsManifesto() + } + foreach ( RequiredModInfo mod in server.requiredMods ) { - if ( !NSGetModNames().contains( mod.name ) ) + // Tolerate core mods having different versions + if ( mod.name.len() > 10 && mod.name.slice(0, 10) == "Northstar." ) + continue + + if ( !NSGetModNames().contains( mod.name ) || NSGetModVersionByModName( mod.name ) != mod.version ) { - // Check if mod can be auto-downloaded - bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + // Auto-download mod + if ( autoDownloadAllowed ) + { + bool modIsVerified = NSIsModDownloadable( mod.name, mod.version ) + + // Display error message if mod is not verified + if ( !modIsVerified ) + { + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) + dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) + dialogData.image = $"ui/menu/common/dialog_error" - // Display an error message if not - if ( !modIsVerified || !autoDownloadAllowed ) + AddDialogButton( dialogData, "#DISMISS" ) + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) + return + } + else + { + if ( DownloadMod( mod, server.name ) ) + { + downloadedMods++ + } + else + { + DisplayModDownloadErrorDialog( mod.name ) + return + } + } + } + + // Mod not found, display error message + else { DialogData dialogData dialogData.header = "#ERROR" dialogData.message = Localize( "#MISSING_MOD", mod.name, mod.version ) dialogData.image = $"ui/menu/common/dialog_error" - // Specify error (only if autoDownloadAllowed is set) - if ( autoDownloadAllowed ) - { - dialogData.message += "\n" + Localize( "#MOD_NOT_VERIFIED" ) - } - AddDialogButton( dialogData, "#DISMISS" ) - AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) OpenDialog( dialogData ) - return } - - else // Launch download - { - if ( DownloadMod( mod ) ) - { - downloadedMods++ - } - else - { - DisplayModDownloadErrorDialog( mod.name ) - return - } - } } else { -- cgit v1.2.3 From e4b3cc7d3ee17488053cae24c8a8c981dbe95eab Mon Sep 17 00:00:00 2001 From: Klemmbaustein <83748124+Klemmbaustein@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:45:17 +0200 Subject: Add a generic "JoinServer" function (#693) Adds a function that allows the client to join a server from a `ServerInfo` struct. This also changes the server browser to use this function. --- .../vscripts/ui/menu_ns_connect_password.nut | 9 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 148 +++++++++++++++++++-- 2 files changed, 147 insertions(+), 10 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index b89e665b..acc6bb36 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -1,4 +1,5 @@ global function AddNorthstarConnectWithPasswordMenu +global function SetPasswordTargetServer struct { @@ -6,6 +7,7 @@ struct var enterPasswordBox var enterPasswordDummy var connectButton + ServerInfo& targetServer } file void function AddNorthstarConnectWithPasswordMenu() @@ -51,11 +53,16 @@ void function OnConnectWithPasswordMenuOpened() } +void function SetPasswordTargetServer( ServerInfo server ) +{ + file.targetServer = server +} + void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) + thread JoinServer( file.targetServer, Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 22cdffcf..5517843e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -2,7 +2,10 @@ untyped // Only way to get Hud_GetPos(sliderButton) working was to use untyped global function AddNorthstarServerBrowserMenu -global function ThreadedAuthAndConnectToServer + +global function JoinServer +global function JoinServerByName +global function CancelJoinServer global function AddConnectToServerCallback global function RemoveConnectToServerCallback @@ -370,7 +373,7 @@ void function ToggleConnectingHUD( bool vis ) void function ConnectingButton_Activate( var button ) { - file.cancelConnection = true + CancelJoinServer() } //////////////////////////// @@ -1097,17 +1100,18 @@ void function OnServerSelected_Threaded( var button ) if ( server.requiresPassword ) { OnCloseServerBrowserMenu() + SetPasswordTargetServer( file.lastSelectedServer ) AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) + thread ThreadedAuthAndConnectToServer() } } -void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) +void function ThreadedAuthAndConnectToServer( string password = "" ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1135,6 +1139,8 @@ void function ThreadedAuthAndConnectToServer( string password = "", bool modsCha if ( NSWasAuthSuccessful() ) { + bool modsChanged = false + // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { @@ -1350,14 +1356,138 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { - ServerInfo server; - if (targetServer == null) - { + if ( !targetServer ) targetServer = file.lastSelectedServer - } + + expect ServerInfo( targetServer ) foreach( callback in file.connectCallbacks ) { - callback( expect ServerInfo( targetServer ) ) + callback( targetServer ) + } +} + +////////////////////////////////////// +// Join server +////////////////////////////////////// + +void function CancelJoinServer() +{ + file.cancelConnection = true +} + +bool function JoinServerByName( string serverName, string password = "" ) +{ + // Request list of online servers. + NSRequestServerList() + while ( NSIsRequestingServerList() ) + { + WaitFrame() + } + + // Go through all servers that are currently online + foreach ( server in NSGetGameServers() ) + { + // Join the server if it has the correct server name. + if ( server.name == serverName ) + { + return JoinServer( server ) + } } + + print( format( "Failed to connect to server %s: No such server", serverName ) ) + + return false +} + +bool function JoinServer( ServerInfo server, string password = "" ) +{ + if ( NSIsAuthenticatingWithServer() ) + return false + + printt( format( "Connecting to server %s with id of %s", server.name, server.id ) ) + + TriggerConnectToServerCallbacks( server ) + NSTryAuthWithServer( server.index, password ) + + ToggleConnectingHUD( true ) + + while ( NSIsAuthenticatingWithServer() && !file.cancelConnection ) + WaitFrame() + + ToggleConnectingHUD( false ) + + if ( file.cancelConnection ) + { + file.cancelConnection = false + return false + } + + file.cancelConnection = false + + if ( NSWasAuthSuccessful() ) + { + bool modsChanged = false + + // disable all RequiredOnClient mods that are not required by the server and are currently enabled + foreach ( string modName in NSGetModNames() ) + { + if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) + { + // find the mod name in the list of server required mods + bool found = false + foreach ( RequiredModInfo mod in server.requiredMods ) + { + if ( mod.name == modName ) + { + found = true + break + } + } + // if we didnt find the mod name, disable the mod + if ( !found ) + { + modsChanged = true + NSSetModEnabled( modName, false ) + } + } + } + + // enable all RequiredOnClient mods that are required by the server and are currently disabled + foreach ( RequiredModInfo mod in server.requiredMods ) + { + if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name ) ) + { + modsChanged = true + NSSetModEnabled( mod.name, true ) + } + } + + // only actually reload if we need to since the uiscript reset on reload lags hard + if ( modsChanged ) + ReloadMods() + + NSConnectToAuthedServer() + return true + } + else + { + string reason = NSGetAuthFailReason() + + DialogData dialogData + dialogData.header = "#ERROR" + dialogData.message = reason + dialogData.image = $"ui/menu/common/dialog_error" + + #if PC_PROG + AddDialogButton( dialogData, "#DISMISS" ) + + AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) + #endif // PC_PROG + AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) + + OpenDialog( dialogData ) + return false + } + return false } -- cgit v1.2.3 From d130ab7d957693b0c83b9acd130bcec02928e7a2 Mon Sep 17 00:00:00 2001 From: Creamy <88903493+CozyMerc@users.noreply.github.com> Date: Tue, 30 Jul 2024 00:46:27 +0200 Subject: Update tbshotgun mdls with skinfamillies/lods, add pbr materials (#796) See pull request description for highly detailed changelog. --- .../ptpov_shotgun_doublebarrel.mdl | Bin 1268987 -> 1277105 bytes .../w_shotgun_doublebarrel.mdl | Bin 743828 -> 924194 bytes .../paks/mp_weapon_shotgun_doublebarrel.rpak | Bin 264566 -> 197556 bytes .../paks/mp_weapon_shotgun_doublebarrel.starpak | Bin 16539736 -> 9605416 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl index 2fcc3439..82b58bec 100644 Binary files a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/ptpov_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl index 137d985d..9e660374 100644 Binary files a/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl and b/Northstar.Custom/mod/models/weapons/shotgun_doublebarrel/w_shotgun_doublebarrel.mdl differ diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak index 3a714d3b..440f16ae 100644 Binary files a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.rpak differ diff --git a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak index 3bd34467..93e59c89 100644 Binary files a/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak and b/Northstar.Custom/paks/mp_weapon_shotgun_doublebarrel.starpak differ -- cgit v1.2.3 From cff6f92f030445b7eacb478a64dbd3d22b28586e Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:24:17 +0200 Subject: Translations update from Weblate (#825) Translated using Weblate (Russian) Currently translated at 94.8% (297 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/ru/ Co-authored-by: WofWca --- Northstar.Client/mod/resource/northstar_client_localisation_russian.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt index 56402ca9..91a0dede 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_russian.txt @@ -365,5 +365,7 @@ "MOD_CORRUPTED" "Файл архива мода повреждён: контрольная сумма не совпадает." "NO_DISK_SPACE_AVAILABLE" "Недостаточно места на диске." "MOD_FETCHING_FAILED_GENERAL" "Ошибка распаковки мода. Проверьте файл лога, чтобы узнать подробности." + "MANIFESTO_FETCHING_TEXT" "Скачиваем список проверенных модов..." + "MANIFESTO_FETCHING_TITLE" "Начало загрузки модов" } } -- cgit v1.2.3 From 459e83b35c3485280bee56e2d3419731d3dd29bc Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:00:21 +0200 Subject: Translations update from Weblate (#826) Translated using Weblate (Portuguese) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/pt/ Co-authored-by: William Miller --- .../mod/resource/northstar_client_localisation_portuguese.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt index b6f5ba26..75a5faad 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_portuguese.txt @@ -374,5 +374,7 @@ Clique em Sim se você concorda. Esta escolha pode ser alterada a qualquer momen "WRONG_MOD_VERSION" "O servidor tem o mod \"%s1\" v%s2 enquanto você possui v%s3" "FAILED_WRITING_TO_DISK" "Um erro ocorreu enquanto se extraía o conteúdo do mod para o sistema." "MOD_FETCHING_FAILED_GENERAL" "Extração do mod falhou. Verifique os logs para mais detalhes." + "MANIFESTO_FETCHING_TEXT" "Retornando a lista de mods verificados..." + "MANIFESTO_FETCHING_TITLE" "Preparando o download do mod" } } -- cgit v1.2.3 From ad2e09bd8d416be5548bf48c866be42ac402d744 Mon Sep 17 00:00:00 2001 From: wolf109909 <84360921+wolf109909@users.noreply.github.com> Date: Wed, 31 Jul 2024 20:21:18 +0800 Subject: Remove redundant parameter in DownloadMod (#827) This parameter is a leftover of a previous refactor, and isn't used anywhere in the function. --- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut | 2 +- Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut index 3b81c7f9..4968714c 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_moddownload.nut @@ -49,7 +49,7 @@ void function FetchVerifiedModsManifesto() CloseActiveMenu() } -bool function DownloadMod( RequiredModInfo mod, string serverName ) +bool function DownloadMod( RequiredModInfo mod ) { // Downloading mod UI DialogData dialogData diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 5517843e..1396dd22 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -1030,7 +1030,7 @@ void function OnServerSelected_Threaded( var button ) } else { - if ( DownloadMod( mod, server.name ) ) + if ( DownloadMod( mod ) ) { downloadedMods++ } -- cgit v1.2.3 From ed76f2bed281d5a8733a559820fcc61e66068b2d Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Wed, 31 Jul 2024 17:49:23 +0200 Subject: Revert "Add a generic "JoinServer" function" (#828) Revert "Add a generic "JoinServer" function (#693)" as it causes issues with MAD due to duplicated server join logic as discussed on Discord This reverts commit e4b3cc7d3ee17488053cae24c8a8c981dbe95eab. --- .../vscripts/ui/menu_ns_connect_password.nut | 9 +- .../scripts/vscripts/ui/menu_ns_serverbrowser.nut | 148 ++------------------- 2 files changed, 10 insertions(+), 147 deletions(-) diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut index acc6bb36..b89e665b 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_connect_password.nut @@ -1,5 +1,4 @@ global function AddNorthstarConnectWithPasswordMenu -global function SetPasswordTargetServer struct { @@ -7,7 +6,6 @@ struct var enterPasswordBox var enterPasswordDummy var connectButton - ServerInfo& targetServer } file void function AddNorthstarConnectWithPasswordMenu() @@ -53,16 +51,11 @@ void function OnConnectWithPasswordMenuOpened() } -void function SetPasswordTargetServer( ServerInfo server ) -{ - file.targetServer = server -} - void function ConnectWithPassword( var button ) { if ( GetTopNonDialogMenu() == file.menu ) { TriggerConnectToServerCallbacks() - thread JoinServer( file.targetServer, Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ) ) + thread ThreadedAuthAndConnectToServer( Hud_GetUTF8Text( Hud_GetChild( file.menu, "EnterPasswordBox" ) ), true ) } } \ No newline at end of file diff --git a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut index 1396dd22..cdeb8b3e 100644 --- a/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut +++ b/Northstar.Client/mod/scripts/vscripts/ui/menu_ns_serverbrowser.nut @@ -2,10 +2,7 @@ untyped // Only way to get Hud_GetPos(sliderButton) working was to use untyped global function AddNorthstarServerBrowserMenu - -global function JoinServer -global function JoinServerByName -global function CancelJoinServer +global function ThreadedAuthAndConnectToServer global function AddConnectToServerCallback global function RemoveConnectToServerCallback @@ -373,7 +370,7 @@ void function ToggleConnectingHUD( bool vis ) void function ConnectingButton_Activate( var button ) { - CancelJoinServer() + file.cancelConnection = true } //////////////////////////// @@ -1100,18 +1097,17 @@ void function OnServerSelected_Threaded( var button ) if ( server.requiresPassword ) { OnCloseServerBrowserMenu() - SetPasswordTargetServer( file.lastSelectedServer ) AdvanceMenu( GetMenu( "ConnectWithPasswordMenu" ) ) } else { TriggerConnectToServerCallbacks() - thread ThreadedAuthAndConnectToServer() + thread ThreadedAuthAndConnectToServer( "", downloadedMods != 0 ) } } -void function ThreadedAuthAndConnectToServer( string password = "" ) +void function ThreadedAuthAndConnectToServer( string password = "", bool modsChanged = false ) { if ( NSIsAuthenticatingWithServer() ) return @@ -1139,8 +1135,6 @@ void function ThreadedAuthAndConnectToServer( string password = "" ) if ( NSWasAuthSuccessful() ) { - bool modsChanged = false - // disable all RequiredOnClient mods that are not required by the server and are currently enabled foreach ( string modName in NSGetModNames() ) { @@ -1356,138 +1350,14 @@ void function RemoveConnectToServerCallback( void functionref( ServerInfo ) call void function TriggerConnectToServerCallbacks( ServerInfo ornull targetServer = null ) { - if ( !targetServer ) - targetServer = file.lastSelectedServer - - expect ServerInfo( targetServer ) - - foreach( callback in file.connectCallbacks ) - { - callback( targetServer ) - } -} - -////////////////////////////////////// -// Join server -////////////////////////////////////// - -void function CancelJoinServer() -{ - file.cancelConnection = true -} - -bool function JoinServerByName( string serverName, string password = "" ) -{ - // Request list of online servers. - NSRequestServerList() - while ( NSIsRequestingServerList() ) + ServerInfo server; + if (targetServer == null) { - WaitFrame() - } - - // Go through all servers that are currently online - foreach ( server in NSGetGameServers() ) - { - // Join the server if it has the correct server name. - if ( server.name == serverName ) - { - return JoinServer( server ) - } - } - - print( format( "Failed to connect to server %s: No such server", serverName ) ) - - return false -} - -bool function JoinServer( ServerInfo server, string password = "" ) -{ - if ( NSIsAuthenticatingWithServer() ) - return false - - printt( format( "Connecting to server %s with id of %s", server.name, server.id ) ) - - TriggerConnectToServerCallbacks( server ) - NSTryAuthWithServer( server.index, password ) - - ToggleConnectingHUD( true ) - - while ( NSIsAuthenticatingWithServer() && !file.cancelConnection ) - WaitFrame() - - ToggleConnectingHUD( false ) - - if ( file.cancelConnection ) - { - file.cancelConnection = false - return false + targetServer = file.lastSelectedServer } - file.cancelConnection = false - - if ( NSWasAuthSuccessful() ) - { - bool modsChanged = false - - // disable all RequiredOnClient mods that are not required by the server and are currently enabled - foreach ( string modName in NSGetModNames() ) - { - if ( NSIsModRequiredOnClient( modName ) && NSIsModEnabled( modName ) ) - { - // find the mod name in the list of server required mods - bool found = false - foreach ( RequiredModInfo mod in server.requiredMods ) - { - if ( mod.name == modName ) - { - found = true - break - } - } - // if we didnt find the mod name, disable the mod - if ( !found ) - { - modsChanged = true - NSSetModEnabled( modName, false ) - } - } - } - - // enable all RequiredOnClient mods that are required by the server and are currently disabled - foreach ( RequiredModInfo mod in server.requiredMods ) - { - if ( NSIsModRequiredOnClient( mod.name ) && !NSIsModEnabled( mod.name ) ) - { - modsChanged = true - NSSetModEnabled( mod.name, true ) - } - } - - // only actually reload if we need to since the uiscript reset on reload lags hard - if ( modsChanged ) - ReloadMods() - - NSConnectToAuthedServer() - return true - } - else + foreach( callback in file.connectCallbacks ) { - string reason = NSGetAuthFailReason() - - DialogData dialogData - dialogData.header = "#ERROR" - dialogData.message = reason - dialogData.image = $"ui/menu/common/dialog_error" - - #if PC_PROG - AddDialogButton( dialogData, "#DISMISS" ) - - AddDialogFooter( dialogData, "#A_BUTTON_SELECT" ) - #endif // PC_PROG - AddDialogFooter( dialogData, "#B_BUTTON_DISMISS_RUI" ) - - OpenDialog( dialogData ) - return false + callback( expect ServerInfo( targetServer ) ) } - return false } -- cgit v1.2.3 From 94fa6608c72a051929f7f579d366c18e1ec75a26 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:01:02 +0200 Subject: Add option to manually run merge conflict label action (#832) so that labels can easily be updated if need be --- .github/workflows/merge-conflict-auto-label.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml index e237726a..372687fc 100644 --- a/.github/workflows/merge-conflict-auto-label.yml +++ b/.github/workflows/merge-conflict-auto-label.yml @@ -1,5 +1,6 @@ name: Merge Conflict Auto Label on: + workflow_dispatch: # Manual run push: branches: - main -- cgit v1.2.3 From fe8972fe40fd4cd63adae1c000107ae3d012cf91 Mon Sep 17 00:00:00 2001 From: GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:06:27 +0200 Subject: Run merge conflict label action periodically (#833) --- .github/workflows/merge-conflict-auto-label.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/merge-conflict-auto-label.yml b/.github/workflows/merge-conflict-auto-label.yml index 372687fc..abb7cabd 100644 --- a/.github/workflows/merge-conflict-auto-label.yml +++ b/.github/workflows/merge-conflict-auto-label.yml @@ -4,6 +4,8 @@ on: push: branches: - main + schedule: + - cron: "10 21 * * *" # Runs at 21:10; time was chosen based on contributor activity and low GitHub Actions cron load. jobs: triage: -- cgit v1.2.3 From 75bbc189f9d595e5811f8e501c423c6d39b1390b Mon Sep 17 00:00:00 2001 From: Harmony Weblate <96563367+harmony-weblate@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:55:56 +0200 Subject: Translations update from Weblate (#834) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Translated using Weblate (French) Currently translated at 100.0% (313 of 313 strings) Translation: Northstar/Northstar Client Localisation Translate-URL: https://translate.harmony.tf/projects/northstar/client/fr/ Co-authored-by: Rémy Raes --- .../mod/resource/northstar_client_localisation_french.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt index 0bb6b328..9444a39e 100644 --- a/Northstar.Client/mod/resource/northstar_client_localisation_french.txt +++ b/Northstar.Client/mod/resource/northstar_client_localisation_french.txt @@ -316,7 +316,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "UNAUTHORIZED_PWD" "Mot de passe incorrect" "STRYDER_RESPONSE" "Impossible d'analyser la réponse de Stryder" "PLAYER_NOT_FOUND" "Impossible de trouver le compte du joueur" - "INVALID_MASTERSERVER_TOKEN" "Jeton du server maître invalide ou expiré" + "INVALID_MASTERSERVER_TOKEN" "Token du server maître invalide ou expiré, veuillez relancer l'application EA." "JSON_PARSE_ERROR" "Une erreur est survenue durant l'analyse JSON" "UNSUPPORTED_VERSION" "La version que vous utilisez n'est plus supportée" @@ -377,5 +377,7 @@ Choisissez Oui si vous êtes d'accord. Ce choix peut être modifié à tout inst "MOD_CORRUPTED" "La somme de contrôle de l'archive ne correspond pas à la signature vérifiée." "NO_DISK_SPACE_AVAILABLE" "L'espace restant sur votre disque est insuffisant." "MOD_FETCHING_FAILED_GENERAL" "L'extraction du mod a échoué. Consultez le journal pour plus d'informations." + "MANIFESTO_FETCHING_TITLE" "Préparation du téléchargement du mod" + "MANIFESTO_FETCHING_TEXT" "Récupération de la liste des mods vérifiés..." } } -- cgit v1.2.3 From 7aa3958ccd8e32970736654dfae0c7a87f0798bb Mon Sep 17 00:00:00 2001 From: Dinorush <62536724+Dinorush@users.noreply.github.com> Date: Wed, 14 Aug 2024 09:19:02 -0400 Subject: Support multiple spaces in custom damage source ID display names (#835) Replace all spaces --- Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut index 4987ee01..bae0116e 100644 --- a/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut +++ b/Northstar.Custom/mod/scripts/vscripts/sh_damage_types.nut @@ -727,7 +727,7 @@ bool function RegisterWeaponDamageSourceInternal( int id, string newVal, string damageSourceID[ newVal ] <- id file.damageSourceIDToString[ id ] <- newVal file.damageSourceIDToName[ id ] <- stringVal - file.customDamageSourceIDList.extend( [ id.tostring(), newVal, StringReplace( stringVal, " ", MESSAGE_SPACE_PADDING ) ] ) + file.customDamageSourceIDList.extend( [ id.tostring(), newVal, StringReplace( stringVal, " ", MESSAGE_SPACE_PADDING, true ) ] ) return true } @@ -773,6 +773,6 @@ void function ReceiveNewDamageSourceIDs( array args ) { // IDs are inserted to the custom list in triplets, so we can trust these indices exist and the loop will end properly for ( int i = 0; i < args.len(); i += 3 ) - RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " " ) ) + RegisterWeaponDamageSourceInternal( args[ i ].tointeger(), args[ i + 1 ], StringReplace( args[ i + 2 ], MESSAGE_SPACE_PADDING, " ", true ) ) } #endif -- cgit v1.2.3