|
2 | 2 |
|
3 | 3 | ## What Is a Function?
|
4 | 4 |
|
5 |
| -function syntax, return types, arguments, local vars, default values |
| 5 | +A function is a bit of code, like you'd put in a command or an event. Unlike commands or events, though, functions don't start running because of something happening in the game. A command might run because someone did `/help`, or an event might run because someone ate a piece of steak, but function run **only when you tell them to.** |
6 | 6 |
|
7 |
| -### Function Definitions |
| 7 | +For example, let's look at a basic function: |
8 | 8 |
|
9 |
| -### Function Calls |
| 9 | +```applescript |
| 10 | +function test(): |
| 11 | + broadcast "hello world!" |
| 12 | +``` |
| 13 | + |
| 14 | +This is called a **function definition**. It's composed of the function's name and its code, as well as some other optional stuff we'll get into later. This function is named "test" and all it does is broadcast "hello world!" when it runs. However, there's nothing to make it run yet. Let's run it every time a player joins: |
| 15 | + |
| 16 | +```applescript |
| 17 | +on join: |
| 18 | + test() |
| 19 | +``` |
| 20 | + |
| 21 | +Now, whenever someone joins, Skript sees `test()` and runs our function, broadcasting "hello world!". The act of telling Skript to run a function is named a **function call**. We just called the function test, or ran it, by using its function call. |
| 22 | + |
| 23 | +{% hint style="info" %} |
| 24 | +This might seem a little, well, useless. Why come up with this whole function thing when you can just write the code when you want it? Why couldn't we just write the following? |
| 25 | + |
| 26 | +```applescript |
| 27 | +on join: |
| 28 | + broadcast "hello world!" |
| 29 | +``` |
| 30 | + |
| 31 | +And you'd be right. These two scripts behave exactly the same. In general, you can always just take the code from a function, plop it right into the place you're calling it from with some minor changes, and have it work the same.  |
| 32 | + |
| 33 | +The main benefits come from when you're using the same code in multiple different locations. Functions allow you to only write that code once. |
| 34 | +{% endhint %} |
| 35 | + |
| 36 | +## Function Definitions |
| 37 | + |
| 38 | +Before we move on to the more advanced uses of functions, let's go over how to write one. |
| 39 | + |
| 40 | +```applescript |
| 41 | +function functionName(): |
| 42 | +``` |
| 43 | + |
| 44 | +This is a basic function, like we saw before. The only thing that changes here is the `fuctionName`. The first character must be an alphabetic character, eg a letter, but the following characters can include digits and underscores as well. Common practices are to name functions in `camelCase` or `snake_case`. |
| 45 | + |
| 46 | +However, this is rather limiting. What if we want to do something to an object? Say we have a function called `giveTenApples()`. We don't know who to give to inside the function! This is where **parameters** come into player. |
| 47 | + |
| 48 | +### Parameters |
| 49 | + |
| 50 | +Parameters are used to give extra information to a function, and look like this: |
| 51 | + |
| 52 | +```applescript |
| 53 | +function functionName(parameterName: parameterType = defaultValue): |
| 54 | +``` |
| 55 | + |
| 56 | +They can be named just like variables, so nearly anything you want. Avoid `:` and `*`, though, they can mess things up. The `parameterType` is the type of the parameter, surprisingly enough. This can be any type you want, but should be pretty specific. Is it a `player`, or a `number`, or maybe even a `inventory`. You can allow lists by making the type plural. If you're not sure what type to use, or you want to allow multiple types, use `object`. |
| 57 | + |
| 58 | +That's a lot, so here's a small example: |
| 59 | + |
| 60 | +```applescript |
| 61 | +function giveTenApples(who: player): |
| 62 | + give 10 apples to {_who} |
| 63 | +``` |
| 64 | + |
| 65 | +Here, we have a parameter named `who` with a type of `player`. We can then use that parameter in our function code, as if it were a local variable: `{_who}`. If the type had been `players`, we would use `{_who::*}`, as it's now a list. |
| 66 | + |
| 67 | +To call this function, we now have to give it the player argument it asks for: |
| 68 | + |
| 69 | +```applescript |
| 70 | +on join: |
| 71 | + giveTenApples(event-player) |
| 72 | +``` |
| 73 | + |
| 74 | +See how the parameter value just goes inside the ()? If you have multiple parameters, you just add them on like a list: |
| 75 | + |
| 76 | +```applescript |
| 77 | +on join: |
| 78 | + # a random function that take a player and 3 numbers |
| 79 | + giveTenApples2(event-player, 10, 20, 30) |
| 80 | +``` |
| 81 | + |
| 82 | +But we skipped over something earlier. We can give parameters **default values**, too. |
| 83 | + |
| 84 | +```applescript |
| 85 | +function giveApples(who: player, amount: number = 10): |
| 86 | + give {_amount} of apples to {_who} |
| 87 | +``` |
| 88 | + |
| 89 | +Now we have a parameter for the amount of apples we're giving to the player. But we don't always want to have to specify how many we're giving, sometimes we want to be lazy. This is where default values come in. If we don't give the function a number when we call it, the function will automatically use `10` instead: |
| 90 | + |
| 91 | +```applescript |
| 92 | +on join: |
| 93 | + # gives 10 apples |
| 94 | + giveApples(event-player) |
| 95 | + |
| 96 | + # gives 20 apples |
| 97 | + giveApples(event-player, 20) |
| 98 | +``` |
| 99 | + |
| 100 | +This is useful when you have a parameter you might need to specify sometimes, but most times it's the same value. |
| 101 | + |
| 102 | +### Return Values |
| 103 | + |
| 104 | +We've looked at functions as ways to simply run code, but one of the most powerful aspects of functions is their ability to return values back to the code they were called from. Here's an example: |
| 105 | + |
| 106 | +```applescript |
| 107 | +on join: |
| 108 | + give player customItem((name of player), golden apple) |
| 109 | + |
| 110 | +function customItem(name: string, base-item: item) :: item: |
| 111 | + set {_item} to {_base-item} named {_name} |
| 112 | + set lore of {_item} to "&fWelcome back!" |
| 113 | + return {_item} |
| 114 | +``` |
| 115 | + |
| 116 | +This would give a golden apple with the player's name and some custom lore to anyone who joins. |
| 117 | + |
| 118 | +There's a few things to pay attention too. First, notice that now we're putting the function call in the `give` effect. It's no longer on its own line. This means we're using it as an `expression`, not an `effect`. Functions are one of, if not the only, syntax in Skript with this property.  |
| 119 | + |
| 120 | +Secondly, notice how the function definition has changed. We now have this `:: type:` bit on the end, which tells Skript what type the function is going to return. Again, if you make this plural you can return a list. |
| 121 | + |
| 122 | +Finally, notice the new syntax at the end of the function: `return {_item}`. This is how we tell the function what value it should return. In this case, it's `{_item}`. Return will also stop execution of the function there, like `stop` does.  |
| 123 | + |
| 124 | +{% hint style="warning" %} |
| 125 | +Note that you cannot use `wait` in a function that returns a value. It has to return it instantly, without delay. |
| 126 | +{% endhint %} |
| 127 | + |
| 128 | +### Full Definition |
| 129 | + |
| 130 | +Now that we've explained all the parts, let's show the whole function at once: |
| 131 | + |
| 132 | +```applescript |
| 133 | +function functionName(parameterName: parameterType = defaultValue) :: returnType: |
| 134 | +``` |
| 135 | + |
| 136 | +Hopefully by now you know all these parts, but let's recap: |
| 137 | + |
| 138 | +* **functionName:** the name of the function, starts with a letter and can use letters, numbers, and underscores |
| 139 | +* **parameterName:** Optional. The name of the parameter, follows the same rules as variable names. Will be accessible as a local variable of the same name in the function. |
| 140 | + * **parameterType:** Required if you have a parameter. Tells Skript what type the parameter will be. Use `object` if you're unsure. |
| 141 | + * **defaultValue:** Optional. Allows the function calls to omit this parameter, and Skript will automatically use this value instead. |
| 142 | +* **returnType:** Optional, only use if you intend to return something. Again, use `object` if you're unsure. Remember, functions that return values can't use `wait`. |
| 143 | + |
| 144 | +And calling a function looks like this: |
| 145 | + |
| 146 | +```applescript |
| 147 | +functionName() |
| 148 | +functionName({_parameter1}, {_parameter2}) |
| 149 | +``` |
10 | 150 |
|
11 | 151 | ## When Should I Use a Function?
|
12 | 152 |
|
13 |
| -Talk about how to use effectively |
| 153 | +Now that we know _how_ to use a function, let's look at when and why. |
| 154 | + |
| 155 | +### Eliminating Duplicate Code |
| 156 | + |
| 157 | +If you have two or more places where you've found yourself copying code and making minor tweaks, that might be a good spot to use a function. For example, let's look at a teleportation function: |
| 158 | + |
| 159 | +```applescript |
| 160 | +function fancyTeleport(entity: entity, destination: location): |
| 161 | + play sound "block.beacon.activate" at {_entity} |
| 162 | + wait 1.85 seconds |
| 163 | + play sound "entity.enderman.teleport" at {_entity} |
| 164 | + teleport {_entity} to {_destination} |
| 165 | +``` |
| 166 | + |
| 167 | +With this function, we can use the code wherever we're teleporting things: |
| 168 | + |
| 169 | +```applescript |
| 170 | +command /spawn: |
| 171 | + trigger: |
| 172 | + fancyTeleport(player, spawn of player's world) |
| 173 | +
|
| 174 | +command /warp <text>: |
| 175 | + trigger: |
| 176 | + fancyTeleport(player, {warp::%arg 1%}) |
| 177 | +``` |
| 178 | + |
| 179 | +And if we want to change the sounds, or the delay, we only have to change it in one spot! |
| 180 | + |
| 181 | +### Running Delayed Code Separately |
| 182 | + |
| 183 | +Sometimes you'll find yourself wanting to start a countdown, or maybe a loop with a delay, but not want to stop doing whatever else you're doing. Function are great for this: |
| 184 | + |
| 185 | +```applescript |
| 186 | +command startGame: |
| 187 | + trigger: |
| 188 | + broadcast "Starting Game" |
| 189 | + # these function calls start code with delays, but the code after |
| 190 | + # them runs immediately! pretty useful! |
| 191 | + startTimer() |
| 192 | + startCountdown() |
| 193 | + set {seeker} to player |
| 194 | + set {hiders::*} to all players where [input is not player] |
| 195 | +
|
| 196 | +function startCountdown(): |
| 197 | + loop reversed 10 times: |
| 198 | + broadcast "Starting in %loop-number%" |
| 199 | + wait 1 second |
| 200 | + broadcast "Game has started! |
| 201 | +
|
| 202 | +function startTimer(): |
| 203 | + wait 10 minutes |
| 204 | + broadcast "Game has ended!" |
| 205 | +``` |
| 206 | + |
| 207 | +### Organization and Readability |
| 208 | + |
| 209 | +Often, function are just nice to make your code easier and clearer to read. They move chunks of code out of large, busy areas and isolate it so it's easier to see what's happening. |
| 210 | + |
| 211 | +Functions also come with names, which are nice labels for your code so you can clearly see what it's doing. |
| 212 | + |
| 213 | +```applescript |
| 214 | +on load: |
| 215 | + loadMinigames() |
| 216 | + loadSurvival() |
| 217 | + loadPrisons() |
| 218 | + resetMines() |
| 219 | + # etc... |
| 220 | +``` |
| 221 | + |
| 222 | +## Conclusion |
| 223 | + |
| 224 | +To wrap up, functions are very useful tools to have in your belt. They're powerful, versatile, and make your code way more organized and easy to maintain. You can even explore fancier topics, like recursion, if you're brave enough. |
| 225 | + |
| 226 | +I hope now you've got a grasp on how functions work, at least enough to go and experiment on your own. All the tutorials in the world can't teach you what good old trial and error can. |
| 227 | + |
| 228 | +{% hint style="danger" %} |
| 229 | +If you didn't like anything about this tutorial, or found it hard to understand, message me on Discord at Sovde#0001, or tag me in the SkUnity discord. |
| 230 | +{% endhint %} |
0 commit comments