예제 #1
0
        public static void BackgroundUpdate(Vessel v, ProtoPartModuleSnapshot m, Reliability reliability, double elapsed_s)
        {
            // if it has not malfunctioned
            if (Lib.Proto.GetUInt(m, "malfunctions") < 2)
            {
                // get epoch
                double epoch = Lib.Proto.GetDouble(m, "epoch");

                // calculate epoch of failure if necessary
                if (epoch <= double.Epsilon)
                {
                    double quality = Lib.Proto.GetDouble(m, "quality", 1.0);
                    double start   = Planetarium.GetUniversalTime();
                    epoch = start + reliability.mtbf * quality * 2.0 * Lib.RandomDouble();
                    Lib.Proto.Set(m, "start", start);
                    Lib.Proto.Set(m, "epoch", epoch);
                }

                // if it has failed, trigger malfunction
                if (Planetarium.GetUniversalTime() > epoch)
                {
                    Break(v, m);
                }
            }
        }
예제 #2
0
        static void ProcessGenerator(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleGenerator generator, vessel_resources resources, double elapsed_s)
        {
            // play nice with BackgroundProcessing
            if (Kerbalism.detected_mods.BackgroundProcessing)
            {
                return;
            }

            // if active
            if (Lib.Proto.GetBool(m, "generatorIsActive"))
            {
                // get malfunction penalty
                double penalty = Reliability.Penalty(p, "Generator");

                // create and commit recipe
                resource_recipe recipe = new resource_recipe(resource_recipe.converter_priority);
                foreach (var ir in generator.inputList)
                {
                    recipe.Input(ir.name, ir.rate * elapsed_s);
                }
                foreach (var or in generator.outputList)
                {
                    recipe.Output(or.name, or.rate * penalty * elapsed_s);
                }
                resources.Transform(recipe);
            }
        }
예제 #3
0
        static void ProcessHarvester(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceHarvester harvester, vessel_resources resources, double elapsed_s)
        {
            // note: ignore stock temperature mechanic of harvesters
            // note: ignore autoshutdown
            // note: ignore depletion (stock seem to do the same)
            // note: using hard-coded crew bonus values from the wiki because the module data make zero sense (DERP ALERT)
            // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)

            // if active
            if (Lib.Proto.GetBool(m, "IsActivated"))
            {
                // do nothing if full
                // note: comparing against previous amount
                if (resources.Info(v, harvester.ResourceName).level < harvester.FillAmount - double.Epsilon)
                {
                    // get malfunction penalty
                    double penalty = Reliability.Penalty(p, "Harvester");

                    // deduce crew bonus
                    int exp_level = -1;
                    if (harvester.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in v.protoVessel.GetVesselCrew())
                        {
                            exp_level = Math.Max(exp_level, c.trait == harvester.Specialty ? c.experienceLevel : -1);
                        }
                    }
                    double exp_bonus = exp_level < 0 ? 1.0 : 5.0 + (double)exp_level * 4.0;

                    // detect amount of ore in the ground
                    AbundanceRequest request = new AbundanceRequest
                    {
                        Altitude     = v.altitude,
                        BodyId       = v.mainBody.flightGlobalsIndex,
                        CheckForLock = false,
                        Latitude     = v.latitude,
                        Longitude    = v.longitude,
                        ResourceType = (HarvestTypes)harvester.HarvesterType,
                        ResourceName = harvester.ResourceName
                    };
                    double abundance = ResourceMap.Instance.GetAbundance(request);

                    // if there is actually something (should be if active when unloaded)
                    if (abundance > harvester.HarvestThreshold)
                    {
                        // create and commit recipe
                        resource_recipe recipe = new resource_recipe(resource_recipe.harvester_priority);
                        foreach (var ir in harvester.inputList)
                        {
                            recipe.Input(ir.ResourceName, ir.Ratio * elapsed_s);
                        }
                        recipe.Output(harvester.ResourceName, abundance * harvester.Efficiency * exp_bonus * penalty * elapsed_s);
                        resources.Transform(recipe);
                    }
                }

                // undo stock behaviour by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #4
0
        public ReliabilityInfo(ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Reliability module_prefab)
        {
            title            = Lib.BuildString(p.partInfo.title, Lib.Color(" " + module_prefab.title, Lib.Kolor.LightGrey));
            group            = module_prefab.redundancy;
            broken           = Lib.Proto.GetBool(m, "broken", false);
            critical         = Lib.Proto.GetBool(m, "critical", false);
            partId           = 0;
            need_maintenance = Lib.Proto.GetBool(m, "need_maintenance", false);

            bool quality = Lib.Proto.GetBool(m, "quality", false);

            if (module_prefab.rated_operation_duration > 0)
            {
                var operation_duration = Lib.Proto.GetDouble(m, "operation_duration", 0);
                rel_duration = operation_duration / Reliability.EffectiveDuration(quality, module_prefab.rated_operation_duration);
                rel_duration = Lib.Clamp(rel_duration, 0, 1);
            }

            if (module_prefab.rated_ignitions > 0)
            {
                var ignitions = Lib.Proto.GetInt(m, "ignitions", 0);
                rel_ignitions = (double)ignitions / Reliability.EffectiveDuration(quality, module_prefab.rated_ignitions);
                rel_ignitions = Lib.Clamp(rel_ignitions, 0, 1);
            }

            mtbf = Reliability.EffectiveMTBF(quality, module_prefab.mtbf);

            if (mtbf > 0)
            {
                var last_inspection = Lib.Proto.GetDouble(m, "last_inspection", 0);
                maintenance_after = last_inspection + mtbf * 0.5;
            }
        }
예제 #5
0
        public ReliabilityInfo(Reliability module)
        {
            title            = Lib.BuildString(module.part.partInfo.title, Lib.Color(" " + module.title, Lib.Kolor.LightGrey));
            group            = module.redundancy;
            broken           = module.broken;
            critical         = module.critical;
            partId           = module.part.flightID;
            need_maintenance = module.needMaintenance;
            mtbf             = Reliability.EffectiveMTBF(module.quality, module.mtbf);

            if (module.rated_operation_duration > 0)
            {
                rel_duration = module.operation_duration / Reliability.EffectiveDuration(module.quality, module.rated_operation_duration);
                rel_duration = Lib.Clamp(rel_duration, 0, 1);
            }

            if (module.rated_ignitions > 0)
            {
                rel_ignitions = (double)module.ignitions / Reliability.EffectiveIgnitions(module.quality, module.rated_ignitions);
                rel_ignitions = Lib.Clamp(rel_ignitions, 0, 1);
            }

            if (mtbf > 0)
            {
                maintenance_after = module.last_inspection + mtbf * 0.5;
            }
        }
예제 #6
0
  // implement gravity ring mechanics for unloaded vessels
  public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, GravityRing ring, vessel_resources resources, double elapsed_s)
  {
    // get protomodule data
    float speed = Lib.Proto.GetFloat(m, "speed");

    // get resource handler
    resource_info ec = resources.Info(vessel, "ElectricCharge");

    // consume ec
    ec.Consume(ring.ec_rate * speed * elapsed_s * Reliability.Penalty(p, "GravityRing", 2.0));

    // reset speed if there isn't enough ec
    // note: comparing against amount in previous simulation step
    if (ec.amount <= double.Epsilon)
    {
      speed = 0.0f;
      Lib.Proto.Set(m, "speed", speed);
    }

    // set entertainment
    // note: entertainmnent is only recomputed for loaded vessels,
    // so changing rate here does nothing until vessel is reloaded
    double rate = 1.0 + (ring.entertainment_rate - 1.0) * speed;
    Lib.Proto.Set(m, "rate", rate);
  }
예제 #7
0
        public void Quality()
        {
            quality = !quality;

            // sync all other modules in the symmetry group
            foreach (Part p in part.symmetryCounterparts)
            {
                Reliability reliability = p.Modules[part.Modules.IndexOf(this)] as Reliability;
                if (reliability != null)
                {
                    reliability.quality = !reliability.quality;
                }
            }

            // refresh VAB ui
            GameEvents.onEditorShipModified.Fire(EditorLogic.fetch.ship);
        }
예제 #8
0
파일: Emitter.cs 프로젝트: zajc3w/Kerbalism
  public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Emitter emitter, resource_info ec, double elapsed_s)
  {
    // if there is enough EC
    // note: comparing against amount in previous simulation step
    if (ec.amount > double.Epsilon)
    {
      // get intensity
      double intensity = Lib.Proto.GetDouble(m, "intensity");

      // consume EC
      ec.Consume(emitter.ec_rate * intensity * elapsed_s * Reliability.Penalty(p, "Emitter", 2.0));
    }
    // else disable it
    else
    {
      Lib.Proto.Set(m, "intensity", 0.0);
    }
  }
예제 #9
0
        // cause a part at random to malfunction
        public static void CauseMalfunction(Vessel v)
        {
            // if vessel is loaded
            if (v.loaded)
            {
                // choose a module at random
                var modules = v.FindPartModulesImplementing <Reliability>();
                if (modules.Count == 0)
                {
                    return;
                }
                var m = modules[Lib.RandomInt(modules.Count)];

                // break it
                m.Break();
            }
            // if vessel is not loaded
            else
            {
                // get all reliability modules
                var modules = new List <KeyValuePair <ProtoPartSnapshot, ProtoPartModuleSnapshot> >();
                foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
                {
                    foreach (ProtoPartModuleSnapshot m in p.modules)
                    {
                        if (m.moduleName == "Reliability")
                        {
                            modules.Add(new KeyValuePair <ProtoPartSnapshot, ProtoPartModuleSnapshot>(p, m));
                        }
                    }
                }

                // choose one at random
                if (modules.Count == 0)
                {
                    return;
                }
                var pair = modules[Lib.RandomInt(modules.Count)];

                // break it
                Reliability.Break(v, pair.Value);
            }
        }
예제 #10
0
        private void EvaluateStatus()
        {
            UnityEngine.Profiling.Profiler.BeginSample("Kerbalism.VesselData.EvaluateStatus");
            // determine if there is enough EC for a powered state
            powered = Lib.IsPowered(Vessel);

            // calculate crew info for the vessel
            crewCount    = Lib.CrewCount(Vessel);
            crewCapacity = Lib.CrewCapacity(Vessel);

            // malfunction stuff
            malfunction = Reliability.HasMalfunction(Vessel);
            critical    = Reliability.HasCriticalFailure(Vessel);

            // communications info
            connection = ConnectionInfo.Update(Vessel, powered, EnvBlackout);

            // habitat data
            habitatInfo.Update(Vessel);
            volume   = Habitat.Tot_volume(Vessel);
            surface  = Habitat.Tot_surface(Vessel);
            pressure = Math.Min(Habitat.Pressure(Vessel), habitatInfo.MaxPressure);

            evas          = (uint)(Math.Max(0, ResourceCache.GetResource(Vessel, "Nitrogen").Amount - 330) / Settings.LifeSupportAtmoLoss);
            poisoning     = Habitat.Poisoning(Vessel);
            shielding     = Habitat.Shielding(Vessel);
            livingSpace   = Habitat.Living_space(Vessel);
            volumePerCrew = Habitat.Volume_per_crew(Vessel);
            comforts      = new Comforts(Vessel, EnvLanded, crewCount > 1, connection.linked && connection.rate > double.Epsilon);

            // data about greenhouses
            greenhouses = Greenhouse.Greenhouses(Vessel);

            Drive.GetCapacity(this, out drivesFreeSpace, out drivesCapacity);

            // solar panels data
            if (Vessel.loaded)
            {
                solarPanelsAverageExposure = SolarPanelFixer.GetSolarPanelsAverageExposure(solarPanelsExposure);
                solarPanelsExposure.Clear();
            }
            UnityEngine.Profiling.Profiler.EndSample();
        }
예제 #11
0
파일: Monitor.cs 프로젝트: zajc3w/Kerbalism
 GUIContent indicator_reliability(Vessel v, vessel_info vi)
 {
   GUIContent state = new GUIContent();
   uint max_malfunctions = vi.max_malfunction;
   if (max_malfunctions == 0)
   {
     state.image = icon_malfunction_nominal;
     state.tooltip = "No malfunctions";
   }
   else if (max_malfunctions == 1)
   {
     state.image = icon_malfunction_warning;
     state.tooltip = "Minor malfunctions";
   }
   else
   {
     state.image = icon_malfunction_danger;
     state.tooltip = "Major malfunctions";
   }
   if (vi.avg_quality > 0.0) state.tooltip += Lib.BuildString("\n<i>Quality: ", Reliability.QualityToString(vi.avg_quality), "</i>");
   return state;
 }
예제 #12
0
        static void ProcessPanel(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleDeployableSolarPanel panel, vessel_info info, resource_info ec, double elapsed_s)
        {
            // note: we ignore temperature curve, and make sure it is not relavant in the MM patch
            // note: we ignore power curve, that is used by no panel as far as I know

            // play nice with BackgroundProcessing
            if (Kerbalism.detected_mods.BackgroundProcessing)
            {
                return;
            }

            // if in sunlight and extended
            if (info.sunlight > double.Epsilon && m.moduleValues.GetValue("stateString") == "EXTENDED")
            {
                // get panel normal direction
                Vector3d normal = panel.part.FindModelComponent <Transform>(panel.raycastTransformName).forward;

                // calculate cosine factor
                // note: for gameplay reasons, we ignore tracking panel pivots
                // note: a possible optimization here is to cache the transform lookup (unity was coded by monkeys)
                double cosine_factor = panel.sunTracking ? 1.0 : Math.Max(Vector3d.Dot(info.sun_dir, (v.transform.rotation * p.rotation * normal).normalized), 0.0);

                // calculate normalized solar flux
                // note: this include fractional sunlight if integrated over orbit
                // note: this include atmospheric absorption if inside an atmosphere
                double norm_solar_flux = info.solar_flux / Sim.SolarFluxAtHome();

                // calculate output
                double output = panel.chargeRate                            // nominal panel charge rate at 1 AU
                                * norm_solar_flux                           // normalized flux at panel distance from sun
                                * cosine_factor                             // cosine factor of panel orientation
                                * Reliability.Penalty(p, "Panel");          // malfunctioned panel penalty

                // produce EC
                ec.Produce(output * elapsed_s);
            }
        }
예제 #13
0
        static void Incentive_redundancy(Vessel v, string redundancy)
        {
            if (v.loaded)
            {
                foreach (Reliability m in Lib.FindModules <Reliability>(v))
                {
                    if (m.redundancy == redundancy)
                    {
                        m.next += m.next - m.last;
                    }
                }
            }
            else
            {
                foreach (ProtoPartModuleSnapshot m in Lib.FindModules(v.protoVessel, "Reliability"))
                {
                    // find part
                    ProtoPartSnapshot p = v.protoVessel.protoPartSnapshots.Find(k => k.modules.Contains(m));

                    // find module prefab
                    string      type        = Lib.Proto.GetString(m, "type", string.Empty);
                    Reliability reliability = p.partPrefab.FindModulesImplementing <Reliability>().Find(k => k.type == type);
                    if (reliability == null)
                    {
                        continue;
                    }

                    // double time to next failure
                    if (reliability.redundancy == redundancy)
                    {
                        double last = Lib.Proto.GetDouble(m, "last");
                        double next = Lib.Proto.GetDouble(m, "next");
                        Lib.Proto.Set(m, "next", next + (next - last));
                    }
                }
            }
        }
예제 #14
0
        // trigger a random breakdown event
        public static void Breakdown(Vessel v, ProtoCrewMember c)
        {
            // constants
            const double res_penalty = 0.1; // proportion of food lost on 'depressed' and 'wrong_valve'

            // get info
            Rule          supply = supply_rules.Count > 0 ? supply_rules[Lib.RandomInt(supply_rules.Count)] : null;
            resource_info res    = supply != null?ResourceCache.Info(v, supply.resource_name) : null;

            // compile list of events with condition satisfied
            List <KerbalBreakdown> events = new List <KerbalBreakdown>();

            events.Add(KerbalBreakdown.mumbling); //< do nothing, here so there is always something that can happen
            if (Lib.CrewCount(v) > 1)
            {
                events.Add(KerbalBreakdown.argument);               //< do nothing, add some variation to messages
            }
            if (Lib.HasData(v))
            {
                events.Add(KerbalBreakdown.fat_finger);
            }
            if (Reliability.CanMalfunction(v))
            {
                events.Add(KerbalBreakdown.rage);
            }
            if (supply != null && res.amount > double.Epsilon)
            {
                events.Add(KerbalBreakdown.depressed);
                events.Add(KerbalBreakdown.wrong_valve);
            }

            // choose a breakdown event
            KerbalBreakdown breakdown = events[Lib.RandomInt(events.Count)];

            // generate message
            string text    = "";
            string subtext = "";

            switch (breakdown)
            {
            case KerbalBreakdown.mumbling:    text = "$ON_VESSEL$KERBAL has been in space for too long"; subtext = "Mumbling incoherently"; break;

            case KerbalBreakdown.argument:    text = "$ON_VESSEL$KERBAL had an argument with the rest of the crew"; subtext = "Morale is degenerating at an alarming rate"; break;

            case KerbalBreakdown.fat_finger:  text = "$ON_VESSEL$KERBAL is pressing buttons at random on the control panel"; subtext = "Science data has been lost"; break;

            case KerbalBreakdown.rage:        text = "$ON_VESSEL$KERBAL is possessed by a blind rage"; subtext = "A component has been damaged"; break;

            case KerbalBreakdown.depressed:   text = "$ON_VESSEL$KERBAL is not respecting the rationing guidelines"; subtext = supply.resource_name + " has been lost"; break;

            case KerbalBreakdown.wrong_valve: text = "$ON_VESSEL$KERBAL opened the wrong valve"; subtext = supply.resource_name + " has been lost"; break;
            }

            // post message first so this one is shown before malfunction message
            Message.Post(Severity.breakdown, Lib.ExpandMsg(text, v, c), subtext);

            // trigger the event
            switch (breakdown)
            {
            case KerbalBreakdown.mumbling: break; // do nothing

            case KerbalBreakdown.argument: break; // do nothing

            case KerbalBreakdown.fat_finger: Lib.RemoveData(v); break;

            case KerbalBreakdown.rage: Reliability.CauseMalfunction(v); break;

            case KerbalBreakdown.depressed:
            case KerbalBreakdown.wrong_valve: res.Consume(res.amount * res_penalty); break;
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-Settings.BreakdownReputationPenalty, TransactionReasons.Any);
            }
        }
예제 #15
0
        public static void update(Vessel v, vessel_info vi, VesselData vd, vessel_resources resources, double elapsed_s)
        {
            // get most used resource handlers
            resource_info ec = resources.Info(v, "ElectricCharge");

            // store data required to support multiple modules of same type in a part
            var PD = new Dictionary <string, Lib.module_prefab_data>();

            // for each part
            foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
            {
                // get part prefab (required for module properties)
                Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                // get all module prefabs
                var module_prefabs = part_prefab.FindModulesImplementing <PartModule>();

                // clear module indexes
                PD.Clear();

                // for each module
                foreach (ProtoPartModuleSnapshot m in p.modules)
                {
                    // get module type
                    // if the type is unknown, skip it
                    module_type type = ModuleType(m.moduleName);
                    if (type == module_type.Unknown)
                    {
                        continue;
                    }

                    // get the module prefab
                    // if the prefab doesn't contain this module, skip it
                    PartModule module_prefab = Lib.ModulePrefab(module_prefabs, m.moduleName, PD);
                    if (!module_prefab)
                    {
                        continue;
                    }

                    // if the module is disabled, skip it
                    // note: this must be done after ModulePrefab is called, so that indexes are right
                    if (!Lib.Proto.GetBool(m, "isEnabled"))
                    {
                        continue;
                    }

                    // process modules
                    // note: this should be a fast switch, possibly compiled to a jump table
                    switch (type)
                    {
                    case module_type.Reliability:           Reliability.BackgroundUpdate(v, p, m, module_prefab as Reliability);                        break;

                    case module_type.Experiment:            Experiment.BackgroundUpdate(v, m, module_prefab as Experiment, ec, elapsed_s);              break;

                    case module_type.Greenhouse:            Greenhouse.BackgroundUpdate(v, m, module_prefab as Greenhouse, vi, resources, elapsed_s);   break;

                    case module_type.GravityRing:           GravityRing.BackgroundUpdate(v, p, m, module_prefab as GravityRing, ec, elapsed_s);         break;

                    case module_type.Emitter:               Emitter.BackgroundUpdate(v, p, m, module_prefab as Emitter, ec, elapsed_s);                 break;

                    case module_type.Harvester:             Harvester.BackgroundUpdate(v, m, module_prefab as Harvester, elapsed_s);                    break;

                    case module_type.Laboratory:            Laboratory.BackgroundUpdate(v, p, m, module_prefab as Laboratory, ec, elapsed_s);           break;

                    case module_type.Command:               ProcessCommand(v, p, m, module_prefab as ModuleCommand, resources, elapsed_s);              break;

                    case module_type.Panel:                 ProcessPanel(v, p, m, module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s);      break;

                    case module_type.Generator:             ProcessGenerator(v, p, m, module_prefab as ModuleGenerator, resources, elapsed_s);          break;

                    case module_type.Converter:             ProcessConverter(v, p, m, module_prefab as ModuleResourceConverter, resources, elapsed_s);  break;

                    case module_type.Drill:                 ProcessHarvester(v, p, m, module_prefab as ModuleResourceHarvester, resources, elapsed_s);  break;

                    case module_type.AsteroidDrill:         ProcessAsteroidDrill(v, p, m, module_prefab as ModuleAsteroidDrill, resources, elapsed_s);  break;

                    case module_type.StockLab:              ProcessStockLab(v, p, m, module_prefab as ModuleScienceConverter, ec, elapsed_s);           break;

                    case module_type.Light:                 ProcessLight(v, p, m, module_prefab as ModuleLight, ec, elapsed_s);                         break;

                    case module_type.Scanner:               ProcessScanner(v, p, m, module_prefab, part_prefab, vd, ec, elapsed_s);                     break;

                    case module_type.CurvedPanel:           ProcessCurvedPanel(v, p, m, module_prefab, part_prefab, vi, ec, elapsed_s);                 break;

                    case module_type.FissionGenerator:      ProcessFissionGenerator(v, p, m, module_prefab, ec, elapsed_s);                             break;

                    case module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, p, m, module_prefab, ec, elapsed_s);                        break;

                    case module_type.CryoTank:              ProcessCryoTank(v, p, m, module_prefab, resources, elapsed_s);                              break;
                    }
                }
            }
        }
예제 #16
0
        public Vessel_info(Vessel v, UInt64 vessel_id, UInt64 inc)
        {
            // NOTE: anything used here can't in turn use cache, unless you know what you are doing

            // NOTE: you can't cache vessel position
            // at any point in time all vessel/body positions are relative to a different frame of reference
            // so comparing the current position of a vessel, with the cached one of another make no sense

            // associate with an unique incremental id
            this.inc = inc;

            // determine if this is a valid vessel
            is_vessel = Lib.IsVessel(v);
            if (!is_vessel)
            {
                return;
            }

            // determine if this is a rescue mission vessel
            is_rescue = Misc.IsRescueMission(v);
            if (is_rescue)
            {
                return;
            }

            // dead EVA are not valid vessels
            if (EVA.IsDead(v))
            {
                return;
            }

            // shortcut for common tests
            is_valid = true;

            // generate id once
            id = vessel_id;

            // calculate crew info for the vessel
            crew_count    = Lib.CrewCount(v);
            crew_capacity = Lib.CrewCapacity(v);

            // get vessel position
            Vector3d position = Lib.VesselPosition(v);

            // this should never happen again
            if (Vector3d.Distance(position, v.mainBody.position) < 1.0)
            {
                throw new Exception("Shit hit the fan for vessel " + v.vesselName);
            }

            // determine if there is enough EC for a powered state
            powered = ResourceCache.Info(v, "ElectricCharge").amount > double.Epsilon;

            // determine if in sunlight, calculate sun direction and distance
            sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

            // environment stuff
            atmo_factor        = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
            gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
            underwater         = Sim.Underwater(v);
            breathable         = Sim.Breathable(v, underwater);
            landed             = Lib.Landed(v);
            zerog = !landed && (!v.mainBody.atmosphere || v.mainBody.atmosphereDepth < v.altitude);

            if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f)
            {
                highspeedWarp(v);
            }

            // temperature at vessel position
            temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);
            temp_diff   = Sim.TempDiff(temperature, v.mainBody, landed);

            // radiation
            radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar);

            // extended atmosphere
            thermosphere = Sim.InsideThermosphere(v);
            exosphere    = Sim.InsideExosphere(v);

            // malfunction stuff
            malfunction = Reliability.HasMalfunction(v);
            critical    = Reliability.HasCriticalFailure(v);

            // communications info
            connection   = new ConnectionInfo(v, powered, blackout);
            transmitting = Science.Transmitting(v, connection.linked && connection.rate > double.Epsilon);

            // habitat data
            volume          = Habitat.Tot_volume(v);
            surface         = Habitat.Tot_surface(v);
            pressure        = Habitat.Pressure(v);
            evas            = (uint)(Math.Max(0, ResourceCache.Info(v, "Nitrogen").amount - 330) / PreferencesLifeSupport.Instance.evaAtmoLoss);
            poisoning       = Habitat.Poisoning(v);
            humidity        = Habitat.Humidity(v);
            shielding       = Habitat.Shielding(v);
            living_space    = Habitat.Living_space(v);
            volume_per_crew = Habitat.Volume_per_crew(v);
            comforts        = new Comforts(v, landed, crew_count > 1, connection.linked && connection.rate > double.Epsilon);

            // data about greenhouses
            greenhouses = Greenhouse.Greenhouses(v);

            // other stuff
            gravioli = Sim.Graviolis(v);
        }
예제 #17
0
        // trigger a random breakdown event
        public static void Breakdown(Vessel v, ProtoCrewMember c)
        {
            // constants
            const double res_penalty = 0.1;                    // proportion of food lost on 'depressed' and 'wrong_valve'

            // get a supply resource at random
            Resource_info res = null;

            if (Profile.supplies.Count > 0)
            {
                Supply supply = Profile.supplies[Lib.RandomInt(Profile.supplies.Count)];
                res = ResourceCache.Info(v, supply.resource);
            }

            // compile list of events with condition satisfied
            List <KerbalBreakdown> events = new List <KerbalBreakdown>
            {
                KerbalBreakdown.mumbling                 //< do nothing, here so there is always something that can happen
            };

            if (Lib.HasData(v))
            {
                events.Add(KerbalBreakdown.fat_finger);
            }
            if (Reliability.CanMalfunction(v))
            {
                events.Add(KerbalBreakdown.rage);
            }
            if (res != null && res.amount > double.Epsilon)
            {
                events.Add(KerbalBreakdown.wrong_valve);
            }

            // choose a breakdown event
            KerbalBreakdown breakdown = events[Lib.RandomInt(events.Count)];

            // generate message
            string text    = "";
            string subtext = "";

            switch (breakdown)
            {
            case KerbalBreakdown.mumbling:
                text    = "$ON_VESSEL$KERBAL has been in space for too long";
                subtext = "Mumbling incoherently";
                break;

            case KerbalBreakdown.fat_finger:
                text    = "$ON_VESSEL$KERBAL is pressing buttons at random on the control panel";
                subtext = "Science data has been lost";
                break;

            case KerbalBreakdown.rage:
                text    = "$ON_VESSEL$KERBAL is possessed by a blind rage";
                subtext = "A component has been damaged";
                break;

            case KerbalBreakdown.wrong_valve:
                text    = "$ON_VESSEL$KERBAL opened the wrong valve";
                subtext = res.resource_name + " has been lost";
                break;
            }

            // post message first so this one is shown before malfunction message
            Message.Post(Severity.breakdown, Lib.ExpandMsg(text, v, c), subtext);

            // trigger the event
            switch (breakdown)
            {
            case KerbalBreakdown.mumbling:
                break;                         // do nothing

            case KerbalBreakdown.fat_finger:
                Lib.RemoveData(v);
                break;

            case KerbalBreakdown.rage:
                Reliability.CauseMalfunction(v);
                break;

            case KerbalBreakdown.wrong_valve:
                res.Consume(res.amount * res_penalty);
                break;
            }

            // remove reputation
            if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER)
            {
                Reputation.Instance.AddReputation(-PreferencesBasic.Instance.breakdownPenalty, TransactionReasons.Any);
            }
        }
예제 #18
0
  // implement greenhouse mechanics for unloaded vessels
  public static void BackgroundUpdate(Vessel vessel, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Greenhouse greenhouse, vessel_info info, vessel_resources resources, double elapsed_s)
  {
    // get protomodule data
    bool door_opened = Lib.Proto.GetBool(m, "door_opened");
    double growth = Lib.Proto.GetDouble(m, "growth");
    float lamps = Lib.Proto.GetFloat(m, "lamps");
    double lighting = Lib.Proto.GetDouble(m, "lighting");

    // if lamp is on
    if (lamps > float.Epsilon)
    {
      // get resource handler
      resource_info ec = resources.Info(vessel, "ElectricCharge");

      // consume ec
      ec.Consume(greenhouse.ec_rate * lamps * elapsed_s * Reliability.Penalty(p, "Greenhouse", 2.0));

      // shut down the light if there isn't enough ec
      // note: comparing against amount at previous simulation step
      if (ec.amount <= double.Epsilon) lamps = 0.0f;
    }

    // determine lighting conditions
    // note: we ignore sun direction for gameplay reasons: else the user must reorient the greenhouse as the planets dance over time
    // - natural light depend on: distance from sun, direct sunlight, door status
    // - artificial light depend on: lamps tweakable and ec available, door status
    lighting = info.solar_flux / Sim.SolarFluxAtHome() * (door_opened ? 1.0 : 0.0) + lamps;

    // if can use waste, and there is some lighting
    double waste_perc = 0.0;
    if (greenhouse.waste_name.Length > 0 && lighting > double.Epsilon)
    {
      // get resource handler
      resource_info waste = resources.Info(vessel, greenhouse.waste_name);

      // consume waste
      waste.Consume(greenhouse.waste_rate * elapsed_s);

      // determine waste bonus
      // note: comparing against amount from previous simulation step
      waste_perc = Math.Min(waste.amount / greenhouse.waste_rate, 1.0);
    }

    // determine growth bonus
    double growth_bonus = greenhouse.soil_bonus * (info.landed ? 1.0 : 0.0) + greenhouse.waste_bonus * waste_perc;

    // grow the crop
    double growing = greenhouse.growth_rate * (1.0 + growth_bonus) * lighting;
    growth += elapsed_s * growing;

    // if it is harvest time
    if (growth >= 1.0)
    {
      // reset growth
      growth = 0.0;

      // produce food
      resources.Produce(vessel, greenhouse.resource_name, greenhouse.harvest_size);

      // show a message to the user
      Message.Post(Lib.BuildString("On <color=FFFFFF>", vessel.vesselName, "</color> the crop harvest produced <color=FFFFFF>",
        greenhouse.harvest_size.ToString("F0"), " ", greenhouse.resource_name, "</color>"));

      // record first space harvest
      if (!info.landed && DB.Ready()) DB.Landmarks().space_harvest = 1;
    }

    // store data
    Lib.Proto.Set(m, "growth", growth);
    Lib.Proto.Set(m, "lamps", lamps);
    Lib.Proto.Set(m, "lighting", lighting);
    Lib.Proto.Set(m, "growth_diff", growing);
  }
예제 #19
0
        public static void Update(Vessel v, VesselData vd, VesselResources resources, double elapsed_s)
        {
            if (!Lib.IsVessel(v))
            {
                return;
            }

            // get most used resource handlers
            ResourceInfo ec = resources.GetResource(v, "ElectricCharge");

            List <ResourceInfo>         allResources       = resources.GetAllResources(v);
            Dictionary <string, double> availableResources = new Dictionary <string, double>();

            foreach (var ri in allResources)
            {
                availableResources[ri.ResourceName] = ri.Amount;
            }
            List <KeyValuePair <string, double> > resourceChangeRequests = new List <KeyValuePair <string, double> >();

            foreach (var e in Background_PMs(v))
            {
                switch (e.type)
                {
                case Module_type.Reliability: Reliability.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Reliability, elapsed_s); break;

                case Module_type.Experiment: (e.module_prefab as Experiment).BackgroundUpdate(v, vd, e.m, ec, resources, elapsed_s); break;                         // experiments use the prefab as a singleton instead of a static method

                case Module_type.Greenhouse: Greenhouse.BackgroundUpdate(v, e.m, e.module_prefab as Greenhouse, vd, resources, elapsed_s); break;

                case Module_type.GravityRing: GravityRing.BackgroundUpdate(v, e.p, e.m, e.module_prefab as GravityRing, ec, elapsed_s); break;

                case Module_type.Harvester: Harvester.BackgroundUpdate(v, e.m, e.module_prefab as Harvester, elapsed_s); break;                         // Kerbalism ground and air harvester module

                case Module_type.Laboratory: Laboratory.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Laboratory, ec, elapsed_s); break;

                case Module_type.Command: ProcessCommand(v, e.p, e.m, e.module_prefab as ModuleCommand, resources, elapsed_s); break;

                case Module_type.Generator: ProcessGenerator(v, e.p, e.m, e.module_prefab as ModuleGenerator, resources, elapsed_s); break;

                case Module_type.Converter: ProcessConverter(v, e.p, e.m, e.module_prefab as ModuleResourceConverter, resources, elapsed_s); break;

                case Module_type.Drill: ProcessDrill(v, e.p, e.m, e.module_prefab as ModuleResourceHarvester, resources, elapsed_s); break;                         // Stock ground harvester module

                // case Module_type.AsteroidDrill: ProcessAsteroidDrill(v, e.p, e.m, e.module_prefab as ModuleAsteroidDrill, resources, elapsed_s); break; // Stock asteroid harvester module
                case Module_type.StockLab: ProcessStockLab(v, e.p, e.m, e.module_prefab as ModuleScienceConverter, ec, elapsed_s); break;

                case Module_type.Light: ProcessLight(v, e.p, e.m, e.module_prefab as ModuleLight, ec, elapsed_s); break;

                case Module_type.Scanner: KerbalismScansat.BackgroundUpdate(v, e.p, e.m, e.module_prefab as KerbalismScansat, e.part_prefab, vd, ec, elapsed_s); break;

                case Module_type.FissionGenerator: ProcessFissionGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.CryoTank: ProcessCryoTank(v, e.p, e.m, e.module_prefab, resources, ec, elapsed_s); break;

                case Module_type.FNGenerator: ProcessFNGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.SolarPanelFixer: SolarPanelFixer.BackgroundUpdate(v, e.m, e.module_prefab as SolarPanelFixer, vd, ec, elapsed_s); break;

                case Module_type.KerbalismSentinel: KerbalismSentinel.BackgroundUpdate(v, e.m, e.module_prefab as KerbalismSentinel, vd, ec, elapsed_s); break;

                case Module_type.APIModule: ProcessApiModule(v, e.p, e.m, e.part_prefab, e.module_prefab, resources, availableResources, resourceChangeRequests, elapsed_s); break;
                }
            }
        }
예제 #20
0
        static void ProcessConverter(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Part part_prefab, int index, vessel_resources resources, double elapsed_s)
        {
            // note: support multiple resource converters
            // note: ignore stock temperature mechanic of converters
            // note: ignore autoshutdown
            // note: using hard-coded crew bonus values from the wiki because the module data make zero sense (DERP ALERT)
            // note: non-mandatory resources 'dynamically scale the ratios', that is exactly what mandatory resources do too (DERP ALERT)
            // note: 'undo' stock behaviour by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)
            // note: support PlanetaryBaseSystem converters
            // note: support NearFuture reactors

            // get converter
            var converter_prefabs = part_prefab.Modules.GetModules <ModuleResourceConverter>();

            if (index >= converter_prefabs.Count)
            {
                return;
            }
            ModuleResourceConverter converter = converter_prefabs[index] as ModuleResourceConverter;

            // if active
            if (Lib.Proto.GetBool(m, "IsActivated"))
            {
                // determine if vessel is full of all output resources
                // note: comparing against previous amount
                bool full = true;
                foreach (var or in converter.outputList)
                {
                    resource_info res = resources.Info(v, or.ResourceName);
                    full &= (res.level >= converter.FillAmount - double.Epsilon);
                }

                // if not full
                if (!full)
                {
                    // get malfunction penalty
                    double penalty = Reliability.Penalty(p, "Converter");

                    // deduce crew bonus
                    int exp_level = -1;
                    if (converter.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in v.protoVessel.GetVesselCrew())
                        {
                            exp_level = Math.Max(exp_level, c.trait == converter.Specialty ? c.experienceLevel : -1);
                        }
                    }
                    double exp_bonus = exp_level < 0 ? 1.0 : 5.0 + (double)exp_level * 4.0;

                    // create and commit recipe
                    resource_recipe recipe = new resource_recipe(resource_recipe.converter_priority);
                    foreach (var ir in converter.inputList)
                    {
                        recipe.Input(ir.ResourceName, ir.Ratio * elapsed_s);
                    }
                    foreach (var or in converter.outputList)
                    {
                        recipe.Output(or.ResourceName, or.Ratio * penalty * exp_bonus * elapsed_s);
                    }
                    resources.Transform(recipe);
                }

                // undo stock behaviour by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #21
0
        public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Reliability reliability)
        {
            // if it has not malfunctioned
            if (!Lib.Proto.GetBool(m, "broken"))
            {
                // get time of next failure
                double next = Lib.Proto.GetDouble(m, "next");

                // get quality
                bool quality = Lib.Proto.GetBool(m, "quality");

                // calculate epoch of failure if necessary
                if (next <= double.Epsilon)
                {
                    double last = Planetarium.GetUniversalTime();
                    next = last + reliability.mtbf * (quality ? Settings.QualityScale : 1.0) * 2.0 * Lib.RandomDouble();
                    Lib.Proto.Set(m, "last", last);
                    Lib.Proto.Set(m, "next", next);
                }

                // if it has failed, trigger malfunction
                if (Planetarium.GetUniversalTime() > next)
                {
                    ProtoBreak(v, p, m);
                }
            }
        }
예제 #22
0
        public static void Update(Vessel v, Vessel_info vi, VesselData vd, Vessel_resources resources, double elapsed_s)
        {
            if (!Lib.IsVessel(v))
            {
                return;
            }

            // get most used resource handlers
            Resource_info ec = resources.Info(v, "ElectricCharge");

            // This is basically handled in cache. However, when accelerating time warp while
            // the vessel is in shadow, the cache logic doesn't kick in soon enough. So we double-check here
            if (TimeWarp.CurrentRate > 1000.0f || elapsed_s > 150)              // we're time warping fast...
            {
                vi.highspeedWarp(v);
            }

            foreach (var e in Background_PMs(v))
            {
                switch (e.type)
                {
                case Module_type.Reliability: Reliability.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Reliability); break;

                case Module_type.Experiment: Experiment.BackgroundUpdate(v, e.m, e.module_prefab as Experiment, ec, resources, elapsed_s); break;

                case Module_type.Greenhouse: Greenhouse.BackgroundUpdate(v, e.m, e.module_prefab as Greenhouse, vi, resources, elapsed_s); break;

                case Module_type.GravityRing: GravityRing.BackgroundUpdate(v, e.p, e.m, e.module_prefab as GravityRing, ec, elapsed_s); break;

                case Module_type.Emitter: Emitter.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Emitter, ec, elapsed_s); break;

                case Module_type.Harvester: Harvester.BackgroundUpdate(v, e.m, e.module_prefab as Harvester, elapsed_s); break;                         // Kerbalism ground and air harvester module

                case Module_type.Laboratory: Laboratory.BackgroundUpdate(v, e.p, e.m, e.module_prefab as Laboratory, ec, elapsed_s); break;

                case Module_type.Command: ProcessCommand(v, e.p, e.m, e.module_prefab as ModuleCommand, resources, elapsed_s); break;

                case Module_type.Panel: ProcessPanel(v, e.p, e.m, e.module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s); break;

                case Module_type.Generator: ProcessGenerator(v, e.p, e.m, e.module_prefab as ModuleGenerator, resources, elapsed_s); break;

                case Module_type.Converter: ProcessConverter(v, e.p, e.m, e.module_prefab as ModuleResourceConverter, resources, elapsed_s); break;

                case Module_type.Drill: ProcessDrill(v, e.p, e.m, e.module_prefab as ModuleResourceHarvester, resources, elapsed_s); break;                         // Stock ground harvester module

                case Module_type.AsteroidDrill: ProcessAsteroidDrill(v, e.p, e.m, e.module_prefab as ModuleAsteroidDrill, resources, elapsed_s); break;             // Stock asteroid harvester module

                case Module_type.StockLab: ProcessStockLab(v, e.p, e.m, e.module_prefab as ModuleScienceConverter, ec, elapsed_s); break;

                case Module_type.Light: ProcessLight(v, e.p, e.m, e.module_prefab as ModuleLight, ec, elapsed_s); break;

                case Module_type.Scanner: KerbalismScansat.BackgroundUpdate(v, e.p, e.m, e.module_prefab as KerbalismScansat, e.part_prefab, vd, ec, elapsed_s); break;

                case Module_type.CurvedPanel: ProcessCurvedPanel(v, e.p, e.m, e.module_prefab, e.part_prefab, vi, ec, elapsed_s); break;

                case Module_type.FissionGenerator: ProcessFissionGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.RadioisotopeGenerator: ProcessRadioisotopeGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.CryoTank: ProcessCryoTank(v, e.p, e.m, e.module_prefab, resources, ec, elapsed_s); break;

                case Module_type.FNGenerator: ProcessFNGenerator(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.NonRechargeBattery: ProcessNonRechargeBattery(v, e.p, e.m, e.module_prefab, ec, elapsed_s); break;

                case Module_type.KerbalismProcess: KerbalismProcess.BackgroundUpdate(v, e.m, e.module_prefab as KerbalismProcess, ec, resources, elapsed_s); break;
                }
            }
        }
예제 #23
0
파일: Cache.cs 프로젝트: zajc3w/Kerbalism
  public vessel_info(Vessel v, uint vessel_id, UInt64 inc)
  {
    // NOTE: anything used here can't in turn use cache, unless you know what you are doing

    // associate with an unique incremental id
    this.inc = inc;

    // determine if this is a valid vessel
    is_vessel = Lib.IsVessel(v);
    if (!is_vessel) return;

    // determine if this is a resque mission vessel
    is_resque = Lib.IsResqueMission(v);
    if (is_resque) return;

    // dead EVA are not valid vessels
    if (v.isEVA && EVA.KerbalData(v).eva_dead) return;

    // shortcut for common tests
    is_valid = true;

    // generate id once
    id = vessel_id;

    // calculate crew info for the vessel
    crew_count = Lib.CrewCount(v);
    crew_capacity = Lib.CrewCapacity(v);

    // get vessel position once
    position = Lib.VesselPosition(v);

    // determine if in sunlight, calculate sun direction and distance
    sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

    // if the orbit length vs simulation step is lower than an acceptable threshold, use discrete sun visibility
    if (v.mainBody.flightGlobalsIndex != 0)
    {
      double orbit_period = Sim.OrbitalPeriod(v);
      if (orbit_period / Kerbalism.elapsed_s < 16.0) sunlight = 1.0 - Sim.ShadowPeriod(v) / orbit_period;
    }

    // calculate environment stuff
    atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
    gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
    breathable = Sim.Breathable(v);
    landed = Lib.Landed(v);

    // calculate temperature at vessel position
    temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);

    // calculate radiation
    radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out inside_pause, out inside_belt);

    // calculate malfunction stuff
    max_malfunction = Reliability.MaxMalfunction(v);
    avg_quality = Reliability.AverageQuality(v);

    // calculate signal info
    antenna = new antenna_data(v);
    avoid_inf_recursion.Add(v.id);
    link = Signal.Link(v, position, antenna, blackout, avoid_inf_recursion);
    avoid_inf_recursion.Remove(v.id);

    // partial data about modules, used by vessel info/monitor
    scrubbers = Scrubber.PartialData(v);
    recyclers = Recycler.PartialData(v);
    greenhouses = Greenhouse.PartialData(v);

    // woot relativity
    time_dilation = Sim.TimeDilation(v);
  }
예제 #24
0
        public static void update(Vessel v, vessel_info vi, vessel_data vd, vessel_resources resources, double elapsed_s)
        {
            // get most used resource handlers
            resource_info ec = resources.Info(v, "ElectricCharge");

            // for each part
            foreach (ProtoPartSnapshot p in v.protoVessel.protoPartSnapshots)
            {
                // a part can contain multiple resource converters
                int converter_index = 0;

                // get part prefab (required for module properties)
                Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                // for each module
                foreach (ProtoPartModuleSnapshot m in p.modules)
                {
                    // get the module prefab
                    PartModule module_prefab = Lib.FindModule(part_prefab, m.moduleName);

                    // if the prefab doesn't contain this module, skip it
                    if (!module_prefab)
                    {
                        continue;
                    }

                    // process modules
                    switch (m.moduleName)
                    {
                    case "Reliability":                  Reliability.BackgroundUpdate(v, m, module_prefab as Reliability, elapsed_s);                 break;

                    case "Scrubber":                     Scrubber.BackgroundUpdate(v, m, module_prefab as Scrubber, vi, resources, elapsed_s);        break;

                    case "Recycler":                     Recycler.BackgroundUpdate(v, m, module_prefab as Recycler, resources, elapsed_s);            break;

                    case "Greenhouse":                   Greenhouse.BackgroundUpdate(v, p, m, module_prefab as Greenhouse, vi, resources, elapsed_s); break;

                    case "GravityRing":                  GravityRing.BackgroundUpdate(v, p, m, module_prefab as GravityRing, resources, elapsed_s);   break;

                    case "Emitter":                      Emitter.BackgroundUpdate(v, p, m, module_prefab as Emitter, ec, elapsed_s);                  break;

                    case "ModuleCommand":                ProcessCommand(v, p, m, module_prefab as ModuleCommand, resources, elapsed_s);               break;

                    case "ModuleDeployableSolarPanel":   ProcessPanel(v, p, m, module_prefab as ModuleDeployableSolarPanel, vi, ec, elapsed_s);       break;

                    case "ModuleGenerator":              ProcessGenerator(v, p, m, module_prefab as ModuleGenerator, resources, elapsed_s);           break;

                    case "ModuleResourceConverter":
                    case "ModuleKPBSConverter":
                    case "FissionReactor":               ProcessConverter(v, p, m, part_prefab, converter_index++, resources, elapsed_s);             break;

                    case "ModuleResourceHarvester":      ProcessHarvester(v, p, m, module_prefab as ModuleResourceHarvester, resources, elapsed_s);   break;

                    case "ModuleAsteroidDrill":          ProcessAsteroidDrill(v, p, m, module_prefab as ModuleAsteroidDrill, resources, elapsed_s);   break;

                    case "ModuleScienceConverter":       ProcessLab(v, p, m, module_prefab as ModuleScienceConverter, ec, elapsed_s);                 break;

                    case "ModuleLight":
                    case "ModuleColoredLensLight":
                    case "ModuleMultiPointSurfaceLight": ProcessLight(v, p, m, module_prefab as ModuleLight, ec, elapsed_s);                          break;

                    case "SCANsat":
                    case "ModuleSCANresourceScanner":    ProcessScanner(v, p, m, module_prefab, part_prefab, vd, ec, elapsed_s);                      break;

                    case "ModuleCurvedSolarPanel":       ProcessCurvedPanel(v, p, m, module_prefab, part_prefab, vi, ec, elapsed_s);                  break;

                    case "FissionGenerator":             ProcessFissionGenerator(v, p, m, module_prefab, ec, elapsed_s);                              break;

                    case "ModuleRadioisotopeGenerator":  ProcessRadioisotopeGenerator(v, p, m, module_prefab, ec, elapsed_s);                         break;

                    case "ModuleCryoTank":               ProcessCryoTank(v, p, m, module_prefab, resources, elapsed_s);                               break;
                    }
                }
            }
        }
예제 #25
0
  public vessel_info(Vessel v, uint vessel_id, UInt64 inc)
  {
    // NOTE: anything used here can't in turn use cache, unless you know what you are doing

    // NOTE: you can't cache vessel position
    // at any point in time all vessel/body positions are relative to a different frame of reference
    // so comparing the current position of a vessel, with the cached one of another make no sense

    // associate with an unique incremental id
    this.inc = inc;

    // determine if this is a valid vessel
    is_vessel = Lib.IsVessel(v);
    if (!is_vessel) return;

    // determine if this is a rescue mission vessel
    is_rescue = Misc.IsRescueMission(v);
    if (is_rescue) return;

    // dead EVA are not valid vessels
    if (EVA.IsDead(v)) return;

    // shortcut for common tests
    is_valid = true;

    // generate id once
    id = vessel_id;

    // calculate crew info for the vessel
    crew_count = Lib.CrewCount(v);
    crew_capacity = Lib.CrewCapacity(v);

    // get vessel position
    Vector3d position = Lib.VesselPosition(v);

    // this should never happen again
    if (Vector3d.Distance(position, v.mainBody.position) < 1.0)
    {
      throw new Exception("Shit hit the fan for vessel " + v.vesselName);
    }

    // determine if in sunlight, calculate sun direction and distance
    sunlight = Sim.RaytraceBody(v, position, FlightGlobals.Bodies[0], out sun_dir, out sun_dist) ? 1.0 : 0.0;

    // at the two highest timewarp speed, the number of sun visibility samples drop to the point that
    // the quantization error first became noticeable, and then exceed 100%
    // to solve this, we switch to an analytical estimation of the portion of orbit that was in sunlight
    // - we check against timewarp rate, instead of index, to avoid issues during timewarp blending
    if (v.mainBody.flightGlobalsIndex != 0 && TimeWarp.CurrentRate > 1000.0f)
    {
      sunlight = 1.0 - Sim.ShadowPeriod(v) / Sim.OrbitalPeriod(v);
    }

    // environment stuff
    atmo_factor = Sim.AtmosphereFactor(v.mainBody, position, sun_dir);
    gamma_transparency = Sim.GammaTransparency(v.mainBody, v.altitude);
    underwater = Sim.Underwater(v);
    breathable = Sim.Breathable(v, underwater);
    landed = Lib.Landed(v);

    // temperature at vessel position
    temperature = Sim.Temperature(v, position, sunlight, atmo_factor, out solar_flux, out albedo_flux, out body_flux, out total_flux);
    temp_diff = Sim.TempDiff(temperature, v.mainBody, landed);

    // radiation
    radiation = Radiation.Compute(v, position, gamma_transparency, sunlight, out blackout, out magnetosphere, out inner_belt, out outer_belt, out interstellar);

    // extended atmosphere
    thermosphere = Sim.InsideThermosphere(v);
    exosphere = Sim.InsideExosphere(v);

    // malfunction stuff
    malfunction = Reliability.HasMalfunction(v);
    critical = Reliability.HasCriticalFailure(v);

    // signal info
    antenna = new AntennaInfo(v);
    avoid_inf_recursion.Add(v.id);
    connection = Signal.connection(v, position, antenna, blackout, avoid_inf_recursion);
    transmitting = Science.transmitting(v, connection.linked);
    relaying = Signal.relaying(v, avoid_inf_recursion);
    avoid_inf_recursion.Remove(v.id);

    // habitat data
    volume = Habitat.tot_volume(v);
    surface = Habitat.tot_surface(v);
    pressure = Habitat.pressure(v);
    poisoning = Habitat.poisoning(v);
    shielding = Habitat.shielding(v);
    living_space = Habitat.living_space(v);
    comforts = new Comforts(v, landed, crew_count > 1, connection.linked);

    // data about greenhouses
    greenhouses = Greenhouse.Greenhouses(v);

    // other stuff
    gravioli = Sim.Graviolis(v);
  }
예제 #26
0
        public static List <ReliabilityInfo> BuildList(Vessel vessel)
        {
            var result = new List <ReliabilityInfo>();

            if (vessel.loaded)
            {
                foreach (var r in Lib.FindModules <Reliability>(vessel))
                {
                    result.Add(new ReliabilityInfo(r));
                }
            }
            else
            {
                var PD = new Dictionary <string, Lib.Module_prefab_data>();
                foreach (ProtoPartSnapshot p in vessel.protoVessel.protoPartSnapshots)
                {
                    // get part prefab (required for module properties)
                    Part part_prefab = PartLoader.getPartInfoByName(p.partName).partPrefab;

                    // get all module prefabs
                    var module_prefabs = part_prefab.FindModulesImplementing <PartModule>();

                    // clear module indexes
                    PD.Clear();

                    // for each module
                    foreach (ProtoPartModuleSnapshot m in p.modules)
                    {
                        if (m.moduleName != "Reliability")
                        {
                            continue;
                        }

                        Reliability module_prefab = Lib.ModulePrefab(module_prefabs, m.moduleName, PD) as Reliability;
                        if (!module_prefab)
                        {
                            continue;
                        }

                        // if the module is disabled, skip it
                        // note: this must be done after ModulePrefab is called, so that indexes are right
                        if (!Lib.Proto.GetBool(m, "isEnabled"))
                        {
                            continue;
                        }

                        result.Add(new ReliabilityInfo(p, m, module_prefab));
                    }
                }
            }

            result.Sort((a, b) => {
                if (a.group != b.group)
                {
                    return(string.Compare(a.group, b.group, StringComparison.Ordinal));
                }
                return(string.Compare(a.title, b.title));
            });

            return(result);
        }
예제 #27
0
        public static void ProtoBreak(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m)
        {
            // get reliability module prefab
            string      type        = Lib.Proto.GetString(m, "type", string.Empty);
            Reliability reliability = p.partPrefab.FindModulesImplementing <Reliability>().Find(k => k.type == type);

            if (reliability == null)
            {
                return;
            }

            // if manned, or if safemode didn't trigger
            if (Cache.VesselInfo(v).crew_capacity > 0 || Lib.RandomDouble() > Settings.SafeModeChance)
            {
                // flag as broken
                Lib.Proto.Set(m, "broken", true);

                // determine if this is a critical failure
                bool critical = Lib.RandomDouble() < Settings.CriticalChance;
                Lib.Proto.Set(m, "critical", critical);

                // for each associated module
                foreach (var proto_module in p.modules.FindAll(k => k.moduleName == reliability.type))
                {
                    // disable the module
                    Lib.Proto.Set(proto_module, "isEnabled", false);
                }

                // type-specific hacks
                switch (reliability.type)
                {
                case "ProcessController":
                    foreach (ProcessController pc in p.partPrefab.FindModulesImplementing <ProcessController>())
                    {
                        ProtoPartResourceSnapshot res = p.resources.Find(k => k.resourceName == pc.resource);
                        if (res != null)
                        {
                            res.flowState = false;
                        }
                    }
                    break;
                }

                // show message
                Broken_msg(v, reliability.title, critical);
            }
            // safe mode
            else
            {
                // reset age
                Lib.Proto.Set(m, "last", 0.0);
                Lib.Proto.Set(m, "next", 0.0);

                // notify user
                Safemode_msg(v, reliability.title);
            }

            // in any case, incentive redundancy
            if (Settings.IncentiveRedundancy)
            {
                Incentive_redundancy(v, reliability.redundancy);
            }
        }
예제 #28
0
        public static void BackgroundUpdate(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, Reliability reliability, double elapsed_s)
        {
            if (!PreferencesReliability.Instance.mtbfFailures)
            {
                return;
            }

            // check for existing malfunction and if it actually uses MTBF failures
            if (Lib.Proto.GetBool(m, "broken"))
            {
                return;
            }
            if (reliability.mtbf <= 0)
            {
                return;
            }

            // get time of next failure
            double next    = Lib.Proto.GetDouble(m, "next");
            bool   quality = Lib.Proto.GetBool(m, "quality");
            var    now     = Planetarium.GetUniversalTime();

            // calculate epoch of failure if necessary
            if (next <= 0)
            {
                var guaranteed = reliability.mtbf / 2.0;
                var r          = 1 - Math.Pow(Lib.RandomDouble(), 3);
                next = now + guaranteed + reliability.mtbf * (quality ? Settings.QualityScale : 1.0) * r;
                Lib.Proto.Set(m, "last", now);
                Lib.Proto.Set(m, "next", next);
#if DEBUG_RELIABILITY
                Lib.Log("Reliability: background MTBF failure in " + (now - next) + " for " + p);
#endif
            }

            var rad   = v.KerbalismData().EnvRadiation;
            var decay = RadiationDecay(quality, rad, elapsed_s, reliability.rated_radiation, reliability.radiation_decay_rate);
            if (decay > 0)
            {
                next -= decay;
                Lib.Proto.Set(m, "next", next);
            }

            // if it has failed, trigger malfunction
            if (now > next)
            {
#if DEBUG_RELIABILITY
                Lib.Log("Reliablity: background MTBF failure for " + p);
#endif
                ProtoBreak(v, p, m);
            }
        }