├── .gitattributes ├── .gitignore ├── Reusable Booster ├── boostback.ks ├── boot │ ├── boostback_boot.ks │ ├── boot_constructor.ks │ ├── payload.ks │ └── refuel_truck.ks ├── cam.ks ├── circ.ks ├── constructor ├── cpu_light.ks ├── exec.ks ├── json │ └── launchParams │ │ ├── F-1 Booster.json │ │ ├── Payload 42.json │ │ └── RP-Lander 1.json ├── launch.ks ├── lib_UI.ks ├── lib_list.ks ├── lib_menu.ks ├── lib_rocket_utility.ks └── refuel_truck.ks ├── ap.ks ├── ap2.ks ├── autopilot.ks ├── boostback.ks ├── boot ├── boostback_boot.ks ├── boot_drone.ks ├── boot_plane.ks ├── boot_propeller.ks ├── boot_qShip.ks └── station.ks ├── boot_drone.ks ├── cam.ks ├── circ.ks ├── cpu_light.ks ├── debug.ks ├── dock.ks ├── drone_ship.ks ├── exec.ks ├── gui ├── blank.png ├── button.png ├── button_on.png ├── gui.png ├── hoverbot.png ├── indent.png ├── mini_terminal.png ├── radio.png ├── radio_hover.png ├── radio_on.png ├── slider_indent.png ├── slider_thumb.png ├── terminal.png ├── terminal_opaque.png ├── toggle_mid.png ├── toggle_off.png ├── toggle_off_hover.png ├── toggle_on.png └── toggle_on_hover.png ├── gui_template.ks ├── json ├── 5m Cargoplane Drone │ ├── autopilot.json │ └── steering.json ├── Aeris 3A kOS │ ├── autopilot.json │ └── steering.json ├── Albatross 3 kOS │ ├── autopilot.json │ └── steering.json ├── Ravenspear Mk3 │ ├── autopilot.json │ └── steering.json ├── Stearwing A300 │ ├── autopilot.json │ └── steering.json ├── Thunderbird │ ├── autopilot.json │ └── steering.json └── runways │ └── Kerbin.json ├── launch.ks ├── lib_UI.ks ├── lib_geo.ks ├── lib_list.ks ├── lib_menu.ks ├── lib_rocket_utility.ks ├── linetest.ks ├── menutest.ks ├── q.ks ├── quad ├── lib_formation.ks ├── lib_json.ks ├── lib_quad.ks ├── quad.ks ├── quad_GUI.ks ├── quad_loop.ks └── race.ks ├── rs.ks ├── steeringeditor.ks ├── steeringmanager.ks └── turret.ks /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Reusable Booster/boot/boostback_boot.ks: -------------------------------------------------------------------------------- 1 | // boostback_boot.ks 2 | clearscreen. 3 | 4 | wait 5. 5 | print "boostback boot program running, waiting for message to start.". 6 | local done is false. 7 | 8 | if altitude > 40000 and ship:messages:empty runpath("0:/boostback.ks", 0). 9 | else wait until kuniverse:timewarp:warp = 0. 10 | 11 | 12 | if ship:status = "LANDED" { 13 | local tars is list(). 14 | list targets in tars. 15 | for t in tars { 16 | if t:name:contains("Crane") global crane is t. 17 | else if t:name:contains("Refuel") global refueler is t. 18 | } 19 | 20 | for sr in ship:resources { 21 | if sr:name = "LiquidFuel" set lf to sr. 22 | else if sr:name = "Oxidizer" set ox to sr. 23 | } 24 | 25 | 26 | 27 | if defined refueler { 28 | if ((lf:amount + 1) < lf:capacity) or ((ox:amount + 1) < ox:capacity) { 29 | HUDTEXT("Requesting refueling from [" + refueler:name + "]", 6, 2, 30, green, false). 30 | 31 | wait 2. 32 | refueler:connection:sendmessage("bruh"). 33 | } 34 | 35 | 36 | } 37 | } 38 | 39 | ag10 off. 40 | until done { 41 | if ag10 { 42 | ag10 off. 43 | ship:connection:sendmessage("bruh"). 44 | } 45 | if not(ship:messages:empty) { 46 | local msg is ship:messages:peek. 47 | 48 | if msg:content = "bruh" { 49 | ship:messages:pop. 50 | wait 1. 51 | HUDTEXT("Spawning payload", 5, 2, 40, cyan, false). 52 | wait 3. 53 | set rand to random(). 54 | if ag5 { 55 | set rand to 0.1. 56 | } 57 | else if ag6 set rand to 0.9. 58 | ag5 off. 59 | ag6 off. 60 | if rand < 0.5 set craft to kuniverse:getcraft("RP-Lander 1","VAB"). 61 | else set craft to kuniverse:getcraft("Payload 42","VAB"). 62 | //local craft is kuniverse:getcraft("Payload 37","VAB"). 63 | //local craft is kuniverse:getcraft("Payload 24","VAB"). 64 | 65 | //set craft to kuniverse:getcraft("Payload 42","VAB"). 66 | set craft to kuniverse:getcraft("RP-Lander 1","VAB"). 67 | kuniverse:launchcraft(craft). 68 | } 69 | else if msg:content = "boostback" { 70 | ship:messages:pop. 71 | switch to 0. 72 | runpath("0:/boostback.ks", 0, msg:sender). 73 | set done to true. 74 | } 75 | else if msg:content = "good luck" { 76 | ship:messages:pop. 77 | switch to 0. 78 | runpath("0:/boostback.ks", 1, msg:sender). 79 | set done to true. 80 | } 81 | } 82 | wait 0.4. 83 | } -------------------------------------------------------------------------------- /Reusable Booster/boot/boot_constructor.ks: -------------------------------------------------------------------------------- 1 | //drone boot 2 | wait until ship:unpacked and ship:loaded. 3 | ag1 off. 4 | switch to 0. 5 | set terminal:brightness to 1. 6 | //set terminal:width to 30. 7 | //set terminal:height to 20. 8 | clearscreen. 9 | print "In standby". 10 | print "-------------------------". 11 | print "[AG 1] START". 12 | print "[AG 2] Force compile all". 13 | print "[AG 3] Exit boot program". 14 | print "-------------------------". 15 | print " ". 16 | 17 | wait until ship:unpacked. 18 | 19 | runoncepath("cpu_light.ks"). 20 | 21 | //local ascending is false. 22 | //local strength is 1.1. 23 | //local strengthIncr is 0.05. 24 | // 25 | //set R to 1. 26 | //set G to 0. 27 | //set B to 0. 28 | 29 | setLights(0,0.6,1). 30 | //set phase to 0. 31 | global pickup is false. 32 | 33 | until ag1 { 34 | 35 | 36 | //if phase = 0 { 37 | // if R = 0 set phase to 1. 38 | // else { 39 | // set R to ROUND(R - 0.1,1). 40 | // set G to ROUND(G + 0.1,1). 41 | // } 42 | //} 43 | //if phase = 1 { 44 | // if G = 0 set phase to 2. 45 | // else { 46 | // set G to ROUND(G - 0.1,1). 47 | // set B to ROUND(B + 0.1,1). 48 | // } 49 | //} 50 | //if phase = 2 { 51 | // if B = 0 set phase to 0. 52 | // else { 53 | // set B to ROUND(B - 0.1,1). 54 | // set R to ROUND(R + 0.1,1). 55 | // } 56 | //} 57 | // 58 | //setlights(R,G,B). 59 | // 60 | //messages 61 | if not ship:messages:empty { 62 | local msg is ship:messages:pop. 63 | 64 | if msg:content[0] = "bruh" { 65 | ag1 on. 66 | global payload is msg:sender. 67 | global payloadPort is payload:partstagged("payload")[0]. 68 | 69 | global booster is vessel(msg:content[1]). 70 | global boosterPort is booster:partstagged("booster")[0]. 71 | set pickup to true. 72 | 73 | print payload. 74 | print booster. 75 | } 76 | } 77 | 78 | 79 | wait 0.2. 80 | } 81 | 82 | global exit is false. 83 | if ag1 { 84 | ag1 off. 85 | //core:doevent("open terminal"). 86 | runpath("constructor/loader_constructor.ks"). 87 | } 88 | 89 | print "Program ended". 90 | reboot. -------------------------------------------------------------------------------- /Reusable Booster/boot/payload.ks: -------------------------------------------------------------------------------- 1 | // launch boot file 2 | 3 | wait until ship:loaded and ship:unpacked. 4 | clearscreen. 5 | wait 1. 6 | 7 | switch to 0. 8 | //for ms in core:part:modules { //for some reason terminal sometimes closes on dock 9 | // set m to core:part:getmodule(ms). 10 | // if m:hasaction("Open Terminal") m:doevent("Open Terminal"). 11 | //} 12 | 13 | local tars is list(). 14 | list targets in tars. 15 | 16 | for t in tars { 17 | if t:name:contains("Crane") global crane is t. 18 | else if t:name:contains("Booster") global booster is t. 19 | } 20 | if defined crane and defined booster and altitude < 1000 { 21 | print crane. 22 | print booster. 23 | 24 | HUDTEXT("Requesting pickup from [" + crane:name + "]", 5, 2, 40, green, false). 25 | 26 | //crane:connection:sendmessage(list("bruh", booster)). 27 | crane:connection:sendmessage(list("bruh",booster:name)). 28 | 29 | print "Sent message to drone crane". 30 | } 31 | 32 | 33 | 34 | 35 | 36 | 37 | print "". 38 | print " AG 1: Start Launch.ks ". 39 | print "". 40 | print " AG 2: Quit ". 41 | 42 | 43 | 44 | ag1 off. 45 | ag2 off. 46 | ag10 off. 47 | until ag2 { 48 | if ag10 reboot. 49 | 50 | //messages 51 | if not ship:messages:empty { 52 | local msg is ship:messages:peek. 53 | 54 | 55 | if msg:content = "Lift done" { 56 | ship:messages:pop. 57 | ag1 on. 58 | } 59 | } 60 | 61 | if ag1 { ag1 off. run launch. set core:bootfilename to "none". } 62 | wait 0.3. 63 | } 64 | ag2 off. 65 | 66 | -------------------------------------------------------------------------------- /Reusable Booster/boot/refuel_truck.ks: -------------------------------------------------------------------------------- 1 | clearscreen. 2 | print "Refueling script is running...". 3 | print "Waiting for a request message". 4 | 5 | wait until ship:loaded and ship:unpacked. 6 | lights off. 7 | 8 | 9 | until false { 10 | wait 0.5. 11 | if not(ship:messages:empty) { 12 | local msg is ship:messages:pop. 13 | if msg:content = "bruh" { 14 | global targetVessel is msg:sender. 15 | if targetVessel:loaded and targetVessel:unpacked { 16 | global targetPort is targetVessel:partstagged("refueling port")[0]. 17 | } 18 | else global targetPort is ship:rootpart. 19 | 20 | kuniverse:forceactive(ship). 21 | 22 | break. 23 | } 24 | } 25 | } 26 | 27 | run refuel_truck. -------------------------------------------------------------------------------- /Reusable Booster/cam.ks: -------------------------------------------------------------------------------- 1 | // ### Functions ### 2 | // >> 3 | function vecToHdg { 4 | parameter v. 5 | set v to vxcl(up:vector,v). 6 | 7 | local ang is vang(north:vector,v). 8 | if vdot(heading(90,0):vector,v) < 0 set ang to -ang. 9 | 10 | return ang. 11 | //return ang * constant():pi / 180. //return in radians 12 | } 13 | 14 | function vecToPitch { 15 | parameter v. 16 | 17 | local ang is vang(-up:vector,v) - 90. 18 | 19 | return -ang. 20 | //return ang * constant():pi / 180. 21 | } 22 | 23 | 24 | 25 | // << 26 | 27 | 28 | 29 | global hasCamAddon is addons:available("camera"). 30 | 31 | if hasCamAddon { 32 | global extcam is addons:camera:flightcamera. 33 | //set extcam:camerafov to 70. 34 | 35 | 36 | 37 | //local ev is v(0,0,0). 38 | //global camAvgList is list(). 39 | //global camAvgFrames is 30. 40 | //global camAvgI is 0. 41 | //for i in range(camAvgFrames) camAvgList:add(ev). 42 | 43 | } -------------------------------------------------------------------------------- /Reusable Booster/circ.ks: -------------------------------------------------------------------------------- 1 | //circularization script, starts immediately when called. 2 | parameter method is "engines". 3 | 4 | sas off. 5 | set th to 0. 6 | lock throttle to th. 7 | set dV to ship:facing:vector:normalized. 8 | if method = "rcs" { 9 | lock steering to "kill". 10 | set old_rcs to rcs. 11 | rcs on. 12 | } 13 | else lock steering to lookdirup(dV, ship:facing:topvector). 14 | 15 | local timeout is time:seconds + 9000. 16 | when dV:mag < 0.1 then { set timeout to time:seconds + 2. return false. } 17 | until dV:mag <= 0.001 or time:seconds > timeout { 18 | set posVec to ship:position - body:position. 19 | set vecNormal to vcrs(posVec,velocity:orbit). 20 | set vecHorizontal to -1 * vcrs(ship:position-body:position, vecNormal). 21 | set vecHorizontal:mag to sqrt(body:MU/(body:Radius + altitude)). 22 | 23 | set dV to vecHorizontal - velocity:orbit. //deltaV as a vector 24 | 25 | //Debug vectors 26 | //set mark_n to VECDRAWARGS(ship:position, vecNormal:normalized * (velocity:orbit:mag / 100), RGB(1,0,1), "n", 1, true). 27 | //set mark_h to VECDRAWARGS(ship:position, vecHorizontal / 100, RGB(0,1,0), "h", 1, true). 28 | //set mark_v to VECDRAWARGS(ship:position, velocity:orbit / 100, RGB(0,0,1), "dv", 1, true). 29 | //set mark_dv to VECDRAWARGS(ship:position, dV * 10, RGB(1,1,1), "dv: " + round(dv:mag,3) + "m/s", 1, true,0.2). 30 | 31 | if method = "rcs" { 32 | set dV:mag to min(dV:mag * 5,1)^0.75. 33 | //set ship:control:fore to -pid1:update(time:seconds,vdot(facing:vector,dV)). 34 | //set ship:control:top to -pid2:update(time:seconds,vdot(facing:topvector,dV)). 35 | //set ship:control:starboard to -pid3:update(time:seconds,vdot(facing:starvector,dV)). 36 | 37 | set ship:control:fore to vdot(facing:vector,dV). 38 | set ship:control:top to vdot(facing:topvector,dV). 39 | set ship:control:starboard to vdot(facing:starvector,dV). 40 | } 41 | else { 42 | //throttle control 43 | set max_acc to ship:maxthrust / ship:mass. 44 | set angvel to ship:angularvel:mag * (180/constant():pi). 45 | if vang(ship:facing:vector,dV) > 1 or angvel > 3 { set th to 0. } 46 | else { set th to dV:mag/ (max_acc * 1). } 47 | } 48 | 49 | 50 | wait 0. 51 | } 52 | set th to 0. 53 | unlock throttle. 54 | unlock steering. 55 | clearvecdraws(). 56 | HUDTEXT("Circularization complete", 3, 2, 30, yellow, false). -------------------------------------------------------------------------------- /Reusable Booster/constructor/lib_constructor.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | 3 | //modes 4 | global m_hover is 2. 5 | global m_land is 3. 6 | global m_free is 4. 7 | global m_bookmark is 5. 8 | global m_pos is 6. 9 | global m_follow is 7. 10 | global m_pickup is 10. 11 | global m_fuel is 99. 12 | 13 | function mode_string { 14 | if mode = m_hover return "hover". 15 | else if mode = m_land return "landing". 16 | else if mode = m_free return "freeroam". 17 | else if mode = m_pos return "position". 18 | else if mode = m_follow return "following " + tarVeh:name. 19 | else if mode = m_pickup return "transport". 20 | else return "error". 21 | } 22 | 23 | //function sortTargets { 24 | // local sorted is list(). 25 | // list targets in tgs. 26 | // 27 | // local i is 0. 28 | // local limited is false. 29 | // 30 | // local lowestTarget is 0. 31 | // until i = tgs:length or i = 10 { 32 | // local isValid is false. 33 | // local lowestValue is 100000. 34 | // for t in tgs { 35 | // local tDistance is t:distance. 36 | // if t:body = ship:body and tDistance < lowestValue and not sorted:contains(t) { 37 | // set lowestValue to tDistance. 38 | // set lowestTarget to t. 39 | // set isValid to true. 40 | // } 41 | // } 42 | // set i to i + 1. 43 | // 44 | // if isValid sorted:add(lowestTarget). 45 | // } 46 | // return sorted. 47 | //} 48 | // 49 | //function targetStrings { 50 | // parameter tgs. //list of vessels 51 | // local stringList is list(""). 52 | // for t in tgs { 53 | // stringList:add(t:name). 54 | // } 55 | // return stringList. 56 | //} 57 | 58 | // parameter 1: A string or index number based on the list below. 59 | // returns: a geoposition 60 | function geo_bookmark { 61 | parameter bookmark. 62 | 63 | 64 | if bookmark = 1 or bookmark = "LAUNCHPAD" or bookmark = "KSC" return LATLNG(-0.0972078822701718, -74.5576864391954). //Kerbal space center 65 | else if bookmark = 2 or bookmark = "RUNWAY E" return LATLNG(-0.0502131096942382, -74.4951289901873). //East 66 | else if bookmark = 3 or bookmark = "RUNWAY W" return LATLNG(-0.0486697432694389, -74.7220377114077). //West 67 | else if bookmark = 4 or bookmark = "VAB" return LATLNG(-0.0967646955755359, -74.6187122587352). //VAB Roof 68 | 69 | else if bookmark = 5 or bookmark = "IKSC" return latlng(20.3926,-146.2514). //inland kerbal space center 70 | else if bookmark = 6 or bookmark = "ISLAND W" return LATLNG(-1.5173500701556, -71.9623911214353). //Island/airfield runway west 71 | else if bookmark = 7 or bookmark = "ISLAND E" return LATLNG(-1.51573303823027, -71.8571463011229).//Island/airfield runway east 72 | else if bookmark = 8 or bookmark = "POOL" return LATLNG(-0.0867719193943464, -74.6609773699654). 73 | //else if bookmark = "" return . 74 | 75 | 76 | else { print "ERROR: geolocation bookmark " + bookmark + " not found!". return latlng(90,0). } 77 | } 78 | 79 | //////////////////// User Interface stuff /////////////////// 80 | function toggleTerVec { 81 | parameter var. 82 | set terMark to var. 83 | 84 | local i is 1. 85 | until i = 6 { 86 | set pm to pList[i]. 87 | set vecs[pm]:show to terMark. 88 | set i to i + 1. 89 | } 90 | } 91 | function toggleVelVec { 92 | parameter var. 93 | set stMark to var. 94 | if submode = m_free { 95 | set vecs[markHorV]:show to true. 96 | set vecs[markDesired]:show to true. 97 | } 98 | else { 99 | set vecs[markHorV]:show to stMark. 100 | set vecs[markDesired]:show to stMark. 101 | } 102 | } 103 | function toggleThrVec { 104 | parameter var. 105 | set thMark to var. 106 | set i to 0. 107 | for eng in engs { 108 | set vecs[i]:show to thMark. 109 | set i to i + 1. 110 | } 111 | } 112 | function toggleAccVec { 113 | parameter var. 114 | set miscMark to var. 115 | set vecs[markTar]:show to miscMark. 116 | //set vecs[markAcc]:show to miscMark. 117 | } 118 | 119 | function popup { 120 | parameter s. 121 | HUDTEXT(s, 5, 2, 40, yellow, false). 122 | if addons:available("tts") addons:tts:say(s). 123 | 124 | // context: HUDTEXT( Message, delaySeconds, style, size, colour, boolean doEcho). 125 | //style: - 1 = upper left - 2 = upper center - 3 = lower right - 4 = lower center 126 | } 127 | function warning { 128 | parameter s. 129 | HUDTEXT(s, 5, 2, 60, red, false). 130 | if addons:available("tts") addons:tts:say("Warning!" + s). 131 | 132 | // context: HUDTEXT( Message, delaySeconds, style, size, colour, boolean doEcho). 133 | //style: - 1 = upper left - 2 = upper center - 3 = lower right - 4 = lower center 134 | } 135 | 136 | 137 | /////////////////////// VECTORS /////////////////////////// 138 | 139 | // vecs_clear(). 140 | function vecs_clear { 141 | if vecs:length > 0 { 142 | for vd in vecs { 143 | set vd:SHOW TO false. 144 | } 145 | vecs:clear. 146 | } 147 | } 148 | 149 | // set [variable] to vecs_add([position],[vector],[color],[string]). 150 | // returns: list index. 151 | // example: 152 | // Create a vecdraw: 153 | // set velocityVec to vecs_add(ship:position,velocity:orbit,blue,round(velocity:orbit:mag) + " m/s"). 154 | // Update it's starting position: 155 | // set vecs[velocityVec]:start to ship:position. 156 | function vecs_add { 157 | parameter p,v,c,descr,w. 158 | vecs:add(VECDRAWARGS(p, v, c, descr, 1, false,w)). 159 | return vecs:length - 1. 160 | } 161 | function vecs_add_v { 162 | parameter p,v,c,descr,w. 163 | vecs:add(VECDRAWARGS(p, v, c, descr, 1, true,w)). 164 | return vecs:length - 1. 165 | } 166 | 167 | global vecs is list(). 168 | if vecs:length > 0 vecs_clear(). 169 | 170 | ////////////////////////////////////////////////////////// 171 | 172 | function nz { //"not zero" , NaN protection 173 | parameter float. 174 | if abs(float) < 0.001 { 175 | set float to 0.001. 176 | } 177 | return float. 178 | } 179 | local c_pi is constant:pi. 180 | function toRad { 181 | parameter n. 182 | return n * (c_pi / 180). 183 | } 184 | 185 | 186 | -------------------------------------------------------------------------------- /Reusable Booster/constructor/loader_constructor.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | SET CONFIG:STAT TO false. 3 | set terminal:brightness to 1. 4 | //set terminal:charwidth to 12. 5 | //set terminal:charheight to 12. 6 | print "Preparing Constructor QUAD script files..". 7 | runoncepath("cpu_light.ksm"). 8 | setLights(0,0.5,0.5). 9 | wait 0.1. 10 | 11 | 12 | clearguis(). 13 | //runoncepath("cam.ks"). 14 | runoncepath("constructor/lib_constructor.ks"). 15 | //runoncepath("lib_json.ks"). 16 | //runoncepath("race.ks"). 17 | runoncepath("constructor/loop_constructor.ks"). 18 | //runoncepath("constructor/GUI_constructor.ks"). 19 | print "Running Quad setup..". 20 | //core:doaction("close terminal",true). 21 | runpath("constructor/main_constructor.ks"). 22 | 23 | //LOG PROFILERESULT() TO qprof.csv. -------------------------------------------------------------------------------- /Reusable Booster/cpu_light.ks: -------------------------------------------------------------------------------- 1 | //function to set the kos cpu's light, if it has one. 2 | 3 | //find the module and store it for later 4 | local lightParts is ship:partstagged("light"). 5 | local kosLightMods is list(). 6 | local hasLights is false. 7 | getLightModule(core:part). 8 | 9 | if lightParts:length > 0 { 10 | for p in lightParts { 11 | getLightModule(p). 12 | } 13 | } 14 | 15 | function getLightModule { 16 | parameter p. 17 | for ms in p:modules { 18 | local m is p:getmodule(ms). 19 | if m:hasfield("light r") { 20 | set hasLights to true. 21 | kosLightMods:add(m). 22 | } 23 | } 24 | } 25 | 26 | function setLights { 27 | parameter r,g,b. 28 | 29 | if hasLights { 30 | for m in kosLightMods { 31 | m:setfield("light r",r). 32 | m:setfield("light g",g). 33 | m:setfield("light b",b). 34 | } 35 | } 36 | } 37 | 38 | if hasLights { 39 | setLights(1,1,1). 40 | } -------------------------------------------------------------------------------- /Reusable Booster/exec.ks: -------------------------------------------------------------------------------- 1 | parameter nn is nextnode. 2 | HUDTEXT("Starting execute node script.", 4, 2, 30, yellow, false). 3 | 4 | runoncepath("lib_rocket_utility.ks"). 5 | 6 | sas off. 7 | set th to 0. 8 | lock throttle to th. 9 | lock steering to lookdirup(nn:deltav, ship:facing:topvector). //points to node, keeping roll the same. 10 | 11 | local burn_stats is half_dv_duration(nn:deltav:mag). 12 | local first_half_duration is burn_stats[0]. 13 | local burn_duration is first_half_duration + burn_stats[1]. 14 | 15 | set kuniverse:timewarp:warp to 0. 16 | 17 | set node_time to time:seconds + nn:eta. 18 | set warp_target to node_time - 5 - first_half_duration. 19 | 20 | wait until vang(facing:vector, steering:vector) < 1 or time:seconds >= warp_target. 21 | 22 | 23 | 24 | 25 | 26 | 27 | HUDTEXT("Estimated burn duration: " + round(burn_duration,1) + "s", 15, 2, 20, yellow, false). 28 | 29 | 30 | 31 | if warp_target > time:seconds { 32 | set kuniverse:timewarp:mode to "rails". 33 | wait 0. 34 | kuniverse:timewarp:warpto(warp_target). 35 | } 36 | 37 | 38 | 39 | wait until nn:eta - first_half_duration <= 0. //wait until we are close to executing the node 40 | set kuniverse:timewarp:mode to "physics". //se we can manually physics warp during a burn 41 | 42 | //HUDTEXT("Begin burn. Physics warp is possible.", 5, 2, 20, yellow, false). 43 | 44 | set dv0 to nn:deltav. 45 | 46 | local done is false. 47 | until done { 48 | set max_acc to ship:availablethrust/ship:mass. 49 | 50 | if nn:deltav:mag/max_acc < 2 set warp to 0. //warp 51 | else if nn:deltav:mag/max_acc < 4 set warp to 1. 52 | else if nn:deltav:mag/max_acc < 7 set warp to 2. 53 | else set warp to 3. 54 | 55 | if vang(facing:vector, steering:vector) > 1 { set th to 0. } 56 | else { set th to min(nn:deltav:mag/(max_acc*0.75), 1). } 57 | 58 | 59 | LIST engines IN engs. 60 | for eng in engs { if eng:ignition = true and eng:flameout = true and stage:ready { stage. } } 61 | 62 | if nn:deltav:mag < 0.05 set done to true. 63 | wait 0. 64 | } 65 | 66 | HUDTEXT("Manouver node has been executed", 4, 2, 30, yellow, false). 67 | 68 | set kuniverse:timewarp:mode to "rails". 69 | unlock steering. 70 | set th to 0. 71 | unlock throttle. 72 | set ship:control:pilotmainthrottle to 0. 73 | remove nn. -------------------------------------------------------------------------------- /Reusable Booster/json/launchParams/F-1 Booster.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "turn_end", 4 | 55000, 5 | "turn_exponent", 6 | 0.63, 7 | "turn_speed", 8 | 30, 9 | "calc_ascent", 10 | false, 11 | "stage_to_orbit", 12 | 2, 13 | "stg_recovery", 14 | true, 15 | "auto_rcs", 16 | true 17 | ], 18 | "$type": "kOS.Safe.Encapsulation.Lexicon" 19 | } -------------------------------------------------------------------------------- /Reusable Booster/json/launchParams/Payload 42.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "turn_end", 4 | 55000, 5 | "turn_exponent", 6 | 0.61, 7 | "turn_speed", 8 | 10, 9 | "calc_ascent", 10 | false, 11 | "stage_to_orbit", 12 | 0, 13 | "stg_recovery", 14 | true, 15 | "auto_rcs", 16 | true 17 | ], 18 | "$type": "kOS.Safe.Encapsulation.Lexicon" 19 | } -------------------------------------------------------------------------------- /Reusable Booster/json/launchParams/RP-Lander 1.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "turn_end", 4 | 55000, 5 | "turn_exponent", 6 | 0.65, 7 | "turn_speed", 8 | 30, 9 | "calc_ascent", 10 | false, 11 | "stage_to_orbit", 12 | 2, 13 | "stg_recovery", 14 | true, 15 | "auto_rcs", 16 | true 17 | ], 18 | "$type": "kOS.Safe.Encapsulation.Lexicon" 19 | } -------------------------------------------------------------------------------- /Reusable Booster/lib_UI.ks: -------------------------------------------------------------------------------- 1 | local emptyString is " ". 2 | 3 | function horizontalLine { 4 | parameter line,char,ret is false. 5 | local s is emptyString:substring(0,terminal:width). 6 | set s to s:replace(" ",char). 7 | 8 | if ret return s. 9 | else print s at (0,line). 10 | } 11 | 12 | function horizontalLineTo { 13 | parameter line,colStart,colEnd,char,ret is false. 14 | local s is emptyString:substring(0,colEnd - colStart + 1). 15 | set s to s:replace(" ",char). 16 | 17 | if ret return s. 18 | else print s at (colStart,line). 19 | } 20 | function verticalLineTo { 21 | parameter column,lineStart,lineEnd,char. 22 | local line is lineStart. 23 | until line > lineEnd { 24 | print char at (column,line). 25 | set line to line + 1. 26 | } 27 | } 28 | 29 | // clears an entire line of the terminal 30 | function clearLine { 31 | parameter line,ret is false. 32 | local s is emptyString:substring(0,terminal:width). 33 | 34 | if ret return s. 35 | else print s at (0,line). 36 | } 37 | 38 | // clears a line from columnStart to columnEnd 39 | function clearLineTo { 40 | parameter line,columnStart,columnEnd,ret is false. 41 | local s is emptyString:substring(0,columnEnd-columnStart + 1). 42 | 43 | if ret return s. 44 | else print s at (columnStart,line). 45 | } 46 | 47 | function clearBox { 48 | parameter line,lineEnd,colStart,colEnd. 49 | 50 | until line > lineEnd { 51 | clearLineTo(line,colStart,colEnd). 52 | set line to line + 1. 53 | } 54 | } 55 | 56 | /////////////////////// VECTORS /////////////////////////// 57 | 58 | // vecs_clear(). 59 | function vecs_clear { 60 | if vecs:length > 0 { 61 | for vd in vecs { 62 | set vd:SHOW TO false. 63 | } 64 | vecs:clear. 65 | } 66 | clearvecdraws(). 67 | } 68 | 69 | // set [variable] to vecs_add([position],[vector],[color],[string]). 70 | // returns: list index. 71 | // example: 72 | // Create a vecdraw: 73 | // set velocityVec to vecs_add(ship:position,velocity:orbit,blue,round(velocity:orbit:mag) + " m/s"). 74 | // Update it's starting position: 75 | // set vecs[velocityVec]:start to ship:position. 76 | function vecs_add { 77 | parameter p,v,c,descr,w. 78 | vecs:add(VECDRAWARGS(p, v, c, descr, 1, true,w)). 79 | return vecs:length - 1. 80 | } 81 | 82 | 83 | global vecs is list(). 84 | clearvecdraws(). 85 | 86 | ////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /Reusable Booster/lib_list.ks: -------------------------------------------------------------------------------- 1 | // ######################################### 2 | // ############ Scrolling list ############# 3 | 4 | @LAZYGLOBAL on. 5 | runoncepath("lib_UI.ks"). //needed for some terminal drawing functions. 6 | 7 | global list_menu is list(""). 8 | //global lib_list_active is true. 9 | 10 | //declare some vars and default values 11 | local listmenu_dimensions is lexicon( 12 | "startColumn", 0, 13 | "endColumn", 1, 14 | "startLine", 0, 15 | "endLine", 1, 16 | "columns", 1, 17 | "lines", 1 18 | ). 19 | 20 | // important: this must be called after loading this library 21 | function list_position { //parameters: start col, end col, start line, end line. 22 | parameter sc,ec,sl,el. 23 | set listmenu_dimensions["startColumn"] to sc. 24 | set listmenu_dimensions["endColumn"] to ec. 25 | set listmenu_dimensions["startLine"] to sl. 26 | set listmenu_dimensions["endLine"] to el. 27 | 28 | set listmenu_dimensions["columns"] to listmenu_dimensions["endColumn"] - listmenu_dimensions["startColumn"] + 1. 29 | set listmenu_dimensions["lines"] to listmenu_dimensions["endLine"] - listmenu_dimensions["startLine"] + 1. 30 | } 31 | 32 | function add_entry { 33 | parameter str_entry. 34 | list_menu:add(str_entry). 35 | parse_entry(str_entry). 36 | 37 | 38 | 39 | draw_list(). 40 | } 41 | 42 | local print_list is list(). 43 | function parse_list { 44 | print_list:clear. 45 | for entry in list_menu { 46 | parse_entry(entry). 47 | } 48 | } 49 | 50 | local indent is "". 51 | function set_indentation { 52 | parameter length. 53 | set indent to "". 54 | local i is 0. 55 | until i = length { 56 | set indent to indent + " ". 57 | set i to i + 1. 58 | } 59 | } 60 | 61 | function parse_entry { 62 | parameter str. 63 | local words is str:split(" "). 64 | local str_list is list(""). 65 | local i is 0. 66 | for word in words { 67 | if word:length + str_list[i]:length <= listmenu_dimensions["columns"] set str_list[i] to str_list[i] + word + " ". 68 | else { 69 | set i to i + 1. 70 | str_list:add(indent + word + " "). 71 | } 72 | } 73 | str_list:add(""). 74 | 75 | local i is str_list:length - 1. 76 | until i < 0 { 77 | print_list:insert(0,str_list[i]:trimend()). 78 | set i to i - 1. 79 | } 80 | } 81 | 82 | function draw_list { 83 | clearBox(listmenu_dimensions["startLine"],listmenu_dimensions["endLine"],listmenu_dimensions["startColumn"],listmenu_dimensions["endColumn"]). 84 | 85 | local i is 0. 86 | until i = print_list:length or i = listmenu_dimensions["lines"] { 87 | print print_list[i] at (listmenu_dimensions["startColumn"],listmenu_dimensions["startLine"] + i). 88 | set i to i + 1. 89 | } 90 | } -------------------------------------------------------------------------------- /Reusable Booster/lib_menu.ks: -------------------------------------------------------------------------------- 1 | // For this to work you need to create at least one menu list in this format (note the extra value at the end of numbers!): 2 | // 3 | // local sv is -9.9993134. 4 | // set someMenu to list( 5 | // list("Some text to display", "text"), 6 | // list("_", "line"), 7 | // list("A read-only variable:", "display", { return round(ship:airspeed,1) + " m/s". }), 8 | // list("A number:", "number", { parameter p is sv. if p <> sv set number1 to p. return number1. }, 10), 9 | // list("Editable text:", "string", { parameter p is sv. if p <> sv set string1 to p. return string1. }), 10 | // list("Boolean value:", "bool", { parameter p is sv. if p <> sv toggle bool1. return bool1. }), 11 | // list("An action", "action", { stage. }), 12 | // list("Some other menu", "menu", { return someSubMenu. }), 13 | // list("The parent menu", "backmenu", { return mainMenu. }) 14 | // ). 15 | // 16 | // The first three types are read-only items and can't be selected or changed by the program 17 | // Available types: 18 | // text: 19 | // just displays the name of the item, can print across all columns. 20 | // line: 21 | // makes a horizontal line across the menu using the single character. 22 | // display: 23 | // displays what you return from the anonymous function 24 | // number: 25 | // Can be edited with A/D (in increments) with Q/E altering increment scale. 26 | // Can be replaced by starting to type in a number when the line is selected. Hit enter to apply it. Backspace works too. 27 | // Can be edited by hitting enter with the line selected. 28 | // Needs a get/set anonymous function like shown above. 29 | // Needs the variable to have been declared by you elsewhere in your main program. 30 | // Needs to have a increment multiplier set in it's list as shown above (a value of 10 will make the default increment 10). 31 | // string: 32 | // Can be edited by hitting enter with the line selected. 33 | // Needs a get/set anonymous function like shown above. 34 | // Needs the variable to have been declared by you elsewhere in your main program. 35 | // bool: 36 | // Can be toggled by hitting enter, A, or D 37 | // Needs a get/set anonymous function like shown above. 38 | // Needs the variable to have been declared by you elsewhere in your main program. 39 | // action: 40 | // Runs the anonymous function when you hit enter/D when it is selected 41 | // menu: 42 | // Opens another menu that you will have to link to in the function. 43 | // backmenu: 44 | // exactly like "menu" but this can also be triggered by pressing backspace 45 | 46 | // Controls: 47 | // W/S/UpArrow/DownArrow: navigates the menu 48 | // A/D: Runs commands, increments numbers 49 | // Q/E: Changes number increment scale 50 | // Enter: Runs commands, edits numbers and strings, toggles boolean values. 51 | // Backspace: opens the parent menu if it exists (for submenues) 52 | // Typing a number: When a number is selected, typing a number will start the number editor. Enter or W/S to confirm. 53 | 54 | 55 | 56 | 57 | //lib_menu.ks 58 | @LAZYGLOBAL on. 59 | runoncepath("lib_UI.ks"). //needed for some terminal drawing functions. 60 | 61 | if not (defined startLine) local startLine is 0. //the first menu item will start at this line in the terminal window 62 | if not (defined startColumn) local startColumn is 3. //menu item description starts at this x coordinate, remember to leave some space for the marker on the left 63 | if not (defined nameLength) local nameLength is 16. //how many characters of the menu item names to display 64 | if not (defined valueLength) local valueLength is 12. //how many characters of the menu item values to display 65 | 66 | if not (defined incrOptions) local incrOptions is list (0.01,0.1,1,10,100,1000). // default increment values in ascending order (for incrementing numbers with A/D). Feel free to add or remove steps from this list 67 | 68 | 69 | local incrI is 2. 70 | local typingNumber is false. 71 | local typingString is false. 72 | global selectedLine is 0. 73 | local lineType is "text". 74 | 75 | local dummyMenu is list( 76 | list("","text"), 77 | list("This is a placeholder menu, if you see this you need to","text"), 78 | list("set the activeMenu variable to a menu list of your own","text"), 79 | list("","text"), 80 | list("","action",{ hudtext("It puts the menu in the variable or else it gets the hose again",5, 4, 35, red, false). }) 81 | ). 82 | 83 | // !! activeMenu is a varaible that should contain the list that defines the menu that you want to display !! 84 | if not (defined activeMenu) global activeMenu is dummyMenu. 85 | local lastMenu is activeMenu. 86 | 87 | // ### Drawing stuff to terminal ### 88 | // >> 89 | //draw the menu 90 | function drawAll { 91 | 92 | terminal:input:clear(). //clear inputs for new menus just in case.. 93 | set selectedLine to 0. 94 | set lineType to activeMenu[selectedLine][1]. 95 | 96 | //column starts 97 | set C1 to startColumn. 98 | set C2 to C1 + nameLength. 99 | set C3 to C2 + valueLength. 100 | 101 | clearBox(startLine,startLine + lastMenu:length - 1,C1,C3). //clear the last menu. This won't clear anything else on the terminal 102 | 103 | 104 | local notFoundSelectable is true. 105 | local i is 0. 106 | inputs(). 107 | until i >= activeMenu:length { 108 | if notFoundSelectable and not readOnlyTypes:contains(activeMenu[i][1]) { //skip read only lines 109 | set selectedLine to i. 110 | set notFoundSelectable to false. 111 | } 112 | updateLine(i). 113 | 114 | //debug info about your current menu, uncomment to display it below your menu: 115 | //print activeMenu[i][0] + " = " + activeMenu[i][1] at (1,startLine + activeMenu:length + 2 + i). 116 | 117 | set i to i + 1. 118 | } 119 | drawMarker(). 120 | } 121 | 122 | local refreshTypes is list("number","display","string","bool"). 123 | function refreshAll { //updates all values of the current menu in the terminal 124 | local i is 0. 125 | until i >= activeMenu:length { 126 | if refreshTypes:contains(activeMenu[i][1]) and not((typingNumber or typingString) and i = selectedLine) { 127 | updateLine(i). 128 | } 129 | set i to i + 1. 130 | } 131 | } 132 | 133 | local markerStr is ">> ". 134 | local suffixString is "". 135 | local markerTimer is time:seconds + 900000. 136 | function drawMarker { 137 | print markerStr at (C1-3,startLine + selectedLine). //print the arrow that displays the active selection 138 | 139 | //print relevant information at the end of the current line 140 | if lineType = "number" { 141 | set suffixString to "-+" + incrOptions[incrI] * activeMenu[selectedLine][3]. 142 | print suffixString at (C3 + 1,startLine + selectedLine). 143 | } 144 | else if lineType = "bool" { 145 | set suffixString to activeMenu[selectedLine][2]():tostring(). 146 | print suffixString at (C3 + 1,startLine + selectedLine). 147 | } 148 | else if lineType = "menu" or lineType = "backmenu" { 149 | set suffixString to "Menu". 150 | print suffixString at (C3 + 1,startLine + selectedLine). 151 | } 152 | } 153 | 154 | local typesWithSuffix is list("number","bool","menu","backmenu"). 155 | function clearMarkers { 156 | print " " at (C1 - markerStr:length,startLine + selectedLine). 157 | 158 | if typesWithSuffix:contains(lineType) { 159 | local emptyString is " ". 160 | print emptyString:substring(0,suffixString:length) at (C3 + 1,startLine + selectedLine). 161 | } 162 | } 163 | // << 164 | 165 | // ### Input and value handling ### 166 | // >> 167 | 168 | local readOnlyTypes is list("text","display","line"). 169 | 170 | function inputs { 171 | if typingNumber { //currently recording numbers, so ignore all other commands 172 | updateLine(selectedLine,numberString). 173 | if terminal:input:haschar() { 174 | local inp is terminal:input. 175 | local ch is inp:getchar(). 176 | if ch:tonumber(99) <> 99 or ch = "." or (numberString:length = 0 and ch = "-") { 177 | set numberString to numberstring + ch. 178 | 179 | } 180 | else if ch = inp:backspace { 181 | if numberString:length > 0 set numberString to numberString:remove(numberString:length-1,1). 182 | } 183 | else if ch = inp:enter or ch = "d" or ch = "w" or ch = "s"{ // confirm 184 | set typingNumber to false. 185 | local converted is numberString:tonumber(-9999). 186 | if converted <> -9999 { //valid 187 | updateLine(selectedLine,numberString). 188 | activeMenu[selectedLine][2](converted). //change the actual variable through the function stored in the lex 189 | } 190 | set numberString to "". 191 | } 192 | else if unchar(ch) = 9 { //tab - cancel and revert 193 | set typingNumber to false. 194 | set numberString to "". 195 | } 196 | } 197 | } 198 | else if typingString { //currently recording text 199 | updateLine(selectedLine,stringString). 200 | if terminal:input:haschar() { 201 | local inp is terminal:input. 202 | local ch is inp:getchar(). 203 | 204 | if ch = inp:enter { // confirm 205 | set typingString to false. 206 | updateLine(selectedLine,stringString). 207 | activeMenu[selectedLine][2](stringString). 208 | set stringString to "". 209 | } 210 | else if ch = inp:backspace { 211 | if stringString:length > 0 set stringString to stringString:remove(stringString:length-1,1). 212 | } 213 | else if unchar(ch) = 9 { //tab - cancel and revert 214 | set typingString to false. 215 | set stringString to "". 216 | updateLine(selectedLine). 217 | } 218 | else set stringString to stringString + ch. 219 | } 220 | } 221 | 222 | else if terminal:input:haschar() { //not recording, so enable all other commands 223 | local inp is terminal:input. 224 | local ch is inp:getchar(). 225 | if unchar(ch) = 9 set ch to inp:backspace. 226 | set lineType to activeMenu[selectedLine][1]. 227 | 228 | local oldLine is selectedLine. 229 | if ch = "w" or ch = inp:upcursorone { 230 | clearMarkers(). 231 | 232 | set selectedLine to selectedLine - 1. 233 | if selectedLine < 0 set selectedLine to activeMenu:length - 1. 234 | //until activeMenu[selectedLine][1] <> "text" and activeMenu[selectedLine][1] <> "line" { //skip text lines as they have no values 235 | until not readOnlyTypes:contains(activeMenu[selectedLine][1]) { 236 | set selectedLine to selectedLine - 1. 237 | if selectedLine < 0 set selectedLine to activeMenu:length - 1. 238 | } 239 | 240 | set incrI to 2. 241 | updateLine(oldLine). 242 | } 243 | else if ch = "s" or ch = inp:downcursorone { 244 | clearMarkers(). 245 | set selectedLine to selectedLine + 1. 246 | if selectedLine >= activeMenu:length set selectedLine to 0. 247 | //until activeMenu[selectedLine][1] <> "text" and activeMenu[selectedLine][1] <> "line" { //skip text lines as they have no values 248 | until not readOnlyTypes:contains(activeMenu[selectedLine][1]) { 249 | set selectedLine to selectedLine + 1. 250 | if selectedLine >= activeMenu:length set selectedLine to 0. 251 | } 252 | 253 | set incrI to 2. 254 | updateLine(oldLine). 255 | } 256 | else if ch = "a" or ch = inp:leftcursorone adjust(-1). 257 | else if ch = "d" or ch = inp:rightcursorone adjust(1). 258 | else if ch = "q" { set incrI to max(0,incrI - 1). } 259 | else if ch = "e" { set incrI to min(incrOptions:length - 1,incrI + 1). } 260 | else if lineType = "number" and (ch:tonumber(99) <> 99 or ch = "-" or ch = inp:enter) { 261 | set typingNumber to true. 262 | if ch = inp:enter set numberString to activeMenu[selectedLine][2]():tostring(). 263 | else set numberString to ch. 264 | } 265 | else if ch = inp:enter { 266 | if lineType = "menu" or lineType = "backmenu" or lineType = "bool" or lineType = "action" adjust(0). 267 | else if lineType = "string" { 268 | set stringString to activeMenu[selectedLine][2](). 269 | set typingString to true. 270 | } 271 | //else if lineType = "action" activeMenu[selectedLine][2](). 272 | } 273 | else if ch = inp:backspace { 274 | local i is 0. 275 | until i >= activeMenu:length { //find the first "backmenu" item if it exists and trigger that 276 | if activeMenu[i][1] = "backmenu" { 277 | clearMarkers(). 278 | set selectedLine to i. 279 | adjust(0). 280 | set i to activeMenu:length. 281 | } 282 | set i to i + 1. 283 | } 284 | } 285 | 286 | set lineType to activeMenu[selectedLine][1]. 287 | clearMarkers(). 288 | drawMarker(). 289 | updateLine(selectedLine). 290 | 291 | inp:clear(). 292 | } 293 | 294 | else if time:seconds > markerTimer + 0.2 { 295 | set markerStr to ">> ". 296 | set markerTimer to time:seconds + 900000. 297 | drawMarker(). 298 | } 299 | 300 | } 301 | 302 | local nonPaddedTypes is list("text","action","menu","backmenu"). 303 | set blink to 0. 304 | function updateLine { 305 | parameter line,val is "x". 306 | local nameStr is activeMenu[line][0]. 307 | local valType is activeMenu[line][1]. 308 | 309 | local finalStr is "". 310 | 311 | if nonPaddedTypes:contains(valType) { 312 | set finalStr to nameStr. 313 | } 314 | else if valType = "line" { 315 | set finalStr to "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx". 316 | local tableWidth is C3-C1. 317 | set finalStr to finalStr:substring(0,tableWidth). 318 | set finalStr to finalStr:replace("x",nameStr). 319 | } 320 | else { 321 | if val = "x" { 322 | set val to activeMenu[line][2](). 323 | //if valType = "number" set val to val:tostring(). 324 | } 325 | 326 | local blinkStr is "". 327 | if (typingNumber or typingString) and line = selectedLine { //blinking cursor when typing in 328 | if blink < 10 set blinkStr to "_". 329 | else set blinkStr to " ". 330 | set blink to blink + 1. 331 | if blink > 20 set blink to 0. 332 | } 333 | 334 | local valStr is "". 335 | 336 | if valType = "bool" { 337 | if val set valStr to "[ X ]". 338 | else set valStr to "[ ]". 339 | } 340 | else if valType = "number" { 341 | //if not typingNumber and val:tonumber(-99.9999) <> -99.9999 and val:tonumber() > 9999 set valStr to round(val:tonumber() / 1000,1) + "K". 342 | 343 | set val to val + blinkStr. 344 | if not typingNumber and abs(val:tonumber()) > 9999 set valStr to round(val:tonumber() / 1000,1) + " K". 345 | else set valStr to val. 346 | } 347 | else if valType = "string" or valType = "display" { 348 | if typingString { 349 | set val to val + blinkStr. 350 | set valStr to val:substring(max(0,val:length - (C3-C2)),min(val:length,C3-C2)). 351 | } 352 | else { 353 | if not val:istype("string") set val to val:tostring(). 354 | set valStr to val:substring(0,min(val:length,C3-C2)). 355 | } 356 | } 357 | set valStr to valStr:padright(C3-C2). 358 | set finalStr to nameStr:padright(C2-C1):substring(0,C2-C1) + valStr. 359 | } 360 | 361 | print finalStr at (C1,startLine + line). 362 | } 363 | 364 | function adjust { 365 | parameter sign. 366 | local func is activeMenu[selectedLine][2]. 367 | set lineType to activeMenu[selectedline][1]. 368 | 369 | set markerStr to "> >". 370 | set markerTimer to time:seconds. 371 | 372 | if lineType = "number" { 373 | func(func() + sign * incrOptions[incrI] * activeMenu[selectedLine][3]). 374 | } 375 | else if lineType = "bool" { 376 | //if sign = -1 func(true). 377 | //else func(false). 378 | func(sign). 379 | 380 | } 381 | else if lineType = "menu" or lineType = "backmenu" { // d 382 | setMenu(func()). 383 | set markerTimer to 0. 384 | } 385 | else if lineType = "action" func(). 386 | 387 | 388 | } 389 | 390 | function setMenu { 391 | parameter menu. 392 | clearMarkers(). 393 | set lastMenu to activeMenu. 394 | set activeMenu to menu. 395 | drawAll(). 396 | set markerTimer to 0. 397 | } 398 | 399 | function boolConvert { 400 | parameter val. 401 | if val = -1 set val to false. 402 | else set val to true. 403 | return val. 404 | } 405 | 406 | // << -------------------------------------------------------------------------------- /Reusable Booster/lib_rocket_utility.ks: -------------------------------------------------------------------------------- 1 | local e is constant():e. 2 | 3 | // Thanks to Dunbaratu for the two following functions! 4 | function burn_duration { 5 | parameter delta_v_mag, m0 is ship:mass. 6 | 7 | local g0 is 9.802. 8 | 9 | // The ISP of first engine found active: 10 | // (For more accuracy with multiple differing engines, 11 | // some kind of weighted average would be needed.) 12 | local ISP is simple_isp(). 13 | 14 | // mass after burn is done 15 | local m1 is m0*e^(-delta_v_mag / (g0*ISP)). 16 | 17 | // From rocket equation, and definition of ISP: 18 | local burn_dur is (g0*ISP*m0/SHIP:AVAILABLETHRUST)*( 1 - e^(-delta_v_mag/(g0*ISP)) ). 19 | 20 | return list(burn_dur,m1). 21 | } 22 | 23 | function simple_isp { 24 | list engines in engs. 25 | local totalFlow is 0. 26 | local totalThrust is 0. 27 | for eng in engs { 28 | if eng:ignition and not eng:flameout { 29 | set totalflow to totalflow + (eng:availablethrust / eng:isp). 30 | set totalthrust to totalthrust + eng:availablethrust. 31 | } 32 | } 33 | return totalthrust / max(0.1, totalflow). 34 | } 35 | 36 | function half_dv_duration { 37 | parameter deltav_mag. 38 | 39 | local first_half is burn_duration(deltav_mag / 2). 40 | local first_half_duration is first_half[0]. 41 | 42 | // the duration of the second half of the burn, with the adjusted starting mass. 43 | local second_half is burn_duration(deltav_mag / 2, first_half[1]). 44 | 45 | 46 | // return list with: first half of deltaV duration, last half of dV duration, mass after full burn. 47 | return list(first_half_duration,second_half[0],second_half[1]). 48 | } -------------------------------------------------------------------------------- /Reusable Booster/refuel_truck.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | 3 | //set targetVessel to ship. 4 | //set targetPort to ship:rootpart. 5 | 6 | function popup { 7 | parameter s. 8 | parameter t is 5. 9 | HUDTEXT(s, t, 2, 40, yellow, false). 10 | 11 | // context: HUDTEXT( Message, delaySeconds, style, size, colour, boolean doEcho). 12 | //style: - 1 = upper left - 2 = upper center - 3 = lower right - 4 = lower center 13 | } 14 | 15 | 16 | 17 | 18 | set mode to 0. 19 | 20 | 21 | 22 | for r in targetVessel:resources { 23 | if r:name = "LIQUIDFUEL" set targetCapacity to r:capacity. 24 | } 25 | for r in ship:resources { 26 | if r:name = "LIQUIDFUEL" set fuelAmount to r:amount. 27 | } 28 | if (targetCapacity + 500) > fuelAmount { 29 | set refilling to true. 30 | set tankVessel to vessel("Fuel Bro"). 31 | set oxidizerport to tankVessel:partstagged("oxidizer")[0]. 32 | set liquidfuelport to tankVessel:partstagged("liquid")[0]. 33 | set targetPort to oxidizerport. 34 | } 35 | else set refilling to false. 36 | 37 | 38 | local port is ship:partstagged("refuel port")[0]. 39 | 40 | // servo parts 41 | local gantryPart is ship:partstagged("side")[0]. 42 | local verticalJointPart is ship:partstagged("up")[0]. 43 | local forward1Part is ship:partstagged("forward")[0]. 44 | local forward2Part is ship:partstagged("forward 2")[0]. 45 | local upJointPart is ship:partstagged("rot up")[0]. 46 | local sideJointPart is ship:partstagged("rot side")[0]. 47 | 48 | // servos 49 | local gantryServo is addons:ir:partservos(gantryPart)[0]. 50 | local verticalJointServo is addons:ir:partservos(verticalJointPart)[0]. 51 | local forward1Servo is addons:ir:partservos(forward1Part)[0]. 52 | local forward2Servo is addons:ir:partservos(forward2Part)[0]. 53 | local upJointServo is addons:ir:partservos(upJointPart)[0]. 54 | local sideJointServo is addons:ir:partservos(sideJointPart)[0]. 55 | 56 | //set gantryServo:acceleration to 4. 57 | 58 | function resetServos { 59 | 60 | for s in addons:ir:allservos { 61 | set s:speed to 1. 62 | s:movecenter(). 63 | } 64 | } 65 | resetServos(). 66 | 67 | set wheelPid to PIDLOOP(0.15, 0.0, 0.02, -1, 1). 68 | set throtPid to PIDLOOP(2, 0.0, 0.8, -1, 1). 69 | 70 | set reverseSteering to false. 71 | 72 | lights on. 73 | set targetDistance to 1. 74 | local frontErr is 999. 75 | set parkingGeoPos to LATLNG(-0.0734059883022779,-74.6206292691976). 76 | set controlPart to ship:partstagged("control")[0]. 77 | 78 | clearvecdraws(). 79 | //local vd_pos is vecdraw(up:vector * 10000,up:vector * -5,yellow,"",1,true,0.5). 80 | 81 | set extcam to addons:camera:flightcamera. 82 | set camOldPos to up:vector * 460 + vxcl(up:vector,-targetPort:position):normalized * 180. 83 | set extcam:position to camOldPos. 84 | set extcam:fov to 65. 85 | wait 0. 86 | set extcam:target to port. 87 | 88 | wait 0. 89 | set extcam:position to camOldPos. 90 | wait 0. 91 | 92 | set upVector to up:vector. 93 | 94 | // ### Loop ### 95 | ag10 off. 96 | local exit is false. 97 | until exit or ag10 { 98 | 99 | 100 | // ### Refueling ### 101 | // >> 102 | if port:state:contains("Docked") { 103 | for s in addons:ir:allservos { 104 | s:stop(). 105 | } 106 | set mode to 3. 107 | controlPart:controlfrom(). 108 | 109 | wait 0.5. 110 | list elements in el. 111 | for e in el { 112 | if e:name:contains("booster") set boosterElement to e. 113 | else if e:name:contains("refuel") set localElement to e. 114 | else if e:name:contains("Fuel Bro") set tankElement to e. 115 | } 116 | 117 | if (targetPort:tag = "oxidizer") { 118 | popup("Pumping Oxidizer.."). 119 | set transfer to transferall("OXIDIZER", tankElement, localElement). 120 | set transfer:active to true. 121 | wait until transfer:status <> "Transferring". 122 | wait 1. 123 | set mode to 2. 124 | targetPort:undock. 125 | port:undock. 126 | wait 0.1. 127 | if not(kuniverse:activevessel = port:ship) { 128 | kuniverse:forceactive(port:ship). 129 | set extcam:target to port. 130 | } 131 | set targetPort to liquidfuelport. 132 | set forward2Servo:speed to 3. 133 | forward2Servo:moveleft(). 134 | wait 0.4. 135 | } 136 | else if (targetPort:tag = "liquid") { 137 | popup("Pumping Liquid Fuel.."). 138 | set transfer to transferall("LIQUIDFUEL", tankElement, localElement). 139 | set transfer:active to true. 140 | wait until transfer:status <> "Transferring". 141 | wait 1. 142 | set mode to 4. 143 | targetPort:undock. 144 | port:undock. 145 | wait 0.1. 146 | if not(kuniverse:activevessel = port:ship) { 147 | kuniverse:forceactive(port:ship). 148 | set extcam:target to port. 149 | } 150 | set forward2Servo:speed to 3. 151 | forward2Servo:moveleft(). 152 | } 153 | else { 154 | popup("Pumping Oxidizer.."). 155 | set transfer to transferall("OXIDIZER", localElement, boosterElement). 156 | set transfer:active to true. 157 | wait until transfer:status <> "Transferring". 158 | //wait 6. 159 | popup("Pumping Liquid Fuel.."). 160 | set transfer to transferall("LIQUIDFUEL", localElement, boosterElement). 161 | set transfer:active to true. 162 | wait until transfer:status <> "Transferring". 163 | //wait 6. 164 | set mode to 4. 165 | targetPort:undock. 166 | port:undock. 167 | wait 0.1. 168 | set extcam:target to targetPort:ship. 169 | set extcam:position to north:vector * 50 + up:vector * 50. 170 | //kuniverse:forceactive(targetPort:ship). 171 | 172 | 173 | popup("Refueling complete"). 174 | wait 1. 175 | } 176 | 177 | 178 | 179 | 180 | 181 | wait 0. 182 | } 183 | 184 | // << 185 | 186 | //### Navigation ### 187 | // >> 188 | // This section is an utter mess. I'm so sorry. 189 | set validTarget to targetPort <> ship:rootpart. 190 | 191 | if validTarget or mode > 3 { 192 | //set wheelPid:kP to ((mass/663)) * 0.5. 193 | 194 | //set wheelPid:kD to (mass/663000) * 0.1. 195 | 196 | if refilling and validTarget { 197 | set targetPosition to (oxidizerport:nodeposition + liquidfuelport:nodeposition)/2. 198 | set targetFacing to oxidizerport:portfacing:vector. 199 | } 200 | else if validTarget = false { //booster vessel not unpacked 201 | set targetPosition to targetVessel:position. 202 | set targetFacing to upVector. 203 | set wpDirection to upVector. 204 | } 205 | else { 206 | set targetPosition to targetPort:nodeposition. 207 | set targetFacing to targetPort:portfacing:vector. 208 | } 209 | 210 | if mode = 0 { 211 | set targetPositionHor to -vxcl(upVector,targetPosition). 212 | set wpDirectionAng to vang(targetPositionHor, vxcl(upVector,targetFacing)). 213 | if vdot(vcrs(targetPositionHor,upVector) , targetFacing) > 0 set wpDirectionAng to -wpDirectionAng. 214 | 215 | set wpDirection to angleaxis(max(-35,min(35,wpDirectionAng)), upVector) * targetPositionHor. 216 | set wpDirection:mag to 60. 217 | 218 | set extcam:position to extcam:position * 0.96 + 0.04 * (-targetPosition:normalized * 15 + upVector * 8). 219 | 220 | if defined wpDistance and wpDistance < 28 { 221 | set mode to 1. 222 | if vdot(facing:starvector,targetPosition) < 0 set camLeft to false. 223 | else set camLeft to true. 224 | wait 0. 225 | } 226 | } 227 | else if mode = 1 { 228 | set wpDirection to vxcl(upVector,targetFacing). 229 | set wpDirection:mag to max(0.1, vxcl(upVector,targetPosition):mag - 10 ). 230 | 231 | set camSideOffset to facing:starvector * min(15,3 + frontErr/2). 232 | if camLeft set camSideOffset to -camSideOffset. 233 | 234 | set extcam:position to extcam:position * 0.98 + 0.02 * (port:position + facing:vector * -(2 + min(10,frontErr/4)) + camSideOffset + upVector * min(10,frontErr/2)) . 235 | 236 | 237 | if forward2Servo:ismoving or abs(frontErr) < 0.5 set mode to 2. 238 | } 239 | else if mode = 4 and vxcl(upVector,targetPosition):mag > 35 { 240 | if refilling { 241 | set mode to 0. 242 | set refilling to false. 243 | set targetPort to targetVessel:partstagged("refueling port")[0]. 244 | set frontErr to 999. 245 | } 246 | 247 | else { 248 | set mode to 5. 249 | popup("Returning to parking spot"). 250 | } 251 | } 252 | 253 | if mode = 5 { 254 | set targetPositionHor to vxcl(upVector,targetPosition). 255 | set parkingPos to vxcl(upVector,parkingGeoPos:position). 256 | if vang(targetPositionHor, parkingPos) > 89 { 257 | set wp to parkingGeoPos. 258 | if parkingPos:mag < 25 set exit to true. //end of program, what a mess. 259 | } 260 | else { 261 | set wpPos to vxcl(targetPositionHor,parkingPos):normalized * 35. 262 | set wp to body:geopositionof(wpPos). 263 | } 264 | 265 | } 266 | else { 267 | set wp to body:geopositionof(targetPosition + wpDirection). 268 | } 269 | 270 | set wpPos to wp:position. 271 | set wpPosHor to vxcl(upVector,wpPos). 272 | set wpDistance to wpPosHor:mag. 273 | 274 | //set vd_pos:start to wpPos + upVector * 5. 275 | 276 | 277 | set wpBearing to vang(vxcl(upVector,facing:vector), wpPosHor). 278 | if vdot(facing:starvector,wpPos) < 0 set wpBearing to -wpBearing. 279 | 280 | 281 | set forwardSpeed to vdot(facing:vector,velocity:surface). 282 | 283 | set wheelPid:kP to 0.4 - min(0.35,max(0,forwardSpeed - 3) / 10 ). //PIDLOOP(0.15, 0.0, 0.03, -1, 1). 284 | 285 | if wpDistance > 0.5 { 286 | set ship:control:wheelsteer to wheelPid:update(time:seconds, wpBearing). 287 | } 288 | else set ship:control:wheelsteer to 0. 289 | 290 | 291 | 292 | 293 | if forwardSpeed < 0 set ship:control:wheelsteer to -ship:control:wheelsteer. 294 | 295 | //if abs(wpBearing) > 5 set targetSpeed to 0. 296 | //else 297 | set targetSpeed to min(25 , (wpDistance^0.87) / 2.5). 298 | if mode = 1 { 299 | if reverseSteering and abs(wpBearing > 10) { set targetSpeed to -2. set ship:control:wheelsteer to ship:control:wheelsteer * 2. } 300 | else if abs(wpBearing) > 30 { 301 | set targetSpeed to -5. 302 | set reverseSteering to true. 303 | } 304 | else { 305 | set targetSpeed to min(4, vxcl(facing:starvector,targetPosition - port:nodeposition):mag / 4 ). 306 | set reverseSteering to false. 307 | } 308 | } 309 | else if mode = 4 { 310 | set targetSpeed to -10. 311 | set ship:control:wheelsteer to 0. 312 | } 313 | 314 | 315 | if mode = 2 or mode = 3 { 316 | set ship:control:wheelsteer to 0. 317 | set ship:control:wheelthrottle to 0. 318 | } 319 | else set ship:control:wheelthrottle to throtPid:Update(time:seconds, forwardSpeed - targetSpeed). 320 | 321 | if mode = 2 { 322 | brakes on. 323 | //set extcam:position to extcam:position * 0.985 + 0.015 * (port:position + port:facing:vector * -5 + upVector * (1 + vdot(upVector,gantryPart:position - port:position))). 324 | if camLeft set extcam:position to extcam:position * 0.98 + 0.02 * (vxcl(facing:starvector,core:part:position) + facing:starvector * (-1.5 + vdot(facing:starvector, port:position)) + upVector * 2). 325 | else set extcam:position to extcam:position * 0.98 + 0.02 * (vxcl(facing:starvector,core:part:position) + facing:starvector * (1.5 + vdot(facing:starvector, port:position)) + upVector * 2). 326 | 327 | } 328 | else if mode = 4 or targetSpeed < 0 brakes off. 329 | else if abs(forwardSpeed - targetSpeed) < 0.4 brakes off. 330 | else if (forwardSpeed - targetSpeed) > 0.1 brakes on. 331 | else brakes off. 332 | 333 | if targetSpeed > forwardSpeed and forwardSpeed < -0.1 brakes on. 334 | 335 | //print round(wheelPid:kP,3) + " kP " at (0, 20). 336 | //print round(ship:control:wheelsteer,2) + " wheelsteer" at (0, 21). 337 | 338 | //print "wp bearing: " + round(wpBearing,1) + " " at (0,5). 339 | //print "wp dist: " + round(wpDistance,1) + " " at (0,6). 340 | //print "targetSpeed: " + round(targetSpeed,1) + " " at (0,7). 341 | } 342 | // << 343 | 344 | //### Docking arm ### 345 | // >> 346 | 347 | if mode = 3 {} 348 | else if mode = 4 { forward2Servo:moveleft(). forward1Servo:moveleft(). } 349 | else if targetPort = ship:rootpart resetServos(). 350 | else if (targetPort:position - port:position):mag > 20 resetServos(). 351 | else { 352 | set portPosition to port:nodeposition. 353 | set portFacing to port:portfacing. 354 | set portVec to portFacing:vector. 355 | set portTopVec to portFacing:topvector. 356 | set portStarVec to portFacing:starvector. 357 | 358 | 359 | 360 | 361 | 362 | 363 | // ### dockingport angling ### 364 | set portAimVec to -targetFacing. 365 | 366 | //vertical 367 | set upAngErr to vang( vxcl(portStarVec,portVec), vxcl(portStarVec,portAimVec) ). 368 | set upJointServo:speed to min(5,upAngErr * 0.1). 369 | if vdot(portTopVec, portAimVec) > 0 set upAngErr to -upAngErr. 370 | 371 | if upAngErr < 0 upJointServo:moveright(). 372 | else if upAngErr > 0 upJointServo:moveleft(). 373 | else upJointServo:stop(). 374 | //print "up angle err: " + round(abs(upAngErr),2) + " " at (0,10). 375 | 376 | //horizontal 377 | set sideAngErr to vang( vxcl(portTopVec,portVec), vxcl(portTopVec,portAimVec) ). 378 | set sideJointServo:speed to min(5,sideAngErr * 0.1). 379 | if vdot(portStarVec, portAimVec) > 0 set sideAngErr to -sideAngErr. 380 | 381 | if sideAngErr < 0 sideJointServo:moveright(). 382 | else if sideAngErr > 0 sideJointServo:moveleft(). 383 | else sideJointServo:stop(). 384 | //print "side angle err: " + round(abs(sideAngErr),2) + " " at (0,11). 385 | 386 | 387 | // ### Translation ### 388 | 389 | set errVec to targetPort:nodeposition - portPosition. 390 | 391 | set frontErr to vdot(portVec,errVec). 392 | set upErr to vdot(portTopVec,errVec). 393 | set sideErr to vdot(portStarVec,errVec). 394 | 395 | 396 | 397 | //side 398 | set gantryServo:speed to min(2,abs(sideErr) * 3). 399 | if sideErr < -0.004 gantryServo:moveleft(). 400 | else if sideErr > 0.004 gantryServo:moveright(). 401 | else gantryServo:stop(). 402 | 403 | //up 404 | set verticalJointServo:speed to min(0.5,abs(upErr) * 0.1). 405 | if forward1Servo:ismoving and upErr > 0 verticalJointServo:stop(). 406 | else if upErr > 0.003 verticalJointServo:moveleft(). 407 | else if upErr < -0.012 verticalJointServo:moveright(). 408 | else verticalJointServo:stop(). 409 | 410 | //if abs(verticalJointServo:position) > 45 { 411 | set forward1Servo:speed to abs(upErr) * 10. 412 | if upErr < -0.015 or verticalJointServo:position > -15 forward1Servo:moveleft(). 413 | else if upErr > 0.005 forward1Servo:moveright(). 414 | else forward1Servo:stop(). 415 | 416 | //} 417 | //else forward1Servo:stop(). 418 | 419 | //forward 2 (the little extendatron on the tip): 420 | if (mode = 1 or mode = 2) and abs(upErr) < 0.1 and abs(sideErr) < 0.1 and abs(sideAngErr) < 2 and abs(upAngErr) < 2 and (frontErr < 0.8 or mode = 2) { 421 | forward2Servo:moveright(). 422 | set forward2Servo:speed to min(5,0.2 + frontErr * 6). 423 | } 424 | else { 425 | forward2Servo:moveleft(). 426 | set forward2Servo:speed to min(5,1 + frontErr * 8). 427 | } 428 | //print "front error: " + round(frontErr,2) + " " at (0,13). 429 | //print "up error: " + round(upErr,2) + " " at (0,14). 430 | //print "side error: " + round(sideErr,2) + " " at (0,15). 431 | } 432 | // << end of arm 433 | 434 | //print "mode: " + mode at (0,18). 435 | 436 | wait 0.03. 437 | } 438 | 439 | clearvecdraws(). 440 | lights off. 441 | brakes on. 442 | SET SHIP:CONTROL:NEUTRALIZE to TRUE. 443 | wait until groundspeed < 0.1. 444 | 445 | if mode = 5 or ag10 { 446 | targetPort:ship:connection:sendmessage("bruh"). 447 | ag10 off. 448 | } 449 | 450 | print "Program ended". 451 | reboot. -------------------------------------------------------------------------------- /boostback.ks: -------------------------------------------------------------------------------- 1 | parameter runmode is 0, payload is ship. 2 | set entryTime to time:seconds - 1. 3 | 4 | 5 | clearvecdraws(). 6 | loaddist(100000). //flying and suborbital 7 | 8 | wait until ship:unpacked. 9 | for ms in core:part:modules { //for some reason terminal sometimes closes on dock 10 | set m to core:part:getmodule(ms). 11 | if m:hasaction("Open Terminal") m:doevent("Open Terminal"). 12 | } 13 | 14 | print "Boostback script running.". 15 | 16 | //local gloc is LATLNG(-0.0972098829757138, -74.557676687929). //Launchpad 17 | //local gloc is LATLNG(-1.52807550218625,-71.8857609633566). //island runway 18 | //local gloc is LATLNG(6.84003072705819, -62.3143155921253). //island (north) resort 19 | 20 | //east continent: 21 | //local gloc is LATLNG(-3.69868452018539,-40.2857948658593). //lz2 22 | local gloc is LATLNG(-3.56930348556625,-40.2248383004123). //lz2 mnt 23 | //local gloc is LATLNG(1.04954086727854,-42.7077262412699). //LZ-3 24 | 25 | //west: 26 | //local gloc is LATLNG(20.6225723742333, -146.431600245751). //ksc2 pad 27 | //local gloc is LATLNG(22.727435661152, -120.969904966499). //lake dermal 28 | //local gloc is LATLNG(10.6432864032526,-132.030819020903). //KKVLA 29 | 30 | set overshoot to 300. 31 | set targetApo to 100000. 32 | set overshoot2 to overshoot. 33 | set reEntryBurn to false. 34 | local lng_diff is abs(70 + gloc:lng). 35 | if lng_diff > 15 { 36 | set targetApo to 130000. 37 | set overshoot2 to lng_diff * 1000. 38 | set reEntryBurn to true. 39 | } 40 | 41 | sas off. 42 | rcs on. 43 | 44 | local th is 0. 45 | lock throttle to th. 46 | 47 | kuniverse:forceactive(ship). 48 | wait 0. 49 | if payload <> ship set target to payload. 50 | 51 | wait until addons:tr:hasimpact. 52 | local st is up:vector. 53 | //local st is heading(gloc:heading,0):vector. 54 | lock steering to lookdirup(st,ship:facing:topvector). 55 | 56 | 57 | 58 | set steeringmanager:pitchtorqueadjust to 0. 59 | set steeringmanager:yawtorqueadjust to 0. 60 | 61 | set steeringmanager:pitchts to 2. 62 | set steeringmanager:yawts to 2. 63 | 64 | set STEERINGMANAGER:PITCHPID:KP to 1.1. 65 | set STEERINGMANAGER:yawPID:KP to 1.1. 66 | 67 | if runmode = 0 { 68 | wait 0. 69 | 70 | set steeringmanager:maxstoppingtime to 6. 71 | 72 | list engines in engs. 73 | for eng in engs { 74 | //set eng:gimbal:limit to 0. 75 | eng:shutdown(). 76 | } 77 | 78 | set st to vxcl(up:vector, gloc:position - addons:tr:impactpos:position):normalized + up:vector * ((targetApo - apoapsis)/ 15000). 79 | wait until vang(steering:vector,facing:vector) < 90. 80 | 81 | //set steeringmanager:pitchtorqueadjust to 0. 82 | //set steeringmanager:yawtorqueadjust to 0. 83 | 84 | 85 | for eng in engs { 86 | //set eng:gimbal:limit to 100. 87 | eng:activate(). 88 | } 89 | //set th to 1. 90 | } 91 | 92 | when altitude < body:atm:height and verticalspeed < 0 then { 93 | wait 3. 94 | for m in ship:modulesnamed("ModuleAnimateGeneric") { 95 | if m:hasevent("deploy fins") m:doevent("deploy fins"). 96 | } 97 | brakes on. 98 | return false. 99 | } 100 | 101 | set steeringmanager:maxstoppingtime to 4. 102 | addons:tr:settarget(gloc). 103 | 104 | set oldT to time:seconds - 0.02. 105 | set oldV to verticalspeed. 106 | 107 | local height_offset is estimate_height() + 5. 108 | local th_pid is pidloop(0.3,0.1,0.001,-1,1). 109 | 110 | set vd_hit to vecdraw(gloc:position,up:vector * 500, red, "", 1, true, 30). 111 | set vd_tar to vecdraw(gloc:position,up:vector * 500, green, "", 1, true, 30). 112 | set vd_error to vecdraw(v(0,0,0),v(0,0,0), yellow, "", 1, true, 0.5). 113 | 114 | set burn_pitch to 30. 115 | when altitude < 15000 and runmode = 1 then { 116 | set burn_pitch to vang(up:vector,-velocity:surface). 117 | print "pitch at burn start: " + round(burn_pitch,2) at (0,17). 118 | return false. 119 | } 120 | 121 | local geo_diff is v(0,0,0). 122 | local done is false. 123 | until done { 124 | if ship:status = "landed" break. 125 | print "dyn press: " + round(ship:q,5) + " " at (0,9). 126 | 127 | if runmode = 0 { //boost back 128 | 129 | if addons:tr:hasimpact { 130 | local offset is vxcl(gloc:position-body:position,gloc:position). 131 | set offset:mag to overshoot2. 132 | local st_vec is vxcl(up:vector, offset + gloc:position - addons:tr:impactpos:position). 133 | set st to st_vec:normalized + up:vector * ((targetApo - apoapsis)/ 15000). 134 | 135 | if st_vec:mag < 50000 set warp to 0. 136 | 137 | local steer_error is vang(facing:vector,st) - 5. 138 | if steer_error < 25 set th to min(1,st_vec:mag / 15000). 139 | else set th to 0. 140 | set th to min(th,(25 - steer_error) / 25). 141 | 142 | print "dist " + round(st_vec:mag) + " " at (0,10). 143 | if st_vec:mag < 200 { 144 | set runmode to 1. 145 | //if payload <> ship kuniverse:forceactive(payload). //switch to payload so it can circularize 146 | set th to 0. 147 | set st to facing:vector. 148 | wait until kuniverse:activevessel = ship. 149 | } 150 | } 151 | else { 152 | set st to vxcl(up:vector,-velocity:orbit). 153 | set th to 1. 154 | } 155 | 156 | } 157 | else if runmode = 1 { 158 | set th to 0. 159 | if alt:radar < 1200 gear on. 160 | if altitude < 15000 rcs off. 161 | 162 | set offset to vxcl(gloc:position-body:position,gloc:position). 163 | //set offset:mag to burn_pitch * 4 * min(1,max(0,velocity:surface:mag - 300)/300). 164 | set offset:mag to min(overshoot,vxcl(up:vector,gloc:position):mag / ((90 - vang(up:vector, -velocity:surface)) * 0.3) ). // /12 165 | local target_pos is gloc:position + offset. 166 | set target_gloc to body:geopositionof(target_pos). 167 | 168 | set vd_hit:start to addons:tr:impactpos:position. 169 | set vd_tar:start to target_gloc:position. 170 | set vd_hit:vec to up:vector * (500 + altitude / 3). 171 | set vd_tar:vec to up:vector * (500 + altitude / 3). 172 | 173 | 174 | 175 | 176 | 177 | if kuniverse:activevessel = ship { 178 | addons:tr:settarget(target_gloc). 179 | set posError to target_gloc:position - addons:tr:impactpos:position. 180 | set geo_diff to geo_diff * 0.8 + 0.2 * vxcl(target_gloc:position - body:position, posError). 181 | print "dist " + round(geo_diff:mag) + " " at (0,10). 182 | } 183 | 184 | set vd_error:vec to geo_diff. 185 | 186 | if vang(up:vector,facing:vector) < 80 and altitude < 20000 { 187 | local max_acc is ship:availablethrust / ship:mass. 188 | local gravityMag is body:mu / (body:radius + altitude)^2. 189 | //local gravityVec is -up:vector * gravityMag. 190 | 191 | if throttle = 0 { 192 | local dt is time:seconds - oldT. 193 | set oldT to time:seconds. 194 | set accel to (verticalspeed-oldV)/dt. 195 | set oldV to verticalspeed. 196 | 197 | set accel to max(0,accel - gravityMag). 198 | 199 | print "drag acc: " + round(accel,2) + " m/s2 " at (0,20). 200 | 201 | } 202 | else set accel to 0. 203 | 204 | local max_v_acc is max(0.6,vdot(up:vector,facing:vector)) * max_acc - gravityMag. // + accel. 205 | 206 | //set vdist_offset to min(100,max(0,vxcl(up:vector,gloc:position):mag - 15) * 0.3). 207 | set vdist_offset to min(100,max(0,vxcl(up:vector,velocity:surface):mag - 2) * 0.5). //min(100,max(0,vxcl(up:vector,velocity:surface):mag - 6) * 0.5). 208 | //set vdist_offset to 0. 209 | 210 | set vdist to altitude - max(0,max(0,gloc:terrainheight)) - 23.2 - vdist_offset. //height_offset. 211 | set desiredVV to -sqrt( 2 * max(0.01,vdist + verticalspeed * 0.02) * max_v_acc ). 212 | 213 | print "vertical dist: " + round(vdist/1000,1) + " km " at (0,11). 214 | print "desired v speed: " + round(desiredVV) + " m/s " at (0,14). 215 | print "speed error: " + round(verticalspeed - desiredVV,1) + " m/s " at (0,16). 216 | 217 | print "height offset: " + round(height_offset,1) at (0,18). 218 | 219 | 220 | if vdist > 3000 set th to 0. 221 | else { 222 | set th_pid:setpoint to min(-8,desiredVV). 223 | set th to 0 + th_pid:update(time:seconds,verticalspeed). 224 | } 225 | 226 | if verticalspeed > -2 and altitude < 10000 set th to 0. 227 | } 228 | 229 | // ### Steering / gliding ### 230 | if (altitude > body:atm:height and verticalspeed > 0) or (verticalspeed > 0 and altitude > 10000) { 231 | if entryTime < time:seconds set entryTime to entryETA(). 232 | set st to -velocityat(ship,entryTime):surface. 233 | print "re-entry ETA: " + round(entryTime - time:seconds) + "s " at (0,11). 234 | if vang(st,facing:vector) < 6 and altitude > body:atm:height + 100 { 235 | set kuniverse:timewarp:mode to "rails". 236 | wait 0. 237 | if reEntryBurn { //warp to and do re-entry burn to steepen/slow trajectory 238 | kuniverse:timewarp:warpto(entryTime - 25). 239 | wait until time:seconds > entryTime - 20. 240 | } 241 | else { //just warp to re-entry, no burn needed 242 | kuniverse:timewarp:warpto(entryTime - 5). 243 | wait until altitude < body:atm:height. 244 | } 245 | } 246 | } 247 | else if altitude > 50000 and vdot(vxcl(up:vector,velocity:surface):normalized,geo_diff) < -300 { 248 | set st to vxcl(up:vector,geo_diff). 249 | set th to (10 - vang(st, facing:vector)) / 8. 250 | set th to min(th, geo_diff:mag / 3000). 251 | } 252 | else if th > 0.2 { 253 | 254 | //if velocity:surface:mag > 550 set st to -velocity:surface. 255 | if verticalspeed >= 0 set st to up:vector. //just some sanity check in case we are going upwards, which we shouldn't 256 | else if vdist + vdist_offset < 150 { 257 | set st to -velocity:surface + vxcl(up:vector,-velocity:surface) * min(2,(vdist + vdist_offset - 200)/300). 258 | } 259 | else { 260 | set geo_diff to vxcl(up:vector, (gloc:position + offset * 0.7) - addons:tr:impactpos:position). 261 | local ang is 0. 262 | 263 | local strength is min(50,abs(300 - velocity:surface:mag))/ 50. 264 | if velocity:surface:mag > 300 * th { 265 | set strength2 to 1 / max(1,velocity:surface:mag/400). 266 | set ang to -min(15,geo_diff:mag / 3) * strength * strength2. 267 | 268 | } 269 | else { 270 | set geo_diff to geo_diff + 2 * vxcl(up:vector,vxcl(velocity:surface,posError)). //increase sideways correction in final burn 271 | set ang to min(15,geo_diff:mag / 3) * strength. 272 | } 273 | 274 | local axis is vcrs(-velocity:surface,geo_diff). 275 | set st to -velocity:surface * angleaxis(ang,axis). 276 | } 277 | 278 | 279 | } 280 | else { //use body lift to decrease hit pos error 281 | local ang is min(15,(geo_diff:mag/(1 + ship:q * 1 + vang(up:vector,-velocity:surface) / 15)) / 3). 282 | //if altitude > 20000 set ang to min(15,ang * altitude/15000). 283 | local axis is vcrs(-velocity:surface,geo_diff). 284 | set st to -velocity:surface * angleaxis(-ang,axis). 285 | } 286 | } 287 | 288 | wait 0. 289 | } 290 | 291 | for m in ship:modulesnamed("ModuleAnimateGeneric") { 292 | if m:hasevent("retract fins") m:doevent("retract fins"). 293 | } 294 | 295 | unlock throttle. 296 | unlock steering. 297 | set ship:control:pilotmainthrottle to 0. 298 | sas on. 299 | rcs off. 300 | 301 | function estimate_height { 302 | local highest is 0. 303 | for p in ship:parts { 304 | local part_h is vdot(-facing:vector,p:position). 305 | set highest to max(part_h,highest). 306 | } 307 | return highest. 308 | } 309 | 310 | function entryETA { 311 | print "ETA check.". 312 | local timecheck is 0. 313 | if verticalspeed > 0 set timecheck to time:seconds + ETA:apoapsis. 314 | else set timecheck to time:seconds. 315 | local checkAlt is apoapsis. 316 | 317 | until checkAlt <= body:atm:height { 318 | set timecheck to timecheck + 10. 319 | set checkPos to positionat(ship,timecheck). 320 | set checkAlt to body:altitudeof(checkPos). 321 | } 322 | 323 | return timecheck. 324 | } 325 | 326 | function loaddist { 327 | parameter dist. 328 | // Note the order is important. set UNLOAD BEFORE LOAD, 329 | // and PACK before UNPACK. Otherwise the protections in 330 | // place to prevent invalid values will deny your attempt 331 | // to change some of the values: 332 | SET KUNIVERSE:DEFAULTLOADDISTANCE:FLYING:UNLOAD TO dist. 333 | SET KUNIVERSE:DEFAULTLOADDISTANCE:FLYING:LOAD TO dist-500. 334 | WAIT 0. 335 | SET KUNIVERSE:DEFAULTLOADDISTANCE:FLYING:PACK TO dist - 1. 336 | SET KUNIVERSE:DEFAULTLOADDISTANCE:FLYING:UNPACK TO dist - 1000. 337 | WAIT 0. 338 | 339 | SET KUNIVERSE:DEFAULTLOADDISTANCE:SUBORBITAL:UNLOAD TO dist. 340 | SET KUNIVERSE:DEFAULTLOADDISTANCE:SUBORBITAL:LOAD TO dist-500. 341 | WAIT 0. 342 | SET KUNIVERSE:DEFAULTLOADDISTANCE:SUBORBITAL:PACK TO dist - 1. 343 | SET KUNIVERSE:DEFAULTLOADDISTANCE:SUBORBITAL:UNPACK TO dist - 1000. 344 | WAIT 0. 345 | } -------------------------------------------------------------------------------- /boot/boostback_boot.ks: -------------------------------------------------------------------------------- 1 | // boostback_boot.ks 2 | clearscreen. 3 | wait 1. 4 | print "boostback boot program running, waiting for message to start.". 5 | local done is false. 6 | 7 | if altitude > 40000 and ship:messages:empty runpath("0:/boostback.ks", 0). 8 | 9 | until done { 10 | if not ship:messages:empty { 11 | local msg is ship:messages:pop. 12 | if msg:content = "boostback" { 13 | switch to 0. 14 | runpath("0:/boostback.ks", 0, msg:sender). 15 | set done to true. 16 | } 17 | else if msg:content = "good luck" { 18 | switch to 0. 19 | runpath("0:/boostback.ks", 1, msg:sender). 20 | set done to true. 21 | } 22 | } 23 | wait 0. 24 | } -------------------------------------------------------------------------------- /boot/boot_drone.ks: -------------------------------------------------------------------------------- 1 | //drone boot 2 | ag1 off. ag2 off. ag3 off. 3 | switch to 0. 4 | set terminal:brightness to 1. 5 | set terminal:width to 30. 6 | set terminal:height to 20. 7 | clearscreen. 8 | print "In standby". 9 | print "-------------------------". 10 | print "[AG 1] START". 11 | print "[AG 2] Force compile all". 12 | print "[AG 3] Exit boot program". 13 | print "-------------------------". 14 | print " ". 15 | 16 | wait until ship:unpacked. 17 | 18 | runoncepath("cpu_light.ks"). 19 | 20 | local ascending is false. 21 | local strength is 1.1. 22 | local strengthIncr is 0.05. 23 | until ag1 or ag3 { 24 | if ag2 { 25 | ag2 off. 26 | runpath("cq.ks",0). 27 | } 28 | 29 | if ascending set strength to strength + strengthIncr. 30 | else set strength to strength - strengthIncr. 31 | if strength <= 0.3 or strength >= 1.1 toggle ascending. 32 | setLights(0,0.45 * strength,1 * strength). 33 | 34 | wait 0.08. 35 | } 36 | ag3 off. 37 | if ag1 { 38 | ag1 off. 39 | core:doevent("open terminal"). 40 | run q. 41 | } 42 | 43 | print "Program ended". -------------------------------------------------------------------------------- /boot/boot_plane.ks: -------------------------------------------------------------------------------- 1 | clearscreen. 2 | print "Propeller manager script is running...". 3 | print "[AG 1] Undock propeller". 4 | print "[AG 5] Toggle mode". 5 | print "[H/N] Adjust authority". 6 | print "[I / K] Adjust target angular velocity". 7 | print "--------------------------------------". 8 | wait until ship:unpacked. 9 | core:doevent("open terminal"). 10 | set terminal:brightness to 1. 11 | wait until ag1. 12 | print "Propeller vessel undocked.". 13 | 14 | wait 0.5. 15 | list targets in allVessels. 16 | 17 | set propellerVessel to ship. //dummy 18 | for ves in allVessels { 19 | if ves:position:mag < 100 { 20 | for p in ves:parts { 21 | if p:tag = "propeller" { 22 | set propellerVessel to ves. 23 | } 24 | } 25 | } 26 | } 27 | if propellerVessel = ship print "Failed to find the propeller vessel, make sure you set the nametag [propeller] on one part.". 28 | else { 29 | set con to propellerVessel:connection. 30 | local msg is list("I am your father",ship). 31 | con:sendmessage(msg). 32 | set mode to "automatic". 33 | set targetRads to 47. 34 | local msg is list("set targetRads", targetRads). 35 | con:sendmessage(msg). 36 | set authority to 0. 37 | 38 | set y to 10. 39 | 40 | ag10 off. 41 | until ag10 { 42 | until ship:messages:empty { 43 | local packet is ship:messages:pop. 44 | local msg is packet:content. 45 | if msg[0] = "authority update" set authority to msg[1]. 46 | } 47 | 48 | 49 | if ship:control:pilotfore <> 0 { // H or N key is being pressed 50 | //set authority to min(150,max(-150,authority - ship:control:pilotfore)). 51 | local msg is list("adjust authority", ship:control:pilotfore * 0.5). 52 | con:sendmessage(msg). 53 | } 54 | if ship:control:pilottop <> 0 { // I or K key is being pressed 55 | set targetRads to max(0,min(120,targetRads - ship:control:pilottop * 0.02)). 56 | //local msg is list("set targetRads", targetRads). 57 | con:sendmessage(list("set targetRads", targetRads)). 58 | } 59 | 60 | if ag5 { 61 | ag5 off. 62 | if mode = "automatic" set mode to "manual". 63 | else set mode to "automatic". 64 | local msg is list("set mode", mode). 65 | con:sendmessage(msg). 66 | } 67 | 68 | // ### Terminal ### 69 | 70 | print "Mode: " + mode at (0,y + 0). 71 | print "Target rotation: " + round(targetRads,2) + " rads/s " at (0,y + 2). 72 | print "Propeller rotation: " + round(propellerVessel:angularvel:mag,2) + " rads/s " at (0,y + 4). 73 | print "Authority limiter: " + round(authority,1) + " " at (0,y + 6). 74 | wait 0. 75 | } 76 | } 77 | 78 | print "Program ended.". -------------------------------------------------------------------------------- /boot/boot_propeller.ks: -------------------------------------------------------------------------------- 1 | function dockSearch { 2 | parameter checkPart,originPart. //checkPart is the current part the function is working on, originPart is the part that called it (a child or parent). 3 | set result to core:part. 4 | 5 | for dockpart in core:element:dockingports { 6 | if checkPart = dockpart { set result to checkPart. } //found a match! 7 | } 8 | 9 | if result = core:part { //while this is true, a match hasn't been found yet 10 | if checkPart:hasparent { 11 | if not(checkPart:parent = originPart) { 12 | set tempResult to dockSearch(checkPart:parent,checkPart). 13 | if not(tempResult = core:part) set result to tempResult. //parent returned a match. 14 | } 15 | } 16 | if checkPart:children:length > 0 and result = core:part { 17 | for child in checkPart:children { 18 | if not(child = originPart) and result = core:part { 19 | set tempResult to dockSearch(child,checkPart). 20 | if not(tempResult = core:part) set result to tempResult. //child returned a match. 21 | } 22 | } 23 | } 24 | } 25 | return result. //return the result to the caller (part or initial call from script) 26 | } 27 | 28 | function setAuthority { 29 | parameter val. 30 | for m in modulesList { 31 | m:setfield("authority limiter",val). 32 | } 33 | } 34 | 35 | clearscreen. 36 | //core:doevent("open terminal"). 37 | set terminal:brightness to 1. 38 | print "Propeller script active.". 39 | wait until ship:unpacked. 40 | 41 | set localPort to dockSearch(core:part:parent,core:part). 42 | 43 | if localPort:state = "Docked (docker)" or localPort:state = "Docked (dockee)" or localPort:state = "PreAttached" { 44 | wait until ag1. //remove this line if you just want it to undock without having to use actiongroup 1. 45 | print "Undocking propeller element.". 46 | for ms in localPort:modules { 47 | local m is localPort:getmodule(ms). 48 | if m:hasevent("Decouple Node") { 49 | m:doevent("Decouple Node"). 50 | } 51 | else if m:hasevent("Undock") m:doevent("Undock"). 52 | wait 0. 53 | } 54 | wait 0. 55 | set ship:name to "Propeller". 56 | } 57 | 58 | //the propeller vessel is now undocked from the main vessel 59 | 60 | set authority to 0. 61 | set modulesList to ship:modulesnamed("ModuleControlSurface"). 62 | if modulesList:length > 0 { 63 | set hasControlSurfaces to true. 64 | set authority to modulesList[0]:getfield("authority limiter"). 65 | print "initial authority limiters are set to " + authority. 66 | } 67 | print "Amount of adjustable blades found (control surfaces): " + modulesList:length. 68 | 69 | set notAnOrphan to false. 70 | set targetRads to 47. //just in case, will probably be instantly overwritten by incomming message 71 | set pid to pidloop(0, 15, 0, -150, 150). 72 | set mode to "automatic". 73 | 74 | ag10 off. 75 | until ag10 { 76 | // ### Handle incomming messages ### 77 | 78 | until ship:messages:empty { 79 | local packet is ship:messages:pop. 80 | local msg is packet:content. 81 | if msg[0] = "set mode" set mode to msg[1]. 82 | else if msg[0] = "set targetRads" set targetRads to max(0,min(120,msg[1])). 83 | else if msg[0] = "adjust authority" set authority to max(-150,min(150,authority + msg[1])). 84 | else if msg[0] = "I am your father" { set parentVessel to packet:sender. set notAnOrphan to true. } 85 | } 86 | 87 | local angVel is ship:angularvel:mag. 88 | 89 | if mode = "automatic" { 90 | set pid:setpoint to targetRads. 91 | set authority to -pid:update(time:seconds, angVel). 92 | } 93 | 94 | 95 | setAuthority(authority). 96 | 97 | if notAnOrphan { local msg is list("authority update",authority). parentVessel:connection:sendmessage(msg). } 98 | wait 0. 99 | } 100 | 101 | print "Program ended.". -------------------------------------------------------------------------------- /boot/boot_qShip.ks: -------------------------------------------------------------------------------- 1 | switch to 0. 2 | 3 | //runoncepath("cpu_light.ks"). 4 | runpath("drone_ship.ks"). -------------------------------------------------------------------------------- /boot/station.ks: -------------------------------------------------------------------------------- 1 | // ### station.ks ### 2 | 3 | clearscreen. 4 | print "Station attitude and sanity control.". 5 | wait until ship:loaded and ship:unpacked. 6 | print "". 7 | print "Running.". 8 | local controlpart is ship:partstagged("control")[0]. 9 | controlpart:controlfrom(). 10 | lock throttle to 0. 11 | lock steering to st. 12 | 13 | 14 | until false { 15 | set aimVec to -body:angularvel. 16 | set topVec to vcrs(sun:position,aimVec). //sun 17 | set st to lookdirup(aimVec, topVec). 18 | 19 | wait 0. 20 | } -------------------------------------------------------------------------------- /boot_drone.ks: -------------------------------------------------------------------------------- 1 | //drone boot 2 | ag1 off. ag2 off. ag3 off. 3 | switch to 0. 4 | set terminal:brightness to 1. 5 | //set terminal:charwidth to 12. 6 | //set terminal:charheight to 12. 7 | clearscreen. 8 | print "In standby". 9 | print "-------------------------". 10 | print "[AG 1] START". 11 | print "[AG 2] Force compile all". 12 | print "[AG 3] Exit boot program". 13 | print "-------------------------". 14 | print " ". 15 | 16 | wait until ship:unpacked. 17 | 18 | runoncepath("cpu_light.ks"). 19 | 20 | local ascending is false. 21 | local strength is 1.1. 22 | local strengthIncr is 0.05. 23 | until ag1 or ag3 { 24 | if ag2 { 25 | ag2 off. 26 | runpath("cq.ks",0). 27 | } 28 | 29 | if ascending set strength to strength + strengthIncr. 30 | else set strength to strength - strengthIncr. 31 | if strength <= 0.3 or strength >= 1.1 toggle ascending. 32 | setLights(0,0.45 * strength,1 * strength). 33 | 34 | wait 0.08. 35 | } 36 | ag3 off. 37 | if ag1 { 38 | ag1 off. 39 | core:doevent("open terminal"). 40 | run q. 41 | } 42 | 43 | print "Program ended". -------------------------------------------------------------------------------- /cam.ks: -------------------------------------------------------------------------------- 1 | // ### Functions ### 2 | // >> 3 | function vecToHdg { 4 | parameter v. 5 | set v to vxcl(up:vector,v). 6 | 7 | local ang is vang(north:vector,v). 8 | if vdot(heading(90,0):vector,v) < 0 set ang to -ang. 9 | 10 | return ang. 11 | //return ang * constant():pi / 180. //return in radians 12 | } 13 | 14 | function vecToPitch { 15 | parameter v. 16 | 17 | local ang is vang(-up:vector,v) - 90. 18 | 19 | return -ang. 20 | //return ang * constant():pi / 180. 21 | } 22 | 23 | // << 24 | 25 | global hasCamAddon is addons:available("camera"). 26 | 27 | if hasCamAddon { 28 | global extcam is addons:camera:flightcamera. 29 | //set extcam:camerafov to 70. 30 | 31 | local ev is v(0,0,0). 32 | global camAvgList is list(). 33 | global camAvgFrames is 30. 34 | global camAvgI is 0. 35 | for i in range(camAvgFrames) camAvgList:add(ev). 36 | 37 | } -------------------------------------------------------------------------------- /circ.ks: -------------------------------------------------------------------------------- 1 | //circularization script, starts immediately when called. 2 | parameter method is "engines". 3 | 4 | sas off. 5 | set th to 0. 6 | lock throttle to th. 7 | set dV to ship:facing:vector:normalized. 8 | if method = "rcs" { 9 | lock steering to "kill". 10 | set old_rcs to rcs. 11 | rcs on. 12 | } 13 | else lock steering to lookdirup(dV, ship:facing:topvector). 14 | 15 | local timeout is time:seconds + 9000. 16 | when dV:mag < 0.05 then { set timeout to time:seconds + 10. return false. } 17 | until dV:mag <= 0.001 or time:seconds > timeout { 18 | set posVec to ship:position - body:position. 19 | set vecNormal to vcrs(posVec,velocity:orbit). 20 | set vecHorizontal to -1 * vcrs(ship:position-body:position, vecNormal). 21 | set vecHorizontal:mag to sqrt(body:MU/(body:Radius + altitude)). 22 | 23 | set dV to vecHorizontal - velocity:orbit. //deltaV as a vector 24 | 25 | //Debug vectors 26 | //set mark_n to VECDRAWARGS(ship:position, vecNormal:normalized * (velocity:orbit:mag / 100), RGB(1,0,1), "n", 1, true). 27 | //set mark_h to VECDRAWARGS(ship:position, vecHorizontal / 100, RGB(0,1,0), "h", 1, true). 28 | //set mark_v to VECDRAWARGS(ship:position, velocity:orbit / 100, RGB(0,0,1), "dv", 1, true). 29 | set mark_dv to VECDRAWARGS(ship:position, dV * 10, RGB(1,1,1), "dv: " + round(dv:mag,3) + "m/s", 1, true,0.2). 30 | 31 | if method = "rcs" { 32 | set dV:mag to min(dV:mag * 5,1)^0.75. 33 | //set ship:control:fore to -pid1:update(time:seconds,vdot(facing:vector,dV)). 34 | //set ship:control:top to -pid2:update(time:seconds,vdot(facing:topvector,dV)). 35 | //set ship:control:starboard to -pid3:update(time:seconds,vdot(facing:starvector,dV)). 36 | 37 | set ship:control:fore to vdot(facing:vector,dV). 38 | set ship:control:top to vdot(facing:topvector,dV). 39 | set ship:control:starboard to vdot(facing:starvector,dV). 40 | } 41 | else { 42 | //throttle control 43 | set max_acc to ship:maxthrust / ship:mass. 44 | set angvel to ship:angularvel:mag * (180/constant():pi). 45 | if vang(ship:facing:vector,dV) > 1 or angvel > 3 { set th to 0. } 46 | else { set th to dV:mag/ (max_acc * 1). } 47 | } 48 | 49 | 50 | wait 0. 51 | } 52 | set th to 0. 53 | unlock throttle. 54 | unlock steering. 55 | clearvecdraws(). 56 | HUDTEXT("Circularization complete", 4, 2, 30, yellow, false). -------------------------------------------------------------------------------- /cpu_light.ks: -------------------------------------------------------------------------------- 1 | //function to set the kos cpu's light, if it has one. 2 | 3 | //find the module and store it for later 4 | local cpuPart is core:part. 5 | local lightParts is ship:partstagged("light"). 6 | local kosLightMods is list(). 7 | local hasLights is false. 8 | getLightModule(cpuPart). 9 | 10 | if lightParts:length > 0 { 11 | for p in lightParts { 12 | getLightModule(p). 13 | } 14 | } 15 | 16 | function getLightModule { 17 | parameter p. 18 | for ms in p:modules { 19 | local m is p:getmodule(ms). 20 | if m:hasfield("light r") and m:hasfield("light g") and m:hasfield("light b") { //not really necessary to check all but why not 21 | set hasLights to true. 22 | kosLightMods:add(m). 23 | } 24 | } 25 | } 26 | 27 | function setLights { 28 | parameter r,g,b. 29 | 30 | if hasLights { 31 | //only takes a value between 0 and 1 32 | //set r to max(0,min(1,r)). 33 | //set g to max(0,min(1,g)). 34 | //set b to max(0,min(1,b)). 35 | 36 | for m in kosLightMods { 37 | m:setfield("light r",r). 38 | m:setfield("light g",g). 39 | m:setfield("light b",b). 40 | } 41 | } 42 | } 43 | 44 | if hasLights { 45 | setLights(1,1,1). 46 | } -------------------------------------------------------------------------------- /debug.ks: -------------------------------------------------------------------------------- 1 | set foreVec to vecdraw(v(0,0,0),v(0,0,0),cyan,"fore",1,true,0.2). 2 | set topVec to vecdraw(v(0,0,0),v(0,0,0),magenta,"top",1,true,0.2). 3 | set starVec to vecdraw(v(0,0,0),v(0,0,0),green,"star",1,true,0.2). 4 | 5 | local partList is list(). 6 | set partList to ship:partstagged("debug"). 7 | if partList:length = 0 set partList to ship:parts. 8 | 9 | for cur_part in partList { 10 | 11 | local foo is highlight(cur_part,RGB(0,1,1)). 12 | brakes off. 13 | until brakes { 14 | clearscreen. 15 | print cur_part:name. 16 | print "---------------------------". 17 | for cur_module_str in cur_part:modules { 18 | set cur_module to cur_part:GETMODULE(cur_module_str). 19 | print cur_module:name. 20 | if cur_module:allfields:length > 0 { for i in cur_module:allfields { print "...Field: " + i. } } 21 | if cur_module:allevents:length > 0 { for i in cur_module:allevents { print "...Event: " + i. } } 22 | if cur_module:allactions:length > 0 { for i in cur_module:allactions { print "...Action: " + i. } } 23 | } 24 | print "stage: " + cur_part:stage. 25 | print "------------------------------------". 26 | 27 | 28 | set foreVec:start to cur_part:position. 29 | set topVec:start to cur_part:position. 30 | set starVec:start to cur_part:position. 31 | 32 | set foreVec:vec to cur_part:facing:vector. 33 | set topVec:vec to cur_part:facing:topvector. 34 | set starVec:vec to cur_part:facing:starvector. 35 | 36 | wait 0. 37 | } 38 | set foo:ENABLED to false. 39 | } 40 | -------------------------------------------------------------------------------- /drone_ship.ks: -------------------------------------------------------------------------------- 1 | // ############# 2 | // ### SETUP ### 3 | 4 | clearscreen. 5 | clearvecdraws(). 6 | 7 | set drone to ship. 8 | set s_ready to 0. 9 | set s_approach to 1. 10 | set s_docked to 2. 11 | set dockingstate to s_ready. 12 | 13 | //set bay to ship:partstitled("mk3CargoBayL")[0]. 14 | //set bayMod to bay:getmodule("ModuleAnimateGeneric"). 15 | set aimPoint to ship:partstagged("aimPoint")[0]. 16 | 17 | local freePorts is ship:partstagged("R"). 18 | if freePorts:length = 0 local freePorts is ship:partstagged("X"). 19 | set port to freePorts[0]. 20 | 21 | set isDocked to getPortState(). 22 | if isDocked set port:tag to "X". 23 | else set port:tag to "R". 24 | 25 | for g in addons:ir:groups { 26 | if g:name = "rail" { 27 | set rail to g:servos[0]. 28 | set rail:acceleration to 4. 29 | } 30 | else if g:name = "arm" set arm to g. 31 | else if g:name = "end" { 32 | set end to g. 33 | set endServo to g:servos[0]. 34 | set endServo:acceleration to 50. 35 | } 36 | else if g:name = "cam pitch" set camPitch to g. 37 | } 38 | 39 | // ################# 40 | // ### FUNCTIONS ### 41 | 42 | function getPortState { 43 | local portSatus is port:state. 44 | if portSatus = "Docked (docker)" or portSatus = "Docked (dockee)" return true. 45 | else return false. 46 | } 47 | function defaultPortPitch { 48 | set endServo:speed to 1. 49 | endServo:moveto(-90,0.5). 50 | } 51 | function resetAll { 52 | set dockingstate to s_ready. 53 | set port:tag to "R". 54 | set drone to ship. 55 | 56 | setArmSpeed(1). 57 | set rail:speed to 0.5. 58 | 59 | rail:movecenter(). 60 | arm:movecenter(). 61 | defaultPortPitch(). 62 | } 63 | function setArmSpeed { 64 | parameter sp. 65 | for s in arm:servos { 66 | if s:part:name = "IR.Foldatron.Extended" set s:speed to sp / 2. 67 | else set s:speed to sp. 68 | } 69 | } 70 | 71 | // ############ 72 | // ### LOOP ### 73 | 74 | until false { 75 | set isDocked to getPortState(). 76 | 77 | 78 | // ### MESSAGES 79 | set queue to ship:messages. 80 | if not queue:empty { //received a message 81 | set msg to queue:pop. 82 | set cnt to msg:content. 83 | 84 | if cnt = "dock" { 85 | 86 | 87 | set port:tag to "X". 88 | set dockingstate to s_approach. 89 | set drone to msg:sender. 90 | set dronePort to drone:dockingports[0]. 91 | 92 | } 93 | else if cnt = "abort" or cnt = "undock" { 94 | resetAll(). 95 | } 96 | } 97 | 98 | // ### SERVOS 99 | if dockingstate = s_approach { 100 | if isDocked { //detected a recent dock, switch to docked mode 101 | set dockingstate to s_docked. 102 | defaultPortPitch(). 103 | arm:stop(). 104 | rail:stop(). 105 | } 106 | else { 107 | local portVec is port:facing:vector. 108 | local portPos is port:position + portVec * 0.13. 109 | 110 | local relativeV is drone:velocity:surface - ship:velocity:surface. 111 | local relativeHV is vxcl(ship:facing:topvector,relativeV). 112 | local portTopVec is vcrs(portVec,ship:facing:starvector). 113 | 114 | //docking arm and rail groups 115 | local dronePortPos is dronePort:position + dronePort:facing:vector * 0.13. 116 | local dronePosVec is dronePortPos - portPos. //relative to plane's dockingport 117 | 118 | //from dockingport's frame of reference 119 | local droneForward is vdot(portVec,dronePosVec). 120 | local droneSide is vdot(ship:facing:starvector,dronePosVec). 121 | local droneUp is vdot(portTopVec,dronePosVec). 122 | 123 | //from plane's frame of reference 124 | local droneUpShip is vdot(ship:facing:topvector,dronePosVec). 125 | 126 | local frontOffset is vdot(-ship:facing:vector, dronePortPos - aimPoint:position). 127 | local upOffset is vdot(-ship:facing:topvector, dronePortPos - aimPoint:position). 128 | 129 | 130 | if abs(frontOffset) < 4 and relativeV:mag < 0.7 { //move closer 131 | local sideErr is vxcl(dronePort:facing:vector,portPos - dronePortPos):mag. 132 | local movePortTo is dronePortPos + dronePort:facing:vector * sideErr * 1.5. 133 | 134 | local errVec is movePortTo - portPos. 135 | local frontErr is vdot(ship:facing:vector,errVec). 136 | local upErr is vdot(ship:facing:topvector,errVec). 137 | 138 | setArmSpeed(min(3,abs(upErr) * 1)). 139 | if upErr < 0 arm:moveleft(). 140 | else arm:moveright(). 141 | 142 | set rail:speed to min(3,abs(frontErr * 6)). 143 | print "railspeed: " + round(rail:speed,1) + " " at (0,14). 144 | if frontErr > 0 rail:moveleft(). 145 | else rail:moveright(). 146 | 147 | set vd1 to vecdraw(portPos,errVec,rgba(0.5,0.5,0,1),"",1,true,0.2). 148 | } 149 | else { //too unstable, pull back 150 | set rail:speed to 0.5. 151 | //set arm:speed to 0.5. 152 | setArmSpeed(0.5). 153 | rail:movecenter(). 154 | arm:movecenter(). 155 | } 156 | 157 | print "Forward distance: " + round(droneForward,1) + "m " at (0,2). 158 | print "Forward offset: " + round(frontOffset,2) + "m " at (0,3). 159 | print "Up distance: " + round(droneUp,1) + "m " at (0,5). 160 | print "Up offset: " + round(upOffset,2) + "m " at (0,6). 161 | print "Side distance: " + round(droneSide,1) + "m " at (0,8). 162 | 163 | //docking port pitch aim 164 | local dronePortVec is vxcl(ship:facing:starvector,drone:facing:vector). 165 | set portAimVec to -dronePortVec. 166 | 167 | 168 | set vertAngErr to vang(vxcl(ship:facing:starvector,portVec), portAimVec). 169 | set endServo:speed to min(8,vertAngErr * 1). 170 | if vdot(portTopVec, portAimVec) < 0 set vertAngErr to -vertAngErr. 171 | 172 | if vertAngErr < 0 endServo:moveright(). 173 | else if vertAngErr > 0 endServo:moveleft(). 174 | else endServo:stop(). 175 | 176 | print "vertical angle err: " + round(abs(vertAngErr),1) + " " at (0,10). 177 | } 178 | } 179 | else if dockingstate = s_ready { 180 | //set portAimVec to -ship:facing:topvector. 181 | } 182 | else if dockingstate = s_docked { 183 | //set portAimVec to -ship:facing:topvector. 184 | if not isDocked { //surprise undock happened, make ready for new ones 185 | resetAll(). 186 | } 187 | } 188 | 189 | 190 | 191 | 192 | //set vertAngOffset to vertAngOffset + vertAngErr * 0.1. 193 | //endServo:moveto(vertAngErr,1). 194 | 195 | //set bayState to bayMod:getfield("status"). 196 | 197 | print "state: " + dockingstate at (0,1). 198 | wait 0. 199 | } -------------------------------------------------------------------------------- /exec.ks: -------------------------------------------------------------------------------- 1 | parameter nn is nextnode. 2 | HUDTEXT("Starting execute node script.", 4, 2, 30, yellow, false). 3 | 4 | runoncepath("lib_rocket_utility.ks"). 5 | 6 | sas off. 7 | set th to 0. 8 | lock throttle to th. 9 | lock steering to lookdirup(nn:deltav, ship:facing:topvector). //points to node, keeping roll the same. 10 | 11 | local burn_stats is half_dv_duration(nn:deltav:mag). 12 | local first_half_duration is burn_stats[0]. 13 | local burn_duration is first_half_duration + burn_stats[1]. 14 | 15 | set kuniverse:timewarp:warp to 0. 16 | 17 | set node_time to time:seconds + nn:eta. 18 | set warp_target to node_time - 15 - first_half_duration. 19 | 20 | wait until vang(facing:vector, steering:vector) < 1 or time:seconds >= warp_target. 21 | 22 | 23 | 24 | 25 | 26 | 27 | HUDTEXT("Estimated burn duration: " + round(burn_duration,1) + "s", 15, 2, 20, yellow, false). 28 | 29 | 30 | 31 | if warp_target > time:seconds { 32 | set kuniverse:timewarp:mode to "rails". 33 | wait 0. 34 | kuniverse:timewarp:warpto(warp_target). 35 | } 36 | 37 | 38 | 39 | wait until nn:eta - first_half_duration <= 0. //wait until we are close to executing the node 40 | set kuniverse:timewarp:mode to "physics". //se we can manually physics warp during a burn 41 | 42 | HUDTEXT("Begin burn. Physics warp is possible.", 5, 2, 20, yellow, false). 43 | 44 | set dv0 to nn:deltav. 45 | 46 | local done is false. 47 | until done { 48 | set max_acc to ship:availablethrust/ship:mass. 49 | if nn:deltav:mag/(max_acc*10) < 1 set warp to 0. //warp 50 | 51 | if vang(facing:vector, steering:vector) > 1 { set th to 0. } 52 | else { set th to min(nn:deltav:mag/(max_acc*1.2), 1). } 53 | 54 | 55 | LIST engines IN engs. 56 | for eng in engs { if eng:ignition = true and eng:flameout = true and stage:ready { stage. } } 57 | 58 | if nn:deltav:mag < 0.05 set done to true. 59 | wait 0. 60 | } 61 | 62 | HUDTEXT("Manouver mode has been executed!", 4, 2, 30, yellow, false). 63 | 64 | set kuniverse:timewarp:mode to "rails". 65 | unlock steering. 66 | set th to 0. 67 | unlock throttle. 68 | set ship:control:pilotmainthrottle to 0. 69 | remove nn. -------------------------------------------------------------------------------- /gui/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/blank.png -------------------------------------------------------------------------------- /gui/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/button.png -------------------------------------------------------------------------------- /gui/button_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/button_on.png -------------------------------------------------------------------------------- /gui/gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/gui.png -------------------------------------------------------------------------------- /gui/hoverbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/hoverbot.png -------------------------------------------------------------------------------- /gui/indent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/indent.png -------------------------------------------------------------------------------- /gui/mini_terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/mini_terminal.png -------------------------------------------------------------------------------- /gui/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/radio.png -------------------------------------------------------------------------------- /gui/radio_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/radio_hover.png -------------------------------------------------------------------------------- /gui/radio_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/radio_on.png -------------------------------------------------------------------------------- /gui/slider_indent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/slider_indent.png -------------------------------------------------------------------------------- /gui/slider_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/slider_thumb.png -------------------------------------------------------------------------------- /gui/terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/terminal.png -------------------------------------------------------------------------------- /gui/terminal_opaque.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/terminal_opaque.png -------------------------------------------------------------------------------- /gui/toggle_mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/toggle_mid.png -------------------------------------------------------------------------------- /gui/toggle_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/toggle_off.png -------------------------------------------------------------------------------- /gui/toggle_off_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/toggle_off_hover.png -------------------------------------------------------------------------------- /gui/toggle_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/toggle_on.png -------------------------------------------------------------------------------- /gui/toggle_on_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozin370/Script/5ce65ea9feb204cac0dd988a9e0830fb1ed6b187/gui/toggle_on_hover.png -------------------------------------------------------------------------------- /json/5m Cargoplane Drone/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 70, 5 | "maxBankSpeed", 6 | 120, 7 | "bankFactor", 8 | 0.8, 9 | "maxBank", 10 | 60, 11 | "landingRadius", 12 | 2000 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/5m Cargoplane Drone/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 5, 9 | "maxstoppingtime", 10 | 2, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 1, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 0.5, 25 | "pitchpid:kp", 26 | 1, 27 | "pitchpid:ki", 28 | 0.1, 29 | "pitchpid:kd", 30 | 0, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.2, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 1.9999999999999996, 39 | "rollpid:ki", 40 | 0, 41 | "rollpid:kd", 42 | 2 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/Aeris 3A kOS/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 50, 5 | "maxBankSpeed", 6 | 90, 7 | "bankFactor", 8 | 1, 9 | "maxBank", 10 | 70, 11 | "landingRadius", 12 | 1000 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/Aeris 3A kOS/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 2, 9 | "maxstoppingtime", 10 | 2, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 1, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 0.5, 25 | "pitchpid:kp", 26 | 1, 27 | "pitchpid:ki", 28 | 0.2, 29 | "pitchpid:kd", 30 | 0, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.2, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 2, 39 | "rollpid:ki", 40 | 0.05, 41 | "rollpid:kd", 42 | 0.5 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/Albatross 3 kOS/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 40, 5 | "maxBankSpeed", 6 | 90, 7 | "bankFactor", 8 | 0.7, 9 | "maxBank", 10 | 45, 11 | "landingRadius", 12 | 2000 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/Albatross 3 kOS/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 2, 9 | "maxstoppingtime", 10 | 2, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 1, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 1, 25 | "pitchpid:kp", 26 | 1, 27 | "pitchpid:ki", 28 | 0.1, 29 | "pitchpid:kd", 30 | 0, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.1, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 0.7, 39 | "rollpid:ki", 40 | 0.1, 41 | "rollpid:kd", 42 | 0.2 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/Ravenspear Mk3/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 75, 5 | "maxBankSpeed", 6 | 150, 7 | "bankFactor", 8 | 0.9, 9 | "maxBank", 10 | 60, 11 | "landingRadius", 12 | 2000 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/Ravenspear Mk3/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 2, 9 | "maxstoppingtime", 10 | 2, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 1, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 0.5, 25 | "pitchpid:kp", 26 | 1, 27 | "pitchpid:ki", 28 | 0.2, 29 | "pitchpid:kd", 30 | 0, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.4, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 1.5, 39 | "rollpid:ki", 40 | 0.4, 41 | "rollpid:kd", 42 | 0.5 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/Stearwing A300/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 90, 5 | "maxBankSpeed", 6 | 130, 7 | "bankFactor", 8 | 0.7, 9 | "maxBank", 10 | 45, 11 | "landingRadius", 12 | 2500 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/Stearwing A300/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 2, 9 | "maxstoppingtime", 10 | 2, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 0.5, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 0.3, 25 | "pitchpid:kp", 26 | 0.8, 27 | "pitchpid:ki", 28 | 0.2, 29 | "pitchpid:kd", 30 | 0.2, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.1, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 0.8, 39 | "rollpid:ki", 40 | 0.1, 41 | "rollpid:kd", 42 | 1.5 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/Thunderbird/autopilot.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "stallSpeed", 4 | 75, 5 | "maxBankSpeed", 6 | 110, 7 | "bankFactor", 8 | 1, 9 | "maxBank", 10 | 55, 11 | "landingRadius", 12 | 1500 13 | ], 14 | "$type": "kOS.Safe.Encapsulation.Lexicon" 15 | } -------------------------------------------------------------------------------- /json/Thunderbird/steering.json: -------------------------------------------------------------------------------- 1 | { 2 | "entries": [ 3 | "pitchts", 4 | 2, 5 | "yawts", 6 | 2, 7 | "rollts", 8 | 2, 9 | "maxstoppingtime", 10 | 3, 11 | "rollcontrolanglerange", 12 | 180, 13 | "pitchtorqueadjust", 14 | 0, 15 | "pitchtorquefactor", 16 | 1, 17 | "yawtorqueadjust", 18 | 0, 19 | "yawtorquefactor", 20 | 1, 21 | "rolltorqueadjust", 22 | 0, 23 | "rolltorquefactor", 24 | 0.2, 25 | "pitchpid:kp", 26 | 1, 27 | "pitchpid:ki", 28 | 0.2, 29 | "pitchpid:kd", 30 | 0, 31 | "yawpid:kp", 32 | 1, 33 | "yawpid:ki", 34 | 0.2, 35 | "yawpid:kd", 36 | 0, 37 | "rollpid:kp", 38 | 1, 39 | "rollpid:ki", 40 | 0.2, 41 | "rollpid:kd", 42 | 0.8 43 | ], 44 | "$type": "kOS.Safe.Encapsulation.Lexicon" 45 | } -------------------------------------------------------------------------------- /json/runways/Kerbin.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "items": [ 5 | "KSC 09", 6 | -0.0486697432694389, 7 | -74.7220377114077, 8 | -0.0502131096942382, 9 | -74.4951289901873, 10 | -0.05539, 11 | -74.61733, 12 | -0.06221, 13 | -74.61739, 14 | -0.06532, 15 | -74.62046, 16 | -0.06462, 17 | -74.62416, 18 | -0.06132, 19 | -74.62816, 20 | -0.05732, 21 | -74.63016 22 | ], 23 | "$type": "kOS.Safe.Encapsulation.ListValue" 24 | }, 25 | { 26 | "items": [ 27 | "KSC 27", 28 | -0.0502131096942382, 29 | -74.4951289901873, 30 | -0.0486697432694389, 31 | -74.7220377114077, 32 | -0.05539, 33 | -74.61733, 34 | -0.06221, 35 | -74.61739, 36 | -0.06532, 37 | -74.62046, 38 | -0.06462, 39 | -74.62416, 40 | -0.06132, 41 | -74.62816, 42 | -0.05732, 43 | -74.63016 44 | ], 45 | "$type": "kOS.Safe.Encapsulation.ListValue" 46 | }, 47 | { 48 | "items": [ 49 | "Island 09", 50 | -1.51806713434498, 51 | -71.9686515236803, 52 | -1.51566431260178, 53 | -71.8513882426904, 54 | -1.52246003880166, 55 | -71.8951322255196, 56 | -1.52238917854372, 57 | -71.9029429161532 58 | ], 59 | "$type": "kOS.Safe.Encapsulation.ListValue" 60 | }, 61 | { 62 | "items": [ 63 | "Island 27", 64 | -1.51566431260178, 65 | -71.8513882426904, 66 | -1.51806713434498, 67 | -71.9686515236803, 68 | -1.52246003880166, 69 | -71.8951322255196, 70 | -1.52238917854372, 71 | -71.9029429161532 72 | ], 73 | "$type": "kOS.Safe.Encapsulation.ListValue" 74 | }, 75 | { 76 | "items": [ 77 | "Island Roof", 78 | -1.84067446835453, 79 | -71.9819052653066, 80 | -1.76179578429485, 81 | -71.9823239609914 82 | ], 83 | "$type": "kOS.Safe.Encapsulation.ListValue" 84 | }, 85 | { 86 | "items": [ 87 | "Field", 88 | 0.17358481490647, 89 | -74.9642214448504, 90 | 0.232681172753888, 91 | -75.0955666284595 92 | ], 93 | "$type": "kOS.Safe.Encapsulation.ListValue" 94 | }, 95 | { 96 | "items": [ 97 | "Inclined", 98 | -0.7378812868294, 99 | -74.8004934841927, 100 | -0.628744824988205, 101 | -74.8807989589523 102 | ], 103 | "$type": "kOS.Safe.Encapsulation.ListValue" 104 | }, 105 | { 106 | "items": [ 107 | "Mountain of Death", 108 | 0.501210374567098, 109 | -79.0620192967054, 110 | 0.551044874260144, 111 | -79.1124370941125 112 | ], 113 | "$type": "kOS.Safe.Encapsulation.ListValue" 114 | }, 115 | { 116 | "items": [ 117 | "Death Peak", 118 | 0.638609133472562, 119 | -79.3483162306698, 120 | 0.677100551194089, 121 | -79.341714788505 122 | ], 123 | "$type": "kOS.Safe.Encapsulation.ListValue" 124 | }, 125 | { 126 | "items": [ 127 | "KSC Sea", 128 | -0.20886, 129 | -74.29441, 130 | 0.19114, 131 | -74.46441 132 | ], 133 | "$type": "kOS.Safe.Encapsulation.ListValue" 134 | }, 135 | { 136 | "items": [ 137 | "Kerman Lake", 138 | 11.152366712434066, 139 | -63.439327194473584, 140 | 11.27837, 141 | -63.52583, 142 | 11.25937, 143 | -63.50613, 144 | 11.25657, 145 | -63.50283, 146 | 11.25457, 147 | -63.50483 148 | ], 149 | "$type": "kOS.Safe.Encapsulation.ListValue" 150 | }, 151 | { 152 | "items": [ 153 | "Kerman Lake take-off", 154 | 11.28072, 155 | -63.52747, 156 | 11.14872, 157 | -63.43687 158 | ], 159 | "$type": "kOS.Safe.Encapsulation.ListValue" 160 | }, 161 | { 162 | "items": [ 163 | "South Hope", 164 | -49.664371658898659, 165 | 16.972707721343873, 166 | -49.79437, 167 | 16.99431, 168 | -49.77337, 169 | 17.00531, 170 | -49.77057, 171 | 17.02331, 172 | -49.77807, 173 | 17.04431, 174 | -49.79187, 175 | 17.04531, 176 | -49.79497, 177 | 17.01931, 178 | -49.79397, 179 | 17.00631 180 | ], 181 | "$type": "kOS.Safe.Encapsulation.ListValue" 182 | }, 183 | { 184 | "items": [ 185 | "South Hope take-off", 186 | -49.79437, 187 | 16.99431, 188 | -49.664371658898659, 189 | 16.972707721343873 190 | ], 191 | "$type": "kOS.Safe.Encapsulation.ListValue" 192 | }, 193 | { 194 | "items": [ 195 | "North Pole", 196 | 79.449739964961, 197 | -77.55962180826964, 198 | 79.57574, 199 | -77.40592, 200 | 79.57454, 201 | -77.45192 202 | ], 203 | "$type": "kOS.Safe.Encapsulation.ListValue" 204 | }, 205 | { 206 | "items": [ 207 | "North Pole take-off", 208 | 79.57574, 209 | -77.40592, 210 | 79.449739964961, 211 | -77.55962180826964 212 | ], 213 | "$type": "kOS.Safe.Encapsulation.ListValue" 214 | }, 215 | { 216 | "items": [ 217 | "Coaler Crater", 218 | 35.389004330956979, 219 | -98.9659504263649, 220 | 35.431, 221 | -98.90215, 222 | 35.432, 223 | -98.90715, 224 | 35.436, 225 | -98.91015, 226 | 35.442, 227 | -98.91615, 228 | 35.442, 229 | -98.92615, 230 | 35.412, 231 | -98.97015, 232 | 35.401, 233 | -98.96315 234 | ], 235 | "$type": "kOS.Safe.Encapsulation.ListValue" 236 | }, 237 | { 238 | "items": [ 239 | "Black Krags", 240 | 11.320802166294715, 241 | -87.687430126559875, 242 | 11.2548, 243 | -87.69603 244 | ], 245 | "$type": "kOS.Safe.Encapsulation.ListValue" 246 | }, 247 | { 248 | "items": [ 249 | "Lake Dermal", 250 | 22.8283092810647, 251 | -121.06537518888707, 252 | 22.72961, 253 | -120.96538, 254 | 22.72661, 255 | -120.97038 256 | ], 257 | "$type": "kOS.Safe.Encapsulation.ListValue" 258 | }, 259 | { 260 | "items": [ 261 | "Lake Dermal take-off", 262 | 22.72961, 263 | -120.96538, 264 | 22.8283092810647, 265 | -121.06537518888707 266 | ], 267 | "$type": "kOS.Safe.Encapsulation.ListValue" 268 | }, 269 | { 270 | "items": [ 271 | "KSC2 36", 272 | 20.50486, 273 | -146.56814, 274 | 20.68786, 275 | -146.58814, 276 | 20.66786, 277 | -146.57614, 278 | 20.66586, 279 | -146.55714, 280 | 20.65786, 281 | -146.54724, 282 | 20.64186, 283 | -146.54424, 284 | 20.61686, 285 | -146.55324, 286 | 20.59886, 287 | -146.55824, 288 | 20.58786, 289 | -146.55524, 290 | 20.57726, 291 | -146.53824, 292 | 20.57926, 293 | -146.49624, 294 | 20.59726, 295 | -146.49024, 296 | 20.59726, 297 | -146.47724, 298 | 20.59226, 299 | -146.46724 300 | ], 301 | "$type": "kOS.Safe.Encapsulation.ListValue" 302 | }, 303 | { 304 | "items": [ 305 | "KSC2 18", 306 | 20.65474, 307 | -146.43828, 308 | 20.50874, 309 | -146.48328, 310 | 20.52274, 311 | -146.49228, 312 | 20.52674, 313 | -146.50528, 314 | 20.53674, 315 | -146.51428, 316 | 20.55174, 317 | -146.51428, 318 | 20.57374, 319 | -146.50698, 320 | 20.57374, 321 | -146.49598, 322 | 20.59874, 323 | -146.48698, 324 | 20.59744, 325 | -146.47698, 326 | 20.59244, 327 | -146.46598 328 | ], 329 | "$type": "kOS.Safe.Encapsulation.ListValue" 330 | }, 331 | { 332 | "items": [ 333 | "Round Range take-off", 334 | -6.03076, 335 | 99.53496, 336 | -6.01196, 337 | 99.38996 338 | ], 339 | "$type": "kOS.Safe.Encapsulation.ListValue" 340 | }, 341 | { 342 | "items": [ 343 | "Round Range landing", 344 | -6.0144902334942518, 345 | 99.409663688844859, 346 | -6.03219, 347 | 99.54666, 348 | -6.03019, 349 | 99.54066, 350 | -6.02619, 351 | 99.54466, 352 | -6.01119, 353 | 99.54666, 354 | -5.99719, 355 | 99.54866, 356 | -5.99349, 357 | 99.55366, 358 | -5.98879, 359 | 99.55166, 360 | -5.98879, 361 | 99.54666, 362 | -5.99279, 363 | 99.54466, 364 | -5.99779, 365 | 99.54866, 366 | -6.00279, 367 | 99.54786, 368 | -6.00879, 369 | 99.54706 370 | ], 371 | "$type": "kOS.Safe.Encapsulation.ListValue" 372 | } 373 | ], 374 | "$type": "kOS.Safe.Encapsulation.ListValue" 375 | } -------------------------------------------------------------------------------- /launch.ks: -------------------------------------------------------------------------------- 1 | // ### Launch.ks ### 2 | 3 | parameter target_apo is 100. 4 | parameter target_inc is 0. 5 | set target_apo to target_apo * 1000. 6 | //runoncepath("kslib/LAZcalc.ks"). 7 | runoncepath("kslib/lib_lazcalc.ks"). 8 | 9 | 10 | // >> ### Console ### 11 | runoncepath("lib_UI.ks"). 12 | set terminal:brightness to 1. 13 | set terminal:width to 44. 14 | set terminal:height to 45. 15 | clearscreen. 16 | 17 | // use the first two of these varables to set the position of the menu. The last two affect the width of the menu. 18 | local startLine is 4. //the first menu item will start at this line in the terminal window 19 | local startColumn is 4. //menu item description starts at this x coordinate, remember to leave some space for the marker on the left 20 | local nameLength is 21. //how many characters of the menu item names to display 21 | local valueLength is 8. //how many characters of the menu item values to display 22 | local sv is -9.9993134. // just a value that is extremely unlikely to be set to any of the varibles we want to change with the menu 23 | 24 | set mainMenu to list( 25 | //list("Modes", "text"), 26 | list("Target APO:", "number", { parameter p is sv. if p <> sv { set target_apo to max(body:atm:height + 100,round(p)). set laz to LAZcalc_init(target_apo,target_inc). } return round(target_apo). }, 10000), 27 | list("Target INC:", "number", { parameter p is sv. if p <> sv { set target_inc to p. set laz to LAZcalc_init(target_apo,target_inc). } return round(target_inc,2). }, 1), 28 | list("", "text"), 29 | list("Calc Ascent Path:", "bool", { parameter p is sv. if p <> sv set calc_ascent to boolConvert(p). return calc_ascent. }), 30 | list("Turn end:", "number", { parameter p is sv. if p <> sv and not calc_ascent set turn_end to p. return round(turn_end). }, 1000), 31 | list("Turn exponent:", "number", { parameter p is sv. if p <> sv and not calc_ascent set turn_exponent to max(0.25,min(1,p)). return round(turn_exponent,2). }, 0.1), 32 | list("Start Speed:", "number", { parameter p is sv. if p <> sv set turn_speed to p. return round(turn_speed). }, 10), 33 | list("-", "line"), 34 | list("Stage # to orbit:", "number", { parameter p is sv. if p <> sv set stage_to_orbit to min(stage:number,max(0,round(p))). return stage_to_orbit. }, 1), 35 | list("RCS in orbit:", "bool", { parameter p is sv. if p <> sv set auto_rcs to boolConvert(p). return auto_rcs. }), 36 | list("1st stg recovery:", "bool", { parameter p is sv. if p <> sv set stg_recovery to boolConvert(p). return stg_recovery. }), 37 | list("", "text"), 38 | list("Cinematic Mode:", "bool", { parameter p is sv. if p <> sv set cinematic to boolConvert(p). return cinematic. }), 39 | list("-", "line"), 40 | list("[ Save settings for craft ]","action", { saveSettings(). }), 41 | list("[ Launch ]", "action", { if not go { set go to true. } else { set done to true. } set mainMenu[(mainMenu:length-1)][0] to "[ Abort ]". setMenu(mainMenu). }) 42 | ). 43 | 44 | set activeMenu to mainMenu. 45 | runoncepath("lib_menu.ks"). 46 | 47 | runoncepath("lib_list.ks"). 48 | set_indentation(6). 49 | local old_height is terminal:height. 50 | local old_width is terminal:width. 51 | 52 | function rescale { 53 | list_position(0,terminal:width-1,startLine + activeMenu:length + 3,terminal:height-2). 54 | horizontalLine(2,"="). 55 | horizontalLine(startLine + activeMenu:length + 2,"-"). 56 | } 57 | 58 | // << 59 | 60 | function stage_until_number { 61 | parameter stage_number. 62 | if stage:number > stage_number { 63 | set kuniverse:timewarp:warp to 0. 64 | add_entry(mission_time() + "Staging to stage " + stage_number). 65 | local old_th is th. 66 | set th to 0. 67 | local i is stage:number. 68 | until i = stage_number { 69 | wait until stage:ready. 70 | stage. 71 | wait 1. 72 | set i to i - 1. 73 | } 74 | set th to old_th. 75 | } 76 | } 77 | 78 | function mission_time { 79 | if go return "T+" + round(time:seconds - mission_start) + " ". 80 | else return "T-5 ". 81 | } 82 | 83 | 84 | // >> ### Settings and defaults ### 85 | 86 | local go is false. 87 | rescale(). 88 | add_entry(mission_time() + "Program started."). 89 | 90 | sas off. 91 | rcs off. 92 | 93 | local turn_end is 40000. 94 | local turn_exponent is 0.5. 95 | local turn_speed is 60. 96 | set starting_alt to altitude. 97 | local calc_ascent is true. 98 | local cinematic is false. 99 | local stage_to_orbit is stage:number. 100 | local stg_recovery is false. 101 | local booster_vessel is ship. 102 | local auto_rcs is true. 103 | 104 | function saveSettings { 105 | local lex is lexicon( 106 | "turn_end", turn_end, 107 | "turn_exponent",turn_exponent, 108 | "turn_speed",turn_speed, 109 | "calc_ascent",calc_ascent, 110 | "stage_to_orbit",stage_to_orbit, 111 | "stg_recovery",stg_recovery, 112 | "auto_rcs",auto_rcs 113 | ). 114 | 115 | local filePath is path("0:/json/launchParams/" + ship:name + ".json"). 116 | writejson(lex, filePath). 117 | add_entry(mission_time() + "Saved launch parameters for craft " + ship:name). 118 | } 119 | 120 | function loadSettings { 121 | local filePath is path("0:/json/launchParams/" + ship:name + ".json"). 122 | if exists(filePath) { 123 | local lex is readjson(filePath). 124 | 125 | if lex:haskey("turn_end") set turn_end to lex["turn_end"]. 126 | if lex:haskey("turn_exponent") set turn_exponent to lex["turn_exponent"]. 127 | if lex:haskey("turn_speed") set turn_speed to lex["turn_speed"]. 128 | if lex:haskey("calc_ascent") set calc_ascent to lex["calc_ascent"]. 129 | if lex:haskey("stage_to_orbit") set stage_to_orbit to lex["stage_to_orbit"]. 130 | if lex:haskey("stg_recovery") set stg_recovery to lex["stg_recovery"]. 131 | if lex:haskey("auto_rcs") set auto_rcs to lex["auto_rcs"]. 132 | 133 | add_entry(mission_time() + "Loaded launch parameters for craft " + ship:name). 134 | return true. 135 | } 136 | else return false. 137 | } 138 | 139 | loadSettings(). 140 | 141 | set laz to LAZcalc_init(target_apo,target_inc). 142 | // << 143 | 144 | runoncepath("cam.ks"). 145 | local cam is addons:camera:flightcamera. 146 | set default_fov to cam:fov. 147 | //set spectator_pos to heading(180 + random() * 180,0):vector * 3000. //max(100,random() * 1000). 148 | set spectator_pos to heading(0,0):vector * 5000. 149 | set spectator_pos to body:geopositionof(spectator_pos). 150 | //set cam:target to ship:rootpart. 151 | 152 | 153 | drawAll(). //draws the menu on the terminal 154 | 155 | until go { 156 | inputs(). //menu stuff 157 | refreshAll(). 158 | wait 0. 159 | } 160 | 161 | // ### Launch ### 162 | set mission_start to time:seconds. 163 | local th is 1. 164 | lock throttle to th. 165 | local runmode is 0. 166 | 167 | local st is up:vector. 168 | lock steering to lookdirup(st,ship:facing:topvector). 169 | 170 | until ship:maxthrust > 0 { 171 | if stage:ready stage. 172 | wait 0. 173 | } 174 | 175 | local starting_TWR is ship:availablethrust / (ship:mass * body:mu / (altitude + body:radius)^2). 176 | set th to 1 / starting_TWR. 177 | if calc_ascent { 178 | set turn_end to 0.128*body:atm:height * starting_TWR + 0.5 * body:atm:height. // Based on testing 179 | set turn_end to round(turn_end/100) * 100. //round it off a bit for readability 180 | SET turn_exponent to round(max(1 / (2.5 * starting_TWR - 1.7), 0.25),2). // Based on testing 181 | add_entry(mission_time() + "Ascent profile calculated. Starting TWR: " + round(starting_TWR,2)). 182 | } 183 | gear off. 184 | 185 | add_entry(mission_time() + "Launch!"). 186 | 187 | // ### Main loop ### 188 | local done is false. 189 | local boostback_staged is false. 190 | until done or abort { 191 | inputs(). //checks if certain keys have been input to the terminal and acts accordingly (changing values, opening new menues etc) 192 | 193 | // ### Staging ### 194 | list engines in engs. 195 | for eng in engs { 196 | if eng:ignition and eng:flameout { 197 | wait until stage:ready. 198 | stage. 199 | add_entry(mission_time() + "Engine flameout detected, staging."). 200 | wait 0.1. 201 | break. 202 | } 203 | } 204 | 205 | set target_heading to LAZcalc(laz). 206 | 207 | // ### Runmodes ### 208 | if runmode = 0 { //initial ascent, straight up 209 | set th to min(1,th + 0.02 * (time:seconds - mission_start)). 210 | if verticalspeed > turn_speed or alt:radar > 2000 { 211 | set runmode to 1. 212 | add_entry(mission_time() + "Beginning ascent profile pitch-over.."). 213 | } 214 | } 215 | else if runmode = 1 { //ascent profile 216 | 217 | set pitch_angle to 90 * (1 - ((altitude - starting_alt) / (turn_end - starting_alt)) ^ turn_exponent). 218 | set st to heading(target_heading, max(0,pitch_angle)):vector. 219 | 220 | set th to max((target_apo - apoapsis)/1000,0.1). 221 | 222 | if apoapsis >= target_apo { 223 | set runmode to 2. 224 | add_entry(mission_time() + "Target apoapsis reached. Coasting.."). 225 | } 226 | } 227 | else if runmode = 2 { //maintain APO to target APO (fight drag as needed) 228 | set pitch_angle to 90 - vang(up:vector,velocity:orbit). 229 | set st to heading(target_heading, pitch_angle):vector. 230 | set th to (target_apo - apoapsis)/1000. 231 | 232 | if stg_recovery and not boostback_staged and th < 0.1 { //target APO is close, stage away the first stage if it is supposed to be boosting back to LP 233 | stage_until_number(stage_to_orbit). 234 | wait 2. 235 | boostback(). 236 | set boostback_staged to true. 237 | } 238 | else if altitude / body:atm:height > 0.85 stage_until_number(stage_to_orbit). 239 | 240 | if altitude > body:atm:height set runmode to 3. 241 | } 242 | else if runmode = 3 { //out of atmo 243 | add_entry(mission_time() + "Out of atmosphere."). 244 | set th to 0. 245 | set kuniverse:timewarp:warp to 0. 246 | if stage:number > stage_to_orbit { stage_until_number(stage_to_orbit). } 247 | panels on. 248 | add_entry(mission_time() + "Deploying solar panels."). 249 | 250 | wait until kuniverse:activevessel = ship. 251 | 252 | if auto_rcs rcs on. 253 | 254 | set target_spd to sqrt(body:MU/(body:Radius + apoapsis)). 255 | set spd_at_apo to velocityat(ship,eta:apoapsis + time:seconds):orbit:mag. 256 | set apo_node to node(eta:apoapsis + time:seconds,0,0,target_spd-spd_at_apo). 257 | add apo_node. 258 | 259 | add_entry(mission_time() + "Maneuver node created at apoapsis. Aligning and warping..."). 260 | runpath("exec.ks",apo_node). //program to timewarp to and execute a node 261 | 262 | add_entry(mission_time() + "Circularization burn complete - fine tuning..."). 263 | //if not stg_recovery { 264 | rcs on. 265 | runpath("circ.ks","rcs"). //program that does the final touches on the circularization. 266 | rcs off. 267 | //} 268 | 269 | add_entry(mission_time() + "Launch complete! Final AP: " + round(apoapsis,1) + ", final PE: " + round(periapsis,1) + ", INC: " + round(ship:obt:inclination,3)). 270 | wait 3. 271 | set done to true. //exit the runmodes loop - we're done here! 272 | } 273 | 274 | // ### Camera stuff 275 | if cinematic { 276 | if altitude < 10000 { 277 | set cam_pos to spectator_pos:position + up:vector * 2000. 278 | set cam:fov to max(1,default_fov - cam_pos:mag/100 - cam_pos:mag^0.75). 279 | 280 | //set cam:position to cam_pos. 281 | //set cam:target to ship:rootpart. 282 | set cam:distance to cam_pos:mag. 283 | set cam:pitch to vecToPitch(-cam_pos). 284 | 285 | } 286 | else { 287 | set cam:fov to default_fov. 288 | } 289 | } 290 | 291 | if old_height <> terminal:height or old_width <> terminal:width { 292 | clearscreen. 293 | rescale(). 294 | parse_list(). 295 | draw_list(). 296 | drawAll(). //draws the menu on the terminal 297 | set old_height to terminal:height. 298 | set old_width to terminal:width. 299 | } 300 | else refreshAll(). // tells the menu to refresh/print all relevant fields with updated values 301 | wait 0. 302 | } 303 | 304 | sas on. 305 | 306 | if stg_recovery { 307 | booster_vessel:connection:sendmessage("good luck"). 308 | wait 0.1. 309 | kuniverse:forceactive(booster_vessel). 310 | } 311 | 312 | function boostback { 313 | list targets in tars. 314 | for ves in tars { 315 | if ves:position:mag < 2000 { 316 | if ves:connection:sendmessage("boostback") { set booster_vessel to ves. break. } 317 | } 318 | } 319 | } 320 | 321 | 322 | -------------------------------------------------------------------------------- /lib_UI.ks: -------------------------------------------------------------------------------- 1 | local emptyString is " ". 2 | 3 | function horizontalLine { 4 | parameter line,char,ret is false. 5 | local s is emptyString:substring(0,terminal:width). 6 | set s to s:replace(" ",char). 7 | 8 | if ret return s. 9 | else print s at (0,line). 10 | } 11 | 12 | function horizontalLineTo { 13 | parameter line,colStart,colEnd,char,ret is false. 14 | local s is emptyString:substring(0,colEnd - colStart + 1). 15 | set s to s:replace(" ",char). 16 | 17 | if ret return s. 18 | else print s at (colStart,line). 19 | } 20 | function verticalLineTo { 21 | parameter column,lineStart,lineEnd,char. 22 | local line is lineStart. 23 | until line > lineEnd { 24 | print char at (column,line). 25 | set line to line + 1. 26 | } 27 | } 28 | 29 | // clears an entire line of the terminal 30 | function clearLine { 31 | parameter line,ret is false. 32 | local s is emptyString:substring(0,terminal:width). 33 | 34 | if ret return s. 35 | else print s at (0,line). 36 | } 37 | 38 | // clears a line from columnStart to columnEnd 39 | function clearLineTo { 40 | parameter line,columnStart,columnEnd,ret is false. 41 | local s is emptyString:substring(0,columnEnd-columnStart + 1). 42 | 43 | if ret return s. 44 | else print s at (columnStart,line). 45 | } 46 | 47 | function clearBox { 48 | parameter line,lineEnd,colStart,colEnd. 49 | 50 | until line > lineEnd { 51 | clearLineTo(line,colStart,colEnd). 52 | set line to line + 1. 53 | } 54 | } 55 | 56 | /////////////////////// VECTORS /////////////////////////// 57 | 58 | // vecs_clear(). 59 | function vecs_clear { 60 | if vecs:length > 0 { 61 | for vd in vecs { 62 | set vd:SHOW TO false. 63 | } 64 | vecs:clear. 65 | } 66 | clearvecdraws(). 67 | } 68 | 69 | // set [variable] to vecs_add([position],[vector],[color],[string]). 70 | // returns: list index. 71 | // example: 72 | // Create a vecdraw: 73 | // set velocityVec to vecs_add(ship:position,velocity:orbit,blue,round(velocity:orbit:mag) + " m/s"). 74 | // Update it's starting position: 75 | // set vecs[velocityVec]:start to ship:position. 76 | function vecs_add { 77 | parameter p,v,c,descr,w. 78 | vecs:add(VECDRAWARGS(p, v, c, descr, 1, true,w)). 79 | return vecs:length - 1. 80 | } 81 | 82 | 83 | global vecs is list(). 84 | clearvecdraws(). 85 | 86 | ////////////////////////////////////////////////////////// -------------------------------------------------------------------------------- /lib_geo.ks: -------------------------------------------------------------------------------- 1 | //parameter 1: geoposition 2 | //parameter 2: time in seconds into the future 3 | //returns: A list: 4 | // index 0: geoposition's position relative to ship in t seconds, only remains valid for the time it was called. 5 | // index 1: geoposition's position relative to body in t seconds. The more useful one, as it remains valid. 6 | function geo_posAt { 7 | parameter geopos,t. 8 | local rotang is body:angularvel:mag * (180/constant():pi) * t. //convert to degrees per seconds and multiply by time (in seconds) 9 | local rotdir is angleaxis(rotang,body:angularvel). 10 | local geoposUP is geopos:position - body:position. 11 | local newposUP is rotdir * geoposUP. 12 | local newpos is newposUP + body:position. 13 | 14 | return list(newpos,newposUP). //first is relative to ship (right now), second is relative to body 15 | } 16 | 17 | // parameter 1: Latitude at which to check for orbit itersections. 18 | // returns: A list, where index 0 is a true if intersections were found, and index 1 and 2 contain intersection vectors. Useful for planning landing to specific geopositions. 19 | function geo_lat_intersect { 20 | parameter targetLat. 21 | if abs(targetLat) > obt:inclination and obt:inclination < 90 { 22 | print "ERROR: latitude " + targetLat + " is not possible to reach with orbit!". 23 | local returnlist is list(false). 24 | return returnlist. 25 | } 26 | 27 | local orbnormal is -vcrs(velocity:orbit,obt:position-body:position):normalized. 28 | local bodynormal is body:angularvel:normalized. 29 | local AnDnAxis is vcrs(orbnormal,bodynormal):normalized * body:position:mag. //points to ascending or descending node 30 | if body:geopositionof(angleaxis(90,orbnormal) * AnDnAxis):lat < 0 set AnDnAxis to -AnDnAxis. //Switch to AN in case it is DN 31 | if targetLat < 0 set AnDnAxis to -AnDnAxis. //if target lat is south, start search from DN. 32 | 33 | local crossvec is AnDnAxis. 34 | //local markAnDn is vecs_add(body:position,AnDnAxis,rgb(0,1,0),"AN/DN"). 35 | //local markCross is vecs_add(body:position,crossvec,rgb(0,0,1),"Intercept"). 36 | local returnlist is list(). 37 | returnlist:add(true). 38 | local mode is 0. 39 | until mode = 2 { 40 | local testlat is body:geopositionof(crossvec + body:position):lat. 41 | if abs(testlat - targetLat) < 0.0001 { 42 | set mode to mode + 1. 43 | returnlist:add(crossvec:vec). 44 | set crossvec to angleaxis(0.0003,orbnormal) * crossvec. 45 | } 46 | else { 47 | set crossvec to angleaxis(abs(testlat - targetLat)/50,orbnormal) * crossvec. 48 | //set vecs[markCross]:vec to crossvec. 49 | } 50 | } 51 | 52 | 53 | //local markinc0 is vecs_add(body:position,bodynormal * body:position:mag,rgb(0,1,1),""). 54 | //local markorbnorm is vecs_add(body:position,orbnormal * body:position:mag,rgb(1,0,1),""). 55 | wait 2. 56 | //vecs_clear(). 57 | return returnlist. //relative to body, not ship 58 | } 59 | 60 | 61 | // parameter 1: a geoposition ( ship:GEOPOSITION / body:GEOPOSITIONOF(position) / LATLNG(latitude,longitude) ) 62 | // parameter 2: size/"radius" of the triangle. Small number gives a local normalvector while a larger one will tend to give a more average normalvector. 63 | // returns: Normalvector of the terrain. (Can be used to determine the slope of the terrain.) 64 | function geo_normalvector { 65 | parameter geopos,size_. 66 | set size to max(5,size_). 67 | local center is geopos:position. 68 | local fwd is vxcl(center-body:position,body:angularvel):normalized. 69 | local right is vcrs(fwd,center-body:position):normalized. 70 | local p1 is body:geopositionof(center + fwd * size_ + right * size_). 71 | local p2 is body:geopositionof(center + fwd * size_ - right * size_). 72 | local p3 is body:geopositionof(center - fwd * size_). 73 | 74 | local vec1 is p1:position-p3:position. 75 | local vec2 is p2:position-p3:position. 76 | local normalVec is vcrs(vec1,vec2):normalized. 77 | 78 | //debug vecdraw: local markNormal is vecs_add(center,normalVec * 300,rgb(1,0,1),"slope: " + round(vang(center-body:position,normalVec),1) ). 79 | 80 | return normalVec. 81 | } 82 | 83 | // parameter 1: a geoposition ( ship:GEOPOSITION / body:GEOPOSITIONOF(position) / LATLNG(latitude,longitude) ) 84 | // returns: The surface velocity VECTOR of the geoposition. Combine with :MAG to get the scalar value. 85 | function geo_surface_vel { 86 | parameter geopos. 87 | local pos is geopos:position. 88 | local posVec is pos - body:position. 89 | local eqRadius is vxcl(body:angularvel,posVec):mag. //radius from polar axis 90 | local surf_vel is -vcrs(posVec,body:angularvel). //direction 91 | set surf_vel:mag to (2*constant():pi*eqRadius)/body:rotationperiod. 92 | return surf_vel. //vector with direction and magnitude of geoposition's surface velocity 93 | } 94 | 95 | // parameter 1: A string or index number based on the list below. 96 | // returns: a geoposition 97 | function geo_bookmark { 98 | parameter bookmark. 99 | 100 | 101 | if bookmark = 1 or bookmark = "LAUNCHPAD" or bookmark = "KSC" return LATLNG(-0.0972078822701718, -74.5576864391954). //Kerbal space center 102 | else if bookmark = 2 or bookmark = "RUNWAY E" return LATLNG(-0.0502131096942382, -74.4951289901873). //East 103 | else if bookmark = 3 or bookmark = "RUNWAY W" return LATLNG(-0.0486697432694389, -74.7220377114077). //West 104 | else if bookmark = 4 or bookmark = "VAB" return LATLNG(-0.0967646955755359, -74.6187122587352). //VAB Roof 105 | 106 | else if bookmark = 5 or bookmark = "IKSC" return latlng(20.3926,-146.2514). //inland kerbal space center 107 | else if bookmark = 6 or bookmark = "ISLAND W" return LATLNG(-1.5173500701556, -71.9623911214353). //Island/airfield runway west 108 | else if bookmark = 7 or bookmark = "ISLAND E" return LATLNG(-1.51573303823027, -71.8571463011229).//Island/airfield runway east 109 | else if bookmark = 8 or bookmark = "POOL" return LATLNG(-0.0867719193943464, -74.6609773699654). 110 | //else if bookmark = "" return . 111 | 112 | 113 | else { print "ERROR: geolocation bookmark " + bookmark + " not found!". return latlng(90,0). } 114 | } -------------------------------------------------------------------------------- /lib_list.ks: -------------------------------------------------------------------------------- 1 | // ######################################### 2 | // ############ Scrolling list ############# 3 | 4 | @LAZYGLOBAL on. 5 | runoncepath("lib_UI.ks"). //needed for some terminal drawing functions. 6 | 7 | global list_menu is list(""). 8 | //global lib_list_active is true. 9 | 10 | //declare some vars and default values 11 | local listmenu_dimensions is lexicon( 12 | "startColumn", 0, 13 | "endColumn", 1, 14 | "startLine", 0, 15 | "endLine", 1, 16 | "columns", 1, 17 | "lines", 1 18 | ). 19 | 20 | // important: this must be called after loading this library 21 | function list_position { //parameters: start col, end col, start line, end line. 22 | parameter sc,ec,sl,el. 23 | set listmenu_dimensions["startColumn"] to sc. 24 | set listmenu_dimensions["endColumn"] to ec. 25 | set listmenu_dimensions["startLine"] to sl. 26 | set listmenu_dimensions["endLine"] to el. 27 | 28 | set listmenu_dimensions["columns"] to listmenu_dimensions["endColumn"] - listmenu_dimensions["startColumn"] + 1. 29 | set listmenu_dimensions["lines"] to listmenu_dimensions["endLine"] - listmenu_dimensions["startLine"] + 1. 30 | } 31 | 32 | function add_entry { 33 | parameter str_entry. 34 | list_menu:add(str_entry). 35 | parse_entry(str_entry). 36 | 37 | 38 | 39 | draw_list(). 40 | } 41 | 42 | local print_list is list(). 43 | function parse_list { 44 | print_list:clear. 45 | for entry in list_menu { 46 | parse_entry(entry). 47 | } 48 | } 49 | 50 | local indent is "". 51 | function set_indentation { 52 | parameter length. 53 | set indent to "". 54 | local i is 0. 55 | until i = length { 56 | set indent to indent + " ". 57 | set i to i + 1. 58 | } 59 | } 60 | 61 | function parse_entry { 62 | parameter str. 63 | local words is str:split(" "). 64 | local str_list is list(""). 65 | local i is 0. 66 | for word in words { 67 | if word:length + str_list[i]:length <= listmenu_dimensions["columns"] set str_list[i] to str_list[i] + word + " ". 68 | else { 69 | set i to i + 1. 70 | str_list:add(indent + word + " "). 71 | } 72 | } 73 | str_list:add(""). 74 | 75 | local i is str_list:length - 1. 76 | until i < 0 { 77 | print_list:insert(0,str_list[i]:trimend()). 78 | set i to i - 1. 79 | } 80 | } 81 | 82 | function draw_list { 83 | clearBox(listmenu_dimensions["startLine"],listmenu_dimensions["endLine"],listmenu_dimensions["startColumn"],listmenu_dimensions["endColumn"]). 84 | 85 | local i is 0. 86 | until i = print_list:length or i = listmenu_dimensions["lines"] { 87 | print print_list[i] at (listmenu_dimensions["startColumn"],listmenu_dimensions["startLine"] + i). 88 | set i to i + 1. 89 | } 90 | } -------------------------------------------------------------------------------- /lib_menu.ks: -------------------------------------------------------------------------------- 1 | // For this to work you need to create at least one menu list in this format (note the extra value at the end of numbers!): 2 | // 3 | // local sv is -9.9993134. 4 | // set someMenu to list( 5 | // list("Some text to display", "text"), 6 | // list("_", "line"), 7 | // list("A read-only variable:", "display", { return round(ship:airspeed,1) + " m/s". }), 8 | // list("A number:", "number", { parameter p is sv. if p <> sv set number1 to p. return number1. }, 10), 9 | // list("Editable text:", "string", { parameter p is sv. if p <> sv set string1 to p. return string1. }), 10 | // list("Boolean value:", "bool", { parameter p is sv. if p <> sv toggle bool1. return bool1. }), 11 | // list("An action", "action", { stage. }), 12 | // list("Some other menu", "menu", { return someSubMenu. }), 13 | // list("The parent menu", "backmenu", { return mainMenu. }) 14 | // ). 15 | // 16 | // The first three types are read-only items and can't be selected or changed by the program 17 | // Available types: 18 | // text: 19 | // just displays the name of the item, can print across all columns. 20 | // line: 21 | // makes a horizontal line across the menu using the single character. 22 | // display: 23 | // displays what you return from the anonymous function 24 | // number: 25 | // Can be edited with A/D (in increments) with Q/E altering increment scale. 26 | // Can be replaced by starting to type in a number when the line is selected. Hit enter to apply it. Backspace works too. 27 | // Can be edited by hitting enter with the line selected. 28 | // Needs a get/set anonymous function like shown above. 29 | // Needs the variable to have been declared by you elsewhere in your main program. 30 | // Needs to have a increment multiplier set in it's list as shown above (a value of 10 will make the default increment 10). 31 | // string: 32 | // Can be edited by hitting enter with the line selected. 33 | // Needs a get/set anonymous function like shown above. 34 | // Needs the variable to have been declared by you elsewhere in your main program. 35 | // bool: 36 | // Can be toggled by hitting enter, A, or D 37 | // Needs a get/set anonymous function like shown above. 38 | // Needs the variable to have been declared by you elsewhere in your main program. 39 | // action: 40 | // Runs the anonymous function when you hit enter/D when it is selected 41 | // menu: 42 | // Opens another menu that you will have to link to in the function. 43 | // backmenu: 44 | // exactly like "menu" but this can also be triggered by pressing backspace 45 | 46 | // Controls: 47 | // W/S/UpArrow/DownArrow: navigates the menu 48 | // A/D: Runs commands, increments numbers 49 | // Q/E: Changes number increment scale 50 | // Enter: Runs commands, edits numbers and strings, toggles boolean values. 51 | // Backspace: opens the parent menu if it exists (for submenues) 52 | // Typing a number: When a number is selected, typing a number will start the number editor. Enter or W/S to confirm. 53 | 54 | 55 | 56 | 57 | //lib_menu.ks 58 | @LAZYGLOBAL on. 59 | runoncepath("lib_UI.ks"). //needed for some terminal drawing functions. 60 | 61 | if not (defined startLine) local startLine is 0. //the first menu item will start at this line in the terminal window 62 | if not (defined startColumn) local startColumn is 3. //menu item description starts at this x coordinate, remember to leave some space for the marker on the left 63 | if not (defined nameLength) local nameLength is 16. //how many characters of the menu item names to display 64 | if not (defined valueLength) local valueLength is 12. //how many characters of the menu item values to display 65 | 66 | if not (defined incrOptions) local incrOptions is list (0.01,0.1,1,10,100,1000). // default increment values in ascending order (for incrementing numbers with A/D). Feel free to add or remove steps from this list 67 | 68 | 69 | local incrI is 2. 70 | local typingNumber is false. 71 | local typingString is false. 72 | global selectedLine is 0. 73 | local lineType is "text". 74 | 75 | local dummyMenu is list( 76 | list("","text"), 77 | list("This is a placeholder menu, if you see this you need to","text"), 78 | list("set the activeMenu variable to a menu list of your own","text"), 79 | list("","text"), 80 | list("","action",{ hudtext("It puts the menu in the variable or else it gets the hose again",5, 4, 35, red, false). }) 81 | ). 82 | 83 | // !! activeMenu is a varaible that should contain the list that defines the menu that you want to display !! 84 | if not (defined activeMenu) global activeMenu is dummyMenu. 85 | local lastMenu is activeMenu. 86 | 87 | // ### Drawing stuff to terminal ### 88 | // >> 89 | //draw the menu 90 | function drawAll { 91 | 92 | terminal:input:clear(). //clear inputs for new menus just in case.. 93 | set selectedLine to 0. 94 | set lineType to activeMenu[selectedLine][1]. 95 | 96 | //column starts 97 | set C1 to startColumn. 98 | set C2 to C1 + nameLength. 99 | set C3 to C2 + valueLength. 100 | 101 | clearBox(startLine,startLine + lastMenu:length - 1,C1,C3). //clear the last menu. This won't clear anything else on the terminal 102 | 103 | 104 | local notFoundSelectable is true. 105 | local i is 0. 106 | inputs(). 107 | until i >= activeMenu:length { 108 | if notFoundSelectable and not readOnlyTypes:contains(activeMenu[i][1]) { //skip read only lines 109 | set selectedLine to i. 110 | set notFoundSelectable to false. 111 | } 112 | updateLine(i). 113 | 114 | //debug info about your current menu, uncomment to display it below your menu: 115 | //print activeMenu[i][0] + " = " + activeMenu[i][1] at (1,startLine + activeMenu:length + 2 + i). 116 | 117 | set i to i + 1. 118 | } 119 | drawMarker(). 120 | } 121 | 122 | local refreshTypes is list("number","display","string","bool"). 123 | function refreshAll { //updates all values of the current menu in the terminal 124 | local i is 0. 125 | until i >= activeMenu:length { 126 | if refreshTypes:contains(activeMenu[i][1]) and not((typingNumber or typingString) and i = selectedLine) { 127 | updateLine(i). 128 | } 129 | set i to i + 1. 130 | } 131 | } 132 | 133 | local markerStr is ">> ". 134 | local suffixString is "". 135 | local markerTimer is time:seconds + 900000. 136 | function drawMarker { 137 | print markerStr at (C1-3,startLine + selectedLine). //print the arrow that displays the active selection 138 | 139 | //print relevant information at the end of the current line 140 | if lineType = "number" { 141 | set suffixString to "-+" + incrOptions[incrI] * activeMenu[selectedLine][3]. 142 | print suffixString at (C3 + 1,startLine + selectedLine). 143 | } 144 | else if lineType = "bool" { 145 | set suffixString to activeMenu[selectedLine][2]():tostring(). 146 | print suffixString at (C3 + 1,startLine + selectedLine). 147 | } 148 | else if lineType = "menu" or lineType = "backmenu" { 149 | set suffixString to "Menu". 150 | print suffixString at (C3 + 1,startLine + selectedLine). 151 | } 152 | } 153 | 154 | local typesWithSuffix is list("number","bool","menu","backmenu"). 155 | function clearMarkers { 156 | print " " at (C1 - markerStr:length,startLine + selectedLine). 157 | 158 | if typesWithSuffix:contains(lineType) { 159 | local emptyString is " ". 160 | print emptyString:substring(0,suffixString:length) at (C3 + 1,startLine + selectedLine). 161 | } 162 | } 163 | // << 164 | 165 | // ### Input and value handling ### 166 | // >> 167 | 168 | local readOnlyTypes is list("text","display","line"). 169 | 170 | function inputs { 171 | if typingNumber { //currently recording numbers, so ignore all other commands 172 | updateLine(selectedLine,numberString). 173 | if terminal:input:haschar() { 174 | local inp is terminal:input. 175 | local ch is inp:getchar(). 176 | if ch:tonumber(99) <> 99 or ch = "." or (numberString:length = 0 and ch = "-") { 177 | set numberString to numberstring + ch. 178 | 179 | } 180 | else if ch = inp:backspace { 181 | if numberString:length > 0 set numberString to numberString:remove(numberString:length-1,1). 182 | } 183 | else if ch = inp:enter or ch = "d" or ch = "w" or ch = "s"{ // confirm 184 | set typingNumber to false. 185 | local converted is numberString:tonumber(-9999). 186 | if converted <> -9999 { //valid 187 | updateLine(selectedLine,numberString). 188 | activeMenu[selectedLine][2](converted). //change the actual variable through the function stored in the lex 189 | } 190 | set numberString to "". 191 | } 192 | else if unchar(ch) = 9 { //tab - cancel and revert 193 | set typingNumber to false. 194 | set numberString to "". 195 | } 196 | } 197 | } 198 | else if typingString { //currently recording text 199 | updateLine(selectedLine,stringString). 200 | if terminal:input:haschar() { 201 | local inp is terminal:input. 202 | local ch is inp:getchar(). 203 | 204 | if ch = inp:enter { // confirm 205 | set typingString to false. 206 | updateLine(selectedLine,stringString). 207 | activeMenu[selectedLine][2](stringString). 208 | set stringString to "". 209 | } 210 | else if ch = inp:backspace { 211 | if stringString:length > 0 set stringString to stringString:remove(stringString:length-1,1). 212 | } 213 | else if unchar(ch) = 9 { //tab - cancel and revert 214 | set typingString to false. 215 | set stringString to "". 216 | updateLine(selectedLine). 217 | } 218 | else set stringString to stringString + ch. 219 | } 220 | } 221 | 222 | else if terminal:input:haschar() { //not recording, so enable all other commands 223 | local inp is terminal:input. 224 | local ch is inp:getchar(). 225 | if unchar(ch) = 9 set ch to inp:backspace. 226 | set lineType to activeMenu[selectedLine][1]. 227 | 228 | local oldLine is selectedLine. 229 | if ch = "w" or ch = inp:upcursorone { 230 | clearMarkers(). 231 | 232 | set selectedLine to selectedLine - 1. 233 | if selectedLine < 0 set selectedLine to activeMenu:length - 1. 234 | //until activeMenu[selectedLine][1] <> "text" and activeMenu[selectedLine][1] <> "line" { //skip text lines as they have no values 235 | until not readOnlyTypes:contains(activeMenu[selectedLine][1]) { 236 | set selectedLine to selectedLine - 1. 237 | if selectedLine < 0 set selectedLine to activeMenu:length - 1. 238 | } 239 | 240 | set incrI to 2. 241 | updateLine(oldLine). 242 | } 243 | else if ch = "s" or ch = inp:downcursorone { 244 | clearMarkers(). 245 | set selectedLine to selectedLine + 1. 246 | if selectedLine >= activeMenu:length set selectedLine to 0. 247 | //until activeMenu[selectedLine][1] <> "text" and activeMenu[selectedLine][1] <> "line" { //skip text lines as they have no values 248 | until not readOnlyTypes:contains(activeMenu[selectedLine][1]) { 249 | set selectedLine to selectedLine + 1. 250 | if selectedLine >= activeMenu:length set selectedLine to 0. 251 | } 252 | 253 | set incrI to 2. 254 | updateLine(oldLine). 255 | } 256 | else if ch = "a" or ch = inp:leftcursorone adjust(-1). 257 | else if ch = "d" or ch = inp:rightcursorone adjust(1). 258 | else if ch = "q" { set incrI to max(0,incrI - 1). } 259 | else if ch = "e" { set incrI to min(incrOptions:length - 1,incrI + 1). } 260 | else if lineType = "number" and (ch:tonumber(99) <> 99 or ch = "-" or ch = inp:enter) { 261 | set typingNumber to true. 262 | if ch = inp:enter set numberString to activeMenu[selectedLine][2]():tostring(). 263 | else set numberString to ch. 264 | } 265 | else if ch = inp:enter { 266 | if lineType = "menu" or lineType = "backmenu" or lineType = "bool" or lineType = "action" adjust(0). 267 | else if lineType = "string" { 268 | set stringString to activeMenu[selectedLine][2](). 269 | set typingString to true. 270 | } 271 | //else if lineType = "action" activeMenu[selectedLine][2](). 272 | } 273 | else if ch = inp:backspace { 274 | local i is 0. 275 | until i >= activeMenu:length { //find the first "backmenu" item if it exists and trigger that 276 | if activeMenu[i][1] = "backmenu" { 277 | clearMarkers(). 278 | set selectedLine to i. 279 | adjust(0). 280 | set i to activeMenu:length. 281 | } 282 | set i to i + 1. 283 | } 284 | } 285 | 286 | set lineType to activeMenu[selectedLine][1]. 287 | clearMarkers(). 288 | drawMarker(). 289 | updateLine(selectedLine). 290 | 291 | inp:clear(). 292 | } 293 | 294 | else if time:seconds > markerTimer + 0.2 { 295 | set markerStr to ">> ". 296 | set markerTimer to time:seconds + 900000. 297 | drawMarker(). 298 | } 299 | 300 | } 301 | 302 | local nonPaddedTypes is list("text","action","menu","backmenu"). 303 | set blink to 0. 304 | function updateLine { 305 | parameter line,val is "x". 306 | local nameStr is activeMenu[line][0]. 307 | local valType is activeMenu[line][1]. 308 | 309 | local finalStr is "". 310 | 311 | if nonPaddedTypes:contains(valType) { 312 | set finalStr to nameStr. 313 | } 314 | else if valType = "line" { 315 | set finalStr to "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx". 316 | local tableWidth is C3-C1. 317 | set finalStr to finalStr:substring(0,tableWidth). 318 | set finalStr to finalStr:replace("x",nameStr). 319 | 320 | } 321 | else { 322 | if val = "x" { 323 | set val to activeMenu[line][2](). 324 | //if valType = "number" set val to val:tostring(). 325 | } 326 | 327 | local blinkStr is "". 328 | if (typingNumber or typingString) and line = selectedLine { //blinking cursor when typing in 329 | if blink < 10 set blinkStr to "_". 330 | else set blinkStr to " ". 331 | set blink to blink + 1. 332 | if blink > 20 set blink to 0. 333 | } 334 | 335 | local valStr is "". 336 | 337 | if valType = "bool" { 338 | if val set valStr to "[ X ]". 339 | else set valStr to "[ ]". 340 | } 341 | else if valType = "number" { 342 | //if not typingNumber and val:tonumber(-99.9999) <> -99.9999 and val:tonumber() > 9999 set valStr to round(val:tonumber() / 1000,1) + "K". 343 | 344 | set val to val + blinkStr. 345 | if not typingNumber and abs(val:tonumber()) > 9999 set valStr to round(val:tonumber() / 1000,1) + " K". 346 | else set valStr to val. 347 | 348 | if activeMenu[line]:length >= 5 set valStr to valStr + activeMenu[line][4]. //suffix 349 | } 350 | else if valType = "string" or valType = "display" { 351 | if typingString { 352 | set val to val + blinkStr. 353 | set valStr to val:substring(max(0,val:length - (C3-C2)),min(val:length,C3-C2)). 354 | } 355 | else { 356 | if not val:istype("string") set val to val:tostring(). 357 | set valStr to val:substring(0,min(val:length,C3-C2)). 358 | } 359 | } 360 | set valStr to valStr:padright(C3-C2). 361 | set finalStr to nameStr:padright(C2-C1):substring(0,C2-C1) + valStr. 362 | } 363 | 364 | print finalStr at (C1,startLine + line). 365 | } 366 | 367 | function adjust { 368 | parameter sign. 369 | local func is activeMenu[selectedLine][2]. 370 | set lineType to activeMenu[selectedline][1]. 371 | 372 | set markerStr to "> >". 373 | set markerTimer to time:seconds. 374 | 375 | if lineType = "number" { 376 | func(func() + sign * incrOptions[incrI] * activeMenu[selectedLine][3]). 377 | } 378 | else if lineType = "bool" { 379 | //if sign = -1 func(true). 380 | //else func(false). 381 | func(sign). 382 | 383 | } 384 | else if lineType = "menu" or lineType = "backmenu" { // d 385 | setMenu(func()). 386 | set markerTimer to 0. 387 | } 388 | else if lineType = "action" func(). 389 | 390 | 391 | } 392 | 393 | function setMenu { 394 | parameter menu. 395 | clearMarkers(). 396 | set lastMenu to activeMenu. 397 | set activeMenu to menu. 398 | drawAll(). 399 | set markerTimer to 0. 400 | } 401 | 402 | function boolConvert { 403 | parameter val. 404 | if val = -1 set val to false. 405 | else set val to true. 406 | return val. 407 | } 408 | 409 | // << -------------------------------------------------------------------------------- /lib_rocket_utility.ks: -------------------------------------------------------------------------------- 1 | local e is constant():e. 2 | 3 | // Thanks to Dunbaratu for the two following functions! 4 | function burn_duration { 5 | parameter delta_v_mag, m0 is ship:mass. 6 | 7 | local g0 is 9.802. 8 | 9 | // The ISP of first engine found active: 10 | // (For more accuracy with multiple differing engines, 11 | // some kind of weighted average would be needed.) 12 | local ISP is simple_isp(). 13 | 14 | // mass after burn is done 15 | local m1 is m0*e^(-delta_v_mag / (g0*ISP)). 16 | 17 | // From rocket equation, and definition of ISP: 18 | local burn_dur is (g0*ISP*m0/SHIP:AVAILABLETHRUST)*( 1 - e^(-delta_v_mag/(g0*ISP)) ). 19 | 20 | return list(burn_dur,m1). 21 | } 22 | 23 | function simple_isp { 24 | list engines in engs. 25 | local totalFlow is 0. 26 | local totalThrust is 0. 27 | for eng in engs { 28 | if eng:ignition and not eng:flameout { 29 | set totalflow to totalflow + (eng:availablethrust / eng:isp). 30 | set totalthrust to totalthrust + eng:availablethrust. 31 | } 32 | } 33 | return totalthrust / max(0.1, totalflow). 34 | } 35 | 36 | function half_dv_duration { 37 | parameter deltav_mag. 38 | 39 | local first_half is burn_duration(deltav_mag / 2). 40 | local first_half_duration is first_half[0]. 41 | 42 | // the duration of the second half of the burn, with the adjusted starting mass. 43 | local second_half is burn_duration(deltav_mag / 2, first_half[1]). 44 | 45 | 46 | // return list with: first half of deltaV duration, last half of dV duration, mass after full burn. 47 | return list(first_half_duration,second_half[0],second_half[1]). 48 | } -------------------------------------------------------------------------------- /linetest.ks: -------------------------------------------------------------------------------- 1 | runoncepath("lib_list.ks"). 2 | list_position(0,round(terminal:width*0.75)-1,10,terminal:height-4). 3 | clearscreen. 4 | 5 | local wordlist is list("Lorem","ipsum","dolor", 6 | "sit","amet","consectetur","adipiscing","elit", 7 | "sed","do","eiusmod","tempor","incididunt", 8 | "ut","labore","et","dolore","magna", 9 | "aliqua","nisi"). 10 | 11 | set oldHeight to terminal:height. 12 | set oldWidth to terminal:width. 13 | 14 | function drawlines { 15 | horizontalLine(9,"-"). 16 | verticalLineTo(round(terminal:width*0.75),10,terminal:height - 1,"|"). 17 | horizontalLineTo(terminal:height-3,0,round(terminal:width*0.75),"-"). 18 | } 19 | 20 | print "test". 21 | drawlines(). 22 | 23 | ag1 on. 24 | until false { 25 | if ag1 { 26 | ag1 off. 27 | 28 | local entry_str is "". 29 | local i is 0. 30 | until i > max(2,random() * 80) { 31 | local word is round((wordlist:length-1) * random()). 32 | set entry_str to entry_str + wordlist[word]. 33 | local rand is random(). 34 | if rand <= 0.01 set entry_str to entry_str + "! ". 35 | else if rand <= 0.1 set entry_str to entry_str + ". ". 36 | else if rand <= 0.25 set entry_str to entry_str + ", ". 37 | else set entry_str to entry_str + " ". 38 | set i to i + 1. 39 | } 40 | 41 | add_entry(entry_str:trimend() + "."). 42 | 43 | print "ADDED: " + entry_str at (0,0). 44 | } 45 | 46 | if terminal:height <> oldHeight or terminal:width <> oldWidth { 47 | list_position(0,round(terminal:width*0.75)-1,10,terminal:height-4). 48 | clearscreen. 49 | drawlines(). 50 | parse_list(). 51 | draw_list(). 52 | 53 | set oldHeight to terminal:height. 54 | set oldWidth to terminal:width. 55 | } 56 | 57 | wait 0. 58 | } -------------------------------------------------------------------------------- /menutest.ks: -------------------------------------------------------------------------------- 1 | // Just setting up the terminal 2 | set terminal:brightness to 1. 3 | set terminal:width to 41. 4 | set terminal:height to 30. 5 | clearscreen. 6 | 7 | runoncepath("lib_UI.ks"). 8 | 9 | print "MenuTest.ks - " + ship:name at (1,1). 10 | horizontalLine(2,"="). 11 | //verticalLineTo(40,3,20,"|"). 12 | //horizontalLineTo(21,0,41,"="). 13 | horizontalLine(21,"="). 14 | print "Some other part of the program.." at (1,26). 15 | 16 | 17 | // use the first two of these varables to set the position of the menu. The last two affect the width of the menu. 18 | local startLine is 4. //the first menu item will start at this line in the terminal window 19 | local startColumn is 4. //menu item description starts at this x coordinate, remember to leave some space for the marker on the left 20 | local nameLength is 16. //how many characters of the menu item names to display 21 | local valueLength is 12. //how many characters of the menu item values to display 22 | runpath("lib_menu.ks"). 23 | 24 | 25 | // ################## 26 | // ### The menues ### 27 | 28 | 29 | 30 | // Sentinel value 31 | local sv is -9.9993134. // just a value that is extremely unlikely to be set to any of the varibles we want to change with the menu 32 | 33 | set mainMenu to list( 34 | //list(name,type,get/set function,increment multiplier (for numbers)). 35 | list("A number:", "number", { parameter p is sv. if p <> sv set number1 to p. return number1. }, 10), 36 | list("Throttle:", "number", { parameter p is sv. if p <> sv lock throttle to min(1,max(0,p)). return round(throttle,3). }, 0.1), 37 | list("Speed:", "display", { return round(ship:airspeed) + " m/s". }), 38 | list("[Stage]", "action", { stage. }), 39 | list("", "text"), //just an empty line 40 | list("Ship Name:", "string", { parameter p is sv. if p <> sv and p <> "" set ship:name to p. return ship:name. }), 41 | list("Status:", "display", { return ship:status. }), 42 | list("", "text"), 43 | list("SAS:", "bool", { parameter p is sv. if p <> sv toggle sas. return sas. }), 44 | list("Lights:", "bool", { parameter p is sv. if p <> sv toggle lights. return lights. }), 45 | list("-", "line"), //only use single character strings for "line" 46 | list("[HUDTEXT menu]", "menu", { return hudtextMenu. }), 47 | list("", "text"), 48 | list("[EXIT]", "action", { set done to true. }) 49 | ). 50 | 51 | set hudtextMenu to list( 52 | list("String:", "string", { parameter p is sv. if p <> sv set hudString to p. return hudString. }), 53 | list("Duration:", "number", { parameter p is sv. if p <> sv set hudDuration to p. return hudDuration. }, 1), 54 | list("Style:", "number", { parameter p is sv. if p <> sv set hudStyle to min(4,max(1,round(p))). return hudStyle. }, 1), //hudtext style needs to be an integer between 1 and 4, so we need to round it and clamp it 55 | list("Size:", "number", { parameter p is sv. if p <> sv set hudSize to max(1,round(p)). return hudSize. }, 1), 56 | list("[Color]", "menu", { return colorMenu. }), 57 | list("", "text"), 58 | list("[Show on HUD]", "action", { testFunction(hudString).}), 59 | list("-", "line"), 60 | list("[SUBMENU]", "menu", { return subMenu2. }), 61 | list("[BACK]", "backmenu", { return mainMenu. }) //the backmenu should point back to the parent menu (so when you press backspace the script will know what menu to send you back to) 62 | ). 63 | 64 | set colorMenu to list( 65 | list("Color", "text"), 66 | list(" R:", "number", { parameter p is sv. if p <> sv set hudR to min(1,max(0,round(p,3))). return hudR. }, 0.1), 67 | list(" G:", "number", { parameter p is sv. if p <> sv set hudG to min(1,max(0,round(p,3))). return hudG. }, 0.1), 68 | list(" B:", "number", { parameter p is sv. if p <> sv set hudB to min(1,max(0,round(p,3))). return hudB. }, 0.1), 69 | list("", "text"), 70 | list("[Show on HUD]", "action", { testFunction(hudString).}), 71 | list("=", "line"), 72 | list("[BACK]", "backmenu", { return hudtextMenu. }) 73 | ). 74 | 75 | set subMenu2 to list( 76 | list("Another submenu", "text"), 77 | list("_", "line"), 78 | list("[BACK]", "backmenu", { return hudtextMenu. }), 79 | list("[MAIN MENU]", "menu", { return mainMenu. }) //you don't have to go back to just the previous menu 80 | ). 81 | 82 | // we need to set this variable to the menu we want to display at the start 83 | set activeMenu to mainMenu. 84 | 85 | // ############################################################################ 86 | // ### Variables, functions, etc - that we want our menues to alter/display ### 87 | 88 | local number1 is -12.74. 89 | local testBool is true. 90 | 91 | local hudString is "something..". 92 | local hudDuration is 2. 93 | local hudStyle is 2. 94 | local hudSize is 40. 95 | local hudR is 1. 96 | local hudG is 0.1. 97 | local hudB is 0.75. 98 | 99 | 100 | function testFunction { 101 | parameter s. 102 | hudtext(s,hudDuration, hudStyle, hudSize, rgb(hudR,hudG,hudB), false). 103 | } 104 | 105 | local done is false. 106 | 107 | // ############ 108 | // ### LOOP ### 109 | 110 | drawAll(). //needs to be called once after all of the variables used in the menu have been declared/set. If not the menu won't show until 111 | 112 | until done { 113 | 114 | //you need to call this function in your running loop or in a persistent trigger so that key inputs can be checked. 115 | //Doesn't necessarily need to be run every tick, larger intervals will just cause it to lag a bit more. 116 | inputs(). 117 | 118 | if activeMenu = mainMenu { //if we want to display updated values to a menu (if it is active in this case) 119 | updateLine(2). //the number here is the index number of the menu item, or in other words the line number (starting at 0. 120 | updateLine(6). 121 | } 122 | 123 | wait 0. 124 | } -------------------------------------------------------------------------------- /q.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | //This is the entry point for the quad drone program 3 | 4 | SET CONFIG:STAT TO false. 5 | set terminal:brightness to 1. 6 | 7 | runoncepath("cpu_light.ks"). 8 | setLights(0,0.5,0.5). 9 | 10 | 11 | //now run the damned thing already 12 | 13 | clearguis(). 14 | runoncepath("cam.ks"). 15 | runoncepath("quad/lib_quad.ks"). 16 | runoncepath("quad/lib_json.ks"). 17 | runoncepath("quad/race.ks"). 18 | runoncepath("quad/lib_formation.ks"). 19 | runoncepath("quad/quad_loop.ks"). 20 | runoncepath("quad/quad_GUI.ks"). 21 | print "Running Quad setup..". 22 | set terminal:width to 80. 23 | set terminal:height to 60. 24 | core:doaction("close terminal",true). 25 | 26 | //main program 27 | runpath("quad/quad.ks"). 28 | 29 | 30 | reboot. -------------------------------------------------------------------------------- /quad/lib_formation.ks: -------------------------------------------------------------------------------- 1 | //follower lib, for both slave and master 2 | global Followers is uniqueset(). 3 | global isLeading is false. 4 | global isFollowing is false. 5 | global formationLastUpdate is time:seconds - 1. 6 | global formationTarget is list(0). 7 | 8 | //Message types (from point of view from the reciever): 9 | // 1: Add me as follower (from slave to master) 10 | // 2: Remove me (as master), 11 | // 3: Stop following (as follower) 12 | // 4: Update (as reciever) 13 | 14 | function formationComUpdate { 15 | set shipMessages to ship:messages. 16 | until shipMessages:empty { 17 | set msg to shipMessages:pop. 18 | set cnt to msg:content. 19 | local msgtype is cnt[0]. 20 | 21 | if msgtype = 1 { //add sender as follower 22 | Followers:add(msg:sender). 23 | set isLeading to true. 24 | } 25 | else if msgtype = 2 { 26 | Followers:remove(msg:sender). 27 | if Followers:length = 0 set isLeading to false. 28 | } 29 | else if msgtype = 4 { 30 | set formationLastUpdate to time:seconds. 31 | set formationTarget to cnt. 32 | } 33 | else if msgtype = 5 { 34 | set r_race:pressed to true. //start race mode 35 | msg:sender:connection:sendmessage(list(2)). 36 | } 37 | } 38 | } 39 | 40 | //parameters: 4, 41 | function formationBroadcast { 42 | parameter velocityVec is v(0,0,0), positionVec is v(0,0,0). 43 | 44 | local i is 0. 45 | for f in Followers { 46 | local followerDist is 10 + 10 * floor(i / 2). //the first two 10m, the next two 20m etc 47 | 48 | if mod(i,2) = 0 set followerPos to angleaxis(120,up:vector) * (positionVec * followerDist). 49 | else set followerPos to angleaxis(-120,up:vector) * (positionVec * followerDist). 50 | 51 | f:connection:sendmessage(list(4,velocityVec,followerPos)). 52 | set i to i + 1. 53 | } 54 | } 55 | 56 | function raceBroadcast { 57 | for f in Followers { 58 | f:connection:sendmessage(list(5)). 59 | } 60 | } -------------------------------------------------------------------------------- /quad/lib_json.ks: -------------------------------------------------------------------------------- 1 | function save_json { 2 | local l is lexicon(). 3 | 4 | l:add("forceDock",forceDock). 5 | l:add("autoFuel",autoFuel). 6 | l:add("autoLand",autoLand). 7 | l:add("fuelRate",fuelRate). 8 | //l:add("agressiveChase",agressiveChase). 9 | //l:add("speedlimitmax",speedlimitmax). 10 | 11 | switch to 1. 12 | 13 | local filename is "quad.json". //"0:vessels/" + ship:name + ".json". 14 | WRITEJSON(l, filename). 15 | 16 | switch to 0. 17 | } 18 | 19 | function load_json { 20 | switch to 1. 21 | local filename is "quad.json". //"0:vessels/" + ship:name + ".json". 22 | if exists(filename) { 23 | local lex is readjson(filename). 24 | 25 | 26 | global forceDock is lex["forceDock"]. 27 | global autoFuel is lex["autoFuel"]. 28 | global autoLand is lex["autoLand"]. 29 | global fuelRate is lex["fuelRate"]. 30 | //global agressiveChase is lex["agressiveChase"]. 31 | 32 | if lex["forceDock"] = "True" set forceDock to true. 33 | else if lex["forceDock"] = "False" set forceDock to false. 34 | if lex["autoFuel"] = "True" set autoFuel to true. 35 | else if lex["autoFuel"] = "False" set autoFuel to false. 36 | if lex["autoLand"] = "True" set autoLand to true. 37 | else if lex["autoLand"] = "False" set autoLand to false. 38 | 39 | //if lex["agressiveChase"] = "True" set agressiveChase to true. 40 | //else if lex["agressiveChase"] = "False" set agressiveChase to false. 41 | 42 | //global speedlimitmax is lex["speedlimitmax"]. 43 | //entry("Config file was loaded."). 44 | } 45 | else { 46 | global forceDock is false. 47 | global autoFuel is true. 48 | global autoLand is true. 49 | global fuelRate is 0.1. 50 | } 51 | switch to 0. 52 | } -------------------------------------------------------------------------------- /quad/lib_quad.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | 3 | //modes 4 | global m_hover is 2. 5 | global m_land is 3. 6 | global m_free is 4. 7 | global m_bookmark is 5. 8 | global m_pos is 6. 9 | global m_follow is 7. 10 | global m_patrol is 8. 11 | global m_race is 9. 12 | global m_fuel is 99. 13 | 14 | function mode_string { 15 | if mode = m_hover return "hover". 16 | else if mode = m_land return "landing". 17 | else if mode = m_free return "freeroam". 18 | else if mode = m_pos return "position". 19 | else if mode = m_follow return "following " + tarVeh:name. 20 | else if mode = m_fuel return "refuel". 21 | else if mode = m_patrol return "patrolling". 22 | else if mode = m_race return "in race". 23 | else return "error". 24 | } 25 | 26 | 27 | function dockSearch { 28 | parameter checkPart,originPart. //checkPart is the current part the function is working on, originPart is the part that called it (a child or parent). 29 | set result to core:part. 30 | 31 | for dockpart in core:element:dockingports { 32 | if checkPart = dockpart { set result to checkPart. } //found a match! 33 | } 34 | 35 | if result = core:part { //while this is true, a match hasn't been found yet 36 | if checkPart:hasparent { 37 | if not(checkPart:parent = originPart) { 38 | set tempResult to dockSearch(checkPart:parent,checkPart). 39 | if not(tempResult = core:part) set result to tempResult. //parent returned a match. 40 | } 41 | } 42 | if checkPart:children:length > 0 and result = core:part { 43 | for child in checkPart:children { 44 | if not(child = originPart) and result = core:part { 45 | set tempResult to dockSearch(child,checkPart). 46 | if not(tempResult = core:part) set result to tempResult. //child returned a match. 47 | } 48 | } 49 | } 50 | } 51 | return result. //return the result to the caller (part or initial call from script) 52 | } 53 | 54 | function sortTargets { 55 | local sorted is list(). 56 | list targets in tgs. 57 | 58 | local i is 0. 59 | local limited is false. 60 | 61 | local lowestTarget is 0. 62 | until i = tgs:length or i = 10 { 63 | local isValid is false. 64 | local lowestValue is 100000. 65 | for t in tgs { 66 | local tDistance is t:distance. 67 | if t:body = ship:body and tDistance < lowestValue and not sorted:contains(t) { 68 | set lowestValue to tDistance. 69 | set lowestTarget to t. 70 | set isValid to true. 71 | } 72 | } 73 | set i to i + 1. 74 | 75 | if isValid sorted:add(lowestTarget). 76 | } 77 | return sorted. 78 | } 79 | 80 | function targetStrings { 81 | parameter tgs. //list of vessels 82 | local stringList is list(""). 83 | for t in tgs { 84 | stringList:add(t:name). 85 | } 86 | return stringList. 87 | } 88 | 89 | // parameter 1: A string or index number based on the list below. 90 | // returns: a geoposition 91 | function geo_bookmark { 92 | parameter bookmark. 93 | 94 | 95 | if bookmark = 1 or bookmark = "LAUNCHPAD" or bookmark = "KSC" return LATLNG(-0.0972078822701718, -74.5576864391954). //Kerbal space center 96 | else if bookmark = 2 or bookmark = "RUNWAY E" return LATLNG(-0.0502131096942382, -74.4951289901873). //East 97 | else if bookmark = 3 or bookmark = "RUNWAY W" return LATLNG(-0.0486697432694389, -74.7220377114077). //West 98 | else if bookmark = 4 or bookmark = "VAB" return LATLNG(-0.0967646955755359, -74.6187122587352). //VAB Roof 99 | 100 | else if bookmark = 5 or bookmark = "IKSC" return latlng(20.3926,-146.2514). //inland kerbal space center 101 | else if bookmark = 6 or bookmark = "ISLAND W" return LATLNG(-1.5173500701556, -71.9623911214353). //Island/airfield runway west 102 | else if bookmark = 7 or bookmark = "ISLAND E" return LATLNG(-1.51573303823027, -71.8571463011229).//Island/airfield runway east 103 | else if bookmark = 8 or bookmark = "POOL" return LATLNG(-0.0867719193943464, -74.6609773699654). 104 | //else if bookmark = "" return . 105 | 106 | 107 | else { print "ERROR: geolocation bookmark " + bookmark + " not found!". return latlng(90,0). } 108 | } 109 | 110 | //////////////////// User Interface stuff /////////////////// 111 | function toggleTerVec { 112 | parameter var. 113 | set terMark to var. 114 | 115 | local i is 1. 116 | until i = 6 { 117 | set pm to pList[i]. 118 | set vecs[pm]:show to terMark. 119 | set i to i + 1. 120 | } 121 | } 122 | function toggleVelVec { 123 | parameter var. 124 | set stMark to var. 125 | if submode = m_free { 126 | set vecs[markHorV]:show to true. 127 | set vecs[markDesired]:show to true. 128 | } 129 | else { 130 | set vecs[markHorV]:show to stMark. 131 | set vecs[markDesired]:show to stMark. 132 | } 133 | } 134 | function toggleThrVec { 135 | parameter var. 136 | set thMark to var. 137 | for m in engsLexList { 138 | set m["vd"]:show to thMark. 139 | } 140 | } 141 | function toggleAccVec { 142 | parameter var. 143 | set miscMark to var. 144 | set vecs[markTar]:show to miscMark. 145 | //set vecs[markAcc]:show to miscMark. 146 | } 147 | 148 | function popup { 149 | parameter s. 150 | HUDTEXT(s, 5, 2, 34, yellow, false). 151 | 152 | // context: HUDTEXT( Message, delaySeconds, style, size, colour, boolean doEcho). 153 | //style: - 1 = upper left - 2 = upper center - 3 = lower right - 4 = lower center 154 | } 155 | function warning { 156 | parameter s. 157 | HUDTEXT(s, 5, 2, 36, red, false). 158 | } 159 | 160 | 161 | /////////////////////// VECTORS /////////////////////////// 162 | 163 | // vecs_clear(). 164 | function vecs_clear { 165 | if vecs:length > 0 { 166 | for vd in vecs { 167 | set vd:SHOW TO false. 168 | } 169 | vecs:clear. 170 | } 171 | } 172 | 173 | // set [variable] to vecs_add([position],[vector],[color],[string]). 174 | // returns: list index. 175 | // example: 176 | // Create a vecdraw: 177 | // set velocityVec to vecs_add(ship:position,velocity:orbit,blue,round(velocity:orbit:mag) + " m/s"). 178 | // Update it's starting position: 179 | // set vecs[velocityVec]:start to ship:position. 180 | function vecs_add { 181 | parameter p,v,c,descr,w. 182 | vecs:add(VECDRAWARGS(p, v, c, descr, 1, false,w)). 183 | return vecs:length - 1. 184 | } 185 | global vecs is list(). 186 | if vecs:length > 0 vecs_clear(). 187 | 188 | ////////////////////////////////////////////////////////// 189 | 190 | local c_pi is constant:pi. 191 | function toRad { 192 | parameter n. 193 | return n * (c_pi / 180). 194 | } 195 | function headingOf { 196 | parameter vect. //0 = north, 90 = east 197 | local ang is vang( vxcl(up:vector,vect) , north:vector ). 198 | if vdot(heading(270,0):vector,vect) > 0 set ang to 360 - ang. 199 | return ang. 200 | } 201 | 202 | -------------------------------------------------------------------------------- /quad/race.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | 3 | function listGates { 4 | list targets in all_targets. 5 | set new_list to list(). 6 | set counter to 0. 7 | set c to 0. 8 | until c = all_targets:length { 9 | for target in all_targets { 10 | if target:name = "Gate " + counter { 11 | new_list:ADD(target). 12 | set counter to counter +1. 13 | } 14 | } 15 | set c to c + 1. 16 | } 17 | 18 | global gatesList is new_list. 19 | global gateI is -1. 20 | } 21 | 22 | 23 | function nextGate { 24 | if not(defined vd_gate) global vd_gate to vecdraw( {return v(0,0,0).}, up:vector * -50, rgba(0.1,0.5,0.1,0.6), "", 1, true, 1, true, true). 25 | 26 | set gateI to gateI + 1. 27 | if gateI = gatesList:length set gateI to 0. 28 | global targetGate is gatesList[gateI]. 29 | 30 | local nextI is gateI + 1. 31 | if nextI = gatesList:length set nextI to 0. 32 | global nextTargetGate is gatesList[nextI]. 33 | 34 | global gateLeft is targetGate:partstagged("left")[0]. 35 | global gateRight is targetGate:partstagged("right")[0]. 36 | global gateHeight is max(0,targetGate:geoposition:terrainheight). 37 | set vd_gate:startupdater to { return targetGate:position + up:vector * 60. }. 38 | 39 | if targetGate:rootpart:tag = "corner" set gateCorner to true. 40 | else set gateCorner to false. 41 | 42 | set targetString to targetGate:name. 43 | 44 | 45 | //setting the speed limit through the gate: 46 | 47 | local targetGateFacing is vxcl(upVector,targetGate:facing:vector):normalized. 48 | local nextGateFacing is vxcl(upVector,nextTargetGate:facing:vector):normalized. 49 | 50 | local gateToNextGate is vxcl(upVector,nextTargetGate:position - targetGate:position). 51 | local nextSideDist is vxcl(nextGateFacing,gateToNextGate):mag. 52 | local nextGateBehind is vdot(targetGateFacing,gateToNextGate) < 0. 53 | 54 | 55 | if (nextGateBehind) { 56 | set gateSpeed to sqrt(2*(gateToNextGate:mag / 3)*maxHA). 57 | } 58 | else if (vdot(gateToNextGate, targetGate:facing:starvector) > 0) = (vdot(gateToNextGate, nextTargetGate:facing:starvector) > 0) { //s-turn 59 | local facingAng is vang(targetGateFacing,gateToNextGate). 60 | local nextFacingAng is vang(nextGateFacing,gateToNextGate). 61 | 62 | local midDist is -20 + gateToNextGate:mag / 63 | ( 64 | 1.5 65 | + abs(90 - vang(up:vector, nextTargetGate:position - targetGate:position))/10 //lower speed with height slope 66 | + (facingAng + nextFacingAng)/30 //lower speed with more total angle of the two turns in the s turn 67 | ). 68 | set gateSpeed to sqrt(2 * max(0.1,midDist) * maxHA). 69 | 70 | popup("S-turn SL: " + round(gateSpeed) + "m/s"). 71 | } 72 | else { 73 | set nextGateSideVec to vcrs(upVector,nextGateFacing):normalized. //vector pointing out from the gate's *right* side 74 | if vang(nextGateSideVec,vxcl(upVector,targetGate:position - nextTargetGate:position)) < 90 set nextGateSideVec to -nextGateSideVec. 75 | 76 | //set nextSideDist to nextSideDist / (1 + abs(90 - vang(up:vector, nextTargetGate:position - targetGate:position))/40). //lower speed with height slope 77 | 78 | 79 | local gateSideSpeed is sqrt(2*nextSideDist*maxHA). 80 | set nextSideDist to max(1,nextSideDist - gateSideSpeed * 0.5). //assume 0.5 second is used for orienting drone 81 | set gateSideSpeed to sqrt(2*nextSideDist*maxHA). 82 | global gateSpeed is gateSideSpeed / max(0.01,vdot(targetGateFacing,nextGateSideVec)). 83 | 84 | } 85 | 86 | 87 | 88 | 89 | 90 | //if vdot(targetGateFacing,gateToNextGate) < 0 set gateSpeed to 20 + gateToNextGate:mag/20. //next gate behind current one 91 | 92 | set gateToNextGateOffset to gateToNextGate - nextGateFacing * min(400,gateToNextGate:mag/3).//min(min(400,abs(vdot(vcrs(upVector,targetGateFacing):normalized,gateToNextGate * 2))),gateToNextGate:mag/3). 93 | 94 | global angleToNextGate is vang(targetGateFacing,gateToNextGateOffset ). 95 | 96 | global maxApproachAngle is min(30,angleToNextGate). 97 | if targetGate:rootpart:tag = "straight" set maxApproachAngle to 0.5. 98 | if vdot(vcrs(upVector,targetGateFacing):normalized,gateToNextGateOffset) < 0 set maxApproachAngle to -maxApproachAngle. 99 | 100 | set tempFacing to angleaxis(maxApproachAngle, upVector) * targetGateFacing. 101 | set gateDistVecOld to gateToNextGate. 102 | 103 | 104 | 105 | set gateSpeed to max(30,min(340,gateSpeed)). 106 | if gateCorner set gateSpeed to min(30,gateSpeed). 107 | 108 | //set destinationLabel to targetString. 109 | 110 | //if kuniverse:activevessel = ship set target to targetGate. 111 | 112 | //GUI 113 | set g_race_gate:text to "Gate " + (gateI + 1) + "/" + gatesList:length. 114 | set g_race_gatespeed:text to "Speedlimit: " + round(gateSpeed) + " m/s". 115 | 116 | if defined raceLapStart and gateI = 1 and raceLapStart > 0 { 117 | set raceLaps to raceLaps + 1. 118 | local laptime is round(time:seconds - raceLapStart,2). 119 | if laptime < fastestLapTime and raceLaps > 1 { 120 | HUDTEXT("Completed lap at " + laptime + "s (-" + round(fastestLapTime - laptime,2) + "s)", 5, 2, 34, green, false). 121 | set fastestLapTime to laptime. 122 | entry("New fastest lap: " + laptime + "s"). 123 | } 124 | else if raceLaps > 1 { 125 | HUDTEXT("Completed lap at " + laptime + "s (+" + round(laptime - fastestLapTime,2) + "s)", 5, 2, 34, red, false). 126 | } 127 | else { 128 | popup("Completed lap at " + laptime + "s"). 129 | set fastestLapTime to laptime. 130 | } 131 | 132 | set g_race_laptime:text to "Laptime: " + laptime + "s". 133 | //raceLapsList:add(laptime). 134 | set raceLapStart to time:seconds. 135 | 136 | local lapFuelRate is max(0.0001,lastLapFuel-fuel)/laptime. 137 | if (fuel/lapFuelRate) < (20 + 1.1 * laptime) and autoFuel brakes on. //refuel 138 | set lastLapFuel to fuel. 139 | } 140 | else if gateI = 1 { 141 | global raceLapStart is time:seconds. 142 | global lastLapFuel is fuel. 143 | } 144 | } 145 | 146 | function detectIntersect { 147 | local result is false. 148 | 149 | if gateDist < 10 { 150 | if vdot(h_vel:normalized,gateDistVec) < 2 { 151 | set sideVec to vcrs(h_vel,upVector):normalized. 152 | if vdot(-sideVec,gateRight:position) > 0 and vdot(sideVec,gateLeft:position) > 0 { 153 | set result to true. 154 | } 155 | } 156 | } 157 | return result. 158 | } 159 | // -------------------------------------------------------------------------------- /rs.ks: -------------------------------------------------------------------------------- 1 | //rs.ks 2 | 3 | clearvecdraws(). 4 | run lib_quad. 5 | ag1 off. ag2 off. ag10 off. 6 | 7 | 8 | 9 | list engines in engs. 10 | local yawRotatrons is list(). 11 | local i is 0. 12 | for eng in engs { 13 | if not(eng:ignition) { eng:activate(). wait 0. } 14 | vecs_add(eng:position,eng:facing:vector * eng:thrust,red,"",0.2). 15 | set eng:thrustlimit to 0. 16 | set vecs[i]:show to true. 17 | 18 | for moduleStr in eng:parent:modules { 19 | if moduleStr = "MuMechToggle" { 20 | local rot is eng:parent:getmodule("MuMechToggle"). 21 | if rot:hasfield("Rotation") { 22 | rot:setfield("Acceleration",50). 23 | yawRotatrons:add(rot). 24 | } 25 | } 26 | } 27 | 28 | if vdot(facing:starvector,eng:position) < -0.3 { set eng_roll_pos to eng. } 29 | else if vdot(facing:starvector,eng:position) > 0.3 { set eng_roll_neg to eng. } 30 | else if vdot(facing:vector,eng:position) < -0.3 { set eng_pitch_pos to eng. } 31 | else if vdot(facing:vector,eng:position) > 0.3 { set eng_pitch_neg to eng. } 32 | 33 | 34 | set i to i + 1. 35 | } 36 | 37 | if yawRotatrons:length = 2 or yawRotatrons:length = 4 { 38 | //entry("Found " + yawRotatrons:length + " servos attached to engines."). 39 | //entry("Yaw control enabled."). 40 | set yawControl to true. 41 | wait 0.2. 42 | } 43 | else set yawControl to false. 44 | 45 | // Vecdraws ----------------------------------------------------------- 46 | 47 | local targetVec is up:forevector. 48 | local targetVecStar is v(0,0,0). 49 | local targetVecTop is v(0,0,0). 50 | local markTar is vecs_add(v(0,0,0),v(0,0,0),cyan,"",0.2). 51 | //local markTarP is vecs_add(v(0,0,0),v(0,0,0),cyan,"TP"). 52 | //local markTarY is vecs_add(v(0,0,0),v(0,0,0),cyan,"TY"). 53 | 54 | set prediction_span to 2. //seconds to check for terrain interesect 55 | set prediction_i to 5. //checks per second 56 | local pList is list(). //terrain prediction vecs 57 | pList:add(0). 58 | local i is 1. 59 | until i > prediction_span * prediction_i { 60 | pList:add(vecs_add(v(0,0,0),v(0,0,0),rgb(1,0,0.0),"",0.2)). 61 | set i to i + 1. 62 | } 63 | 64 | set timerFlying to time:seconds. 65 | set inAir to false. 66 | 67 | set vecs[markTar]:show to true. 68 | 69 | 70 | 71 | function updateVec { 72 | parameter targetVec. 73 | set targetVecStar to vxcl(facing:vector, targetVec). 74 | set targetVecTop to vxcl(facing:starvector, targetVec). 75 | set vecs[markTar]:vec to targetVec*5. 76 | 77 | //set vecs[markTarP]:vec to targetVecTop*5. 78 | //set vecs[markTarY]:vec to targetVecStar*5. 79 | } 80 | // EO vecdraws --------------------------------------------------------- 81 | 82 | function flightcontroller { 83 | set gravity to -up:vector * (body:mu / body:position:mag^2). 84 | 85 | if not(ship:status = "LANDED") { 86 | if not(inAir) { //first tick in air 87 | set timerFlying to time:seconds. 88 | } 89 | set inAir to true. 90 | } 91 | else { 92 | if inAir { //first tick landed 93 | 94 | local impactV is vdot(-shipNormal, old_vel). 95 | if impactV > 10 { 96 | 97 | HUDTEXT("Impact velocity: " + round(impactV,1) + "m/s", 5, 2, 40, rgb(255,200,0), false). 98 | 99 | HUDTEXT("Pitch error: " + round(pitch_err,1), 5, 2, 35, yellow, false). 100 | HUDTEXT(" Roll error: " + round(roll_err,1), 5, 2, 35, yellow, false). 101 | HUDTEXT(" Yaw error: " + round(roll_err,1), 5, 2, 35, yellow, false). 102 | 103 | } 104 | } 105 | set inAir to false. 106 | } 107 | 108 | inputs(). 109 | set shipNormal to geo_normalvector(ship:geoposition,5). 110 | if vang(ship:facing:topvector,shipNormal) > 5 set tilting to true. 111 | else set tilting to false. 112 | 113 | if inAir { 114 | set predictedPos to ship:position. 115 | set old_vel to ship:velocity:surface. 116 | set vel to ship:velocity:surface. 117 | local i is 1. 118 | local hasIntersected is false. 119 | until i > prediction_span * prediction_i { 120 | set predictedPos to predictedPos + (vel + 0.5 * gravity)/prediction_i. 121 | set vel to vel + gravity/prediction_i. 122 | 123 | set curGeo to body:geopositionof(predictedPos). 124 | 125 | set pm to pList[i]. 126 | set terPos to curGeo:position. 127 | set vecs[pm]:start to terPos. 128 | set vecs[pm]:vec to predictedPos - terPos. 129 | if hasIntersected { 130 | set vecs[pm]:show to false. 131 | } 132 | else if vdot(up:vector,predictedPos - terPos) > 0 and not(i = prediction_span * prediction_i) { 133 | set vecs[pm]:show to true. 134 | } 135 | else if hasIntersected = false { 136 | set hasIntersected to true. 137 | set targetVec to geo_normalvector(curGeo,5). 138 | set vecs[markTar]:start to terPos. 139 | set vecs[pm]:show to false. 140 | } 141 | else if i = prediction_span * prediction_i { //last iteration 142 | set targetVec to geo_normalvector(curGeo,5). 143 | set vecs[markTar]:start to terPos. 144 | set vecs[pm]:show to false. 145 | } 146 | else set vecs[pm]:show to false. 147 | 148 | set i to i + 1. 149 | } 150 | } 151 | else { 152 | set targetVec to shipNormal. 153 | set vecs[markTar]:start to ship:geoposition:position. 154 | 155 | for pm in pList { 156 | set vecs[pm]:show to false. 157 | } 158 | } 159 | updateVec(targetVec). 160 | 161 | // ---------------------------------------------- 162 | // engine balancing 163 | 164 | set pitch_err to vdot(facing:vector, targetVecTop). 165 | set roll_err to vdot(facing:starvector, targetVecStar). 166 | 167 | set pitch_vel_target to pitch_err * 2. 168 | set roll_vel_target to roll_err * 2. 169 | set pitch_vel to -vdot(facing:starvector, ship:angularvel). 170 | set roll_vel to vdot(facing:vector, ship:angularvel). 171 | 172 | set pitch_distr to PD_seek(PID_pitch, pitch_vel_target, -pitch_vel). //returns 0-100 173 | set roll_distr to PD_seek(PID_roll, roll_vel_target, -roll_vel). 174 | 175 | if inAir or tilting { 176 | set eng_pitch_pos:thrustlimit to max(0, pitch_distr). 177 | set eng_pitch_neg:thrustlimit to max(0, -pitch_distr). 178 | set eng_roll_pos:thrustlimit to max(0, roll_distr). 179 | set eng_roll_neg:thrustlimit to max(0, -roll_distr). 180 | } 181 | else { 182 | set eng_pitch_pos:thrustlimit to 0. 183 | set eng_pitch_neg:thrustlimit to 0. 184 | set eng_roll_pos:thrustlimit to 0. 185 | set eng_roll_neg:thrustlimit to 0. 186 | } 187 | 188 | local i is 0. 189 | until i = 4 { 190 | set vecs[i]:vec to engs[i]:facing:vector * engs[i]:thrustlimit/60. 191 | set vecs[i]:start to engs[i]:position. 192 | local c is rgb(255,200*((100 - engs[i]:thrustlimit)/100),0). 193 | set vecs[i]:color to c. 194 | set i to i + 1. 195 | } 196 | 197 | 198 | //----------------------------------------------- 199 | // yaw control 200 | if yawControl and not ag2 and time:seconds > timerFlying + 1 { 201 | local vel is vxcl(targetVec,ship:velocity:surface). 202 | local front is vxcl(targetVec,facing:vector). 203 | global roll_err is vang(vel,front). 204 | if vdot(-facing:starvector,vel) < 0 set roll_err to -1 * roll_err. 205 | 206 | set yawAngVel to vdot(facing:topvector, ship:angularvel). 207 | set yawAngVel to yawAngVel * (180/constant:pi()). 208 | 209 | 210 | 211 | 212 | if abs(roll_err) > 2 set roll_vel_target to -3 * (abs(roll_err)^0.7) * (roll_err/abs(roll_err)). 213 | //else set targetRot to -1 * min(20,sqrt(abs(yawAngVel)) * 5). 214 | else set roll_vel_target to 0. 215 | 216 | set yaw_rotation to PD_seek(PID_roll, roll_vel_target, yawAngVel). 217 | if pitch_err > 5 * (constant:pi()/180) or roll_err > 5 * (constant:pi()/180) or not(inAir) set yaw_rotation to 0. 218 | 219 | print "roll_err abs: " + round(roll_err) + " " at (1,terminal:height-5). 220 | print "yawAngVel : " + round(yawAngVel,2) + " " at (1,terminal:height-4). 221 | 222 | print "roll_vel_target: " + round(roll_vel_target,2) + " " at (1,terminal:height-2). 223 | print "yaw_rotation : " + round(yaw_rotation,2) + " " at (1,terminal:height-1). 224 | 225 | for servo in addons:ir:allservos { 226 | servo:moveto(yaw_rotation,1000). 227 | if abs(yaw_rotation) > 0 and abs(servo:position) > 0 and inAir { 228 | set servo:part:children[0]:thrustlimit to 10 + abs(servo:position). 229 | } 230 | } 231 | 232 | } 233 | // ----------------------------------- 234 | 235 | wait 0. 236 | } 237 | 238 | //function that checks for user key input 239 | function inputs { 240 | if ag10 { 241 | ag10 off. 242 | set exit to true. 243 | } 244 | } 245 | 246 | // parameter 1: a geoposition ( ship:GEOPOSITION / body:GEOPOSITIONOF(position) / LATLNG(latitude,longitude) ) 247 | // parameter 2: size/"radius" of the triangle. Small number gives a local normalvector while a larger one will tend to give a more average normalvector. 248 | // returns: Normalvector of the terrain. (Can be used to determine the slope of the terrain.) 249 | function geo_normalvector { 250 | parameter geopos,size_. 251 | set size to max(5,size_). 252 | local center is geopos:position. 253 | local fwd is vxcl(center-body:position,body:angularvel):normalized. 254 | local right is vcrs(fwd,center-body:position):normalized. 255 | local p1 is body:geopositionof(center + fwd * size_ + right * size_). 256 | local p2 is body:geopositionof(center + fwd * size_ - right * size_). 257 | local p3 is body:geopositionof(center - fwd * size_). 258 | 259 | local vec1 is p1:position-p3:position. 260 | local vec2 is p2:position-p3:position. 261 | local normalVec is vcrs(vec1,vec2):normalized. 262 | 263 | //debug vecdraw: local markNormal is vecs_add(center,normalVec * 300,rgb(1,0,1),"slope: " + round(vang(center-body:position,normalVec),1) ). 264 | 265 | return normalVec. 266 | } 267 | 268 | // PID controllers ----------------------------------- 269 | global PID_pitch is PD_init(200.0,10,-100,100). 270 | global PID_roll is PD_init(200.0,10,-100,100). 271 | 272 | global PID_roll is PD_init(2.0,0,-90,90). 273 | 274 | 275 | // main controller loop ------------------------------ 276 | print "Rover stability assist is running!". 277 | set exit to false. 278 | 279 | until exit { 280 | flightcontroller(). 281 | } 282 | 283 | //---------------------------------------------------- 284 | //EXIT 285 | 286 | vecs_clear(). 287 | clearvecdraws(). 288 | for eng in engs { 289 | eng:shutdown(). 290 | } 291 | 292 | if yawControl { 293 | for rotMod in yawRotatrons { 294 | rotMod:doaction("move +",false). rotMod:doaction("move -",false). 295 | } 296 | } 297 | unlock throttle. 298 | set ship:control:pilotmainthrottle to 0. -------------------------------------------------------------------------------- /steeringeditor.ks: -------------------------------------------------------------------------------- 1 | @LAZYGLOBAL on. 2 | clearscreen. 3 | 4 | runoncepath("lib_UI.ks"). //This library contains some functions to format the terminal 5 | 6 | //These are related to loading and saving the settings to the archive (based on craft name) 7 | runoncepath("steeringmanager.ks"). 8 | if loadSteering() HUDTEXT("Loaded steeringmanager settings from 0:/json/" + ship:name + "/steering.json",15,2,25,yellow,false). 9 | else HUDTEXT("No steeringmanager settings found. Using default values",8,2,25,yellow,false). 10 | 11 | //Example variables 12 | local targetHeading is 90. 13 | local testBool is true. 14 | local testNumber is 10. 15 | 16 | 17 | //Setting up the menus: 18 | // use the first two of these varables to set the position of the menu. The last two affect the width of the menu. 19 | global startLine is 1. //the first menu item will start at this line in the terminal window 20 | global startColumn is 4. //menu item description starts at this x coordinate, remember to leave some space for the marker on the left (so minimum value should be 4) 21 | global nameLength is 22. //how many characters of the menu item names to display 22 | global valueLength is 20. //how many characters of the menu item values to display 23 | global sv is -9.9993134. // just a value that is extremely unlikely to be set to any of the varibles we want to change with the menu 24 | set terminal:width to max(terminal:width,startColumn + nameLength + valueLength + 4). 25 | 26 | set mainMenu to list( 27 | list("This is the main menu", "text"), 28 | list("Altitude:", "display", { return round(altitude). }), 29 | list("-", "line"), 30 | list("Ship name:", "string", { parameter p is sv. if p <> sv set ship:name to p. return ship:name. }), 31 | list("Test bool:", "bool", { parameter p is sv. if p <> sv set testBool to boolConvert(p). return testBool. }), 32 | list("", "text"), 33 | list("Heading:", "number", { parameter p is sv. if p <> sv { 34 | if p > 360 set p to p - 360. 35 | else if p < 0 set p to 360 + p. 36 | set targetHeading to p. 37 | } 38 | return round(targetHeading,2). }, 10), 39 | list("-", "line"), 40 | list("[>] Steeringmanager", "menu" , { return steeringMenu. }), 41 | list("[X] Exit", "action", { set done to true. }) 42 | ). 43 | 44 | set steeringMenu to list( 45 | list("[>] Angular Velocity PID", "menu", { return pidMenu. }), 46 | list("-", "line"), 47 | list("Pitch settling time:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchts to max(0.01,round(p,2)). return steeringmanager:pitchts. }, 0.1), 48 | list("Yaw settling time:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawts to max(0.01,round(p,2)). return steeringmanager:yawts. }, 0.1), 49 | list("Roll settling time:", "number", { parameter p is sv. if p <> sv set steeringmanager:rollts to max(0.01,round(p,2)). return steeringmanager:rollts. }, 0.1), 50 | list("", "text"), 51 | list("Max stopping time:", "number", { parameter p is sv. if p <> sv set steeringmanager:maxstoppingtime to max(0.01,round(p,2)). return steeringmanager:maxstoppingtime. }, 0.1), 52 | list("Roll ctrl ang range:", "number", { parameter p is sv. if p <> sv set steeringmanager:rollcontrolanglerange to round(p,2). return steeringmanager:rollcontrolanglerange. }, 1), 53 | list("", "text"), 54 | list("Angle error:", "display", { return round(steeringmanager:angleerror,2). }), 55 | list("Pitch error:", "display", { return round(steeringmanager:pitcherror,2). }), 56 | list("Yaw error:", "display", { return round(steeringmanager:yawerror,2). }), 57 | list("Roll error:", "display", { return round(steeringmanager:rollerror,2). }), 58 | list("-", "line"), 59 | list("Pitch torq adjust:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchtorqueadjust to round(p,2). return steeringmanager:pitchtorqueadjust. }, 1), 60 | list("Pitch torq factor:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchtorquefactor to max(0.01,round(p,2)). return steeringmanager:pitchtorquefactor. }, 0.1), 61 | list("", "text"), 62 | list("Yaw torq adjust:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawtorqueadjust to round(p,2). return steeringmanager:yawtorqueadjust. }, 1), 63 | list("Yaw torq factor:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawtorquefactor to max(0.01,round(p,2)). return steeringmanager:yawtorquefactor. }, 0.01), 64 | list("", "text"), 65 | list("Roll torq adjust:", "number", { parameter p is sv. if p <> sv set steeringmanager:rolltorqueadjust to round(p,2). return steeringmanager:rolltorqueadjust. }, 1), 66 | list("Roll torq factor:", "number", { parameter p is sv. if p <> sv set steeringmanager:rolltorquefactor to max(0.01,round(p,2)). return steeringmanager:rolltorquefactor. }, 0.01), 67 | list("-", "line"), 68 | list("Facing vecs:", "bool", { parameter p is sv. if p <> sv set steeringmanager:showfacingvectors to boolConvert(p). return steeringmanager:showfacingvectors. }), 69 | list("Angular vecs:", "bool", { parameter p is sv. if p <> sv set steeringmanager:showangularvectors to boolConvert(p). return steeringmanager:showangularvectors. }), 70 | list("Write CSV files:", "bool", { parameter p is sv. if p <> sv set steeringmanager:writecsvfiles to boolConvert(p). return steeringmanager:writecsvfiles. }), 71 | list("-", "line"), 72 | list("[ ] REVERT CHANGES", "action", { loadSteering(). }), 73 | list("", "text"), 74 | list("[ ] SAVE CHANGES", "action", { saveSteering(). }), 75 | list("[<] MAIN MENU", "backmenu", { return mainMenu. }) 76 | ). 77 | 78 | set pidMenu to list( 79 | list("Pitch kP:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchpid:kp to max(0,round(p,3)). return steeringmanager:pitchpid:kp. }, 0.1), 80 | list("Pitch kI:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchpid:ki to max(0,round(p,3)). return steeringmanager:pitchpid:ki. }, 0.1), 81 | list("Pitch kD:", "number", { parameter p is sv. if p <> sv set steeringmanager:pitchpid:kd to max(0,round(p,3)). return steeringmanager:pitchpid:kd. }, 0.1), 82 | list("Setpoint:", "display", { return round(steeringmanager:pitchpid:setpoint,2). }, 1), 83 | list("Error:", "display", { return round(steeringmanager:pitchpid:error,2). }, 1), 84 | list("Output:", "display", { return round(steeringmanager:pitchpid:output,2). }, 1), 85 | list("-", "line"), 86 | list("Yaw kP:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawpid:kp to max(0,round(p,3)). return steeringmanager:yawpid:kp. }, 0.1), 87 | list("Yaw kI:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawpid:ki to max(0,round(p,3)). return steeringmanager:yawpid:ki. }, 0.1), 88 | list("Yaw kD:", "number", { parameter p is sv. if p <> sv set steeringmanager:yawpid:kd to max(0,round(p,3)). return steeringmanager:yawpid:kd. }, 0.1), 89 | list("Setpoint:", "display", { return round(steeringmanager:yawpid:setpoint,2). }, 1), 90 | list("Error:", "display", { return round(steeringmanager:yawpid:error,2). }, 1), 91 | list("Output:", "display", { return round(steeringmanager:yawpid:output,2). }, 1), 92 | list("-", "line"), 93 | list("Roll kP:", "number", { parameter p is sv. if p <> sv set steeringmanager:rollpid:kp to max(0,round(p,3)). return steeringmanager:rollpid:kp. }, 0.1), 94 | list("Roll kI:", "number", { parameter p is sv. if p <> sv set steeringmanager:rollpid:ki to max(0,round(p,3)). return steeringmanager:rollpid:ki. }, 0.1), 95 | list("Roll kD:", "number", { parameter p is sv. if p <> sv set steeringmanager:rollpid:kd to max(0,round(p,3)). return steeringmanager:rollpid:kd. }, 0.1), 96 | list("Setpoint:", "display", { return round(steeringmanager:rollpid:setpoint,2). }, 1), 97 | list("Error:", "display", { return round(steeringmanager:rollpid:error,2). }, 1), 98 | list("Output:", "display", { return round(steeringmanager:rollpid:output,2). }, 1), 99 | list("-", "line"), 100 | list("[ ] Reset PIDs", "action", { steeringmanager:resetpids(). }), 101 | list("[ ] REVERT CHANGES", "action", { loadSteering(). }), 102 | list("", "text"), 103 | list("[ ] SAVE CHANGES", "action", { saveSteering(). }), 104 | list("[<] BACK", "backmenu", { return steeringMenu. }) 105 | ). 106 | 107 | set activeMenu to mainMenu. 108 | runpath("lib_menu.ks"). 109 | drawAll(). 110 | 111 | local done is false. 112 | until done { 113 | inputs(). //this function captures user inputs to the terminal 114 | 115 | //other logic 116 | //.... 117 | 118 | refreshAll(). //this function updates the display of all variables in the currently open menu 119 | wait 0. 120 | } -------------------------------------------------------------------------------- /steeringmanager.ks: -------------------------------------------------------------------------------- 1 | 2 | 3 | function saveSteering { 4 | 5 | local lex is lexicon( 6 | "pitchts", steeringmanager:pitchts, 7 | "yawts", steeringmanager:yawts, 8 | "rollts", steeringmanager:rollts, 9 | "maxstoppingtime", steeringmanager:maxstoppingtime, 10 | "rollcontrolanglerange", steeringmanager:rollcontrolanglerange, 11 | "pitchtorqueadjust", steeringmanager:pitchtorqueadjust, 12 | "pitchtorquefactor", steeringmanager:pitchtorquefactor, 13 | "yawtorqueadjust", steeringmanager:yawtorqueadjust, 14 | "yawtorquefactor", steeringmanager:yawtorquefactor, 15 | "rolltorqueadjust", steeringmanager:rolltorqueadjust, 16 | "rolltorquefactor", steeringmanager:rolltorquefactor, 17 | "pitchpid:kp", steeringmanager:pitchpid:kp, 18 | "pitchpid:ki", steeringmanager:pitchpid:ki, 19 | "pitchpid:kd", steeringmanager:pitchpid:kd, 20 | "yawpid:kp", steeringmanager:yawpid:kp, 21 | "yawpid:ki", steeringmanager:yawpid:ki, 22 | "yawpid:kd", steeringmanager:yawpid:kd, 23 | "rollpid:kp", steeringmanager:rollpid:kp, 24 | "rollpid:ki", steeringmanager:rollpid:ki, 25 | "rollpid:kd", steeringmanager:rollpid:kd 26 | ). 27 | 28 | local filePath is path("0:/json/" + ship:name + "/steering.json"). 29 | writejson(lex, filePath). 30 | } 31 | 32 | function loadSteering { 33 | local filePath is path("0:/json/" + ship:name + "/steering.json"). 34 | 35 | if exists(filePath) { 36 | local lex is readjson(filePath). 37 | 38 | set steeringmanager:pitchts to lex["pitchts"]. 39 | set steeringmanager:yawts to lex["yawts"]. 40 | set steeringmanager:rollts to lex["rollts"]. 41 | set steeringmanager:maxstoppingtime to lex["maxstoppingtime"]. 42 | set steeringmanager:rollcontrolanglerange to lex["rollcontrolanglerange"]. 43 | set steeringmanager:pitchtorqueadjust to lex["pitchtorqueadjust"]. 44 | set steeringmanager:pitchtorquefactor to lex["pitchtorquefactor"]. 45 | set steeringmanager:yawtorqueadjust to lex["yawtorqueadjust"]. 46 | set steeringmanager:yawtorquefactor to lex["yawtorquefactor"]. 47 | set steeringmanager:rolltorqueadjust to lex["rolltorqueadjust"]. 48 | set steeringmanager:rolltorquefactor to lex["rolltorquefactor"]. 49 | set steeringmanager:pitchpid:kp to lex["pitchpid:kp"]. 50 | set steeringmanager:pitchpid:ki to lex["pitchpid:ki"]. 51 | set steeringmanager:pitchpid:kd to lex["pitchpid:kd"]. 52 | set steeringmanager:yawpid:kp to lex["yawpid:kp"]. 53 | set steeringmanager:yawpid:ki to lex["yawpid:ki"]. 54 | set steeringmanager:yawpid:kd to lex["yawpid:kd"]. 55 | set steeringmanager:rollpid:kp to lex["rollpid:kp"]. 56 | set steeringmanager:rollpid:ki to lex["rollpid:ki"]. 57 | set steeringmanager:rollpid:kd to lex["rollpid:kd"]. 58 | 59 | return true. 60 | } 61 | else return false. 62 | } -------------------------------------------------------------------------------- /turret.ks: -------------------------------------------------------------------------------- 1 | set config:ipu to 4000. 2 | run cam. 3 | clearvecdraws(). 4 | 5 | set tracking to false. 6 | set camera_focus to false. 7 | set camera_spin to false. 8 | set kill_all to false. 9 | set shoot_distance to 2000. 10 | local missileDetectionRange is 1400. 11 | 12 | // ### GUI 13 | clearguis(). 14 | 15 | local g is gui(280). 16 | set g:x to 4. 17 | set g:y to 37. 18 | set g:style:padding:h to 5. 19 | set g:style:padding:v to 5. 20 | set g:skin:font to "Nimbus Mono". 21 | 22 | local title is g:addhlayout(). 23 | set title:style:margin:top to 0. 24 | local title_label is title:addlabel("[T] - " + ship:name + ""). 25 | set title_label:style:fontsize to 14. 26 | //set title_label:style:font to "Nimbus Mono Bold". 27 | set title_label:style:margin:h to 2. 28 | set title_label:style:margin:v to 0. 29 | local g_enabled is title:addcheckbox("",tracking). 30 | set g_enabled:style:width to 20. 31 | set g_enabled:style:height to 20. 32 | set g_enabled:style:margin:v to 0. 33 | //set g_enabled:style:margin:h to 10. 34 | //set g_enabled:style:margin:v to 10. 35 | set g_enabled:ontoggle to { parameter b. set tracking to b. }. 36 | local g_hide is title:addbutton("S"). 37 | set g_hide:style:margin:h to 0. 38 | set g_hide:style:margin:v to 0. 39 | set g_hide:toggle to true. 40 | set g_hide:style:width to 20. 41 | set g_hide:style:height to 20. 42 | set g_hide:ontoggle to { parameter b. if b g_b:hide(). else g_b:show(). }. 43 | 44 | local g_t is g:addvbox(). 45 | set g_t:style:margin:h to 0. 46 | set g_t:style:padding:h to 10. 47 | set g_t:style:padding:v to 15. 48 | local g_target is g_t:addlabel(""). 49 | local g_target_distance is g_t:addlabel(""). 50 | local g_target_speed is g_t:addlabel(""). 51 | local g_target_traveltime is g_t:addlabel(""). 52 | local g_target_bulletspeed is g_t:addlabel(""). 53 | 54 | local g_b is g:addvbox(). 55 | set g_b:style:margin:h to 0. 56 | set g_b:style:padding:h to 10. 57 | set g_b:style:padding:v to 15. 58 | 59 | //g_b:addspacing(10). shoot_distance 60 | 61 | local g_dist_text is g_b:addlabel("Missile tracking distance:"). 62 | set g_dist_text:style:margin:bottom to 0. 63 | local g_sliderbox is g_b:addhlayout(). 64 | local g_distance is g_sliderbox:addhslider(2500,1000,6000). 65 | set g_distance:onchange to g_distance_change@. 66 | local g_dist_disp is g_sliderbox:addlabel("2500m"). 67 | set g_dist_disp:style:width to 45. 68 | local g_shoot_dist_text is g_b:addlabel("Gun range:"). 69 | set g_shoot_dist_text:style:margin:bottom to 0. 70 | local g_sliderbox2 is g_b:addhlayout(). 71 | local g_shoot_distance is g_sliderbox2:addhslider(shoot_distance,300,5000). 72 | set g_shoot_distance:onchange to g_shoot_distance_change@. 73 | local g_shoot_dist_disp is g_sliderbox2:addlabel(shoot_distance + "m"). 74 | set g_shoot_dist_disp:style:width to 45. 75 | 76 | local g_cam is g_b:addcheckbox("Camera focus targets",camera_focus). 77 | set g_cam:ontoggle to { parameter b. set camera_focus to b. }. 78 | local g_cam_spin is g_b:addcheckbox("Camera spin",camera_spin). 79 | set g_cam_spin:ontoggle to { parameter b. set camera_spin to b. }. 80 | local g_kill_all is g_b:addcheckbox("Shoot all the things",false). 81 | set g_kill_all:ontoggle to { parameter b. set kill_all to b. }. 82 | 83 | function g_distance_change { 84 | parameter newValue. 85 | 86 | set missileDetectionRange to round(newValue / 100) * 100. 87 | set g_dist_disp:text to missileDetectionRange:tostring() + "m". 88 | } 89 | function g_shoot_distance_change { 90 | parameter newValue. 91 | 92 | set shoot_distance to round(newValue / 100) * 100. 93 | set g_shoot_dist_disp:text to shoot_distance:tostring() + "m". 94 | } 95 | 96 | g:show(). 97 | 98 | // ### New multi turret setup 99 | 100 | function turretSearch { //recursive function searching downwards in the parts tree, starting at the first parent servo of each turret 101 | parameter parentPart. 102 | 103 | for p in parentPart:children { 104 | if p:tag = "vertical" { 105 | lex:add("camRotV", p). 106 | lex:add("rotVMod", p:getmodule("MuMechToggle")). 107 | p:getmodule("MuMechToggle"):setfield("acceleration",50). 108 | } 109 | else if p:tag = "roll" { 110 | lex:add("camRotR", p). 111 | lex:add("rotRMod", p:getmodule("MuMechToggle")). 112 | p:getmodule("MuMechToggle"):setfield("acceleration",20). 113 | //set hasCamRoll to true. 114 | } 115 | else if p:tag = "arm" { 116 | lex:add("camArm", p). 117 | lex:add("armMod", p:getmodule("MuMechToggle")). 118 | p:getmodule("MuMechToggle"):setfield("acceleration",20). 119 | } 120 | else if p:tag = "camera" { 121 | lex:add("cam", p). 122 | lex:add("camMod", p:getmodule("MuMechModuleHullCameraZoom")). 123 | set hasCam to true. 124 | } 125 | else if p:modules:contains("ModuleWeapon") { 126 | //lex["guns"]:add(p). 127 | lex["gunMods"]:add(p:getmodule("ModuleWeapon")). 128 | } 129 | 130 | turretSearch(p). //search further down the tree 131 | } 132 | } 133 | 134 | local turrets is list(). 135 | for horPart in ship:partstagged("horizontal") { //for each turret 136 | set lex to lexicon(). 137 | //lex:add("guns",list()). //probably not needed 138 | lex:add("gunMods",list()). 139 | lex:add("camRotH",horPart). 140 | lex:add("rotHMod", horPart:getmodule("MuMechToggle")). 141 | horPart:getmodule("MuMechToggle"):setfield("acceleration",50). 142 | turretSearch(horPart). 143 | 144 | set hasGimbal to true. 145 | 146 | 147 | for servo in addons:ir:allservos { 148 | if servo:part = lex["camRotH"] lex:add("servoH", servo). 149 | else if servo:part = lex["camRotV"] lex:add("servoV", servo). 150 | 151 | if lex:haskey("camRotR") { 152 | if servo:part = lex["camRotR"] lex:add("servoR", servo). 153 | } 154 | if lex:haskey("camArm") { 155 | if servo:part = lex["camArm"] lex:add("servoArm", servo). 156 | } 157 | } 158 | lex:add("horErrorI",0). 159 | lex:add("vertErrorI",0). 160 | lex:add("VD", vecdraw(v(0,0,0),v(0,0,0),red,"",1,true,0.1)). 161 | turrets:add(lex). 162 | } 163 | 164 | 165 | 166 | wait 0.1. 167 | // << 168 | 169 | if hasGimbal { //turret stuff 170 | set horErrorI to 0. 171 | set vertErrorI to 0. 172 | set tarVelLast to v(0,0,0). 173 | set tarAcc to v(0,0,0). 174 | set tarAccOld to v(0,0,0). 175 | set accAngRot to 0. 176 | set accRotAxis to v(0,0,0). 177 | set lastCamPos to extcam:position. 178 | 179 | for p in ship:parts { 180 | if p:name = "bahaBrowningAnm2" set muzzleVel to 890. 181 | else if p:name:contains("vulcan") set muzzleVel to 1000. 182 | else if p:name = "bahaGau-8" set muzzleVel to 980. 183 | } 184 | } 185 | 186 | set camMove to 0. 187 | //set targetLastPos to v(0,0,0). 188 | set lastTickAtShip to true. 189 | set tOld to time:seconds - 0.02. 190 | 191 | set vd_target to vecdraw(v(0,0,0),v(0,0,0),magenta,"",1,true,0.4). 192 | set vd_aim to vecdraw(v(0,0,0),v(0,0,0),red,"",1,true,0.1). 193 | set vd_acc1 to vecdraw(v(0,0,0),v(0,0,0),green,"",1,true,0.2). 194 | set vd_acc2 to vecdraw(v(0,0,0),v(0,0,0),yellow,"",1,true,0.2). 195 | 196 | 197 | //return a list of the 5 closest vessels, sorted by distance 198 | function sortTargetsDistance { 199 | local sorted is list(). 200 | list targets in tars. 201 | local tgs is list(). //the list that will get sorted later 202 | for t in tars { //filter out distant vessels and debris 203 | if t:distance < missileDetectionRange { 204 | if not t:name:endswith("Debris") or kill_all tgs:add(t). 205 | } 206 | } 207 | 208 | local i is 0. 209 | local limited is false. 210 | 211 | local lowestTarget is 0. 212 | until i = tgs:length or i = 3 { //sort the list, stop when the 5 closest targets have been found 213 | local isValid is false. 214 | local lowestValue is missileDetectionRange. 215 | for t in tgs { 216 | local tDistance is t:distance. 217 | if tDistance < lowestValue and not sorted:contains(t) { 218 | set lowestValue to tDistance. 219 | set lowestTarget to t. 220 | set isValid to true. 221 | } 222 | } 223 | if isValid sorted:add(lowestTarget). 224 | set i to i + 1. 225 | } 226 | return sorted. 227 | } 228 | 229 | local tarList is list(). 230 | local lastSorted is time:seconds - 2. 231 | 232 | function updateGimbal { 233 | print " dt: " + dT2 at (0,terminal:height-6). 234 | 235 | set targetVes to ship. 236 | 237 | 238 | 239 | if tracking { 240 | if time:seconds - 0.2 > lastSorted { 241 | set tarList to sortTargetsDistance(). 242 | set lastSorted to time:seconds. 243 | } 244 | 245 | //clearscreen. // debug 246 | for t in tarList { 247 | //print t:name + " - " + t:distance. // debug 248 | 249 | if not(t:isdead) and vdot(-t:position,t:velocity:surface) > -100 { 250 | if t:name:startswith("Aim") or t:name:startswith("AGM") or t:name:startswith("BGM") or t:name:startswith("PAC-") { 251 | set targetVes to t. 252 | break. 253 | } 254 | } 255 | } 256 | if kill_all and tarList:length > 0 set targetVes to tarList[0]. 257 | 258 | if hastarget and targetVes = ship and target:distance < 6000 { 259 | set targetVes to target. 260 | if targetVes:istype("Part") set targetVes to targetVes:ship. 261 | } 262 | } 263 | 264 | if not(targetVes = ship) and camera_focus { 265 | if lastTickAtShip { 266 | set lastTickAtShip to false. 267 | set camMove to 1.1. 268 | set extcam:target to targetVes. 269 | set extcam:position to ship:position. 270 | } 271 | 272 | //set extcam:position to targetVes:position * (1-camMove). 273 | if camMove > 0 set extcam:cameradistance to max(15,(targetVes:distance * (camMove^0.5))). 274 | if camera_spin set extcam:heading to extcam:heading + 0.5. 275 | print "Missile Speed: " + round(targetVes:airspeed) + "m/s " at (1,4). 276 | set camMove to max(0,camMove - 0.003 - 40/targetVes:distance). 277 | } 278 | else { 279 | set lastTickAtShip to true. 280 | set extcam:target to ship. 281 | if extcam:cameradistance > 50 set extcam:cameradistance to 49. 282 | } 283 | 284 | if not(targetVes = ship) { //valid target in range for tracking 285 | //### targeting code, this is where the target future position prediction happens 286 | local tarVel is targetVes:velocity:surface. 287 | local tarPos is targetVes:position. 288 | set bulletSpeed to muzzleVel + vdot(tarPos:normalized,shipVelocitySurface). 289 | set travelTime to tarPos:mag / bulletSpeed. 290 | 291 | set tarAcc to (tarVel - tarVelLast) / dT2. //tarAccOld * 0.9 + ((tarVel - tarVelLast) / dT2) * 0.1. 292 | local accAngRot is min(45,vang(tarAcc,tarAccOld) / dT2). //how much degrees we should rotate the accel vector between steps (when the target is turning) 293 | local accRotAxis is vcrs(tarAccOld,tarAcc). //the axis that we should rotate the acc vec around 294 | set tarAccOld to tarAcc. 295 | set tarVelLast to tarVel. 296 | 297 | local tarAccTemp is angleaxis(accAngRot * travelTime * 0.5,accRotAxis) * tarAcc. //the average acceleration in a turn during the travelTime 298 | set tarPosNew to tarPos + tarVel * travelTime + tarAccTemp:normalized * (0.5*tarAccTemp:mag*(travelTime^2)). 299 | 300 | for i in Range(5) { 301 | set bulletSpeed to muzzleVel + vdot(tarPosNew:normalized,shipVelocitySurface). 302 | set travelTime to min(15, tarPosNew:mag / bulletSpeed). 303 | set tarAccTemp to angleaxis(accAngRot * travelTime * 0.5,accRotAxis) * tarAcc. //the average acceleration in a turn during the travelTime 304 | set tarPosNew to tarPos + tarVel * travelTime + tarAccTemp:normalized * (0.5*tarAccTemp:mag*(travelTime^2)). 305 | } 306 | set tarPosNew to tarPosNew + tarVel * dT2 - shipVelocitySurface * dT2. 307 | //set tarPosNew to tarPosNew + tarVel * dT2 * 0 - shipVelocitySurface * dT2 * 0. 308 | 309 | 310 | 311 | set h_vel to vxcl(upVector,shipVelocitySurface). 312 | local heightMod is upVector * (-verticalspeed * travelTime + 0.5*9.81*(travelTime^2)). //(0.5*9.81*(((tarPosNew:mag^1.002) / bulletSpeed)^2))). //taking gravity and initial vertical velocity of self into account 313 | local horMod is h_vel * -travelTime. //initial horizontal velocity old: -(h_vel + h_acc*0.02) * travelTime. 314 | 315 | set focusPos to tarPosNew + heightMod + horMod. 316 | 317 | //update vecdraws 318 | //set vd_acc1 to vecdraw(tarPos,tarAcc,green,"",1,true,0.2). 319 | set vd_target:start to tarPos. 320 | set vd_target:vec to focusPos-tarPos. 321 | 322 | //set vd_acc1:start to tarPos. 323 | //set vd_acc1:vec to tarAcc. 324 | set vd_acc2:start to tarPos. 325 | set vd_acc2:vec to tarAccTemp. 326 | 327 | //print " bullet speed: " + round(bulletSpeed) + " m/s " at (0,terminal:height-5). 328 | //print " travelTime: " + round(travelTime,2) + " s " at (0,terminal:height-4). 329 | //print " height offset: " + round(heightMod:mag) + " m " at (0,terminal:height-3). 330 | //print " horis offset: " + round(horMod:mag) + " m " at (0,terminal:height-2). 331 | //print " horis error: " + round(vdot(cam:facing:starvector,focusPos) * 100) + " cm " at (0,terminal:height-1). 332 | 333 | // ### GUI 334 | if not g_t:visible g_t:show(). 335 | set g_target:text to "Target: " + targetVes:name + "". 336 | set g_target_distance:text to "Distance: " + round(targetVes:distance) + "m". 337 | set g_target_speed:text to "Velocity: " + round(tarVel:mag) + "m/s". 338 | 339 | set g_target_traveltime:text to "Impact: " + round(travelTime,2) + "s, " + round(tarPosNew:mag) + "m". 340 | set g_target_bulletspeed:text to "Bullet speed: " + round(bulletSpeed) + "m/s". 341 | } 342 | //else if submode = m_follow set focusPos to tarVeh:position. 343 | else { 344 | //set focusPos to focusPos * 0.9 + (shipVelocitySurface) * 0.1. 345 | if g_t:visible g_t:hide(). 346 | set focusPos to v(0,0,0). 347 | //set focusPos to desiredHV:normalized * 500. 348 | } 349 | 350 | rcs off. //default to not firing 351 | 352 | if focusPos:mag > 1 { 353 | for t in turrets { 354 | local localFocusPos is focusPos - t["cam"]:position. 355 | //vertical hinge 356 | set vertAngleErr to vang(t["cam"]:facing:topvector,vxcl(t["camRotV"]:facing:starvector,localFocusPos)). 357 | if vdot(t["camRotV"]:facing:topvector,localFocusPos) < 0 set vertAngleErr to -vertAngleErr. 358 | 359 | if abs(vertAngleErr < 0.8) set t["vertErrorI"] to max(-2,min(2,t["vertErrorI"] - vertAngleErr * 0.1)). 360 | else set t["vertErrorI"] to 0. 361 | 362 | t["servoV"]:moveto(t["rotVMod"]:getfield("rotation") - vertAngleErr - vdot(t["camRotV"]:facing:starvector,ship:angularvel) * (180/constant:pi) * dT2 + t["vertErrorI"],50). 363 | 364 | //horizontal rotatron 365 | 366 | set horAngleErr to vang(vxcl(t["camRotH"]:facing:vector,localFocusPos),-t["camRotH"]:facing:topvector). 367 | if vdot(t["camRotH"]:facing:starvector,localFocusPos) < 0 set horAngleErr to -horAngleErr. 368 | set targetRot to t["rotHMod"]:getfield("rotation") - horAngleErr. 369 | set targetRot to targetRot - vdot(t["camRotH"]:facing:vector * -1,ship:angularvel) * (180/constant:pi) * dT2. //compensate for angular velocity of the drone 370 | 371 | if abs(horAngleErr < 0.8) set t["horErrorI"] to max(-2,min(2,t["horErrorI"] - horAngleErr * 0.1)). 372 | else set t["horErrorI"] to 0. 373 | t["servoH"]:moveto(targetRot + 0.08 + t["horErrorI"], 50).//min(100,abs(horAngleErr) * 1) 374 | 375 | //print "horErrorI offset: " + round(horErrorI,4) + " " at (0,terminal:height-7). 376 | 377 | local aimError is vang(t["cam"]:facing:topvector,localFocusPos). 378 | if aimError < 1 { 379 | if aimError < 0.4 and localFocusPos:mag < shoot_distance rcs on. 380 | 381 | for gunMod in t["gunMods"] { 382 | if gunMod:getfield("status") = "Disabled" gunMod:doevent("Toggle"). 383 | } 384 | 385 | set t["VD"]:show to true. 386 | set t["VD"]:start to t["cam"]:position. 387 | set t["VD"]:vec to t["cam"]:facing:topvector * localFocusPos:mag. 388 | } 389 | else { 390 | for gunMod in t["gunMods"] { 391 | if gunMod:getfield("status") = "Enabled" gunMod:doevent("Toggle"). 392 | } 393 | set t["VD"]:show to false. 394 | } 395 | } 396 | } 397 | else { 398 | for t in turrets { 399 | t["servoV"]:moveto(0,1). 400 | t["servoH"]:moveto(0,1). 401 | } 402 | } 403 | 404 | //if hasCamRoll { 405 | // set rollAng to vang(upVector,vxcl( vxcl(upVector,-camRotV:facing:vector) ,-camRotH:facing:vector)). 406 | // if vdot(camRotH:facing:starvector,upVector) > 0 set rollAng to -rollAng. 407 | // servoR:moveto(rollAng,5). 408 | //} 409 | // 410 | //if hasCamArm { 411 | // if ag1 servoArm:moveto( ((alt:radar - 2 + vdot(upVector,cam:position))/3) * armMod:getfield("max") ,100). 412 | // else servoArm:moveto(0,100). 413 | //} 414 | } 415 | --------------------------------------------------------------------------------