/// <summary> /// Handles LifeSupport, Consumables, and EVA LifeSupport drain on startup /// </summary> private void StartupMain() { bool skip_startup_request = false; showed_eva_warning = false; // Check if this ship belongs to a Rescue contract // and has not been set up with LifeSupport for (int i = 0; i < ContractChecker.Guids.Count; i++) { string contract_guid = ContractChecker.Guids[i]; if (part.flightID.ToString() == ContractChecker.GetPartID(contract_guid)) { Util.Log("For Contract GUID: " + contract_guid); Util.Log("Found PartID " + part.flightID + ", skipping startup request for " + vessel.name); // Remove guid from tracking, vessel will only transition to Owned once ContractChecker.Guids.Remove(contract_guid); part.Resources[C.NAME_LIFESUPPORT].amount = part.Resources[C.NAME_LIFESUPPORT].maxAmount / 2.0; skip_startup_request = true; break; } } double seconds_remaining = 0; // -- 1. Request primary LifeSupport resource and capture seconds unaccounted for -- if (!skip_startup_request) { // Use the seconds remaining to calculate how much EVA LifeSupport needs to be deducted seconds_remaining = Util.StartupRequest(this, C.NAME_LIFESUPPORT, C.LS_DRAIN_PER_SEC); } // Return early to avoid scanning all the parts // Just make sure all Kerbals are in tracking before exit, // otherwise this is taken care of in section 3 if (seconds_remaining < C.DOUBLE_MARGIN) { foreach (ProtoCrewMember kerbal in part.protoModuleCrew) { EVALifeSupportTracker.AddKerbalToTracking(kerbal.name); } return; } // -- 2. Deduct from Consumables if vessel has Converter -- bool has_manned_converter = false; List <Cons2LSModule> consParts = vessel.FindPartModulesImplementing <Cons2LSModule>(); foreach (Cons2LSModule converter in consParts) { if (converter.IsOperational()) { has_manned_converter = true; break; } } // Found Converter, convert Consumables. // Ignore ElectricCharge here. Too many escapes re. capacity, // charge rate, LOS to sun, etc. Assume Kerbals have been // converting slowly while player is away. if (has_manned_converter) { double cons_over_lifesupport = C.CONV_CONS_PER_SEC / C.CONV_LS_PER_SEC; double cons_per_sec = C.LS_DRAIN_PER_SEC * cons_over_lifesupport; // Initial Consumables request for time passed double request = seconds_remaining * cons_per_sec * part.protoModuleCrew.Count; double frac_obtained = part.RequestResource(C.NAME_CONSUMABLES, request) / request; seconds_remaining *= (1 - frac_obtained); // Now add a bit more LifeSupport double cons_extra_request = C.AUTO_LS_REFILL_EXTRA * cons_over_lifesupport * part.protoModuleCrew.Count; double frac_extra_obtained = part.RequestResource(C.NAME_CONSUMABLES, cons_extra_request) / cons_extra_request; part.RequestResource(C.NAME_LIFESUPPORT, -C.AUTO_LS_REFILL_EXTRA * frac_extra_obtained, C.FLOWMODE_LIFESUPPORT); } // -- 3. Finally, deduct from EVA LifeSupport -- double eva_diff = seconds_remaining * C.EVA_LS_DRAIN_PER_SEC; Util.Log(seconds_remaining + " seconds remaining for " + vessel.vesselName); if (seconds_remaining < C.DOUBLE_MARGIN) { eva_diff = 0; } Util.Log("Deducting " + eva_diff + " " + C.NAME_EVA_LIFESUPPORT); foreach (ProtoCrewMember kerbal in part.protoModuleCrew) { // If Kerbal isn't yet in tracking (i.e. mod was just installed), // add EVA LifeSupport but don't deduct anything. That seems unfair. if (!EVALifeSupportTracker.InTracking(kerbal.name)) { EVALifeSupportTracker.AddKerbalToTracking(kerbal.name); continue; } // Current EVA LifeSupport after draining from tracking double current = EVALifeSupportTracker.AddEVAAmount(kerbal.name, -eva_diff, EVA_Resource.LifeSupport); if (current < C.KILL_BUFFER) { EVALifeSupportTracker.SetCurrentAmount(kerbal.name, C.KILL_BUFFER, EVA_Resource.LifeSupport); } else if (current < C.EVA_LS_30_SECONDS) { Util.PostUpperMessage(kerbal.name + " has " + (int)(current / C.EVA_LS_DRAIN_PER_SEC) + " seconds to live!", 1); } // If Kerbal is about to die, messages will already be printed. // Don't clutter the screen with the "now on EVA LS" message too. if (current < C.EVA_LS_30_SECONDS) { showed_eva_warning = true; } } }
public override void OnStart(StartState state) { Util.Log("EVALifeSupportModule OnStart()"); // Check if EVA Kerbal has exactly one ProtoCrewMember if (part.protoModuleCrew.Count == 0) { string msg = "0 PMCs found in EVA Kerbal: " + part.name; Util.Log(msg); throw new IndexOutOfRangeException(msg); } else if (part.protoModuleCrew.Count > 1) { Util.Log("Weird...multiple PMCs found in EVA Kerbal: " + part.name); } // To avoid conflicts with Unity variable "name" string kerbal_name = part.protoModuleCrew[0].name; PartResource ls_resource = null; foreach (PartResource pr in part.Resources) { if (pr.resourceName == C.NAME_EVA_LIFESUPPORT) { ls_resource = pr; break; } } // Kerbals assigned after this mod's installation should already be tracked, // but for Kerbals already in flight, add EVA LS according to current state // of astronaut complex EVALifeSupportTracker.AddKerbalToTracking(kerbal_name); if (ls_resource == null) { // If not found, add EVA LS resource to this PartModule. Util.Log("Adding " + C.NAME_EVA_LIFESUPPORT + " resource to " + part.name); var info = EVALifeSupportTracker.GetEVALSInfo(kerbal_name); ConfigNode resource_node = new ConfigNode("RESOURCE"); resource_node.AddValue("name", C.NAME_EVA_LIFESUPPORT); resource_node.AddValue("amount", info.ls_current.ToString()); resource_node.AddValue("maxAmount", info.ls_max.ToString()); ls_resource = part.AddResource(resource_node); Util.Log("Added EVA LS resource to " + part.name); } else { // If found, this EVA is already active - deduct LS. Util.StartupRequest(this, C.NAME_EVA_LIFESUPPORT, C.EVA_LS_DRAIN_PER_SEC); if (ls_resource.amount < C.KILL_BUFFER) { ls_resource.amount = C.KILL_BUFFER; } else if (ls_resource.amount < C.EVA_LS_30_SECONDS) { Util.PostUpperMessage(kerbal_name + " has " + (int)(ls_resource.amount / C.EVA_LS_DRAIN_PER_SEC) + " seconds to live!", 1); } } PartResource prop_resource = part.Resources[C.NAME_EVA_PROPELLANT]; // Necessary to override game's default behavior, which refills // EVA Propellant automatically every time EVA Kerbal is reset var eva_info = EVALifeSupportTracker.GetEVALSInfo(kerbal_name); prop_resource.maxAmount = eva_info.prop_max; prop_resource.amount = eva_info.prop_current; // Will this add safety Propellant on every load? // Should only be added when Kerbal first leaves ship // // Confirmed (1.0.5). At the time of this comment, the Propellant // threshold is brutally low (0.1), so it's okay, // but this should be changed in the future. if (prop_resource.amount < C.EVA_PROP_SAFE_MIN) { prop_resource.amount = C.EVA_PROP_SAFE_MIN; } // If difficulty option "Immediate Level Up" is selected, // immediately set this Kerbal's EVA to new max if (this.vessel.CanUpdateEVAStat(Config.EVA_MAX_UPDATE)) { ls_resource.maxAmount = Util.MaxAllowedEVA(EVA_Resource.LifeSupport); prop_resource.maxAmount = Util.MaxAllowedEVA(EVA_Resource.Propellant); } base.OnStart(state); }