A Hat in Time

A Hat in Time

Not enough ratings
Scripting A Hat in Time: A Beginners Guide
By SamiSha
A basic introduction to coding in A Hat in Time, this guide will give a run down on the basics elements of coding while adding few more additional useful ones that are used in unreal script, if you know those (e.g for loop, if, else-if, foreach, switches, etc) then you can skip this guide, or just scroll to ones you never knew about!

THIS WILL NOT EXPLAIN HOW TO DO CERTAIN SCRIPTS (Status Effects, Collectibles, HUDs, custom Kismets etc).
3
   
Award
Favorite
Favorited
Unfavorite
Getting An Editing Software
First thing first, we need an editing software, fortunately everyone can do that already with notepad which is built in!


Though from the image above you can see it falls super flat immediately, It is quite limited and awful whilst surely not the best thing for beginners, the thing about coding is that you can use whatever you like when it comes editing software to whichever suits you the most, and in that case I have 2 recommendations, Notepad++ or VSCode, both have their advantages and disadvantages.

Notepad++, download here.[notepad-plus-plus.org]
VSCode, download here.[code.visualstudio.com]

A side by side comparison between Notepad (left) and Notepad++/VSCode (right).


First image is Notepad++ with modified background and a custom UnrealScript format.
Second Image is VSCode with a plugin that adds UnrealScript formatting support.

Setting Up your Editing Software

Unfortunately both of them do not support UnrealScript by default and thus you have to manually add them, in the case of Notepad++ you can use this XML file for my own personal set up, to do so:

1) Download this XML file.[cdn.discordapp.com]
2) While Notepad++ is open, click on Language -> User Defined Language -> Define Your Language...
3) Click on the import button on the top left and select that XML file you just downloaded,
4) (Recommended) This works effectively in dark mode, go to Settings -> Style Configurator... -> And then mess around with the "Select Theme" to which ever that suits you the most (being dark that is), my personal theme is Solarized.
5) Once you are done, close Notepad++ and reopen again and any file that ends in ".uc" should be automatically be formatted through that XML file.

In the case of VSCode:

1) Go to the Extensions tab (Ctrl + Shift + X).
2) In "Search Extensions in Marketplace" type "UnrealScript".
3) Open first result and then click Install, once done click the drop down next to "Uninstall" and install a different version, in this case version 0.4.4 because the latest one is BROKEN!!!
4) For the installation to apply you must close VSCode and relaunch it and thus like Notepad++ will handle any file with .uc format in the end.
.png]Important: While this UC extension helps, it dislikes array adding (like listName.AddItem(item)), even though it shows an ERROR it should be ok, also defaultproperties is broken and will show a lot of "ERRORS" even though its not.

Setting up a Workspace (VSCode)
Please watch this video to set it up, a workspace is a VSC feature that allows you to open multiple folders from different locations, either for checking the files and reading them and effectively swap between coding different files simultaneously.

https://www.youtube.com/watch?v=DaKelz5JVo8

Well done! You are now all set to coding, if you still have any issues in the installations please comment down below!
Creating an UnrealScript File
In your Mod Manager click the "Browse Mod"
.png]


Then inside create a folder called "Classes" this is essential to scripting in A Hat in Time, without it you won't be able to compile new code or add/run new code.


.png]
After creating the folder go inside and follow what is said below:

There are many ways to create an UnrealScript but the easiest one is as follows:

1) Right click in the Classes folder.
2) Hover over "New" -> Then click "Text Document".
3) Right click on "Text Document" and click "Rename" OR highlight the file and press F2 to rename.
4) Call the text file a reasonable name, my recommendation is to call it as follows "YourNameHere_NameOfTheScriptHere" (example: SS_GameMod_DeathDefiance, SS_Ability_WaterSprintDash) this is helpful to avoid your scripts and mods conflict with other mods on the workshop, but most importantly change ".txt" into ".uc".

NOTE: If you cannot see the file extension, in your File Explorer, change to View and then check "File name extensions", that way, it allows you to modify the format of a file, otherwise you cannot really make ".uc" files.
.png]5) Open the file and add the following code, replace "NAME_OF_THE_FILE_HERE" with the name of the file. (Do not add the ".uc" in the class definer)

class NAME_OF_THE_FILE_HERE extends Actor; // Set up properties that this item has, from variables to objects. defaultproperties { } // Runs when the game starts, or level loaded. event PostBeginPlay() { } // Runs every frame, it also passes a value that we can use to simulate many things. event Tick(float d) { }
Creating a GameMod File
For this guide we are going to go around scripting in a GameMod and just printing into the console, reason because this guide is behaving as an entry point to coding in general, though if you know about coding essentials you can always skip a lot here.

Either by using
`broadcast("hello everyone!");

OR use this community Print function (recommended):
// Make sure to add this into your file to use it!!!! // Then simply print stuff like Print("Hi there!"); or Print(VARIABLE_HERE); or Print("look at this number:" @ VARIABLE_HERE); and much more! final function Print(const string msg) { local WorldInfo wi; wi = class'WorldInfo'.static.GetWorldInfo(); if (wi != None) { if (wi.GetALocalPlayerController() != None) wi.GetALocalPlayerController().TeamMessage(None, "[DEBUG" @ Class.Name $ "]" @ msg, 'Event', 6); else wi.Game.Broadcast(wi, "[DEBUG" @ Class.Name $ "]" @ msg); } }

GameMod are the Mods most essential class file, though not necessary to have but they are by default automatically activates whenever the Mod is considered "loaded", by default when a mod is created they are loaded with the option to unload the mod through the "mods menu".

Following the tutorial above over creating an UnrealScript file, insert the following info to create a GameMod script, this will behave as our starting in giving us the fundamentals of programming, which will be rather similar to other languages like c++ with files such as "main.cpp" that are very been used as an introductionary to basic coding.

class INSERT_FILE_NAME_HERE extends GameMod; // Runs when the game starts, or level loaded. event PostBeginPlay() { } // Runs every frame, it also passes a value that we can use to simulate many things. event Tick(float d) { } // Set up properties that this item has, from variables to objects. defaultproperties { }

Finally, go back to your mod manager page and compile the script:

.png]
Good job! You've set up your GameMod and now you are ready to add into it, if you look closely in the Compile Page it now detects the GameMod class which means it was a success!

.png]
One last note and is very important, every time you are about to change something in the file you must save the changes and press the "Compile Scripts" button again.
Variables
Variables are containers that stores data values, they are pretty much the main core of any script/code.

There are many types of variables and you can even make your own custom variables using structs and even specify certain files as the variable! (but that is beyond beginner, so we aren't going to document this here).

But the most widely used are:

1) int - Store integers, 0, 1, 2, 3, -1, -2, -3.
2) float - Stores a float value of a specific number, e.g 1.032173, 1.03f, -99.9999.
3) string - Stores a text, for example "A Hat in Time"
4) bool - Stores either one or the other, being True or False!

Default Properties
Is a section where you can specify your variables to store that specific type of data when that specific script gets called and initialized.

var int number; var float floatNumber; var string titleOfTheGame; var bool saidThePWord; // Set up properties that this item has, from variables to objects. defaultproperties { number = 10; floatNumber = 5.04923; titleOfTheGame = "A Hat in Time"; saidThePWord = true; }
Constants
A constant behaves slightly similar to variables, however they are instead have an already predefined value outside of the "default properties" scope but also CANNOT CHANGE THE DEFINED VALUE ANYMORE, why is that?

To simply put it imagine you want to always have a reference to a value or a name but you also believe that this value is suppose to be the same from the start till the end of the script this is where consts comes in handy, they disallow any changes forward on so you are always in trust that it will always be that specifically defined value no matter what! In short, consts are READ ONLY! In comparison to Variables they are READ and WRITE!

Also const do not take a predefined type (int, float, string) and instead the compiler will figure this out, however you can always give it guidance which type it is, for example, what if you want it a float instead of an integer? How is it going to figure out its a float and not an int when it sees... To solve this we format the value defined as the const, otherwise it will automatically set it to the "most suitable".

// Consts are pre-compiler, cannot be changed after compiled and are READ ONLY! const iValue = 1; // This is an intenger! const fValue1 = 1.043247; // This is a float! const fValue2 = 1f; // This is also a float! const fValue3 = 1.0f; // Another float! const sValue = "Hello, World!"; // This is a string! const nValue = 'A Hat in Time'; // This is a name!
.png]‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎‏‏‎ ‎

Variable Constant:
An alternative type of a Constant, they like their Constant version is considered READ ONLY type.

However, they can be defined a value in default properties, this can become useful if you by any means will be "sub classing" this class if you want to reuse this script for other class. (Sub classing will be explained later on in this guide).

var const float value; defaultproperties { value = 5.0f; // This can be changed forward on if this class gets extended to, this value is READ ONLY! }
Functions
Functions are a block of code which runs when called, you can pass in data as parameters into, functions are useful when it comes to reusing code and would as a result save a lot of time, space and make workflow much more efficient in the process.

var int number; var float floatNumber; var string titleOfTheGame; var bool saidThePWord; // Set up properties that this item has, from variables to objects. defaultproperties { number = 10; floatNumber = 5.04923; titleOfTheGame = "A Hat in Time"; saidThePWord = true; } // Runs when the game starts, or level loaded. event PostBeginPlay() { AddFiveToNumber(); Print("number is:" @ number); // number = 15! number = RemoveValueAmount(10); Print("number is:" @ number); // number = 5! Print(titleOfTheGame); // Should print "A Hat in Time"! } function AddFiveToNumber() // This is a function that adds 5 { number = number + 5; } static function Print(string s) // This function takes a parameter { class'WorldInfo'.static.GetWorldInfo().Game.Broadcast(class'WorldInfo'.static.GetWorldInfo(), s); } // This is a function that takes a parameter but also returns a value function int RemoveValueAmount(int amount) { return number - amount; }

Local Variables
Local variables are defined variables in the scope of a function, once the compiler exit that function that variable NO LONGER EXIST and thus destroyed until that function gets called again, if there's anything that needs to be saved after exiting a function then you must save it into a global variable which are defined through writing at the top of the script as as var type variable_name; (example: var int health;)

That or using a return call (explained down below).

Returning a value from a Function
Functions have the ability to return a value of a specific type, to do so, simply add "return" inside the function that is specified as follows:

function dataType nameOfFunction();

Where dataType can be int, float, string, name and so on including Arrays.

Any return call will cancel any other code forward on and instead return a value that was inputted in the return call.

Few other notes that must be highlighted:
  • If the data type was specified you must return value at some point otherwise it will give you a warning and likely a crash.
  • You can have multiple returns through a function or event that returns different values though this requires to control the workflow of your code (Code workflow is discussed in a section below).

Void Function

You can call return without returning anything as long as the function doesn't have data type specified when declared, if you remember any other coding language like C#, Java or C++ and so on, you're maybe familiar with "void type[en.wikipedia.org]" which you may find slightly similar to UnrealScript.

function nameOfFunction();

Notice the missing dataType unlike the previous code block above this one? A void function is created by not specifiying a dataType (UnrealScript of course, majority of mainstream coding languages explicitly require you to specify void, such as all C-Languages).

Code Example:

event PostBeginPlay() { local int playersHealth; // This is a local variable, only present in here but nowhere else. Print("How healthy are you today?"); // Print is a function with a parameter that takes a string. playersHealth = GetPlayerHealth(); // This returns the Player health. Print("Player current health is:" @ playersHealth $ "!"); // This prints the player's health. } // This function returns the player's health. function int GetPlayerHealth() { local Hat_Player player; // player is a variable of a class called Hat_Player player = Hat_Player(GetALocalPlayerController().Pawn); // Getting the player and saving it in the local variable return player.Health; // Accessing the player's health which is an int and returning it. } static function Print(string s) { class'WorldInfo'.static.GetWorldInfo().Game.Broadcast(class'WorldInfo'.static.GetWorldInfo(), s); }
Controlling the Flow of Your Code
Coding isn't really a straight line, sometimes you just want to:

  • Repeat the code multiple times.
  • Run a certain code line when a certain condition meets.

This is where things like If statements, For/While/Do Loops, Switch Cases and ForEach comes to mind, this section will explain how each one works and provide an example that can be pasted in your GameMod file (if you already made one of course).
If Statement
If statement is a conditional statement which only takes true and false, they can also take a lot of different types other than a boolean, like value == 5, value != 5 or value > 5.

The conditional operators are as follows:
  • value == x, value must equal x.
  • value != x, value must NOT equal x.
  • value > x, value must be bigger than x.
  • value >= x, value must be bigger than or equal x.
  • value < x, value must be less than x.
  • value <= x, value must be less than equal x.

If these conditions turn out true the code chunk below it between the brackets will run, otherwise if the condition is false it will skip.

The Exclamation Point!
The purpose of Exclamation point is to reverse the value result, the best way to understand exclamations is to read it as NOT, after all its the reverse of the previous value, this means !false = true and !true = false.

if(!(value == 5)) is the same as if(value != 5) if(!eating) // can be read as "NOT eating"

Else statement:
Like the above, sometimes you want to run something when the if statement turns out to be false, "Else" will run otherwise.

Else If Statement:
But what if you want to also constantly check different conditions as things fail over and over? else if(conditionHere) will go through the same criteria like an if statement, and you can keep adding else if(s) as much as you want, if any of the "if" or "else if" statements turns out true, the conditional check breaks and skips the rest of the "else if" that are present in.

&& (AND) and || (OR):
Sometimes you just want to check multiple conditions at once and this is where && and || come to mind!

&&: Means that BOTH should meet true else they are false.

Condition 1
Condition 2
Result
false
false
false
true
false
false
false
true
false
true
true
true

||: Means that ANY should meet true.

Condition 1
Condition 2
Result
false
false
false
true
false
true
false
true
true
true
true
true

var bool hatKidIsCurrentlyEating; var int cookieAmount; var int maxCookies; defaultproperties { cookieAmount = 4; } event PostBeginPlay() { Print("Hmm... I wonder if Hat Kid is eating cookies..."); // Checks if less than or equal 4 if(cookieAmount <= 4) { hatKidIsCurrentlyEating = true; } // Checks if they are currently eating. if(hatKidIsCurrentlyEating) { Print("Hat Kid! Stop eating Cookies you had enough!"); } else { Print("Hat Kid isn't eating!"); } if(cookieAmount == 5) { Print("There's 5 cookies"); } else if(cookieAmount == 4 || cookieAmount == 3) // Checks if it equals 3 OR 4. { Print("I cannot believe Hat Kid ate 1 cookie!"); } else if(cookieAmount <= 2 && cookieAmount > 0) // Checks if its "less than equal 3" AND "bigger than 0" { Print("I cannot believe Hat Kid ate" @ maxCookies - cookieAmount @ "cookie!"); } else Print("There are no more cookies :("); } // Prints to the console static function Print(string s) { class'WorldInfo'.static.GetWorldInfo().Game.Broadcast(class'WorldInfo'.static.GetWorldInfo(), s); }

Parentheses:
If statements doesn't really go with just a one or two conditions, they can get a little bit complex, sometimes requires a lot different conditions to meet for something to execute, parentheses are used for that purpose too, for example:
if((true || true) && false) // -> false if((true || false) && (false || true)) // -> true if((true && false)) is the same as if(true && false) which results in false of course.
Loop Iterators
Just like adding conditions to make some code run and some to be avoided based on certain conditions, you can rerun code multiple times at one go!

For Loop:
It takes 3 cases inside:
  1. An iterator to iterate through with a starting value (usually 0).
  2. A condition that is met to keep iterating like i < 5.
  3. With each loop ending the value changes, manly around incrementing the value (like i++).

local int i; for(i = 0; i < 5; i++) { // Calls this function 5 times, with i being between 0 - 4 Print("Just grabbed a cookie now I have" @ i + 1 $ "!"); }

While Loop:
Similar to the above but it only takes a condition, this means it will keep running as long as that condition is true, if by any points it becomes false.

local int i; while(i < 5) { // Calls this function 5 times, with i being between 0 - 4 Print("Just grabbed a cookie now I have" @ i + 1 $ "!"); i++; }

Do Loop:
Similar to the While Loop but instead it will do that following task before it checks if the condition is false to whether stop doing it, this means if it straight up the condition became false then the task was done ONCE.
local int i; do { // Calls this function 5 times, with i being between 0 - 4 Print("Just grabbed a cookie now I have" @ i + 1 $ "!"); i++; } until (i >= 5)

Multiple Loops:
Loop iterator inside a loop iterator is actually more possible than you can imagine, in fact you can go pretty much with a lot more loops inside a loop though that's not really recommended. (No seriously infinite loops can be really a suicide) and I would advice to stick to 2/3 loops.

local int i, u, result; for(i = 0; i < 5; i++) { result++; for(u = 0; u < 5; u++) { result++; } } Print("I've found" @ result @ "cookies!");
Continue and Break
Conditions inside iterators aren't usually enough, just like in if statements what if we need MORE conditions or a very specific condition and that condition was met? Maybe you'd want to skip that loop and move on to the next immediately or maybe you just want to break the loop entirely?

Continue:
If continue gets cast when a condition was met, the loop will skip everything forward on and move on to the next loop.

Break:
If break gets cast when a condition was met, the loop will stop everything forward on and exit the iterator, stopping the loop.

local int i; for(i = 0; i < 10; i++) { if(i == 8) break; // if we reach cookie number 8, stop the loop! if(i == 3 || i == 5) continue; Print("This is cookie number" @ i $ "!"); }
Switch Cases
Switch cases are a selection control mechanism that used to control your code flow, it takes a variable or a value as an input, after that the switch will then go through each Case until it meets that value and proceed to run the following code underneath that specific case that was matched.

It is important to add a break or return once you are done going through a specific code block or it will go through every other case that is below the Case you are looking for.

Switch Cases are highly recommended if you know which value types such as int, strings/names and even Enumeration (enums discussed in the next section).

Default
In Switches, you can set up a default value, if the Switch goes through each case and is unable to find something that matches the inputted value, then it will instead go into the default case if specified.

local int health; health = 3; Switch(health) { Case 0: Print("dead" @ health); break; Case 1: Print("You look like you are about to collapse..." @ health); break; Case 2: Print("You should probably go to a doctor." @ health); break; Case 3: Print("Just a bruise, I've seen worse." @ health); break; Case 4: Print("You seem as healthy as ever!" @ health); break; default: Print("You seem more healthy than intended..." @ health); break; }
Object Oriented Programming
Unreal Script is an Object Oriented Programming language, a style of writing code by creating a Class which are represented as blueprints.

Classes are made out of variables, functions and pretty much everything you've read about before and they make that object unique in its way as it has its own custom attributes and functionality.

Inheritance:
An acronym where two classes, a child extends from the parent class, extending is mostly done for different reasons but one of them is to recycle previous structure with the idea of ADDING or OVERRIDING certain attributes.

To put this into a different perspective, let's take the most essential class that the entirety of the game is built upon, Object.uc, every single thing you can imagine, the player, the enemy the bosses, lights, UI, the timepiece are all Objects, of course they function differently according to their designated purposes but they are still considered a child to a parent.

Another example are Bosses, Bosses uses Hat_Enemy_Boss.uc which extends from Hat_Enemy.uc, meaning that Bosses function quite similarly to Enemies but they have aditional functionality or alternative overrides to change its workflow to act as a boss, despite boss being a higher ranked enems, they are considered a child and pretty much similar to their normal enemy counterpart.

In short, Object Oriented Programming is a way of class hierarchy which class extended from its parent has more data, variables or functionality to mess with.

The Super call
When a child extends from a class, they also receive all their functions, however if you write down the function from the previous class, it will only be overriding the previous functionality of the class, what if you want to add more to the function while also run the previous code that was written in this class parent?

Simply cast Super.NAME_OF_FUNCTION();

As an example, A Hat in Time StatusEffects have a function called Update which is used to add functionality that is checked every frame, if we do not add a line such as "if(!Super.Update(d)) return false;" inside, the duration that was set into the StatusEffect will not work! That's because the Super call EXTENDS the functionality to also handle the duration of the statuseffect! Otherwise it will turn out as you've overridden the function, meaning you have to manually handle the Duration value by yourself!
// the child class that is extending from Hat_StatusEffect function bool Update(float d) { if(!Super.Update(d)) return false; /* ..... Additional code here ..... */ return true; } // the parent class Hat_StatusEffect Update function, notice how the Parent function has the duration implementation. function bool Update(float delta) { if (IsExpired()) return false; if (!Paused) { CurrentDuration += delta; if (!Infinite && CurrentDuration >= Duration) { CurrentDuration = Duration; OnExpired(); return false; } } return true; }

Note: As a reminder, overriding a class only happens if you explicitly specify the function in the child class, if you do not specify it, then it will run the one in the parent class instead!
Advanced Variable Data Types
So by now you learned about simple data types like floats, integers, strings and so on when it comes to defining variables.

Variables can do more than using simple data types, they can get more extensively advanced, for example, what if we want to preserve a list of data of a similar type? How about creating your own data type that saves multiple variables of data types? And so on and on.

Object Reference Variables:

All variables can hold an Object, for examples:

var Hat_Player player; var Actor actor; var Hat_HUD hud; var SoundCue hurtSound; var ParticleSystemComponent ouchParticle;

All of these of course would by default defined as "None", for more info on getting Object Variable Data Type of declared or defined when it comes to the current level or searching ways for those references, read this guide: [WORK IN PROGRESS]

Class Reference Variables:

They are highly similar to arrays, which in that case an object is holding the class name reference (including its children).

// This cannot hold active collectibles nor declared collectibles, instead it holds a reference to the collectible class to be used. var Class<Hat_Collectible> collectible; // Similar to the above but can hold multiple class references. var Array<Class<Hat_Collectible>> collectibles;

Struct
.png]
Are unique data types, they serve as a way to create custom variables which store multiple basic or advanced data types, allowing you to keep everything sorted into one variable, they behave extremely similar to Classes.

There's as a matter of fact data types like Vector, Vector2D, Rotator, Color are ALL structs!!! Which are really useful fundamental blocks found throughout the game, a lot of class files have at least one of those specified once or many times to emphasize how important they are.

To create a struct you must first define it as follows:

struct BatteryInformation { var string batteryName; var float charge; var int ATypeAmount; // 1 = A, 2 = Double A, 3 = Triple A };

After creating a struct, you can use its name as a data type for a variable:

var BatteryInformation battery;

And to access that variable's variables:

battery.batteryName = "Literally Can't Sink Battery"; battery.charge = 75.64f; battery.ATypeAmount = 3;

Struct Default Properties:

If you initialize a new struct variable, you can always give it a default properties to some its variables, this can be done by specifying a structdefaultproperties.

struct BatteryInformation { var string batteryName; var float charge; var int ATypeAmount; // 1 = A, 2 = Double A, 3 = Triple A structdefaultproperties { // specify the defaults here! batteryName = "Literally Can't Sink Battery"; charge = 75.64f; ATypeAmount = 3; } };

structdefaultproperties pretty much work exactly like defaultproperties.