<emstyle="font-family: 'Comic Sans MS', 'Comic Sans', Impact, Arial">Official manual!!!!</em>
</center>
<br>
**Uranium Template** is a Love2D-inspired NotITG game development template, focusing on keeping things as **Lua-pure** as possible with enough abstractions to make you feel like you're not dealing with Stepmania jank at all.
Uranium Template originally formed during the creation of a currently unreleased project, and since then I've went ahead and refined and polished it up to be usable on its own. Most of the design decisions came from experience using prototype versions of it!
- [Installation](#installation)
- [Distribution](#distribution)
- [How do I start writing code?](#how-do-i-start-writing-code)
1. Unzip your installation zip, as you would a modfile
2. Edit `Song.sm` in your editor of choice (ArrowVortex, NotITG) to include necessary metadata; replace `silence.ogg` with an actual track, if necessary
3. Edit `main.lua` to do whatever you wish to do with it! The entirety of the `src/` folder is yours!
4._(Recommended)_ Install [sumneko's Lua LSP](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) and grab the latest NotITG typings [here](https://gitlab.com/CraftedCart/notitg_docs/-/archive/master/notitg_docs-master.zip?path=lua) (put them in a folder like `.typings`!)
## Distribution
After you're done with writing your file, be sure to take these steps to reduce the filesize and get your game ready for zipping up!
- Remove `MANUAL.md`, `docs/`, `.vscode/`, `.gitconfig`, `.gitignore` and `template/typings.lua`. These are files that aren't necessary outside of a development environment!
All actors that take in filenames have their filenames starting from the root of the project; meaning if you had a file in `myModFile/src/test.png`, you'd have to pass in a filename of `src/test.png`. **If an image is blank, or a single pink pixel, it hasn't loaded properly.**
Once you have an actor defined, you can run whatever methods you want.
> **Note**
> Even though you get a fully functional actor, what you actually get is a _proxied actor_! What this means for you is that you really shouldn't call any getters on the actor, as it'll just return `nil`.
```lua
local text = BitmapText('common', 'hello, world!')
As you may have noticed, when you print an actor defined with Uranium, it won't show up as an actor - it'll show up as a "proxy" of an actor. This is because we can't actually get actors created on demand in NotITG - what happens instead is you get an object that _acts_ like an actor by calling all the same methods you pass into it, but isn't really one.
```lua
local q = Quad()
print(q) --> 'Proxy of Quad'
```
Typically, this doesn't matter; however, in certain contexts, it may be required for you to get the raw actor from a proxy actor. You can do this by accessing `__raw` on the actor - this is defined on all actors and is only available _post-initialization_.
```lua
local q = Quad()
print(q.__raw) --> nil
q:addcommand('Init', function()
print(q.__raw) --> 'Sprite (168F7F78)'
end)
```
For most things that require this, there exist simple abstractions - applying shaders has `setShader`, `setShaderfuck`, etc., however in rare circumstances this may be useful. _Please let me know if there's a use-case that I haven't accounted for!_
See [the AFT example](#afts) for a quick setup to play around with, or the example in the [aft library](#aft) for a barebones setup. The ability to dynamically adjust at which point in the stack they render makes them _a lot_ more powerful than you'd expect.
**This will mess up rendering for those actors!** This is because all actors that are outside the _root_`ActorFrame` of the template would be unaffected with the frame's transformations if they're drawn outside of their respective DrawFunctions. You'd want to then create a setup similar to this:
**Nested AFs are supported.** As with all complicated things in this template, check out the [`ActorFrame` example](#simple-actorframe-setup) for a simple working setup.
`ActorFrame` already has an extremely, _extremely_ complicated setup powering it in the back-end; and `ActorScroller` is way too niche for me to give it the same treatment. Sorry!
If you want to specify theme-provided fonts, that's easy enough:
```lua
local text1 = BitmapText(nil, 'test') -- defaults to 'common'
local text2 = BitmapText('_wendy white', 'test')
local text3 = BitmapText('_misobold white', 'test')
```
However, providing custom fonts is a bit tedious due to a [vanilla bug](https://discord.com/channels/227650173256466432/666629297544495124/1023573412028891177) that's annoying to work around. In order to specify a custom font, consider the _root path_ to be in `template/`. For example, if you want to load a font from your `src/` folder, you'd do:
```lua
local text = BitmapText('../src/_inter v 22px.ini', 'test')
Shaders cannot be manually defined on actors [due to a technical limitation](https://discord.com/channels/227650173256466432/666629297544495124/1022119161415077909); plus, it wouldn't make much sense to integrate them in the same way that NotITG integrates shaders with the current XML behavior. In order to give an actor a shader, you need to define them seperately:
```lua
local sprite = Sprite('docs/uranium.png')
local shader = Shader('src/shader.frag') -- returns a RageShaderProgram
If you return a non-falsy value in a callback, however, it'll cancel every other callback after it. This can be useful for, eg. capturing inputs and ensuring they don't get passed through to other callbacks on accident.
### Default callbacks
These are the callbacks that are built into Uranium:
Uranium Template's base functionality can be configured using `uranium.config`. You can access the raw values by requiring `uranium.config`, but this is currently undocumented.
`vector2D` is a simple 2D vector class system. For example, to define a vector:
```lua
local vec = vector2D(0, 0)
-- or
local vec = vector(0, 0)
-- or
local vec = vector(0)
-- or
local vec = vector()
```
Then add another vector to it:
```lua
vec = vec + vector(1)
print(vec) --> (1, 1)
```
Then measure its length:
```lua
local len = vec:length()
print(len) --> 1.4142135623730951
-- (sqrt of 2)
```
Then rotate it and index it:
```lua
vec:rotate(180)
local x = vec.x
-- or
local x = vec[1]
print(x) --> -1
```
#### `vector2D(x: number | nil, y: number | nil): vector2D`
Creates a new vector. If only `x` is passed in, `y` = `x`. If no arguments are passed, `x` = `y` = `0`.
#### `vectorFromAngle(ang: number | nil, amp: number | nil): vector2D`
Creates a new vector pointing in a specific angle. **Specify `ang` in degrees.**`ang` defaults to 0, `amp` defaults to 1.
#### `vector2D:length(): number`
Returns the vector's length. Equal to `vector:distance(vector())`.
#### `vector2D:lengthSquared(): number`
Returns the vector's length, squared. Here mainly for optimization purposes; this is a cheaper version of [`length()`](#vectorlength-number) that's less accurate.
Gets the distance between one vector and another, squared. Here mainly for optimization purposes; this is a cheaper version of [`distance()`](#vectordistancevect-vector-number) that's less accurate.
#### Operations
Here are all valid operations for vectors:
-`vector2D + number`: equal to `vector2D + vector2D(number)`
-`vector2D + vector2D`: adds the vectors' X and Y coordinates together, respectively, forming a new vector
-`vector2D - number`: equal to `vector2D - vector2D(number)`
-`vector2D - vector2D`: subtracts the vectors' X and Y coordinates, respectively, forming a new vector
-`vector2D * number`: equal to `vector2D * vector2D(number)`
-`vector2D * vector2D`: multiplies the vectors' X and Y coordinates together, respectively, forming a new vector
-`vector2D / number`: equal to `vector2D / vector2D(number)`
-`vector2D / vector2D`: divides the vectors' X and Y coordinates, respectively, forming a new vector
-`vector2D == vector2D`: checks if the two vectors' X and Y coordinates are equivalent; returns false with any other type
-`-vector2D`: negates the X and Y coordinates of the vector
Constructs a new color using the `h`, `s`, `l` and `a` values using the [HSL color model](https://en.wikipedia.org/wiki/HSL_and_HSV). Assumes all values are contained in the set [0, 1]. `a` defaults to 1; `h` wraps around.
Constructs a new color using the `h`, `s`, `v` and `a` values using the [HSV color model](https://en.wikipedia.org/wiki/HSL_and_HSV). Assumes all values are contained in the set [0, 1]. `a` defaults to 1; `h` wraps around.
Equal to [`hsv()`](#hsvh-number-s-number-v-number-a-number--nil), except the hue value is smoothed using cubic smoothing. Not accurate, but produces neater-looking color blends for rainbow-shifting colors.
```lua
local rainbow = shsv(t, 1, 0.5)
```
#### `hex(hex: string): color`
Reads in a hex string and parses it into a `color`. Accepted hex string formats are `#ffffff`, `ffffff`, `#fff` and `fff`.
Unpacks the color into its R, G, B and A values. Useful for `diffuse`:
```lua
local quad = Quad()
quad:diffuse(col:unpack())
```
#### `color:rgb(): number, number, number`
Returns the color's R, G and B values.
#### `color:hsl(): number, number, number`
Returns the color's H, S and L values in the [HSL color model](https://en.wikipedia.org/wiki/HSL_and_HSV).
#### `color:hsv(): number, number, number`
Returns the color's H, S and V values in the [HSV color model](https://en.wikipedia.org/wiki/HSL_and_HSV).
#### `color:hex(): string`
Returns the color's hex string representation in the format `ffffff`.
#### `color:hue(h: number): color`
Sets the color's hue value in the [HSL/HSV color model](https://en.wikipedia.org/wiki/HSL_and_HSV).
#### `color:huesmooth(h: number): color`
Equivalent to [`color:hue()`](#colorhueh-number-color), except the hue value is smoothed using cubic smoothing. Not accurate, but produces neater-looking color blends for rainbow-shifting colors.
#### `color:alpha(a: number): color`
Sets the color's alpha channel.
#### `color:malpha(a: number): color`
Sets the color's alpha channel, multiplying the previous value with `a`.
#### `color:invert(): color`
Inverts the color.
#### `color:grayscale(): color`
Makes the color grayscale using a more accurate formula than just multiplying every value by `0.5`.
#### `color:hueshift(a: number): color`
Shifts the color's hue by `a`.
#### Operations
Here are all valid operations for colors:
-`color + number`: equal to `color + rgb(number, number, number)`
-`color + color`: adds the colors' R, G and B values together, respectively, forming a new color
-`color - number`: equal to `color - rgb(number, number, number)`
-`color - color`: subtracts the colors' R, G and B values, respectively, forming a new color
-`color * number`: equal to `color * rgb(number, number, number)`
-`color * color`: multiplies the colors' R, G and B values together, respectively, forming a new color
-`color / number`: equal to `color / rgb(number, number, number)`
-`color / color`: divides the colors' R, G and B values, respectively, forming a new color
-`color == color`: checks if the two colors' R, G and B values are equivalent; returns false with any other type
Creates a new easable, setting the default to `default`. Can technically be anything that has `T * number`, `number - T` and `T + T` defined, including a `vector2D`.
`input` is the library that handles everything input-related. Its main feature is providing the `press` and `release` callbacks, but you can also access the raw inputs with the `inputs` table (each value is `-1` if the key is not pressed and the time at which it was pressed, estimated with `t` if it is pressed) and the _raw_ inputs (ignoring callback returns) with `rawInputs`.
#### `input.inputType`
The `input` module can detect every input that the game can pass through the [`StepP<player><input><action>MessageCommand`](https://craftedcart.gitlab.io/notitg_docs/message_commands.html#stepp-player-input-action-messagecommand). This list is:
```
MenuLeft
MenuRight
MenuUp
MenuDown
Start
Select
Back
Coin
Operator
Left
Right
Up
Down
UpLeft
UpRight
ActionLeft
ActionRight
ActionUp
ActionDown
Action1
Action2
Action3
Action4
Action5
Action6
Action7
Action8
MenuStart
```
All of these inputs are neatly stored away in an enum called `inputType`. For instance, if you wanted to check if an input was `Start`, you would do:
Shorthand for `input.getInput(i, pn) ~= -1`. If `pn` is not provided, players are ignored and it checks if either of the players have the input held down
Working with left/down/up/right inputs can be tiring at times and it's hard to always fit designs to work with them. However, if you're willing to take a little compromise, you can also _access all keyboard inputs_. However, it's worth noting that this **depends on NotITG's Simply Love** (any forks will work fine too) both for your development environment and for all players. That being said, if you want to access the keyboard API, this is how you do it:
```lua
-- check if the user is using simply love at all
if not stitch then error('This modfile requires the Simply Love theme! https://github.com/TaroNuke/Simply-love-NotITG-ver.-') end
keyboard = stitch('lua.keyboard')
-- table that contains every keyboard key as the key and a boolean as the value
local buffer = keyboard.buffer
-- for example:
local isDebugKeyHeld = buffer['F3']
-- contains booleans for shift, ctrl, alt, win and altgr
local special = keyboard.special
local isDebugKeyAndShiftHeld = isDebugKeyHeld and special.shift
```
### `bitop`
A Lua 5.0 port of [bitop-lua](https://github.com/AlberTajuelo/bitop-lua). See their repository for documentation.
local mydata = binser.serialize(45, {4, 8, 12, 16}, 'Hello, World!')
print(binser.deserializeN(mydata, 3))
-- 45 table: 0x7fa60054bdb0 Hello, World!
```
If you want to serialize custom types using the savedata module, check binser's [Custom types](https://github.com/bakpakin/binser#custom-types) section.
A copy of the [Mirin Template by XeroOl](https://github.com/XeroOl/notitg-mirin/) (currently at 5.0.1), shoved in and ported for your convinience. Works exactly the same as regular Mirin.
#### A note about `reset`
Both Uranium Template and Mirin Template contain the global `reset` - Mirin Template uses it for mod resetting, while Uranium Template uses it for actor resetting. To avoid this collision, Uranium's `reset` has an alias called `resetActor`; Mirin will, by default, overwrite the usual `reset`. There's currently no way to change this.
A complete library for saving and loading arbitrary data to the user's profile. Uses [binser](#binser) for serialization. See [Savedata example](#savedata-example) for an example of how to use this library.
Initializes the savedata module. `forceIgnore` makes the function ignore name checks, **but please don't use it unless you know what you're doing!!!**
##### Generating a savedata name
Ideally, you'd generate a savedata name by [generating a random 16-character string](https://www.random.org/strings/?num=1&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=plain&rnd=new) and appending it to your game's name. For instance:
The reason this is done is to avoid name collision - all modfiles share a global profile namespace to put their saved data in. To prevent it as much as possible, I've decided to force the user to generate a unique name that _most likely_ won't be taken by anything else. `forceIgnore` completely ignores the 16-character and special/normal character checks.
Creates a new module in your savedata. It uses `data` for defaults, then uses it for writing savedata to it and reading savedata from it; for instance, this would be correct usage:
By default, the name that's used for your module will be the folder your Lua file is located in, followed by its filename. **This means you should not rely on the automatic name generation if your Lua file rests at the root of your file or if you're calling this function via `loadstring` or similar** as it will create unpredictable module names that will change between setups and sometimes even game restarts. You can pass in any string you like to `name`, as long as it's unique in your project, to override this behavior.
#### `savedata.save(instant: boolean): void`
Saves the savedata onto the user's profile. It waits a single tick to do so and sets the boolean `saveNextFrame` to `true`; this is so that your game can display a loading frame for the temporary lagspike, as chances are, on lower-end setups with hard drives, this will momentarily freeze the game as it writes the profile. You can make it instantly save with `instant`.
Gets the last save time that persists between game restarts in the format `{hour, minute, date, month, year}`. If the game has not saved once, returns `nil`.
Initializes a new RNG class. `seed` must be a table of size 4; if it is not provided, `os.time()` is used in its place. _(Not `os.clock()`!!! Two RNG values created at the same time with no provided seed will be the same.)_
#### `rng(a: number | nil, b: number | nil): number`
Acts identical to `math.random()`. Pass in no arguments to get a random float from 0 to 1, pass in one argument to get a random inclusive integer from 1 to `a`, pass in two arguments to get a random integer from `a` to `b`.
#### `rng:int(min: number, max: number | nil): number`
Generates an inclusive random integer. Pass in one argument to get a random integer from 1 to `a`, pass in two arguments to get a random integer from `a` to `b`.
#### `rng:float(max: number | nil): number`
Generates a random fractional number from `0` to `max`. `max` defaults to 1.
#### `rng:bool(): boolean`
Generates either a `true` or a `false` randomly.
#### `rng:seed(seed: number): void`
Sets the seed and advances the state.
#### `rng:next(): number`
Gets the next pseudo-random value. Recommended to use [`int`](#rngintmin-number-max-number-number), [`float`](#rngfloatmax-number--nil-number), etc. over this.
#### `rng:jump(): void`
The jump function:
> This is the jump function for the generator. It is equivalent
> to 2^64 calls to next(); it can be used to generate 2^64
> non-overlapping subsequences for parallel computations.
#### `rng:longJump(): void`
The long-jump function:
> This is the long-jump function for the generator. It is equivalent to
> 2^96 calls to next(); it can be used to generate 2^32 starting points,
> from each of which jump() will generate 2^32 non-overlapping
> subsequences for parallel distributed computations.
A direct copy of [Mirin Template's `ease.lua`](https://github.com/XeroOl/notitg-mirin/blob/master/template/ease.lua), for convinience. See the docs for those [**here**](https://xerool.github.io/notitg-mirin/docs/eases.html).
A simple profiler for Uranium Template's callback system. Require it and it'll display in the left-top corner of your screen, showing what callback functions are taking the longest to run.
A single function which turns your file into an eternal, neverending file, until the player puts it out of its misery by exiting. The current beat will always go from 0 to 1 and start over once this is enabled. This also sets the notedata to nothing to avoid hitting padding mines.
**XeroOl** - Mirin Template was a massive design inspiration; early stages of this template borrowed lots of code from it and the current `require` implementation has been grabbed directly from it<br>