untyped global function AiMarvins_Init function AiMarvins_Init() { FlagInit( "Disable_Marvins" ) FlagSet( "Disable_Marvins" ) level.livingMarvins <- {} AddSpawnCallback( "npc_marvin", LivingMarvinSpawned ) AddCallback_EntitiesDidLoad( EntitiesDidLoad ) } void function EntitiesDidLoad() { if ( IsAutoPopulateEnabled() == false ) return FlagEnd( "disable_npcs" ) array marvin_spawners = GetEntArrayByClass_Expensive( "info_spawnpoint_marvin" ) if ( !marvin_spawners.len() ) return for ( ;; ) { wait 3 if ( !Flag( "Disable_Marvins" ) ) { if ( TotalLivingMarvins() < 5 ) { SpawnRandomMarvin( marvin_spawners ) } } } } void function LivingMarvinSpawned( entity self ) { level.livingMarvins[ self ] <- self } function TotalLivingMarvins() { local count = 0 foreach ( entity marvin in clone level.livingMarvins ) { if ( IsAlive( marvin ) ) { count++ continue } // cleanup dead marvins delete level.livingMarvins[ marvin ] } return count } entity function SpawnRandomMarvin( array marvin_spawners ) { marvin_spawners.randomize() entity spawnpoint = marvin_spawners[0] // if no valid spawn is found use this one for ( int i = 0; i < marvin_spawners.len(); i++ ) { if ( IsMarvinSpawnpointValid( marvin_spawners[ i ] ) ) { spawnpoint = marvin_spawners[ i ] break } } entity marvin = SpawnAmbientMarvin( spawnpoint ) return marvin } bool function IsMarvinSpawnpointValid( entity spawnpoint ) { // ensure spawnpoint is not occupied (i.e. would spawn inside another player or object ) if ( spawnpoint.IsOccupied() ) return false bool visible = spawnpoint.IsVisibleToEnemies( TEAM_IMC ) || spawnpoint.IsVisibleToEnemies( TEAM_MILITIA ) if ( visible ) return false return true } entity function SpawnAmbientMarvin( entity spawnpoint ) { entity npc_marvin = CreateEntity( "npc_marvin" ) SetTargetName( npc_marvin, UniqueString( "mp_random_marvin") ) npc_marvin.SetOrigin( spawnpoint.GetOrigin() ) npc_marvin.SetAngles( spawnpoint.GetAngles() ) //npc_marvin.kv.rendercolor = "255 255 255" npc_marvin.kv.health = -1 npc_marvin.kv.max_health = -1 npc_marvin.kv.spawnflags = 516 // Fall to ground, Fade Corpse //npc_marvin.kv.FieldOfView = 0.5 //npc_marvin.kv.FieldOfViewAlert = 0.2 npc_marvin.kv.AccuracyMultiplier = 1.0 npc_marvin.kv.physdamagescale = 1.0 npc_marvin.kv.WeaponProficiency = eWeaponProficiency.GOOD Marvin_SetModels( npc_marvin, spawnpoint ) DispatchSpawn( npc_marvin ) SetTeam( npc_marvin, TEAM_UNASSIGNED ) return npc_marvin } function Marvin_SetModels( entity npc_marvin, entity spawnpoint ) { //default npc_marvin.s.bodytype <- MARVIN_TYPE_WORKER // set body and head based on KVP if ( spawnpoint.HasKey( "bodytype" ) ) { local bodytype = spawnpoint.GetValueForKey( "bodytype" ).tointeger() Assert( bodytype >= MARVIN_TYPE_SHOOTER && bodytype <= MARVIN_TYPE_FIREFIGHTER, "Specified invalid body type index " + bodytype + " for info_spawnpoint_marvin " + spawnpoint + ", Use values from 0-2 instead." ) npc_marvin.s.bodytype = bodytype } if ( spawnpoint.HasKey( "headtype" ) ) { local headtype = spawnpoint.GetValueForKey( "headtype" ) npc_marvin.kv.body = headtype } }