Murto's Tower Defence Assets Guide

Information and discussion for custom maps and mods.
Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Murto's Tower Defence Assets Guide

Post by Murto the Ray » Wed Jul 27, 2016 8:17 pm

[font=Arial]Introduction[/font]

For the purpose of allowing players to create tower defence minigames, i have created several assets.

The assets include:
  • 5 YAML files
  • 5 SHPs
  • 17 lua scripts
This guide aims to show how you can use these to create your own tower defence map using these assets.


[font=Arial]Downloads[/font]

The download for the assets alone is available in two formats:

Download zip.

Download tar.gz


[font=Arial]Adding the assets[/font]

Ensure that your map in in an unpacked state before doing the following:
  • Download and unpack the assets.
  • Add the asset files to your map's directory. If there are any file name disputes then rename file appropriately
  • Add the following lines to the bottom of your map.yaml file, making sure to substitute any new file names due to disputes:

Code: Select all

Rules: rules.yaml, overrides.yaml, towers.yaml
Sequences: sequences.yaml
Weapons: weapons.yaml

All the tower defence assets have now been added to your map and are ready to be used.


[font=Arial]Definitions[/font]

[font=Arial]rules.yaml[/font]

The rules.yaml file includes several definition of actors that are custom to tower defence:

SPAWN: This actor is the entrance for enemies into the map

TARGET: An enemy actor's goal is to enter this actor, make sure it is accessible.

PATH: This actor should be placed onto every tile on every tile you do not want players to be build on. See path.lua.

BORDER: This actor should be placed to limit the movement of enemies. See path.lua.

CONTROLLER: This actor provides the build queue for the player. See controller.lua.

MODE_BUILD: This actor is used to enable the controller's building functionality. See controller.lua.

MODE_WAVE: This actor is used to disable the controller's building functionality. See controller.lua.

Here is an example of what your map may look like:

Image


[font=arial]overrides.yaml[/font]

The overrides.yaml file includes redefinitions for several actors to make them work better with tower defence:

BRIK: Removes buildability.

SILO: Removes buildability.

MSLO: Remove buildability.

^ENEMY: Make enemies block projectiles.

^Infantry: Inherit ^ENEMY and remove bounty.

^Vehicle: Inherit ^ENEMY, remove bounty and share cell.

^Ship: Remove bounty.

^NeutralPlane: Remove bounty.

^BasicBuilding: Remove bounty.

1TNK: Don't spawn actor on death.

2TNK: Don't spawn actor on death.

3TNK: Don't spawn actor on death.

4TNK: Don't spawn actor on death.

Zombie: Scale up 3x.


[font=arial]towers.yaml[/font]

The towers.yaml file includes a towers super-definition and a few example towers.

^Tower: Tower actor super-definition.

TOWER.MACHINE: Machine gun tower.

TOWER.LASER: Laser tower.

TOWER.TRACTOR: Slow tower, commented out as it has been superceded by the tesla tower.

TOWER.FOUNTAIN: Flame tower.

TOWER.MORTAR: Artillery tower.

TOWER.TESLA: Tesla tower.

DUMMY.TESLA: Dummy tesla weapon actor.


[font=arial]sequences.yaml[/font]

sequences.yaml contains sequence definitions for custom actors defined in rules.yaml.


[font=arial]weapons.yaml[/font]

weapons.yaml contains weapon definitions for the towers defined in towers.yaml.


[font=arial]Scripts[/font]

The first version of tower defence had a single, monolithic, script accomanied
by a couple of supplementary scripts. Version 2 features script modules which
each add something to the game but can (mostly) be removed without breaking
the game. This means modders should have an easier time adding custom content.
However it is difficult to ensure that core modules aren't dependent on one
another so it may take a while for updates.


[font=arial]config.lua[/font]

The config.lua script contains several global variables that can be set to
modify the game and it's core modules. At a later date config files will be
separated per module.

Config.lives: Sets the number of lives the player has. (Requires
lives.lua)

Config.maxLives: Sets the max lives the player has. (Requires lives.lua)

Config.player: Sets the player player.

Config.enemy: Sets the enemy player.

Config.neutral: Sets the neutral player.

Config.wavesToSurvive: Sets the number of waves the player must survive
to win. Set this to nil to make it endless.


[font=arial]wave-config.lua[/font]

wave-config.lua is the wave-specific config file. It contains several global variables
that have an effect on how waves are generated.

Config.initWaveNum: Sets the initial wave number.

[n]Config.waveOwner:[/b] Sets the player owner of the spawned wave actors.

Config.spawnDelay: Sets the delay between spawning enemies. (Requires
wave-manager.lua)

Config.waveTypes: Sets the actor types that can be generated using wave-maker.lua. The cost field specifies the cost of the unit in the budget calculation, the shares field specifies the chance the type is chosen (the higher, the more likely), the minWave field specifies the minimum wave this type can be spawned, the maxWave field specifies the maximum wave that the type can be spawned in. Cost is required.


[font=arial]interface.lua[/font]

The interface.lua script manages the user interface.

Interface.update(): Spdates the user interface.

Interface.output(): Returns a string to be displayed on screen.

Interface.setOutputFunc(func): Sets Interface.output to the function
func.


[font=arial]utility.lua[/font]

The utility.lua script provides a functions with broad use cases.


[font=arial]array.lua[/font]

The array.lua script provides utility functions with broad use cases for
array-like tables. Since this is for utility use I will not be documenting it.
The functions are all small and usually self-explanitory.


[font=arial]set.lua[/font]

The set.lua script provides utility functions with broad use cases for
set-like tables. Since this is for utility use I will not be documenting it.
The functions are all small and usually self-explanitory.


[font=arial]tesla.lua[/font]

The tesla.lua script makes the tesla weapon bounce between struck targets.

Tesla.hitTrigger(actor, n): Adds a trigger to actor which bounces tesla
hits to n other targets.

Tesla.addTriggers(actors, n): Calls Tesla.hitTrigger(actor, n) for each
actor in actors.


[font=arial]map-utility.lua[/font]

The map-utility.lua script provides several functions to make your life a
little easier when working with the map.

MapUtility.width(): Returns the map's width in cells.

MapUtility.height(): Returns the map's height in cells.

MapUtility.centre(): Returns the map's centre WPos.

MapUtility.inBounds(pos): Returns true if pos (CPos) is in the map's
bounds, returns false otherwise.


[font=arial]camera.lua[/font]

The camera.lua script provides a function to centre the camera.

Camera.centre(): Centres the camera.


[font=arial]path.lua[/font]

The path.lua script provides functionality for the PATH and BORDER actors,
using them to control passability and builability.

Path.updatePath(): Updates the table of PATH actors controlled by this
script.

Path.updateBorder(): Updates the table of BORDER actors controlled by
this script.

Path.pathEnabled(): Returns true if PATH actors are in the world,
returns false otherwise.

Path.setPathEnabled(state): Sets all PATH actors' IsInWorld to state.

Path.borderEnabled(): Returns true if BORDER actors are in the world,
return false otherwise.

Path.setBorderEnabled(state): Sets all BORDER actors' IsInWorld to state.


[font=arial]controller.lua[/font]

The controller.lua script provides functions for controlling a single
CONTROLLER actor, which manages production, for the player. This script keeps
track of a mode actor which provides prerequisites for production.

Controller.init(mode, func): Creates the CONTROLLER actor for the
player player defined in config.lua and gives it the mode actor mode. When
a non-building actor is produced, func is called with the actor as a
parameter. The controller actor is returned.

Controller.getMode(): Returns the mode actor of the controller.

Controller.setMode(mode): Sets the controller's mode actor to mode
and destroys the previous mode actor.


[font=arial]target.lua[/font]

The target.lua script keeps track of valid target actors for enemies to head
towards. TARGET actors are not automatically tracked as targets, instead they
need to be added manually. This allows you to enable/disable targets as you
wish.

Target.isTarget(actor): Returns true if the actor has been added as a
target.

Target.makeTarget(actor, func): Adds the actor as a target if it is not
already tracked as a target. func is the callback function for
Trigger.OnPassengerEntered.

Target.makeTargets(actors, funcs): Calls Target.makeTarget(actor, func)
for each actor in actors.

Target.removeTarget(actor): Removes actor from the table of tracked
target actors if it is being tracked.

Target.removeTargets(actors): Calls Target.removeTargets(actor) for
each actor in actors.

Target.getTargets(): Returns a table of currently tracked target
actors.


[font=arial]spawn.lua[/font]

The spawn.lua script keeps track of valid spawn actors for enemies to spawn
from. SPAWN actors are not automatically tracked as spawns, instead they need
to be added manually. This allows you to enable/diable spawns as you wish.

Spawn.isSpawn(actor): Returns true if the actor has been added as a
spawn.

Spawn.makeSpawn(actor, targets): Adds the actor as a spawn if it is not
already tracked as a spawn. targets is a table of target actors that enemies spawned
from actor can head towards.

Spawn.makeSpawns(actors, targets): Calls Spawn.makeSpawn(actor,
targets) for each actor in actors.

Spawn.removeSpawn(actor): Removes actor from the table of tracked spawn
actors.

Spawn.removeSpawns(actors): Calls Spawn.removeSpawn(actor) for each
actor in actors.

Spawn.getSpawns(): Returns a table of currently tracked spawn actors.

Spawn.getSpawnTargets(actor): Returns a table of valid targets for
actor if it is being tracked.


[font=arial]wave-manager.lua[/font]

The wave-manager.lua script handles waves and keeps track of wave information.

WaveManger.getWaveNum(): Returns the number of wave that the player is currently
on.

WaveManager.getTime(): Returns the time left (in ticks) for the current
wave to be completed if it is a timed wave.

WaveManager.getWave(num): Returns wave number num. Returns nil if the wave
has not been set.

WaveManager.setWaveNum(value): Sets the wave number to value.

WaveManager.setTime(value): Sets the time left to value.

WaveManager.setWave(num, types): Sets wave number num to types.

WaveManager.incWaveNum(value): Increments the wave number by value or 1 if value
is not provided. Use this to decrement by giving negative values of value.

WaveManager.sendWave(wave, time, deadFunc): Spawns actors from currently tracked
spawns and sends them towards currently tracked targets. If wave is provided then the wave is
recorded, otherwise it uses one previously set. If none have been set an error occurs. If time is
provided the wave will end after time ticks, otherwise it ends after all actors are dead. deadFunc
is called at the end of the wave and must be provided.


[font=arial]wave-maker.lua[/font]

The wave-maker.lua script provides functions for generating waves for use with wave-manager.lua.
If Config.waveTypes has been provided they will be automatically loaded in at the start of the map.

WaveMaker.getTypes(): Returns a table of added types.

WaveMaker.getCost(type): Returns the cost of type if it was defined.

WaveMaker.getShares(type): Returns the shares of type if it was defined.

WaveMaker.getMinWave(type): Returns the minWave of type if it was defined.

WaveMaker.getMaxWave(type): Returns the maxWave of type if it was defined.

WaveMaker.createWave(budget): Returns a table of types based on Config.waveTypes
and it's limitations. Budget is how much can be "spent" on units. The cost of a unit is deducted
from the budget when it is added to the wave.



[font=arial]lives.lua[/font]

The lives.lua script keeps track of the player's lives and provides several
functions for manipulating them.

Lives.init(lives, maxLives): Sets the player's current lives to lives
and their max number of lives to maxLives.

Lives.isAlive(): Returns true if the number of lives is greater than 0,
returns false otherwise.

Lives.getLives(): Returns the number of lives the player has left.

Lives.getMaxLives(): Returns the max number of lives the player can
have.

Lives.setLives(value): Sets the player's lives to value.

Lives.setMaxLives(value): Sets the player's max lives to value.

Lives.incLives(value): Increments the player's lives by value or 1 if
value is not provided.

Lives.decLives(value): Decrements the player's lives by value or 1 if
value is not provided.

Lives.toString: Returns a string representative of the lives remaining.
Must be set using Lives.setToStringFunc before use.

Lives.setToStringFunc(func): Sets Lives.toString to return func(lives,
maxLives).

Lives.setIncFunc(func): func is called when Lives.incLives is called.

Lives.setDecFunc(func): func is called when Lives.decLives is called.

Lives.setDeathFunc(func): func is called when the number of lives the
player has reaches 0 after a decrementation or a set.


[font=arial]main.lua[/font]

The main.lua script should, ideally be created by you. The modules described
above give a lot of functionality that can be utilised to create a custom
tower defence game. However, this is nothing stopping you from using the
provided main.lua instead.


Feedback

Feedback is welcome and so are suggestions. Don't be scared to comment/ask! If you have errors then please use www.pastebin.com to record them and then send me a link via IRC or comment here.
Last edited by Murto the Ray on Sun Jul 02, 2017 3:04 pm, edited 34 times in total.

User avatar
Norman_
Posts: 141
Joined: Wed Jan 30, 2013 1:39 pm
Location: TD Server

Post by Norman_ » Wed Jul 27, 2016 8:42 pm

great :)
Image

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Sat Jul 30, 2016 5:55 pm

The map has been updated several times, several crashes have been fixed and a few more features added.

noobmapmaker
Posts: 1086
Joined: Wed Dec 10, 2014 11:59 am

Post by noobmapmaker » Sat Jul 30, 2016 9:22 pm

Really cool and thanks for the guide. Itll take a bit of trying for me to get it working, but hope to make a map sometime soon. As said, I think RA provides alot of chances to build very nice topwer defense maps!
Playlist with ALL games of the Dark Tournament Youtube.com/CorrodeCasts
Consider supporting OpenRA by setting a bounty or by donating for a server

User avatar
raymundo
Posts: 117
Joined: Mon Mar 30, 2015 10:39 am

Post by raymundo » Sat Aug 06, 2016 1:24 am

Murto, you are doing great things here for the community, just coming here to say this! I will tinker away with this next rainy day I get :D

User avatar
zypres1
Posts: 258
Joined: Mon Oct 24, 2011 8:22 pm

Cool

Post by zypres1 » Sun Aug 07, 2016 10:58 am

Can anyone build nexus&tower-defence map. A mix between two cool maps...
Build defence towers and build units...

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Sun Aug 07, 2016 11:54 am

raymundo wrote: Murto, you are doing great things here for the community, just coming here to say this! I will tinker away with this next rainy day I get :D
Thanks Raymundo :) I'll continue to develop these kind of things while there is interest in them :)
zypres1 wrote: Can anyone build nexus&tower-defence map. A mix between two cool maps...
Build defence towers and build units...
I'd be willing if you can create a detailed proposal for the map's features.

zypres
Posts: 42
Joined: Mon Oct 17, 2011 12:50 am
Location: Bergen

nexus defence tower castle fight

Post by zypres » Mon Aug 08, 2016 10:04 pm

zypres1 wrote: Can anyone build nexus&tower-defence map. A mix between two cool maps...
Build defence towers and build units...
murto wrote:I'd be willing if you can create a detailed proposal for the map's features.
Ok, lets try, If you or others want to be inspired: Quick and ugly,...
  • up to 8 vs 8 (could also be 1 vs 1)
  • You start with 8 oil and one engie each to capture. Only controllable unit. Can help repair main-base once if not killed. Cannot capture
  • same eco as nexus map?
  • You can build the same as nexus map, but all upgrades are there.
  • You can also build one oil to get more income (but then you get less income from fighting)
  • You can see your enemies base.
  • You can build untill 1/3 of the map. Middle is only to watch incoming/outcoming
  • You can go top or bottom, some fights will only be on bottom, some will do incoming one place, and attack on the other. whatever they see the enemy does.
  • If tech center/main building dies, the game ends
  • You cannot repair
  • Defence towers cost is around the same as producing houses.
    you also get income from defence towers.
  • nuke is off, iron is on for all
  • you can build medic/mechanics
This focus should be to counter the enemies units.
We must try to make sure it does not stall like nexus, but the income will fix that

This map is insipred from warcraft 3 mod castle fight:https://www.youtube.com/watch?v=cvEkIBXwQd8
Attachments
game.png
Pic
game.png (782.18 KiB) Viewed 11662 times

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Wed Aug 17, 2016 10:23 am

*Update*

I have added support for external scripts now as well as moved all configs to a separate tower_defence_config.lua file so there is no need to go into the main script!

Enjoy 8)

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Thu Aug 25, 2016 12:20 pm

Just a warning to those using the assets for endless towdef; OpenRA will crash if you don't have sufficient memory. Before playing make sure you have plenty free. I am currently investigating into methods of preventing this.

User avatar
jaZz_KCS
Posts: 266
Joined: Tue Nov 10, 2015 4:46 pm
Location: Bremen

Post by jaZz_KCS » Thu Sep 01, 2016 10:29 am

Murto the Ray wrote: Just a warning to those using the assets for endless towdef; OpenRA will crash if you don't have sufficient memory. Before playing make sure you have plenty free. I am currently investigating into methods of preventing this.
Indeed, I tried it over here with a machine that has general RAM shortage anyways, and safe to say that I didn't get very far. #NotSkillRelated ;P
Image
RAGL -->Replay Archive<--

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Thu Jun 29, 2017 2:17 am

Guide has been updated for new version. Plenty of updates still to come.

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Thu Jun 29, 2017 12:56 pm

Assets have been updated with a fix for some of the functions in wave-manager.lua that would cause crashes when called.

User avatar
MustaphaTR
Posts: 198
Joined: Mon Aug 04, 2014 6:38 am
Location: Kastamonu, Turkey

Post by MustaphaTR » Thu Jun 29, 2017 1:23 pm

Murto the Ray wrote: Assets have been updated with a fix for some of the functions in wave-manager.lua that would cause crashes when called.
Looks like you forgot a "v" at line 32 of wave-manager.lua. It is giving lua error on end of wave.

Murto the Ray
Posts: 486
Joined: Mon Nov 10, 2014 4:34 pm

Post by Murto the Ray » Thu Jun 29, 2017 1:33 pm

MustaphaTR wrote: -Snip-
Assets have been fixed & updated. Included sound file for tesla weapon.

Post Reply