DLL Modding Guide, Lesson 3 - Creating a New Power

Next Lesson - Adding Your Power to the Game

Previous Lesson: Reading the Game's Code

Table of Contents

In our last lesson, we created a new class, directly copy-pasted from She Who Will Feast’s Eyes in the Shadows power. In this lesson, we’ll edit this class to do what we want.

Not every subclass we copy will have every function we want to override, but in this case it does. That means we can just rewrite every function contained in here, and when we’re done we’ll have a new power.

Open up P\_ThanosSnap.cs and rename “public class P\_EyesInShadow : Power” to “**public class P\_ThanosSnap : Power**”. This will make Visual Studio angry about the constructor having a different name than the class, so **rename the constructor as well**.

**getName()** should **return “Thanos Snap”**, and getDesc() should return “**Every named character not under your control has a 50% chance of dying instantly. Characters under your control will survive, but will gain 10 <b>menace</b>.**” Try to be precise with your descriptions, as you don’t want players getting unpleasant surprises later when it doesn’t quite match up with the code.

**getIconFore()** is the first complicated one. We could type in “return map.world.iconstore.” and look through the drop-down list for one that fits reasonably well, but none of the base game icons involve finger-snapping, and that won’t do at all. We’ll need to add our own.

Most square images in this game, including power icons, are 256x256 .png files. Paste this image into your mod folder in optionalData, named “power\_snap.png”:

I recommend building your art off images that you have the right to use and crediting the artists appropriately (the base image for this one is "When I snap my fingers you will wake up" by underwhelmer, licensed under CC BY-NC 2.0), but I’m not your dad. Openverse Creative Commons and Rawpixel are decent resources, and Rawpixel is particularly good for classical public domain paintings as seen in SoFG’s event art and settlements.

SoFG incorporates a special function for mods to insert their own art into the game. Replace getIconFore()’s current return with the following:

·        **return EventManager.getImg("thanos.power\_snap.png");**

Remember that “prefix” we listed in mod\_desc.json? That’s what we’re using here so the game knows where to look for the image file.

You’ll notice that EventManager is a type of class instead of an instance of that class, but we can still call a function based on it. Normally you can’t do this – you can tell a specific person to die, but you can’t tell Person to die. However, EventManager.getImg() is marked as a **static** function, which lets us use it without having a specific eventManager to work with. Static functions and properties are good when they’re not related to any specific instance of the class, though note that static properties won’t have their status saved and loaded with the game even if they’re public.

**validTarget()**: You’ll see that this one returns a “bool” – short for “Boolean”, and basically just means “true or false”. You’ll also see that this one comes in two different forms, one that takes a unit and one that takes a location. These determine whether the locations and units will appear as lit up on the casting screen (therefore whether you can cast them). Naturally, Eyes in the Shadows can never hit a unit, and it can only hit uninfiltrated settlements. For now, we’ll have the one for units **return false** and the one for locations **return true**, as the Snap doesn’t really target anyone in particular. The player can then click whatever location they want to cast it.

This is also a good time to talk about the other basic data structures (“**variables**”) you’ll be using a lot in SoFG. For general modding, the important ones are as follows:

* **int**: Short for “integer”. Can be any number from -2 billion to 2 billion (with some rounding), but can’t include fractions. For example, a character’s gold is an int.
* **double**: Can store around 15-17 digits worth of complexity, either in fractions or whole numbers. For example, a settlement’s shadow is a double between 0 and 1, and a modifier’s charge is a double normally between 0 and 300.
* **bool**: Can only be “true” or “false”.
* **string**: Basically a piece of text. You can do fancy things with strings like using formatting and pasting in numbers as part of the strings – Pr\_DeepOneCult.getDesc() includes a good example of this.
* **float**: A double, except that it can only store around 6-9 digits of complexity but takes up less space. Very rare in SoFG - these are only really used for map hexes (NOT locations), and you have to write their numbers differently. 0.5 is a double, 0.5f is a float.

**getCost()**: The power cost. Now that we know our variable types, we should know exactly what to do with this. I suggest “**return 1**”, so you can start snapping as soon as you load the game up.

**getFlavour()**: I never watched any movies with Thanos in them, so we’ll follow a proud programming tradition and **return "Goodbye world.”**

**getRestrictionText()**: This will show up in the power’s description, as well as appearing in the middle of the screen when selecting a target. This power is unrestricted, so we can write **return “Can target any location”**.

**cast(Location loc)**: Change to the following:

```
public override void cast(Location loc)
{
 base.cast(loc);

 foreach (Person person in map.persons)
 {

 if (person.unit == null || person.unit.isCommandable() == false)
 {

 if (person.isDead == false && Eleven.random.Next(2) == 0)
 {
 person.die("Killed by Thanos Snap", false, null);
 }

 }
 else
 {
 person.unit.addMenace(10);
 }
 }
}

```
As before, we’ll go over that bit by bit:

```
public override void cast(Location loc)

```
So far, the functions we’ve looked at have a return type like a string, bool, or int. “void” means that it has no return type, and you don’t need to end every possible chain of the function with a “return” call. The function does what it does without passing anything back to whatever called the function.

```
base.cast(loc)

```
Like with the constructor, this will run Power’s cast(Location loc) function – namely, playing a sound effect and spending the power cost.

```
foreach (Person person in map.persons)

```
"persons” is a data structure called a List (a List<Person> specifically), which contains a bunch of whatever it’s a list of. In this case, this contains every Person in the game, alive or dead.
The code within the curly brackets of a foreach loop will run once for every item in the list, and whatever item they’re working on currently will be called the named property. On the first runthrough “person” will be map.persons[0], on the second runthrough it’ll be map.persons[1], etc. Foreach loops are a simple way to do something “for each” item in a list.

```
if (person.unit == null || person.unit.isCommandable() == false)

```
There’s a lot going on with this one that we need to cover, but that’s because it’s one of the most important building blocks in programming.

This is an “if” statement – the stuff within the curly brackets will only happen if the contents of the if statement are true.

“==” means something different than “=” in C#. “==” means “resolves to true if the thing on the left and the thing on the right are the exact same”, and “=” means “set the thing on the left to the thing on the right”. Here are some other common operators and expressions:

* **!=** - “Does not equal”, resolves to true if the things on each side are different
* **||** - “or”, resolves to true if at least one of the things on either side of it is true
* **&&** - “and”, resolves to true only if both of the things on either side are true
* **<** - “Is less than”, resolves to true if the number on the left is less than the number on the right
* **<=** - “Is less than or equal to”, resolves to true if the number on the left is not greater than the number on the right
* **>** - “Is greater than”, resolves to true if the number on the left is greater than the number on the right
* **>=** - “Is greater than or equal to”, resolves to true if the number on the left is not less than the number on the right
* **is** - resolves to true if the thing on the left is of the type on the right, or one of its subtypes. For example, "if (person.unit is UM)" resolves to true if person.unit is a pure UM (not that those exist in-game), a UM\_HumanArmy, a UM\_RavenousDead, etc.
* **+**: “Plus” – resolves to the number on the left plus the number on the right
* **+=**: “Plus equals” – increases the first number by the second number – for example, “x += 1” is the same as “x = x + 1”
* **++**: Increases the number on the left by 1 - shorthand for “+= 1”
* **-, -=. --**: “Minus” – same as plus, except subtracts instead of adding.
* **\*, \*=**: “Times” – same as plus, except multiplies instead of adding.
* **/, /=**: “Divided by” – same as plus, except divides instead of adding.

The first part of that if statement is called a **null check**, and it’s very important. Other than the basic variables, properties can have a value of “null”, which means there’s nothing in them. For example, if it just said “if (person.unit.isCommandable() == false)”, it would work fine until it encountered a ruler or some other person who didn’t have a unit connected to them, and then it would cause the game to crash – can’t check “person.unit.isCommandable()” if there’s no person.unit. Don’t check an instance's property or call one of its functions until you’re absolutely certain the instance won’t be null.

Like with validTarget() earlier, Unit.isCommandable() is a bool function. That means, when we call it, it’ll turn into “true” or “false” depending on what gets returned.

To put everything together, that means the stuff in the curly brackets after this if statement will run for everyone who isn’t under your control.

```
if (person.isDead == false && Eleven.random.Next(2) == 0)

```
“Eleven” is a class comprised entirely of static functions and properties, which means we don’t need a specific instance of “Eleven”. We mostly use it because it stores the random number generator for the current map's seed.

Random is a class that takes a seed and uses it to spit out various random numbers. There’s a bunch of different ways to generate random numbers, but the simplest one is to use random.Next and give it an integer with the number of possible outcomes you want. It starts at 0, so random.Next(3) will give either a 0, a 1, or a 2.

Therefore, “Eleven.random.Next(2)” will be 0 about half the time.

```
person.die("Killed by Thanos Snap", false, null);

```
If you type in “person.die(“, it’ll tell you what parameters you need to feed it. In this case, we get told the following:

You have the helpfully named string “v” (the specific death message), the bool “printMsg” (if true, you get a pop-up about the death - we don't want that, since it would give a LOT of pop-ups), the object “killer” (objects can be a lot of things, but the game will generally check if they’re a Person or a Unit, and it’s safe to leave this as null if there is no Person or Unit doing the killing), and the bool printTurnMsg (if true, their death will show up in the events list on the right even if there is no pop-up). That one also says “= true” after it, which means we don’t actually need to give it a bool for this – it’s just that, if we don’t give it anything, it’ll just treat it as true.

```
else
{

```
The contents of the curly brackets after the word “else” will only run if the previous if statement was *not* true. That means we don’t need to null-check person.unit.addMenace(10), since the if statement would’ve been true if person.unit was null.

We need to use a special function for addMenace instead of just changing person.unit.inner\_menace, because adding menace requires the game to calculate what the new minimum menace should be. Thankfully, the game handles that for us if we use addMenace.

All in all, P\_ThanosSnap.cs should now look like this:

```
using Assets.Code;
using System;
using System.Text;
using UnityEngine;

namespace ShadowsThanosSnap
{
 public class P\_ThanosSnap : Power
 {
 public P\_ThanosSnap(Map map)
 : base(map)
 {
 }

 public override string getName()
 {
 return "Thanos Snap";
 }

 public override string getDesc()
 {
 return "Every named character not under your control has a 50% chance of dying instantly. Characters under your control will survive, but will gain 10 <b>menace</b>.";
 }

 public override Sprite getIconFore()
 {
 return EventManager.getImg("thanos.power\_snap.png");
 }

 public override bool validTarget(Unit unit)
 {
 return false;
 }

 public override bool validTarget(Location loc)
 {
 return true;
 }

 public override int getCost()
 {
 return 1;
 }

 public override void cast(Location loc)
 {
 base.cast(loc);
 foreach (Person person in map.persons)
 {

 if (person.unit == null || person.unit.isCommandable() == false)
 {
 if (person.isDead == false && Eleven.random.Next(2) == 0)
 {
 person.die("Killed by Thanos Snap", false, null);
 }
 }
 else
 {
 person.unit.addMenace(10);
 }

 }
 }

 public override string getFlavour()
 {
 return "Goodbye world.";
 }

 public override string getRestrictionText()
 {
 return "Can target any location.";
 }
 }

}

```
This concludes Lesson 3. With this, you should have a basic understanding of C#’s and SoFG’s building blocks. In the next lesson, we’ll actually put this power into the game.

Next Lesson - Adding Your Power to the Game

Previous Lesson: Reading the Game's Code

Table of Contents