

mpink
Members-
Posts
58 -
Joined
-
Last visited
Content Type
Profiles
Forums
Developer Articles
KSP2 Release Notes
Everything posted by mpink
-
How do you launch multiple craft from one pad at the same time ? Hi. I am an old ksp player and I am trying to play an 18 T / 30 Part stock career mode game. My 1st return probe mun lander involves 5 separate craft and to avoid the "Clear Launch Pad" problem I am currently driving them all to the crawler way. This is very time consuming and annoying. I have tried various different google searches but can not seam to find a simple solution. I have also had a good look in the settings/physics/save files but cant seam to find anything relevant. So i am also curious now as to where the defining values for the different levels of Pad & VAB are hiding ? (Size, Mass & Part limit values) It would be nice to upgrade the look of my pad whilst keeping the limits in place. Any mod ideas, setting names or thoughts of any kind would be much appreciated. Thanks very much.
-
Hi there and welcome to the career mode hotseat challenge. The idea is that you download the latest save game directory, present a mission plan (as to claim the seat before flying any long missions) fly a mission and then upload your save directory and make a report. I find Dropbox very handy for shearing files like this. I say directory as i would like to test your craft and we may like some shared parts/craft as the game develops. I strongly suggest saving craft using the naming system of MissionNumber(3 digets) - ForumName - CraftName. So my 1st mission shall have a craft named "001 - MPink - Experimental 5K VTOL" and you will only need to remember a mission number in order to find a craft you may want to use again later (+ alphabetical mission order sorting). Rules The career mode is running in hard mode but with a few added restrictions to make it more interesting. 1) As you may have spotted all craft must be 100% reusable. By that i mean all craft parts should theoretically be 100% recoverable (land on the pad or runway) but i understand that sometimes things don't go as planed . This adds some difficulty with some missions as testing decouplers at low altitudes is as good as impossible and early exploration missions are extremely difficult to return from. Theoretically we could collect old satellites later in the game using retrieval craft. Having extra fuel on them to help with making a return rondaview would go a very long way to convince me that you haven't just chucked it into space and forgotten about it. 2) No pilot purchase. When your dead your dead. We should be able to rescue a few pilots hear and there but i doubt we shall ever produce a colony. 3) No contract skipping. Canceling a contract is different and allowed as it has a financial penalty and sometimes you might just take a contract to unlock a part you need for another mission but clicking the X on a mission you dont like the look of is just cheating. 4) only one launch per turn. Some missions may need multiple launches that require the next player to continue where you left off. An exception to this is placing a target on the pad as to help guide you back home. This can be done when your over the 30K mark and helps hugely with guiding you back home. Using and empty decopler on the pad results in an explosion but yes you can place a target on the pad at launch time too, It just needs to be 2 parts and have some mass to it. 5) No double seating. After you have flown a mission You must wait for another player to fly before taking the seat again. Mods Im more of a stock player myself but see no reason why you cant use a mod just as long as the save can still run in a stock version afterwards. No longterm craft with parts that are not stock. When we get to some serious missions I think Kerbal Engineer will be a must. Scoring Im intending to keep a score of the missions and try to rate them all. This may be complicated and depend a lot on my mood though so you must understand its just a bit of fun. Max 10 points for accomplishing your mission objective (gaining science, cash & crew). Max 10 points for presentation of report. Im going to try a make a video for every mission I do using afterburner to capture then VLC to encode and youtube to edit. I see no reason why a few screen shots with some well thought out words wouldn't get a good score too though. Its all about telling the story. Max 10 points for your piloting awesomeness. Im not sure what will be good enough for a 10 at this stage or even how I might judge it without a video. My thoughts are to test the craft made and compare it to what you have done. Some craft are just impossible to fly so may score high for just not killing everyone. Recovering from an accident would be a great way to score points hear but then your likely to lose some in other areas for that. Bonuses 1 SemiBull = Landing just off the center of the landing pad. 2 BullsEye = Landing exactly in the center of the pad. 5 Deadeye = Landing in the center of the pad from orbit. 2 Cleaner = Returning a craft/part left by someone else but only after your primary mission is done. 5 VomitComet = Making a flight with no chance of using SAS. -2 Junker = Some part of your craft was not recovered. -10 Destroyer = Crashing a perfectly good craft or trying to land on a building and breaking it. -15 Killer = You ended a pilots life. Im sure there shall be more so if you can think of a reason your flight deserves extra points then you should state it in your report. Leaderboard 1) 14 - MPink - Mission 001 2) 3) 4) 5) Bare with me as i do the 1st mission to demonstrate. humm so you cant make double posts and self bump your own thread now then. Ill just have to hope that people are willing comment and chat as we get this thing started. - - - Updated - - - Mission 001 Plan Reach the 5K mark and bring home some much needed cash/science while demonstrating that it is possible to land back on the pad. We need at least 5 science to open the next tech so I shall try "Launch new Vesal" + "Set Altitude Record" for an expected return of just under 4K and at least 3 science. Starting with 10K cash and 0 science/reputation (before excepting contracts or doing anything) at Year 1 Day 1 0H 0M. There shall be a small gap while I attempt the mission but I shale return with the save file shortly. - - - Updated - - - Mission 001 Report Mission 001 Save File jeb achieved both missions and done some science landing back on the pad safely. He generated 12.4 Science and upped the cash to 15,286 so managed to bring home 1K more than i was expecting he managed all this in about 2mins of game time but it sure seamed like longer to me. - - - Updated - - - Judging Mission 001 Well ill give the mission a score of 4. It achieved all the goals it set out to but only bringing back 12.4 science on the first mission isnt hugely helpfully. For the report ill give a 5. The mouse pointer is missing there wasn't any commentary or story telling and the music just overruns a little. On the upside though it dose demonstrate using cockpit mode to get better accuracy with the navball. Piloting will get you a 4. At 5K you can still do this all by eye and don't need SAS at all. I should have hit the black dot exactly at this range with that much fuel and how hard is flying in a straight line anyways. +1 for a BullsEye (ill count the whole grey circle as a bull and it should be about the same size as the mesh on the next pad) for a Total of 14 Points
-
Usefulness of Girders, Adapters and the Like
mpink replied to frog's topic in KSP1 Gameplay Questions and Tutorials
I found the Girder Segment very handy in career mode. on my 1st mission i added extra parachutes using them as mounts. On my 2nd mission i used them to connect 6 engines to an X200-8 fuel tank producing an expensive and dangerous version of a mainsail. The Girder Segment has a very strange fuel flow that only works in one direction when using surface attachment so it can be very handy for making drive sections. -
I most certainly am interested thanks Im not sure at this point that its going to be at the same level as what i was thinking as we seam to have a very different idea as to when errors could happen and what they should be but then i have only just read about it and not played it so i should go investigate..............
-
Hi there I was watching the and they mentioned the problems of trying to launch a rocket with 30 engines and how the chance of problems drastically increases with more engines.This got me thinking about an engine failure mod and how much it would change the early stages of career mode. So the theory gos a bit like this. When you light up an engine a random number is produced to see if something gos wrong. If a problem is detected a second number is generated to determine what the problem is from an engine specific error table. For the moment im just thinking about engine problems and not trying to make a mock-up of the error tables. A single Engine Error may trigger multiple engine problems that may change in severity over time so at this point im just trying to think of the simple problems that may happen and would love your help with suggestions. All Engines Explode - The engine just explodes (Part.explode()) Liquid Engines Overheat - The engine generates more heat so it will explode if you dont reduce the thrust (ModuleEngines.heatProduction). Thrust Limit - The engine is limited to a maximum % thrust so you must re-balance the craft in flight (ModuleEngines.thrustPercentage.maxValue). Efficiency Problem - Lowering the ISP by a small amount would result in a fuel balance problem that cant be fixed by simple thrust adjustment on other engines (ModuleEngines.atmosphereCurve[]). Hydraulic Leak - The engines gimbal slows down until it locks into place (ModuleGimbal.gimbalResponseSpeed (Could be overridden by using lock gimbal button and forcing downward thrust again)). Stuck Valve - The engines throttle gets stuck at its current setting and so dosnt change with the throttle control (ModuleEngines.engineAccelerationSpeed ModuleEngines.engineDecelerationSpeed). Damaged Ignitor - Prevents the engine from restarting if it is shutoff (ModuleEngines.allowRestart). Solid Engines Cracked Seal - The engine has a random crack causing thrust to escape. To do this i would randomly place a hacked sepratron and reduce the fuel and thrust values of the original engine. Broken Nozzle - This is just a combination of Efficiency Problem and Thrust Limit but combined in a way as to maintain the same burn time with reduced thrust. I have thrown together a basic test mod implementing the Explode result as it is the easiest to program and tested this with the LV30 and LV45 in the early stage career mode. I have found it changed my design style and launch method a bit as I now have my launch towers on a separate stage so i can test my engines on low power before launching. I also try harder to not layer my rocket with extra engines in separate stages as i know there is a chance they will pop when i light them up. The final change its forced on me is to maintain a low level of thrust for the full orbital insertion as apposed to reaching a targeted speed and shutting the engines off until AP is reached. Just for fun hears the chance table for 30 engines each having a 5% chance of error Engines | Chance Change | Chance Of Error ---------------------------------------------- 1 | 5.00% | 5.00% 2 | 4.75% | 9.75% 3 | 4.51% | 14.26% 4 | 4.29% | 18.55% 5 | 4.07% | 22.62% 6 | 3.87% | 26.49% 7 | 3.68% | 30.17% 8 | 3.49% | 33.66% 9 | 3.32% | 36.98% 10 | 3.15% | 40.13% 11 | 2.99% | 43.12% 12 | 2.84% | 45.96% 13 | 2.70% | 48.67% 14 | 2.57% | 51.23% 15 | 2.44% | 53.67% 16 | 2.32% | 55.99% 17 | 2.20% | 58.19% 18 | 2.09% | 60.28% 19 | 1.99% | 62.26% 20 | 1.89% | 64.15% 21 | 1.79% | 65.94% 22 | 1.70% | 67.65% 23 | 1.62% | 69.26% 24 | 1.54% | 70.80% 25 | 1.46% | 72.26% 26 | 1.39% | 73.65% 27 | 1.32% | 74.97% 28 | 1.25% | 76.22% 29 | 1.19% | 77.41% 30 | 1.13% | 78.54% I am testing with a 5% error chance and trying to do Mun flybys using a 19 engine design. The 1st stage of 12 booster engines has had problems a few times and i can just shut off the opposite engine and still reach orbit with no problems. If the 2nd or 3rd stage engine breaks on ignition it is a fail and we have to shutdown and recover. Iv not had the 3rd stage engine break whilst attempting reentry yet but 5% is a bit steep so it will happen one day.
-
Thanks. That is about what i expected its just the Altitude score i find a bit confusing. i think ill have to collect all those distinctions just for the sake of it. As for Relaunching, Well im 100% certain i can do it but ill probably take a week or 2 fiddling with things. I tested the HLS with a tailless configuration and a pair of quad docked top and bottom boosters. The fuel line system is something of a maze but all went as planed and seams to work. Is there any rule against refueling ? Im assuming that i cant just refuel at an orbital fuel dump or else we could go almost anywhere with just a little planing ? Then im wondering how this would relate to Relaunching as i could place fuel in the 1st launch to get the 2nd payload to the Mun but it would all be fuel from one single mission ? Humm yeah well that sounds confusing .
-
Oh shuttles...... Can i play Pnk Engineering proudly presents the HLS Tweed. A heavy lift shuttle that can place an orange tank into LKO and return return safely. Its a bit lame not putting doors on or even a belly but what can i say.... i was having flashbacks of thunderbird 2. Errr im not too sure how this scoring works yet but that is a 36.05T payload into an 86K-184K Kerbin orbit. LOL sounds like fun but i have a question 1st. When i land my next shuttle and manage to get it back on the pad pointing at the sky with a new payload in it and new boosters strapped to it, Will you give me any more points for the 2nd payload delivery and how would the scoring for that work ?
-
Oh I think all stock shuttle builders have had those unable to redock days. Do you get any attraction ? You just have to keep trying until it all works out. Just a slight bit of clipping or angle mismatch can give you a very bad day. A small problem with my shuttle means the crew are trapped in there pod. This is a shame as I'd love to plant a flag on minmus. This makes for an interesting landing and reentry procedure. I need to redo the nose for a better look anyways so I might have an attempt at a single part sliding door. Oh thats cute. I love the boostets with the solid bottoms and those nose cones.
-
Pnk Engineering is proud to present the CSS Stour The Constructable Space Shuttle is an attempt to make a stable shuttle system that can be transported and launched from wherever you please. In its first few tests it happily places 22.5T into LKO. It is totally stock but I use hyper edit to fuel the craft when it has been constructed. The odd payload is due to a challenge entry where fuel mass didn't count towards payload points so i just filled it with the heaviest things i could find . The zip file contains a persistent save file identical to the start of the video and a number of SPH craft and some subassemblys. The SPH has 2 very useful craft test craft. CSS Stour (Landing Practice) is a stripped down version that can reach 10K meters before running out of fuel (Perfect for practicing landings). CSS Stour (Launch Test) is a fully constructed and ready to launch version of the shuttle. Reentry Reentry can be a bit tricky but i suggest placing your PE just above the island to the right of the KSC at 37.2K meters and then maintain a 15 degrees nose up. Any less than 15 degrees and the tail will burn up so when you hit 30K try and maintain 20 degrees. The glide slope is very shallow and has 3 points for checking your position. The main target is to hit 30K and the start of reentry effects as you hit the landmass that KSC is on. As you leave the landmass before that you should be at about 39K. This is where deceleration starts to take effect and is your last chance to correct using engines. Its about 90 seconds from hear untill the next checkpoint. The end of the landmass prior to this one is about the start of the atmosphere and you should be at 47K. You will decelerate by around 150 M/S by the time you hit the next check point so wings arnt going to do very much at this point but they may make a small difference and small changes at this point make for large changes in your landing zone. After reentry effects have stopped at about 20k and before you hit the soup 10K you should use all your remaining fuel. The engines will help to shallow out you glide slope and if you still have the mass of the fuel when you hit the soup you will just fall instead of gliding. In this uncut landing video you can see a demonstration of me coming in too step and correcting the slope using the check point system. I think the problem was due to not doing the deorbit burn on the opposite side of the planet to the KSC. There are also some very confusing readings on the nav ball due to it changing to target mode and me not noticing. Hot Keys. 1) Undock cargo bay doors. 2) Toggle door wheals. 3) Toggle payload wheals. 4) Toggle booster/shuttle wheals. 6) Undock Jet sled / Construction plates. 7) Toggle jet sled wheels. 8) Toggle forward jet engines. 9) Toggle Backward jet engines. Tips for construction The sled needs to drop half a meter to connect with the Construction Plates so you need to get the hang of rolling whilst toggling the wheals (7). The back booster and shuttle have a slight mismatch in height that needs to be corrected by changing to the back booster and toggling its wheals. This makes the first docking very hard but it is doable. This unedited construction video demonstrates shows the entire construction with all the problems of docking. I am fairly certain that all problems with primary and secondary docking ports and fuel flow are now fixed but iv only done two constructions of the Stour and so theres is always a chance something like this may happen again. If you detect a problem below 10K i strongly suggest cutting the engines and dropping the boosters and tanks. At 10K you should have more than enough fuel in the shuttle to turn around and land back on the runway. I had already rendered and uploaded the construction videos as prof for a challenge so I did every thing i could to make orbit. That early version just had too many fuel flow problems though so was doomed.
-
Pnk Engineering proudly presents the CSS Stour. Stour you say........ what happened to the Derwent you say..... :Cough :Cough The Stour successfully made orbit with 59.38T and returned to the hanger at KSC. Unfortunately it was still carrying 522 units of fuel and 760 units of oxidizer witch in my book adds up to 6.41T. So with a Medium payload of 52.97 + 10 points for a 3rd stage + 25 points for returning i calculate a total of 299.85 points . Its very late and iv had a long day so im calling that a win on the bases of building on the pad, but im sure ttnarg wont give up and will find a way to get his idea working . There is also a full 15 minutes unedited version of the construction with all the docking problems for you entertainment / education. Oh the Derwent........ Well it had problems....... The booster fuel pipes added to maintain flow in the case of primary docking on the wings....... was bad . Even worse though was that i didnt notice that radial decoplers have cross feed ! This resulted in the new fuel pipes on the wing docking ports pulling fuel from the tanks that the wings were attached too . So i now present the death of the Derwent (All Hands Survived). I see a lot of room for improvement of the CSS series. I think if i had the patients it could make a hard entry but it would take a long time. It might be able to do a Mun flyby with minimal changes so i will looking into that. I also have the CIS (Constructable Interplanetary Shuttle) upgrade to the CSS planed out in my head and the CFS (Constructable Freight Shuttle) in low altitude landing tests. Im thinking i should test the CIS first as the upgrade would be transferable to the CFS and im not sure i would want to make the latter if it cant go off world. The Supper heavy lifter is still a long way off im afraid but it always sits in the back of my mind prodding at me. Im sure i can make a 100T hard lifter although i know i could score more making other craft. Breaking the 100T mark is a personal goal for me .
-
Thanks Mainly it was a test of my new GFX card. The cargo doors wasnt too hard. I have tried horizontal doors in the past but they are a nightmare. The hardest thing is balancing the wings as to be able to pull out of a 45 degree dive at 200/MS in less than 300 meters whilst not flipping out of control and crashing tail 1st. This also means it can maintain 20 degrees nose up on reentry. I think i said something about a supper heavy lifter a few months ago. I have an image of a test flight you might like too see. I made that hover plugin as i thought i would be able to build higher using a vertical build system. It turns out though that 3 orange tanks is about the limit of what my reinforced large docking port can take . Oh and then there is the the difficulty in trying to move a layer containing 9 orange tanks :rofl Iv still got some ideas about a stock only supper heavy lifter but ill keep them to myself for the moment. The CSS Derwent had its 1st successful test flight (including construction) today and a full video should be ready for the submission by Friday night. It most certainly can and will be constructed on the pad. I think i will release the ship and construction system somewhere too. I remember seeing a shuttle thread in the exchange section some time ago. There is still the possibility of having the primary docking port on a wing and so iv got some more pipes to add just in case this ever happens. Hummm.... I cant help but have thoughts about building off world now. Duna seams a little thin on the atmospheric side but both eve and Laythe could support parachute drops of components. I think it would take more than 1 craft for the construction though as you would need to roll the components into an upright position before starting the build. :daydreams seeing a shuttle aerobraking around jool would be very cool.
-
Oh Ship..... Well done ttnarg, excellent vessel. I so should have checked for new posts before working so hard at my next entry. What can i say, I just didnt think there was anyone else crazy enough to give this a serious try. The construction phase is still all in my head but im sure it wouldn't have been to hard compared to the rest of the build so far. It was going to be a constructable shuttle system. In the demo video it delivers 42.24T to orbit. I was planing to enter at medium and claim top position at all levels so with -4.27T of fuel it would have been 189.85 points in payload. Well it still makes for an interesting video if youv got 8 mins to waste. I dont know what to do now though. A redesign for a 100T Freight Shuttle could be interesting. On the other hand though cupcake could always introduce a new 2X points bonus for landing back at KSC (exact point from where your meant to start) and then it might be worth me making the constructor.
-
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Lol yeah only Kethane, Engineer and AHS myself. Iv tried to stay away from mods to keep my lag under control. Iv bumped into the mem limit in other threads before http://forum.kerbalspaceprogram.com/threads/43600-Allowing-KSP-to-use-more-than-4gb-of-memory As for lag well..... iv only just grabbed myself a gfx card (was using an inbuilt) so im used to it and even with the card my comp cant seam to get the physics over 0.3X-0.4X My main lunch system is running around 700 parts and drops down to 0.25X at the moment but compered to what it was before the 0.23 physics update it feels very smooth to me. In the older versions i had to reduce the physics frames and could not build over 200 parts without explosions. Iv got to try videoing a launch of the 5 orange tank Fuel Transport System. Its a true monster . -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Yeah its my attempt at balancing and so dosnt have much of a place in real life. The mass of the small AHS is based on the Advanced Stabilizer (0.5T with a 9MS crash tolerance). As the Small AHS has a 30MS tolerance it seams fair to be 1.5T ? Im not claiming that the computer system is heavy just the container. Following this though the Large AHS should probably only be around 1.4T as the larger default control system is only 0.2T but this seams a bit unfair as it has a 60/MS tolerance with 6 node attachments and crossfead ability. Yeah true i was just trying to link systems to provide a reason for adding sensors to your craft. I think in real life i would want at least 3 or more gravity and accelerometer sensors but yeah to make things easier to use i should include them in the AHS. Thanks it also has the advantage of not loading any extra models or textures so shouldn't waste any memory (Theres often talk of a memory limit when using lots and lots of plugins) To reduce heat you must place parts onto the Part producing heat and these connected parts absorb heat and convert it into light dissipating it. Iv been using it to build my space stations without using RCS thrusters/tanks and iv been building a small 70T kethane mine on minmus. The plugin has become stupidly complex and should probably be broken into 2 different systems. After linking vertical speed control into the RCS forward/backward keys i just had to add a full RCS style control and they are most defiantly 2 different systems/plugins and should be split. So what im thinking is ill try to integrate engines into the default RCS systems and remove the complicated direction setup for the engines. Then i will add a simple on/off tweak for setting if an engine should be used to Hover. My biggest concern now though is not breaking my test colony but then i could just hack my save file and fix any compatibility problems. So far the colony consist of 7 parts. One of them is my low grav constructor better seen on the 2nd image attached to the stations core. It has been painful to get this far but the more it hurts me the faster ill get around to fixing it. -
Yeah i had the same problem. Half a full orange tank makes a huge impact force even at 1-2 M/S. Have you tryed using runners like my entry dose ? Watching the video will show them off in action (1st post). Not just do they help align for docking but they also take most of the impact in the suspension whilst correcting your angle so you hover towards the center point. Then on top of all of that i think i tested a 3X runner system with 3X mainsails pointing down at max throttle and the connection still did not break (well until the fuel run out and the suspension/clipping fired the engines into the sky).
-
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
All links have been updated to V0.41 And iv been working on some basic tutorial videos. Basic Hover Setup That all might be a lot more convincing if i were a better pilot Was stuck on a train for a few hours yesterday so i managed to sketch out and do some basic math for my kethane colony and look forward to giving this a true test. It will probably take me a week or 2 to get the videos made but they should be a lot more interesting from a showcase point of view. Change Log 0.41 Fixed stupid bugs so that the RCS Translation directions are the same as the RCS system (still dose not change perspective when using control from hear). Fixed silly bug where slaves were controlling as well as masters. Added 95% heat auto shutdown / crash state (wont always save you on a warp though) Running out of power now causes a crash state (When crashed the AHS needs to be shut down and started up again). Changed some of the max settings on sliders to try and give more precise control ( low end still seams to have a dead spot though ) Changed the gravity sensor reading so that the AHS gets its own supper precise gravity reading but only if a gravity sensor is in a working readable state. Added RCS Translation event and actions (No longer uses the RCS toggle). Removed the check for SAS toggle as hover mode replaced the need for this. Added Icon colours for the SAS stack icon (Cant use custom icons yet) so you can tell what state it is in at a glance without needing to right click the part. //M Pink provides AHS (v0.41) freely for anyone to use for anyreason they see fit. //M Pink is not responsable for any damage caused by AHS. //AHS Should Be Used At Your Own Risk ! using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; namespace AHS { public class Direction {//Put an end to the problems of compearing strings (miss spelling a direction) by using the AHS.Direction public const string None = "None"; public const string Left = "Left"; public const string Right = "Right"; public const string Up = "Up"; public const string Down = "Down"; public const string Forward = "Forward"; public const string Backward = "Backward"; } [KSPAddon(KSPAddon.Startup.MainMenu,true)] public class RCSAddonSetup :MonoBehaviour { void Awake () { Debug.Log("(AHS.RCSAddonSetup) Awake()"); PartLoader pl = PartLoader.Instance; if (pl==null) { Debug.Log("(AHS.RCSAddonSetup) Partloader was null"); } else { Debug.Log("(AHS.RCSAddonSetup) Partloader Found"); Debug.Log("(AHS.RCSAddonSetup) Number of parts to scan = "+pl.parts.Count); int a=0; for (a=0; a<pl.parts.Count; a++) { bool has_engine = false; bool has_rcs = false; bool throtle_locked = true;//fail safe. Only use if throtleLocked is found and false int b=0; for (b=0; b<pl.parts[a].moduleInfos.Count; b++) { if ("Engine" == pl.parts[a].moduleInfos[b].moduleName) has_engine=true; if ("RCSEngineTranslation" == pl.parts[a].moduleInfos[b].moduleName) has_rcs=true; } if (has_engine) {//parts that dont have a ModuleEngines will return null for FindModulesImplementing if (pl.parts[a].partPrefab.FindModulesImplementing<ModuleEngines>().Count!=0) { throtle_locked = pl.parts[a].partPrefab.FindModulesImplementing<ModuleEngines>()[0].throttleLocked; } } if (has_engine && !has_rcs && !throtle_locked) { Debug.Log("(AHS.RCSAddonSetup) Engine module found for "+pl.parts[a].title+" adding RCSEngineTranslation module"); pl.parts[a].partPrefab.AddModule("RCSEngineTranslation"); AvailablePart.ModuleInfo info = new AvailablePart.ModuleInfo(); info.moduleName = "RCSEngineTranslation"; pl.parts[a].moduleInfos.Add(info); }//endof if (has_engine && !has_rcs) }//endof for (a=0; a<pl.parts.Count; a++) }//end of else if (pl==null) } } public class RCSEngineTranslation : PartModule { [KSPField (guiName = "dimention", isPersistant=true, guiActive=false)] int dimention = 0; [KSPField (guiName = "direction", isPersistant=true, guiActive=false)] bool invert_direction = false; [KSPField (guiName = "RCS Direction", isPersistant=false, guiActive=true, guiActiveEditor=true)] public string state_string = "Not Set Yet"; [KSPEvent ( guiName="Next RCS Dimention", guiActive=true, guiActiveEditor=true )] public void EventNextDirection() { this.dimention++; if (this.dimention>3) this.dimention=0; this.DisplayMode(); } [KSPEvent ( guiName="Togle RCS Direction", guiActive=true, guiActiveEditor=true )] public void EventTogleDirection() { this.invert_direction = !this.invert_direction; this.DisplayMode(); } [KSPAction ("Set RCS None")] void ActionSetRCSNone () { this.dimention=0; this.DisplayMode(); } [KSPAction ("Set RCS Left")] void ActionSetRCSLeft () { this.dimention=1; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Right")] void ActionSetRCSRight () { this.dimention=1; this.invert_direction=true; this.DisplayMode(); } [KSPAction ("Set RCS Up")] void ActionSetRCSUp () { this.dimention=2; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Down")] void ActionSetRCSDown () { this.dimention=2; this.invert_direction=true; this.DisplayMode(); } [KSPAction ("Set RCS Forward")] void ActionSetRCSForward () { this.dimention=3; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Backward")] void ActionSetRCSBackward () { this.dimention=3; this.invert_direction=true; this.DisplayMode(); } public void DisplayMode () { switch (this.dimention) { case 1: if (!this.invert_direction) this.state_string=Direction.Left; else this.state_string=Direction.Right; break; case 2: if (!this.invert_direction) this.state_string=Direction.Up; else this.state_string=Direction.Down; break; case 3: if (!this.invert_direction) this.state_string=Direction.Forward; else this.state_string=Direction.Backward; break; default: this.state_string = Direction.None; break; } } public RCSEngineTranslation () { }//end of public RCSEngineTranslation () public override void OnLoad (ConfigNode node) { this.DisplayMode(); } public override void OnStart (PartModule.StartState state) { this.DisplayMode(); } }//end of public class RCSEngineTranslation : PartModule public class AHS : PartModule { //energy used per seconde [KSPField (isPersistant=true)] public float power_consumption = 0.5f; //heat produced per seconde [KSPField (isPersistant=true)] public float heat_production = 50f; //thrust settings for all dimentions //isPersistant is probably not needed as saves cant be done throtled up in an atmoshpher [KSPField (guiName = "throtel left", isPersistant=true, guiActive=false)] public float thrust_left = 100f; [KSPField (guiName = "throtel right", isPersistant=true, guiActive=false)] public float thrust_right = 100f; [KSPField (guiName = "throtel up", isPersistant=true, guiActive=false)] public float thrust_up = 100f; [KSPField (guiName = "throtel down", isPersistant=true, guiActive=false)] public float thrust_down = 100f; [KSPField (guiName = "throtel forward", isPersistant=true, guiActive=false)] public float thrust_forward = 100f; [KSPField (guiName = "throtel backward", isPersistant=true, guiActive=false)] public float thrust_backward = 100f; //start of display fields [KSPField (guiName = "Version", guiActive=true, guiActiveEditor=true)] public string version = "0.41"; [KSPField (guiName = "Comand State", guiActive=true, guiActiveEditor=true)] public string comand_state = "Not Set Yet";//Master,Slave,Off or Crashed. The state should be set to Off on deactivation and ony be set to Mast/Slave if its not Crashed [KSPField (guiName = "Engine Usage", guiActive=true, guiActiveEditor=true)] public string engine_usage = "Not Set Yet";//no / max [KSPField (guiName="Gravity", isPersistant=false, guiActive=true, guiActiveEditor=false)] public string gravity_state = "Not Set Yet"; public int grav_sensor_index = -1; public bool grav_sensor_active = false; public string grav_readout = "....."; public float gravity = 9.82f; [UI_Toggle (enabledText="Deactivate", disabledText="Activate"), KSPField(guiName="AHS", isPersistant=true, guiActive=true, guiActiveEditor=true)] public bool ahs_on = true; public bool ahs_was_on = true; [KSPAction ("Activate AHS")] public void ActionActivateAHS (KSPActionParam param) { this.ahs_on=true; } [KSPAction ("Deactivate AHS")] public void ActionDeactivateAHS (KSPActionParam param) { this.ahs_on=false; } [KSPAction ("Toggle AHS")] public void ActionToggleAHS (KSPActionParam param) { this.ahs_on=!this.ahs_on; } //halfway range seporators [UI_FloatRange (stepIncrement=0.01f, maxValue=3f, minValue=0.01f), KSPField (guiName="Translation G", isPersistant=true, guiActive=true, guiActiveEditor=true)] public float max_g_change = 0.25f; [UI_FloatRange (stepIncrement=0.5f, maxValue=25f, minValue=0.5f), KSPField (guiName="Thrust Change Rate", isPersistant=true, guiActive=true, guiActiveEditor=true)] public float max_thrust_change = 4f; [UI_Toggle (enabledText="Deactivate", disabledText="Activate"), KSPField(guiName="RCS Translation", isPersistant=true, guiActive=true, guiActiveEditor=true)] public bool rcs_on = true; [KSPAction ("Activate RCS Translation")] public void ActionActivateRCSTranslation (KSPActionParam param) { this.rcs_on=true; } [KSPAction ("Deactivate RCS Translation")] public void ActionDeactivateRCSTranslation (KSPActionParam param) { this.rcs_on=false; } [KSPAction ("Toggle RCS Translation")] public void ActionToggleRCSTranslation (KSPActionParam param) { this.rcs_on=!this.rcs_on; } [KSPField (guiName = "dimention", isPersistant=true, guiActive=false)] int hover_dimention = 3; [KSPField (guiName = "direction", isPersistant=true, guiActive=false)] bool hover_invert_direction = false; [KSPField (guiName = "Hover Direction", guiActive=true, guiActiveEditor=true)] public string hover_state_string = "Not Set Yet"; //index 0 [KSPEvent ( guiName="Next Hover Dimention", guiActive=true, guiActiveEditor=true )] public void EventNextDirection() { this.hover_dimention++; if (this.hover_dimention>3) this.hover_dimention=1; this.HoverDisplayMode(); } //index 1 [KSPEvent ( guiName="Togle Hover Direction", guiActive=true, guiActiveEditor=true )] public void EventTogleDirection() { this.hover_invert_direction = !this.hover_invert_direction; this.HoverDisplayMode(); } [KSPAction ("Hover Left")] public void ActionHoverLeft (KSPActionParam param) { this.hover_dimention=1; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Right")] public void ActionHoveRight (KSPActionParam param) { this.hover_dimention=1; this.hover_invert_direction=true; this.HoverDisplayMode(); } [KSPAction ("Hover Up")] public void ActionHoverUP (KSPActionParam param) { this.hover_dimention=2; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Down")] public void ActionHoverDown (KSPActionParam param) { this.hover_dimention=2; this.hover_invert_direction=true; this.HoverDisplayMode(); } [KSPAction ("Hover Forward")] public void ActionHoverForward (KSPActionParam param) { this.hover_dimention=3; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Backward")] public void ActionHoverBackward (KSPActionParam param) { this.hover_dimention=3; this.hover_invert_direction=true; this.HoverDisplayMode(); } public void HoverDisplayMode () { switch (this.hover_dimention) { case 1: if (!this.hover_invert_direction) this.hover_state_string="Left"; else this.hover_state_string="Right"; break; case 2: if (!this.hover_invert_direction) this.hover_state_string="Up"; else this.hover_state_string="Down"; break; case 3: if (!this.hover_invert_direction) this.hover_state_string="Forward"; else this.hover_state_string="Backward"; break; default: this.hover_state_string = "None"; break; } } [KSPField (guiName="Hover Mode: Active", guiActive=false, isPersistant=true)] public int hover_mode = 1; //index 2 [KSPEvent (guiName="Hover Mode: Active", guiActive=true, guiActiveEditor=true)] public void EventNextHoverMode() { this.hover_mode++; if (this.hover_mode>2) this.hover_mode=0; this.SetHoverGUI(); } [KSPAction ("Set Active Hover Mode")] public void ActionSetActiveHover (KSPActionParam param) { this.hover_mode=1; this.SetHoverGUI(); } [KSPAction ("Set Fixed Hover Mode")] public void ActionSetFixedHover (KSPActionParam param) { this.hover_mode=2; this.SetHoverGUI(); } [KSPAction ("Set Hover Mode Off")] public void ActionSetHoverModeOff (KSPActionParam param) { this.hover_mode=0; this.SetHoverGUI(); } public void SetHoverGUI () { switch(this.hover_mode) { case 0: base.Events.GetByIndex(2).guiName="Hover Mode: Off"; break; case 1: base.Events.GetByIndex(2).guiName="Hover Mode: Active"; break; case 2: base.Events.GetByIndex(2).guiName="Hover Mode: Fixed"; break; } } //index 3 [KSPEvent (guiName="Force Editor Update", guiActive=true, guiActiveEditor=true)] void EventForceEditorUpdate () { this.CheckSlaveState(); this.CountEngines(); } int no_parts_in_last_check = -1;//used to check if parts have changed from last update [KSPField (isPersistant=true)] public int max_engines=10; public int controlable_engines=0; public List<int> slave_indices = new List<int>(); public AHS () { Debug.Log("(AHS) Constructor()"); }//endof public AHS () public override void OnStart (PartModule.StartState state) { base.OnStart (state); if (this.vessel!=null) {//vessel = null in editor //disable editor only events Debug.Log ("(AHS) Number of events = "+base.Events.Count); base.Events.GetByIndex(3).active=false; } this.HoverDisplayMode(); this.SetHoverGUI(); this.part.stagingIcon = "SAS";//DefaultIcons.CUSTOM } public override void OnUpdate () { base.OnUpdate(); this.CheckSlaveState();//master slave states could change every frame so needs checking //set icon color if (!this.ahs_on) this.part.stackIcon.SetIconColor(Color.white); else if (this.comand_state=="Crashed") this.part.stackIcon.SetIconColor(Color.red); else if (this.hover_mode!=0 && this.rcs_on) { this.part.stackIcon.SetIconColor(Color.cyan); } else if (this.hover_mode==0 && !this.rcs_on) { this.part.stackIcon.SetIconColor(Color.white); } else { if (this.hover_mode!=0) this.part.stackIcon.SetIconColor(Color.green); if (this.rcs_on) this.part.stackIcon.SetIconColor(Color.blue); } if (this.comand_state!="Master" && this.comand_state!="Slave") return; this.CheckGravSensor(); //all changes in craft must now have been detected and delt with this.no_parts_in_last_check = this.vessel.parts.Count; //energy useage check double amount_needed = (double)(this.power_consumption * TimeWarp.deltaTime); double amount_got = this.part.RequestResource("ElectricCharge" ,amount_needed); if ((amount_needed*0.95) > amount_got ) { this.comand_state = "Crashed"; return; } //temperature check if (this.part.temperature >= (this.part.maxTemp*0.95)) { this.comand_state = "Crashed"; return; } this.part.temperature += (this.heat_production * TimeWarp.deltaTime); //check for change in control states this.ahs_was_on = this.ahs_on; if (!this.ahs_on) return; this.CountEngines();//engines may be changed anytime so need rechecking //only the master control system should do any actual work if (this.comand_state!="Master") return; //apply AHS stablisation CenterOfThrustQuery cot = new CenterOfThrustQuery(); Vector3 thrust_up_vec = Vector3.zero; Vector3 thrust_down_vec = Vector3.zero; Vector3 thrust_left_vec = Vector3.zero; Vector3 thrust_right_vec = Vector3.zero; Vector3 thrust_forward_vec = Vector3.zero; Vector3 thrust_backward_vec = Vector3.zero; float t; int i; int c=0; List<ModuleEngines> engine_modules = new List<ModuleEngines>(); List<string> engine_rcs_state = new List<string>(); //make thrust vectors for (i=0; i<this.vessel.parts.Count; i++) { if (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>().Count>0) { if (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string!="None" && c<this.controlable_engines) { c++; if (c==this.controlable_engines) Debug.Log("(AHS) Max controlable engines reached"); engine_modules.Add(this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0]); engine_rcs_state.Add (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string); this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0].OnCenterOfThrustQuery(cot); t = this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0].finalThrust; cot.dir.x *= t; cot.dir.y *= t; cot.dir.z *= t; switch (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string) { case Direction.Up: thrust_up_vec += cot.dir; break; case Direction.Down: thrust_down_vec += cot.dir; break; case Direction.Left: thrust_left_vec += cot.dir; break; case Direction.Right: thrust_right_vec += cot.dir; break; case Direction.Forward: thrust_forward_vec += cot.dir; break; case Direction.Backward: thrust_backward_vec += cot.dir; break; } } } } float target_up_thrust = 0f; float target_down_thrust = 0f; float target_left_thrust = 0f; float target_right_thrust = 0f; float target_forward_thrust = 0f; float target_backward_thrust = 0f; if (this.rcs_on) {//Change target thrust and thus vertical speed float g_change_in_thrust = (this.max_g_change*9.82f)*this.vessel.GetTotalMass (); target_down_thrust -= (g_change_in_thrust*this.vessel.ctrlState.Y); target_up_thrust += (g_change_in_thrust*this.vessel.ctrlState.Y); target_left_thrust += (g_change_in_thrust*this.vessel.ctrlState.X); target_right_thrust -= (g_change_in_thrust*this.vessel.ctrlState.X); target_forward_thrust -= (g_change_in_thrust*this.vessel.ctrlState.Z); target_backward_thrust += (g_change_in_thrust*this.vessel.ctrlState.Z); } //adjust target thrust for hover correction if (this.hover_mode>0) { switch (this.hover_state_string) { case Direction.Up: target_up_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case Direction.Down: target_down_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case Direction.Left: target_left_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case Direction.Right: target_right_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case Direction.Forward: target_forward_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case Direction.Backward: target_backward_thrust += (this.gravity*this.vessel.GetTotalMass()); break; } if (this.hover_mode==1) { Vector3 sky_vector = this.vessel.mainBody.transform.position-this.vessel.transform.position; Vector3 sky_n = sky_vector.normalized; Vector3 thr_n = Vector3.zero; //rotating one normal into the other should return 0 if they are on the same plan and 1 if at 90 degrease to each other switch (this.hover_state_string) { case Direction.Up: thr_n = thrust_up_vec.normalized; break; case Direction.Down: thr_n = thrust_down_vec.normalized; break; case Direction.Left: thr_n = thrust_left_vec.normalized; break; case Direction.Right: thr_n = thrust_right_vec.normalized; break; case Direction.Forward: thr_n = thrust_forward_vec.normalized; break; case Direction.Backward: thr_n = thrust_backward_vec.normalized; break; } float m = Mathf.Abs( (sky_n.x* thr_n.x) + (sky_n.y*thr_n.y) + (sky_n.z* thr_n.z)); if (m==0f) m=0.00000001f;//avoid divide by 0 switch (this.hover_state_string) { case Direction.Up: target_up_thrust /= m; break; case Direction.Down: target_down_thrust /= m; break; case Direction.Left: target_left_thrust /= m; break; case Direction.Right: target_right_thrust /= m; break; case Direction.Forward: target_forward_thrust /= m; break; case Direction.Backward: target_backward_thrust /= m; break; } } } //Adjust throtles slowly and hope we find a sweatspot ! float irevavent_thrust = ((9.82f*this.vessel.GetTotalMass())*0.01f); if (target_up_thrust==thrust_up_vec.magnitude && thrust_up_vec.magnitude==0f) this.thrust_up=0f; else { if ((target_up_thrust-thrust_up_vec.magnitude)<0f) this.thrust_up-=this.max_thrust_change; else this.thrust_up+=this.max_thrust_change; this.thrust_up = Mathf.Clamp(this.thrust_up,0f,100f); } if (target_down_thrust==thrust_down_vec.magnitude && thrust_down_vec.magnitude==0f) this.thrust_down=0f; else { if ((target_down_thrust-thrust_down_vec.magnitude)<0f) this.thrust_down-=this.max_thrust_change; else this.thrust_down+=this.max_thrust_change; this.thrust_down = Mathf.Clamp(this.thrust_down,0f,100f); } if (target_left_thrust==thrust_left_vec.magnitude && thrust_left_vec.magnitude==0f) this.thrust_left=0f; else { if ((target_left_thrust-thrust_left_vec.magnitude)<0f) this.thrust_left-=this.max_thrust_change; else this.thrust_left+=this.max_thrust_change; this.thrust_left = Mathf.Clamp(this.thrust_left,0f,100f); } if (target_right_thrust==thrust_right_vec.magnitude && thrust_right_vec.magnitude==0f) this.thrust_right=0f; else { if ((target_right_thrust-thrust_right_vec.magnitude)<0f) this.thrust_right-=this.max_thrust_change; else this.thrust_right+=this.max_thrust_change; this.thrust_right = Mathf.Clamp(this.thrust_right,0f,100f); } if (target_forward_thrust==thrust_forward_vec.magnitu de && thrust_forward_vec.magnitude==0f) this.thrust_forward=0f; else { if ((target_forward_thrust-thrust_forward_vec.magnitude)<0f) this.thrust_forward-=this.max_thrust_change; else this.thrust_forward+=this.max_thrust_change; this.thrust_forward = Mathf.Clamp(this.thrust_forward,0f,100f); } if (target_backward_thrust==thrust_backward_vec.magni tude && thrust_backward_vec.magnitude==0f) this.thrust_backward=0f; else { if ((target_backward_thrust-thrust_backward_vec.magnitude)<0f) this.thrust_backward-=this.max_thrust_change; else this.thrust_backward+=this.max_thrust_change; this.thrust_backward = Mathf.Clamp(this.thrust_backward,0f,100f); } //set engine thrusts for (i=0; i<engine_modules.Count; i++) { switch (engine_rcs_state[i]) { case Direction.Up: engine_modules[i].thrustPercentage = this.thrust_up; break; case Direction.Down: engine_modules[i].thrustPercentage = this.thrust_down; break; case Direction.Left: engine_modules[i].thrustPercentage = this.thrust_left; break; case Direction.Right: engine_modules[i].thrustPercentage = this.thrust_right; break; case Direction.Forward: engine_modules[i].thrustPercentage = this.thrust_forward; break; case Direction.Backward: engine_modules[i].thrustPercentage = this.thrust_backward; break; } } }//endof public override void OnUpdate () //Used in editor to update gui info. Should be done in update as a full engine scan will be done every time as to check for states public void CountEngines () { int i; int master_index=-1; //vessel will = null in the editor so we must cycle through parts list another way if it is not set List <Part> part_list; if (this.vessel!=null) { part_list = this.vessel.Parts; } else { part_list = new List<Part>(); Part start_part = this.part; while (start_part.parent!=null) start_part=start_part.parent; AddPartToList(start_part,part_list); } int controlable_no = 0; int found_engines = 0; for (i=0; i<part_list.Count; i++) { if (part_list[i].FindModulesImplementing<AHS>().Count>0) { //functional states are only Master or Slave if (part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Master") { master_index=i; } if ( part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Master" || part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Slave" ) { controlable_no += part_list[i].FindModulesImplementing<AHS>()[0].max_engines; } } if (part_list[i].FindModulesImplementing<RCSEngineTranslation>().Count>0) { if (part_list[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string!="None") found_engines++; } } if (master_index!=-1) { part_list[master_index].FindModulesImplementing<AHS>()[0].controlable_engines = controlable_no; part_list[master_index].FindModulesImplementing<AHS>()[0].engine_usage = found_engines+"/"+controlable_no; List<int> slaves = part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices; for (i=0; i<slaves.Count; i++) { part_list[slaves[i]].FindModulesImplementing<AHS>()[0].engine_usage = found_engines+"/"+controlable_no; } } } //Search for working slaves and update the master's slave list public void CheckSlaveState () { int master_index = -1; int i; //vessel will = null in the editor so we must cycle through parts list another way if it is not set List <Part> part_list; if (this.vessel!=null) { part_list = this.vessel.Parts; } else { part_list = new List<Part>(); Part start_part = this.part; while (start_part.parent!=null) start_part=start_part.parent; AddPartToList(start_part,part_list); } for (i=0; i<part_list.Count; i++) { if (part_list[i].FindModulesImplementing<AHS>().Count>0) { //All inactive states must be checked before asigning master slave states if (!part_list[i].FindModulesImplementing<AHS>()[0].ahs_on) { part_list[i].FindModulesImplementing<AHS>()[0].comand_state = "Off"; } else if ( part_list[i].FindModulesImplementing<AHS>()[0].comand_state!="Crashed" ) { if (master_index==-1) { master_index=i; part_list[master_index].FindModulesImplementing<AHS>()[0].comand_state = "Master"; part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices.Clear(); } else { part_list[i].FindModulesImplementing<AHS>()[0].comand_state = "Slave"; part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices.Add(i); } } } } } //Find active gravity sensor and then set gravity to a useable value public void CheckGravSensor () { this.FindActiveSensor(); }//endof void CheckGravSensor () //Updates grav readout and sets active state + finds an active sensor //You can force sensor finding by setting grav_sensor_index to -1 public void FindActiveSensor () { if (no_parts_in_last_check!=this.vessel.parts.Count) {//if parts have change then the index is no longer valid this.grav_sensor_index = -1; this.grav_sensor_active = false; } if ( this.grav_sensor_index != -1 ) {//if grav sensor is valid check it is active and update readout this.ReadGravSensor(); } //We dont need to search again if we have an active sensor and parts have not changed if ( no_parts_in_last_check==this.vessel.parts.Count && this.grav_sensor_active==true ) return; this.grav_sensor_index = -1; this.grav_sensor_active = false; int i; for (i=0; i<this.vessel.parts.Count; i++) { if (this.vessel.parts[i].name=="sensorGravimeter") { if (this.vessel.parts[i].FindModulesImplementing<ModuleEnviroSensor>().Count>0) { if (this.grav_sensor_index == -1) { this.grav_sensor_index=i; } this.ReadGravSensor(); if (this.grav_sensor_active) { this.grav_sensor_index = i; break; } } } } }//endof void FindActiveSensor () public void ReadGravSensor () { if (this.grav_sensor_index==-1) { this.grav_readout = this.gravity_state = "No Sonsor Found"; this.gravity = 9.82f; this.grav_sensor_active = false; return; } float grav = float.NaN; try { ModuleEnviroSensor sensor = this.vessel.parts[this.grav_sensor_index].FindModulesImplementing<ModuleEnviroSensor>()[0]; if (sensor.readoutInfo.Length>6) { grav = float.Parse(sensor.readoutInfo.Substring(0,sensor. readoutInfo.Length-6)); if (grav != float.NaN) { //duplicate of the grav sensors methode of getting gravity but with out the lose of precision from string convertion grav = (float)FlightGlobals.getGeeForceAtPosition( base.transform.position ).magnitude; } } } catch { } if (grav==float.NaN || float.IsInfinity(grav) || grav.ToString()=="NaN") { this.gravity_state = this.grav_readout = "Senneor Read Error"; this.gravity = 9.82f; this.grav_sensor_active = false; } else { this.gravity_state = this.grav_readout = grav.ToString(); this.gravity = grav; this.grav_sensor_active = true; } } //part list builder. much better to use vessle.parts but its not avalible in the editor public void AddPartToList ( Part p_, List<Part> list_ ) { list_.Add(p_); int i; for (i=0; i<p_.children.Count; i++) { this.AddPartToList(p_.children[i],list_); } } public override void OnLoad (ConfigNode node) { base.OnLoad(node); this.HoverDisplayMode(); this.SetHoverGUI(); } //place for adding right click info to parts in the editor ? public override string GetInfo () { string result = ""; result += "Energy Usage: "+this.power_consumption.ToString()+"/sec\n"; result += "Heat Production: "+this.heat_production.ToString()+"/sec\n"; result += "Controlable Engines: "+this.max_engines.ToString()+"/sec\n"; return base.GetInfo ()+result; } }//endof public class AHS : PartModule }//endof namespace AHS -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Fixed hover Sets the thrust output = to the force of gravity So if you tilt the craft and point the thrust in a direction not exactly opposite to gravity then you start to fall out of the sky. Active Hover increases the thrust as you tilt in an attempt to maintain your hover So will use 100% thrust if you are pointing at the horizon. The active thrust seams to be far superior to fixed thrust but i was not convinced it would work so well at the time of programming so kept the fixed version in too. Both systems will use variable gravity if an active grav sensor is found. Im still fixing some nasty silly bugs. There was a problem with RCS Left tracking the up key in one part and up and down may be the wrong way around. Ill fix up the last small problems and do some more testing. With luck V0.41 will be released in a few hours and ill start on a tutorial video or 2. -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Yeah the video ended up being a bit too fast and so not very easy to understand + i should have built the craft so you could see the full setup process. You should right click on an engine and use the Next RCS Dimension and Toggle RCS Direction to set the RCS Direction and thus define how the engine is controlled. I use Forward as my preferred hover direction as the H/N keys are called Forward/Backward in the settings and my 1st craft had a cockpit pointing at the sky. These directions have no relevance to what way you are facing (unlike RCS) but are just a way to connect keys with events. If you like I/K as your hover control keys then theres no reason not to use Up as your Hover direction but be Warned that the default keys are K/I = Up/Down. By default the AHS is set to use Forward engines for hover but this is changeable using the change Hover tweakables or action groups. It may well be too flexible now and so stupidly complex to setup. You must then enable SAS for the system to attempt any form of control and enable RCS if you want translation control (This seams to now be total missing from any text and was in the part description). That seams very silly now as the hover mode setting allows you to enable/disable hover and thus replaces the need to check the SAS state. The only reason for using these states now would be that they have a good GUI on the HUD. You must also check your energy usage but if your using jets that tends not to be a problem. I will do another video very soon once iv fixed a few little bugs. -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
I hope it makes things achievable for you and don't forgot to let me know how you get on ? Id love to see craft photos and stories about any achievements or even near misses from the plugin (Its the little things that make me feel the worth of publishing). I can confirm that v0.4 certainly dose work with solid rockets and that i should fix this by checking for ModuleEngines.throttleLocked = True. I also found a nasty bug where setting time warp causes the small AHS to explode from over heating. You can avoid this by turning it off before warping. Its a very fine balance with heat on the small AHS but i hope that changing both the heat and power over usage into a crashed state should fix this. This would crash the system and stop it generating heat if you reach 95% heat or run out of power. You would then need to turn the system off and back on again (like you don't know how to deal with a crash !). I could use some feed back on power usage and heat production. I am sure its going to be hard to please every one with my moral obligation to transferring the difficulty from one place to another. I think 0.4 is starting to get on the overpowered side with both the active hover and RCS Translation systems but feedback always helps. I have not tested the Large AHS yet but at a 6T mass i was hoping it would make large hover systems unwieldy. Iv also found that low gravity effects result in more unstable hovers and suspect that there is a major reduction in the sensitivity of a grav sensor readout when compered to a 32bit float. It should not be to hard to check this but will take a few mins of work. Hummm.... ill have to update the to do list when i sober up -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Ok i have what seams to be a working V0.4 Advanced Hover System update. Im more than sure there shall be some bugs to squash though. For instance iv not tested it with solid rockets yet . It will probably work with them too so i should check that and see if it needs fixing. Change Log v0.4 Redesigned the ASS into an AHS so it now has hover direction, hover mode and some-other tweakables. Added RCSEngineTranslation Module and added it to all engine parts on start-up. Made 2 new models so that the AHS have there very own look (stock style). Added resource usage so it now eats up the energy and leaks out heat. Added Master/Slave system along with a more limiting number of controllable engines so multiple AHS should be needed for large craft. Added the Active hover mode as suggested by Virindi (good call there ) V0.4 Code with do what you want licence //M Pink provides AHS (v0.4) freely for anyone to use for anyreason they see fit. //M Pink is not responsable for any damage caused by AHS. //AHS Should Be Used At Your Own Risk ! using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; namespace AHS { [KSPAddon(KSPAddon.Startup.MainMenu,true)] public class RCSAddonSetup :MonoBehaviour { void Awake () { Debug.Log("(AHS.RCSAddonSetup) Awake()"); PartLoader pl = PartLoader.Instance; if (pl==null) { Debug.Log("(AHS.RCSAddonSetup) Partloader was null"); } else { Debug.Log("(AHS.RCSAddonSetup) Partloader Found"); Debug.Log("(AHS.RCSAddonSetup) Number of parts to scan = "+pl.parts.Count); int a=0; for (a=0; a<pl.parts.Count; a++) { bool has_engine = false; bool has_rcs = false; int b=0; for (b=0; b<pl.parts[a].moduleInfos.Count; b++) { if ("Engine"==pl.parts[a].moduleInfos[b].moduleName) has_engine=true; if ("RCSEngineTranslation"==pl.parts[a].moduleInfos[b].moduleName) has_rcs=true; } if (has_engine && !has_rcs) { Debug.Log("(AHS.RCSAddonSetup) Engine module found for "+pl.parts[a].title+" adding RCSEngineTranslation module"); pl.parts[a].partPrefab.AddModule("RCSEngineTranslation"); AvailablePart.ModuleInfo info = new AvailablePart.ModuleInfo(); info.moduleName = "RCSEngineTranslation"; pl.parts[a].moduleInfos.Add(info); }//endof if (has_engine && !has_rcs) }//endof for (a=0; a<pl.parts.Count; a++) }//end of else if (pl==null) } } public class RCSEngineTranslation : PartModule { /* [KSPAddon (KSPAddon.Startup.MainMenu,true)] void KSPAddonSetupRCSModules () { Debug.Log("(AHS.RCSEngineTranslation) KSPAddonSetupRCSModules()"); PartLoader pl = PartLoader.Instance; if (pl==null) { Debug.Log("(AHS.RCSEngineTranslation) Partloader was null"); } else { Debug.Log("(AHS.RCSEngineTranslation) Partloader Found"); Debug.Log("(AHS.RCSEngineTranslation) Number of parts to scan = "+pl.parts.Count); int a=0; for (a=0; a<pl.parts.Count; a++) { bool has_engine = false; bool has_rcs = false; int b=0; for (b=0; b<pl.parts[a].moduleInfos.Count; b++) { if ("Engine"==pl.parts[a].moduleInfos[b].moduleName) has_engine=true; if ("RCSEngineTranslation"==pl.parts[a].moduleInfos[b].moduleName) has_rcs=true; } if (has_engine && !has_rcs) { Debug.Log("(AHS.RCSEngineTranslation) Engine module found for "+pl.parts[a].title+" adding RCSEngineTranslation module"); pl.parts[a].partPrefab.AddModule("RCSEngineTranslation"); AvailablePart.ModuleInfo info = new AvailablePart.ModuleInfo(); info.moduleName = "RCSEngineTranslation"; pl.parts[a].moduleInfos.Add(info); }//endof if (has_engine && !has_rcs) }//endof for (a=0; a<pl.parts.Count; a++) }//end of else if (pl==null) }*/ [KSPField (guiName = "dimention", isPersistant=true, guiActive=false)] int dimention = 0; [KSPField (guiName = "direction", isPersistant=true, guiActive=false)] bool invert_direction = false; [KSPField (guiName = "RCS Direction", isPersistant=false, guiActive=true, guiActiveEditor=true)] public string state_string = "Not Set Yet"; [KSPEvent ( guiName="Next RCS Dimention", guiActive=true, guiActiveEditor=true )] public void EventNextDirection() { this.dimention++; if (this.dimention>3) this.dimention=0; this.DisplayMode(); } [KSPEvent ( guiName="Togle RCS Direction", guiActive=true, guiActiveEditor=true )] public void EventTogleDirection() { this.invert_direction = !this.invert_direction; this.DisplayMode(); } [KSPAction ("Set RCS None")] void ActionSetRCSNone () { this.dimention=0; this.DisplayMode(); } [KSPAction ("Set RCS Left")] void ActionSetRCSLeft () { this.dimention=1; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Right")] void ActionSetRCSRight () { this.dimention=1; this.invert_direction=true; this.DisplayMode(); } [KSPAction ("Set RCS Up")] void ActionSetRCSUp () { this.dimention=2; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Down")] void ActionSetRCSDown () { this.dimention=2; this.invert_direction=true; this.DisplayMode(); } [KSPAction ("Set RCS Forward")] void ActionSetRCSForward () { this.dimention=3; this.invert_direction=false; this.DisplayMode(); } [KSPAction ("Set RCS Backward")] void ActionSetRCSBackward () { this.dimention=3; this.invert_direction=true; this.DisplayMode(); } public void DisplayMode () { switch (this.dimention) { case 1: if (!this.invert_direction) this.state_string="Left"; else this.state_string="Right"; break; case 2: if (!this.invert_direction) this.state_string="Up"; else this.state_string="Down"; break; case 3: if (!this.invert_direction) this.state_string="Forward"; else this.state_string="Backward"; break; default: this.state_string = "None"; break; } } public RCSEngineTranslation () { }//end of public RCSEngineTranslation () public override void OnLoad (ConfigNode node) { this.DisplayMode(); } public override void OnStart (PartModule.StartState state) { this.DisplayMode(); } }//end of public class RCSEngineTranslation : PartModule public class AHS : PartModule { //energy used per seconde [KSPField (isPersistant=true)] public float power_consumption = 0.5f; //heat produced per seconde [KSPField (isPersistant=true)] public float heat_production = 50f; //thrust settings for all dimentions //isPersistant is probably not needed as saves cant be done throtled up in an atmoshpher [KSPField (guiName = "throtel left", isPersistant=true, guiActive=false)] public float thrust_left = 100f; [KSPField (guiName = "throtel right", isPersistant=true, guiActive=false)] public float thrust_right = 100f; [KSPField (guiName = "throtel up", isPersistant=true, guiActive=false)] public float thrust_up = 100f; [KSPField (guiName = "throtel down", isPersistant=true, guiActive=false)] public float thrust_down = 100f; [KSPField (guiName = "throtel forward", isPersistant=true, guiActive=false)] public float thrust_forward = 100f; [KSPField (guiName = "throtel backward", isPersistant=true, guiActive=false)] public float thrust_backward = 100f; //start of display fields [KSPField (guiName = "Version", guiActive=true, guiActiveEditor=true)] public string version = "0.4"; [KSPField (guiName = "Comand State", guiActive=true, guiActiveEditor=true)] public string comand_state = "Not Set Yet";//Master,Slave,No Energy [KSPField (guiName = "Engine Usage", guiActive=true, guiActiveEditor=true)] public string engine_usage = "Not Set Yet";//no / max [KSPField (guiName="Gravity", isPersistant=false, guiActive=true, guiActiveEditor=false)] public string gravity_state = "Not Set Yet"; public int grav_sensor_index = -1; public bool grav_sensor_active = false; public string grav_readout = "....."; public float gravity = 9.82f; [UI_Toggle (enabledText="Deactivate", disabledText="Activate"), KSPField(guiName="AHS", isPersistant=true, guiActive=true, guiActiveEditor=true)] public bool ahs_on = true; public bool ahs_was_on = true; [KSPAction ("Activate AHS")] public void ActionActivateAHS (KSPActionParam param) { this.ahs_on=true; } [KSPAction ("Deactivate AHS")] public void ActionDeactivateAHS (KSPActionParam param) { this.ahs_on=false; } [KSPAction ("Toggle AHS")] public void ActionToggleAHS (KSPActionParam param) { this.ahs_on=!this.ahs_on; } //halfway range seporators [UI_FloatRange (stepIncrement=0.01f, maxValue=4f, minValue=0.01f), KSPField (guiName="Translation G", isPersistant=true, guiActive=true, guiActiveEditor=true)] public float max_g_change = 0.25f; [UI_FloatRange (stepIncrement=0.5f, maxValue=100f, minValue=0.5f), KSPField (guiName="Thrust Change Rate", isPersistant=true, guiActive=true, guiActiveEditor=true)] public float max_thrust_change = 4f; [KSPField (guiName = "dimention", isPersistant=true, guiActive=false)] int hover_dimention = 3; [KSPField (guiName = "direction", isPersistant=true, guiActive=false)] bool hover_invert_direction = false; [KSPField (guiName = "Hover Direction", guiActive=true, guiActiveEditor=true)] public string hover_state_string = "Not Set Yet"; //index 0 [KSPEvent ( guiName="Next Hover Dimention", guiActive=true, guiActiveEditor=true )] public void EventNextDirection() { this.hover_dimention++; if (this.hover_dimention>3) this.hover_dimention=1; this.HoverDisplayMode(); } //inde 1 [KSPEvent ( guiName="Togle Hover Direction", guiActive=true, guiActiveEditor=true )] public void EventTogleDirection() { this.hover_invert_direction = !this.hover_invert_direction; this.HoverDisplayMode(); } [KSPField (guiName="Hover Mode: Active", guiActive=false, isPersistant=true)] public int hover_mode = 1; //index 2 [KSPEvent (guiName="Hover Mode: Active", guiActive=true, guiActiveEditor=true)] public void EventNextHoverMode() { this.hover_mode++; if (this.hover_mode>2) this.hover_mode=0; this.SetHoverGUI(); } [KSPAction ("Set Active Hover Mode")] public void ActionSetActiveHover (KSPActionParam param) { this.hover_mode=1; this.SetHoverGUI(); } [KSPAction ("Set Fixed Hover Mode")] public void ActionSetFixedHover (KSPActionParam param) { this.hover_mode=2; this.SetHoverGUI(); } [KSPAction ("Set Hover Mode Off")] public void ActionSetHoverModeOff (KSPActionParam param) { this.hover_mode=0; this.SetHoverGUI(); } public void SetHoverGUI () { switch(this.hover_mode) { case 0: base.Events.GetByIndex(2).guiName="Hover Mode: Off"; break; case 1: base.Events.GetByIndex(2).guiName="Hover Mode: Active"; break; case 2: base.Events.GetByIndex(2).guiName="Hover Mode: Fixed"; break; } } [KSPAction ("Hover Left")] public void ActionHoverLeft (KSPActionParam param) { this.hover_dimention=1; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Right")] public void ActionHoveRight (KSPActionParam param) { this.hover_dimention=1; this.hover_invert_direction=true; this.HoverDisplayMode(); } [KSPAction ("Hover Up")] public void ActionHoverUP (KSPActionParam param) { this.hover_dimention=2; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Down")] public void ActionHoverDown (KSPActionParam param) { this.hover_dimention=2; this.hover_invert_direction=true; this.HoverDisplayMode(); } [KSPAction ("Hover Forward")] public void ActionHoverForward (KSPActionParam param) { this.hover_dimention=3; this.hover_invert_direction=false; this.HoverDisplayMode(); } [KSPAction ("Hover Backward")] public void ActionHoverBackward (KSPActionParam param) { this.hover_dimention=3; this.hover_invert_direction=true; this.HoverDisplayMode(); } public void HoverDisplayMode () { switch (this.hover_dimention) { case 1: if (!this.hover_invert_direction) this.hover_state_string="Left"; else this.hover_state_string="Right"; break; case 2: if (!this.hover_invert_direction) this.hover_state_string="Up"; else this.hover_state_string="Down"; break; case 3: if (!this.hover_invert_direction) this.hover_state_string="Forward"; else this.hover_state_string="Backward"; break; default: this.hover_state_string = "None"; break; } } //index 3 [KSPEvent (guiName="Force Editor Update", guiActive=true, guiActiveEditor=true)] void EventForceEditorUpdate () { this.CheckSlaveState(); this.CountEngines(); } bool sas_on=false; bool rcs_on=true; int no_parts_in_last_check = -1;//used to check if parts have changed from last update [KSPField (isPersistant=true)] public int max_engines=10; public int controlable_engines=0; public List<int> slave_indices = new List<int>(); public AHS () { Debug.Log("(AHS) Constructor()"); /* PartLoader pl = PartLoader.Instance; if (pl==null) { Debug.Log("(AHS) Partloader was null"); } else { Debug.Log("(AHS) Partloader Found"); Debug.Log("(AHS) Number of parts to scan = "+pl.parts.Count); int a=0; for (a=0; a<pl.parts.Count; a++) { bool has_engine = false; bool has_rcs = false; int b=0; for (b=0; b<pl.parts[a].moduleInfos.Count; b++) { if ("Engine"==pl.parts[a].moduleInfos[b].moduleName) has_engine=true; if ("RCSEngineTranslation"==pl.parts[a].moduleInfos[b].moduleName) has_rcs=true; } if (has_engine && !has_rcs) { Debug.Log("(AHS) Engine module found for "+pl.parts[a].title+" adding RCSEngineTranslation module"); pl.parts[a].partPrefab.AddModule("RCSEngineTranslation"); AvailablePart.ModuleInfo info = new AvailablePart.ModuleInfo(); info.moduleName = "RCSEngineTranslation"; pl.parts[a].moduleInfos.Add(info); }//endof if (has_engine && !has_rcs) }//endof for (a=0; a<pl.parts.Count; a++) }//end of else if (pl==null) */ }//endof public AHS () public override void OnStart (PartModule.StartState state) { base.OnStart (state); if (this.vessel!=null) {//vessel = null in editor //disable editor only events Debug.Log ("(AHS) Number of events = "+base.Events.Count); base.Events.GetByIndex(3).active=false; } this.HoverDisplayMode(); this.SetHoverGUI(); if (base.part.stagingIcon == string.Empty) { base.part.stagingIcon = "ADV_SAS"; } } public override void OnUpdate () { base.OnUpdate(); this.CheckGravSensor(); //all changes in craft must now have been detected and delt with this.no_parts_in_last_check = this.vessel.parts.Count; this.ahs_was_on = this.ahs_on; if (!this.ahs_on) return; //check for change in control states bool sas_state = this.vessel.ActionGroups[KSPActionGroup.SAS]; bool sas_changed = false; if (this.sas_on != sas_state) { this.sas_on = sas_state; sas_changed = true; } if (this.rcs_on != this.vessel.ActionGroups[KSPActionGroup.RCS] ) { this.rcs_on = this.vessel.ActionGroups[KSPActionGroup.RCS]; } double amount_needed = (double)(this.power_consumption * TimeWarp.deltaTime); double amount_got = this.part.RequestResource("ElectricCharge" ,amount_needed); if ((amount_needed*0.95) > amount_got ) { this.comand_state = "No Energy"; this.CheckSlaveState(); return; } else { if (this.comand_state=="No Energy") { this.comand_state="Rebooting"; this.CheckSlaveState(); return; } } this.part.temperature += (this.heat_production * TimeWarp.deltaTime); //deal with changes in control state if (!this.sas_on && sas_changed) { //set thrust back to max on SAS deactivation this.thrust_backward = 100f; this.thrust_down = 100f; this.thrust_forward = 100f; this.thrust_left = 100f; this.thrust_right = 100f; this.thrust_up = 100f; } this.CheckSlaveState();//master slave states could change every frame so need checking this.CountEngines();//engines may be changed anytime so need rechecking //apply sas stablisation if (this.sas_on) { CenterOfThrustQuery cot = new CenterOfThrustQuery(); Vector3 thrust_up_vec = Vector3.zero; Vector3 thrust_down_vec = Vector3.zero; Vector3 thrust_left_vec = Vector3.zero; Vector3 thrust_right_vec = Vector3.zero; Vector3 thrust_forward_vec = Vector3.zero; Vector3 thrust_backward_vec = Vector3.zero; float t; int i; int c=0; List<ModuleEngines> engine_modules = new List<ModuleEngines>(); List<string> engine_rcs_state = new List<string>(); //make thrust vectors for (i=0; i<this.vessel.parts.Count; i++) { if (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>().Count>0) { if (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string!="None" && c<this.controlable_engines) { c++; if (c==this.controlable_engines) Debug.Log("(AHS) Max controlable engines reached"); engine_modules.Add(this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0]); engine_rcs_state.Add (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string); this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0].OnCenterOfThrustQuery(cot); t = this.vessel.parts[i].FindModulesImplementing<ModuleEngines>()[0].finalThrust; cot.dir.x *= t; cot.dir.y *= t; cot.dir.z *= t; switch (this.vessel.parts[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string) { case "Up": thrust_up_vec += cot.dir; break; case "Down": thrust_down_vec += cot.dir; break; case "Left": thrust_left_vec += cot.dir; break; case "Right": thrust_right_vec += cot.dir; break; case "Forward": thrust_forward_vec += cot.dir; break; case "Backward": thrust_backward_vec += cot.dir; break; } } } } float target_up_thrust = 0f; float target_down_thrust = 0f; float target_left_thrust = 0f; float target_right_thrust = 0f; float target_forward_thrust = 0f; float target_backward_thrust = 0f; if (this.rcs_on) {//Change target thrust and thus vertical speed float g_change_in_thrust = (this.max_g_change*9.82f)*this.vessel.GetTotalMass(); target_down_thrust -= (g_change_in_thrust*this.vessel.ctrlState.Y); target_up_thrust += (g_change_in_thrust*this.vessel.ctrlState.Y); target_left_thrust -= (g_change_in_thrust*this.vessel.ctrlState.X); target_right_thrust += (g_change_in_thrust*this.vessel.ctrlState.X); target_forward_thrust -= (g_change_in_thrust*this.vessel.ctrlState.Z); target_backward_thrust += (g_change_in_thrust*this.vessel.ctrlState.Z); } //adjust target thrust for hover correction if (this.hover_mode>0) { switch (this.hover_state_string) { case "Up": target_up_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case "Down": target_down_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case "Left": target_left_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case "Right": target_right_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case "Forward": target_forward_thrust += (this.gravity*this.vessel.GetTotalMass()); break; case "Backward": target_backward_thrust += (this.gravity*this.vessel.GetTotalMass()); break; } if (this.hover_mode==1) { Vector3 sky_vector = this.vessel.mainBody.transform.position-this.vessel.transform.position; Vector3 sky_n = sky_vector.normalized; Vector3 thr_n = Vector3.zero; //rotating one normal into the other should return 0 if they are on the same plan and 1 if at 90 degrease to each other switch (this.hover_state_string) { case"Up": thr_n=thrust_up_vec.normalized; break; case"Down": thr_n=thrust_down_vec.normalized; break; case"Left": thr_n=thrust_left_vec.normalized; break; case"Right": thr_n=thrust_right_vec.normalized; break; case"Forward": thr_n=thrust_forward_vec.normalized; break; case"Backward": thr_n=thrust_backward_vec.normalized; break; } float m = Mathf.Abs( (sky_n.x* thr_n.x) + (sky_n.y*thr_n.y) + (sky_n.z* thr_n.z)); if (m==0f) m=0.00000001f;//avoid divide by 0 switch (this.hover_state_string) { case"Up": target_up_thrust /= m; break; case"Down": target_down_thrust /= m; break; case"Left": target_left_thrust /= m; break; case"Right": target_right_thrust /= m; break; case"Forward": target_forward_thrust /= m; break; case"Backward": target_backward_thrust /= m; break; } } } //Adjust throtles slowly and hope we find a sweatspot ! float irevavent_thrust = ((9.82f*this.vessel.GetTotalMass())*0.01f); if (target_up_thrust==thrust_up_vec.magnitude && thrust_up_vec.magnitude==0f) this.thrust_up=0f; else if (Mathf.Abs(target_up_thrust-thrust_up_vec.magnitude) > irevavent_thrust ) { if ((target_up_thrust-thrust_up_vec.magnitude)<0f) this.thrust_up-=this.max_thrust_change; else this.thrust_up+=this.max_thrust_change; this.thrust_up = Mathf.Clamp(this.thrust_up,0f,100f); } if (target_down_thrust==thrust_down_vec.magnitude && thrust_down_vec.magnitude==0f) this.thrust_down=0f; else if (Mathf.Abs(target_down_thrust-thrust_down_vec.magnitude) > irevavent_thrust ) { if ((target_down_thrust-thrust_down_vec.magnitude)<0f) this.thrust_down-=this.max_thrust_change; else this.thrust_down+=this.max_thrust_change; this.thrust_down = Mathf.Clamp(this.thrust_down,0f,100f); } if (target_left_thrust==thrust_left_vec.magnitude && thrust_left_vec.magnitude==0f) this.thrust_left=0f; else if (Mathf.Abs(target_left_thrust-thrust_left_vec.magnitude) > irevavent_thrust ) { if ((target_left_thrust-thrust_left_vec.magnitude)<0f) this.thrust_left-=this.max_thrust_change; else this.thrust_left+=this.max_thrust_change; this.thrust_left = Mathf.Clamp(this.thrust_up,0f,100f); } if (target_right_thrust==thrust_right_vec.magnitude && thrust_right_vec.magnitude==0f) this.thrust_right=0f; else if (Mathf.Abs(target_right_thrust-thrust_right_vec.magnitude) > irevavent_thrust ) { if ((target_right_thrust-thrust_right_vec.magnitude)<0f) this.thrust_right-=this.max_thrust_change; else this.thrust_right+=this.max_thrust_change; this.thrust_right = Mathf.Clamp(this.thrust_right,0f,100f); } if (target_forward_thrust==thrust_forward_vec.magnitude && thrust_forward_vec.magnitude==0f) this.thrust_forward=0f; else if (Mathf.Abs(target_forward_thrust-thrust_forward_vec.magnitude) > irevavent_thrust ) { if ((target_forward_thrust-thrust_forward_vec.magnitude)<0f) this.thrust_forward-=this.max_thrust_change; else this.thrust_forward+=this.max_thrust_change; this.thrust_forward = Mathf.Clamp(this.thrust_forward,0f,100f); } if (target_backward_thrust==thrust_backward_vec.magnitude && thrust_backward_vec.magnitude==0f) this.thrust_backward=0f; else if (Mathf.Abs(target_backward_thrust-thrust_backward_vec.magnitude) > irevavent_thrust ) { if ((target_backward_thrust-thrust_backward_vec.magnitude)<0f) this.thrust_backward-=this.max_thrust_change; else this.thrust_backward+=this.max_thrust_change; this.thrust_backward = Mathf.Clamp(this.thrust_backward,0f,100f); } //set engine thrusts for (i=0; i<engine_modules.Count; i++) { switch (engine_rcs_state[i]) { case "Up": engine_modules[i].thrustPercentage = this.thrust_up; break; case "Down": engine_modules[i].thrustPercentage = this.thrust_down; break; case "Left": engine_modules[i].thrustPercentage = this.thrust_left; break; case "Right": engine_modules[i].thrustPercentage = this.thrust_right; break; case "Forward": engine_modules[i].thrustPercentage = this.thrust_forward; break; case "Backward": engine_modules[i].thrustPercentage = this.thrust_backward; break; } } } }//endof public override void OnUpdate () //Used in editor to update gui info. Should be done in update as a full engine scan will be done every time as to check for states public void CountEngines () { int i; int master_index=-1; //vessel will = null in the editor so we must cycle through parts list another way if it is not set List <Part> part_list; if (this.vessel!=null) { part_list = this.vessel.Parts; } else { part_list = new List<Part>(); Part start_part = this.part; while (start_part.parent!=null) start_part=start_part.parent; AddPartToList(start_part,part_list); } int controlable_no = 0; int found_engines = 0; for (i=0; i<part_list.Count; i++) { if (part_list[i].FindModulesImplementing<AHS>().Count>0) { //functional states are only Master or Slave if (part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Master") { master_index=i; } if ( part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Master" || part_list[i].FindModulesImplementing<AHS>()[0].comand_state=="Slave" ) { controlable_no += part_list[i].FindModulesImplementing<AHS>()[0].max_engines; } } if (part_list[i].FindModulesImplementing<RCSEngineTranslation>().Count>0) { if (part_list[i].FindModulesImplementing<RCSEngineTranslation>()[0].state_string!="None") found_engines++; } } if (master_index!=-1) { part_list[master_index].FindModulesImplementing<AHS>()[0].controlable_engines = controlable_no; part_list[master_index].FindModulesImplementing<AHS>()[0].engine_usage = found_engines+"/"+controlable_no; List<int> slaves = part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices; for (i=0; i<slaves.Count; i++) { part_list[slaves[i]].FindModulesImplementing<AHS>()[0].engine_usage = found_engines+"/"+controlable_no; } } } //Search for working slaves and update the master's slave list public void CheckSlaveState () { int master_index = -1; int i; //vessel will = null in the editor so we must cycle through parts list another way if it is not set List <Part> part_list; if (this.vessel!=null) { part_list = this.vessel.Parts; } else { part_list = new List<Part>(); Part start_part = this.part; while (start_part.parent!=null) start_part=start_part.parent; AddPartToList(start_part,part_list); } for (i=0; i<part_list.Count; i++) { if (part_list[i].FindModulesImplementing<AHS>().Count>0) { //All inactive states must be checked before asigning master slave states if (!part_list[i].FindModulesImplementing<AHS>()[0].ahs_on) { part_list[i].FindModulesImplementing<AHS>()[0].comand_state = "Off"; } else if ( part_list[i].FindModulesImplementing<AHS>()[0].comand_state!="No Power" ) { if (master_index==-1) { master_index=i; part_list[master_index].FindModulesImplementing<AHS>()[0].comand_state = "Master"; part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices.Clear(); } else { part_list[i].FindModulesImplementing<AHS>()[0].comand_state = "Slave"; part_list[master_index].FindModulesImplementing<AHS>()[0].slave_indices.Add(i); } } } } } //Find active gravity sensor and then set gravity to a useable value public void CheckGravSensor () { this.FindActiveSensor(); if (this.grav_sensor_index==-1) { this.gravity_state = "No Sonsor Found"; } else { if (this.grav_sensor_active) { this.gravity_state = "No Active Sensor"; } else { try { // Debug.Log("(AHS) grav string = "+this.grav_readout); if (this.grav_readout.Length>5) { string s = this.grav_readout.Substring(0,this.grav_readout.Length-5); // Debug.Log("(AHS) shrotend grav string = "+s); this.gravity = float.Parse(s); } else this.gravity = 9.82f; } catch { this.gravity = 9.82f; } this.gravity_state = this.grav_readout; } } }//endof void CheckGravSensor () //Updates grav readout and sets active state + finds an active sensor //You can force sensor finding by setting grav_sensor_index to -1 public void FindActiveSensor () { if (no_parts_in_last_check!=this.vessel.parts.Count) {//if parts have change then the index is no longer valid this.grav_sensor_index = -1; this.grav_sensor_active = false; } if ( this.grav_sensor_index != -1 ) {//if grav sensor is valid check it is active and update readout this.grav_readout = this.vessel.parts[this.grav_sensor_index].FindModulesImplementing<ModuleEnviroSensor>()[0].readoutInfo; this.grav_sensor_active = this.grav_readout=="off"; } //We dont need to search again if we have an active sensor and parts have not changed if ( no_parts_in_last_check==this.vessel.parts.Count && this.grav_sensor_active==true ) return; this.grav_sensor_index = -1; this.grav_sensor_active = false; int i; for (i=0; i<this.vessel.parts.Count; i++) { if (this.vessel.parts[i].name=="sensorGravimeter") { if (this.vessel.parts[i].FindModulesImplementing<ModuleEnviroSensor>().Count>0) { // Debug.Log("(AHS) found sensor at "+i+") name="+this.vessel.parts[i].name); if (this.grav_sensor_index == -1) { // Debug.Log("(AHS) grav sensor index set to "+i+" as it was invalid"); this.grav_sensor_index=i; } this.grav_readout = this.vessel.parts[i].FindModulesImplementing<ModuleEnviroSensor>()[0].readoutInfo; this.grav_sensor_active = this.grav_readout=="off"; if (this.grav_sensor_active) { // Debug.Log("(AHS) found active sensor at "+i+" name="+this.vessel.parts[i].name); this.grav_sensor_index = i; break; } } } } }//endof void FindActiveSensor () //part list builder. much better to use vessle.parts but its not avalible in the editor public void AddPartToList ( Part p_, List<Part> list_ ) { list_.Add(p_); int i; for (i=0; i<p_.children.Count; i++) { this.AddPartToList(p_.children[i],list_); } } public override void OnLoad (ConfigNode node) { base.OnLoad(node); this.HoverDisplayMode(); this.SetHoverGUI(); } //place for adding right click info to parts in the editor ? public override string GetInfo () { string result = ""; result += "Energy Usage: "+this.power_consumption.ToString()+"/sec\n"; result += "Heat Production: "+this.heat_production.ToString()+"/sec\n"; result += "Controlable Engines: "+this.max_engines.ToString()+"/sec\n"; return base.GetInfo ()+result; } }//endof public class AHS : PartModule }//endof namespace AHS -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
My main reason for looping was a mismatch in jet output resulting in great climb rate after undocking LOL (not shown in a video). It all depends on craft weight as light craft are very forgiving. I think providing there are a decent amount of Action groups so you can choose the correct setup with 1 key then there should be no problem with getting 100% thrust when pointing over horizontal I think no matter what i do, for anything approaching stunt flight things will get stupidly complicated and always need a vertical rocket toggle key (thats good). Oh and there is always the normal throttle settings that override tweak thrust anyways. You can just hit X and throttle up again. I cant wait to see how it handles . Im pondering what i should do to showoff the next version of Control system ? One thought is beating my own time for my KSC tour challenge but doing a loop around the walkway or my other thought is to make a monstrous 3 part supper heavy lifter for the today i build a rocket challenge. Im still some way off of making my kethane mining colony that was my main reason for making the plugin but things are moving along there too. Been looking into models today, mainly at the part merge tool. It done a very good job of showing me how to use stock parts and save game resources. Im a big fan of the stock look and way prefer the laziness of not having to make new models and textures. Only downside is a game bug forcing vertical stacking like with the 2 cross shaped parts. -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Yeah it sounds interesting and I will give it a try. I dont think it will work though. I think that if you rotated to 45 degrease the jets would take so long to spool up that you would find it not very useful but thats what rockets are for . I do see that it would add a lot of power to a racer and let you focus more on not crashing rather than worrying about your height so much. It would be very easy to extend on this and say that it should select the best engines for the hover and try to only thrust up but then we would be replacing more RCS systems and loosing translation ability. I am very concerned about what should or will happen when the hover engines cant help with vertical climb though. Currently with the fixed thrust system you can do loops without worrying that the jets might power down or power up to full when your pointing down . Hummmm..... I see ups and downs to both systems with nether being perfect so i like it and will add a mode system so you can choose what hover type to use. -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Im on the drunk side so im struggling with this a bit but hear gos. No problems. Its all part of the development process and i most certainly should add making a model to the to do list. all engines use the same module and so yes easy and no hard. The basic jet engine looks like this name = ModuleEngines useEngineResponseTime = True engineAccelerationSpeed = 0.12 engineDecelerationSpeed = 0.21 Very easy to find and hard to understand but easy to not care about and fun to tweak around while making your life just a little harder. The even more complicated part of calculating jet thrust comes from the height curves and pressure curves. The plugin uses a simple is best strategy and so sets all controlled engines to the same thrust which proves far more interesting than you may imagine if jets are involved. The very 1st video shows my pod racer hovering with jets and rockets enabled in the A.S.S. This uses lots of fuel but provides instant vertical control response that was needed at times. You could just Action group the rockets so they turn off and give yourself some up thrust prior to disabling to get you through the change. Turning them back on would not be so bad as it would be an instant boost up and so not do any damage but the intent is to find the correct balance of jet to rocket and im sure it changes from planet to planet. As spotted by others the plugin is not overpowered and just intended to change the form of the VTOL challenge. The mod is very interesting hear as it runs on fact not fiction. It adjust the thrust tweak based on the current known output of the controlled engines and nothing else. This means adding thrust by activating none controlled engines will not effect the controlled engines so will result in drastic speed changes. With jets it also results in a constant yo yo thrust level as the due to spool rates. It is finding the balance of jets to rockets that is intended to be the designers challenge (Replacing the piloting challenge). The I build a Mun Lander video has just jets in the A.S.S control and all the other rockets are set to action groups bound to the key pad. This is my third 3D set of controls that makes Jeb die so very much at the moment. I use the (key pad) Arrows for translation with exception for very fine height controls provided by the RCS H,N key watching. Then i use 1 action group for toggling the upwards rockets for the oh crap moments. 5 turns all the keypad controlled rockets off. This is needed as you will get confused and press the wrong button not know what you have done and start panicking. There are times in the video where forward and backward engines are both on and im so focused on the nav ball i just dont know so i hit the panic button and try to regain control. Combine this with SAS drift and its no walk in the park. well in the 1st lines of the code //M Pink provides ASS (v0.3) freely for anyone to use for anyreason they see fit. //M Pink is not responsable for any damage caused by ASS. //Ass Should Be Used At Your Own Risk ! Im not one for caring to much about licenses and so this dose bring up the possibility for anyone to claim the rights to this code and take ownership of it and or sell it as there own work but for me the greatest thing i could hope for is the plugin being claimed and used by squad and me not having to follow up with any problems of my bad coding I think it dose count as a licence without using any stranded copyright. If there is any way i could provide this more freely and clearly or something i should add please share. Thanks you could always send some cheap beer I hope so but its probably a bit confusing as to how at the moment. The tweakable is confusing and i should write something about it but hope to replace the system soon. The design is meant to be a bit limiting so it can only recognize the first 5 found engine types. It presents these as tweakable (Right click PNK A.S.S part) toggles with Control/Release next to them. It gets very confusing though when in the editor as there is a scan for engines button that is needed there to find the engines. What makes things truly confusing though is pressing sometimes dose nothing but if you right click the part again after triggering this, the menu will refresh and you will see the list. Shortened names sure don't help but i don't think there's much i can do there and the next update should change this totally anyways. Well thats where im pushing for yes. No insult taken its actually quite an achievement to be able to practice zero g whilst so close to a planet that you wont always die when you crash. If memory serves some of the early moon lander practice craft were the most dangerous things we have ever tried to fly. The idea is that the mod combined with some design skills should negate gravity until your fuel runs out and thus just a few RCS thrusters could get you from the launch pad to the VAB helipad with no danger. The fun comes though when you try to move something or change the S.A.S lock. The hover thrust is controlled by your crafts angle and A.S.S dose nothing to change this so life can get very complicated very very quickly if you place you RCS thrusters in a stupid place. This is truly the most basic form of fly by wire as it just removes the need for you to do some computing in flight. It just trys to keep a thrust stream = to the strength of gravity and nothing more, not even compare if the thrust and gravity are in the opposite directions (loops are not a good idea). -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
Hummm.... Interesting You said you added the module to a cockpit so you must know your way around KSP very well. So i have to ask the stupid questions just to get them out of the way. Did you copy the plugin to the GameData directory ? Of course you did or the module would not have been found. Are you running version 0.23 ? Yes or the module would not work due to lack of tweakables. Did you look in the correct place for the control system ? yes why where else would i look for a control system. So for some speculation. Looking at my log file i notice that there is a space in my part name. [LOG 10:06:17.233] Config(PART) Im_A_Cupcake_Wannabe/part/PNK ASS I think that can only be a bad thing. Im testing on windows 7 and it seams to work fine but im not sure why there's a directory style entry in the log with the part name in it anyway. Im sure this could cause problems on some operating systems as file paths with spaces arnt a good thing but still I cant see how it could be an actual file reference. It is something that looks very dodgy so you could try changing the part.cfg file from name = PNK ASS to name = PNK_ASS and seeing if that fixes it. If it still dosnt work posting your log file using the code wrap would be very handy. Thanks . It was more luck than anything else. Just turns out that keeping things simple makes it work better. The original SAS system is where all the clever trickery is going on. Iv tried doing the docking without using translation rockets (like cupcake dose) and it is almost impossible using keys even with the hover control so it dose just shift the problem from one of precision control to expert design. Iv still not docked a full orange tank yet but im sue it can be done with a well designed craft (balanced translation rockets is the key). Things do start to get very interesting with large masses and jets though as the spool up time starts to get out of hand but then using 2 types of engines for a hover fixes that at the cost of fuel usage. The main thing is that its a lot of fun -
[0.23] Im a Cupcake Wannabe (Advanced Hover System)
mpink replied to mpink's topic in KSP1 Mod Releases
just added a new video for the 0.3 demonstration. Iv also updated my to do list with some thoughts about where to go next. Iv still not tested this off world yet but i am in my base component design phase hence the thoughts about what changes would be good for 0.4 Building the Mun Lander demonstrated to me how important it is to link translation engines into the RCS keys. Having 3 different key systems each with 3 directions of control will get Jeb killed ! If all gos well then i think 0.4 should be the completion of the plugin and a change to V1. It should probably rename it then as to make it easier to understand. Ill certainly keep a reference to Cupcake in the description as the primary inspiration though. Anyone got an idea for a good name ? Advanced VTOL Control Systems Humm..... adding words to an acronym is just wrong. Advanced Hover System (VTOL) humm... AHS might be a better name for the component and the plugin. Rocket Operation Coordination Kontroler...... well yeah i might need to brush of an old fashioned dictionary and search for some good K words. Id think knowing k words could nether be a bad thing when it comes to naming stuff in the PNK engineering department. This would be a great time to suggest any ideas you may have. The next update will probably involve another complete rewrite to get everything to function correctly so suggestions are best done sooner than later. Have fun and fly safely.