Modding Resources

As of r18964, the code base of 0AD attempts to deal with gatherable/tradable/tributable resources (e.g. food, wood) in an agnostic fashion. In other words, the resources are not hardcoded inside simulation components, the GUI or the AI.

This means that adding or removing resources are somewhat easier for modders to do, should they wish. The following guide attempts to show how to do just that.

Please Note: The process of adding a resource, although a lot easier than before, is still not very modder friendly, particularly in the later sections, and you may get errors that might seem confusing. Please visit the 0ad-dev irc channel if you have questions (and please stick around long enough for an answer).

Resources

0 A.D. currently has several different types of resources:

  • four normal resources: food, wood, stone, and metal
  • a special resource: population
  • a local resource (affecting only individual units): experience
  • a fundamental resource: time (time can not be edited, neither in 0 A.D. nor outside)

This page simply considers modifying normal resources and ignores all others.

How to edit an existing resource

Change a resource icon

Suppose you want to replace the meat icon used by “food” with a different one (because you care about historical accuracy and realize most people living in Antiquity could not afford meat even a single day in the year; or because you are a vegetarian and are opposed to the use of meat as generic food; or because you simply like to know how to change an icon; or for any other reason), all you have to do is create or edit two images:

  • food.png (the convention is 64×64 pixels)
  • food_small.png (16×16 pixels)

and place those in art/textures/ui/session/icons/resources/

Then launch the game and admire your icon being used everywhere for food.

Change a resource name or other aspects

The resources themselves are defined each in a separate {resource}.json file in simulation/data/resources/ Let's have a look at the complete file of resource number one, food, to see how it works; food.json:

{
  "code": "food",
  "name": "Food",
  "description": "Harvest from animals, berry bushes, fish, or fields.",
  "order": 1,
  "subtypes": {
    "fish": "Fish",
    "fruit": "Fruit",
    "grain": "Grain",
    "meat": "Meat"
  },
  "truePrice": 100,
  "aiAnalysisInfluenceGroup": "ignore"
}

It contains the following elements:

  • code - Internal identifying code for this resource. Cannot be the same as another resource
  • name - Player-friendly name of the resource. This will be localized into the player's chosen language (if localizing data exists for it)
  • order - The order it appears in the in-game GUI. Resources will appear in numerical order of this attribute.
  • subtypes - An object of Subtypes of this resource. At least one must be specified. The entries within this object follow the form "{subtype-code}": "{subtype-name}" where subtype-code is the internal reference to this subtype, and subtype-name is the user-friendly translatable name of the subtype. Resources can have the same subtype codes (e.g. both wood and stone both possess a ruin subtype).
  • truePrice - This is the true worth of the resource. This is used in calculating how much should be exchanged per click in the markets' Barter dialogue compared to other resources. See the Barter component for further details.
  • aiAnalysisInfluenceGroup - This is used by the AI to help determine where to build resource deposit sites and where to allocate workers. There are three possible values:
  • ignore - The AI will ignore this resource when it comes to planning where to build gather sites. This could be for several reasons, for instance that supplies of this resource move around (e.g. animals) or can be built by the player (e.g. farms)
    • abundant - This resource is abundant (very common) on the average map, but each deposit only contains a small amount of the given resource. (e.g. wood)
    • scarce - The resource has few deposits on the average map, but each deposit contains a fair to large quantity of the given resource. (e.g. stone or metal)

NB It is imperative that a {resource.json} file contains all these entries. So even if you do not want to use any subtype resources, you can not simply remove the "subtypes" element; a resource has to contain at least one subtype (the name does not really matter).

Examples of things you can easily change here:

  • add a “cheese” subtype in food.json
  • display “stone” consistently before “wood” everywhere in the game by swapping the order values in stone.json and wood.json
  • rename all entries of “Metal” in the game into “Iron” (0 A.D. is situated in the Iron Age) by changing the "name": element into "Iron", in metal.json
  • making a resource twice as expensive or half as valuable by changing the truePrice: element into 200, respectively 50,

How to remove a resource

Substraction is the inverse of addition. To remove a resource, in short, follow the instructions to add a resource (below), but in reverse making sure to remove all reference to the resource. Although not really difficult, it is a lot of work. Suppose you would want to remove a certain resource, e.g. food (because your units are not children anymore, they can look after themselves, and get their own food; just because AoE includes food as a resource doens't mean 0 A.D. has to as well). A sensible, though not necessary complete approach, could be:

  • remove all entries (e.g. Cost, Loot, ResourceGatherer?, etc.) in all simulation/data/ and simulation/templates/ (e.g. using grep food * is very helpful)
  • edit the simulation/ai files to prevent the AI from looking for the resource
  • remove the resource (objects) from the maps/ files
  • edit the gui/session/ files
  • edit gui/common/setup_resources.xml
  • finally, remove the file in simulation/data/resources/ by adding “.DELETED” behind the file name (e.g. create an empty file called food.json.DELETED)

How to add a new resource

Adding resources is not particularly difficult, provided you do not overlook any files (and there are quite a few you have to edit). Suppose you would want to add a new resource, e.g. “water”, then here is what you have to do.

Create the resource

  1. Create two icons:
    • art/textures/ui/session/icons/resources/water.json (64×64 pixels)
    • art/textures/ui/session/icons/resources/water_small.json (16×16 pixels)
  1. Create a new resource file: simulation/data/resources/water.json, e.g.:
    {
      "code": "water",
      "name": "Water",
      "order": 1.1,
      "subtypes": {
        "well": "Well Water"
      },
      "truePrice": 50,
      "aiAnalysisInfluenceGroup": "ignore",
    }
    
  1. Amend gui/common/setup_resources.xml so that you can use the icon in game UI texts (e.g. tech tree, tooltips); insert e.g.:
      <icon name="icon_water"
        sprite="stretched:session/icons/resources/water_small.png"
        size="16 16"
      />
    
  1. Modify the following files to a display a number of resources larger than four:
    • gui/session/selection_panels.js: search for g_SelectionPanels.Barter (currently line 96) and change the "getMaxNumberOfItems" and "rowLength" elements, e.g.:
        {
          return 5;
        },
        "rowLength": 5,
      
    • gui/session/selection_panels_left/barter_panel.xml (currently line 6): e.g. <repeat count="5"> (this value must match the return value of the JS file)
    • gui/session/top_panel/resources.xml (currently line 4): e.g. <repeat count="5">

(Note that due to 0 A.D.'s requirement to support a minimum screen resolution of 1024x768px, there isn't really enough space in the top panel for more than four resources plus the population count, nor is their in the market barter panel. If you do not care about this, the easiest solution, perfectly fine. If you do care, then the harder solution is to redesign the session UI. Good luck with that.)

  1. Insert Player/BarterMultiplier/ Buy/ and Sell/ elements, e.g. <water>1.0</water>, into:
    • simulation/templates/special/player.xml
    • simulation/templates/special/player_gaia.xml
  1. Insert a Production/TechCostMultiplier/ element, e.g. <water>1.0</water>, into:
    • simulation/templates/template_structure.xml (you can also do it in any of its descendants instead, but better do it here, in case you forget later)
    • any trainer unit templates (use grep TechCostMultiplier * to find them), e.g. simulation/templates/units/athen_ship_trireme.xml

Congratulations! You can now have, display, trade, barter, tribute, and spend “water”! You can now also “water” in technologies and templates (e.g. as costs, loot, resource trickle rate, etc.).

Gathering the new resource (in the normal way)

  1. Supply at least two cursors: one that shows when you want a unit to return with a stack of resources, the others are used for tasking a unit to gather.

In 0AD, a cursor is comprised of two files: a .png and a .txt. The first is the actual image displayed on screen, whilst the second marks the co-ordinates that should be considered the "point" of the cursor. Both files are named almost identically with the only difference being their given extension.

The cursor used when tasking a unit to gather follows the pattern action-gather-{res}.{ext}. So to create a gather cursor for the water resource, the .png will be called action-gather-water.png, and the .txt action-gather-water.txt.

In a similar fashion, the cursor used when tasking a unit to return with their stack of the gathered resource follows the pattern action-return-{res}.{ext}.

All four new files should be placed within art/textures/cursors/. They'll get included by 0AD automagically.

You will also need to provide gather (but not return) icons for each of your resource's subtypes. These follow the same pattern as before: action-gather-{subtype}.{ext}. These can just be renamed copies of your action-gather-{res}.{ext} icon. (Remember you'll need both a .png and a .txt)

  1. Provide something to gather from. For this you will need to create or modify an xml file to define the entity that will be your gather-site.

The parent template you may wish to inherit from will differ depending on your resource, for instance if your resource is something mined then inheriting from template_gaia_geo would be a good start, or if your resource comes from a plant then inherit from template_gaia_flora, or if gathered from some kind of structure (e.g. a farm) template_structure_resource.

Either way, in order to make the gather-site provide your resource you must include the ResourceSupply component into the template of your gather-site:

  <ResourceSupply>
    <KillBeforeGather>false</KillBeforeGather>
    <Amount>Infinity</Amount>
    <Type>water.well</Type>
    <MaxGatherers>1</MaxGatherers>
  </ResourceSupply>

For the specifics of what tag does what here, see the schema of the ResourceSupply component.

  1. To the templates of the units that will be doing the gathering (or the parent templates of those units), add a gather rate and carry capacity to the ResourceGatherer component. For example:
      <ResourceGatherer>
        <Rates>
          <water>1</water>
        </Rates>
        <Capacities>
          <water>10</water>
        </Capacities>
      </ResourceGatherer>
    
  1. Your units will then need to drop the resource off somewhere. If the resource is to be dropped off at a structure (or worker elephant) that already permits resource dropping off, add your resource type to the existing Types list inside the ResourceDropsite component. Else add the component to the structure:
      <ResourceDropsite>
        <Types>water</Types>
        <Sharable>true</Sharable>
      </ResourceDropsite>
    
  1. Lastly, modify the art/actor xml files of all the actors of all the units you wish to gather this new resource so as to tell the game which animations and props to use on units for gathering and returning with your new resource. Every civ that has that unit, every promotion level. The easiest way to do this is to use variants (see the contents of the art/variants folder for some idea of how this works), but it will still require modifying a lot of actor templates.

This step could be seen as optional, as the gathering will still take place without error, but without it units will just stand at the resource (playing the idle animation) until their resource capacity is full.

Teaching the AI to gather the new resource

For this you will have to edit some of the simulation/ai/ files.

Including your resource objects on maps

If you have created new objects from which your new resource can be gathered (e.g. water wells), you might want to include these into the maps/ files.

Summary

In short, to add a resource you need at least to create:

  • art/textures/ui/session/icons/resources/{newresource}.png
  • art/textures/ui/session/icons/resources/{newresource}_small.png
  • simulation/data/resources/{newresource}.json

and to edit:

  • gui/common/setup_resources.xml
  • gui/session/selection_panels.js
  • gui/session/selection_panels_left/barter_panel.xml
  • gui/session/top_panel/resources.xml
  • simulation/templates/special/player.xml
  • simulation/templates/special/player_gaia.xml
  • simulation/templates/template_structure.xml

This is sufficient for having, displaying, trading, bartering, tributing, and using a resource.

If you also want to make your resource gatherable, you'll need more icons, create templates, and edit AI files and maps; see the relevant sections (above).

Known Issues or Problems

  • The session gui is limited to displaying four resources (plus population count) in the top bar.
  • Modifying countless actor files to add animations and props is not very mod-friendly.
  • Modders may wish to restrict the ability to barter, trade, or tribute resources. This is not currently implemented, see #4370.
Last modified 17 months ago Last modified on Oct 28, 2017, 3:45:52 PM