From a352fbb877aabdaf9b124eee47fb78f2ac0007a6 Mon Sep 17 00:00:00 2001 From: Connie Price Date: Tue, 4 Jan 2022 19:13:56 +0000 Subject: Big Boost/Earn Meter Fixes! * Only set the boost from persistence once, allowing for the boost to be changed mid game by other scripts. * Added `PlayerEarnMeter_SetBoostByRef(string boostRef)` to simplify setting boosts. * Boosts now correctly disappear after being reward to the player. * Client-side reward icon will now update when the boost is changed. * Titan cores will now pull the HUD icon from the core, instead of the titan chassis. Allowing this to be handled better by other scripts. * Player boost inventory implemented! Now players will be able to store multiple boosts like vanilla. * Boost inventory limits, all vanilla boost limits are respected, and `BurnMeter_SetBoostLimit( string burnRef, int limit )` was added to accommodate this. * Fixed the unused nuke titan boost code so that if anyone decides to use it it's not horribly error prone. --- .../mod/scripts/vscripts/burnmeter/_burnmeter.gnut | 88 +++++++++------- .../scripts/vscripts/earn_meter/sv_earn_meter.gnut | 22 ++++ .../vscripts/earn_meter/sv_earn_meter_mp.gnut | 64 +++++------- .../vscripts/item_inventory/sv_item_inventory.gnut | 113 ++++++++++++++++++++- 4 files changed, 207 insertions(+), 80 deletions(-) (limited to 'Northstar.CustomServers/mod/scripts/vscripts') diff --git a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut index 6d13c75b..9bcfd308 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/burnmeter/_burnmeter.gnut @@ -1,6 +1,8 @@ untyped global function BurnMeter_Init +global function BurnMeter_SetBoostLimit +global function BurnMeter_CheckBoostLimit global function ForceSetGlobalBurncardOverride global function GetSelectedBurncardRefFromWeaponOrPlayer global function RunBurnCardUseFunc @@ -22,6 +24,7 @@ const float MAPHACK_PULSE_DELAY = 2.0 struct { string forcedGlobalBurncardOverride = "" + table boostLimits } file void function BurnMeter_Init() @@ -46,6 +49,11 @@ void function BurnMeter_Init() BurnReward_GetByRef( "burnmeter_rodeo_grenade" ).rewardAvailableCallback = PlayerUsesRodeoGrenadeBurncard BurnReward_GetByRef( "burnmeter_nuke_titan" ).rewardAvailableCallback = PlayerUsesNukeTitanBurncard // unused in vanilla, fun though + BurnMeter_SetBoostLimit( "burnmeter_ticks", 6 ) + BurnMeter_SetBoostLimit( "burnmeter_ap_turret_weapon", 3 ) + BurnMeter_SetBoostLimit( "burnmeter_at_turret_weapon", 3 ) + BurnMeter_SetBoostLimit( "burnmeter_holopilot_nova", 3 ) + // setup player callbacks AddCallback_GameStateEnter( eGameState.Playing, InitBurncardsForIntroPlayers ) AddCallback_OnClientConnected( InitBurncardsForLateJoiner ) @@ -57,6 +65,31 @@ void function BurnMeter_Init() RegisterSignal( "StopAmpedWeapons" ) } +void function BurnMeter_SetBoostLimit( string burnRef, int limit ) +{ + file.boostLimits[burnRef] <- limit +} + +bool function BurnMeter_CheckBoostLimit( entity player ) +{ + EarnObject earnObject = PlayerEarnMeter_GetReward( player ) + string burnRef = earnObject.ref + int limit = -1 + + if ( burnRef in file.boostLimits ) + limit = file.boostLimits[burnRef] + + if ( limit < 0 ) + return false + + int current = PlayerInventory_CountBurnRef( player, burnRef ) + + if ( current < limit ) + return false + + return true +} + void function ForceSetGlobalBurncardOverride( string ref ) { file.forcedGlobalBurncardOverride = ref @@ -203,13 +236,10 @@ void function UseBurnCardWeapon( entity weapon, entity player ) Remote_CallFunction_Replay( player, "ServerCallback_RewardUsed", BurnReward_GetByRef( ref ).id ) RunBurnCardUseFunc( player, ref ) - // dont remove in RunBurnCardUseFunc because it can be called in non-burn_card_weapon_mod contexts - // TODO: currently not sure how burncards can be stacked ( max clipcount for all burncards is 1, so can't just set that ) - // if this gets figured out, add a conditional check here to prevent removes if they've got burncards left if ( PlayerEarnMeter_IsRewardAvailable( player ) ) PlayerEarnMeter_SetRewardUsed( player ) - player.TakeWeapon( BurnReward_GetByRef( ref ).weaponName ) + PlayerInventory_PopInventoryItem( player ) } void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer ) @@ -220,20 +250,8 @@ void function UseBurnCardWeaponInCriticalSection( entity weapon, entity ownerPla void function BurnMeter_GiveRewardDirect( entity player, string itemRef ) { - BurnReward burncard = BurnReward_GetByRef( itemRef ) - - array mods = [ "burn_card_weapon_mod" ] - if ( burncard.extraWeaponMod != "" ) - mods.append( burncard.extraWeaponMod ) - - // ensure inventory slot isn't full to avoid crash - entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) - if ( IsValid( preexistingWeapon ) ) - player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) - - player.GiveOffhandWeapon( burncard.weaponName, OFFHAND_INVENTORY, mods ) + PlayerInventory_PushInventoryItemByBurnRef( player, itemRef ) Remote_CallFunction_Replay( player, "ServerCallback_RewardReadyMessage", player.s.respawnTime ) - } int function GetBurnCardWeaponSkin( entity weapon ) @@ -408,35 +426,27 @@ void function PlayerUsesNukeTitanBurncard( entity player ) void function PlayerUsesNukeBurncardThreaded( entity player ) { - // if this is given manually ( i.e. not the equipped burnreward in inventory ), this will run at bad times - // so do this check here, yes, this will cause people to lose their cards and get nothing, but better than free titan regens - if ( !BurnMeterPlayer_CanUseReward( player, BurnReward_GetByRef( "burnmeter_nuke_titan" ) ) ) - return - - float ownedFrac = PlayerEarnMeter_GetOwnedFrac( player ) + Point spawnpoint = GetTitanReplacementPoint( player, false ) + entity titan = CreateOgre( TEAM_UNASSIGNED, spawnpoint.origin, spawnpoint.angles ) + DispatchSpawn( titan ) - // use player's titan loadout, but with warpfall so faster and no dome - TitanLoadoutDef titanLoadout = GetTitanLoadoutForPlayer( player ) - titanLoadout.passive3 = "pas_warpfall" + titan.kv.script_hotdrop = "4" + thread NPCTitanHotdrops( titan, false, "at_hotdrop_drop_2knee_turbo" ) - thread CreateTitanForPlayerAndHotdrop( player, GetTitanReplacementPoint( player, false ) ) + Remote_CallFunction_Replay( player, "ServerCallback_ReplacementTitanSpawnpoint", spawnpoint.origin.x, spawnpoint.origin.y, spawnpoint.origin.z, Time() + GetHotDropImpactTime( titan, "at_hotdrop_drop_2knee_turbo" ) + 1.6 ) - entity titan = player.GetPetTitan() - SetTeam( titan, TEAM_UNASSIGNED ) // make it so you can kill yourself lol DoomTitan( titan ) - NPC_SetNuclearPayload( titan ) - // this should get run after the vanilla set_usable's event, so titan is never embarkable - // embarking a titan in this state WILL kill the server so uhh, pretty bad - AddAnimEvent( titan, "set_usable", void function( entity titan ) { titan.UnsetUsable() } ) + titan.SetBossPlayer(player) // Do this so that if we crush something we get awarded the kill. - titan.WaitSignal( "TitanHotDropComplete" ) - AutoTitan_SelfDestruct( titan ) + entity soul = titan.GetTitanSoul() + soul.soul.nukeAttacker = player // Use this to get credit for the explosion kills. + + NPC_SetNuclearPayload( titan ) - while ( PlayerEarnMeter_GetMode( player ) == eEarnMeterMode.PET ) - WaitFrame() + titan.WaitSignal( "ClearDisableTitanfall" ) + titan.ClearBossPlayer() // Stop being the boss so we don't get an award for this titan blowing up. - // restore original earnmeter values, no way to set earned that's exposed unfortunately - PlayerEarnMeter_SetOwnedFrac( player, ownedFrac ) + thread TitanEjectPlayer( titan, true ) } void function PlayerUsesPermanentAmpedWeaponsBurncard( entity player ) diff --git a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter.gnut index dda84976..691f07fb 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 @@ -39,6 +39,8 @@ global function SharedEarnMeter_AddEarnedAndOwned global function PlayerEarnMeter_SetEnabled global function PlayerEarnMeter_Enabled +global function PlayerEarnMeter_SetBoostByRef + global struct EarnMeterThresholdEarnedStruct { float threshold @@ -505,4 +507,24 @@ void function PlayerEarnMeter_SetEnabled( bool enabled ) bool function PlayerEarnMeter_Enabled() { return file.earnMeterEnabled +} + +void function PlayerEarnMeter_SetBoostByRef( entity player, string boostRef ) { + EarnObject earnobject = EarnObject_GetByRef( boostRef ) + BurnReward burncard = BurnReward_GetByRef( boostRef ) + + if ( Riff_BoostAvailability() != eBoostAvailability.Disabled ) + { + PlayerEarnMeter_SetReward( player, earnobject ) // pretty sure this works? + PlayerEarnMeter_SetRewardFrac( player, burncard.cost ) + PlayerEarnMeter_EnableReward( player ) + } + + if ( EarnMeterMP_IsTitanEarnGametype() ) + { + PlayerEarnMeter_SetGoal( player, EarnObject_GetByRef( GetTitanLoadoutForPlayer( player ).titanClass ) ) + PlayerEarnMeter_EnableGoal( player ) // prevents goalstate from being set incorrectly + } + else + PlayerEarnMeter_SetGoal( player, earnobject ) } \ No newline at end of file diff --git a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter_mp.gnut b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter_mp.gnut index 4c42a825..193262f1 100644 --- a/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter_mp.gnut +++ b/Northstar.CustomServers/mod/scripts/vscripts/earn_meter/sv_earn_meter_mp.gnut @@ -23,7 +23,7 @@ void function EarnMeterMP_SetTitanLoadout( entity player ) if ( EarnMeterMP_IsTitanEarnGametype() ) PlayerEarnMeter_SetGoal( player, EarnObject_GetByRef( GetTitanLoadoutForPlayer( player ).titanClass ) ) else - PlayerEarnMeter_SetGoal( player, EarnObject_GetByRef( GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) ) ) + PlayerEarnMeter_SetGoal( player, PlayerEarnMeter_GetReward( player ) ) } void function EarnMeterMP_SetPassiveMeterGainEnabled( bool enabled ) @@ -34,23 +34,10 @@ void function EarnMeterMP_SetPassiveMeterGainEnabled( bool enabled ) void function SetupPlayerEarnMeter( entity player ) { PlayerEarnMeter_Reset( player ) - - if ( Riff_BoostAvailability() != eBoostAvailability.Disabled ) - { - string burncardRef = GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) - PlayerEarnMeter_SetReward( player, EarnObject_GetByRef( burncardRef ) ) // pretty sure this works? - PlayerEarnMeter_SetRewardFrac( player, BurnReward_GetByRef( burncardRef ).cost ) - PlayerEarnMeter_EnableReward( player ) - } - - if ( EarnMeterMP_IsTitanEarnGametype() ) - { - PlayerEarnMeter_SetGoal( player, EarnObject_GetByRef( GetTitanLoadoutForPlayer( player ).titanClass ) ) - PlayerEarnMeter_EnableGoal( player ) // prevents goalstate from being set incorrectly - } - else - PlayerEarnMeter_SetGoal( player, EarnObject_GetByRef( GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) ) ) - + + string burncardRef = GetSelectedBurnCardRef( player ) + PlayerEarnMeter_SetBoostByRef( player, burncardRef ) + // catchup bonus for late joiners // todo: maths on this is fine but for some reason it won't set correctly, could be getting reset somewhere? PlayerEarnMeter_AddOwnedFrac( player, ( ( Time() - file.playingStartTime ) / 4.0 ) * 0.01 ) @@ -61,24 +48,24 @@ void function OnPlaying() file.playingStartTime = Time() foreach ( entity player in GetPlayerArray() ) SetupPlayerEarnMeter( player ) - + if ( Riff_BoostAvailability() != eBoostAvailability.Disabled ) SetCallback_EarnMeterRewardEarned( EarnMeterMP_BoostEarned ) - + // do this in playing so that gamemodes/maps can disable and this'll take affect if ( EarnMeterMP_IsTitanEarnGametype() ) // settitanavailable when earnmeter full { Riff_ForceTitanAvailability( eTitanAvailability.Custom ) // doesn't seem to affect anything aside from preventing some annoying client stuff svGlobal.titanAvailabilityCheck = IsTitanAvailable } - + SetCallback_EarnMeterGoalEarned( EarnMeterMP_TitanEarned ) } void function OnPlayerRespawned( entity player ) { thread EarnMeterMP_PlayerLifeThink( player ) - + if ( PlayerEarnMeter_IsRewardAvailable( player ) ) EarnMeterMP_BoostEarned( player ) } @@ -116,14 +103,12 @@ void function EarnMeterMP_PlayerLifeThink( entity player ) { if ( !IsTitanAvailable( player ) && PlayerEarnMeter_GetOwnedFrac( player ) == 1.0 ) // this should only be the case after player has dropped their titan { + float oldRewardFrac = PlayerEarnMeter_GetRewardFrac( player ) PlayerEarnMeter_Reset( player ) - // reset rewards - string burncardRef = GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) - PlayerEarnMeter_SetReward( player, EarnObject_GetByRef( burncardRef ) ) - PlayerEarnMeter_SetRewardFrac( player, BurnReward_GetByRef( burncardRef ).cost ) + PlayerEarnMeter_SetRewardFrac( player, oldRewardFrac ) PlayerEarnMeter_EnableReward( player ) } - + if ( PlayerEarnMeter_GetRewardFrac( player ) != 0 ) PlayerEarnMeter_EnableReward( player ) } @@ -135,7 +120,7 @@ void function EarnMeterMP_PlayerLifeThink( entity player ) lastEarnMeterMode = desiredEarnMeterMode } - + if ( lastEarnMeterMode == eEarnMeterMode.DEFAULT ) { if ( PlayerEarnMeter_GetOwnedFrac( player ) < 1.0 ) @@ -148,26 +133,31 @@ void function EarnMeterMP_PlayerLifeThink( entity player ) player.SetPlayerNetInt( "goalState", eRewardState.AVAILABLE ) PlayerEarnMeter_RefreshGoal( player ) } - + if ( Time() - lastPassiveGainTime > 4.0 && file.passiveMeterGainEnabled ) // this might be 5.0 { lastPassiveGainTime = Time() PlayerEarnMeter_AddOwnedFrac( player, 0.01 ) } } - + WaitFrame() } } void function EarnMeterMP_BoostEarned( entity player ) { - BurnReward burncard = BurnReward_GetByRef( GetSelectedBurnCardRef( player ) ) - + EarnObject earnobject = PlayerEarnMeter_GetReward( player ) + BurnReward burncard = BurnReward_GetByRef( earnobject.ref ) + while ( burncard.ref == "burnmeter_random_foil" ) burncard = BurnReward_GetRandom() - BurnMeter_GiveRewardDirect( player, burncard.ref ) + if ( !BurnMeter_CheckBoostLimit( player ) ) { + BurnMeter_GiveRewardDirect( player, burncard.ref ) + } + + PlayerEarnMeter_DisableReward( player ) } void function EarnMeterMP_TitanEarned( entity player ) @@ -179,13 +169,11 @@ void function EarnMeterMP_TitanEarned( entity player ) } else { + float oldRewardFrac = PlayerEarnMeter_GetRewardFrac( player ) PlayerEarnMeter_Reset( player ) - // reset rewards - string burncardRef = GetSelectedBurncardRefFromWeaponOrPlayer( null, player ) - PlayerEarnMeter_SetReward( player, EarnObject_GetByRef( burncardRef ) ) - PlayerEarnMeter_SetRewardFrac( player, BurnReward_GetByRef( burncardRef ).cost ) + PlayerEarnMeter_SetRewardFrac( player, oldRewardFrac ) PlayerEarnMeter_EnableReward( player ) - + if ( PlayerEarnMeter_GetRewardFrac( player ) != 0 ) PlayerEarnMeter_EnableReward( player ) } diff --git a/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut b/Northstar.CustomServers/mod/scripts/vscripts/item_inventory/sv_item_inventory.gnut index 6d8cf55c..a768b3f3 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 @@ -5,19 +5,126 @@ global function PlayerInventory_RefreshEquippedState global function PlayerInventory_StartCriticalSection global function PlayerInventory_EndCriticalSectionForWeaponOnEndFrame +global function PlayerInventory_PushInventoryItem +global function PlayerInventory_PushInventoryItemByBurnRef +global function PlayerInventory_PopInventoryItem +global function PlayerInventory_CountBurnRef + +struct +{ + table > playerInventoryStacks +} file + void function Sv_ItemInventory_Init() { + AddCallback_OnClientConnected( Sv_ItemInventory_OnClientConnected ) + AddCallback_OnPlayerRespawned( Sv_ItemInventory_OnPlayerRespawned ) +} +void function Sv_ItemInventory_OnClientConnected( entity player ) +{ + file.playerInventoryStacks[ player ] <- [] } +void function Sv_ItemInventory_OnPlayerRespawned( entity player ) +{ + array playerInventoryStack = file.playerInventoryStacks[ player ] + + if (playerInventoryStack.len() > 0) { + InventoryItem topInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1] + PlayerInventory_GiveInventoryItem(player, topInventoryItem) + } + + return +} + + int function SvPlayerInventory_ItemCount( entity player ) { - return 0 + return file.playerInventoryStacks[ player ].len() } int function PlayerInventory_CountTurrets( entity player ) { - return 0 + int turretCount = 0 + + foreach ( inventoryItem in file.playerInventoryStacks[ player ] ) + if ( inventoryItem.weaponRef == "mp_ability_turretweapon" ) + turretCount += 1 + + return turretCount +} + +int function PlayerInventory_CountBurnRef( entity player, string burnRef ) +{ + int count = 0 + + foreach ( inventoryItem in file.playerInventoryStacks[ player ] ) + if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) + if ( inventoryItem.burnReward.ref == burnRef ) + count += 1 + + return count +} + +void function PlayerInventory_TakeInventoryItem( entity player ) +{ + entity preexistingWeapon = player.GetOffhandWeapon( OFFHAND_INVENTORY ) + if ( IsValid( preexistingWeapon ) ) + player.TakeWeaponNow( preexistingWeapon.GetWeaponClassName() ) +} + +void function PlayerInventory_GiveInventoryItem( entity player, InventoryItem inventoryItem ) +{ + array mods = [] + + if ( inventoryItem.itemType == eInventoryItemType.burnmeter ) { + mods.append( "burn_card_weapon_mod" ) + if ( inventoryItem.burnReward.extraWeaponMod != "" ) + mods.append( inventoryItem.burnReward.extraWeaponMod ) + } + + // ensure inventory slot isn't full to avoid crash + PlayerInventory_TakeInventoryItem( player ) + + player.GiveOffhandWeapon( inventoryItem.weaponRef, OFFHAND_INVENTORY, mods ) +} + +void function PlayerInventory_PushInventoryItem( entity player, InventoryItem inventoryItem ) +{ + file.playerInventoryStacks[ player ].append(inventoryItem) + player.SetPlayerNetInt( "itemInventoryCount", file.playerInventoryStacks[ player ].len() ) + + PlayerInventory_GiveInventoryItem(player, inventoryItem) +} + +void function PlayerInventory_PushInventoryItemByBurnRef( entity player, string burnRef ) +{ + InventoryItem inventoryItem + inventoryItem.itemType = eInventoryItemType.burnmeter + inventoryItem.burnReward = BurnReward_GetByRef( burnRef ) + inventoryItem.weaponRef = inventoryItem.burnReward.weaponName + + PlayerInventory_PushInventoryItem(player, inventoryItem) +} + +void function PlayerInventory_PopInventoryItem( entity player ) +{ + array playerInventoryStack = file.playerInventoryStacks[ player ] + + if (playerInventoryStack.len() > 0) { + InventoryItem topInventoryItem = playerInventoryStack.pop() + player.SetPlayerNetInt( "itemInventoryCount", playerInventoryStack.len() ) + + if (playerInventoryStack.len() > 0) { + InventoryItem nextInventoryItem = playerInventoryStack[playerInventoryStack.len() - 1] + PlayerInventory_GiveInventoryItem(player, nextInventoryItem) + } else { + PlayerInventory_TakeInventoryItem( player ) + } + } + + return } void function PlayerInventory_RefreshEquippedState( entity player ) @@ -30,7 +137,7 @@ void function PlayerInventory_StartCriticalSection( entity player ) } -void function PlayerInventory_EndCriticalSectionForWeaponOnEndFrame( entity player ) +void function PlayerInventory_EndCriticalSectionForWeaponOnEndFrame( entity weapon ) { } \ No newline at end of file -- cgit v1.2.3