How to create new enemies in Soulash

Hey guys,



As promised in the last week devlog, this weekend I'll dive into explaining how you can modify or create content for Soulash. This will be a bit technical devlog, but I'll try to explain everything as simple as possible. As you may know, the proper modding support with tools assisting with the creation of mods and a way to share them with other players will be the theme of a v0.4 major release, but it's possible to change a lot right now. Some things would be a pain to edit without an editor, like maps or animations, so today we'll dive into modifying spawns and creating new enemies in the game.

First, let's consider spawns. In Soulash enemies don't respawn during play. The game generates the AI entities with their equipment based on a predefined template - a set of rules. In your game folder, you can find a "data/organizations.json" file. This file specifies who and where should be created during the generation of a new world. If you're not familiar with JSON data format, essentially what you need to know is that array or list of things are defined inside brackets "[]", while objects or definition of things inside "{}". You can read about this in depth here, but we'll go through an example, so hopefully, everything will become apparent soon.

Player starting region in the v0.2.5 is 30,27,0 (x,y,z). The region at position 31,27,0 is positioned directly to the east, while 30,28,0 up north. Let's look through the organizations.json file in your text editor of choice and see what's up at 30,28,0. In most editors to find something inside a file, you need to press ctrl + f. We're looking for a line: "map": "30,28,0".

And this is what you should find in the file:

{ "id": 11, "level": 1, "name": "Fishmen", "map": "30,28,0", "workers": [313, 313, 313, 313, 313, 313, 313, 313], "recipes": [], "leader": -1 }



It's an object inside {} that describes what kind of entities the world generator will create on a region map with position 30,28,0. On the left side is the name of object properties, while on the right side, their values. Let's go through them one by one.

id field is a unique number identifier, you shouldn't need to change this value and if you want to add a new organization object, make the id field value to be higher than the last entry in the file.

field is a unique number identifier, you shouldn't need to change this value and if you want to add a new organization object, make the id field value to be higher than the last entry in the file. level field is not used inside the game. You can safely ignore it or write down the average level of entities you will create.

field is not used inside the game. You can safely ignore it or write down the average level of entities you will create. name is not used in the game as well, but it's the best way to identify what does this entry create.

is not used in the game as well, but it's the best way to identify what does this entry create. map is the location of the spawn.

is the location of the spawn. workers is a list of entities for the region separated by a comma. These numbers are unique identifiers from "data/entities.json" which we get to shortly.

is a list of entities for the region separated by a comma. These numbers are unique identifiers from "data/entities.json" which we get to shortly. recipes is a relic of the past, should be an empty array.

is a relic of the past, should be an empty array. leader doesn't have a special meaning inside the game for now, but it's the place to put the identifier of the boss for the region. -1 means there is no leader, just regular enemies. In Kabula entry you can find "leader": 38, where 38 is the unique identifier of Magnus.

Some entries also have "mark" and "mark_color" properties. These describe how to render the points of interest you can see on the world map (question marks and exclamation mark). We will skip them for today.

The most important properties are "workers", "map", and "leader". Now to create new groups of enemies or replace the ones we see right now, we need to know how to get their unique identifiers. Let's open the biggest of the data files: "data/entities.json".

This file describes everything you encounter in the game from a simple grass patch to random trees or mushroom spawners and all AI entities available. Soulash entities are created from 74 different components, and the count is still increasing during the development of the game. Describing them all would be out of the scope of this article, but I'll make a wiki for it at some point. Today we will focus on AI entities specifically, so we can create new enemies and spawn them inside the game. Let's take a Fishman as an example.

{ "artificial_intelligence": { "allies": [ 8 ], "enemies": [ 5 ] }, "components": [ "artificial_intelligence", "actor", "collidable", "fighter", "glyph", "health", "humanoid", "name", "moveable", "position_2d", "stamina", "statistics", "sight", "tags", "equipment", "experience_gainer" ], "corpse": "Fishman corpse", "description": "Placeholder", "equipment": { "backpack": [ { "chance": 0.4, "name": "Perch" } ], "right_hand": [ { "chance": 0.33, "name": "Primitive knife" }, { "chance": 0.33, "name": "Primitive spear" }, { "chance": 0.34, "name": "Primitive sword" } ] }, "experience_gainer": { "exp": 5, "level": 1 }, "glyph": { "color": [ 46, 136, 154 ], "id": 150, "tile_type": 0, "tiles": [ 0 ] }, "fighter": { "attackNames": ["Fist", "Kick", "Fin", "Bite"] }, "health": 45, "id": 313, "moveable": { "speed": 1.2 }, "name": "Fishman", "sight": { "infravision": false, "range": 7 }, "statistics": { "dexterity": [ 7, 12 ], "endurance": [ 10, 13 ], "intelligence": [ 6, 9 ], "strength": [ 10, 16 ], "willpower": [ 7, 10 ] }, "tags": [ 8, 9, 13 ] }

Whew, that's a lot more data. Fortunately, it's not as complicated as it looks (I hope). Let's go from the top.

"artificial_intelligence" and inside it "allies" and "enemies". This field describes how AI should act and will be expanded a lot in the future, but for now, it has a simplified form. Inside "enemies" there is number 5, which is a "tag" of the player. This is what makes an entity aggressive toward the player. We will get to know tags and their meaning later in the article. "components" is the list of components that describe this entity. If you want to add "statistics" component to the entity, it has to be a part of this array. Otherwise, the game will not process its values. Some elements are just mentioned here because they don't have other properties to be specified. Components without properties that we need for our AIs are: "actor" - necessary for the entity to take any action in the game. "collidable" - otherwise it won't be able to interact. "humanoid" - there is an optional "gender" property exposed, if, for example, you want to create only female enemies like amazons. "moveable" is necessary for the character to be able to move. "position_2d" is required for all entities that are not just background tiles like grass. "stamina" won't be necessary after one of the later patches, but right now attacking someone without stamina causes crashes, so it has to be added. "corpse" is a field required by entities with "health" property. It's the "name" of the body that will spawn when the character dies. "description" is a field required by "name" component. You can see some entities have "Placeholder" in the description. It's a keyword that triggers the random NPC generator to create a unique description for the entity. It's only available to entities with some tags. You can write the description yourself if you prefer to have a unique entity like Magnus. "equipment" describes items available to the AI. This part is split for all available slots (optional): backpack, head_armor, head_cloth, amulet, cape, ammo, right_hand, left_hand, torso_cloth, torso_armor, gloves, belt, ring1, ring2, legs_armor, legs_cloth, boots. There are a couple of options for item generation like: "chance" - percentage chance to have the item in the slot (adds up to the other options, so the above Fishman example will always have one of the three specified weapons in the right hand) "name" - the name of the item, not ideal solution because names have to be unique now, so this might have to be changed later on to "id". "stack" - number of items if the item is stackable, like arrows. "experience_gainer" - this describes the level of the entity and the "exp" you gain when you kill it. "glyph" - one of the signs or letters from the available tilesheet. This is a little tough to use without the editor.

"color" is the RGB color values from 0 to 255, the easiest way to pick a color is to use an online color picker. "id" is the tricky bit. This is the field that points to a position on the "Assets/gfx/tileset_bold32.png" for the tile of the entity. The count starts from the bottom left, goes to the right and moves back to the left when reaching the end. It's easier if you pick an existing glyph and move from there. For example, the Fishman "f" is at "id" 150. If you need "g", it's 1 to the right, so 151. Either way, I know this is a problem, and I'll resolve it with an editor in v0.4. "tile_type" and "tiles" are part of the non-ASCII tiles support. I haven't tested these for a long time, so it's best to leave them as they are. :) "fighter" is an optional component. If you would like to create a non-aggressive animal like hares or deers, you can skip it. It has a property "attackNames" which can replace some of the base attacks the entity can do without a weapon. In the example above, if Fishman loses his weapon, he can hit you with a fist, he can kick you, he can bite you or hit you with his fin. These are just flavor texts. The actual attack damage is the same. "health" is probably self-explanatory. It's the number of hit points before the character dies. "id" is the identifier we can use in "data/organizations.json" to spawn this entity. Remember that this value has to be unique. Otherwise, something else might be used by the scripts. The best way to keep that in check is to add new entities at the end of the file and check the last "id" there. "moveable" has a "speed" property. The base speed is 1.0, which is the player base speed. It's an equivalent of a single turn. A higher number means more time is required for the AI to make a move. "name" is the base name. It can be edited by the NPC generator if applicable. "sight" has two properties, "infravision" allows seeing in the dark, while "range" is the sight range in the number of tiles from the entity position. "statistics" describe all of the base entity statistics, but you can see that there are two values for each. The first one is the minimum value, and the second one - maximum. When the game creates the entity, it selects the actual value at random between the two specified here. "tags" are a way to categorize entities. There are multiple tags, and abilities can use them in their effects like poacher ability "sense life" that can mark the living beings in an area (but not undead for example). The "artificial intelligence" component also uses these tags to determine friends and foes. NPC generator can use these tags to determine the race and pick appropriate descriptions and names. You can see that these can be quite useful. Every entity can have multiple tags. The currently available tags are:

- (0) GOBLIN

- (1) HUMAN

- (2) ANIMAL

- (3) MAGIC

- (4) UNDEAD

- (5) PLAYER

- (6) DWARF

- (7) ELF

- (8) OWLMAN

- (9) ALIVE

- (10) TROGLODYTE

- (11) TROLL

- (12) ORC

- (13) FISHMAN

- (14) DEMON

- (15) SATYR

- (16) CENTAUR

- (17) MUTANT

- (18) INSECTOID

- (19) DRAGON

- (20) SKELETON

- (21) GHOUL

- (22) ZOMBIE



I hope I didn't bore you to death by now. Feel free to experiment, but remember to make copies of the changed files. An update to the game could replace your changes. There are a lot of things that you can do with these components, but also a lot of unusual combinations can probably result in crashes, so if it does happen, make sure to let me know what you changed. You can send me the zipped data files to support@wizardsofthecode.pro.

I know these are not easy to change, require some technical knowledge, and remembering different numbers. It's a problem we will be tackling in v0.4 with editors for maps, entities, abilities, and animations that will abstract all of these technical things so everyone who would like to, can create new regions, adventures, even new races, and professions and share them with others for truly unlimited number of unique experiences.

Let me know in the comments below if this is something you guys are interested at all and would like me to expand further into items and abilities before v0.4 that will come next year, or if it's way too hard to bother without editors. If your text editor doesn't support JSON validation, you can use one online to determine if the file structure is invalid.

Can't wait to see worlds with anvils made out of human corpses and scissors on Fishman. Crafting shirts on a sleeping Fishman sounds pretty epic, maybe it should be in the main game? Have fun!