예제 #1
0
		void VesselDestroyed(Vessel v)
		{
			// for each part
			foreach (Part p in v.parts)
			{
				// forget all potential vessel data
				DB.vessels.Remove(p.flightID);
			}

			// rescan the damn kerbals
			// - vessel crew is empty at destruction time
			// - we can't even use the flightglobal roster, because sometimes it isn't updated yet at this point
			HashSet<string> kerbals_alive = new HashSet<string>();
			HashSet<string> kerbals_dead = new HashSet<string>();
			foreach (Vessel ov in FlightGlobals.Vessels)
			{
				foreach (ProtoCrewMember c in Lib.CrewList(ov)) kerbals_alive.Add(c.name);
			}
			foreach (var p in DB.kerbals)
			{
				if (!kerbals_alive.Contains(p.Key)) kerbals_dead.Add(p.Key);
			}
			foreach (string n in kerbals_dead) DB.kerbals.Remove(n);

			// purge the caches
			Cache.Purge(v);
			ResourceCache.Purge(v);
		}
예제 #2
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)
                {
                    // deduce crew bonus
                    int exp_level = -1;
                    if (harvester.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in Lib.CrewList(v))
                        {
                            if (c.experienceTrait.Effects.Find(k => k.Name == harvester.ExperienceEffect) != null)
                            {
                                exp_level = Math.Max(exp_level, c.experienceLevel);
                            }
                        }
                    }
                    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();
                        foreach (var ir in harvester.inputList)
                        {
                            recipe.Input(ir.ResourceName, ir.Ratio * elapsed_s);
                        }
                        recipe.Output(harvester.ResourceName, abundance * harvester.Efficiency * exp_bonus * elapsed_s);
                        resources.Transform(recipe);
                    }
                }

                // undo stock behaviour by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #3
0
        void VesselDestroyed(Vessel v)
        {
            // rescan the damn kerbals
            // - vessel crew is empty at destruction time
            // - we can't even use the flightglobal roster, because sometimes it isn't updated yet at this point
            HashSet <string> kerbals_alive = new HashSet <string>();
            HashSet <string> kerbals_dead  = new HashSet <string>();

            foreach (Vessel ov in FlightGlobals.Vessels)
            {
                foreach (ProtoCrewMember c in Lib.CrewList(ov))
                {
                    kerbals_alive.Add(c.name);
                }
            }
            foreach (string key in DB.Kerbals().Keys)
            {
                if (!kerbals_alive.Contains(key))
                {
                    kerbals_dead.Add(key);
                }
            }
            foreach (string n in kerbals_dead)
            {
                // we don't know if the kerbal really is dead, or if it is just not currently assigned to a mission
                DB.KillKerbal(n, false);
            }

            // purge the caches
            ResourceCache.Purge(v);                 // works with loaded and unloaded vessels
            //Drive.Purge(v);				// works with loaded and unloaded vessels
            Cache.PurgeVesselCaches(v);             // works with loaded and unloaded vessels
        }
예제 #4
0
파일: EVA.cs 프로젝트: tinygrox/Kerbalism
 // return true if the vessel is a kerbal eva, and is flagged as dead
 public static bool IsDead(Vessel v)
 {
     if (!v.isEVA)
     {
         return(false);
     }
     return(DB.Kerbal(Lib.CrewList(v)[0].name).eva_dead);
 }
예제 #5
0
        public static void manageRescueMission(Vessel v)
        {
            // true if we detected this was a rescue mission vessel
            bool detected = false;

            // deal with rescue missions
            foreach (ProtoCrewMember c in Lib.CrewList(v))
            {
                // get kerbal data
                KerbalData kd = DB.Kerbal(c.name);

                // flag the kerbal as not rescue at prelaunch
                if (v.situation == Vessel.Situations.PRELAUNCH)
                {
                    kd.rescue = false;
                }

                // if the kerbal belong to a rescue mission
                if (kd.rescue)
                {
                    // remember it
                    detected = true;

                    // flag the kerbal as non-rescue
                    // note: enable life support mechanics for the kerbal
                    kd.rescue = false;

                    // show a message
                    Message.Post(Lib.BuildString("We found <b>", c.name, "</b>"), Lib.BuildString((c.gender == ProtoCrewMember.Gender.Male ? "He" : "She"), "'s still alive!"));
                }
            }

            // gift resources
            if (detected)
            {
                var reslib = PartResourceLibrary.Instance.resourceDefinitions;
                var parts  = Lib.GetPartsRecursively(v.rootPart);

                // give the vessel some propellant usable on eva
                string monoprop_name   = Lib.EvaPropellantName();
                double monoprop_amount = Lib.EvaPropellantCapacity();
                foreach (var part in parts)
                {
                    if (part.CrewCapacity > 0 || part.FindModuleImplementing <KerbalEVA>() != null)
                    {
                        if (Lib.Capacity(part, monoprop_name) <= double.Epsilon)
                        {
                            Lib.AddResource(part, monoprop_name, 0.0, monoprop_amount);
                        }
                        break;
                    }
                }
                ResourceCache.Produce(v, monoprop_name, monoprop_amount);

                // give the vessel some supplies
                Profile.SetupRescue(v);
            }
        }
예제 #6
0
		bool render_vessel(Panel p, Vessel v)
		{
			// get vessel info
			vessel_info vi = Cache.VesselInfo(v);

			// skip invalid vessels
			if (!vi.is_valid) return false;

			// get data from db
			VesselData vd = DB.Vessel(v);

			// determine if filter must be shown
			show_filter |= vd.group.Length > 0 && vd.group != "NONE";

			// skip filtered vessels
			if (filtered() && vd.group != filter) return false;

			// get resource handler
			vessel_resources resources = ResourceCache.Get(v);

			// get vessel crew
			List<ProtoCrewMember> crew = Lib.CrewList(v);

			// get vessel name
			string vessel_name = v.isEVA ? crew[0].name : v.vesselName;

			// get body name
			string body_name = v.mainBody.name.ToUpper();

			// render entry
			p.header
			(
			  Lib.BuildString("<b>",
			  Lib.Ellipsis(vessel_name, Styles.ScaleStringLength(((page == MonitorPage.data || page == MonitorPage.log || selected_id == Guid.Empty) && !Lib.IsFlight()) ? 50 : 30)),
			  "</b> <size=", Styles.ScaleInteger(9).ToString(),
			  "><color=#cccccc>", Lib.Ellipsis(body_name, Styles.ScaleStringLength(8)), "</color></size>"),
			  string.Empty,
			  () => { selected_id = selected_id != v.id ? v.id : Guid.Empty; }
			);

			// problem indicator
			indicator_problems(p, v, vi, crew);

			// battery indicator
			indicator_ec(p, v, vi);

			// supply indicator
			if (Features.Supplies) indicator_supplies(p, v, vi);

			// reliability indicator
			if (Features.Reliability) indicator_reliability(p, v, vi);

			// signal indicator
			if (RemoteTech.Enabled() || HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet) indicator_signal(p, v, vi);

			// done
			return true;
		}
예제 #7
0
        static void ProcessConverter(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceConverter converter, vessel_resources resources, double elapsed_s)
        {
            // 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
            // note: assume dump overboard is false for all outputs

            // 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)
                {
                    // deduce crew bonus
                    int exp_level = -1;
                    if (converter.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in Lib.CrewList(v))
                        {
                            if (c.experienceTrait.Effects.Find(k => k.Name == converter.ExperienceEffect) != null)
                            {
                                exp_level = Math.Max(exp_level, c.experienceLevel);
                            }
                        }
                    }
                    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();
                    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 * exp_bonus * elapsed_s);
                    }
                    resources.Transform(recipe);
                }

                // undo stock behaviour by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #8
0
        static void ProcessConverter(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleResourceConverter converter, VesselResources resources, double elapsed_s)
        {
            // note: ignore stock temperature mechanic of converters
            // note: ignore auto shutdown
            // note: non-mandatory resources 'dynamically scale the ratios', that is exactly what mandatory resources do too (DERP ALERT)
            // note: 'undo' stock behavior by forcing lastUpdateTime to now (to minimize overlapping calculations from this and stock post-facto simulation)

            // 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)
                {
                    ResourceInfo res = resources.GetResource(v, or.ResourceName);
                    full &= (res.Level >= converter.FillAmount - double.Epsilon);
                }

                // if not full
                if (!full)
                {
                    // deduce crew bonus
                    int exp_level = -1;
                    if (converter.UseSpecialistBonus)
                    {
                        foreach (ProtoCrewMember c in Lib.CrewList(v))
                        {
                            if (c.experienceTrait.Effects.Find(k => k.Name == converter.ExperienceEffect) != null)
                            {
                                exp_level = Math.Max(exp_level, c.experienceLevel);
                            }
                        }
                    }
                    double exp_bonus = exp_level < 0
                                          ? converter.EfficiencyBonus * converter.SpecialistBonusBase
                                          : converter.EfficiencyBonus * (converter.SpecialistBonusBase + (converter.SpecialistEfficiencyFactor * (exp_level + 1)));

                    // create and commit recipe
                    ResourceRecipe recipe = new ResourceRecipe(ResourceBroker.StockConverter);
                    foreach (var ir in converter.inputList)
                    {
                        recipe.AddInput(ir.ResourceName, ir.Ratio * exp_bonus * elapsed_s);
                    }
                    foreach (var or in converter.outputList)
                    {
                        recipe.AddOutput(or.ResourceName, or.Ratio * exp_bonus * elapsed_s, or.DumpExcess);
                    }
                    resources.AddRecipe(recipe);
                }

                // undo stock behavior by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #9
0
  bool render_vessel(Panel p, Vessel v)
  {
    // get vessel info
    vessel_info vi = Cache.VesselInfo(v);

    // skip invalid vessels
    if (!vi.is_valid) return false;

    // get data from db
    VesselData vd = DB.Vessel(v);

    // determine if filter must be shown
    show_filter |= vd.group.Length > 0 && vd.group != "NONE";

    // skip filtered vessels
    if (filtered() && vd.group != filter) return false;

    // get resource handler
    vessel_resources resources = ResourceCache.Get(v);

    // get vessel crew
    List<ProtoCrewMember> crew = Lib.CrewList(v);

    // get vessel name
    string vessel_name = v.isEVA ? crew[0].name : v.vesselName;

    // get body name
    string body_name = v.mainBody.name.ToUpper();

    // render entry
    p.header
    (
      Lib.BuildString("<b>", Lib.Ellipsis(vessel_name, 20), "</b> <size=9><color=#cccccc>", Lib.Ellipsis(body_name, 8), "</color></size>"),
      string.Empty,
      () => { selected_id = selected_id != v.id ? v.id : Guid.Empty; }
    );

    // problem indicator
    indicator_problems(p, v, vi, crew);

    // battery indicator
    indicator_ec(p, v, vi);

    // supply indicator
    if (Features.Supplies) indicator_supplies(p, v, vi);

    // reliability indicator
    if (Features.Reliability) indicator_reliability(p, v, vi);

    // signal indicator
    if (Features.Signal) indicator_signal(p, v, vi);

    // done
    return true;
  }
예제 #10
0
        public static void TelemetryPanel(this Panel p, Vessel v)
        {
            // avoid corner-case when this is called in a lambda after scene changes
            v = FlightGlobals.FindVessel(v.id);

            // if vessel doesn't exist anymore, leave the panel empty
            if (v == null)
            {
                return;
            }

            // get vessel data
            VesselData vd = v.KerbalismData();

            // if not a valid vessel, leave the panel empty
            if (!vd.IsSimulated)
            {
                return;
            }

            // set metadata
            p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " ", Lib.Color(Local.TELEMETRY_title, Lib.Kolor.LightGrey)));            //"TELEMETRY"
            p.Width(Styles.ScaleWidthFloat(355.0f));
            p.paneltype = Panel.PanelType.telemetry;

            // time-out simulation
            if (p.Timeout(vd))
            {
                return;
            }

            // get resources
            VesselResources resources = ResourceCache.Get(v);

            // get crew
            var crew = Lib.CrewList(v);

            // draw the content
            Render_crew(p, crew);
            if (Features.Science)
            {
                Render_science(p, v, vd);
            }
            Render_greenhouse(p, vd);
            Render_supplies(p, v, vd, resources);
            Render_habitat(p, v, vd);
            Render_environment(p, v, vd);

            // collapse eva kerbal sections into one
            if (v.isEVA)
            {
                p.Collapse(Local.TELEMETRY_EVASUIT);                     //"EVA SUIT"
            }
        }
예제 #11
0
        public static void TelemetryPanel(this Panel p, Vessel v)
        {
            // avoid corner-case when this is called in a lambda after scene changes
            v = FlightGlobals.FindVessel(v.id);

            // if vessel doesn't exist anymore, leave the panel empty
            if (v == null)
            {
                return;
            }

            // get info from the cache
            Vessel_info vi = Cache.VesselInfo(v);

            // if not a valid vessel, leave the panel empty
            if (!vi.is_valid)
            {
                return;
            }

            // set metadata
            p.Title(Lib.BuildString(Lib.Ellipsis(v.vesselName, Styles.ScaleStringLength(20)), " <color=#cccccc>TELEMETRY</color>"));
            p.Width(Styles.ScaleWidthFloat(355.0f));
            p.paneltype = Panel.PanelType.telemetry;

            // time-out simulation
            if (p.Timeout(vi))
            {
                return;
            }

            // get vessel data
            VesselData vd = DB.Vessel(v);

            // get resources
            Vessel_resources resources = ResourceCache.Get(v);

            // get crew
            var crew = Lib.CrewList(v);

            // draw the content
            Render_crew(p, crew);
            Render_greenhouse(p, vi);
            Render_supplies(p, v, vi, resources);
            Render_habitat(p, v, vi);
            Render_environment(p, v, vi);

            // collapse eva kerbal sections into one
            if (v.isEVA)
            {
                p.Collapse("EVA SUIT");
            }
        }
예제 #12
0
        // return true if the vessel is a rescue mission
        public static bool IsRescueMission(Vessel v)
        {
            // if at least one of the crew is flagged as rescue, consider it a rescue mission
            foreach (var c in Lib.CrewList(v))
            {
                if (DB.Kerbal(c.name).rescue)
                {
                    return(true);
                }
            }

            // not a rescue mission
            return(false);
        }
예제 #13
0
        private static void ResourceUpdate(Vessel v, Harvester harvester, double min_abundance, double elapsed_s)
        {
            double abundance = SampleAbundance(v, harvester);

            if (abundance > min_abundance)
            {
                ResourceRecipe recipe = new ResourceRecipe(ResourceBroker.Harvester);
                recipe.AddInput("ElectricCharge", harvester.ec_rate * elapsed_s);
                recipe.AddOutput(
                    harvester.resource,
                    Harvester.AdjustedRate(harvester, engineer_cs, Lib.CrewList(v), abundance) * elapsed_s,
                    dump: false);
                ResourceCache.AddRecipe(v, recipe);
            }
        }
예제 #14
0
        public void Execute(Vessel v, VesselData vd, VesselResources resources)
        {
            // get crew
            List <ProtoCrewMember> crew = Lib.CrewList(v);

            // get resource handler
            ResourceInfo res = resources.GetResource(v, resource);

            // get data from db
            SupplyData sd = v.KerbalismData().Supply(resource);

            // message obey user config
            bool show_msg = resource == "ElectricCharge" ? vd.cfg_ec : vd.cfg_supply;

            // messages are shown only if there is some capacity and the vessel is manned
            // special case: ElectricCharge related messages are shown for unmanned vessels too
            if (res.Capacity > double.Epsilon && (crew.Count > 0 || resource == "ElectricCharge"))
            {
                // manned/probe message variant
                uint variant = crew.Count > 0 ? 0 : 1u;

                // manage messages
                if (res.Level <= double.Epsilon && sd.message < 2)
                {
                    if (empty_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(empty_message, v, null, variant));
                    }
                    sd.message = 2;
                }
                else if (res.Level < low_threshold && sd.message < 1)
                {
                    if (low_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(low_message, v, null, variant));
                    }
                    sd.message = 1;
                }
                else if (res.Level > low_threshold && sd.message > 0)
                {
                    if (refill_message.Length > 0 && show_msg)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(refill_message, v, null, variant));
                    }
                    sd.message = 0;
                }
            }
        }
예제 #15
0
        void VesselDestroyed(Vessel v)
        {
            // for each part
            foreach (Part p in v.parts)
            {
                // forget all potential vessel data
                DB.vessels.Remove(p.flightID);
            }

            // rescan the damn kerbals
            // - vessel crew is empty at destruction time
            // - we can't even use the flightglobal roster, because sometimes it isn't updated yet at this point
            HashSet <string> kerbals_alive = new HashSet <string>();
            HashSet <string> kerbals_dead  = new HashSet <string>();

            foreach (Vessel ov in FlightGlobals.Vessels)
            {
                foreach (ProtoCrewMember c in Lib.CrewList(ov))
                {
                    kerbals_alive.Add(c.name);
                }
            }
            foreach (KeyValuePair <string, KerbalData> p in DB.Kerbals())
            {
                if (!kerbals_alive.Contains(p.Key))
                {
                    kerbals_dead.Add(p.Key);
                }
            }
            foreach (string n in kerbals_dead)
            {
                // we don't know if the kerbal really is dead, or if it is just not currently assigned to a mission
                DB.KillKerbal(n, false);
            }

            // purge the caches
            Cache.Purge(v);
            ResourceCache.Purge(v);
        }
예제 #16
0
        // return true if the vessel is a rescue mission
        public static bool IsRescueMission(Vessel v)
        {
            // avoid corner-case situation on the first update : rescue vessel handling code is called
            // after the VesselData creation, causing Vesseldata evaluation to be delayed, causing anything
            // that rely on it to fail on its first update or in OnStart
            if (v.situation == Vessel.Situations.PRELAUNCH)
            {
                return(false);
            }

            // if at least one of the crew is flagged as rescue, consider it a rescue mission
            foreach (var c in Lib.CrewList(v))
            {
                if (DB.Kerbal(c.name).rescue)
                {
                    return(true);
                }
            }


            // not a rescue mission
            return(false);
        }
예제 #17
0
  public static void telemetry(this Panel p, Vessel v)
  {
    // if vessel doesn't exist anymore
    if (FlightGlobals.FindVessel(v.id) == null) return;

    // get info from the cache
    vessel_info vi = Cache.VesselInfo(v);

    // if not a valid vessel
    if (!vi.is_valid) return;

    // set metadata
    p.title(Lib.BuildString(Lib.Ellipsis(v.vesselName, 20), " <color=#cccccc>TELEMETRY</color>"));

    // time-out simulation
    if (p.timeout(vi)) return;

    // get vessel data
    VesselData vd = DB.Vessel(v);

    // get resources
    vessel_resources resources = ResourceCache.Get(v);

    // get crew
    var crew = Lib.CrewList(v);

    // draw the content
    render_crew(p, crew);
    render_greenhouse(p, vi);
    render_supplies(p, v, vi, resources);
    render_habitat(p, v, vi);
    render_environment(p, v, vi);

    // collapse eva kerbal sections into one
    if (v.isEVA) p.collapse("EVA SUIT");
  }
예제 #18
0
        static void ProcessAsteroidDrill(Vessel v, ProtoPartSnapshot p, ProtoPartModuleSnapshot m, ModuleAsteroidDrill asteroid_drill, vessel_resources resources, double elapsed_s)
        {
            // note: untested
            // note: ignore stock temperature mechanic of asteroid drills
            // note: ignore autoshutdown
            // 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"))
            {
                // get asteroid data
                ProtoPartModuleSnapshot asteroid_info     = null;
                ProtoPartModuleSnapshot asteroid_resource = null;
                foreach (ProtoPartSnapshot pp in v.protoVessel.protoPartSnapshots)
                {
                    if (asteroid_info == null)
                    {
                        asteroid_info = pp.modules.Find(k => k.moduleName == "ModuleAsteroidInfo");
                    }
                    if (asteroid_resource == null)
                    {
                        asteroid_resource = pp.modules.Find(k => k.moduleName == "ModuleAsteroidResource");
                    }
                }

                // if there is actually an asteroid attached to this active asteroid drill (it should)
                if (asteroid_info != null && asteroid_resource != null)
                {
                    // get some data
                    double mass_threshold = Lib.Proto.GetDouble(asteroid_info, "massThresholdVal");
                    double mass           = Lib.Proto.GetDouble(asteroid_info, "currentMassVal");
                    double abundance      = Lib.Proto.GetDouble(asteroid_resource, "abundance");
                    string res_name       = Lib.Proto.GetString(asteroid_resource, "resourceName");
                    double res_density    = PartResourceLibrary.Instance.GetDefinition(res_name).density;

                    // if asteroid isn't depleted
                    if (mass > mass_threshold && abundance > double.Epsilon)
                    {
                        // deduce crew bonus
                        int exp_level = -1;
                        if (asteroid_drill.UseSpecialistBonus)
                        {
                            foreach (ProtoCrewMember c in Lib.CrewList(v))
                            {
                                if (c.experienceTrait.Effects.Find(k => k.Name == asteroid_drill.ExperienceEffect) != null)
                                {
                                    exp_level = Math.Max(exp_level, c.experienceLevel);
                                }
                            }
                        }
                        double exp_bonus = exp_level < 0
          ? asteroid_drill.EfficiencyBonus * asteroid_drill.SpecialistBonusBase
          : asteroid_drill.EfficiencyBonus * (asteroid_drill.SpecialistBonusBase + (asteroid_drill.SpecialistEfficiencyFactor * (exp_level + 1)));

                        // determine resource extracted
                        double res_amount = abundance * asteroid_drill.Efficiency * exp_bonus * elapsed_s;

                        // transform EC into mined resource
                        resource_recipe recipe = new resource_recipe();
                        recipe.Input("ElectricCharge", asteroid_drill.PowerConsumption * elapsed_s);
                        recipe.Output(res_name, res_amount, true);
                        resources.Transform(recipe);

                        // if there was ec
                        // note: comparing against amount in previous simulation step
                        if (resources.Info(v, "ElectricCharge").amount > double.Epsilon)
                        {
                            // consume asteroid mass
                            Lib.Proto.Set(asteroid_info, "currentMassVal", (mass - res_density * res_amount));
                        }
                    }
                }

                // undo stock behaviour by forcing last_update_time to now
                Lib.Proto.Set(m, "lastUpdateTime", Planetarium.GetUniversalTime());
            }
        }
예제 #19
0
 /// <summary>
 /// return true if the crew of specified vessel satisfy the specs
 /// </summary>
 public bool Check(Vessel v)
 {
     return(Check(Lib.CrewList(v)));
 }
예제 #20
0
 /// <summary>
 /// Returns the total crew level bonus (= how many levels above required minimum is the crew).
 /// </summary>
 public int Bonus(Vessel v, int requiredLevel = Int16.MinValue)
 {
     return(Bonus(Lib.CrewList(v), requiredLevel));
 }
예제 #21
0
        bool Render_vessel(Panel p, Vessel v, bool selected = false)
        {
            // get vessel info
            Vessel_info vi = Cache.VesselInfo(v);

            // skip invalid vessels
            if (!vi.is_valid)
            {
                return(false);
            }

            // get data from db
            VesselData vd = DB.Vessel(v);

            // get vessel crew
            List <ProtoCrewMember> crew = Lib.CrewList(v);

            // get vessel name
            string vessel_name = v.isEVA ? crew[0].name : v.vesselName;

            // get body name
            string body_name = v.mainBody.name.ToUpper();

            // skip filtered vessels
            if (!Filter_match(v.vesselType, vd.group + " " + body_name + " " + vessel_name))
            {
                return(false);
            }

            // render entry
            p.AddHeader
            (
                Lib.BuildString("<b>",
                                Lib.Ellipsis(vessel_name, Styles.ScaleStringLength(((page == MonitorPage.data || page == MonitorPage.log || selected_id == Guid.Empty) && !Lib.IsFlight()) ? 45 : 25)),
                                "</b> <size=", Styles.ScaleInteger(9).ToString(), ">", Lib.Color("#cccccc", Lib.Ellipsis(body_name, Styles.ScaleStringLength(8))), "</size>"),
                string.Empty,
                () => { selected_id = selected_id != v.id ? v.id : Guid.Empty; }
            );

            // vessel type icon
            if (!selected)
            {
                p.SetIcon(GetVesselTypeIcon(v.vesselType), v.vesselType.displayDescription(), () => { selected_id = selected_id != v.id ? v.id : Guid.Empty; });
            }
            else
            {
                if (FlightGlobals.ActiveVessel != v)
                {
                    if (Lib.IsFlight())
                    {
                        p.SetIcon(GetVesselTypeIcon(v.vesselType), "Go to vessel!", () => Lib.Popup
                                      ("Warning!",
                                      Lib.BuildString("Do you really want go to ", vessel_name, " vessel?"),
                                      new DialogGUIButton("Go", () => { GotoVessel.JumpToVessel(v); }),
                                      new DialogGUIButton("Target", () => { GotoVessel.SetVesselAsTarget(v); }),
                                      new DialogGUIButton("Stay", () => { })));
                    }
                    else
                    {
                        p.SetIcon(GetVesselTypeIcon(v.vesselType), "Go to vessel!", () => Lib.Popup
                                      ("Warning!",
                                      Lib.BuildString("Do you really want go to ", vessel_name, " vessel?"),
                                      new DialogGUIButton("Go", () => { GotoVessel.JumpToVessel(v); }),
                                      new DialogGUIButton("Stay", () => { })));
                    }
                }
                else
                {
                    p.SetIcon(GetVesselTypeIcon(v.vesselType), v.vesselType.displayDescription(), () => { });
                }
            }

            // problem indicator
            Indicator_problems(p, v, vi, crew);

            // battery indicator
            Indicator_ec(p, v, vi);

            // supply indicator
            if (Features.Supplies)
            {
                Indicator_supplies(p, v, vi);
            }

            // reliability indicator
            if (Features.Reliability)
            {
                Indicator_reliability(p, v, vi);
            }

            // signal indicator
            if (API.Comm.handlers.Count > 0 || HighLogic.fetch.currentGame.Parameters.Difficulty.EnableCommNet)
            {
                Indicator_signal(p, v, vi);
            }

            // done
            return(true);
        }
예제 #22
0
		// return true if the vessel is a kerbal eva, and is flagged as dead
		public static bool IsDead(Vessel v)
		{
			if (!v.isEVA) return false;
			return DB.Kerbal(Lib.CrewList(v)[0].name).eva_dead;
		}
예제 #23
0
        public void Execute(Vessel v, Vessel_info vi, Vessel_resources resources, double elapsed_s)
        {
            // store list of crew to kill
            List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>();

            // get input resource handler
            Resource_info res = input.Length > 0 ? resources.Info(v, input) : null;

            // determine message variant
            uint variant = vi.temperature < PreferencesLifeSupport.Instance.survivalTemperature ? 0 : 1u;

            // get product of all environment modifiers
            double k = Modifiers.Evaluate(v, vi, resources, modifiers);

            bool lifetime_enabled = PreferencesBasic.Instance.lifetime;

            // for each crew
            foreach (ProtoCrewMember c in Lib.CrewList(v))
            {
                // get kerbal data
                KerbalData kd = DB.Kerbal(c.name);

                // skip rescue kerbals
                if (kd.rescue)
                {
                    continue;
                }

                // skip disabled kerbals
                if (kd.disabled)
                {
                    continue;
                }

                // get kerbal property data from db
                RuleData rd = kd.Rule(name);
                rd.lifetime = lifetime_enabled && lifetime;

                // if continuous
                double step;
                if (interval <= double.Epsilon)
                {
                    // influence consumption by elapsed time
                    step = elapsed_s;
                }
                // if interval-based
                else
                {
                    // accumulate time
                    rd.time_since += elapsed_s;

                    // determine number of steps
                    step = Math.Floor(rd.time_since / interval);

                    // consume time
                    rd.time_since -= step * interval;

                    // remember if a meal is consumed/produced in this simulation step
                    if (step > 0.99)
                    {
                        res.SetMealHappened();
                    }
                    if (output.Length > 0 && step > 0.99)
                    {
                        ResourceCache.Info(v, output).SetMealHappened();
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > double.Epsilon)
                {
                    double r = rate * Variance(name, c, individuality);                      // kerbal-specific variance

                    // if there is a resource specified
                    if (res != null && r > double.Epsilon)
                    {
                        // determine amount of resource to consume
                        double required = r                                   // consumption rate
                                          * k                                 // product of environment modifiers
                                          * step;                             // seconds elapsed or number of steps

                        // if there is no output
                        if (output.Length == 0)
                        {
                            // simply consume (that is faster)
                            res.Consume(required);
                        }
                        // if there is an output and monitor is false
                        else if (!monitor)
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            Resource_recipe recipe = new Resource_recipe((Part)null);                              // kerbals are not associated with a part
                            recipe.Input(input, required);
                            recipe.Output(output, required * ratio, true);
                            resources.Transform(recipe);
                        }
                        // if monitor then do not consume input resource and only produce output if resource percentage + monitor_offset is < 100%
                        else if ((res.amount / res.capacity) + monitor_offset < 1.0)
                        {
                            // simply produce (that is faster)
                            resources.Produce(v, output, required * ratio);
                        }
                    }

                    // degenerate:
                    // - if the environment modifier is not telling to reset (by being zero)
                    // - if the input threshold is reached if used
                    // - if this rule is resource-less, or if there was not enough resource in the vessel
                    if (input_threshold >= double.Epsilon)
                    {
                        if (res.amount >= double.Epsilon && res.capacity >= double.Epsilon)
                        {
                            trigger = (res.amount / res.capacity) + monitor_offset >= input_threshold;
                        }
                        else
                        {
                            trigger = false;
                        }
                    }
                    else
                    {
                        trigger = input.Length == 0 || res.amount <= double.Epsilon;
                    }

                    if (k > 0.0 && trigger)
                    {
                        rd.problem += degeneration                                   // degeneration rate per-second or per-interval
                                      * k                                            // product of environment modifiers
                                      * step                                         // seconds elapsed or by number of steps
                                      * Variance(name, c, variance);                 // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                    }
                }

                bool do_breakdown = false;

                if (breakdown && PreferencesBasic.Instance.stressBreakdowns)
                {
                    // stress level
                    double breakdown_probability = rd.problem / warning_threshold;
                    breakdown_probability = Lib.Clamp(breakdown_probability, 0.0, 1.0);

                    // use the stupidity of a kerbal.
                    // however, nobody is perfect - not even a kerbal with a stupidity of 0.
                    breakdown_probability *= c.stupidity * 0.6 + 0.4;

                    // apply the weekly error rate
                    breakdown_probability *= PreferencesBasic.Instance.stressBreakdownRate;

                    // now we have the probability for one failure per week, based on the
                    // individual stupidity and stress level of the kerbal.

                    breakdown_probability = (breakdown_probability * elapsed_s) / (Lib.DaysInYear() * Lib.HoursInDay() * 3600);
                    if (breakdown_probability > Lib.RandomDouble())
                    {
                        do_breakdown = true;

                        // we're stressed out and just made a major mistake, this further increases the stress level...
                        rd.problem += warning_threshold * 0.05;                         // add 5% of the warning treshold to current stress level
                    }
                }

                // kill kerbal if necessary
                if (rd.problem >= fatal_threshold)
                {
                    if (fatal_message.Length > 0)
                    {
                        Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant));
                    }

                    if (breakdown)
                    {
                        do_breakdown = true;

                        // move back between warning and danger level
                        rd.problem = (warning_threshold + danger_threshold) * 0.5;

                        // make sure next danger message is shown
                        rd.message = 1;
                    }
                    else
                    {
                        deferred_kills.Add(c);
                    }
                }
                // show messages
                else if (rd.problem >= danger_threshold && rd.message < 2)
                {
                    if (danger_message.Length > 0)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(danger_message, v, c, variant));
                    }
                    rd.message = 2;
                }
                else if (rd.problem >= warning_threshold && rd.message < 1)
                {
                    if (warning_message.Length > 0)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(warning_message, v, c, variant));
                    }
                    rd.message = 1;
                }
                else if (rd.problem < warning_threshold && rd.message > 0)
                {
                    if (relax_message.Length > 0)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(relax_message, v, c, variant));
                    }
                    rd.message = 0;
                }

                if (do_breakdown)
                {
                    // trigger breakdown event
                    Misc.Breakdown(v, c);
                }
            }

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }
예제 #24
0
        public void Execute(Vessel v, VesselData vd, VesselResources resources, double elapsed_s)
        {
            // store list of crew to kill
            List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>();

            // get input resource handler
            ResourceInfo res = input.Length > 0 ? resources.GetResource(v, input) : null;

            // determine message variant
            uint variant = vd.EnvTemperature < Settings.LifeSupportSurvivalTemperature ? 0 : 1u;

            // get product of all environment modifiers
            double k = Modifiers.Evaluate(v, vd, resources, modifiers);

            bool lifetime_enabled = PreferencesRadiation.Instance.lifetime;

            // for each crew
            foreach (ProtoCrewMember c in Lib.CrewList(v))
            {
                // get kerbal data
                KerbalData kd = DB.Kerbal(c.name);

                // skip rescue kerbals
                if (kd.rescue)
                {
                    continue;
                }

                // skip disabled kerbals
                if (kd.disabled)
                {
                    continue;
                }

                // get kerbal property data from db
                RuleData rd = kd.Rule(name);
                rd.lifetime = lifetime_enabled && lifetime;

                // influence consumption by elapsed time
                double step = elapsed_s;

                // if interval-based
                if (interval > 0.0)
                {
                    // accumulate time
                    rd.time_since += elapsed_s;

                    // determine number of intervals that has passed (can be 2 or more if elapsed_s > interval * 2)
                    step = Math.Floor(rd.time_since / interval);

                    // consume time
                    rd.time_since -= step * interval;
                }

                // if there is a resource specified
                if (res != null && rate > double.Epsilon)
                {
                    // get rate including per-kerbal variance
                    double resRate =
                        rate                                                        // consumption rate
                        * Variance(name, c, individuality)                          // kerbal-specific variance
                        * k;                                                        // product of environment modifiers

                    // determine amount of resource to consume

                    double required = resRate * step;                           // seconds elapsed or interval amount

                    // remember if a meal is consumed/produced in this simulation step
                    if (interval > 0.0)
                    {
                        double ratePerStep = resRate / interval;
                        res.UpdateIntervalRule(-required, -ratePerStep, name);
                        if (output.Length > 0)
                        {
                            ResourceCache.GetResource(v, output).UpdateIntervalRule(required * ratio, ratePerStep * ratio, name);
                        }
                    }

                    // if continuous, or if one or more intervals elapsed
                    if (step > 0.0)
                    {
                        // if there is no output
                        if (output.Length == 0)
                        {
                            // simply consume (that is faster)
                            res.Consume(required, name);
                        }
                        // if there is an output
                        else
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            ResourceRecipe recipe = new ResourceRecipe(name);
                            recipe.AddInput(input, required);
                            recipe.AddOutput(output, required * ratio, true);
                            resources.AddRecipe(recipe);
                        }
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > 0.0)
                {
                    // degenerate:
                    // - if the environment modifier is not telling to reset (by being zero)
                    // - if this rule is resource-less, or if there was not enough resource in the vessel
                    if (k > 0.0 && (input.Length == 0 || res.Amount <= double.Epsilon))
                    {
                        rd.problem += degeneration                                   // degeneration rate per-second or per-interval
                                      * k                                            // product of environment modifiers
                                      * step                                         // seconds elapsed or by number of steps
                                      * Variance(name, c, variance);                 // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                    }
                }

                bool do_breakdown = false;

                if (breakdown)
                {
                    // don't do breakdowns and don't show stress message if disabled
                    if (!PreferencesComfort.Instance.stressBreakdowns)
                    {
                        return;
                    }

                    // stress level
                    double breakdown_probability = rd.problem / warning_threshold;
                    breakdown_probability = Lib.Clamp(breakdown_probability, 0.0, 1.0);

                    // use the stupidity of a kerbal.
                    // however, nobody is perfect - not even a kerbal with a stupidity of 0.
                    breakdown_probability *= c.stupidity * 0.6 + 0.4;

                    // apply the weekly error rate
                    breakdown_probability *= PreferencesComfort.Instance.stressBreakdownRate;

                    // now we have the probability for one failure per week, based on the
                    // individual stupidity and stress level of the kerbal.

                    breakdown_probability = (breakdown_probability * elapsed_s) / (Lib.DaysInYear * Lib.HoursInDay * 3600);
                    if (breakdown_probability > Lib.RandomDouble())
                    {
                        do_breakdown = true;

                        // we're stressed out and just made a major mistake, this further increases the stress level...
                        rd.problem += warning_threshold * 0.05;                         // add 5% of the warning treshold to current stress level
                    }
                }

                // kill kerbal if necessary
                if (rd.problem >= fatal_threshold)
                {
#if DEBUG || DEVBUILD
                    Lib.Log("Rule " + name + " kills " + c.name + " at " + rd.problem + " " + degeneration + "/" + k + "/" + step + "/" + Variance(name, c, variance));
#endif
                    if (fatal_message.Length > 0)
                    {
                        Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant));
                    }

                    if (breakdown)
                    {
                        do_breakdown = true;

                        // move back between warning and danger level
                        rd.problem = (warning_threshold + danger_threshold) * 0.5;

                        // make sure next danger message is shown
                        rd.message = 1;
                    }
                    else
                    {
                        deferred_kills.Add(c);
                    }
                }
                // show messages
                else if (rd.problem >= danger_threshold && rd.message < 2)
                {
                    if (danger_message.Length > 0)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(danger_message, v, c, variant));
                    }
                    rd.message = 2;
                }
                else if (rd.problem >= warning_threshold && rd.message < 1)
                {
                    if (warning_message.Length > 0)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(warning_message, v, c, variant));
                    }
                    rd.message = 1;
                }
                else if (rd.problem < warning_threshold && rd.message > 0)
                {
                    if (relax_message.Length > 0)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(relax_message, v, c, variant));
                    }
                    rd.message = 0;
                }

                if (do_breakdown)
                {
                    // trigger breakdown event
                    Misc.Breakdown(v, c);
                }
            }

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }
예제 #25
0
        public void Execute(Vessel v, vessel_info vi, vessel_resources resources, double elapsed_s)
        {
            // store list of crew to kill
            List <ProtoCrewMember> deferred_kills = new List <ProtoCrewMember>();

            // get input resource handler
            resource_info res = input.Length > 0 ? resources.Info(v, input) : null;

            // determine message variant
            uint variant = vi.temperature < Settings.SurvivalTemperature ? 0 : 1u;

            // get product of all environment modifiers
            double k = Modifiers.evaluate(v, vi, resources, modifiers);

            // for each crew
            foreach (ProtoCrewMember c in Lib.CrewList(v))
            {
                // get kerbal data
                KerbalData kd = DB.Kerbal(c.name);

                // skip rescue kerbals
                if (kd.rescue)
                {
                    continue;
                }

                // skip disabled kerbals
                if (kd.disabled)
                {
                    continue;
                }

                // get kerbal property data from db
                RuleData rd = kd.Rule(name);

                // if continuous
                double step;
                if (interval <= double.Epsilon)
                {
                    // influence consumption by elapsed time
                    step = elapsed_s;
                }
                // if interval-based
                else
                {
                    // accumulate time
                    rd.time_since += elapsed_s;

                    // determine number of steps
                    step = Math.Floor(rd.time_since / interval);

                    // consume time
                    rd.time_since -= step * interval;

                    // remember if a meal is consumed/produced in this simulation step
                    res.meal_happened |= step > 0.99;
                    if (output.Length > 0)
                    {
                        ResourceCache.Info(v, output).meal_happened |= step > 0.99;
                    }
                }

                // if continuous, or if one or more intervals elapsed
                if (step > double.Epsilon)
                {
                    // if there is a resource specified
                    if (res != null && rate > double.Epsilon)
                    {
                        // determine amount of resource to consume
                        double required = rate                                    // consumption rate
                                          * k                                     // product of environment modifiers
                                          * step;                                 // seconds elapsed or number of steps

                        // if there is no output
                        if (output.Length == 0)
                        {
                            // simply consume (that is faster)
                            res.Consume(required);
                        }
                        // if there is an output and output_only is false
                        else if (!output_only)
                        {
                            // transform input into output resource
                            // - rules always dump excess overboard (because it is waste)
                            resource_recipe recipe = new resource_recipe();
                            recipe.Input(input, required);
                            recipe.Output(output, required * ratio, true);
                            resources.Transform(recipe);
                        }
                        // if output_only then do not consume input resource
                        else
                        {
                            // simply produce (that is faster)
                            resources.Produce(v, output, required);
                        }
                    }

                    // degenerate:
                    // - if the environment modifier is not telling to reset (by being zero)
                    // - if the input threshold is reached if used
                    // - if this rule is resource-less, or if there was not enough resource in the vessel
                    if (input_threshold >= double.Epsilon)
                    {
                        if (res.amount >= double.Epsilon && res.capacity >= double.Epsilon)
                        {
                            trigger = res.amount / res.capacity >= input_threshold;
                        }
                        else
                        {
                            trigger = false;
                        }
                    }
                    else
                    {
                        trigger = input.Length == 0 || res.amount <= double.Epsilon;
                    }

                    if (k > 0.0 && trigger)
                    {
                        rd.problem += degeneration                                   // degeneration rate per-second or per-interval
                                      * k                                            // product of environment modifiers
                                      * step                                         // seconds elapsed or by number of steps
                                      * Variance(c, variance);                       // kerbal-specific variance
                    }
                    // else slowly recover
                    else
                    {
                        rd.problem *= 1.0 / (1.0 + Math.Max(interval, 1.0) * step * 0.002);
                        rd.problem  = Math.Max(rd.problem, 0.0);
                    }
                }

                // kill kerbal if necessary
                if (rd.problem >= fatal_threshold)
                {
                    if (fatal_message.Length > 0)
                    {
                        Message.Post(breakdown ? Severity.breakdown : Severity.fatality, Lib.ExpandMsg(fatal_message, v, c, variant));
                    }

                    if (breakdown)
                    {
                        // trigger breakdown event
                        Misc.Breakdown(v, c);

                        // move back between warning and danger level
                        rd.problem = (warning_threshold + danger_threshold) * 0.5;

                        // make sure next danger messagen is shown
                        rd.message = 1;
                    }
                    else
                    {
                        deferred_kills.Add(c);
                    }
                }
                // show messages
                else if (rd.problem >= danger_threshold && rd.message < 2)
                {
                    if (danger_message.Length > 0)
                    {
                        Message.Post(Severity.danger, Lib.ExpandMsg(danger_message, v, c, variant));
                    }
                    rd.message = 2;
                }
                else if (rd.problem >= warning_threshold && rd.message < 1)
                {
                    if (warning_message.Length > 0)
                    {
                        Message.Post(Severity.warning, Lib.ExpandMsg(warning_message, v, c, variant));
                    }
                    rd.message = 1;
                }
                else if (rd.problem < warning_threshold && rd.message > 0)
                {
                    if (relax_message.Length > 0)
                    {
                        Message.Post(Severity.relax, Lib.ExpandMsg(relax_message, v, c, variant));
                    }
                    rd.message = 0;
                }
            }

            // execute the deferred kills
            foreach (ProtoCrewMember c in deferred_kills)
            {
                Misc.Kill(v, c);
            }
        }