Jump to content

Tralfagar

Members
  • Posts

    78
  • Joined

  • Last visited

Everything posted by Tralfagar

  1. @Deimos Rast Do you mean you like the quantity of life support? The modules should be roughly the same (save the extras I left in by mistake for TAC/USILS).
  2. @Deimos Rast N there are not supposed to be. My text editor is probably creating backups. I'll take care of it when I can access wifi.
  3. @Lord Coriolis Glad to hear it's working. Eventually, I'll write a script to remove Civilians from the admin building but for now, they're extremely useful for debugging purposes. For your questions: 1) Right now, there is not, except for editing the part file. I have a parameter (populationGrowthModifier) within the CivilianDockGrowth/CivilianSpawGrowth module. For dock growth, it is a proportionality constant. Increasing it will give a 1:1 increase. For spawning, that is the exponential rate for increase/decay (the rate first exponentially increases and then exponentially decreases after half-full). Increasing it will cut the time until the population reaches maximum capacity. For spawning, you can include more modules that have CivilianSpawGrowth (i.e. more apartments). Since the function essentially goes from 0-100% capacity, adding more housing acts as a scaling factor. To elaborate a little more on Spawning, the equation as a function of current population: dN/dt = rN*(1-N/K) Where dN/dt -> rate of growth (units: Kerbal/sec), r -> exponential constant (aka populationGrowthModifier) (units: 1/s), K -> Total capacity of parts implementing CivilianSpawGrowth module (units: Kerbal). 2) Ideally they would act like Tourists...but I'm afraid I can't find a way to implement that (making them act like tourists without actually being Tourists). All of my attempts ended in badstuffTM happening to the save. I am hesitant to make the Civilians into Tourists because I don't want someone to mess up a contract by recruiting them. 3) Thank you for reminding me. Eventually, yes, I will add a way to recruit specific classes (possibly using the inspiration mechanic the previous iterations used). For the moment, the University (under Science) is acting as a recruiting station. Load up a Civilian and he'll be given a random trait (pilot/scientist/engineer).
  4. Version 0.0.4 is up. The problem was that the MM patch I used as a template was out dated (using organics). I updated it and re-scaled the supply budget. All modules should be set to keep the specified number of Kerbals (IIRC 8, 25, 50, 70) alive for 100 days when filled up (1 Kerbal consumes 16 supplies/day). Also bundles MM. It's not essential as-written, but I'm intending this to be used with other mods.
  5. @LeuZ I don't believe USI uses waste water. Instead, the life support resources should be Supplies/Mulch/Fertilizer (shown here). Let me fire up KSP and I will investigate. EDIT: I think I found a couple of problems. I'm adding in part info for the greenhouses (thought I had already added them). It looks like I left the TAC info as default. It also looks like the USI MM patch I used as a template is depreciated. I'll try updating it and have a new version up tonight!
  6. @Lord Coriolis For now, you can also recruit a seed Civilian as normal from the Admin building. I look forward to hearing how you broke my mod in new and interesting ways!
  7. For my plugin, I want to do some background processing on unfocused vessels: Adding a given amount of resources over time to a vessel implementing my plugin and occasionally spawn new Kerbals on those vessels when a limit is hit. Initially, I was going to use the Background Processing mod by @jamespicone. But now that I've done some research, it seems that mod may be overkill for what I want to do. Looking through the API, it looks like I can use FlightGlobals.vessels to get a list of all vessels in the game, and use vessel.isActiveVessel to determine if it is focused or not. It would look something like this: void checkBackgroundVessels() { foreach(Vessel myVessel in FlightGlobals.Vessels) { if (!myVessel.isActiveVessel && myVessel.FindPartModulesImplementing<myModule> () != null) { //do some stuff } } } However, Background Processing specifically mentions accessing ProtoVessels instead of Vessels. Is there an issue with accessing vessels that are unfocused? Or am I going to hit a brick wall down the road?
  8. @Lord Coriolis They should act identical to pilots/engineers/scientists. Likely that each would have to be frozen but I've never used that mod before. There is a minimum for reproductive growth: 1. I may increase it at a later date but for now Kerbals are weeds. For docking/contractor growth, there is no minimum limit. edit: Also, there is no change in spawn rate no matter where you are. I am considering changing it so some places spawn faster than others. Further than Kerbin -> faster growth? Only some hot-spots in the solar system? Keep it the same? I'm open to feedback. For docking/contractor growth, it is only active in Kerbin's, Mun's, and Minmus' SoI. Kerbin is at 1.0x, Mun ix 0.5x, and Minmus is 0.25x.
  9. Whoops! My mistake. I browsed through CRP and looked in the wrong file (configs for planetary resources, not common resources). In that case, by all means use the CRP food (which comes bundled with Civilian Population).
  10. @Dazza23 Do you mean for TAC Life Support? I removed all of the entries for TAC life support and moved them into a Module Manager (MM) file. So you'll need MM (which comes bundled with TAC Life Support) and the TAC Life Support mod for food. Otherwise, if you don't want life support but want food, it's very easy to add extra resources. Go into GameData/Squad/Resources/ResourcesGeneric.cfg. You'll find something like this RESOURCE_DEFINITION RESOURCE_DEFINITION { name = LiquidFuel density = 0.005 unitCost = 0.8 hsp = 2010 flowMode = STACK_PRIORITY_SEARCH transfer = PUMP isTweakable = true volume = 5 } This is all of the information needed to create a new resource. name is the name to reference it, density is the mass/unit, unit cost is $cost/unit, hsp is the specific heat; you can leave that as 2010. flowMode basically says whether it drains like MonoProp or liquid fuel. Transfer is how you move it. IsTweakable says whether or not you can alter the amounts in the editors. Not 100% what Volume does. But you can leave it as-is. Create a new file in GameData and call it whatever you like. I'm going to go with "DazzaMod". Then open a text editor and save this in your new folder. Copy/paste the below into it and save it as "DazzaResources.cfg". the name can be whatever you want, but it MUST have a .cfg extension. RESOURCE_DEFINITION { name = Food density = 0.0001 unitCost = 0.8 hsp = 2010 flowMode = STACK_PRIORITY_SEARCH transfer = PUMP isTweakable = true volume = 5 } This gives the game the background on what your resource is. Now go into GameData/CivilianPopulationRevamp/Parts/. All of the parts are grouped by function. Go into the .cfg for any of the ones you want to add food to and add the following within the last brace-level: RESOURCE { name = Food amount = 500 maxAmount = 500 } The file should look something like this: PART { **Lots of unimportant stuff** **More unimportant stuff** MODULE { **Does some stuff** } **Some stuff is in here** RESOURCE { name = Food amount = 500 maxAmount = 500 } } Then start up KSP and make sure it runs! But again, I want to make sure to emphasize that the RESOURCE *must* be within PART {...}. @Lord Coriolis Glad to hear it! Knock yourself out! @Deimos Rast I was looking at reverse-engineering how Ship Manifest does it. It looks pretty straight forward but I'm having trouble coming up with how the GUI works with that mod. Specifically the highlighting. I can figure everything else out except how it selects the parts. I have some time off this week to figure it out. In the mean time, I'll update the OP to link to those. Regarding portraits, I also suspect it's a matter of refreshing the right variable. I'll see what I can dig up on it. Thank you!
  11. @Kepler68 That's really not supposed to happen. I don't know why it would be. It looks like some parts are missing (they are, but it has never presented a problem for me). Can you run this mod by itself on Vanilla? Is anyone else having any trouble? Also, version 0.0.3 is up. Fixed bug caused by v0.0.2 where time warping no longer had an impact on Civilian growth. So something requiring 100 hours would only work in 100 hours real-time despite time warp. Corrected bug where civilian spawning was only active when part was activated (staged) Do note that spawning Kerbals to capacity will take about 2000 days (halfway at 1000 days). However, due to the exponential growth, it really gets going when it's up to speed. Population Growth Time (date from origin) Change (days) 1(starter) 0 N/A 2 260 260 3 396 136 4 491 95 5 566 75 6 628 62 7 683 55 8 733 50 9 779 46 10 822 43 11 864 42 12 905 41 13 945 40 14 985 40 15 1025 40 16 1066 41 Due to the nature of the logistic function, once it passes the half way point, growth is mirrored (exponentially decaying). So 260 days for the first Kerbal, but once saturated, a new one almost every month. Adding more modules will increase the growth rate. Planned next steps: Learning Background Processing and bringing in the last parts.
  12. @Deimos Rast That was a little bit of an oversight on my part. I missed the 1.1.3 update because I was using a non-Steam version of KSP for testing. I'm in the process of making sure it works as expected. Thusfar, it looks like it'll work with 1.1.3 without any problems. I've fixed a couple of bugs and will have a release (0.0.3) up by tonight. It'll play nice with existing saves. Also, I'm adding that this re-distributes Community Resource Pack (due to reactor). Edit: Actually the update will come in tomorrow. Fixing a bug showed me an issue with the values for the spawn rates of the apartments and an emergency came up tonight.
  13. I just created a new thread for my WIP version of this mod. I also updated to version 0.0.2. It has the EVA button (Transfering is more complicated than I expected, but I'm working on it). I've added a few more parts and the mod should be usable playable. Should be compatible with USI, TAC, CTT, and a couple others. With luck, not having to keep track of all the life support should make it easier to maintain. It can be found here:
  14. I've been working on/continuing Civilian Population Revamp, based on @michaelhester07, @rabidninjawombat, and @GGumby's collective work (found here, here, and here, respectively). I'm excited that it's gotten to a state where I think it can be shared (but still not released officially). Key Differences between mine and the above: Civilians are now full-fledged Kerbals, instead of being abstracted as resources There are now two methods of growth Linear growth by Civilians being ferried to your base -> A new arrival will arrive roughly every 85 days within Kerbin/Mun/Minmus SoI (contractor docks) Logistic growth by Civilians spawning within the craft -> Based on the number of Civilians present; first positive then negative exponential growth (apartment complexes) Civilian Growth is tracked by a new resource called "Civilian Growth Rate". It can be found on the upper-right hand corner of the screen with the other resources. It can be taken as a percent complete (0-1.00) until another Civilian arrives. Most of the time, it should read 0.00 because Kerbals take a long time to arrive. The mod is now life-support agnostic (due to Civilians now being Kerbals). Tac and USI Life Support are both supported in Module Manager config files Planned Future Work: Parts: Finish implementing the old Civilian Population parts that are missing Sort the assets into the appropriate folders for ease of use Plugin: Implement a method to transfer Kerbals using the GUI (without having to search the whole craft for them) Implement @jamespicone's Background Processing because it can take a while to grow a Civilian Note: Right now, this is still WIP and I am sure bugs will have to be squashed. Also, for simplicity, you can recruit Kerbals from the docking port. I will remove that before release. Known Issues/Workarounds: All modules with crew do not have internal spaces for the crews (and thus no portraits). If you need to EVA, use the GUI or right-click menu. For transfers, it's only the right-click menu at the moment. But for all parts, the first couple of seats should have an IVA. I highly suggest using Ship Manifest which has the above functionality. When a Civilian is added to the crew, the portrait does not automatically appear, even with a part with an internal space. Still trying to find the root-cause of that. Restart the vessel (go to another one and come back) and this should be resolved. Working on this after I get unfocused vessels working Civilians only spawn/come to your bases when they are the active vessel. Currently working on it. If anyone has any suggestions on how to improve it, feedback is more than welcome! This mod redistributes Community Resource Pack and Module Manager. Download (Version 0.0.5): SpaceDock: [ http://spacedock.info/mod/844/Civilian Population Revamp ] GitHub: [ https://github.com/maanderson22/CivilianPopulationRevamp ] License: [ CC-BY-SA 4.0 ]
  15. I have a menu that displays some information about Kerbals on my ship such as what their name is, their trait. I also want to use two buttons: EVA and Crew Transfer. I just figured out how to initialize the EVA ( FlightEVA.SpawnEVA (ProtoCrewMember.KerbalRef) for reference). For the crew transfer, I've checked out Sarbian's Crew Manifest and going by the API, it looks like I should be looking at the Monobehaviour.CrewTransfer class, specifically the Create(Part, ProtoCrewMember, Callback<CrewTransfer.DismissAction>) method. However, Sarbian's code doesn't seem to match up with that class and I'm not sure why, specifically lines 190-204 of CrewManifestModule. Indeed, he doesn't seem to use it in any of his code. Can anyone explain why he would need to create his own class instead of using the one with KSP? Or what the Callback method/pointer is for? To give reference to what I'm envisioning, I'd want the user to press the Transfer button next to the Kerbal's name (which will already have access to the ProtoCrewMember of that Kerbal) and then click on the part that they want to transfer to. Basically identical to the right-click context menu's Crew Transfer but in my own GUI window.
  16. @Nightside I'm not sure how it'll work either because I haven't tested it! Right now, they're mostly blank. I haven't looked too far into implementing internal views as of yet because I've had my hands full with other aspects of this plugin. But my current plan is to keep the parts as MichaelHester/RNW created them (2-4 seats shown, the rest not shown) and have collapsible menus that shows what Kerbals are on board. For each Kerbal, it would be something like: [NAME] [TRAIT] [EVA_BUTTON] [TRANSFER_BUTTON] I can go back and learn how to model with Unity at a later date. Right now, I want to get the plugin functional before going into cosmetics. At a minimum, that means including: 1) The above-mentioned buttons in the GUI (GUI is functional, I just need to add the fields) 2) Ships functional in background (likely using Background Process mod as a dependency) 3) Writing MM .cfgs for parts so they can be used with Community Tech Tree/USILS/TACLS/Shared Living Space 4) And of course adding parts that I have left out so far (mostly editing .cfg files)
  17. @GalacticAC I'm not in charge of *this* mod but I'm finishing up a rewrite of Civilian Population from more or less the ground up and @GGumby doesn't seem to have been active in a couple of months. I'm having some trouble figuring out Git/licensing, but I anticipate having a release ready by this weekend. I should note that there are several changes I have made: 1) Civilians are no longer a resource, but full-fledged Kerbals that are pretty useless. Not a whole lot of use except... 2) Life support can now be taken care of by USILS/TACLS without writing additional code; MM .cfg edits will be able to take care of this. 3) Civilian growth via docking is more or less the same (linear ramp within the Kerbin system), but on-ship breeding is modeled as a logistic function (initially exponential before reaching a limiting factor. Wikipedia has some good background information on it. 4) The modules may/may not be rejiggered to match. At the moment, I believe I'm using the University as a Recruiting station because it fits well in stock fairings. 5) The converters now function as soon as the craft is in flight, not when the last stage is triggered An old (but not too out of date) WIP build can be found here if you want to take a look. Not all of the parts are integrated; I've been adding them as I verify that they are good and work. Also, I want to add some buttons on the GUI since the portraits don't seem to display. Mostly a couple for EVA and Transfer.
  18. @xEvilReeperx commenting that out worked great. Thank you! No more phantom method calls. I'm a little hazy on KSPAddon. I had thought it was necessary to include or else badstuffTM will happen. Is it only necessary for part-less plugins?
  19. Hello everyone! I seem to have run into a problem with a plugin I'm writing that is going from OnFixedUpdate to FixedUpdate and I was hoping someone here might have an idea why a null exception is being thrown. Background: I noticed that OnFixedUpdate was only updated when the part's stage is activated. Since I want the part to be active whether or not it has been staged (i.e. always active), I thought I would try the Unity method FixedUpdate instead. Each of my modules has a master and a slave field to detail what logic should be run on it (master runs the "main" code once/update; slaves do nothing). Testing Method: I built a small craft with 2x of my module, an engine, a parachute, and a command pod. I launched it from the pad and recovered it then looked at the KSP.log file. I repeated using FixedUpdate and took a look at the KSP.log file and have a portion of these copied below Results: Here is a comparison of the KSP.log files with OnFixedUpdate and FixedUpdate using a craft with 2 of my modules (so OnFixedUpdate/FixedUpdate should run twice per update: once as a slave, once as a master) The only change made was renaming the method and the removal/inclusion of "override" modifier of the method: With OnFixedUpdate: [LOG 12:33:35.957] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:33:35.957] [CivilianPop Revamp]Master Status: TrueSlave Status: False [LOG 12:33:35.957] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:33:35.957] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:33:35.957] [CivilianPop Revamp]Master Status: FalseSlave Status: True [LOG 12:33:35.957] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:33:36.011] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:33:36.011] [CivilianPop Revamp]Master Status: TrueSlave Status: False [LOG 12:33:36.011] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:33:36.011] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:33:36.011] [CivilianPop Revamp]Master Status: FalseSlave Status: True [LOG 12:33:36.011] [CivilianPop Revamp]Finished FixedUpdate! With FixedUpdate: [LOG 12:37:34.804] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.804] [CivilianPop Revamp]Master Status: TrueSlave Status: False [LOG 12:37:34.804] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:37:34.804] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.804] [CivilianPop Revamp]Master Status: FalseSlave Status: True [LOG 12:37:34.804] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:37:34.848] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.848] [CivilianPop Revamp]Master Status: FalseSlave Status: False [EXC 12:37:34.848] NullReferenceException: Object reference not set to an instance of an object CivilianPopulationRevamp.CivilianDockGrowth.FixedUpdate () [LOG 12:37:34.848] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.848] [CivilianPop Revamp]Master Status: TrueSlave Status: False [LOG 12:37:34.848] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:37:34.848] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.848] [CivilianPop Revamp]Master Status: FalseSlave Status: True [LOG 12:37:34.848] [CivilianPop Revamp]Finished FixedUpdate! [LOG 12:37:34.850] [CivilianPop Revamp]Starting FixedUpdate! [LOG 12:37:34.850] [CivilianPop Revamp]Master Status: FalseSlave Status: False [EXC 12:37:34.850] NullReferenceException: Object reference not set to an instance of an object CivilianPopulationRevamp.CivilianDockGrowth.FixedUpdate () The above is a sample of two update cycles. As can be seen, OnFixedUpdate runs as expected: It starts for the master, prints the master/slave status, and ends. This is repeated twice. FixedUpdate, however, results in three different instances of updates. The first two are expected (once for master, once for slave). But the last (which has both master and slave as false) results in a NullReferenceException. I've run a few tests and it looks like the problem lies in the line with List<CivilianDockGrowth> listOfCivilianParts = vessel.FindPartModulesImplementing<CivilianDockGrowth> (); I can patch that up easily, but I think the root of the problem is that there is a third method being called during update. What's really confusing me is that it seems to have both master and slave as false...which means that the part would not be present during the OnStart method (which successfully executed) Here is my code. My module being called is CivilianDockGrowth, which inherits CivilianPopulationRegulator. Everything within the if-statement can be ignored but I've included it just in case it proves useful. using System; using System.Collections.Generic; using UnityEngine; using KSP; namespace CivilianPopulationRevamp { [KSPAddon (KSPAddon.Startup.Flight, false)] public class CivilianDockGrowth : CivilianPopulationRegulator { public override void OnStart (StartState state) { bool shouldCheckForUpdate = getCheckForUpdate (); if (shouldCheckForUpdate) { //if master/slaves not set, flight status...should only be run once Debug.Log (debuggingClass.modName + this.name + " is running OnStart()!"); List<CivilianDockGrowth> partsWithCivies = vessel.FindPartModulesImplementing<CivilianDockGrowth> (); foreach (CivilianDockGrowth part in partsWithCivies) {//reset all master/slaves part.master = false; part.slave = true; } //assign this part as master master = true; slave = false; } else { //if master/slave set or flight status fail. Should be run n-1 times where n = #parts Debug.Log (debuggingClass.modName + "WARNING: " + this.name + " is skipping OnStart!"); } } public void FixedUpdate () { if (!HighLogic.LoadedSceneIsFlight) return; Debug.Log (debuggingClass.modName + "Starting FixedUpdate!"); //if (!master & !slave) //return; int civilianPopulation = 0; int nonCivilianPopulation = 0; int civilianPopulationSeats = 0; double percentCurrentCivilian = 0d; Debug.Log (debuggingClass.modName + "Master Status: " + master + "Slave Status: " + slave); List<CivilianDockGrowth> listOfCivilianParts = vessel.FindPartModulesImplementing<CivilianDockGrowth> (); if (master == true) { //master is set during OnStart() double dt = GetDeltaTimex (); //Section to calculate growth variables civilianPopulation = countCiviliansOnShip (listOfCivilianParts);//number of seats taken by civilians in parts using class nonCivilianPopulation = countNonCiviliansOnShip (listOfCivilianParts);//number of civilianPopulationSeats = countCivilianSeatsOnShip (listOfCivilianParts);//total seats implementing class percentCurrentCivilian = getResourceBudget (debuggingClass.civilianResource);//get current value of Civilian Counter (0.0-1.0) percentCurrentCivilianRate = calculateLinearGrowthRate () * getRecruitmentSoIModifier (); //how much civilianCounter will change on iteration if (HighLogic.CurrentGame.Mode == Game.Modes.CAREER) getTaxes (civilianPopulation, dt); //Section to create Civilians part.RequestResource (debuggingClass.civilianResource, -percentCurrentCivilianRate * dt); if ((percentCurrentCivilian > 1.0) && (civilianPopulationSeats > civilianPopulation + nonCivilianPopulation)) { placeNewCivilian (listOfCivilianParts); part.RequestResource (debuggingClass.civilianResource, 1.0); }//end if condition to create Civilians } Debug.Log (debuggingClass.modName + "Finished FixedUpdate!"); } // end FixedUpdate /// <summary> /// Calculates the growth rate for civilians taking rides up to the station. /// TODO: /// </summary> /// <returns>The linear growth rate.</returns> public double calculateLinearGrowthRate () { double myRate = 0d;//seems to be essential to create a middle variable, else rate does not update (returns to 0) myRate = populationGrowthModifier; return myRate; } /// <summary> /// Gets the recruitment modifier from being with Kerbin's, Mun's. or Minmus' SoI. It is easier for competing /// programs to get astronauts into Kerbin orbit than it is to Mun/Minus. None of them are as good as you are. /// </summary> /// <returns>The recruitment modifier due to.</returns> double getRecruitmentSoIModifier () { if (!vessel.LandedOrSplashed) { ////print(FlightGlobals.currentMainBody.name); double recruitmentRateModifier = 0d; //if(vessel.situation.ToString == "Orbit") switch (FlightGlobals.currentMainBody.name) { case "Kerbin": //Debug.Log (debuggingClass.modName + "Currently near Kerbin!"); recruitmentRateModifier = 1.0; return recruitmentRateModifier; case "Mun": //Debug.Log (debuggingClass.modName + "Currently near Mun!"); recruitmentRateModifier = 0.5; return recruitmentRateModifier; case "Minmus": //Debug.Log (debuggingClass.modName + "Currently near Minmus!"); recruitmentRateModifier = 0.25; return recruitmentRateModifier; default: //Debug.Log (debuggingClass.modName + "I don't care where I am!"); recruitmentRateModifier = 0; return recruitmentRateModifier; } } //Debug.Log (debuggingClass.modName + "I'm landed!"); return 0;//else case } } } Which inherits: using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; using KSP; namespace CivilianPopulationRevamp { //[KSPAddon (KSPAddon.Startup.Flight, false)] public class CivilianPopulationRegulator : BaseConverter { /// <summary> /// The current rate at which a civilian is created. Typically around 1E-8 to start. /// </summary> [KSPField (isPersistant = true, guiActive = true, guiName = "Current Growth Rate")] public double percentCurrentCivilianRate = 0d; [KSPField (isPersistant = true, guiActive = false)] public double populationGrowthModifier; /// <summary> /// The time until taxes; once each day /// </summary> [KSPField (isPersistant = true, guiActive = true, guiName = "Time until Rent payment")] public double TimeUntilTaxes = 21600.0; /// <summary> /// The last time since calculateRateOverTime() was run. Used to calculate time steps (?) /// </summary> [KSPField (isPersistant = true, guiActive = false)] public float lastTime; //only one part with this can be the master on any vessel. //this prevents duplicating the population calculation public bool master = false; public bool slave = false; /// <summary> /// Gets the first part within the vessel implementing Civilian Population and assigns it as the master. Also /// sets all other parts implementing Civilian Population as slaves. /// </summary> /// <returns>The master part.</returns> public growthRate getMaster<growthRate> (List<growthRate> partsWithCivies) where growthRate: CivilianPopulationRegulator { growthRate foundMaster = null; foreach (growthRate p in partsWithCivies) { if (p.master) { //initially only executes if master is set in OnStart() if (foundMaster != null) { //if this is NOT the first time executing; seems to never execute p.slave = true; p.master = false; Debug.Log (debuggingClass.modName + "Master part found; set to slave"); } else { foundMaster = p; Debug.Log (debuggingClass.modName + "Master part set"); } } } return foundMaster;//first part containing Civilian Population resource } /// <summary> /// Checks status of on scene, vessel, and pre-initiliazation of craft. /// </summary> /// <returns><c>true </c>, if active flight and no master/slave detected in part, <c>false</c> otherwise.</returns> public bool getCheckForUpdate () { if (!HighLogic.LoadedSceneIsFlight) {//only care about running on flights because master/slaves are being set once return false; } if (this.vessel == null) { //Make sure vessel is not empty (likely will cause error) return false; } if (master || slave) { //If (for whatever reason) master/slaves already assigned (such as previous flight) return false; } return true; } /// <summary> /// Counts Civilians within parts implementing CivilianPopulationRegulator class. This should be limited to only /// Civilian Population Parts. It also only counts Kerbals with Civilian Population trait. Iterates first over each /// part implementing CivilianPopulationRegulator, and then iterates over each crew member within that part. /// </summary> /// <returns>The number of Civilians on the ship</returns> /// <param name="listOfMembers">List of members.</param> public int countCiviliansOnShip<growthRate> (List<growthRate> listOfMembers) where growthRate: CivilianPopulationRegulator //to get current ship, use this.vessel.protoVessel { int numberCivilians = 0; foreach (growthRate myRegulator in listOfMembers) {//check for each part implementing CivilianPopulationRegulator if (myRegulator.part.protoModuleCrew.Count > 0) { foreach (ProtoCrewMember kerbalCrewMember in myRegulator.part.protoModuleCrew) {//check for each crew member within each part above if (kerbalCrewMember.trait == debuggingClass.civilianTrait) { numberCivilians++; }//end if civilian }//end foreach kerbalCrewMember }//end if crew capacity }//end foreach part implementing class return numberCivilians;//number of Kerbals with trait: debuggingClass.civilianTrait -> Civilian } public int countNonCiviliansOnShip<growthRate> (List<growthRate> listOfMembers) where growthRate: CivilianPopulationRegulator { int numberNonCivilians = 0; foreach (growthRate myRegulator in listOfMembers) {//check for each part implementing CivilianPopulationRegulator if (myRegulator.part.protoModuleCrew.Count > 0) { foreach (ProtoCrewMember kerbalCrewMember in myRegulator.part.protoModuleCrew) {//check for each crew member within each part above if (kerbalCrewMember.trait != debuggingClass.civilianTrait) { numberNonCivilians++; }//end if nonCivilian }//end foreach kerbalCrewMember }//end if crew capacity }//end foreach part implementing class return numberNonCivilians;//number of Kerbals without trait: debuggingClass.civilianTrait -> Civilian } /// <summary> /// Counts the civilian seats on ship. /// </summary> /// <returns>The civilian seats on ship.</returns> /// <param name="listOfMembers">List of members.</param> public int countCivilianSeatsOnShip<growthRate> (List<growthRate> listOfMembers) where growthRate: CivilianPopulationRegulator { int numberPossibleSeats = 0; foreach (growthRate myRegulator in listOfMembers) { numberPossibleSeats += myRegulator.part.CrewCapacity; } return numberPossibleSeats; } /// <summary> /// Calculates the rent based on the number of Kerbals within a ship. /// TODO: Implement changing values after mod successfully altered /// </summary> /// <returns>The total rent.</returns> /// <param name="numberOfCivilians">Number of civilians.</param> int calculateRent (int numberOfCivilians) { int rentRate = 200; int totalRent = 0; totalRent = numberOfCivilians * rentRate;//Use fixed value for testing return totalRent; } /// <summary> /// Gets the highest module growth rate of all modules on the craft. Growth rates come from the part's .cfg files. /// </summary> /// <returns>The highest module growth rate.</returns> /// <param name="listOfMembers">List of members.</param> public double getHighestModuleGrowthRate<growthRate> (List<growthRate> listOfMembers) where growthRate: CivilianPopulationRegulator { double exponentialRate = 0d;//the malthusian parameter used to calculate the population growth. Taken as largest value on vessel. foreach (CivilianPopulationRegulator myRegulator in listOfMembers) { if (myRegulator.populationGrowthModifier > exponentialRate) { exponentialRate = myRegulator.populationGrowthModifier; } } return exponentialRate;//returns the largest rate among parts using CivilianPopulationRegulator class. } /// <summary> /// This method will place a new civilian in a part containing CivlianPopulationRegulator. It should only /// be called when there are seat positions open in onesuch part. Perhaps in the future, there will be a specific /// part that generates Civilians. /// </summary> /// <param name="listOfMembers">List of members.</param> public void placeNewCivilian<growthRate> (List<growthRate> listOfMembers) where growthRate : CivilianPopulationRegulator { ProtoCrewMember newCivilian = createNewCrewMember (debuggingClass.civilianTrait); bool civPlaced = false; foreach (growthRate currentPart in listOfMembers) { if (currentPart.part.CrewCapacity > currentPart.part.protoModuleCrew.Count () && !civPlaced) { if (currentPart.part.AddCrewmember (newCivilian)) { Debug.Log (debuggingClass.modName + newCivilian.name + " has been placed successfully by placeNewCivilian"); civPlaced = true; } } } if (civPlaced == false) Debug.Log (debuggingClass.modName + "ERROR: " + newCivilian.name + " could not be placed in method placeNewCivilian"); } /// <summary> /// Creates the new crew member of trait kerbalTraitName. It must be of type Crew because they seem to be the only /// type of Kerbal that can keep a trait. /// </summary> /// <returns>The new crew member.</returns> /// <param name="kerbalTraitName">Kerbal trait name.</param> ProtoCrewMember createNewCrewMember (string kerbalTraitName) { KerbalRoster roster = HighLogic.CurrentGame.CrewRoster; ProtoCrewMember newKerbal = roster.GetNewKerbal (ProtoCrewMember.KerbalType.Crew); KerbalRoster.SetExperienceTrait (newKerbal, kerbalTraitName);//Set the Kerbal as the specified role (kerbalTraitName) Debug.Log (debuggingClass.modName + "Created " + newKerbal.name + ", a " + newKerbal.trait); return newKerbal;//returns newly-generated Kerbal } /// <summary> /// Gets the delta time of the physics (?) update. First it confirms the game is in a valid state. Then it calculats /// the time between physics update by comparing with Planetarium.GetUniversalTime() and GetMaxDeltaTime(). /// </summary> /// <returns>The delta time.</returns> protected double GetDeltaTimex () { if (Time.timeSinceLevelLoad < 1.0f || !FlightGlobals.ready) { //Error: Not sure what this error is for...maybe not enough time since load? Debug.Log(debuggingClass.modName + "ERROR: check timeSinceLevelLoad/FlightGlobals"); Debug.Log(debuggingClass.modName + "timeSinceLevelLoad = " + Time.timeSinceLevelLoad); Debug.Log(debuggingClass.modName + "FlightGlobals.ready = " + !FlightGlobals.ready); return -1; } if (Math.Abs (lastUpdateTime) < float.Epsilon) { //Error: Just started running Debug.Log(debuggingClass.modName + "ERROR: check lastUpdateTime"); Debug.Log(debuggingClass.modName + "lastUpdateTime = " + lastUpdateTime); lastUpdateTime = Planetarium.GetUniversalTime(); return -1; } var deltaTime = Math.Min (Planetarium.GetUniversalTime () - lastUpdateTime, ResourceUtilities.GetMaxDeltaTime ()); return deltaTime; //why is deltaTime == 0? //return deltaTime; } public void getTaxes (int numCivilians, double reduceTime) { int rentAcquired = 0; TimeUntilTaxes -= reduceTime; if (TimeUntilTaxes <= 0) { rentAcquired = calculateRent (numCivilians); Funding.Instance.AddFunds (rentAcquired, TransactionReasons.Vessels); TimeUntilTaxes = 21600; } } /// <summary> /// Looks over vessel to find amount of a given resource matching name. In this project's scope, it is used /// in order to determine how far along the civilian growth counter is towards creating a new Kerbal. /// </summary> /// <returns>The amount of resource matching name.</returns> /// <param name="name">Name.</param> public double getResourceBudget (string name) { if (this.vessel != null) { var resources = vessel.GetActiveResources (); for (int i = 0; i < resources.Count; i++) { if (resources [i].info.name == name) { return (double)resources [i].amount; } } } return 0; } //Anything below this, I don't know what it does but it is essential to keep from seeing //"No Resource definition found for RESOURCE" error message in OnFixedUpdate. [KSPField] public string RecipeInputs = ""; [KSPField] public string RecipeOutputs = ""; [KSPField] public string RequiredResources = ""; public ConversionRecipe Recipe { get { return _recipe ?? (_recipe = LoadRecipe ()); } } private ConversionRecipe _recipe; protected override ConversionRecipe PrepareRecipe (double deltatime) { if (_recipe == null) _recipe = LoadRecipe (); UpdateConverterStatus (); if (!IsActivated) return null; return _recipe; } private ConversionRecipe LoadRecipe () { var r = new ConversionRecipe (); try { if (!String.IsNullOrEmpty (RecipeInputs)) { var inputs = RecipeInputs.Split (','); for (int ip = 0; ip < inputs.Count (); ip += 2) { print (String.Format ("[REGOLITH] - INPUT {0} {1}", inputs [ip], inputs [ip + 1])); r.Inputs.Add (new ResourceRatio { ResourceName = inputs [ip].Trim (), Ratio = Convert.ToDouble (inputs [ip + 1].Trim ()) }); } } if (!String.IsNullOrEmpty (RecipeOutputs)) { var outputs = RecipeOutputs.Split (','); for (int op = 0; op < outputs.Count (); op += 3) { print (String.Format ("[REGOLITH] - OUTPUTS {0} {1} {2}", outputs [op], outputs [op + 1], outputs [op + 2])); r.Outputs.Add (new ResourceRatio { ResourceName = outputs [op].Trim (), Ratio = Convert.ToDouble (outputs [op + 1].Trim ()), DumpExcess = Convert.ToBoolean (outputs [op + 2].Trim ()) }); } } if (!String.IsNullOrEmpty (RequiredResources)) { var requirements = RequiredResources.Split (','); for (int rr = 0; rr < requirements.Count (); rr += 2) { print (String.Format ("[REGOLITH] - REQUIREMENTS {0} {1}", requirements [rr], requirements [rr + 1])); r.Requirements.Add (new ResourceRatio { ResourceName = requirements [rr].Trim (), Ratio = Convert.ToDouble (requirements [rr + 1].Trim ()), }); } } } catch (Exception) { print (String.Format ("[REGOLITH] Error performing conversion for '{0}' - '{1}' - '{2}'", RecipeInputs, RecipeOutputs, RequiredResources)); } return r; } } } Has anyone ever seen anything like this before?
  20. I've done some reading and casting looks like it'll work well. Now to figure out how to use git while my code still runs! Good to know. I'll test to see how base interacts, but that will be after I've had some time to start writing the new classes. Again, thank you!
  21. Thank you. I knew about overloading constructors but didn't put it together with the fact that constructors are methods, too...oops! And then I can have the overloaded methods call a common (regular) method. For the second question, you're spot on. I'm asking how I can split OnFixedUpdate process between an extended class and the extending class. In the testing I've done thusfar, it looks like the override modifier overrides all instances of OnFixedUpdate(). I was wondering if there was a way around that. If not, I will call the methods and logic within the respective extending classes. edit: Here is the code I am using to check if OnFixedUpdate() will run in extended classes: using System; using UnityEngine; using KSP; namespace PopulationMod { public class CivilianDockGrowth: PartModule { public override void OnFixedUpdate () { Debug.Log (debuggingClass.modName + "CivilianDockGrowth checking in!"); } public class CivilianSpawnGrowth: CivilianDockGrowth { public override void OnFixedUpdate () { Debug.Log (debuggingClass.modName + "CivilianSpawnGrowth checking in!"); } } } And I'm implementing it in a part's .cfg within module like so: MODULE { name = CivilianSpawnGrowth } Which outputs: [LOG 17:28:09.198] [CivilianPop Revamp]CivilianSpawnGrowth checking in! [LOG 17:28:09.202] [CivilianPop Revamp]CivilianSpawnGrowth checking in! [LOG 17:28:09.204] [CivilianPop Revamp]CivilianSpawnGrowth checking in! [LOG 17:28:09.257] [CivilianPop Revamp]CivilianSpawnGrowth checking in! [LOG 17:28:09.258] [CivilianPop Revamp]CivilianSpawnGrowth checking in! Note that CivilainDockGrowth is never reported to the log.
  22. Hello all, I'm trying to figure out how to implement a few classes. Right now, I have a class called OldClass. Despite my best efforts, it is trying to do too many things and needs to be split into two classes that both inherit from a third. To avoid confusion, here is a quick key for what I'm talking about: Current (bloated) class -> OldClass Base class to be inherited from -> newBaseClass Class to extend newBaseClass -> extendingClass1 Class to extend newBaseClass -> extendingClass2 Currently, OldClass has a few methods to generate a list of all parts extending itself. These methods will have to be used again for each of the inheriting classes. However, these methods are set up to use that list as arguments of type OldClass. For example, method: int countCiviliansOnShip (List<OldClass> listOfMembers) { int numberCivilians = 0; foreach (OldClass myRegulator in listOfMembers) {//check for each part implementing CivilianPopulationRegulator if (myRegulator.part.protoModuleCrew.Count > 0) { foreach (ProtoCrewMember kerbalCrewMember in myRegulator.part.protoModuleCrew) {//check for each crew member within each part above if (kerbalCrewMember.trait == debuggingClass.civilianTrait) { numberCivilians++; }//end if civilian }//end foreach kerbalCrewMember }//end if crew capacity }//end foreach part implementing class return numberCivilians;//number of Kerbals with trait: debuggingClass.civilianTrait -> Civilian } In brief, the above code iterates across every member of the list, gets the crew types within those parts, and checks if it is a civilian. All of that is exactly what I want both classes to do. The only change that needs to be made is changing from an argument of List<extendingClass1> or List<extendingClass2>, pending which class is calling it. Is that possible/advisable? Or would I be better off copy/pasting that function in each class? And another question: Currently OldClass is overriding OnFixedUpdate(). Should I leave it and the common method invocations in newBaseClass, with extendingClass1 and extendingClass2 calling only what is different? Or should there be no OnFixedUpdate() method in newBaseClass, instead have it only called in extendingClass1 and extendingClass2? Thank you!
  23. Personally, I'm using a Logistic function for the growth rate. It is simple to implement and gives at minimum two "valves" to control as well as encouraging large bases: The maximum rate at half population/exponential windup (function of both r and K, below) and carrying capacity (maximum number of civilians, K). rate = dN/dt = rN*(1-N/K) N -> current (civilian) population r -> maximum rate variable K -> Maximum capacity variable In C#, it looks like this: double calculateGrowthRate (double maximumSeats, double maximumSteepness, double currentPopulation) { double populationGrowthRate = 0; populationGrowthRate = maximumSteepness * currentPopulation * (1 - (currentPopulation / maximumSeats)); return populationGrowthRate; } From there, multiply the returned value by change in time and update the population resource.
  24. I'm still trying to wrap my head around the code, specifically the methods calculateRateOverTime() and GetInfo() in the class CivilianPopulationRegulator. The method GetInfo is a virtual method that is an inherited method, originally in PartModule. The API description is "The return value of this function appears in the part's description in the editor. Returns - Editor info for the part". However, I can't find anything that mentions days or hours in the editor. Meanwhile, the method CalculateRateOvertime looks like it is never called. Do you have any insight on these that you can share?
×
×
  • Create New...