2006-01-16 03:01:24 +01:00
/ *
DESCRIPTION : Functions that define the scripted behaviour of properties , particularly the effects of entity events and their properties when initialised .
NOTES :
* /
// ====================================================================
// To add a new generic order, do the following all within template_entity_script.js:
2006-08-25 08:04:33 +02:00
// * Pick a number to be its ID (add this to the "const"s directly below). f
2006-01-16 03:01:24 +01:00
// * Add code in the entityInit() function below that will call setActionParams to set the action's range, speed and animation if the entity supports this action. For example this.setActionParams( ACTION_GATHER, 0.0, a.range, a.speed, "gather" ) tells the entity that the action with ID of ACTION_GATHER has min range 0, max range a.range, speed a.speed, and should play the animation called "gather" while active.
// * Add code in entityEventTargetChanged() to tell the GUI whether the entity should use this action depending on what target the mouse is hovering over. This is also where you can set a cursor for the action.
// * Add code in entityEventGeneric() to deal with new generic order events of your type. Note that if you want to have your action handler in a separate function (is preferable), you need to also add this function to the entity object in entityInit() (its initialize event), e.g. this.processGather = entityEventGather.
2006-02-13 04:28:36 +01:00
const ACTION _NONE = 0 ;
2006-01-16 03:01:24 +01:00
const ACTION _ATTACK = 1 ;
const ACTION _GATHER = 2 ;
const ACTION _HEAL = 3 ;
2006-01-22 09:51:34 +01:00
const ACTION _ATTACK _RANGED = 4 ;
2006-02-26 10:56:47 +01:00
const ACTION _BUILD = 5 ;
2006-05-16 06:43:11 +02:00
const ACTION _REPAIR = 6 ;
2006-02-13 04:28:36 +01:00
2006-04-30 22:34:39 +02:00
const PRODUCTION _TRAIN = 1 ;
const PRODUCTION _RESEARCH = 2 ;
2006-07-02 06:30:33 +02:00
2005-12-15 22:55:18 +01:00
// ====================================================================
2005-12-13 09:03:49 +01:00
2006-10-06 16:21:56 +02:00
function entityInit ( evt )
2005-12-13 09:03:49 +01:00
{
2005-12-15 22:55:18 +01:00
// Initialise an entity when it is first spawned (generate starting hitpoints, etc).
2006-07-02 06:30:33 +02:00
// This function is called for all "full" entities - those inheriting from template_entity_full; there is a simpler version below
// called entityInitQuasi for quasi-entities (rocks, trees, etc) for which most of the things dealt with here don't apply.
2005-12-15 22:55:18 +01:00
2006-07-13 22:15:38 +02:00
startXTimer ( 1 ) ;
2006-06-10 05:05:16 +02:00
// If the entity is a foundation, we must deduct resource costs here
if ( this . building )
{
var template = getEntityTemplate ( this . building , this . player ) ;
var result = checkEntityReqs ( this . player , template ) ;
if ( result == true ) // If the entry meets requirements to be added to the queue (eg sufficient resources)
{
// Cycle through all costs of this entry.
var pool = template . traits . creation . resource ;
for ( resource in pool )
{
switch ( resource . toString ( ) )
{
case "population" :
case "housing" :
break ;
default :
// Deduct the given quantity of resources.
this . player . resources [ resource . toString ( ) ] -= parseInt ( pool [ resource ] ) ;
2006-10-08 19:34:46 +02:00
//console.write ("Spent " + pool[resource] + " " + resource + " to build " +
// template.traits.id.generic);
2006-06-10 05:05:16 +02:00
break ;
}
}
}
else
{
// Might happen if the player clicks to place 2 buildings really fast
evt . preventDefault ( ) ;
2006-10-09 06:16:01 +02:00
stopXTimer ( 1 ) ;
2006-06-10 05:33:22 +02:00
return ;
2006-06-10 05:05:16 +02:00
}
}
2005-12-16 23:52:10 +01:00
2006-07-13 22:15:38 +02:00
stopXTimer ( 1 ) ;
startXTimer ( 2 ) ;
2006-07-17 02:58:37 +02:00
// Attach our functions to ourselves
2006-09-09 01:58:57 +02:00
this . getAttackAction = getAttackAction ; // Note: required by CEntity
2006-07-17 02:58:37 +02:00
this . performAttack = performAttack ;
this . performAttackRanged = performAttackRanged ;
this . performGather = performGather ;
this . performHeal = performHeal ;
this . performBuild = performBuild ;
this . performRepair = performRepair ;
this . damage = damage ;
this . entityComplete = entityComplete ;
this . GotoInRange = GotoInRange ;
this . attachAuras = attachAuras ;
this . setupRank = setupRank ;
2006-10-26 23:35:25 +02:00
this . chooseGatherTarget = chooseGatherTarget ;
2006-07-17 02:58:37 +02:00
// Some temp variables to speed up property access
var id = this . traits . id ;
var health = this . traits . health ;
var stamina = this . traits . stamina ;
2006-02-26 10:56:47 +01:00
// If this is a foundation, initialize traits from the building we're converting into
2006-02-27 05:58:04 +01:00
if ( this . building && this . building != "" )
2006-02-26 10:56:47 +01:00
{
2006-05-16 06:43:11 +02:00
var building = getEntityTemplate ( this . building , this . player ) ;
2006-07-17 02:58:37 +02:00
id . generic = building . traits . id . generic ;
id . specific = building . traits . id . specific ;
id . civ = building . traits . id . civ ;
id . icon _cell = building . traits . id . icon _cell ;
2006-02-26 10:56:47 +01:00
this . traits . health . max = building . traits . health . max ;
2006-08-08 05:44:15 +02:00
this . buildPoints = new Object ( ) ;
this . buildPoints . curr = 0.0 ;
this . buildPoints . max = parseFloat ( building . traits . creation . time ) ;
2007-07-14 08:15:19 +02:00
this . traits . creation . buildingLimitCategory = building . traits . creation . buildingLimitCategory ;
2007-09-16 19:43:38 +02:00
if ( building . traits . supply )
{
this . traits . supply = new Object ( ) ;
this . traits . supply . max = building . traits . supply . max ;
this . traits . supply . curr = building . traits . supply . max ;
this . traits . supply . type = building . traits . supply . type ;
this . traits . supply . subType = building . traits . supply . subType ;
}
2006-02-26 10:56:47 +01:00
}
2005-12-15 22:55:18 +01:00
// Generate civ code (1st four characters of civ name, in lower case eg "Carthaginians" => "cart").
2006-07-17 02:58:37 +02:00
if ( ! id . civ _code && id . civ )
2005-12-13 09:03:49 +01:00
{
2006-07-17 02:58:37 +02:00
var civ _code = id . civ . toString ( ) . substring ( 0 , 4 ) ;
civ _code = civ _code . toString ( ) . toLowerCase ( ) ;
2005-12-15 22:55:18 +01:00
2006-07-17 02:58:37 +02:00
// Exception to make the Romans into rome and Hellenes into hele.
if ( civ _code == "roma" ) civ _code = "rome" ;
else if ( civ _code == "hell" ) civ _code = "hele" ;
id . civ _code = civ _code ;
2005-12-15 22:55:18 +01:00
}
// If entity can contain garrisoned units, empty it.
2006-02-26 10:56:47 +01:00
if ( this . traits . garrison && this . traits . garrison . max )
this . traits . garrison . curr = 0 ;
2005-12-15 22:55:18 +01:00
2006-02-26 10:56:47 +01:00
// If entity has health, set current to same, unless it's a foundation, in which case we set it to 0.
2006-07-17 02:58:37 +02:00
if ( health && health . max )
health . curr = ( this . building != "" ? 0.0 : health . max ) ;
2005-12-15 22:55:18 +01:00
2006-01-18 04:31:21 +01:00
// If entity has stamina, set current to same.
2006-07-17 02:58:37 +02:00
if ( stamina && stamina . max )
stamina . curr = stamina . max
2006-01-16 11:55:01 +01:00
2006-07-13 22:15:38 +02:00
stopXTimer ( 2 ) ;
startXTimer ( 3 ) ;
2007-09-16 19:43:38 +02:00
var supply = this . traits . supply ;
2006-07-17 02:58:37 +02:00
if ( supply )
2005-12-15 22:55:18 +01:00
{
// If entity has supply, set current to same.
2006-07-17 02:58:37 +02:00
supply . curr = supply . max ;
2005-12-15 22:55:18 +01:00
2006-08-01 05:29:10 +02:00
// If entity has type of supply and no subType, set subType to same
// (so we don't have to say type="wood", subType="wood"
if ( supply . type && ! supply . subType )
supply . subType = supply . type ;
2005-12-17 10:28:26 +01:00
2006-08-08 05:44:15 +02:00
// The "dropsiteCount" array holds the number of units with gather aura in range of the object;
2005-12-17 10:28:26 +01:00
// this is important so that if you have two mills near something and one of them is destroyed,
// you can still gather from the thing. Initialize it to 0 (ungatherable) for every player unless
// the entity is forageable (e.g. for huntable animals).
2006-08-08 05:44:15 +02:00
var dropsiteCount = new Array ( ) ;
2006-08-01 05:29:10 +02:00
initialCount = supply . subType . meat ? 1 : 0 ;
2005-12-17 10:28:26 +01:00
for ( i = 0 ; i <= 8 ; i ++ )
{
2006-08-08 05:44:15 +02:00
dropsiteCount [ i ] = initialCount ;
2005-12-17 10:28:26 +01:00
}
2006-08-08 05:44:15 +02:00
supply . dropsiteCount = dropsiteCount ;
2005-12-15 22:55:18 +01:00
}
if ( ! this . traits . promotion )
this . traits . promotion = new Object ( ) ;
// If entity becomes another entity after it gains enough experience points, set up secondary attributes.
if ( this . traits . promotion . req )
{
2006-07-16 21:33:33 +02:00
this . setupRank ( ) ;
2006-01-08 15:01:10 +01:00
// Give the entity an initial value of 0 earned XP at startup if a default value is not specified.
if ( ! this . traits . promotion . curr )
2006-07-16 21:33:33 +02:00
this . traits . promotion . curr = 0 ;
2005-12-15 22:55:18 +01:00
}
else
2005-12-29 09:43:38 +01:00
{
2006-01-08 15:01:10 +01:00
this . traits . promotion . rank = "0" ;
2005-12-29 09:43:38 +01:00
}
2006-07-13 22:15:38 +02:00
stopXTimer ( 3 ) ;
startXTimer ( 4 ) ;
2005-12-29 09:43:38 +01:00
// Register our actions with the generic order system
if ( this . actions )
{
2006-05-04 06:14:48 +02:00
if ( this . actions . move && this . actions . move . speed )
2006-08-08 05:44:15 +02:00
this . actions . move . speedCurr = this . actions . move . speed ;
2006-05-04 06:14:48 +02:00
2006-01-22 12:08:27 +01:00
if ( this . actions . attack && this . actions . attack . melee )
2005-12-29 09:43:38 +01:00
{
2006-01-22 09:51:34 +01:00
a = this . actions . attack . melee ;
2005-12-29 09:43:38 +01:00
minRange = ( a . minRange ? a . minRange : 0.0 ) ;
this . setActionParams ( ACTION _ATTACK , minRange , a . range , a . speed , "melee" ) ;
}
if ( this . actions . gather )
{
a = this . actions . gather ;
this . setActionParams ( ACTION _GATHER , 0.0 , a . range , a . speed , "gather" ) ;
}
if ( this . actions . heal )
{
a = this . actions . heal ;
this . setActionParams ( ACTION _HEAL , 0.0 , a . range , a . speed , "heal" ) ;
}
2006-01-22 12:08:27 +01:00
if ( this . actions . attack && this . actions . attack . ranged )
2006-01-22 09:51:34 +01:00
{
a = this . actions . attack . ranged ;
minRange = ( a . minRange ? a . minRange : 0.0 ) ;
2006-01-22 12:55:47 +01:00
// this animation should actually be "ranged" except the current actors still have it called "melee"
this . setActionParams ( ACTION _ATTACK _RANGED , minRange , a . range , a . speed , "melee" ) ;
2006-01-22 09:51:34 +01:00
}
2006-02-26 10:56:47 +01:00
if ( this . actions . build )
{
this . setActionParams ( ACTION _BUILD , 0.0 , 2.0 , this . actions . build . speed , "build" ) ;
}
2006-05-16 06:43:11 +02:00
if ( this . actions . repair )
{
this . setActionParams ( ACTION _REPAIR , 0.0 , 2.0 , this . actions . repair . speed , "build" ) ;
}
2005-12-29 09:43:38 +01:00
}
2005-12-15 22:55:18 +01:00
2006-07-13 22:15:38 +02:00
stopXTimer ( 4 ) ;
startXTimer ( 5 ) ;
2006-02-26 23:25:17 +01:00
this . attachAuras ( ) ;
2005-12-29 09:43:38 +01:00
2006-01-11 16:12:41 +01:00
// If the entity either costs population or adds to it,
if ( this . traits . population )
{
// If the entity increases the population limit (provides Housing),
if ( this . traits . population . add )
2006-06-10 05:05:16 +02:00
this . player . resources . housing += parseInt ( this . traits . population . add ) ;
2006-06-10 05:33:22 +02:00
// If the entity takes up Housing,
2006-01-11 16:12:41 +01:00
if ( this . traits . population . rem )
2006-06-10 05:05:16 +02:00
this . player . resources . population += parseInt ( this . traits . population . rem ) ;
2006-01-11 16:12:41 +01:00
}
2006-01-22 06:28:41 +01:00
2006-08-01 05:29:10 +02:00
// Build Unit Ai Stance list, and set default stance. ---> Can eventually be done in C++, since stances will likely be implemented in C++.
2006-03-01 21:23:09 +01:00
if ( this . actions && this . actions . move )
2006-01-22 06:28:41 +01:00
{
2006-03-01 21:23:09 +01:00
if ( ! this . traits . ai . stance . list )
this . traits . ai . stance . list = new Object ( ) ;
// Create standard stances that all units have.
this . traits . ai . stance . list . avoid = new Object ( ) ;
this . traits . ai . stance . list . hold = new Object ( ) ;
if ( this . actions && this . actions . attack )
{
// Create stances that units only have if they can attack.
this . traits . ai . stance . list . aggress = new Object ( ) ;
this . traits . ai . stance . list . defend = new Object ( ) ;
this . traits . ai . stance . list . stand = new Object ( ) ;
// Set default stance for combat units.
2006-10-08 19:34:46 +02:00
this . traits . ai . stance . curr = "aggress" ;
2006-03-01 21:23:09 +01:00
}
2006-01-22 06:28:41 +01:00
}
2006-02-26 10:56:47 +01:00
2006-10-26 23:35:25 +02:00
// Set up allure counter
if ( this . actions && this . actions . gather && this . actions . gather . affectedByAllure )
{
this . allureCount = 0 ;
}
2006-07-13 22:15:38 +02:00
stopXTimer ( 5 ) ;
2005-12-15 22:55:18 +01:00
/ *
// Generate entity's personal name (if it needs one).
if ( this . traits . id . personal )
{
// todo
// Look in the appropriate array for a random string.
switch ( this . traits . id . classes [ ] )
{
case "Male" :
this . traits . id . personal . table1 = "Male"
break ;
case "Female" :
this . traits . id . personal . table1 = "Female"
break ;
default :
this . traits . id . personal . table1 = "Gen"
break ;
}
this . traits . id . personal . name = getRandom ( this . traits . id . civ _code + this . traits . id . personal . table1 + "1" )
this . traits . id . personal . name = this . traits . id . personal . name + " " + getRandom ( this . traits . id . civ _code + this . traits . id . personal . table1 + "2" )
2005-12-13 09:03:49 +01:00
}
2005-12-15 22:55:18 +01:00
else
this . traits . id . personal . name = "" ;
* /
// Log creation of entity to console.
2005-12-16 00:20:53 +01:00
//if (this.traits.id.personal && this.traits.id.personal.name)
// console.write ("A new " + this.traits.id.specific + " (" + this.traits.id.generic + ") called " + this.traits.id.personal.name + " has entered your dungeon.")
//else
// console.write ("A new " + this.traits.id.specific + " (" + this.traits.id.generic + ") has entered your dungeon.")
2005-12-13 09:03:49 +01:00
}
// ====================================================================
2006-07-02 06:30:33 +02:00
function entityInitQuasi ( )
{
// Initialization function for quasi-entities like trees, rocks, etc; only sets up resources
2006-07-13 22:15:38 +02:00
startXTimer ( 6 ) ;
2006-07-17 02:58:37 +02:00
var supply = this . traits . supply ;
if ( supply )
2006-07-02 06:30:33 +02:00
{
// If entity has supply, set current to same.
2006-07-17 02:58:37 +02:00
supply . curr = supply . max ;
2006-07-02 06:30:33 +02:00
2006-08-01 05:29:10 +02:00
// If entity has type of supply and no subType, set subType to same
// (so we don't have to say type="wood", subType="wood"
if ( supply . type && ! supply . subType )
supply . subType = supply . type ;
2006-07-02 06:30:33 +02:00
2006-08-08 05:44:15 +02:00
// The "dropsiteCount" array holds the number of units with gather aura in range of the object;
2006-07-02 06:30:33 +02:00
// this is important so that if you have two mills near something and one of them is destroyed,
// you can still gather from the thing. Initialize it to 0 (ungatherable) for every player unless
// the entity is forageable (e.g. for huntable animals).
2006-08-08 05:44:15 +02:00
var dropsiteCount = new Array ( ) ;
2006-08-01 05:29:10 +02:00
initialCount = supply . subType . meat ? 1 : 0 ;
2006-07-02 06:30:33 +02:00
for ( i = 0 ; i <= 8 ; i ++ )
{
2006-08-08 05:44:15 +02:00
dropsiteCount [ i ] = initialCount ;
2006-07-02 06:30:33 +02:00
}
2006-08-08 05:44:15 +02:00
supply . dropsiteCount = dropsiteCount ;
2006-07-02 06:30:33 +02:00
}
2006-07-13 22:15:38 +02:00
stopXTimer ( 6 ) ;
startXTimer ( 7 ) ;
2006-07-02 06:30:33 +02:00
// Generate civ code (1st four characters of civ name, in lower case eg "Carthaginians" => "cart").
2006-07-17 02:58:37 +02:00
var id = this . traits . id ;
if ( ! id . civ _code && id . civ )
2006-07-02 06:30:33 +02:00
{
2006-07-17 02:58:37 +02:00
var civ _code = id . civ . toString ( ) . substring ( 0 , 4 ) ;
civ _code = civ _code . toString ( ) . toLowerCase ( ) ;
2006-07-02 06:30:33 +02:00
2006-07-17 02:58:37 +02:00
// Exception to make the Romans into rome and Hellenes into hele.
if ( civ _code == "roma" ) civ _code = "rome" ;
else if ( civ _code == "hell" ) civ _code = "hele" ;
2006-07-15 23:17:02 +02:00
2006-07-17 02:58:37 +02:00
id . civ _code = civ _code ;
2006-07-02 06:30:33 +02:00
}
2006-07-17 04:38:43 +02:00
/ *
// Original unoptimized version of the above code (for reference)
if ( this . traits . id && this . traits . id . civ )
{
var id = this . traits . id ;
id . civ _code = id . civ . toString ( ) . substring ( 0 , 4 ) ;
id . civ _code = id . civ _code . toString ( ) . toLowerCase ( ) ;
// Exception to make the Romans into rome.
if ( id . civ _code == "roma" ) id . civ _code = "rome" ;
// Exception to make the Hellenes into hele.
if ( id . civ _code == "hell" ) id . civ _code = "hele" ;
}
* /
2007-02-05 03:42:24 +01:00
this . damage = damage ;
2006-07-17 04:38:43 +02:00
2007-02-05 03:42:24 +01:00
stopXTimer ( 7 ) ;
2006-07-02 06:30:33 +02:00
}
// ====================================================================
2006-12-31 07:23:33 +01:00
// A special version of the entity init function that causes the unit to automatically start gathering
// nearby resources, for use in gameplay cinematics before full CPU player AI is implemented.
function entityInitGatherer ( evt )
{
// Call the original entityInit function
this . entityInit = entityInit ;
this . entityInit ( evt ) ;
// After initialization is complete, start gatherering the nearest thing we can;
// this has to be done later using setTimeout to ensure that other entities are initialized
setTimeout (
function ( ) {
this . chooseGatherTarget ( null , this . getVisibleEntities ( ) ) ;
} ,
100 , this
) ;
}
// ====================================================================
2006-07-16 21:33:33 +02:00
// Setup entity's next rank
function setupRank ( )
{
// Get the name of the entity.
entityName = this . tag . toString ( ) ;
2006-07-17 02:58:37 +02:00
// For accessing the this.traits.promotion object quicker
var promotion = this . traits . promotion ;
2006-07-16 21:33:33 +02:00
// Determine whether current is basic, advanced or elite, and set rank to suit.
switch ( entityName . substring ( entityName . length - 2 , entityName . length ) )
{
case "_b" :
// Basic. Upgrades to Advanced.
2006-07-17 02:58:37 +02:00
promotion . rank = "1" ;
2006-07-16 21:33:33 +02:00
// Set rank image to put over entity's head.
this . traits . rank . name = "" ;
break ;
case "_a" :
// Advanced. Upgrades to Elite.
2006-07-17 02:58:37 +02:00
promotion . rank = "2" ;
2006-07-16 21:33:33 +02:00
// Set rank image to put over entity's head.
this . traits . rank . name = "advanced.dds" ;
break ;
case "_e" :
// Elite. Maximum rank.
2006-07-17 02:58:37 +02:00
promotion . rank = "3" ;
2006-07-16 21:33:33 +02:00
// Set rank image to put over entity's head.
this . traits . rank . name = "elite.dds" ;
break ;
default :
// Does not gain promotions.
2006-07-17 02:58:37 +02:00
promotion . rank = "0"
2006-07-16 21:33:33 +02:00
break ;
}
// If entity is an additional rank and the correct actor has not been specified
// (it's just inherited the Basic), point it to the correct suffix. (Saves us specifying it each time.)
2007-01-06 06:10:48 +01:00
/ * a c t o r S t r = t h i s . a c t o r . t o S t r i n g ( ) ;
2006-07-17 02:58:37 +02:00
if ( promotion . rank > "1"
2006-07-16 21:33:33 +02:00
&& actorStr . substring ( actorStr . length - 5 , actorStr . length ) != nextSuffix + ".xml" )
2007-01-06 06:10:48 +01:00
this . actor = actorStr . substring ( 1 , actorStr . length - 5 ) + nextSuffix + ".xml" ; * /
2006-07-16 21:33:33 +02:00
}
// ====================================================================
2006-02-26 23:25:17 +01:00
// Attach any auras the entity is entitled to. This was moved to a separate function so that buildings can have their auras
// attached to them only when they finish construction.
function attachAuras ( )
{
2006-10-26 23:35:25 +02:00
// Add all auras defined in this.traits.auras
var t = this . traits . auras ;
var a ;
if ( t )
2006-02-26 23:25:17 +01:00
{
2006-10-26 23:35:25 +02:00
if ( t . courage )
2006-02-26 23:25:17 +01:00
{
2006-10-26 23:35:25 +02:00
a = t . courage ;
2006-08-25 08:04:33 +02:00
this . addAura ( "courage" , a . radius , 0 , a . r , a . g , a . b , a . a , new DamageModifyAura ( this , true , a . bonus ) ) ;
2006-02-26 23:25:17 +01:00
}
2006-10-26 23:35:25 +02:00
if ( t . fear )
2006-02-26 23:25:17 +01:00
{
2006-10-26 23:35:25 +02:00
a = t . fear ;
2006-08-25 08:04:33 +02:00
this . addAura ( "fear" , a . radius , 0 , a . r , a . g , a . b , a . a , new DamageModifyAura ( this , false , - a . bonus ) ) ;
2006-02-26 23:25:17 +01:00
}
2006-10-26 23:35:25 +02:00
if ( t . infidelity )
2006-02-26 23:25:17 +01:00
{
2006-10-26 23:35:25 +02:00
a = t . infidelity ;
2006-08-25 08:04:33 +02:00
this . addAura ( "infidelity" , a . radius , 0 , a . r , a . g , a . b , a . a , new InfidelityAura ( this , a . time ) ) ;
2006-02-26 23:25:17 +01:00
}
2006-10-26 23:35:25 +02:00
if ( t . dropsite )
2006-02-26 23:25:17 +01:00
{
2006-10-26 23:35:25 +02:00
a = t . dropsite ;
2006-08-25 08:04:33 +02:00
this . addAura ( "dropsite" , a . radius , 0 , a . r , a . g , a . b , a . a , new DropsiteAura ( this , a . types ) ) ;
2006-05-16 06:43:11 +02:00
}
2006-10-26 23:35:25 +02:00
if ( t . heal )
2006-05-16 06:43:11 +02:00
{
2006-10-26 23:35:25 +02:00
a = t . heal ;
2006-08-25 08:04:33 +02:00
this . addAura ( "heal" , a . radius , a . speed , a . r , a . g , a . b , a . a , new HealAura ( this ) ) ;
2006-05-16 06:43:11 +02:00
}
2006-10-26 23:35:25 +02:00
if ( t . trample )
2006-05-16 06:43:11 +02:00
{
2006-10-26 23:35:25 +02:00
a = t . trample ;
2006-08-25 08:04:33 +02:00
this . addAura ( "trample" , a . radius , a . speed , a . r , a . g , a . b , a . a , new TrampleAura ( this ) ) ;
2006-02-26 23:25:17 +01:00
}
2006-10-26 23:35:25 +02:00
if ( t . allure )
{
a = t . allure ;
this . addAura ( "allure" , a . radius , 0 , a . r , a . g , a . b , a . a , new AllureAura ( this ) ) ;
}
2006-02-26 23:25:17 +01:00
}
2006-07-10 01:13:20 +02:00
2006-10-26 23:35:25 +02:00
// Settlements also get a special aura that will let them change player when a Civ Centre is built on top
2006-07-10 01:13:20 +02:00
if ( this . hasClass ( "Settlement" ) )
{
2006-08-25 08:04:33 +02:00
this . addAura ( "settlement" , 1.0 , 0 , 0.0 , 0.0 , 0.0 , 0.0 , new SettlementAura ( this ) ) ;
2006-07-10 01:13:20 +02:00
}
2006-02-26 23:25:17 +01:00
}
// ====================================================================
2006-06-10 05:05:16 +02:00
function entityDestroyed ( evt )
{
// If the entity either costs population or adds to it,
if ( this . traits . population )
{
// If the entity increases the population limit (provides Housing),
if ( this . traits . population . add )
this . player . resources . housing -= parseInt ( this . traits . population . add ) ;
// If the entity occupies population slots (occupies Housing),
if ( this . traits . population . rem )
this . player . resources . population -= parseInt ( this . traits . population . rem ) ;
}
}
// ====================================================================
2006-02-26 10:56:47 +01:00
function foundationDestroyed ( evt )
{
if ( this . building != "" ) // Check that we're *really* a foundation since the event handler is kept when we change templates (probably a bug)
{
//console.write( "Hari Seldon made a small calculation error." );
2006-08-08 05:44:15 +02:00
var bp = this . buildPoints ;
2006-02-26 10:56:47 +01:00
var fractionToReturn = ( bp . max - bp . curr ) / bp . max ;
2006-05-16 06:43:11 +02:00
var resources = getEntityTemplate ( this . building , this . player ) . traits . creation . resource ;
2006-02-26 10:56:47 +01:00
for ( r in resources )
{
amount = parseInt ( fractionToReturn * parseInt ( resources [ r ] ) ) ;
2006-06-10 05:05:16 +02:00
this . player . resources [ r . toString ( ) ] += amount ;
2006-02-26 10:56:47 +01:00
}
}
}
// ====================================================================
2006-01-20 22:37:45 +01:00
function performAttack ( evt )
2005-04-15 06:23:33 +02:00
{
2006-08-08 05:44:15 +02:00
this . lastCombatTime = getGameTime ( ) ;
2006-01-23 04:55:35 +01:00
2007-01-20 19:35:02 +01:00
if ( getGUIGlobal ( ) . newRandomSound ) {
var curr _hit = getGUIGlobal ( ) . newRandomSound ( "voice" , "hit" , this . traits . audio . path ) ;
curr _hit . play ( ) ;
}
2005-04-15 06:23:33 +02:00
// Attack logic.
2006-02-26 10:56:47 +01:00
var dmg = new DamageType ( ) ;
2006-01-22 09:51:34 +01:00
if ( this . getRunState ( ) )
{
2006-05-13 06:08:41 +02:00
console . write ( "" + this + " doing a charge attack!" ) ;
2006-05-16 06:43:11 +02:00
var a = this . actions . attack . charge ;
2007-01-13 19:41:24 +01:00
dmg . crush = a . crush ;
dmg . hack = a . hack ;
dmg . pierce = a . pierce ;
2006-05-13 06:08:41 +02:00
this . setRun ( false ) ;
2006-01-22 09:51:34 +01:00
}
else
{
2006-05-16 06:43:11 +02:00
var a = this . actions . attack . melee ;
2007-01-13 19:41:24 +01:00
dmg . crush = a . crush ;
dmg . hack = a . hack ;
dmg . pierce = a . pierce ;
2006-05-16 06:43:11 +02:00
}
2006-06-06 08:31:17 +02:00
// Add flank penalty
2006-10-09 01:41:17 +02:00
var bonus = 1.0 ;
2006-08-08 05:44:15 +02:00
if ( evt . target . traits . flankPenalty )
2006-10-09 01:41:17 +02:00
bonus += ( evt . target . getAttackDirections ( ) - 1 ) * evt . target . traits . flankPenalty . value ;
bonus += getElevationBonus ( this . getHeight ( ) - evt . target . getHeight ( ) ) ;
dmg . crush *= bonus ;
dmg . hack *= bonus ;
dmg . pierce *= bonus ;
2006-01-22 09:51:34 +01:00
2005-04-15 06:23:33 +02:00
evt . target . damage ( dmg , this ) ;
2006-04-09 00:35:23 +02:00
2005-04-15 06:23:33 +02:00
}
2005-04-29 15:30:08 +02:00
// ====================================================================
2006-01-20 22:37:45 +01:00
function performAttackRanged ( evt )
2005-05-10 09:13:25 +02:00
{
2006-08-08 05:44:15 +02:00
this . lastCombatTime = getGameTime ( ) ;
2006-01-23 04:55:35 +01:00
2005-05-10 09:13:25 +02:00
// Create a projectile from us, to the target, that will do some damage when it hits them.
dmg = new DamageType ( ) ;
2006-05-16 06:43:11 +02:00
var a = this . actions . attack . ranged ;
2007-01-13 19:41:24 +01:00
dmg . crush = a . crush ;
dmg . hack = a . hack ;
dmg . pierce = a . pierce ;
2005-05-10 09:13:25 +02:00
2006-06-06 08:31:17 +02:00
// Add flank penalty and elevation bonus
2006-10-09 01:41:17 +02:00
var bonus = 1.0 ;
2006-08-08 05:44:15 +02:00
if ( evt . target . traits . flankPenalty )
2006-10-09 01:41:17 +02:00
bonus += ( evt . target . getAttackDirections ( ) - 1 ) * evt . target . traits . flankPenalty . value ;
bonus += getElevationBonus ( this . getHeight ( ) - evt . target . getHeight ( ) ) ;
dmg . crush *= bonus ;
dmg . hack *= bonus ;
dmg . pierce *= bonus ;
2006-05-04 06:14:48 +02:00
// The parameters for Projectile are:
2005-05-10 09:13:25 +02:00
// 1 - The actor to use as the projectile. There are two ways of specifying this:
// the first is by giving an entity. The projectile's actor is found by looking
// in the actor of that entity. This way is usual, and preferred - visual
// information, like the projectile model, should be stored in the actor files.
// The second way is to give a actor/file name string (e.g. "props/weapon/weap_
// arrow_front.xml"). This is only meant to be used for 'Acts of Gaia' where
// there is no originating entity. Right now, this entity is the one doing the
// firing, so pass this.
// 2 - Where the projectile is coming from. This can be an entity or a Vector3D.
// For now, that's also us.
// 3 - Where the projectile is going to. Again, either a vector (attack ground?)
// or an entity. Let's shoot at our target, lest we get people terribly confused.
// 4 - How fast the projectile should go. To keep things clear, we'll set it to
// just a bit faster than the average cavalry.
// 5 - Who fired it? Erm... yep, us again.
// 6 - The function you'd like to call when it hits an entity.
// There's also a seventh parameter, for a function to call when it misses (more
// accurately, when it hits the floor). At the moment, however, the default
// action (do nothing) is what we want.
// Parameters 5, 6, and 7 are all optional.
2006-10-04 06:49:17 +02:00
projectile = new Projectile ( this , this , evt . target ,
this . actions . attack . ranged . projectileSpeed ,
this , projectileEventImpact )
2005-05-10 09:13:25 +02:00
// We'll attach the damage information to the projectile, just to show you can
// do that like you can with most other objects. Could also do this by making
// the function we pass a closure.
projectile . damage = dmg ;
// Finally, tell the engine not to send this event to anywhere else -
// in particular, this shouldn't get to the melee event handler, above.
evt . stopPropagation ( ) ;
2006-01-02 04:07:29 +01:00
//console.write( "Fire!" );
2005-05-10 09:13:25 +02:00
}
// ====================================================================
2005-12-15 22:55:18 +01:00
function projectileEventImpact ( evt )
2005-05-10 09:13:25 +02:00
{
2006-01-02 04:07:29 +01:00
//console.write( "Hit!" );
2006-10-18 00:34:11 +02:00
if ( evt . impacted . damage )
evt . impacted . damage ( this . damage , evt . originator ) ;
2005-05-10 09:13:25 +02:00
// Just so you know - there's no guarantee that evt.impacted is the thing you were
// aiming at. This function gets called when the projectile hits *anything*.
// For example:
2006-10-08 19:34:46 +02:00
//if( evt.impacted.player == evt.originator.player )
// console.write( "Friendly fire!" );
2005-05-10 09:13:25 +02:00
// The three properties of the ProjectileImpact event are:
// - impacted, the thing it hit
// - originator, the thing that fired it (the fifth parameter of Projectile's
// constructor) - may be null
// - position, the position the arrow was in the world when it hit.
// The properties of the ProjectileMiss event (the one that gets sent to the
// handler that was the seventh parameter of the constructor) are similar,
// but it doesn't have 'impacted' - for obvious reasons.
}
// ====================================================================
2006-01-20 22:37:45 +01:00
function performGather ( evt )
2005-04-15 06:23:33 +02:00
{
2005-12-17 10:28:26 +01:00
g = this . actions . gather ;
s = evt . target . traits . supply ;
2006-08-08 05:44:15 +02:00
if ( ! s . dropsiteCount [ this . player . id ] )
2005-12-17 10:28:26 +01:00
{
2006-02-13 03:06:57 +01:00
// Entity has become ungatherable for us, probably meaning our mill near it was killed; cancel order
evt . preventDefault ( ) ;
2005-12-17 10:28:26 +01:00
return ;
}
2006-10-26 23:35:25 +02:00
var allureMod = 1 ;
if ( g . affectedByAllure && this . allureCount > 0 )
allureMod = 1.2 ;
2006-08-01 05:29:10 +02:00
if ( g . resource [ s . type ] [ s . subType ] )
2006-10-26 23:35:25 +02:00
gather _amt = parseFloat ( g . resource [ s . type ] [ s . subType ] * allureMod ) ;
2005-04-17 08:00:00 +02:00
else
2006-10-26 23:35:25 +02:00
gather _amt = parseFloat ( g . resource [ s . type ] * allureMod ) ;
2005-04-17 08:00:00 +02:00
2005-12-17 10:28:26 +01:00
if ( s . max > 0 )
2005-04-15 06:23:33 +02:00
{
2005-12-17 10:28:26 +01:00
if ( s . curr <= gather _amt )
2005-09-14 02:50:25 +02:00
{
2006-07-15 23:17:02 +02:00
gather _amt = s . curr . valueOf ( ) ;
2005-09-14 02:50:25 +02:00
}
2006-07-15 23:17:02 +02:00
2005-09-14 02:50:25 +02:00
// Remove amount from target.
2005-12-17 10:28:26 +01:00
s . curr -= gather _amt ;
2006-07-15 23:17:02 +02:00
2005-09-14 02:50:25 +02:00
// Add extracted resources to player's resource pool.
2006-06-10 05:05:16 +02:00
this . player . resources [ s . type . toString ( ) ] += gather _amt ;
2005-12-17 10:28:26 +01:00
// Kill the target if it's now out of resources
if ( s . curr == 0 )
{
evt . target . kill ( ) ;
}
2005-04-15 06:23:33 +02:00
}
}
2005-11-13 07:43:04 +01:00
// ====================================================================
2005-12-15 22:55:18 +01:00
2006-01-20 22:37:45 +01:00
function performHeal ( evt )
2005-11-13 07:43:04 +01:00
{
2006-08-28 05:07:07 +02:00
if ( this . player . getDiplomaticStance ( evt . target . player ) == DIPOLMACY _ENEMY )
2005-11-13 07:43:04 +01:00
{
2006-10-08 19:34:46 +02:00
//console.write( "You have a traitor!" );
2005-11-13 07:43:04 +01:00
return ;
}
2005-12-15 22:55:18 +01:00
// Cycle through all resources.
2006-06-10 05:05:16 +02:00
pool = this . player . resources ;
2005-12-15 22:55:18 +01:00
for ( resource in pool )
2005-11-13 07:43:04 +01:00
{
2006-02-23 19:22:30 +01:00
switch ( resource . toString ( ) )
2005-12-15 22:55:18 +01:00
{
2006-06-10 05:05:16 +02:00
case "population" || "housing" :
2005-12-15 22:55:18 +01:00
break ;
default :
// Make sure we have enough resources.
if ( pool [ resource ] - evt . target . actions . heal . cost * evt . target . traits . creation . cost [ resource ] < 0 )
{
console . write ( "Not enough " + resource . toString ( ) + " for healing." ) ;
return ;
}
break ;
}
2005-11-13 07:43:04 +01:00
}
evt . target . traits . health . curr += this . actions . heal . speed ;
2006-10-08 19:34:46 +02:00
//console.write( this.traits.id.specific + " has performed a miracle!" );
2005-11-13 07:43:04 +01:00
if ( evt . target . traits . health . curr >= evt . target . traits . health . max )
{
evt . target . traits . health . curr = evt . target . traits . health . max ;
}
2005-12-15 22:55:18 +01:00
// Cycle through all resources.
2006-06-10 05:05:16 +02:00
pool = this . player . resources ;
2005-12-15 22:55:18 +01:00
for ( resource in pool )
{
2006-02-23 19:22:30 +01:00
switch ( resource . toString ( ) )
2005-12-15 22:55:18 +01:00
{
2006-06-10 05:05:16 +02:00
case "population" :
case "housing" :
2006-02-26 10:56:47 +01:00
break ;
2005-12-15 22:55:18 +01:00
default :
// Deduct resources to pay for healing.
2006-06-10 05:05:16 +02:00
this . player . resources [ resource . toString ( ) ] -= parseInt ( evt . target . actions . heal . cost * evt . target . traits . creation . cost [ resource ] ) ;
2006-02-26 10:56:47 +01:00
break ;
2005-12-15 22:55:18 +01:00
}
}
2005-11-13 07:43:04 +01:00
}
2005-12-15 22:55:18 +01:00
2005-04-29 15:30:08 +02:00
// ====================================================================
2006-02-26 10:56:47 +01:00
function performBuild ( evt )
{
2006-05-16 06:43:11 +02:00
if ( ! canBuild ( this , evt . target ) )
{
evt . preventDefault ( ) ;
return ;
}
2006-02-26 10:56:47 +01:00
var t = evt . target ;
var b = this . actions . build ;
2006-08-08 05:44:15 +02:00
var bp = t . buildPoints ;
2006-02-26 10:56:47 +01:00
var hp = t . traits . health ;
var points = parseFloat ( b . rate ) * parseFloat ( b . speed ) / 1000.0 ;
2006-11-24 20:45:04 +01:00
if ( bp . curr == 0 )
{
t . flattenTerrain ( ) ; //make the terrain stable for the building
//t.placeBuildingFootprint(false); //false means display regular footprint, not rubble
}
2006-02-26 10:56:47 +01:00
bp . curr += points ;
2007-09-16 19:43:38 +02:00
hp . curr += ( points / bp . max ) * hp . max ;
if ( hp . curr >= hp . max )
hp . curr = hp . max ;
2006-11-24 20:45:04 +01:00
2006-02-26 10:56:47 +01:00
if ( bp . curr >= bp . max )
{
2006-04-30 22:34:39 +02:00
// We've finished building this object; convert the foundation to a building
2006-02-26 10:56:47 +01:00
if ( t . building != "" ) // Might be false if another unit finished building the thing during our last anim cycle
{
2006-05-16 06:43:11 +02:00
t . template = getEntityTemplate ( t . building , t . player ) ;
2006-02-26 10:56:47 +01:00
t . building = "" ;
2006-04-30 22:34:39 +02:00
2006-02-26 23:25:17 +01:00
t . attachAuras ( ) ;
2006-04-30 22:34:39 +02:00
if ( t . traits . population && t . traits . population . add )
2006-06-10 05:05:16 +02:00
this . player . resources . housing += parseInt ( t . traits . population . add ) ;
2006-02-26 10:56:47 +01:00
}
evt . preventDefault ( ) ; // Stop performing this action
}
}
// ====================================================================
2006-05-16 06:43:11 +02:00
function performRepair ( evt )
{
if ( ! canRepair ( this , evt . target ) )
{
evt . preventDefault ( ) ;
return ;
}
var t = evt . target ;
var b = this . actions . build ;
var hp = t . traits . health ;
2006-10-08 19:34:46 +02:00
var resources = t . traits . creation . resource ;
2006-05-16 06:43:11 +02:00
// Find the fraction of max health to repair by; this should be one build tick (i.e. longer for buildings with
// longer creation time) but also not so much that it causes the unit to have more than max HP
var fraction = Math . min (
parseFloat ( b . rate ) / t . traits . creation . time ,
( hp . max - hp . curr ) / hp . max
) ;
2006-10-08 19:34:46 +02:00
//console.write("Repair fraction is " + fraction);
2006-05-16 06:43:11 +02:00
// Check if we can afford to repair
for ( r in resources )
{
2006-10-08 19:34:46 +02:00
var amount = parseInt ( fraction * parseInt ( resources [ r ] ) ) ;
if ( this . player . resources [ r . toString ( ) ] < amount )
{
console . write ( "Can't repair - not enough " + r . toString ( ) ) ;
evt . preventDefault ( ) ;
return ;
}
2006-05-16 06:43:11 +02:00
}
// Heal the building
hp . curr = Math . min ( hp . max , hp . curr + fraction * hp . max ) ;
// Deduct the resources
for ( r in resources )
{
amount = parseInt ( fraction * parseInt ( resources [ r ] ) ) ;
2006-10-08 19:34:46 +02:00
this . player . resources [ r . toString ( ) ] -= amount ;
2006-05-16 06:43:11 +02:00
}
}
// ====================================================================
2006-01-20 22:37:45 +01:00
function damage ( dmg , inflictor )
2006-01-02 04:07:29 +01:00
{
2006-10-09 01:41:17 +02:00
var arm = this . traits . armour ;
if ( ! arm ) return ; // corpses have no armour, everything else should
2006-01-23 04:55:35 +01:00
2006-08-08 05:44:15 +02:00
this . lastCombatTime = getGameTime ( ) ;
2006-05-04 06:14:48 +02:00
2005-04-15 06:23:33 +02:00
// Apply armour and work out how much damage we actually take
2007-01-12 17:18:20 +01:00
crushDamage = dmg . crush - arm . crush ;
2005-04-15 06:23:33 +02:00
if ( crushDamage < 0 ) crushDamage = 0 ;
2007-01-12 17:18:20 +01:00
pierceDamage = dmg . pierce - arm . pierce ;
2005-04-15 06:23:33 +02:00
if ( pierceDamage < 0 ) pierceDamage = 0 ;
2007-01-12 17:18:20 +01:00
hackDamage = dmg . hack - arm . hack ;
2005-04-15 06:23:33 +02:00
if ( hackDamage < 0 ) hackDamage = 0 ;
2006-01-20 22:37:45 +01:00
totalDamage = parseInt ( dmg . typeless + crushDamage + pierceDamage + hackDamage ) ;
2005-04-15 06:23:33 +02:00
// Minimum of 1 damage
if ( totalDamage < 1 ) totalDamage = 1 ;
this . traits . health . curr -= totalDamage ;
2005-12-15 22:55:18 +01:00
2005-04-15 06:23:33 +02:00
if ( this . traits . health . curr <= 0 )
{
2006-01-13 06:00:55 +01:00
// If the fallen is worth any loot and the inflictor is capable of looting
2006-02-13 03:06:57 +01:00
if ( this . traits . loot && inflictor . actions && inflictor . actions . loot )
2005-04-15 06:23:33 +02:00
{
2005-09-14 02:50:25 +02:00
// Cycle through all loot on this entry.
2007-02-02 15:53:16 +01:00
const LOOTS = [ "food" , "wood" , "metal" , "stone" , "xp" ]
for ( i in LOOTS )
2005-09-14 02:50:25 +02:00
{
2007-02-02 15:53:16 +01:00
var loot = LOOTS [ i ] ;
if ( this . traits . loot [ loot ] ) {
switch ( loot )
{
case "xp" :
// If the inflictor gains promotions, and he's capable of earning more ranks,
if ( inflictor . traits . promotion && inflictor . traits . promotion . curr
&& inflictor . traits . promotion . req
&& inflictor . traits . promotion . entity
&& inflictor . traits . promotion . entity != ""
&& this . traits . loot && this . traits . loot . xp
&& inflictor . actions . loot . xp )
2006-01-13 06:00:55 +01:00
{
2007-02-02 15:53:16 +01:00
// Give him the fallen's upgrade points (if he has any).
if ( this . traits . loot . xp )
inflictor . traits . promotion . curr = parseInt ( inflictor . traits . promotion . curr ) + parseInt ( this . traits . loot . xp ) ;
// Notify player.
2006-10-08 19:34:46 +02:00
/ * i f ( i n f l i c t o r . t r a i t s . i d . s p e c i f i c )
2007-02-02 15:53:16 +01:00
console . write ( inflictor . traits . id . specific + " has earned " + this . traits . loot . xp + " upgrade points!" ) ;
2006-01-13 06:00:55 +01:00
else
2007-02-02 15:53:16 +01:00
console . write ( "One of your units has earned " + this . traits . loot . xp + " upgrade points!" ) ;
* /
// If he now has maximum upgrade points for his rank,
if ( inflictor . traits . promotion . curr >= inflictor . traits . promotion . req )
{
// Notify the player.
/ * i f ( i n f l i c t o r . t r a i t s . i d . s p e c i f i c )
console . write ( inflictor . traits . id . specific + " has gained a promotion!" ) ;
else
console . write ( "One of your units has gained a promotion!" ) ; * /
// Reset his upgrade points.
inflictor . traits . promotion . curr = 0 ;
// Upgrade his portrait to the next level.
inflictor . traits . id . icon _cell ++ ;
// Transmogrify him into his next rank.
inflictor . template = getEntityTemplate ( inflictor . traits . promotion . entity , inflictor . player ) ;
inflictor . setupRank ( ) ;
}
2006-01-13 06:00:55 +01:00
}
2007-02-02 15:53:16 +01:00
break ;
default :
if ( inflictor . actions . loot . resources )
{
// Give the inflictor his resources.
this . player . resources [ loot . toString ( ) ] -= parseInt ( this . traits . loot [ loot . toString ( ) ] ) ;
}
break ;
}
2005-09-14 02:50:25 +02:00
}
}
2005-04-15 06:23:33 +02:00
}
// Notify player.
2006-01-08 15:01:10 +01:00
if ( inflictor )
2006-01-02 04:07:29 +01:00
console . write ( this . traits . id . generic + " got the point of " + inflictor . traits . id . generic + "'s weapon." ) ;
2005-04-15 06:23:33 +02:00
else
console . write ( this . traits . id . generic + " died in mysterious circumstances." ) ;
// Make him cry out in pain.
2005-12-15 22:55:18 +01:00
if ( this . traits . audio && this . traits . audio . path )
{
2007-01-20 19:35:02 +01:00
if ( getGUIGlobal ( ) . newRandomSound ) {
2007-02-02 03:17:15 +01:00
var curr _pain = getGUIGlobal ( ) . newRandomSound (
2007-01-20 19:35:02 +01:00
"voice" , "pain" , this . traits . audio . path ) ;
if ( curr _pain ) curr _pain . play ( ) ;
}
2005-12-11 03:08:24 +01:00
}
2005-12-15 22:55:18 +01:00
else
{
console . write ( "Sorry, no death sound for this unit; you'll just have to imagine it ..." ) ;
2005-12-11 03:08:24 +01:00
}
2005-04-15 06:23:33 +02:00
// We've taken what we need. Kill the swine.
2006-10-08 19:34:46 +02:00
//console.write("Kill!!");
2005-04-15 06:23:33 +02:00
this . kill ( ) ;
}
2006-09-09 01:58:57 +02:00
/ * e l s e i f ( i n f l i c t o r & & t h i s . a c t i o n s & & t h i s . a c t i o n s . a t t a c k )
2005-04-15 06:23:33 +02:00
{
// If we're not already doing something else, take a measured response - hit 'em back.
2006-08-01 05:29:10 +02:00
// You know, I think this is quite possibly the first Ai code the Ai divlead has written
2005-04-15 06:23:33 +02:00
// for 0 A.D....
2006-09-09 01:58:57 +02:00
//When the entity changes order, we can readjust flank penalty. We must destroy the notifiers ourselves later,however.
2006-05-04 06:14:48 +02:00
this . requestNotification ( inflictor , NOTIFY _ORDER _CHANGE , false , true ) ;
this . registerDamage ( inflictor ) ;
2005-04-15 06:23:33 +02:00
if ( this . isIdle ( ) )
2006-09-09 01:58:57 +02:00
this . order ( ORDER _GENERIC , inflictor , this . getAttackAction ( inflictor ) ) ;
} * /
2006-05-04 06:14:48 +02:00
2006-09-09 01:58:57 +02:00
this . onDamaged ( inflictor ) ;
2005-04-15 06:23:33 +02:00
}
2005-12-15 22:55:18 +01:00
// ====================================================================
2005-12-29 09:43:38 +01:00
function entityEventGeneric ( evt )
{
switch ( evt . action )
{
case ACTION _ATTACK :
2006-01-20 22:37:45 +01:00
this . performAttack ( evt ) ; break ;
2005-12-29 09:43:38 +01:00
case ACTION _GATHER :
2006-04-02 01:49:59 +02:00
evt . notifyType = NOTIFY _GATHER ;
2006-05-13 07:54:01 +02:00
this . performGather ( evt ) ;
2006-04-02 01:49:59 +02:00
break ;
2005-12-29 09:43:38 +01:00
case ACTION _HEAL :
2006-01-20 22:37:45 +01:00
this . performHeal ( evt ) ; break ;
2006-01-22 09:51:34 +01:00
case ACTION _ATTACK _RANGED :
this . performAttackRanged ( evt ) ; break ;
2006-02-26 10:56:47 +01:00
case ACTION _BUILD :
this . performBuild ( evt ) ; break ;
2006-05-16 06:43:11 +02:00
case ACTION _REPAIR :
this . performRepair ( evt ) ; break ;
2006-02-13 04:28:36 +01:00
2005-12-29 09:43:38 +01:00
default :
console . write ( "Unknown generic action: " + evt . action ) ;
}
}
2006-01-16 11:55:01 +01:00
//======================================================================
2006-01-08 09:23:59 +01:00
function entityEventNotification ( evt )
{
2006-05-04 06:14:48 +02:00
//This is used to adjust the flank penalty (we're no longer being attacked).
if ( this . getCurrentRequest ( ) == NOTIFY _ORDER _CHANGE )
{
2006-07-06 05:17:44 +02:00
this . registerOrderChange ( evt . target ) ;
2006-05-04 06:14:48 +02:00
destroyNotifier ( evt . target ) ;
return ;
}
2006-02-13 04:28:36 +01:00
//Add "true" to the end of order() to indicate that this is a notification order.
switch ( evt . notifyType )
2006-01-08 09:23:59 +01:00
{
2006-02-13 04:28:36 +01:00
2006-05-04 06:14:48 +02:00
case NOTIFY _GOTO :
2006-02-13 04:28:36 +01:00
this . GotoInRange ( evt . location . x , evt . location . z , false ) ;
break ;
2006-01-22 12:08:27 +01:00
case NOTIFY _RUN :
2006-02-13 04:28:36 +01:00
this . GotoInRange ( evt . location . x , evt . location . z , true ) ;
2006-01-21 12:01:08 +01:00
break ;
2006-01-08 09:23:59 +01:00
case NOTIFY _ATTACK :
case NOTIFY _DAMAGE :
2006-10-09 06:16:01 +02:00
this . order ( ORDER _GENERIC , evt . target , ACTION _ATTACK ) ;
2006-01-21 12:01:08 +01:00
break ;
2006-01-08 09:23:59 +01:00
case NOTIFY _HEAL :
2006-10-09 06:16:01 +02:00
this . order ( ORDER _GENERIC , evt . target , ACTION _HEAL ) ;
2006-01-21 12:01:08 +01:00
break ;
2006-01-08 09:23:59 +01:00
case NOTIFY _GATHER :
2006-10-09 06:16:01 +02:00
this . order ( ORDER _GENERIC , evt . target , ACTION _GATHER ) ;
2006-01-21 12:01:08 +01:00
break ;
2006-04-09 00:35:23 +02:00
case NOTIFY _IDLE :
2006-05-04 06:14:48 +02:00
//target is the unit that has become idle. Eventually...do something here.
2006-04-09 00:35:23 +02:00
break ;
2006-01-21 12:01:08 +01:00
default :
2006-02-13 04:28:36 +01:00
console . write ( "Unknown notification request " + evt . notifyType ) ;
2006-05-04 06:14:48 +02:00
return ;
2006-01-08 09:23:59 +01:00
}
2006-05-04 06:14:48 +02:00
2006-01-08 09:23:59 +01:00
}
2006-01-22 12:55:47 +01:00
// ====================================================================
2006-09-09 01:58:57 +02:00
function getAttackAction ( target )
2006-01-22 12:55:47 +01:00
{
2006-09-09 01:58:57 +02:00
if ( ! this . actions . attack )
2006-02-13 04:28:36 +01:00
return ACTION _NONE ;
2006-09-09 01:58:57 +02:00
var attack = this . actions . attack ;
2006-02-13 04:28:36 +01:00
if ( attack . melee )
2006-01-22 12:55:47 +01:00
return ACTION _ATTACK ;
2006-02-13 04:28:36 +01:00
else if ( attack . ranged )
2006-01-22 12:55:47 +01:00
return ACTION _ATTACK _RANGED ;
2006-02-13 04:28:36 +01:00
else
return ACTION _NONE ;
2006-01-22 12:55:47 +01:00
}
2005-12-29 09:43:38 +01:00
// ====================================================================
2006-02-26 10:56:47 +01:00
// TODO: Change this to an event so that it gets passed to our parent too, like other events
function entityComplete ( )
{
console . write ( this + " is finished building." ) ;
}
2006-09-16 22:11:42 +02:00
2006-04-09 00:35:23 +02:00
//=====================================================================
2006-09-16 22:11:42 +02:00
2006-04-09 00:35:23 +02:00
function entityEventIdle ( evt )
{
2006-05-04 06:14:48 +02:00
//Use our own data for target; we aren't affecting anyone, so listeners want to know about us
2006-04-09 00:35:23 +02:00
this . forceCheckListeners ( NOTIFY _IDLE , this ) ;
}
2006-02-26 10:56:47 +01:00
// ====================================================================
2006-10-09 06:16:01 +02:00
function entityEventTargetExhausted ( evt )
{
if ( evt . action == ACTION _GATHER )
{
2006-10-26 23:35:25 +02:00
// Look for other resources of the same type to gather
this . chooseGatherTarget ( evt . target . traits . supply . subType . toString ( ) ) ;
2006-10-09 06:16:01 +02:00
}
else if ( evt . action == ACTION _BUILD )
{
2007-09-16 22:01:57 +02:00
// If the target was gatherable, try to gather it.
if ( canGather ( this , evt . target ) )
{
this . order ( ORDER _GENERIC , evt . target , ACTION _GATHER ) ;
return ;
}
2006-10-09 06:16:01 +02:00
// Look for other stuff to build
var visible = this . getVisibleEntities ( ) ;
var bestDist = 1e20 ;
var bestTarget = null ;
for ( var i = 0 ; i < visible . length ; i ++ )
{
var e = visible [ i ] ;
if ( canBuild ( this , e ) )
{
var dist = this . getDistance ( e ) ;
if ( dist < bestDist )
{
bestDist = dist ;
bestTarget = e ;
}
}
}
if ( bestTarget != null )
{
this . order ( ORDER _GENERIC , bestTarget , ACTION _BUILD ) ;
2007-09-16 22:01:57 +02:00
return ;
2006-10-09 06:16:01 +02:00
}
2007-09-16 22:01:57 +02:00
// Nothing to build, but try to gather any resource around us if this was a village object.
if ( evt . target . hasClass ( "Village" ) )
2006-10-26 23:35:25 +02:00
{
this . chooseGatherTarget ( null , evt . target . getVisibleEntities ( ) ) ;
}
}
}
function chooseGatherTarget ( resourceSubType , targetList )
{
if ( ! targetList )
targetList = this . getVisibleEntities ( ) ;
var bestDist = 1e20 ;
var bestTarget = null ;
for ( var i = 0 ; i < targetList . length ; i ++ )
{
var e = targetList [ i ] ;
if ( canGather ( this , e )
&& ( ! resourceSubType || e . traits . supply . subType . toString ( ) == resourceSubType ) )
{
var dist = this . getDistance ( e ) ;
if ( dist < bestDist )
{
bestDist = dist ;
bestTarget = e ;
}
}
}
if ( bestTarget != null )
{
this . order ( ORDER _GENERIC , bestTarget , ACTION _GATHER ) ;
return true ;
2006-10-09 06:16:01 +02:00
}
2006-10-26 23:35:25 +02:00
return false ;
2006-10-09 06:16:01 +02:00
}
// ====================================================================
2005-12-15 22:55:18 +01:00
function entityEventTargetChanged ( evt )
2005-04-15 06:23:33 +02:00
{
// This event lets us know when the user moves his/her cursor to a different unit (provided this
// unit is selected) - use it to tell the engine what context cursor should be displayed, given
// the target.
2005-09-19 03:20:23 +02:00
// If we can gather, and the target supplies, gather. If it's our enemy, and we're armed, attack.
2006-01-20 22:37:45 +01:00
// If all else fails, move (or run on a right-click).
2005-04-22 09:12:55 +02:00
2006-06-22 00:37:31 +02:00
if ( getCursorName ( ) == "cursor-rally" )
{
evt . defaultCursor = "cursor-rally" ;
evt . defaultOrder = - 1 ;
return ;
}
2005-12-29 09:43:38 +01:00
evt . defaultOrder = NMT _Goto ;
2005-04-22 09:12:55 +02:00
evt . defaultCursor = "arrow-default" ;
2006-02-13 04:28:36 +01:00
evt . defaultAction = ACTION _NONE ;
evt . secondaryAction = ACTION _NONE ;
2006-01-16 11:55:01 +01:00
evt . secondaryCursor = "arrow-default" ;
2006-02-26 10:56:47 +01:00
if ( this . actions && this . actions . run && this . actions . run . speed > 0 )
2006-01-21 12:01:08 +01:00
{
evt . secondaryOrder = NMT _Run ;
}
2006-02-13 04:28:36 +01:00
2005-12-15 22:55:18 +01:00
if ( evt . target && this . actions )
2005-04-15 06:23:33 +02:00
{
2005-12-29 09:43:38 +01:00
if ( this . actions . attack &&
2006-08-28 05:07:07 +02:00
this . player . getDiplomaticStance ( evt . target . player ) != DIPLOMACY _ALLIED &&
2005-12-17 10:28:26 +01:00
evt . target . traits . health &&
evt . target . traits . health . max != 0 )
2005-04-22 09:12:55 +02:00
{
2005-12-29 09:43:38 +01:00
evt . defaultOrder = NMT _Generic ;
2006-09-09 01:58:57 +02:00
evt . defaultAction = this . getAttackAction ( evt . target ) ;
2005-04-22 09:12:55 +02:00
evt . defaultCursor = "action-attack" ;
2006-01-16 11:55:01 +01:00
evt . secondaryOrder = NMT _Generic ;
2006-09-09 01:58:57 +02:00
evt . secondaryAction = this . getAttackAction ( evt . target ) ;
2006-01-16 11:55:01 +01:00
evt . secondaryCursor = "action-attack" ;
2005-04-22 09:12:55 +02:00
}
2006-02-26 10:56:47 +01:00
2006-02-13 04:28:36 +01:00
if ( this . actions . escort &&
this != evt . target &&
evt . target . player == this . player &&
evt . target . actions )
{
if ( evt . target . actions . move )
{
//Send an empty order
evt . defaultOrder = NMT _NotifyRequest ;
evt . secondaryOrder = NMT _NotifyRequest ;
evt . defaultAction = NOTIFY _ESCORT ;
evt . secondaryAction = NOTIFY _ESCORT ;
}
}
if ( canGather ( this , evt . target ) )
2005-04-22 09:12:55 +02:00
{
2005-12-29 09:43:38 +01:00
evt . defaultOrder = NMT _Generic ;
evt . defaultAction = ACTION _GATHER ;
2006-01-20 22:37:45 +01:00
// Set cursor (eg "action-gather-fruit").
2006-08-01 05:29:10 +02:00
evt . defaultCursor = "action-gather-" + evt . target . traits . supply . subType ;
2006-01-16 11:55:01 +01:00
evt . secondaryOrder = NMT _Generic ;
evt . secondaryAction = ACTION _GATHER ;
// Set cursor (eg "action-gather-fruit").
2006-08-01 05:29:10 +02:00
evt . secondaryCursor = "action-gather-" + evt . target . traits . supply . subType ;
2005-04-22 09:12:55 +02:00
}
2006-02-26 10:56:47 +01:00
if ( canBuild ( this , evt . target ) )
{
evt . defaultOrder = NMT _Generic ;
evt . defaultAction = ACTION _BUILD ;
evt . defaultCursor = "action-build" ;
evt . secondaryOrder = NMT _Generic ;
evt . secondaryAction = ACTION _BUILD ;
evt . secondaryCursor = "action-build" ;
}
2006-05-16 06:43:11 +02:00
if ( canRepair ( this , evt . target ) )
{
evt . defaultOrder = NMT _Generic ;
evt . defaultAction = ACTION _REPAIR ;
evt . defaultCursor = "action-build" ;
evt . secondaryOrder = NMT _Generic ;
evt . secondaryAction = ACTION _REPAIR ;
evt . secondaryCursor = "action-build" ;
}
2005-04-22 09:12:55 +02:00
}
2006-07-06 05:17:44 +02:00
//Rally point
else if ( this . building )
{
evt . defaultOrder = - 1 ;
evt . defaultCursor = "cursor-rally" ;
}
2006-02-13 04:28:36 +01:00
2005-04-15 06:23:33 +02:00
}
2005-04-29 15:30:08 +02:00
// ====================================================================
2005-12-15 22:55:18 +01:00
function entityEventPrepareOrder ( evt )
2005-04-15 06:23:33 +02:00
{
// This event gives us a chance to veto any order we're given before we execute it.
// Not sure whether this really belongs here like this: the alternative is to override it in
2006-08-01 05:29:10 +02:00
// subTypes - then you wouldn't need to check tags, you could hardcode results.
2005-12-11 03:08:24 +01:00
2006-02-13 04:28:36 +01:00
if ( ! this . actions )
2005-12-11 03:08:24 +01:00
{
evt . preventDefault ( ) ;
return ;
}
2006-02-26 10:56:47 +01:00
2006-02-13 04:28:36 +01:00
//evt.notifySource is the entity order data will be obtained from, so if we're attacking and we
//want our listeners to copy us, then we will use our own order as the source.
2006-05-04 06:14:48 +02:00
//registerOrderChange() is used to adjust the flank penalty
2005-12-15 22:55:18 +01:00
2005-04-15 06:23:33 +02:00
switch ( evt . orderType )
{
2005-12-15 22:55:18 +01:00
case ORDER _GOTO :
2006-02-13 04:28:36 +01:00
if ( ! this . actions . move )
2006-05-04 06:14:48 +02:00
{
2005-12-15 22:55:18 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
2006-02-13 04:28:36 +01:00
evt . notifyType = NOTIFY _GOTO ;
evt . notifySource = this ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-02-26 10:56:47 +01:00
break ;
2006-01-16 11:55:01 +01:00
case ORDER _RUN :
2006-02-13 04:28:36 +01:00
if ( ! this . actions . move . run )
2006-05-04 06:14:48 +02:00
{
2006-01-16 11:55:01 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
2006-02-13 04:28:36 +01:00
evt . notifyType = NOTIFY _RUN ;
evt . notifySource = this ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-01-16 11:55:01 +01:00
break ;
2006-02-26 10:56:47 +01:00
2005-12-15 22:55:18 +01:00
case ORDER _PATROL :
2006-02-13 04:28:36 +01:00
if ( ! this . actions . patrol )
2006-05-04 06:14:48 +02:00
{
2005-12-15 22:55:18 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
this . registerOrderChange ( ) ;
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2005-12-15 22:55:18 +01:00
break ;
2006-02-26 10:56:47 +01:00
2005-12-29 09:43:38 +01:00
case ORDER _GENERIC :
2006-02-13 04:28:36 +01:00
evt . notifySource = this ;
switch ( evt . action )
{
case ACTION _ATTACK :
case ACTION _ATTACK _RANGED :
2006-09-09 01:58:57 +02:00
evt . action = this . getAttackAction ( evt . target ) ;
2006-02-22 23:45:16 +01:00
if ( evt . action == ACTION _NONE )
2006-05-04 06:14:48 +02:00
{
evt . preventDefault ( ) ;
return ;
}
2006-02-13 04:28:36 +01:00
evt . notifyType = NOTIFY _ATTACK ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-02-13 04:28:36 +01:00
break ;
case ACTION _GATHER :
if ( ! this . actions . gather )
2006-05-04 06:14:48 +02:00
{
2006-02-13 04:28:36 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
2006-02-13 04:28:36 +01:00
evt . notifyType = NOTIFY _GATHER ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-05-13 08:21:06 +02:00
// Change our gather animation based on the type of target
var a = this . actions . gather ;
this . setActionParams ( ACTION _GATHER , 0.0 , a . range , a . speed ,
2006-08-01 05:29:10 +02:00
"gather_" + evt . target . traits . supply . subType ) ;
2006-05-13 08:21:06 +02:00
2006-02-13 04:28:36 +01:00
break ;
2006-02-26 10:56:47 +01:00
2006-02-13 04:28:36 +01:00
case ACTION _HEAL :
if ( ! this . actions . heal )
2006-05-04 06:14:48 +02:00
{
2006-02-13 04:28:36 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
2006-02-13 04:28:36 +01:00
evt . notifyType = NOTIFY _HEAL ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-02-13 04:28:36 +01:00
break ;
2006-02-26 10:56:47 +01:00
case ACTION _BUILD :
2006-05-14 00:12:57 +02:00
if ( ! this . actions . build || ! evt . target . building || evt . target . building == "" )
2006-05-04 06:14:48 +02:00
{
2006-02-26 10:56:47 +01:00
evt . preventDefault ( ) ;
2006-05-04 06:14:48 +02:00
return ;
}
2006-02-26 10:56:47 +01:00
evt . notifyType = NOTIFY _NONE ;
2006-05-04 06:14:48 +02:00
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
2006-02-26 10:56:47 +01:00
break ;
2006-05-16 06:43:11 +02:00
case ACTION _REPAIR :
if ( ! this . actions . repair )
{
evt . preventDefault ( ) ;
return ;
}
evt . notifyType = NOTIFY _NONE ;
this . forceCheckListeners ( NOTIFY _ORDER _CHANGE , this ) ;
break ;
2006-02-13 04:28:36 +01:00
}
2005-12-29 09:43:38 +01:00
break ;
2006-02-22 23:45:16 +01:00
case ORDER _PRODUCE :
2006-05-04 09:41:06 +02:00
case ORDER _START _CONSTRUCTION :
2006-02-22 23:45:16 +01:00
evt . notifyType = NOTIFY _NONE ;
break ;
2006-02-13 04:28:36 +01:00
2005-12-15 22:55:18 +01:00
default :
2006-02-22 23:45:16 +01:00
console . write ( "Unknown order type " + evt . orderType + "; ignoring." ) ;
evt . preventDefault ( ) ;
2006-02-13 03:06:57 +01:00
break ;
2005-04-15 06:23:33 +02:00
}
}
2005-04-29 15:30:08 +02:00
// ====================================================================
2006-05-04 09:41:06 +02:00
function entityStartConstruction ( evt )
{
this . order ( ORDER _GENERIC , evt . target , ACTION _BUILD ) ;
}
// ====================================================================
2006-10-26 23:35:25 +02:00
const TECH _RESOURCES = new Array ( "food" , "wood" , "stone" , "metal" ) ;
2006-07-19 07:25:57 +02:00
2006-02-22 23:45:16 +01:00
function entityStartProduction ( evt )
{
2006-10-08 19:34:46 +02:00
//console.write("StartProduction: " + evt.productionType + " " + evt.name);
2006-04-30 22:34:39 +02:00
2006-07-19 07:25:57 +02:00
if ( evt . productionType == PRODUCTION _TRAIN )
2006-04-30 22:34:39 +02:00
{
2006-05-16 06:43:11 +02:00
var template = getEntityTemplate ( evt . name , this . player ) ;
2006-06-10 05:05:16 +02:00
var result = checkEntityReqs ( this . player , template ) ;
2006-02-22 23:45:16 +01:00
2006-04-30 22:34:39 +02:00
if ( result == true ) // If the entry meets requirements to be added to the queue (eg sufficient resources)
{
// Cycle through all costs of this entry.
var pool = template . traits . creation . resource ;
for ( resource in pool )
{
2006-06-10 05:05:16 +02:00
switch ( resource . toString ( ) )
2006-04-30 22:34:39 +02:00
{
2006-06-10 05:05:16 +02:00
case "population" :
case "housing" :
2006-04-30 22:34:39 +02:00
break ;
default :
// Deduct the given quantity of resources.
2006-06-10 05:05:16 +02:00
this . player . resources [ resource . toString ( ) ] -= parseInt ( pool [ resource ] ) ;
2006-04-30 22:34:39 +02:00
2006-10-08 19:34:46 +02:00
/ * c o n s o l e . w r i t e ( " S p e n t " + p o o l [ r e s o u r c e ] + " " + r e s o u r c e + " t o p u r c h a s e " +
template . traits . id . generic ) ; * /
2006-04-30 22:34:39 +02:00
break ;
}
}
2006-06-10 05:33:22 +02:00
// Reserve population space for the unit
if ( template . traits . population && template . traits . population . rem )
{
this . player . resources . population += parseInt ( template . traits . population . rem ) ;
}
2006-04-30 22:34:39 +02:00
// Set the amount of time it will take to complete production of the production object.
2006-05-16 06:43:11 +02:00
evt . time = getEntityTemplate ( evt . name , this . player ) . traits . creation . time ;
2006-04-30 22:34:39 +02:00
}
else
{
// If not, output the error message.
console . write ( result ) ;
evt . preventDefault ( ) ;
2006-06-10 05:33:22 +02:00
return ;
2006-04-30 22:34:39 +02:00
}
}
2006-07-19 07:25:57 +02:00
else if ( evt . productionType == PRODUCTION _RESEARCH )
{
var tech = getTechnology ( evt . name , this . player ) ;
if ( ! tech )
{
console . write ( "No such tech: " + evt . name ) ;
evt . preventDefault ( ) ;
return ;
}
// Check tech requirements other than resources
if ( ! tech . isValid ( ) )
{
console . write ( "Tech " + evt . name + " is currently unavailable" ) ;
evt . preventDefault ( ) ;
return ;
}
// Check for sufficient resources
for ( i in TECH _RESOURCES )
{
var res = TECH _RESOURCES [ i ] ;
if ( this . player . resources [ res ] < tech [ res ] )
{
console . write ( "Cannot afford " + evt . name + ": need " + tech [ res ] + " " + res ) ;
evt . preventDefault ( ) ;
return ;
}
}
// Subtract resources
for ( i in TECH _RESOURCES )
{
var res = TECH _RESOURCES [ i ] ;
this . player . resources [ res ] -= tech [ res ] ;
}
// Mark it as in progress
tech . in _progress = true ;
// Set the amount of time it will take to complete production of the tech.
evt . time = tech . time ;
}
2006-04-30 22:34:39 +02:00
else
{
evt . preventDefault ( ) ;
}
2006-02-22 23:45:16 +01:00
}
function entityCancelProduction ( evt )
{
2006-10-08 19:34:46 +02:00
//console.write("CancelProduction: " + evt.productionType + " " + evt.name);
2006-04-30 22:34:39 +02:00
2006-07-19 07:25:57 +02:00
if ( evt . productionType == PRODUCTION _TRAIN )
2006-04-30 22:34:39 +02:00
{
// Give back all the resources spent on this entry.
2006-05-16 06:43:11 +02:00
var template = getEntityTemplate ( evt . name , this . player ) ;
2006-04-30 22:34:39 +02:00
var pool = template . traits . creation . resource ;
for ( resource in pool )
{
2006-06-10 05:05:16 +02:00
switch ( resource . toString ( ) )
2006-04-30 22:34:39 +02:00
{
2006-06-10 05:05:16 +02:00
case "population" :
case "housing" :
2006-04-30 22:34:39 +02:00
break ;
default :
2006-06-10 05:05:16 +02:00
// Refund the given quantity of resources.
this . player . resources [ resource . toString ( ) ] += parseInt ( pool [ resource ] ) ;
2006-04-30 22:34:39 +02:00
console . write ( "Got back " + pool [ resource ] + " " + resource + " from cancelling " +
template . traits . id . generic ) ;
break ;
}
}
2006-06-10 05:33:22 +02:00
// Give back the reserved population space
if ( template . traits . population && template . traits . population . rem )
{
this . player . resources . population -= parseInt ( template . traits . population . rem ) ;
}
2006-04-30 22:34:39 +02:00
}
2006-07-19 07:25:57 +02:00
else if ( evt . productionType == PRODUCTION _RESEARCH )
{
var tech = getTechnology ( evt . name , this . player ) ;
// Give back the player's resources
for ( i in TECH _RESOURCES )
{
var res = TECH _RESOURCES [ i ] ;
this . player . resources [ res ] += tech [ res ] ;
}
// Unmark tech as in progress
tech . in _progress = false ;
}
2006-04-30 22:34:39 +02:00
}
function entityFinishProduction ( evt )
{
2006-10-08 19:34:46 +02:00
//console.write("FinishProduction: " + evt.productionType + " " + evt.name);
2006-04-30 22:34:39 +02:00
2006-07-19 07:25:57 +02:00
if ( evt . productionType == PRODUCTION _TRAIN )
2006-04-30 22:34:39 +02:00
{
2006-05-16 06:43:11 +02:00
var template = getEntityTemplate ( evt . name , this . player ) ;
2006-04-30 22:34:39 +02:00
2006-06-10 05:33:22 +02:00
// Give back reserved population space (the unit will take it up again in its initialize event, if we find space to place it)
if ( template . traits . population && template . traits . population . rem )
{
this . player . resources . population -= parseInt ( template . traits . population . rem ) ;
}
2006-04-30 22:34:39 +02:00
// Code to find a free space around an object is tedious and slow, so
// I wrote it in C. Takes the template object so it can determine how
// much space it needs to leave.
var position = this . getSpawnPoint ( template ) ;
// The above function returns null if it couldn't find a large enough space.
if ( ! position )
{
console . write ( "Couldn't train unit - not enough space" ) ;
// Oh well. The player's just lost all the resources and time they put into
// construction - serves them right for not paying attention to the land
// around their barracks, doesn't it?
}
else
{
2006-06-10 05:05:16 +02:00
var created = new Entity ( template , position , 0 , this . player ) ;
2006-04-30 22:34:39 +02:00
// Above shouldn't ever fail, but just in case...
if ( created )
{
2006-10-08 19:34:46 +02:00
//console.write( "Created: ", template.tag );
2006-06-22 00:37:31 +02:00
var rally = this . getRallyPoint ( ) ;
created . order ( ORDER _GOTO , rally . x , rally . z ) ;
2006-04-30 22:34:39 +02:00
}
}
}
2006-07-19 07:25:57 +02:00
else if ( evt . productionType == PRODUCTION _RESEARCH )
{
// Apply the tech's effects
var tech = getTechnology ( evt . name , this . player ) ;
tech . applyEffects ( ) ;
}
2006-02-22 23:45:16 +01:00
}
2006-06-10 05:05:16 +02:00
// Old training queue system
2006-02-22 23:45:16 +01:00
2006-06-10 05:05:16 +02:00
// ====================================================================
/ *
2005-12-15 22:55:18 +01:00
function entityAddCreateQueue ( template , tab , list )
2005-04-15 06:23:33 +02:00
{
// Make sure we have a queue to put things in...
if ( ! this . actions . create . queue )
2005-04-19 04:06:18 +02:00
this . actions . create . queue = new Array ( ) ;
// Construct template object.
comboTemplate = template ;
comboTemplate . list = list ;
comboTemplate . tab = tab ;
2005-04-15 06:23:33 +02:00
// Append to the end of this queue
2005-04-22 09:12:55 +02:00
this . actions . create . queue . push ( template ) ;
2005-04-19 04:06:18 +02:00
2005-04-15 06:23:33 +02:00
// If we're not already building something...
2005-04-22 09:12:55 +02:00
if ( ! this . actions . create . progress )
2005-04-15 06:23:33 +02:00
{
console . write ( "Starting work on (unqueued) " , template . tag ) ;
// Start the progress timer.
// - First parameter is target value (in this case, base build time in seconds)
// - Second parameter is increment per millisecond (use build rate modifier and correct for milliseconds)
// - Third parameter is the function to call when the timer finishes.
// - Fourth parameter is the scope under which to run that function (what the 'this' parameter should be)
2005-12-16 23:52:10 +01:00
this . actions . create . progress = new ProgressTimer ( template . traits . creation . time ,
this . actions . create . speed / 1000 , entityCreateComplete , this )
2005-04-15 06:23:33 +02:00
}
}
2005-04-29 15:30:08 +02:00
// ====================================================================
2005-04-15 06:23:33 +02:00
// This is the syntax to add a function (or a property) to absolutely every entity.
2005-12-15 22:55:18 +01:00
Entity . prototype . add _create _queue = entityAddCreateQueue ;
2005-04-15 06:23:33 +02:00
2005-04-29 15:30:08 +02:00
// ====================================================================
2005-12-15 22:55:18 +01:00
function entityCreateComplete ( )
2005-04-15 06:23:33 +02:00
{
// Get the unit that was at the head of our queue, and remove it.
// (Oh, for information about all these nifty properties and functions
// of the Array object that I use, see the ECMA-262 documentation
// at http://www.mozilla.org/js/language/E262-3.pdf. Bit technical but
// the sections on 'Native ECMAScript Objects' are quite useful)
2005-04-22 09:12:55 +02:00
var template = this . actions . create . queue . shift ( ) ;
2005-04-15 06:23:33 +02:00
// Code to find a free space around an object is tedious and slow, so
// I wrote it in C. Takes the template object so it can determine how
// much space it needs to leave.
position = this . getSpawnPoint ( template ) ;
// The above function returns null if it couldn't find a large enough space.
if ( ! position )
{
console . write ( "Couldn't train unit - not enough space" ) ;
// Oh well. The player's just lost all the resources and time they put into
// construction - serves them right for not paying attention to the land
// around their barracks, doesn't it?
}
2005-04-22 09:12:55 +02:00
else
{
created = new Entity ( template , position ) ;
2005-04-15 06:23:33 +02:00
2005-04-22 09:12:55 +02:00
// Above shouldn't ever fail, but just in case...
if ( created )
{
console . write ( "Created: " , template . tag ) ;
2005-04-15 06:23:33 +02:00
2005-04-22 09:12:55 +02:00
// Entities start under Gaia control - make the controller
// the same as our controller
created . player = this . player ;
}
}
2005-04-15 06:23:33 +02:00
// If there's something else in the build queue...
2005-04-22 09:12:55 +02:00
if ( this . actions . create . queue . length > 0 )
2005-04-15 06:23:33 +02:00
{
// Start on the next item.
2005-04-22 09:12:55 +02:00
template = this . actions . create . queue [ 0 ] ;
2005-04-15 06:23:33 +02:00
console . write ( "Starting work on (queued) " , template . tag ) ;
2005-12-16 23:52:10 +01:00
this . actions . create . progress = new ProgressTimer ( template . traits . creation . time ,
this . actions . create . speed / 1000 , entityCreateComplete , this )
2005-04-15 06:23:33 +02:00
}
else
{
// Otherwise, delete the timer.
this . actions . create . progress = null ;
}
}
2005-04-29 15:30:08 +02:00
// ====================================================================
2005-12-15 22:55:18 +01:00
function attemptAddToBuildQueue ( entity , create _tag , tab , list )
2005-04-15 06:23:33 +02:00
{
2006-05-16 06:43:11 +02:00
template = getEntityTemplate ( create _tag , entity . player ) ;
2006-06-10 05:05:16 +02:00
result = checkEntityReqs ( entity , template ) ;
2005-04-29 15:30:08 +02:00
2006-02-23 19:22:30 +01:00
if ( result == true ) // If the entry meets requirements to be added to the queue (eg sufficient resources)
2005-04-29 15:30:08 +02:00
{
// Cycle through all costs of this entry.
2005-12-16 23:52:10 +01:00
pool = template . traits . creation . resource ;
2006-02-23 19:22:30 +01:00
for ( resource in pool )
2005-04-29 15:30:08 +02:00
{
2006-06-10 05:05:16 +02:00
switch ( resource . toString ( ) )
2005-04-29 15:30:08 +02:00
{
2006-06-10 05:05:16 +02:00
case "population" :
case "housing" :
2005-04-29 15:30:08 +02:00
break ;
default :
// Deduct the given quantity of resources.
2006-06-10 05:05:16 +02:00
this . player . resources [ resource . toString ( ) ] -= parseInt ( pool [ resource ] ) ;
2005-04-29 15:30:08 +02:00
2006-02-23 19:22:30 +01:00
console . write ( "Spent " + pool [ resource ] + " " + resource + " to purchase " +
2005-12-16 23:52:10 +01:00
template . traits . id . generic ) ;
2005-04-29 15:30:08 +02:00
break ;
}
}
// Add entity to queue.
console . write ( "Adding " , create _tag , " to build queue..." ) ;
2005-12-16 23:52:10 +01:00
entity . addCreateQueue ( template , tab , list ) ;
2006-02-23 19:22:30 +01:00
return true ;
2005-04-29 15:30:08 +02:00
}
2006-02-23 19:22:30 +01:00
else
{ // If not, output the error message.
2005-04-29 15:30:08 +02:00
console . write ( result ) ;
2006-02-23 19:22:30 +01:00
return false ;
}
2005-04-29 15:30:08 +02:00
}
2006-06-10 05:05:16 +02:00
* /
2005-04-29 15:30:08 +02:00
// ====================================================================
2006-06-10 05:05:16 +02:00
function checkEntityReqs ( player , template )
2005-04-29 15:30:08 +02:00
{
// Determines if the given entity meets requirements for production by the player, and returns an appropriate
// error string.
// A return value of 0 equals success -- entry meets requirements for production.
// Cycle through all resources that this item costs, and check the player can afford the cost.
2006-04-30 22:34:39 +02:00
var resources = template . traits . creation . resource ;
2005-04-29 15:30:08 +02:00
for ( resource in resources )
{
2006-06-10 05:05:16 +02:00
switch ( resource . toString ( ) )
2005-04-29 15:30:08 +02:00
{
2006-06-10 05:05:16 +02:00
case "population" :
case "housing" : // Ignore housing. It's handled in combination with population.
2005-04-29 15:30:08 +02:00
break
default :
// If the item costs more of this resource type than we have,
2006-06-10 05:05:16 +02:00
var cur = player . resources [ resource ] ;
2006-04-30 22:34:39 +02:00
var req = parseInt ( resources [ resource ] ) ;
if ( req > cur )
2005-04-29 15:30:08 +02:00
{
// Return an error.
2006-04-30 22:34:39 +02:00
return ( "Insufficient " + resource + "; " + ( req - cur ) + " more required." ) ;
2005-04-29 15:30:08 +02:00
}
2006-07-17 02:58:37 +02:00
//else
// console.write("Player has at least " + req + " " + resource + ".");
2005-04-29 15:30:08 +02:00
break ;
}
}
2006-04-30 22:34:39 +02:00
// Check if we have enough population space for the entity
if ( template . traits . population && template . traits . population . rem )
{
var req = parseInt ( template . traits . population . rem ) ;
2006-06-10 05:05:16 +02:00
var space = player . resources . housing - player . resources . population ;
2006-04-30 22:34:39 +02:00
// If the item costs more of this resource type than we have,
if ( req > space )
{
// Return an error.
return ( "Insufficient Housing; " + ( req - space ) + " more required." ) ;
}
}
2005-04-29 15:30:08 +02:00
// Check if another entity must first exist.
// Check if another tech must first be researched.
// Check if the limit for this type of entity has been reached.
// If we passed all checks, return success. Entity can be queued.
2006-02-23 19:22:30 +01:00
return true ;
2005-04-29 15:30:08 +02:00
}
2005-05-18 07:35:25 +02:00
// ====================================================================
2005-12-13 09:03:49 +01:00
2005-12-17 10:28:26 +01:00
function canGather ( source , target )
{
2006-08-01 05:29:10 +02:00
// Checks whether we're allowed to gather from a target entity (this involves looking at both the type and subType).
2006-10-09 06:16:01 +02:00
if ( ! source . actions || ! target . traits )
2005-12-17 10:28:26 +01:00
return false ;
g = source . actions . gather ;
s = target . traits . supply ;
return ( g && s && g . resource && g . resource [ s . type ] &&
2006-08-01 05:29:10 +02:00
( s . subType == s . type || g . resource [ s . type ] [ s . subType ] ) &&
2005-12-17 10:28:26 +01:00
( s . curr > 0 || s . max == 0 ) &&
2006-08-08 05:44:15 +02:00
s . dropsiteCount [ source . player . id ] ) ;
2005-12-17 10:28:26 +01:00
}
// ====================================================================
2006-02-26 10:56:47 +01:00
function canBuild ( source , target )
{
// Checks whether we're allowed to build a target entity
if ( ! source . actions )
return false ;
b = source . actions . build ;
2006-10-09 06:16:01 +02:00
return ( b && target . building != "" && target . player . id == source . player . id
&& target . buildPoints . curr < target . buildPoints . max ) ;
2006-02-26 10:56:47 +01:00
}
// ====================================================================
2006-05-16 06:43:11 +02:00
function canRepair ( source , target )
{
2006-08-01 05:29:10 +02:00
// Checks whether we're allowed to gather from a target entity (this involves looking at both the type and subType).
2006-05-16 06:43:11 +02:00
if ( ! source . actions )
return false ;
r = source . actions . repair ;
return ( r && target . traits . health . repairable && target . player . id == source . player . id
&& target . traits . health . curr < target . traits . health . max
&& target . building == "" ) ;
}
// ====================================================================
2006-10-09 01:41:17 +02:00
// Get the elevation attack bonus if we are heightDif units higher than our target
function getElevationBonus ( heightDif )
{
if ( heightDif > 2.0 )
return 0.3 ; // we are significantly higher, get a positive bonus
else
return 0.0 ; // we are at roughly the same height, or below
}
// ====================================================================
// DamageType class
2006-01-02 04:07:29 +01:00
function DamageType ( )
{
this . typeless = 0.0 ;
this . crush = 0.0 ;
this . pierce = 0.0 ;
this . hack = 0.0 ;
}
// ====================================================================
function DamageModifyAura ( source , ally , bonus )
2005-12-13 09:03:49 +01:00
{
2005-12-15 22:55:18 +01:00
// Defines the effects of the DamageModify Aura. (Adjacent units have modified attack bonus.)
// The Courage Aura uses this function to give attack bonus to allies.
// The Fear Aura uses this function to give attack penalties to enemies.
2005-12-13 09:03:49 +01:00
this . source = source ;
this . bonus = bonus ;
this . ally = ally ;
this . affects = function ( e )
{
if ( this . ally )
{
2005-12-15 22:55:18 +01:00
return ( e . player . id == this . source . player . id && e . actions && e . actions . attack ) ;
2005-12-13 09:03:49 +01:00
}
else
{
2005-12-15 22:55:18 +01:00
return ( e . player . id != this . source . player . id && e . actions && e . actions . attack ) ;
2005-12-13 09:03:49 +01:00
}
}
this . onEnter = function ( e )
{
if ( this . affects ( e ) )
{
2005-12-17 10:28:26 +01:00
//console.write( "DamageModify aura: giving " + this.bonus + " damage to " + e );
2007-01-13 19:41:24 +01:00
e . actions . attack . crush += this . bonus ;
e . actions . attack . pierce += this . bonus ;
e . actions . attack . hack += this . bonus ;
2005-12-13 09:03:49 +01:00
}
} ;
this . onExit = function ( e )
{
if ( this . affects ( e ) )
{
2005-12-17 10:28:26 +01:00
//console.write( "DamageModify aura: taking away " + this.bonus + " damage from " + e );
2007-01-13 19:41:24 +01:00
e . actions . attack . crush -= this . bonus ;
e . actions . attack . pierce -= this . bonus ;
e . actions . attack . hack -= this . bonus ;
2005-12-13 09:03:49 +01:00
}
} ;
}
// ====================================================================
2006-01-02 04:07:29 +01:00
function DropsiteAura ( source , types )
2005-12-17 10:28:26 +01:00
{
// Defines the effects of the Gather aura. Enables resource gathering on entities
// near the source for it's owner.
this . source = source ;
this . types = types ;
this . affects = function ( e )
{
return ( e . traits . supply && this . types [ e . traits . supply . type ] ) ;
}
this . onEnter = function ( e )
{
if ( this . affects ( e ) )
{
//console.write( "Dropsite aura: adding +1 for " + this.source.player.id + " on " + e );
2006-08-08 05:44:15 +02:00
e . traits . supply . dropsiteCount [ this . source . player . id ] ++ ;
2005-12-17 10:28:26 +01:00
}
} ;
this . onExit = function ( e )
{
if ( this . affects ( e ) )
{
//console.write( "Dropsite aura: adding -1 for " + this.source.player.id + " on " + e );
2006-08-08 05:44:15 +02:00
e . traits . supply . dropsiteCount [ this . source . player . id ] -- ;
2005-12-17 10:28:26 +01:00
}
} ;
}
// ====================================================================
2006-01-02 04:07:29 +01:00
function InfidelityAura ( source , time )
2005-12-13 09:03:49 +01:00
{
2005-12-15 22:55:18 +01:00
// Defines the effects of the Infidelity Aura. Changes ownership of entity when only one player's units surrounds them.
2005-12-13 09:03:49 +01:00
this . source = source ;
2005-12-18 08:30:11 +01:00
this . time = time ;
2005-12-13 09:03:49 +01:00
this . count = new Array ( 9 ) ;
2005-12-16 08:22:40 +01:00
for ( i = 0 ; i <= 8 ; i ++ )
2005-12-13 09:03:49 +01:00
{
this . count [ i ] = 0 ;
}
2005-12-18 08:30:11 +01:00
this . convertTimer = 0 ;
2005-12-13 09:03:49 +01:00
this . affects = function ( e )
{
2005-12-13 22:43:08 +01:00
return ( e . player . id != 0 && ( ! e . traits . auras || ! e . traits . auras . infidelity ) ) ;
2005-12-13 09:03:49 +01:00
}
this . onEnter = function ( e )
{
if ( this . affects ( e ) )
{
2005-12-17 10:28:26 +01:00
//console.write( "Infidelity aura: adding +1 count to " + e.player.id );
2005-12-13 09:03:49 +01:00
this . count [ e . player . id ] ++ ;
this . changePlayerIfNeeded ( ) ;
}
} ;
this . onExit = function ( e )
{
if ( this . affects ( e ) )
{
2005-12-17 10:28:26 +01:00
//console.write( "Infidelity aura: adding -1 count to " + e.player.id );
2005-12-13 09:03:49 +01:00
this . count [ e . player . id ] -- ;
this . changePlayerIfNeeded ( ) ;
}
} ;
this . changePlayerIfNeeded = function ( )
{
2005-12-13 22:43:08 +01:00
if ( this . count [ this . source . player . id ] == 0 )
2005-12-13 09:03:49 +01:00
{
2005-12-18 08:30:11 +01:00
// If our owner has nothing near us but someone else does, start a time to convert over if we haven't done so already
if ( ! this . convertTimer )
2005-12-13 09:03:49 +01:00
{
2005-12-18 08:30:11 +01:00
for ( i = 1 ; i <= 8 ; i ++ )
2005-12-13 22:43:08 +01:00
{
2005-12-18 08:30:11 +01:00
if ( this . count [ i ] > 0 )
{
this . convertTimer = setTimeout ( this . convert , parseInt ( this . time * 1000 ) , this ) ;
return ;
}
2005-12-13 22:43:08 +01:00
}
}
2005-12-18 08:30:11 +01:00
}
// If we had started a convert timer before, cancel it (either we have units from our owner in range, or there are no units from anyone in range)
if ( this . convertTimer )
{
cancelTimer ( this . convertTimer ) ;
this . convertTimer = 0 ;
}
}
this . convert = function ( )
{
// Switch ownership to whichever non-gaia player has the most units near us
bestPlayer = 0 ;
bestCount = 0 ;
for ( i = 1 ; i <= 8 ; i ++ )
{
if ( this . count [ i ] > bestCount )
2005-12-13 22:43:08 +01:00
{
2005-12-18 08:30:11 +01:00
bestCount = this . count [ i ] ;
bestPlayer = i ;
2005-12-13 09:03:49 +01:00
}
}
2005-12-18 08:30:11 +01:00
if ( bestCount > 0 )
{
//console.write( "Infidelity aura: changing ownership to " + bestPlayer );
this . source . player = players [ bestPlayer ] ;
}
this . convertTimer = 0 ;
2005-12-13 09:03:49 +01:00
}
2005-12-15 22:55:18 +01:00
}
// ====================================================================
2006-05-16 06:43:11 +02:00
function HealAura ( source )
{
// Defines the effects of the Heal aura. Slowly heals nearby allies over time.
this . source = source ;
this . affects = function ( e )
{
return ( e . player . id == this . source . player . id && e . traits . health
&& e . traits . health . healable
&& e . traits . health . curr < e . traits . health . max ) ;
}
this . onTick = function ( e )
{
if ( this . affects ( e ) )
{
var hp = e . traits . health ;
var rate = this . source . traits . auras . heal . rate ;
hp . curr = Math . min ( hp . max , hp . curr + rate ) ;
}
} ;
}
// ====================================================================
function TrampleAura ( source )
{
// Defines the effects of the Trample aura. Damages nearby enemies over time if the unit is charging or has recently charged.
this . source = source ;
this . affects = function ( e )
{
// Check if the target is an enemy foot unit with health and if we were running in the last 3 seconds
var a = this . source . traits . auras . trample ;
return ( e . player . id != this . source . player . id && e . traits . health && e . hasClass ( "Foot" )
2006-08-08 05:44:15 +02:00
&& ( getGameTime ( ) - this . source . lastRunTime < a . duration ) ) ;
2006-05-16 06:43:11 +02:00
}
this . onTick = function ( e )
{
if ( this . affects ( e ) )
{
// Set up the damage object
var dmg = new DamageType ( ) ;
var a = this . source . traits . auras . trample ;
2007-01-13 19:41:24 +01:00
dmg . crush = parseInt ( a . crush ) ;
dmg . hack = parseInt ( a . hack ) ;
dmg . pierce = parseInt ( a . pierce ) ;
2006-05-16 06:43:11 +02:00
// Add flank bonus
2006-08-08 05:44:15 +02:00
if ( e . traits . flankPenalty )
2006-05-16 06:43:11 +02:00
{
2006-08-08 05:44:15 +02:00
var flank = ( e . getAttackDirections ( ) - 1 ) * e . traits . flankPenalty . value ;
2006-05-16 06:43:11 +02:00
dmg . crush += dmg . crush * flank ;
dmg . hack += dmg . hack * flank ;
dmg . pierce += dmg . pierce * flank ;
}
// Perform the damage
e . damage ( dmg , this . source ) ;
}
} ;
}
// ====================================================================
2006-07-10 01:13:20 +02:00
function SettlementAura ( source )
{
// Defines the effects of the Settlement Aura. Changes ownership of entity when a civil center is on it.
this . source = source ;
this . affects = function ( e )
{
return ( e . hasClass ( "CivilCentre" ) ) ;
}
this . onEnter = function ( e )
{
if ( this . affects ( e ) )
{
// If a new Civ Centre has entered our radius, it must mean it's on us; switch player and become invisible
source . player = e . player ;
source . visible = false ;
}
} ;
this . onExit = function ( e )
{
if ( this . affects ( e ) )
{
// If a Civ Centre has entered our radius, it must mean the one on us died; become visible again
source . visible = true ;
}
}
}
// ====================================================================
2006-10-26 23:35:25 +02:00
function AllureAura ( source )
{
// Defines the effects of the Allure Aura. (Adjacent male units owned by the same player gather faster.)
this . source = source ;
this . affects = function ( e )
{
return ( e . player . id == this . source . player . id && e . actions && e . actions . gather
&& e . actions . gather . affectedByAllure ) ;
}
this . onEnter = function ( e )
{
if ( this . affects ( e ) )
{
e . allureCount ++ ;
}
} ;
this . onExit = function ( e )
{
if ( this . affects ( e ) )
{
e . allureCount -- ;
}
} ;
}
// ====================================================================
2006-02-13 04:28:36 +01:00
function GotoInRange ( x , y , run )
{
if ( ! this . actions || ! this . actions . move )
return ;
//Add "true" at the end to indicate that this is a notification order.
if ( run && this . actions . move . run )
this . order ( ORDER _RUN , x , y - this . actions . escort . distance , true ) ;
else
this . order ( ORDER _GOTO , x , y - this . actions . escort . distance , true ) ;
}
2006-05-16 06:43:11 +02:00
2006-04-09 00:35:23 +02:00
//=====================================================================
2006-05-16 06:43:11 +02:00
2006-03-31 05:37:36 +02:00
function entityEventFormation ( evt )
{
if ( evt . formationEvent == FORMATION _ENTER )
{
2006-04-09 00:35:23 +02:00
if ( this . getFormationBonus ( ) && this . hasClass ( this . getFormationBonusType ( ) ) )
2006-03-31 05:37:36 +02:00
{
2006-05-04 06:14:48 +02:00
eval ( this + this . getFormationBonus ( ) ) += eval ( this + this . getFormationBonusBase ( ) ) *
2006-03-31 05:37:36 +02:00
this . getFormationBonusVal ( ) ;
}
2006-04-09 00:35:23 +02:00
if ( this . getFormationPenalty ( ) && this . hasInClass ( this . getFormationPenaltyType ( ) ) )
2006-03-31 05:37:36 +02:00
{
2006-05-04 06:14:48 +02:00
eval ( this + this . getFormationPenalty ( ) ) -= eval ( this + this . getFormationPenaltyBase ( ) ) *
2006-03-31 05:37:36 +02:00
this . getFormationPenaltyVal ( ) ;
}
}
//Reverse the bonuses
else if ( evt . formationEvent == FORMATION _LEAVE )
{
2006-04-09 00:35:23 +02:00
if ( this . getFormationPenalty ( ) && this . hasInClass ( this . getFormationPenaltyType ( ) ) )
2006-03-31 05:37:36 +02:00
{
2006-05-04 06:14:48 +02:00
eval ( this + this . getFormationPenalty ( ) ) += eval ( this + this . getFormationPenaltyBase ( ) ) *
2006-03-31 05:37:36 +02:00
this . getFormationPenaltyVal ( ) ;
}
2006-04-09 00:35:23 +02:00
if ( this . getFormationBonus ( ) && this . hasClass ( this . getFormationBonusType ( ) ) )
{
2006-05-04 06:14:48 +02:00
eval ( this + this . getFormationBonus ( ) ) -= eval ( this + this . getFormationBonusBase ( ) ) * this . getFormationBonusVal ( ) ;
2006-04-09 00:35:23 +02:00
}
}
2007-07-14 08:15:19 +02:00
}
// ====================================================================
function getBuildingLimit ( category /*, gameMode*/ )
{
// Civil
if ( category == "CivilCentre" ) return 1 ;
if ( category == "House" ) return 15 ;
if ( category == "Farmstead" ) return 2 ;
2007-07-16 03:56:08 +02:00
if ( category == "Field" ) return 8 ;
2007-07-14 08:15:19 +02:00
// Military
if ( category == "Dock" ) return 2 ;
if ( category == "Fortress" ) return 1 ;
if ( category == "Barracks" ) return 2 ;
if ( category == "ScoutTower" ) return 10 ;
// Other
if ( category == "Special" ) return 1 ;
return 0 ;
2006-03-31 05:37:36 +02:00
}