KOS and programming introduction

This tutorial is for people who are new to programming and want to start programming using KOS.

Accessing the KOS terminal

To use KOS you need to have a KOS processor on your vessel, they can be found under the ‘control’ tab in the editor and are under the same tab as the RCS thrusters and the reaction wheels. Right clicking the KOS processor in the editor after adding it to your vessel shows a screen where you can tweak settings of the KOS processor.

There are two ways you can create KOS scripts: either you make them in game and edit them in game or you use a text editor.

Making scripts in-game

First we’ll look at making and editing scripts in-game. Put your vessel with KOS processor on the launchpad and right click the processor. Press the button that says ‘open terminal’ and click on the window that just popped up.

typing the following will create a file called ‘hello’, to enter the command press ENTER (don’t forget the period at the end):

edit hello.

you can now edit the file and make your script for the processor to execute, the other tutorials will show how you can make a working script. Keep in mind that files made in game dissapear after the vessel is gone. This happens because you locally made a file on the ship’s processor.

To run the file, type:

run hello.

Making scrips with an editor

To use a text editor instead go to your KSP folder and go to Ships/Script/ and create an empty file and name it whatever you want (be cautious using spaces in filenames because this might mess stuff up, also, avoid using capital letters in .ks files if you are running Linux). Not sure where your KSP folder is? If you used steam to install KSP, go to your steam library and right click Kerbal Space Program in the list of games. Next click on properties and go to the local files tab. Finally, press on the browse local files button. (KSP doesn’t require you to use steam, you can copy the KSP folder from the Steam folder to your desktop so you can play without using Steam).

All KOS script files should end with .ks. An example of a valid KOS script file name would be:

hello.ks

Running files you made using text editors is a bit more complex than if you’d make a file in game. This is because when you make a script in game the script is locally stored on the ship. Files you made with a text editor are saved in the archive, can be accessed from different saved games and won’t be lost after the vessel is gone. You could compare it with ground control, which has infinite data storage and a spaceship which has limited space for data.

To access the archive type:

switch to 0.

To run hello.ks type the same as above:

run hello.

If statements

Now we know how to set certain text to a variable we can explore more stuff. For instance if, this checks if a certain value matches the given value.

set x to 1.

if x = 1 {
  print "x is one".
}

This will show: x is one.

You’ve probably noticed the curly brackets { } after an if statement. You don’t need a period at the end of an if statement but you need these brackets if you have more than one statement in the body, otherwise they’re optional.

This is valid:

if x = 1
  print "x is one".

You could cover the piece the code within the curly brackets with your hand and say: if x is equal to 1, then do whatever I covered with my hand. If statements can also be used for booleans:

set SomeBoolean to true.

if SomeBoolean = true {
  print "this is a true".
}

This will show: this is true.

Ofcourse the equals sign isn’t the only symbol you can use, other symbols are:

Equals to or bigger than:

1 >= 1

2 >= 1

Equals to or smaller than

1 <= 1

1 <= 2

Is not equal to:

1 <> 2

So as you have seen, we created some commands that will only happen if a condition is true, otherwise nothing happens and we move on. But what if you want to do some commands when the condition is true and instead of doing nothing when it’s false, you’d give it commands to do instead. The else statement also requires curly brackets { }.

set SomeAnimal to "Dog".

if SomeAnimal = "Cat" {
  print "this is a cat".
} else {
  print "this is not a cat".
}

Since SomeAnimal isn’t Cat, it skips whatever would happen if SomeAnimal would be Cat. Then it checks what else to do, which is to print this is not a cat. You could expand this by using else if, which means that if the first if statement isn’t true then check the following if statement.

set SomeAnimal to "Dog".

if SomeAnimal = "Cat" {
  print "this is a cat".
} else if SomeAnimal = "Dog" {
  print "this is a dog".
} else {
  print "this is neither a cat nor a dog".
}

This would print this is a dog.

if vs else if

Hopefully you now know the basics of how if works. You might be wondering why use else if if it’s the same as if.

Example 1, using else if

if distance <= 1 {
  print "Distance is within a meter.".
} else if distance <= 100 {
  print "Distance is within 100 meters.".
} else {
  print "Distance is farther than 100 m.".
}

Example 2, only using if

if distance <= 1 {
  print "Distance is within a meter.".
}
if distance <= 100 {
  print "Distance is within 100 meters.".
}
if distance > 1000 {
  print "Distance is farther than 1 kilometer.".
}

Using example 1, if your distance is less than a meter you’ll get the following message:

Distance is within a meter.

Using example 2, if your distance is less than a meter you’ll get the following messages:

Distance is within a meter.
Distance is within 100 meters.

As you can imagine the second example isn’t good. If we’re at less than a meter away from something and the messages for if we would be farther than 100 meters show up we have a big problem. This could be fixed by doing the following, but THIS IS UNNECESSARILY COMPLEX:

set Done to false.

if Done = false {
  if distance <= 1 {
    print "Distance is within a meter.".
    set Done to true.
  }
}

if Done = false {
  if distance <= 100 {
    print "Distance is within 100 meters.".
    set Done to true.
  }
}

if Done = false {
  if distance > 1000 {
    print "Distance is farther than 1 kilometer.".
    set Done to true.
  }
}

Now this essentially does the same as the else if script but it’s way more confusing and complicating.

Until, lock and wait

The wait command is pretty straight forward:

wait 10.
print "done waiting".

It will take 10 seconds before done waiting shows up. Using wait 0 will let the script wait for one physics tick (a physics tick is the time it takes for KSP to update its physics), this can be handy for when you’re doing stuff with maneuvers. Maneuvers don’t show up instantly but show up after one physics tick. More about maneuvers in a future tutorial.

The until command will keep looping a piece of code until the given value has been met. Here’s a simple example of what you can do with an until command:

set x to 0.
until x > 100 {
  print x.
  set x to x + 1.
}

This first sets x to 0 and until x is bigger than 100 it does whatever happens within the brackets. In this case it prints x and then it increases x by 1. This loop repeats itself until x is bigger than 100. Before we can talk about more complex until loops let’s first talk about time:seconds and the lock command.

print time:seconds.

Will print the current time in seconds. Let’s say the in-game time is 1 minute. It would print 60. You can also set the current in-game time as a variable:

set CurrentTime to time:seconds.

The variable CurrentTime will stay 60 seconds. Eventhough the in-game time changes:

set CurrentTime to time:seconds.
print CurrentTime. // shows: 60
wait 10.
print CurrentTime. // shows: 60

As you can see, eventhough the in-game time has changed the variable CurrentTime is still 60. The set command does NOT constantly update the variable. If you want a constantly updating variable you have to use the lock command. Here’s an example of what the lock command can do:

lock TimeSecondsPlusTen to time:seconds + 10.

If you print TimeSecondsPlusTen at 60 seconds it will show 70, if you print TimeSecondsPlusTen at 4000 seconds it will show 4010.

Using until, lock and wait in an example

If we now combine all the command we can make the following piece of code:

set Adder to 0.
lock Multiplier to Adder * 2.
set TimePlusFive to time:seconds + 5.

until time:seconds > TimePlusFive {
  print Multiplier.
  set Adder to Adder + 1.
  wait 1.
}

So an easy way to read the until loop is to cover what ever is inside of the curly brackets and say: until time:seconds is bigger than our current time plus 5 seconds, repeat whatever I covered with my hand. In this case that’d be: print Multiplier, increase the value of Adder and wait 1 second.

The outcome of this piece of code is:

0
2
4
6
8
10

Wait until

You can also use the wait until command, this pauses the current script until the conditions have been met.

set TimePlusFive to time:seconds + 5.
wait until time:seconds > TimePlusFive.
print "done waiting".

It will take 5 seconds for done waiting to show up. Note: the wait until command only checks the condition once per physics tick. Using wait until for a fraction of a physics tick will round up to the start of a new physics tick.

Lists and lexicons

set Value1 to 0.
set Value2 to 5.
set Value3 to 10.
set Value4 to 15.
set Value5 to 20.

Let’s say we want to put these values in a list we want to edit later we can put them into a list by typing the following:

set ValueList to list(Value1, Value2, Value3, Value4, Value5).
print ValueList.

This will show:

[0] = 0
[1] = 5
[2] = 10
[3] = 15
[4] = 20

As you can see the list goes from 0-4 instead of 1-5. So if you’d want to access Value3 you’d need to look for [2]. This can be done as follows:

print ValueList[2]. // shows 10

But let’s say you want to print every item in the list you could do:

print ValueList[0]. // shows 0
print ValueList[1]. // shows 5
print ValueList[2]. // shows 10
print ValueList[3]. // shows 15
print ValueList[4]. // shows 20

But the problem with this is that you have to know how big the list is and it’d take up a lot space when dealing with big lists.

for Whatever in ValueList {
  print Whatever.
}

for Value in ValueList {
  print Value.
}

Both pieces of code do EXACTLY the same. This checks each item in a given list (now called Whatever) and does what the curly brackets contains. (For each item in the list called ValueList, which we call Whatever, do whatever is inside of the brackets).

In this case it prints:

0
5
10
15
20

You can also use variables to check an item in a list:

set x to 3.
print ValueList[x]. // shows 15

Does the same as:

print ValueList[3]. // also shows 15

Lexicons

Lexicons are in a way the same as lists but they have some crucial differences. Lexicons can store a pair of information, for example:

set MyLexicon to lexicon("MyValue1", 100, "MyValue2", 200, "MyValue3", 300).

The following piece of code acts EXACTLY the same as the piece of code above but is easier to read:

set MyLexicon to lexicon(
  "MyValue1", 100,
  "MyValue2", 200,
  "MyValue3", 300
).
print MyLexicon["MyValue1"]. // shows 100
print MyLexicon["MyValue2"]. // shows 200
print MyLexicon["MyValue3"]. // shows 300

NOTE: print MyLexicon[100]. will NOT work.

Functions

Imagine you’re driving in a manual shift car for with an instructor for the first time. He helps you getting into first gear and tells you the following when you want to accelerate:

Let go of the gas pedal.
Press in the clutch pedal.
Shift the gear stick from first to second.
Let go of the clutch pedal.
Press in the gas pedal.

After a while he tells you:

Let go of the gas pedal.
Press in the clutch pedal.
Shift the gear stick from second to third.
Let go of the clutch pedal.
Press in the gas pedal.

Not long after that he tells you:

Let go of the gas pedal.
Press in the clutch pedal.
Shift the gear stick from third to fourth.
Let go of the clutch pedal.
Press in the gas pedal.

Wouldn’t it be easier if instead of telling you the entire procedure he’d tell you the following:

Shift from first to second.
And after a after he tells you:
Shift from second to third.
And not long after that he tells you:
Shift from third to fourth.

As you can see you only need to know how to shift once (if you’re a quick learner) and after that telling the whole process is repetitive. The same goes for code in KOS, you might want to use a piece of code more than once without typing it out everytime. This is called a function and functions often have parameters (similar to starting conditions).

Keep in mind that the following piece of code is pseudo-code and is not actual working code but an example of what functions are like:

Function ShiftGearFirstToSecond {
  Let go of the gas pedal.
  Press in the clutch pedal.
  Shift the gear stick from first gear to second gear.
  Let go of the clutch pedal.
  Press in the gas pedal.
}

Your instructor could now say ShiftGearFirstToSecond() and you’d know how to go from the first gear to the second. But this is only about going from the first gear to the second and not from the second gear to the third. To do that you’d need to have blank spaces for you to fill in with your desired gears.

Function ShiftGear {
  Let go of the gas pedal.
  Press in the clutch pedal.
  Shift the gear stick from ____ to ____.
  Let go of the clutch pedal.
  Press in the gas pedal.
}

On paper this sounds like a great idea but if your instructor tells you ShiftGear() first gear, second gear. But you’re not sure where to put first gear and where to put second gear. Wouldn’t it be handy if you made rule that the first word your instructor says is the gear you start in and the second word he says is the gear you end in? Well luckily there’s a way to apply that rule. This is were parameters come into play, all functions get called using () after the function name and inside of the brackets you put the parameters.

Function ShiftGear {
  Parameter StartGear.
  Parameter EndGear.

  Let go of the gas pedal.
  Press in the clutch pedal.
  Shift the gear stick from StartGear to EndGear.
  Let go of the clutch pedal.
  Press in the gas pedal.
}

As you can see we replaced the blank spaces with variables (parameters are also variables). So to go from first gear to second gear you’d use: ShiftGear(first, second). To go from second to third you’d use: ShiftGear(second, third). To go from third to second you’d use: ShiftGear(third, second).

A working example of a function

Here’s an example of a simple function which works in KOS:

Function OneThroughFivePrint {
  print 1.
  print 2.
  print 3.
  print 4.
  print 5.
  }

Functions can have any name but avoid making functions and variables the same name as this will very likely cause problems. A function will do anything that’s inside of the curly brackets. To use this function type the following:

OneThroughFivePrint().

This will show:

1
2
3
4
5

A more complex function

Here’s an example of a more complex function which has a parameter and will also work in KOS:

Let’s say we’re in a perfectly circular orbit around kerbin, we can use the following formula: velocity = (2 * pi * radius) / orbital period (https://en.wikipedia.org/wiki/Circular_motion#Formulas)

Ignore how ship:orbit:period works for now, that will be discussed in the next chapter.

Function VelocityCalculator {
  Parameter OrbitHeight.

  set KerbinRadius to 600000.
  set TotalRadius to OrbitHeight + KerbinRadius.
  set OrbitalPeriod to ship:orbit:period.
  print (2 * 3.1416 * TotalRadius) / OrbitalPeriod.
}

If you’re in a 400 km circular orbit and type:

VelocityCalculator(400000).

Will show your orbital velocity.

Now what if you want to use the velocity for other calculations, is that possible? Yes of course that’s possible! The return command is very helpful is these situations. The return function returns a value, piece of text, boolean etc and ends the function it is in.

Function VelocityCalculator {
  Parameter OrbitHeight.

  set KerbinRadius to 600000.
  set TotalRadius to OrbitHeight + KerbinRadius.
  set OrbitalPeriod to ship:orbit:period.
  return (2 * 3.1416 * TotalRadius) / OrbitalPeriod.
  // everything after the return command will be skipped because a return command ends a function.
  print "this will be skipped".
}

set CurrentVelocity to VelocityCalculator(400000).
print CurrentVelocity.

Will show your orbital velocity for a circular orbit at 400 kilometers.

Suffixes

In KOS you can access information about orbits using special structures. Let’s start with things we can check about our ship’s orbit.

print ship:orbit:apoapsis. // shows the ship's apoapsis
print kerbin:orbit:apoapsis. // shows kerbin's apoapsis
print ship:body:orbit:apoapsis. // shows kerbin's apoapsis if you're currently orbiting kerbin

You could compare these structures to a fill in the blanks story:

print ___:orbit:apoapsis. // shows the apoapsis of whatever you fill in the blank

There are also other things you can get instead of just apoapsis, for example:

print ship:orbit:periapsis. // shows the ship's periapsis
print ship:orbit:period. // shows the ship's period
print ship:orbit:inclination. // shows the ship's inclination
print ship:orbit:eccentricity. // shows the ship's eccentricity
print ship:orbit:semimajoraxis. // shows the ship's semimajoraxis

The full list of things you can add after :orbit can be found here: https://ksp-kos.github.io/KOS/structures/orbits/orbit.html

Taking a step back, you can also look up values of planets

print kerbin:name. // shows kerbin
print kerbin:mass. // shows kerbin's mass
print kerbin:radius // shows kerbin's radius
print kerbin:mu // shows kerbin's gravitational parameter

If you’re currently orbiting kerbin, the following is true:

print ship:body:name. // shows kerbin
print ship:body:mass. // shows kerbin's mass
print ship:body:radius // shows kerbin's radius
print ship:body:mu // shows kerbin's gravitational parameter

More information about that here: https://ksp-kos.github.io/KOS/structures/orbits/orbitable.html