Skip to content

Commit

Permalink
Merge branch 'main' into tbshotgun_fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Zanieon authored Jul 8, 2024
2 parents 7266650 + e76789b commit 9c17efa
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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" "Выключить"
Expand Down Expand Up @@ -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" "Ошибка распаковки мода. Проверьте файл лога, чтобы узнать подробности."
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<IntroDropship> militiaDropships
array<IntroDropship> imcDropships
table< entity, array<entity> > militiaDropships
table< entity, array<entity> > imcDropships

float introStartTime
} file
Expand All @@ -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()
Expand All @@ -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<entity> validDropshipSpawns
array<entity> dropshipSpawns = GetEntArrayByClass_Expensive( "info_spawnpoint_dropship_start" )
foreach ( entity dropshipSpawn in dropshipSpawns )
Expand All @@ -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<IntroDropship> teamDropships = createTeam == TEAM_MILITIA ? file.militiaDropships : file.imcDropships
table< entity, array<entity> > 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 )
}
Expand All @@ -128,76 +124,79 @@ 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<entity> > 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<IntroDropship> 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)
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 )
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
Expand All @@ -208,23 +207,25 @@ 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
FirstPersonSequenceStruct jumpSequence
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?
#if BATTLECHATTER_ENABLED
if( playerDropshipIndex == 0 )
PlayBattleChatterLine( player, "bc_pIntroChat" )
#endif

waitthread FirstPersonSequence( jumpSequence, player, playerDropship )

player.s.dropshipIntroIsJumping <- true
thread PlayerJumpsFromDropship( player )
}

Expand All @@ -240,20 +241,21 @@ 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 )
}
})

// 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 )
}
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions Northstar.CustomServers/mod/scripts/vscripts/mp/_stats.nut
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down

0 comments on commit 9c17efa

Please sign in to comment.