1
0
forked from 0ad/0ad

Added Building AI, and some small changes to GarrisonHolder

This was SVN commit r8636.
This commit is contained in:
evanssthomas 2010-11-17 07:30:25 +00:00
parent 404456ee8e
commit 222095fa44
6 changed files with 186 additions and 11 deletions

View File

@ -8,6 +8,7 @@
<prop actor="props/structures/celts/outpost_windows.xml" attachpoint="root"/>
<prop actor="props/structures/celts/outpost_door.xml" attachpoint="root"/>
<prop actor="props/structures/celts/outpost_shields.xml" attachpoint="root"/>
<prop actor="props/units/weapons/arrow_front.xml" attachpoint="projectile"/>
</props>
</variant>
<variant frequency="1" name="celt outpost b">
@ -16,6 +17,7 @@
<prop actor="props/structures/celts/outpost2_windows.xml" attachpoint="root"/>
<prop actor="props/structures/celts/outpost_shields.xml" attachpoint="root"/>
<prop actor="props/structures/celts/outpost_door.xml" attachpoint="root"/>
<prop actor="props/units/weapons/arrow_front.xml" attachpoint="projectile"/>
</props>
</variant>
</group>

View File

@ -0,0 +1,138 @@
function BuildingAI() {}
BuildingAI.prototype.Schema =
"<element name='DefaultArrowCount'>" +
"<data type='nonNegativeInteger'/>" +
"</element>" +
"<element name='GarrisonArrowMultiplier'>" +
"<ref name='nonNegativeDecimal'/>" +
"</element>";
/**
* Initialize BuildingAI Component
*/
BuildingAI.prototype.Init = function()
{
if (this.template.DefaultArrowCount > 0 || this.template.GarrisonArrowMultiplier > 0)
{
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.timer = cmpTimer.SetTimeout(this.entity, IID_BuildingAI, "FireArrows", 1000, {});
}
};
BuildingAI.prototype.OnOwnershipChanged = function(msg)
{
if (msg.to != -1)
this.SetupRangeQuery(msg.to);
};
/**
* Cleanup on destroy
*/
BuildingAI.prototype.OnDestroy = function()
{
if (this.timer)
{
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
cmpTimer.CancelTimer(this.timer);
this.timer = undefined;
}
// Clean up range queries
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (this.enemyUnitsQuery)
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
};
/**
* Setup the Range Query to detect units coming in & out of range
*/
BuildingAI.prototype.SetupRangeQuery = function(owner)
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
var players = [];
var player = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
// Get our diplomacy array
var diplomacy = player.GetDiplomacy();
var numPlayers = cmpPlayerManager.GetNumPlayers();
for (var i = 1; i < numPlayers; ++i)
{ // Exclude gaia, allies, and self
// TODO: How to handle neutral players - Special query to attack military only?
if ((i != owner) && (diplomacy[i - 1] < 0))
players.push(i);
}
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
if (cmpAttack)
{
var range = cmpAttack.GetRange("Ranged");
this.enemyUnitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, 0);
cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
}
};
/**
* Called when units enter or leave range
*/
BuildingAI.prototype.OnRangeUpdate = function(msg)
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var targetUnits = cmpRangeManager.ResetActiveQuery(this.enemyUnitsQuery);
if (targetUnits.length > 0)
this.targetUnit = targetUnits[0];
else
this.targetUnit = undefined;
};
/**
* Returns the number of arrows which needs to be fired.
* DefaultArrowCount + Garrisoned Archers(ie., any unit capable
* of shooting arrows from inside buildings)
*/
BuildingAI.prototype.GetArrowCount = function()
{
var count = +this.template.DefaultArrowCount;
var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
if (cmpGarrisonHolder)
{
//Need to get garrisoned infantry count
count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount() * this.template.GarrisonArrowMultiplier);
}
return count;
};
/**
* Fires arrows. Called every N times every 2 seconds
* where N is the number of Arrows
*/
BuildingAI.prototype.FireArrows = function()
{
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
if (cmpAttack)
{
var timerInterval;
var arrowCount = this.GetArrowCount();
if (arrowCount > 0)
{
timerInterval = Math.round(2000 / arrowCount);
}
else
{
timerInterval = 1000;
}
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.timer = cmpTimer.SetTimeout(this.entity, IID_BuildingAI, "FireArrows", timerInterval, {});
if ((this.targetUnit != undefined) && (arrowCount > 0))
{
cmpAttack.PerformAttack("Ranged", this.targetUnit);
}
}
};
Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);

View File

@ -55,6 +55,42 @@ GarrisonHolder.prototype.GetCapacity = function()
return this.template.Max;
};
/**
* Get number of garrisoned units capable of shooting arrows
* Not necessarily archers
*/
GarrisonHolder.prototype.GetGarrisonedArcherCount = function()
{
var count = 0;
for each (var entity in this.entities)
{
var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
var classes = cmpIdentity.GetClassesList();
if (classes.indexOf("Infantry") != -1 || classes.indexOf("Ranged") != -1)
count++;
}
return count;
}
/**
* Checks if an entity can be allowed to garrison in the building
* based on it's class
*/
GarrisonHolder.prototype.AllowedToGarrison = function(entity)
{
var allowedClasses = this.GetAllowedClassesList();
var entityClasses = (Engine.QueryInterface(entity, IID_Identity)).GetClassesList();
var classNotAllowed = true;
// Check if the unit is allowed to be garrisoned inside the building
for each (var allowedClass in allowedClasses)
{
if (entityClasses.indexOf(allowedClass) != -1)
{
return true;
}
}
return false;
};
/**
* Garrison a unit inside.
* Returns true if successful, false if not
@ -65,22 +101,12 @@ GarrisonHolder.prototype.Garrison = function(entity)
var entityPopCost = (Engine.QueryInterface(entity, IID_Cost)).GetPopCost();
var entityClasses = (Engine.QueryInterface(entity, IID_Identity)).GetClassesList();
var allowedClasses = this.GetAllowedClassesList();
var classNotAllowed = true;
if (!this.HasEnoughHealth())
return false;
// Check if the unit is allowed to be garrisoned inside the building
for each (var allowedClass in allowedClasses)
{
if (entityClasses.indexOf(allowedClass) != -1)
{
classNotAllowed = false;
break;
}
}
if (classNotAllowed)
if(!this.AllowedToGarrison(entity))
return false;
if (this.GetCapacity() < this.spaceOccupied + 1)

View File

@ -0,0 +1 @@
Engine.RegisterInterface("BuildingAI");

View File

@ -57,4 +57,8 @@
<death>attack/destruction/explode_debris.xml</death>
</SoundGroups>
</Sound>
<BuildingAI>
<DefaultArrowCount>0</DefaultArrowCount>
<GarrisonArrowMultiplier>0</GarrisonArrowMultiplier>
</BuildingAI>
</Entity>

View File

@ -60,4 +60,8 @@
<RepeatTime>2000</RepeatTime>
</Ranged>
</Attack>
<BuildingAI>
<DefaultArrowCount>1</DefaultArrowCount>
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
</BuildingAI>
</Entity>