class AreaExposureMdfr: ModifierBase { const int EVENT_1_INTERVAL_MIN = 3; const int EVENT_1_INTERVAL_MAX = 5; const float AGENTS_PER_SEC = 5; protected float m_NextEvent1; protected float m_Time1; const int EVENT_2_INTERVAL_MIN = 13; const int EVENT_2_INTERVAL_MAX = 18; const float AGENT_DOSE_PER_BS_SEC = 0.33;//how many agents will be injected in one sec per a single bleeding source protected float m_NextEvent2; protected float m_Time2; override void Init() { m_TrackActivatedTime = false; m_AnalyticsStatsEnabled = true; m_ID = eModifiers.MDF_AREAEXPOSURE; m_TickIntervalInactive = DEFAULT_TICK_TIME_INACTIVE_LONG; m_TickIntervalActive = DEFAULT_TICK_TIME_ACTIVE_SHORT; m_SyncID = eModifierSyncIDs.MODIFIER_SYNC_ZONE_EXPOSURE; DisableActivateCheck(); DisableDeactivateCheck(); } override bool ActivateCondition(PlayerBase player) { return false; } override void OnActivate(PlayerBase player) { JsonDataContaminatedAreas data = EffectAreaLoader.GetData(); if (data) { MiscGameplayFunctions.TeleportCheck(player, data.SafePositions); player.SetPersistentFlag(PersistentFlag.AREA_PRESENCE, false); } //make the player cough immediately float transmitted = TransmitAgents(player, 1); if(transmitted) player.GetSymptomManager().QueueUpPrimarySymptom(SymptomIDs.SYMPTOM_COUGH); m_NextEvent1 = Math.RandomFloatInclusive( EVENT_1_INTERVAL_MIN, EVENT_1_INTERVAL_MAX ); } override void OnDeactivate(PlayerBase player) { } override bool DeactivateCondition(PlayerBase player) { return false; } override void OnTick(PlayerBase player, float deltaT) { #ifdef DEVELOPER if(!player.GetCanBeDestroyed()) return; #endif float transmitted = TransmitAgents(player, AGENTS_PER_SEC * deltaT); m_Time2 += deltaT; if (transmitted) { m_Time1 += deltaT; if (m_Time1 >= m_NextEvent1 ) { player.GetSymptomManager().QueueUpPrimarySymptom(SymptomIDs.SYMPTOM_COUGH); if(Math.RandomFloat01() < 0.25)//creates a cough cooldown once in a while { m_NextEvent1 = Math.RandomFloatInclusive( EVENT_1_INTERVAL_MIN * 2, EVENT_1_INTERVAL_MAX * 2 ); } else { m_NextEvent1 = Math.RandomFloatInclusive( EVENT_1_INTERVAL_MIN, EVENT_1_INTERVAL_MAX ); } m_Time1 = 0; } } if ( m_Time2 >= m_NextEvent2 ) { BleedingSourceCreateCheck(player); m_Time2 = 0; m_NextEvent2 = Math.RandomFloatInclusive( EVENT_2_INTERVAL_MIN, EVENT_2_INTERVAL_MAX ); } ApplyAgentsToBleedingSources(player, deltaT); } void ApplyAgentsToBleedingSources(PlayerBase player, float deltaT) { int count = player.GetBleedingSourceCount(); float agent_dose = count * AGENT_DOSE_PER_BS_SEC * deltaT; player.InsertAgent(eAgents.CHEMICAL_POISON, agent_dose); } void BleedingSourceCreateCheck(PlayerBase player) { int free_bs_locations = 0;//bitmask where each bit set to 1 represents available bleeding source location set list = player.GetBleedingManagerServer().GetBleedingSourcesLocations(); foreach(int location: list) { float prot_level = PluginTransmissionAgents.GetProtectionLevelEx(DEF_CHEMICAL, location, player, true); float dice_throw = Math.RandomFloat01(); if(dice_throw > prot_level) { free_bs_locations = player.GetBleedingManagerServer().GetFreeBleedingSourceBitsByInvLocation(location) | free_bs_locations; } } int num_of_free_bs = Math.GetNumberOfSetBits(free_bs_locations);//gets us the number of bits set to 1, where each represents a free bleeding source location if ( num_of_free_bs > 0 ) { int random_bs_index = Math.RandomIntInclusive(0, num_of_free_bs - 1 );// - 1 on the max to convert count to index int random_bs_bit = Math.Pow(2, Math.GetNthBitSet(free_bs_locations,random_bs_index)); player.GetBleedingManagerServer().AttemptAddBleedingSourceDirectly(random_bs_bit, eBleedingSourceType.CONTAMINATED); } } float TransmitAgents(PlayerBase player, float count) { PluginTransmissionAgents plugin = PluginTransmissionAgents.Cast(GetPlugin(PluginTransmissionAgents)); return plugin.TransmitAgentsEx(null, player, AGT_AIRBOURNE_CHEMICAL, count, eAgents.CHEMICAL_POISON); } };