Northgard Editor

**Northgard Editor** - IDE for writing and modifying scripts in Haxe programming language. Used to create Modifications (mods). In combination with Map Editor and CDB allows high-level of mod-ability for Northgard. To use scripts, mod has to have Map first.

## Default Script

Save following code as **script.hx** text file and put it together with your map file (**map.dat**)

```
// --- Named constants, settings and flags ---
var CONSTS = {
    DEBUG: false
}

// --- State to set onFirstLaunch, keep and serialize with Save  ---
DATA = {
}

// // --- BEGIN of BOILERPLATE ---
function saveState() {
    state.scriptProps = {
        DATA: DATA
    }
}

function init() {
    if(!isHost()) return;
    setPause(true);

    if (state.time == 0)
    {
        onFirstLaunch();
    }
    onEachLaunch();

    setPause(false);
}

function onFirstLaunch() {
    setVictory();
    // setObjectives(); // if you want to use Objectives API do it here, on first launch only
}

function onEachLaunch() {

}

// Regular update is called every 0.5s
function regularUpdate(dt : Float) {

}

function setVictory() {
    // state.removeVictory(Victory.Military);
    state.removeVictory(Victory.Fame);
    state.removeVictory(Victory.Money);
    state.removeVictory(Victory.Lore);
    state.removeVictory(Victory.Yggdrasil);
    state.removeVictory(Victory.OdinSword);
    state.removeVictory(Victory.Helheim);
    state.removeVictory(Victory.MealSquirrel);
}
// --- END of BOILERPLATE ---

```

## FAQ

### To set the victory condition to military only.

You can only do this through scripting, you can not use the Map Editor. Place this in the init() call to function:

```
function setVictory() {
    // Set up domination-only victory
    // state.removeVictory(Victory.Military);
    state.removeVictory(Victory.Fame);
    state.removeVictory(Victory.Money);
    state.removeVictory(Victory.Lore);
    state.removeVictory(Victory.Yggdrasil);
    state.removeVictory(Victory.OdinSword);
    state.removeVictory(Victory.Helheim);
    state.removeVictory(Victory.MealSquirrel);
}

```

### Can I choose my clan at start?

No, there is no functionality for that at this time. It will be hopefully be added in the future. If your map has DLC clans, then ALL players that join the map must have the DLC to play, regardless if they pick a DLC clan or not.

### Can I set teams in the Map Editor?

Yes, since September 2020 you can set teams in MapEditor.

But, for something more complex (i.e, making actual use of that teams) you can use scripts, see: http://northgard.net/doc/api/current/ScriptApi.html#setAlly

```
var p1 = getZone(160).owner;
var p2 = getZone(176).owner;
var p3 = getZone(189).owner;
p1.discoverZone(getZone(176));
p2.discoverZone(getZone(160));
p2.discoverZone(getZone(189));
p1.discoverZone(getZone(189));
setAlly(p1, p2);
setAlly(p3, p2);

```

In the above example, p2 is the leader of the team. The game will not auto-reveal home tiles of teammates, so you will need to do that yourself by calling discoverZone for each player to the other.

#### Help, setting teams won't work!

Make sure you have the correct zone numbers, and only one person is the leader for the whole team.

### Can I create my own units, heroes, characters, buildings?

No, there is currently no functionality to do anything like that. You can however change some values of existing buildings and units within the database.

### Can I have more than one of the same building on a tile?

No, though the devs have seen this request and may in the future deliver. Until then, you can manually place multiple of the same building into a tile, but the players would be unable to build multiple during the game.

### Can the number of buildings on a tile be increased?

Yes, to do so, simply set the value on the zone like this: `getZone(12).maxBuildings = 20;`
This will increase the number of allowed buildings on zone 12 to 20.

### What does it mean that a function is "host only"?

Many functions, in particular those that change the game state, can only be run by the host player. For example, the function addResource() under player can only be done by the host player. This means that if you the modder want to add 500 wood to all players at the start, only the host player can call that function. To do this, make sure you wrap all calls to host only functions with an if(isHost()) conditional. The script on the host player can then just loop through all the players can call addResources() for them.

### My game crashes, and I think it is because my loops are too big, what to do?

Your script has a very small amount of time to execute code before the game crashes. If you must process large numbers of things (all the zones on the map, 100+ units, etc), then you will want to chunk that scanning across multiple calls to regularUpdate(). For example, maybe only scan the even zones when state.time is even, or maybe only 30 zones at a time. Alternatively, store Zones of interest that you need to watch or don't scan Zones you don't care for, therefore reducing the number of lookups.

Reduce the number of times you do things, or alternate what you process on various modulo of state.time to spread out the computation. Since regularUpdate is called every 500ms, a small delay of a few updates won't be noticeable to the player.

### Can I change the commercial influence needed to win? What about other default victory conditions?

The amount of Fame required to win can be changed, but none of the other default victories can have their conditions changed. Instead, you should disable them and implement your own, or manipulate the resources of a player so they are earned slower (for example, take away Fame to make Fame requirement higher, or commercial influence, etc). See the FAQ "How do I make my own victory conditions" for more info.

If you just want to raise the Fame required for a Fame victory, then look at the rule "AltFameVictory".

### How do I make my own victory conditions?

You will need to use ScriptObjectives, seen here: http://northgard.net/doc/api/current/ScriptObjectives.html

For example, see below. Note, that all objectives must be created within the init() function call otherwise they will not work. If you want an objective to be seen only later, then you can set visibility to false and then change it to true when desired.

Then, in regular update, you will need to update your objectives to show the player their progress. And once the player has achieve the goal you set, you can call the following to make them win: http://northgard.net/doc/api/current/Player.html#customVictory

An example is shown below of setting up a new objective.

```
function onFirstLaunch() {
    state.objectives.add("farmObjectiveId", "Capture the farms", {showProgressBar:true, visible:true});
    state.objectives.setGoalVal("farmObjectiveId", 3);
}

```

Then, to update the value when the player captures a farm.

```
state.objectives.setCurrentVal("farmObjectiveId", 1);

```

Then, when the player has achieved the objective you set, give them the win.

```
customVictory("You have captured the farms, congrats!", "You failed to capture the farms, the rest of you lose!");

```

The first string is what the winning player and their team sees. The second string is what the losing players all see.

Note, not shown, is how to know when a farm is captured. That is very specific for a map, and your objective may differ, so it is omitted. You will need quite a bit of coding to track what players are doing on a map and mark the objective correctly.

### I can not check if player has Lighthouse

At this moment (July 2020) check for Lighthouse or RavenLighthouse is not working. You should use "Upgraded Port" instead.

```
   function hasLighthouse(p : Player) {
       return p.hasBuilding(Building.Port, false, false, true, null) || p.hasBuilding(Building.RavenPort, false, false, true, null);
   }

```

### Why can't I Add Happiness or Warband?

While Happiness and Warband are both resources, it seems they are unaffected by addResource and setResource. It isn't known why this is the case, but it could be because both resources are a "sum of their parts", meaning happiness is the sum of things that produce happiness and take it away. Warband is the sum of buildings that provide it, and units that take it away.

### How do I get the current or future months? How do I convert a year/month to seconds?

This will convert a calendar date into seconds, which is useful for comparing against state.time

```
   function calToSeconds(month:Int, year:Int) {
       // 60 seconds per month, and 12 months in a year
       return month * 60 + year * 60 * 12;
   }

```

This will, given a time, convert to the month in the year it will fall under, where 0 is March, and 11 is February.

```
   function convertTimeToMonth(time:Float) : Int {
       return toInt(time % 720 / 60);
   }

```

### I want something to happen only once after a certain time, how do I do that?

You can't just do state.time == DO\_THE\_THING, because state.time is a Float. This means it will return something like 5.0033505783. You'll instead need to do something like

```
   if(state.time > DO_THE_THING && !hasDoneTheThingYet) {
       hasDoneTheThingYet = true;
       // Do the thing
   }

```

Where hasDoneTheThingYet is a boolean you define globally. This will ensure you only run the code inside the if-statement once.

Note, that if you do something like toInt(state.time), while you can certainly use == now, don't forget that regularUpdate is called every 0.5 seconds, so you might do something twice!

### I want to scan the player units and find PREDICATE

Make this function and use in your code (replace PREDICATE/PREDICATENAME after Copy-Pasting):

```
   function findUnitsInZonePREDICATENAME(z : Zone) : Array<Unit> {
       var result = [];
       for( unit in z.units )
       {
           if( PREDICATE )
           {
               result.push(unit);
           }
           wait(0);
       }
       return result;
   }
   function findUnitsOfPlayerPREDICATENAME(p : Player) : Array<Unit> {
       var result = [];
       for( unit in p.units )
       {
           if( PREDICATE )
           {
               result.push(unit);
           }
           wait(0);
       }
       return result;
   }

```

Frequently-used predicates: ownership (unit.owner == p), (unit.owner != p); (non-)military check (unit.isMilitary),(!unit.isMilitary)

### How to save time and pre-load tiles that are used often throughout the script?

Put this above all code:

```
   var bases = [getZone(1), getZone(11), getZone(111), getZone(191)];

```

Then, when you need to scan through them use generic foreach loop:

```
   for( zone in bases ) {
       // CODE
   }

```

### Where I can see my Workshop-subscribed mods?

```
SteamLibrary\steamapps\workshop\content\466560\

```

### Which API features are only for single-player?

Most all features work singleplayer and multiplayer, however the host must control any changes to the game itself (such as creating units, modifying ore, setting teams, etc). For clients, the host should tell the client to play a cinematic, or use talk(), or to show buttons and objectives.

## Rules and Conquest Rules

There are 89 different rules that you can add to your mod that are used across the campaign, skirmish, and conquest. These rules come with lots of predefined behavior and are great for adding to mods, and many have attributes that can be changed to fine-tune the experience of the rule for your map. That said, many don't work or have odd behaviors. In an attempt to understand, the below table breaksdown the rules, whether they work, links to mods that use them, and notes about the rule.

If a rule is not listed below, it is likely not tested. Please help by testing rules and updating below! If you have published your mod to the workshop and made it publicly visible, please also link it here.

If a rule is marked as NO, do feel free to try it anyway. The game frequently gets updated and maybe people who tried it previously did something weird. Just don't be surprised if it doesn't actually work.

## Known Issues

* Cannot set units controllable
	+ Even mercenaries, used as the example in Documentation
* If drakkar is called with too many units, the game crashes
* Mercenaries do not belong to the Player.units array but instead to an array called "Player.capturedUnits".
* state.players.length will always return an incorrect value. It is recommended to copy out the array into your own, or write a wrapper to return length
	+ Now you can use state.startPlayers
* Cannot manipulate values of launched events
* BSilo and BSiloImproved bonuses don't work
* Cannot manipulate Warband. (Whether adjust Training Camp in .diff, or changing Warband as a Resource in script)
* Can't create Dictionaries/Maps data structures. Only arrays, anon structs, and primitives.
* Exceptions or failures in the script fail silently and stop execution of the script with no warning.
* Can't loop over all zones without exceeding the time budget and causing a crash
* Can't check for the Lighthouse in a tile, must check for an upgraded port
* No error reporting when game crashes to desktop
* Player defined callbacks will not work, and while functions can be passed as parameters, the script silently crashes when you try to call it
* If a player chooses random for a clan during setup in a multiplayer game, and other players choose a clan, the player choosing random can steal the chosen clan of another player
* If a player joins a game with a corrupted mod, the game will allow the player to pick any clan, but will crash to desktop after loading completes
* If the CDB isn't displayed correctly you have to make sure, that the following project is opened: "C:/programs/steamapps/common/Northgard/NGEditor". Don't open your custom map in here or it will bug! however you have to load the CDB.diff tile from your correct custom map under: ".../steamapps/common/Northgard/mods/your map".

## Community Wishlist

### Map Editor Suggestions

* Enable or disable victory conditions
* Manipulate the tile geometry
	+ allow arbitrary tile creation, size, boundaries, divisions
* Modify maximum buildings of a tile
* Allow map to be randomly generated at start instead of a pre-defined map
* Don't fix the clan selection to predefined clans, allow players to choose a clan
* Modify victory requirements within the map editor

### Script Editor Suggestions

* Debug, Output and/or Error log streams, crash dumps in mod directory.
* Disable Squirrel victory
* Classes and objects we can define and instantiate
* Map datastructure (not just anonymous structs)
* Arguments to callbacks for buttons (allows re-use of callback functions and expands functionality)
* Modifying a button's value/text after creation
* API to modify happiness/warband by fixed amounts
* Get the username of a player

### CDB Suggestions

* Custom art assets, units
* Modify more of the values
* Turn on/off abilities of units
* Freely add/remove/set Happiness and Warband amount of units

### General Suggestions

* When uploading a mod, it should only upload expected files, not everything in the directory
* Statistics screen at end of match
* Allow arbitrary team selection in lobby
* Have cosmetics work in modded games
* Not needing to subscribe to your own mod to host the game
* Link to mod in the lobby, or automatically download mods when joining a modded game
* Get the color of a player (currently, you have to hardcode the known color of a player at a location to know what color they are in scripts)
* Not needing a map file in order to run a script file as a mod
* More explanation of the player.setAILevel() function. In the map editor it has values -2 to 5 in half-increments, but the API takes only integers and does not explain the domain of inputs. Current recommendation is to pass in 5
* How to add the ability to create a mythical lure for another player to use, we can currently create a mythical lure but it remains inactive and doesn't spawn creatures as it should