diff options
Diffstat (limited to 'Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut')
-rw-r--r-- | Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut new file mode 100644 index 000000000..3f914745d --- /dev/null +++ b/Northstar.Custom/mod/scripts/vscripts/burnmeter/sh_burnmeter.gnut @@ -0,0 +1,488 @@ +global function ShBurnMeter_Init +global function BurnReward_GetById +global function BurnReward_GetByRef +global function BurnReward_GetRandom +global function GetSelectedBurnCardRef +global function GetBoostSkin +#if SERVER || CLIENT +global function BurnMeterEnabled +global function CanUseWeaponAsBurnCard +global function TryUsingBurnCardWeapon +global function TryUsingBurnCardWeaponInCriticalSection +global function BurnMeterPlayer_CanUseEquipped +global function OnWeaponAttemptOffhandSwitch_burncardweapon +global function BurnMeterPlayer_CanUseReward +global function BurnMeterPlayer_GetRewardOrGoal +global function BurnReward_GetTopInventoryItemBurnCard +global function OnWeaponPrimaryAttack_nuke_eject +global function BurnMeter_HarvesterShieldCanUse +#endif + +global function GetAllBoostTurretTypes + +global const BURN_METER_SMALL_POINT_VALUE = 1 +global const BURN_METER_MID_POINT_VALUE = 2 +global const BURN_METER_LARGE_POINT_VALUE = 5 +global const BURN_METER_EXTRA_LARGE_POINT_VALUE = 10 + +global const BURN_METER_RADAR_JAMMER_PULSE_DURATION = 6.0 +global const BURN_METER_RADAR_JAMMER_EASE_OFF_TIME = 1.0 + +global enum eBurnMeterRewardAvailableFor +{ + PILOT_ONLY, + TITAN_ONLY, + PILOT_AND_TITAN, + SPECIAL_PLAYERS_ONLY, +} + +global struct BurnReward +{ + int id = -1 + string ref = "" + string localizedName = "" + string description = "" + asset image = $"" + float cost + int userType = -1 + int skinIndex = 0 + string weaponName = "" + string extraWeaponMod = "" + string activationText = "" + + void functionref( entity ) ornull rewardAvailableCallback = null +} + +global struct BurnStruct +{ + table< string, BurnReward > burnRewards + array< BurnReward > allCards //Kinda inefficient to store the same burn cards 3 times (once in burnRewards, once in foil/normal, once in allcards. Prefer speed over memory? ) + array< BurnReward > allowedCards + +} + +global BurnStruct burn + +global table< string, bool functionref( entity ) > burnMeterCanUseFuncTable + +struct +{ + + bool shouldCycleOnRelease = false + +} file + +array<string> turretBurnCards = [ + "burnmeter_ap_turret_weapon", + "burnmeter_at_turret_weapon", + "burnmeter_ap_turret_weapon_infinite", + "burnmeter_at_turret_weapon_infinite", +] + +void function ShBurnMeter_Init() +{ + + #if SERVER || CLIENT + //burnMeterCanUseFuncTable[ "burnmeter_random_foil" ] <- BurnMeter_RandomFoilCanUse + burnMeterCanUseFuncTable[ "burnmeter_emergency_titan" ] <- BurnMeter_EmergencyTitanCanUse + burnMeterCanUseFuncTable[ "burnmeter_nuke_titan" ] <- BurnMeter_NukeTitanCanUse + // burnMeterCanUseFuncTable[ "burnmeter_harvester_shield" ] <- BurnMeter_HarvesterShieldCanUse + #endif + + + + var dataTable = GetDataTable( $"datatable/burn_meter_rewards.rpak" ) + + for ( int row = 0; row < GetDatatableRowCount( dataTable ); row++ ) + { + BurnReward burnReward + burnReward.id = row + burnReward.ref = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_REF_COLUMN_NAME ) ) + burnReward.localizedName = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_NAME_COLUMN_NAME ) ) + burnReward.description = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_DESCRIPTION_COLUMN_NAME ) ) + burnReward.image = GetDataTableAsset( dataTable, row, GetDataTableColumnByName( dataTable, BURN_IMAGE_COLUMN_NAME ) ) + burnReward.cost = GetDataTableFloat( dataTable, row, GetDataTableColumnByName( dataTable, BURN_COST_COLUMN_NAME ) ) + string userType = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_AVAILABLE_COLUMN_NAME ) ) + burnReward.userType = eBurnMeterRewardAvailableFor[userType] + burnReward.weaponName = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_WEAPON_COLUMN_NAME ) ) + burnReward.extraWeaponMod = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, BURN_EXTRA_WEAPON_MOD_NAME ) ) + burnReward.activationText = GetDataTableString( dataTable, row, GetDataTableColumnByName( dataTable, "activationText" ) ) + burnReward.skinIndex = GetDataTableInt( dataTable, row, GetDataTableColumnByName( dataTable, "skinIndex" ) ) + + if ( IsDisabledRef( burnReward.ref ) ) + continue + +#if SERVER || CLIENT + if ( burnReward.weaponName != "" ) + PrecacheWeapon( burnReward.weaponName ) + #endif + + burn.burnRewards[burnReward.ref] <- burnReward + + bool selectable = GetDataTableBool( dataTable, row, GetDataTableColumnByName( dataTable, "selectable" ) ) + burn.allCards.append( burnReward ) + if ( selectable ) + burn.allowedCards.append( burnReward ) + } + + #if CLIENT + //Registering here instead of in CreateWeaponData() in _items.nut to remove dependence on HUD script with items. If more weapons other than smart pistol run into this problem, just add a column in burn_meter_rewards to specify we need to do this. ( ticks are fine because they have a damagedef associated with them ) + RegisterWeaponDamageSourceName( "mp_weapon_smart_pistol", expect string( GetWeaponInfoFileKeyField_GlobalNotNull( "mp_weapon_smart_pistol", "shortprintname" ) ) ) + + RegisterConCommandTriggeredCallback( "-offhand4", CycleOnRelease ) + #endif +} + +#if SERVER || CLIENT +bool function BurnMeterEnabled() +{ + return Riff_BoostAvailability() != eBoostAvailability.Disabled +} +#endif + +BurnReward function BurnReward_GetById( int id ) +{ + return burn.allCards[ id ] +} + + +BurnReward function BurnReward_GetByRef( string ref ) +{ + Assert( ref in burn.burnRewards ) + + // more hacks for arena + if ( !( ref in burn.burnRewards ) && GetCurrentPlaylistVarString( "boost_store_mode", "off" ) == "arena" ) + return GetArenaLoadoutItemAsBurnReward( ref ) + + return burn.burnRewards[ref] +} + +int function GetBoostSkin( string ref ) +{ + BurnReward reward = BurnReward_GetByRef( ref ) + //printt( "ref: " + ref + ", Boost skin: " + reward.skinIndex ) + return reward.skinIndex +} + + +BurnReward function BurnReward_GetRandom() +{ + return burn.allowedCards.getrandom() +} + +string function GetSelectedBurnCardRef( entity player ) +{ + int burnCardID = expect int ( player.GetPersistentVar( "burnmeterSlot" ) ) + BurnReward burnCard = burn.allCards[ burnCardID ] + string ref = burnCard.ref + + #if SERVER + if ( GetItemDisplayData( ref ).hidden ) + ClientCommand( player, "disconnect" ) + #endif + + #if SERVER || CLIENT + + if ( Riff_TitanAvailability() == eTitanAvailability.Never ) + { + //JFS: Batteries and Titan turrets are useless in PvP, turn them into amped weapons instead. Not an elegant solution at all. Fix next game. (Make boosts editable mid-match? ) + if ( ref == "burnmeter_emergency_battery" || ref == "burnmeter_at_turret_weapon" ) + ref = "burnmeter_amped_weapons" + } + + if ( GetCurrentPlaylistVarInt( "featured_mode_all_ticks", 0 ) >= 1 ) + { + if ( ref == "burnmeter_ticks" || ref == "burnmeter_random_foil" ) + ref = "burnmeter_amped_weapons" + } + #endif + + return ref +} + + +#if SERVER || CLIENT +bool function CanUseWeaponAsBurnCard( entity weapon, entity ownerPlayer ) +{ + Assert( weapon.HasMod( "burn_card_weapon_mod" ) ) + + if ( !BurnMeterPlayer_CanUseEquipped( ownerPlayer ) ) + { + weapon.EmitWeaponSound( "CoOp_SentryGun_DeploymentDeniedBeep" ) + return false + } + + return true +} + +bool function TryUsingBurnCardWeapon( entity weapon, entity ownerPlayer ) +{ + Assert( weapon.HasMod( "burn_card_weapon_mod" ) ) + + if ( !CanUseWeaponAsBurnCard( weapon, ownerPlayer ) ) + return false + + #if SERVER + UseBurnCardWeapon( weapon, ownerPlayer ) + #endif + + return true +} + +bool function TryUsingBurnCardWeaponInCriticalSection( entity weapon, entity ownerPlayer ) +{ + Assert( weapon.HasMod( "burn_card_weapon_mod" ) ) + + if ( !CanUseWeaponAsBurnCard( weapon, ownerPlayer ) ) + return false + + #if SERVER + UseBurnCardWeaponInCriticalSection( weapon, ownerPlayer ) + #endif + + return true +} + + + +bool function BurnMeterPlayer_CanUseReward( entity player, BurnReward burnReward ) +{ + if ( !BurnMeterPlayer_CanUseGlobal( player ) ) + return false + + switch( burnReward.userType ) + { + case eBurnMeterRewardAvailableFor.PILOT_ONLY: + return !player.IsTitan() + + case eBurnMeterRewardAvailableFor.TITAN_ONLY: + return player.IsTitan() + + case eBurnMeterRewardAvailableFor.PILOT_AND_TITAN: + return true + + case eBurnMeterRewardAvailableFor.SPECIAL_PLAYERS_ONLY: + return BurnMeterPlayer_CanUseSpecial( player, burnReward ) //TODO: Note that for the case of reaperfall we also send the message to the client if they can't summon reaper in the validation function. Not ideal... + } + + unreachable + +} + + +bool function BurnMeterPlayer_CanUseEquipped( entity player ) +{ + BurnReward burnReward = BurnReward_GetTopInventoryItemBurnCard( player ) + return BurnMeterPlayer_CanUseReward( player, burnReward ) +} + + +EarnObject function BurnMeterPlayer_GetRewardOrGoal( entity player ) +{ + if ( PlayerEarnMeter_IsRewardEnabled( player ) ) // TODO: more robust + return PlayerEarnMeter_GetReward( player ) + else + return PlayerEarnMeter_GetGoal( player ) + + unreachable +} + + +bool function BurnMeterPlayer_CanUseGlobal( entity player ) +{ + if ( player.IsBot() ) + return false + + if ( !IsAlive( player ) ) + return false + + if ( player.IsPhaseShifted() ) + return false + + if ( player.ContextAction_IsInVehicle() ) //no rewards when in dropship + return false + + if ( !IsBurnMeterRewardAvailableForGameState() ) + return false + + return true +} + + +bool function IsBurnMeterRewardAvailableForGameState() //Based off IsReplacementTitanAvailable +{ + int currentGameState = GetGameState() + + switch ( currentGameState ) //need to add a new entry in here for every new game state we make + { + case eGameState.WaitingForCustomStart: + case eGameState.WaitingForPlayers: + case eGameState.PickLoadout: + case eGameState.Prematch: + case eGameState.SwitchingSides: + case eGameState.Postmatch: + return false + + case eGameState.Playing: + case eGameState.SuddenDeath: + return true + + case eGameState.WinnerDetermined: + case eGameState.Epilogue: + { + if ( IsRoundBased() ) + { + // TODO: make this work on the client + #if SERVER + if ( !IsRoundBasedGameOver() ) + return false + + if ( !ShouldRunEvac() ) + return false + #endif + } + + return true + } + + default: + Assert( false, "Unknown Game State: " + currentGameState ) + return false + } + + unreachable +} + + +bool function OnWeaponAttemptOffhandSwitch_burncardweapon( entity weapon ) +{ + entity ownerPlayer = weapon.GetWeaponOwner() + Assert( ownerPlayer.IsPlayer() ) + + if ( ownerPlayer.IsUsingOffhandWeapon() ) + return false + + if ( weapon.HasMod( "burn_card_weapon_mod" ) ) + { + bool canUse = BurnMeterPlayer_CanUseEquipped( ownerPlayer ) + + return canUse + } + else + return true + + unreachable +} + +BurnReward function BurnReward_GetTopInventoryItemBurnCard( entity player ) +{ + int burnRewardID = player.GetPlayerNetInt( TOP_INVENTORY_ITEM_BURN_CARD_ID ) + return BurnReward_GetById( burnRewardID ) +} + +bool function BurnMeterPlayer_CanUseSpecial( entity player, BurnReward burnReward ) +{ + Assert( burnReward.ref in burnMeterCanUseFuncTable ) + return burnMeterCanUseFuncTable[ burnReward.ref ]( player ) +} + +bool function BurnMeter_HarvesterShieldCanUse( entity player ) +{ +// entity harvester = GetGlobalNetEnt( "FD_activeHarvester" ) + bool canUse = GetGlobalNetTime( "FD_harvesterInvulTime" ) < Time() + // harvester.GetShieldHealth() < harvester.GetShieldHealthMax() + + if ( !canUse ) + { + #if CLIENT + AddPlayerHint( 3.0, 0.5, $"", "#HINT_HARVESTER_BOOST_CANT_USE" ) + #endif + } + + return canUse +} + +bool function BurnMeter_NukeTitanCanUse( entity player ) +{ + bool canUse = BurnMeter_EmergencyTitanCanUse( player ) + + if ( !canUse ) + { + #if CLIENT + AddPlayerHint( 5.0, 0.5, $"", "#HINT_NUKE_TITAN_CANT_USE" ) + #endif + } + + return canUse +} + +bool function BurnMeter_EmergencyTitanCanUse( entity player ) +{ + if ( IsAlive( player.GetPetTitan() ) ) + return false + + #if SERVER + if ( !IsReplacementTitanAvailableForGameState() ) + return false + + if ( player.isSpawning ) + return false + + return true + #endif + + #if CLIENT + return true + #endif +} + +bool function BurnMeter_SummonReaperCanUse( entity player ) +{ + array< entity > allReapers = GetNPCArrayByClass( "npc_super_spectre" ) + + int playerTeam = player.GetTeam() + + foreach( reaper in allReapers ) + { + if ( reaper.GetTeam() == playerTeam ) + { + #if SERVER + MessageToPlayer( player, eEventNotifications.BurnMeter_CantSummonReaper ) + #endif + + return false + } + } + return true +} + +var function OnWeaponPrimaryAttack_nuke_eject( entity weapon, WeaponPrimaryAttackParams attackParams ) +{ + #if CLIENT + entity weaponOwner = weapon.GetWeaponOwner() + if ( weaponOwner.IsPlayer() && IsValid( weaponOwner.GetCockpit() ) ) + { + weaponOwner.ClientCommand( "TitanEject " + 3 ) + PlayerEjects( weaponOwner, weaponOwner.GetCockpit() ) //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 + } + #endif + return 0 +} + +#endif + +#if CLIENT +void function CycleOnRelease( entity player ) +{ + if ( file.shouldCycleOnRelease ) + { + CycleInventory( player ) + file.shouldCycleOnRelease = false + } +} +#endif + +array<string> function GetAllBoostTurretTypes() +{ + return turretBurnCards +}
\ No newline at end of file |