untyped global function PowerUps_Init struct { array powerupSpawns } file void function PowerUps_Init() { SH_PowerUp_Init() AddSpawnCallbackEditorClass( "script_ref", "script_power_up_other", AddPowerupSpawn ) AddCallback_OnTouchHealthKit( "item_powerup", OnPowerupCollected ) AddCallback_GameStateEnter( eGameState.Prematch, RespawnPowerups ) } void function AddPowerupSpawn( entity spawnpoint ) { file.powerupSpawns.append( spawnpoint ) } void function RespawnPowerups() { foreach ( entity spawnpoint in file.powerupSpawns ) { PowerUp powerupDef = GetPowerUpFromItemRef( expect string( spawnpoint.kv.powerUpType ) ) thread PowerupSpawnerThink( spawnpoint, powerupDef ) } } void function PowerupSpawnerThink( entity spawnpoint, PowerUp powerupDef ) { svGlobal.levelEnt.EndSignal( "CleanUpEntitiesForRoundEnd" ) entity base = CreatePropDynamic( powerupDef.baseModel, spawnpoint.GetOrigin(), spawnpoint.GetAngles(), 2 ) OnThreadEnd( function() : ( base ) { base.Destroy() }) while ( true ) { if ( !powerupDef.spawnFunc() ) return entity powerup = CreateEntity( "item_powerup" ) powerup.SetOrigin( base.GetOrigin() + powerupDef.modelOffset ) powerup.SetAngles( base.GetAngles() + powerupDef.modelAngles ) powerup.SetValueForModelKey( powerupDef.model ) powerup.s.powerupRef <- powerupDef.itemRef // this needs to be done before dispatchspawn since OnPowerupCollected will run as soon as we call dispatchspawn if there's a player on battery as it spawns DispatchSpawn( powerup ) // unless i'm doing something really dumb, this all has to be done after dispatchspawn to get the powerup to not have gravity powerup.StopPhysics() powerup.SetOrigin( base.GetOrigin() + powerupDef.modelOffset ) powerup.SetAngles( base.GetAngles() + powerupDef.modelAngles ) powerup.SetModel( powerupDef.model ) PickupGlow glow = CreatePickupGlow( powerup, powerupDef.glowColor.x.tointeger(), powerupDef.glowColor.y.tointeger(), powerupDef.glowColor.z.tointeger() ) glow.glowFX.SetOrigin( spawnpoint.GetOrigin() ) // want the glow to be parented to the powerup, but have the position of the spawnpoint OnThreadEnd( function() : ( powerup ) { if ( IsValid( powerup ) ) powerup.Destroy() }) powerup.WaitSignal( "OnDestroy" ) wait powerupDef.respawnDelay } } bool function OnPowerupCollected( entity player, entity healthpack ) { PowerUp powerup = GetPowerUpFromItemRef( expect string( healthpack.s.powerupRef ) ) if ( powerup.titanPickup == player.IsTitan() ) { // hack because i couldn't figure out any other way to do this without modifying sh_powerup // ensure we don't kill the powerup if it's a battery the player can't pickup if ( powerup.index == ePowerUps.titanTimeReduction || powerup.index == ePowerUps.LTS_TitanTimeReduction ) { if ( player.IsTitan() ) return false if ( PlayerHasMaxBatteryCount( player ) ) return false // this is seemingly innacurate to what fra actually did, but for whatever reason embarking with >1 bat crashes in vanilla code // so idk this is easier if ( GAMETYPE == FREE_AGENCY && ( IsValid( player.GetPetTitan() ) || IsTitanAvailable( player ) ) && GetPlayerBatteryCount( player ) > 0 ) return false } // idk why the powerup.destroyFunc doesn't just return a bool? would mean they could just handle stuff like this in powerup code powerup.destroyFunc( player ) return true // destroys the powerup } return false // keeps powerup alive }