Entities are objects in the game world that participate in gameplay, such as units, buildings, and resource nodes (as opposed to purely decorative objects such as grass patches). Each entity can have a number of properties that are available to the game engine and game scripts. Entity properties are specified in XML files in binaries/data/mods/official/entities and its subdirectories. Because many objects have similar properties (for example, all infantry tend to have the same speed, all spearmen tend to have the same armour, etc), the entity files use inheritance to let you import traits from a "template" and just modify the ones you wish to change. Each file has a parent specified in the <Entity> tag and inherits that parent's properties, then any properties set or modified in its own XML file are applied on top of that.

Currently, the template_* entities in binaries/data/mods/official/entities, such as template_unit_infantry_spearman, hold most of the traits, and the civilization-specific entities in binaries/data/mods/official/entities/[civ], such as celt_infantry_spearman, just inherit from them.

The root parent for most entities is template_entity_full. Some very simple entities, such as trees, also have template_entity_quasi, which defines fewer event handlers and properties and is therefore more efficient to load.

Example:

<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> 
  
  <!-- Beware! The string "false" maps to 'true'. The only string that maps to 'false' is "". -->
 

  <Entity
  	parent="template_entity"
  >
  	<Traits 
		extant="true" 
		corpse="template_corpse"
	>

  		<Id>
  			<Internal_Only />  
  
  			<Generic>Infantry Spearman</Generic>
  			<Specific>Caldeer</Specific>
  
  			<Icon>sheet_civ</Icon>
  			<Icon_Cell>42</Icon_Cell>
  
  			<Classes>Unit, Infantry, Melee, Organic, CitizenSoldier, Male</Classes>
  			<Civ>Celts</Civ>
  
  			<Rollover>blah</Rollover>
  			<History>blah</History>
  
  			<Personal />
  		</Id>
  		
  		<AI>
                        <Behaviour>Support</Behaviour>
                          		  	
  			<Stance>
  				<List>
                                        <Aggress />
  				        <Defend />
  				        <Avoid />
  				        <Stand />
                                        <Hold />
  				</List>
                          	
  				<Curr>Defend</Curr>
  			</Stance>
 		</AI>
  
  		<Anchor>
  			<type>Ground</type>
  		</Anchor>
  
  		<Armour>
  			<crush>2.0</crush>
  			<hack>1.0</hack>
  			<pierce>0.0</pierce>
  		</Armour>
  
  		<Audio>
  			<path>audio/voices/hellenes/soldier</path>
  		</Audio>
  
  		<Creation>
  			<Time>20</Time>
  			<Resource>
  				<Food>2</Food>
  				<Wood>1</Wood>
  				<Stone>3</Stone>
  			</Resource>
  		</Creation>
  
  		<Footprint>
  			<radius>1.5</radius>
  			<width>3.0</width>
  			<depth>3.0</depth>
  			<height>7.5</height>
  		</Footprint>
    		
    		<Formation>
  			<Category>Melee</Category>
  			<Curr>Loose</Curr>
  			<List>
  				<Loose/>
  				<Box/>
  				<Column_C/>
  				<Line_C/>
  				<Column_O/>
  				<Line_O/>
  				<Flank/>
  				<Skirmish/>
  				<Wedge/>
  				<Testudo/>
  				<Phalanx/>
  			</List>
    		</Formation>
  
  		<Garrison>
  			<max>6</max>
  		</Garrison>
    
   	 	<Health> 
 		 	<Bar_Height>-1.0</Bar_Height>
  			<Bar_Size>20</Bar_Size>
 	 		<Bar_Width>2.0</Bar_Width>
 	 	 	<Regen_Rate>5.0</Regen_Rate>
   	  		<Regen_Start>15.0</Regen_Start>
  	  		<Decay_Rate>5.0</Decay_Rate>
  
 	  		<Border_Height>7</Border_Height>
 	  		<Border_Width>28</Border_Width>
 	  		<Border_Name>bar.dds</Border_Name>
  	 	</Health>
  	        <Stamina>
 	  		<Bar_Height>-1.0</Bar_Height>
 	   		<Bar_Size>20</Bar_Size>
 	   		<Bar_Width>2.0</Bar_Width>
 	   		<Border_Height>7</Border_Height>
 	     		<Border_Width>28</Border_Width>
 	  		<Border_Name>bar.dds</Border_Name>
 	  	</Stamina>
    		  
  		<Loot>
  			<XP>200</XP>
  			<Food>1</Food>
  			<Wood>1</Wood>
  			<Stone>1</Stone>
  			<Ore>1</Ore>
  		</Loot>
  		  
  		<MiniMap>
  			<type>Unit</type>
  			<red>100</red>
  			<green>200</green>
  			<blue>50</blue>
  		</MiniMap>
  
  		<Population>
  			<Add>1</Add>
  			<Rem>1</Rem>
  		</Population>
                
  		<Promotion>
  			<req>900</req>
  			<newentity>bob</newentity> (only if you want to do something other than normal rank progression)
  		</Promotion>
   
                <Rank>
 			<Width>7.0</Width>
 			<Size>17</Size>
 			<Height>-1.0</Height>
 			<Name></Name>
 		</Rank>
                 
  		<Supply>
  			<max>50</max>
  			<type>food</type>
  			<subtype>fruit</subtype>
  		</Supply>
  
  		<Vision>
  			<LOS>4</LOS>
  			<Permanent />
  		</Vision>
  
  		<Auras>
  			<Courage>
  				<Radius>20</Radius>
  				<Bonus>5</Bonus>
  			</Courage>
  			<Fear>
  				<Radius>20</Radius>
  				<Bonus>5</Bonus>
  			</Fear>
  			<Infidelity>
  				<Radius>20</Radius>
  				<Time>0</Time>
  			</Infidelity>
  			<Dropsite>
  				<Radius>50</Radius>
  				<Types>
  					<Food/>
  					<Wood/>
  					<Stone/>
  					<Ore/>
  				</Types>
  			</Dropsite>
 			<Heal>
 				<Radius>30</Radius>
 				<Rate>5</Rate>
 				<Speed>2000</Speed>
 			</Heal>
  			<Trample>
  				<Radius>8</Radius>
 				<Speed>1000</Speed>
 				<Duration>3</Duration>
 				<Damage>20.0</Damage>
 				<Crush>0.0</Crush>
 				<Hack>0.5</Hack>
 				<Pierce>0.5</Pierce>
  			</Trample>
  		</Auras>
 
                <Flank_Penalty>
 			<Sectors>6</Sectors>
 			<Value>.2</Value>
 		</Flank_Penalty>

  		<Pitch>
 			<Max_Actor>0.03</Max_Actor>
 			<Min_Actor>-0.03</Min_Actor>
 			<Divs>9</Divs>
 			<Value>.2</Value>
 		</Pitch>
   
  	</Traits>
  
  	<Actor>structures/celts/civil_centre.xml</Actor>
  
  	<Actions>
  		<Attack>
  			<Crush>0.0</Crush>
  			<Hack>5.0</Hack>
  			<Pierce>5.0</Pierce>
  			<Range>2.0</Range>
  			<Speed>1500</Speed>
  		</Attack>
  
  		<Create>
  			<List>
  			  	<StructCiv>civil_centre;farmstead;house;mill;market;temple</StructCiv>
  			  	<StructMil>barracks;dock;fortress;scout_tower;wall;wall_gate;wall_tower</StructMil>
  			  	<Unit>infantry_swordsman_b;infantry_spearman_b;infantry_javelinist_b;
                                       infantry_archer_b;infantry_slinger_b;cavalry_swordsman_b;
                                       cavalry_spearman_b;cavalry_javelinist_b;cavalry_archer_b;
                                       female_citizen</Unit>
  				<Tech>bob</Tech>
  			</List>
  			<Speed>100</Speed>
  		</Create>
                
  		<Gather>
                        <Resource>
  			        <Food>
  			        	<Meat>3000</Meat>
  				        <Fruit>3000</Fruit>
  			        	<Grain>3000</Grain>
  				        <Fish>3000</Fish>
  			        </Food>
  			        <Wood>3000</Wood>
  			        <Stone>3000</Stone>
  			        <Ore>3000</Ore>
                        </Resource>
  			<Range>2.0</Range>
  		</Gather>
                
  		<Loot>
                        <Resources />
                        <XP />
  		</Loot>
 
  		<Move>
  			<Speed>5.0</Speed>
  			<TurningRadius>0.0</TurningRadius>
  			<Run>
                                <Speed>10.0</Speed>
                                <Range>5.5</Range>
                                <RangeMin>2.0</RangeMin>
                                
                                <Regen_Rate>10.0</Regen_Rate>
                                <Decay_Rate>5.0</Decay_Rate>
  			</Run>
  		</Move>
 
  		<Patrol />
    	</Actions>
  
  	<Script File="entities/template_entity_script.js" />
  	<Event On="Initialize" Function="entityInit" />
  	<Event On="Death" Function="entityDeath" />
  
  	<Event On="TargetChanged" Function ="entityEvent_TargetChanged" />
  	<Event On="PrepareOrder" Function="entityEvent_PrepareOrder" />
  
  	<Event On="Attack" Function="entityEvent_Attack_Melee" />
  	<Event On="Attack" Function="entityEvent_Attack_Ranged" />
  	<Event On="Gather" Function="entityEvent_Gather" />
         
        <Event On="StartProduction" Function="entityStartProduction" />
        <Event On="CancelProduction" Function="entityCancelProduction" />
        <Event On="FinishProduction" Function="entityFinishProduction" />
  </Entity>

Extant

Set to "true" for the top-most entity in the hierarchy (i.e. template_entity). Otherwise defaults to false.

Corpse

The entity is replaced with this entity when it dies. (For example, a dead tree, a corpse, or a broken siege weapon.)

TODO: Make corpse entities disappear from the map after a period of time. This will likely require properties to indicate the method of removal (fade / sink into the ground) and the delay period before removal occurs should be available to JS for the graphics options menu.

Parent

Indicates the name of the entity from which this entity inherits any unspecified properties. If specified, any attributes -- including Events -- that are not defined in this XML object will be inherited from the specified parent object (which in turn inherits from its own parent, and so forth).

This makes the declaration of properties more efficient, since shared properties can simply bem declared just once and propagate down the entity tree to those that share them.

This inheritance tree means that we can be very efficient about our XML content. For example, we can express the events of upgrading, getting a new appearance on certain ranks, etc, in a single generic Citizen Soldier entity (which in turn could inherit even more basic building blocks from the grandparent), which each Citizen Soldier inherits. Where they differ from the norm, each unit then just specifies any unique attributes.

There's less repetition of data, global changes are a snap (make all infantry faster? No problem), the XMLs are smaller and load faster too.

Traits

Group object for "passive" properties: innate attributes that do not require any action on the part of the entity and little to no intervention from the player. Here we have information such as the entity's health, armour, and vision, what units can garrison in it, and how much it costs to create one. It also covers abilities and effects that occur automatically.

ID

These properties identify and classify an entity. Attributes include the unit's name, icon, class properties, tooltip rollover, historical information, and civilisation ownership.

AI

Entity action that is controlled by the computer is required to have an Artificial Intelligence attached to it. TODO: These properties are distinctly the product of guesswork and speculation based on other games ... The precise content will ultimately depend on what's needed for unit AI.

Anchor

This trait simply indicates the manner in which this entity should be attached to the terrain plane.

Armour

Armour is an attribute that absorbs/deflects attack damage.

Audio

These attributes handle the behaviours of sounds associated with this entity. TODO: The audio properties will be revised/implemented depending on those needed by the new sound requirements.

Auras

An "Aura" is a passive ability that affects other entities within a certain radius of the entity with an aura. It usually changes the statistics of affected units.

Creation

An entity with this trait can be created (constructed, trained) by an entity that has it in its Actions.Create.List. The Traits.Creation attributes define the requirements for creation of this entity (cost, time, pre-requisites, etc).

Footprint

These attributes define the "bounding box" of an entity (the area that it occupies). This is used in collision detection, for example. This area is also highlighted when the unit is selected.

Formation

Indicates how this entity is used in formations (the role it takes in a formation, and which formations it can use).

Garrison

If an entity has this trait, specified entities are able to garrison (be contained) within it.

Health

An object with this trait has a certain number of hitpoints that sustains him.

Loot

This trait determines the quantity of resources automatically added to an opponent's Resource Pool, and/or the experience points he receives, when he destroys this entity.

MiniMap

This attribute specifies how the entity appears on the Mini-Map.

Population

This object affects population in some way.

Promotion

An entity with this trait can accumulate experience points (see Traits.Loot.XP) and eventually accumulate enough to gain a promotion. This basically replaces him with a more advanced version of the unit.

Rank

Attributes of the rank bar.

Supply

An object with this attribute contains some kind of resource which can be harvested (generically known as "Supply").

Transform

An entity with this attribute can be replaced with another entity under certain conditions. Not yet implemented.

Vision

The object is able to reveal areas of the map within his sight radius, lifting Shroud of Darkness and Fog of War.

Actions

Group object for "active" properties (those that relate to actions that the entity can take ... How much damage it inflicts when it attacks, its gather rate, its ability to heal other units, construction rate, and so forth.

Actions are abilities that the entity can use, such as attacking an opponent, gathering a resource, or patrolling an area. These in turn have additional attributes that further define the behaviour of the action (such as how much damage the entity inflicts in attacks, and against what armour types, and how quickly the entity moves when performing a move action).

If there is no action assigned to the entity, then we can assume that it doesn't have that ability. Actions typically have a cursor and GUI button that can be used to command the entity to perform this action.

Attack

An object with this ability is able to attack opponents or wild animals.

Barter

An entity with the Barter action has a special market interface to buy and sell resources in exchange for other resources (used by the Market). Not yet implemented.

Create

An entity with the Create action is able to create (train, construct) other entities. For details about an entity's prerequisites and costs for creation, see the Traits.Creation trait.

Escort

Has an Escort GUI button (also performed by right-clicking a friendly entity). When commanded to Escort, the entity remains within close range of the target until directed otherwise, following and defending it. Not yet implemented.

Gather

An object with this ability can gather resources from some source of Supply and transfer it to the player's Resource Pool.

Graze

This is an action that's only used by animals. It simply causes the animal to move to the specified location and initiate a grazing animation there, to add more variety to its wander AI. Not yet implemented.

Heal

The Heal Action is used by the Healer unit to regenerate the health of the player's organic units. While the action is applied to a viable damaged target, his hitpoints increase until restored to maximum, while the entity performs his "Heal" animation. Not yet implemented.

Lock

The entity has alternating Lock and Unlock buttons in the GUI, which can be used to force its gate open or closed (unlocked gates stay open if a player entity is adjacent, but close to deny entry to the enemy). Not yet implemented.

Loot

This action allows a unit to retrieve an opponent's "loot" and experience points when he kills them (see Traits.Loot).

Move

An object with this ability can be commanded to move from one location to another.

Patrol

Has a Patrol button in the GUI. Once put on a patrol route, entity(s) repeatedly moves from one extreme limit back to the other, back and forth. There is no limit to the number of Patrol routes that may be set up.

Repair

The Repair Action is used by econ units (Citizen Soldiers) to regenerate the health of the player's mechanical mobile and non-mobile entities (structures, ships, siege weapons). While the action is applied to a viable damaged target, his hitpoints increase until restored to maximum, while the entity performs his "Repair" animation. Not yet implemented.

Scout

The entity has a Scout command in the GUI. Once put into Scout mode, the entity moves methodically back and forth through an enemy's Civ Territory in ever expanding arcs to reveal the terrain/entities there. Not yet implemented.

Trade

An entity with this ability is able to generate supply (resources) by travelling on a patrol route between two specified structures. (Note: The quantity it can carry and the type of resource is specified by the entity's Traits.Supply attributes.) Not yet implemented.

Event

Events are the conditions under which effects occur. An event is true when an entity enters a certain state. Generally the event jumps in just before the actual event takes place. For example, logic written for the Death event occurs just before the unit is about to die.

See below for a listing of all intended events.

Introduction

We want to hardcode the bare minimum of game logic into the engine. In designing these XML attributes, we strive to keep it flexible so that designers can easily adjust the nature and behaviour of the game's units and other objects with minimal bugging of overworked programmers.

However, trying to create an XML attribute for every contingency that could ever be required ("BelchesGreenFire=true") is an exercise in futility.

The event/action model uses the flexibility of JavaScript to embed script commands/functions/calls directly into the XML of a game object (entity, cliff, water, terrain, tech, actor, etc), which is then executed when a specific event occurs for an instance of this entity.

This allows custom logic to be written for an entity and encapsulated with its data, instead of having a special XML attribute that flags some logic which we assume to be "handled elsewhere".

Like the GUI, these commands could also call a function written in another file (good for reuse of code) or an engine function.

Warnings

Before we describe how events can be used, a couple of warnings:

  • Allowing script-based game logic gives modders and developers great power.. But that same power could be used to make 0 A.D. a hacker's paradise. We need to ensure that each player's data in a multiplayer game is sufficiently validated so that a player can't alter the script of his local version to give himself an unfair advantage (eg give himself resources every tick). Client/server architecture, out-of-sync checks, hashing, checksums, we need to use any means necessary to ensure modders have the freedom to adapt game data, while ensuring that players must have the same data version in order to play together.
  • Script code isn't as fast as engine code, so lots of resource-intensive script logic could slow the game down. Time will tell exactly how much we can get away with it. But initially, at least, we want to script almost everything. JavaScript at least makes a token effort to efficiency; if the same script is used multiple times, it only has to be parsed and compiled to bytecode once. There are two ways that we can take advantage of this feature to reduce the overhead:
  1. Wrap logic in a function wherever possible and call that, so that it can be called by other entities if needed.
  2. Entities can inherit attributes from each other, including event logic. For example, the behaviour for unit upgrading could be written once, in the generic-citizen-soldier entity. All Citizen Soldiers could then inherit from this entity, gaining the upgrade script automatically.
  • Events should generally be used for one-offs (eg raising/lowering of sails) or complicated exceptions (eg auras). For example, it isn't worth scripting the upgrade system into each Citizen Soldier's XML because so many units make use of it ... that would probably double the size of the entity files. Even wrapped in a function, it means more repetition of the same commands, which all have to be parsed and processed.

On

This list will grow as we implement and hammer down the details of game logic (eg formations, repairing, town bell, AI) ... It's easy for programmers to add additional events, but remember to minimise the amount of script that needs to be executed every frame. For example, it's less costly to check XYZBegin and XYZCancel than check XYZ every frame.

All the relevant data for an event will be copied to a special 'ev' object, allowing easy passing of event information to a script (i.e., for TakesDamage, there'd be ev.inflictor, ev.damage.crush, ev.damage.pierce, ev.range and so on).

Currently planned events are:

Attack

Occurs when the entity is commanded to attack another entity.

AuraComplete

When an entity has remained in aura radius for the length of time specified by Aura.Time. Not yet implemented.

AuraEnter

When an entity enters the aura radius of this entity. Not yet implemented.

AuraLeave

When an entity leaves the aura radius of this entity. Not yet implemented.

CancelProduction

Occurs when production of an entity has been prematurely cancelled (usually deliberately by the user). This is the time to refund any spent resources, remove the item for the GUI queue, etc.

CreateBegin

Occurs when creation (training/building/researching) of this entity has started. Not yet implemented.

CreateCancel

Occurs when creation (training/building/researching) of this entity has been cancelled by the user. Not yet implemented.

CreateComplete

Occurs when creation (training/building/researching) of this entity has finished. Not yet implemented.

Death

Occurs immediately before the entity is destroyed.

FinishProduction

Occurs when a production in the entity's queue completes its production time. At this point, the new entity should be spawned or the technology applied.

GarrisonEmpty

Occurs when all garrison slots are empty. Not yet implemented.

GarrisonEnter

Occurs when an entity is garrisoned in this entity. Not yet implemented.

GarrisonExit

Occurs when an entity is ungarrisoned from this entity. Not yet implemented.

GarrisonFull

Occurs when all garrison slots are occupied. Not yet implemented.

Gather

Occurs when the entity is commanded to Gather supply from another entity.

HoverStart

Occurs when the player places the cursor over the entity. Not yet implemented.

Initialize

Occurs when the entity first enters the world.

HoverStop

Occurs when the player moves the cursor off of the entity. Not yet implemented.

LOSEnter

When an entity enters the sight radius of this entity. Not yet implemented.

LOSLeave

When an entity leaves the sight radius of this entity. Not yet implemented.

MouseDown

Occurs when the player clicks on the entity. Not yet implemented.

MouseUp

Occurs when the player releases the mouse button, or moves the cursor off the entity. Not yet implemented.

OrderBegin

Occurs when the entity has been given a command and is about to start carrying it out. Not yet implemented.

OrderCancel

Occurs when the user cancels the order. Not yet implemented.

OrderComplete

Occurs when the entity has finished an order. Not yet implemented.

PrepareOrder

Occurs when the entity is given a new order.

SocketEnter

Occurs when an entity occupies a socket (prop point) in this entity. Not yet implemented.

SocketEmpty

Occurs when all sockets are empty. Not yet implemented.

SocketExit

Occurs when an entity occupies a socket (prop point) in this entity. Not yet implemented.

SocketFull

Occurs when all sockets are occupied. Not yet implemented.

StartProduction

Dispatched by ORDER_PRODUCE and occurs when the entity has started producing another entity which has been added to its queue. Resources and population space should be subtracted at this time.

  • evt.name: Name of the production, usually its entity name.
  • evt.productionType: int indicating the type of production (research, training, etc).
  • evt.time: The time it will take to complete the production. The event handler must set this value for each production so the game knows how long it should last. (Usually calculated from the entity's property Traits.Creation properties, plus any build speed bonuses, etc).
  • evt.preventDefault(): Prevent this production from starting (e.g. if the player doesn't have enough resources for it).

SupplyEmpty

Occurs when all Supply has been gathered from an entity. Not yet implemented.

SupplyFull

Occurs when an entity has reached its maximum Supply. Not yet implemented.

TakesDamage

Occurs when the entity is attacked by another entity.

NOTE: Right now this event has been removed, and the script calls a damage() function itself, so that the C++ engine doesn't need to know anything about damage types. If it is determined that some damage behaviour should be inherited, we can add in some functions to allow JavaScript to dispatch an event up the entity hierarchy and attach arbitary data to it.

TargetChanged

Occurs when the entity is given a new target.

Tick

Occurs every simulation frame; currently 10 Hz unless this framerate cannot be achieved. JavaScript isn't particularly efficient, so while this is a very powerful feature, it's almost always better to add an additional event to this list than constantly scan for a condition.

WalkOver

Occurs when an entity moves over the surface of it. Typically only used by terrains. Not yet implemented.

Function

Specifies a JS function that is executed when the event occurs. Note that the .js file that contains the function must first be included in the entity XML's scope using the <Script File="" /> attribute.

Dynamic Properties

A number of entity properties are not specified in the entity XML files, but are provided by the game for each entity to allow scripts to interact with it.

Last_Combat_Time

The variable entity.last_combat_time is used by the game to decide when to start health regeneration. It should be set by the scripts for any millitary events (when the entity is either attacking or receiving damage).

Production_Queue

The production queue of a given entity can be accessed through entity.production_queue. It provides the following fields and methods:

  • entity.production_queue.length: The number of items in the queue (read-only).
  • entity.production_queue.get(i): Get the production item at a particular index in the queue. A production item has the following properties (all read-only):
    • item.type: The production type, as in the event above.
    • item.name: The production name, as in the event above.
    • item.totalTime: How long the production takes to complete.
    • item.elapsedTime: How much time the entity has spent "working" on this production (i.e. with it at the head of its queue). When elapsedTime reaches totalTime, the production is complete and a FinishProduction event is fired.
  • entity.production_queue.cancel(i): Cancel production of the item at a particular index in the queue. This will cause a CancelProduction event to be fired, where the entity can grant back resources, etc to the player.
Last modified 9 years ago Last modified on Aug 20, 2008 9:23:57 PM