2010-03-12 22:41:40 +01:00
|
|
|
function Foundation() {}
|
|
|
|
|
2010-04-23 18:09:03 +02:00
|
|
|
Foundation.prototype.Schema =
|
|
|
|
"<a:component type='internal'/><empty/>";
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
Foundation.prototype.Init = function()
|
|
|
|
{
|
2011-02-10 17:06:28 +01:00
|
|
|
// Foundations are initially 'uncommitted' and do not block unit movement at all
|
|
|
|
// (to prevent players exploiting free foundations to confuse enemy units).
|
|
|
|
// The first builder to reach the uncommitted foundation will tell friendly units
|
|
|
|
// and animals to move out of the way, then will commit the foundation and enable
|
|
|
|
// its obstruction once there's nothing in the way.
|
|
|
|
this.committed = false;
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
this.buildProgress = 0.0; // 0 <= progress <= 1
|
|
|
|
};
|
|
|
|
|
|
|
|
Foundation.prototype.InitialiseConstruction = function(owner, template)
|
|
|
|
{
|
|
|
|
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
|
|
|
|
|
|
|
|
this.finalTemplateName = template;
|
|
|
|
this.addedHitpoints = cmpHealth.GetHitpoints();
|
|
|
|
this.maxHitpoints = cmpHealth.GetMaxHitpoints();
|
|
|
|
|
|
|
|
// We need to know the owner in OnDestroy, but at that point the entity has already been
|
|
|
|
// decoupled from its owner, so we need to remember it in here (and assume it won't change)
|
|
|
|
this.owner = owner;
|
2010-03-18 00:16:04 +01:00
|
|
|
|
|
|
|
this.initialised = true;
|
2010-03-12 22:41:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
Foundation.prototype.GetBuildPercentage = function()
|
|
|
|
{
|
|
|
|
return Math.floor(this.buildProgress * 100);
|
|
|
|
};
|
|
|
|
|
|
|
|
Foundation.prototype.OnDestroy = function()
|
|
|
|
{
|
|
|
|
// Refund a portion of the construction cost, proportional to the amount of build progress remaining
|
|
|
|
|
2010-03-18 00:16:04 +01:00
|
|
|
if (!this.initialised) // this happens if the foundation was destroyed because the player had insufficient resources
|
|
|
|
return;
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
if (this.buildProgress == 1.0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
|
|
|
|
var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(this.owner), IID_Player);
|
|
|
|
|
|
|
|
var cmpCost = Engine.QueryInterface(this.entity, IID_Cost);
|
|
|
|
var costs = cmpCost.GetResourceCosts();
|
|
|
|
for (var r in costs)
|
|
|
|
{
|
|
|
|
var scaled = Math.floor(costs[r] * (1.0 - this.buildProgress));
|
|
|
|
if (scaled)
|
|
|
|
cmpPlayer.AddResource(r, scaled);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2010-03-12 23:28:51 +01:00
|
|
|
* Perform some number of seconds of construction work.
|
2010-03-12 22:41:40 +01:00
|
|
|
* Returns true if the construction is completed.
|
|
|
|
*/
|
|
|
|
Foundation.prototype.Build = function(builderEnt, work)
|
|
|
|
{
|
|
|
|
// Do nothing if we've already finished building
|
2010-07-21 18:09:58 +02:00
|
|
|
// (The entity will be destroyed soon after completion so
|
|
|
|
// this won't happen much)
|
2010-03-12 22:41:40 +01:00
|
|
|
if (this.buildProgress == 1.0)
|
2010-07-21 18:09:58 +02:00
|
|
|
return;
|
2010-03-12 22:41:40 +01:00
|
|
|
|
2011-02-10 17:06:28 +01:00
|
|
|
// Handle the initial 'committing' of the foundation
|
|
|
|
if (!this.committed)
|
|
|
|
{
|
|
|
|
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
|
|
|
if (cmpObstruction)
|
|
|
|
{
|
|
|
|
// If there's any units in the way, ask them to move away
|
|
|
|
// and return early from this method.
|
|
|
|
// Otherwise enable this obstruction so it blocks any further
|
|
|
|
// units, and continue building.
|
|
|
|
|
|
|
|
var collisions = cmpObstruction.GetConstructionCollisions();
|
|
|
|
if (collisions.length)
|
|
|
|
{
|
|
|
|
for each (var ent in collisions)
|
|
|
|
{
|
|
|
|
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
|
|
|
|
if (cmpUnitAI)
|
|
|
|
cmpUnitAI.LeaveFoundation(this.entity);
|
|
|
|
|
|
|
|
var cmpAnimalAI = Engine.QueryInterface(ent, IID_AnimalAI);
|
|
|
|
if (cmpAnimalAI)
|
|
|
|
cmpAnimalAI.LeaveFoundation(this.entity);
|
|
|
|
|
|
|
|
// TODO: What if an obstruction has no UnitAI/AnimalAI?
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: maybe we should tell the builder to use a special
|
|
|
|
// animation to indicate they're waiting for people to get
|
|
|
|
// out the way
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmpObstruction.SetActive(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.committed = true;
|
|
|
|
}
|
|
|
|
|
2010-03-12 23:28:51 +01:00
|
|
|
// Calculate the amount of progress that will be added (where 1.0 = completion)
|
|
|
|
var cmpCost = Engine.QueryInterface(this.entity, IID_Cost);
|
|
|
|
var amount = work / cmpCost.GetBuildTime();
|
2010-03-12 22:41:40 +01:00
|
|
|
|
|
|
|
// TODO: implement some kind of diminishing returns for multiple builders.
|
|
|
|
// e.g. record the set of entities that build this, then every ~2 seconds
|
|
|
|
// count them (and reset the list), and apply some function to the count to get
|
|
|
|
// a factor, and apply that factor here.
|
|
|
|
|
|
|
|
this.buildProgress += amount;
|
|
|
|
if (this.buildProgress > 1.0)
|
|
|
|
this.buildProgress = 1.0;
|
|
|
|
|
|
|
|
// Add an appropriate proportion of hitpoints
|
|
|
|
var targetHP = Math.max(0, Math.min(this.maxHitpoints, Math.floor(this.maxHitpoints * this.buildProgress)));
|
|
|
|
var deltaHP = targetHP - this.addedHitpoints;
|
|
|
|
if (deltaHP > 0)
|
|
|
|
{
|
|
|
|
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
|
|
|
|
cmpHealth.Increase(deltaHP);
|
|
|
|
this.addedHitpoints += deltaHP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.buildProgress >= 1.0)
|
|
|
|
{
|
|
|
|
// Finished construction
|
|
|
|
|
|
|
|
// Create the real entity
|
|
|
|
var building = Engine.AddEntity(this.finalTemplateName);
|
|
|
|
|
|
|
|
// Copy various parameters from the foundation
|
|
|
|
|
|
|
|
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
|
|
|
var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);
|
|
|
|
var pos = cmpPosition.GetPosition();
|
|
|
|
cmpBuildingPosition.JumpTo(pos.x, pos.z);
|
|
|
|
var rot = cmpPosition.GetRotation();
|
|
|
|
cmpBuildingPosition.SetYRotation(rot.y);
|
|
|
|
cmpBuildingPosition.SetXZRotation(rot.x, rot.z);
|
|
|
|
// TODO: should add a ICmpPosition::CopyFrom() instead of all this
|
|
|
|
|
|
|
|
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
|
|
|
var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);
|
|
|
|
cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());
|
2010-11-12 23:24:49 +01:00
|
|
|
|
|
|
|
var cmpPlayerStatisticsTracker = QueryOwnerInterface(this.entity, IID_StatisticsTracker);
|
|
|
|
cmpPlayerStatisticsTracker.IncreaseConstructedBuildingsCounter();
|
|
|
|
|
|
|
|
var cmpIdentity = Engine.QueryInterface(building, IID_Identity);
|
|
|
|
if (cmpIdentity.GetClassesList().indexOf("CivCentre") != -1) cmpPlayerStatisticsTracker.IncreaseBuiltCivCentresCounter();
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
|
|
|
|
var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);
|
|
|
|
cmpBuildingHealth.SetHitpoints(cmpHealth.GetHitpoints());
|
|
|
|
|
2010-07-21 18:09:58 +02:00
|
|
|
Engine.PostMessage(this.entity, MT_ConstructionFinished,
|
|
|
|
{ "entity": this.entity, "newentity": building });
|
2010-03-12 22:41:40 +01:00
|
|
|
|
2010-07-21 18:09:58 +02:00
|
|
|
Engine.DestroyEntity(this.entity);
|
2010-03-12 22:41:40 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Engine.RegisterComponentType(IID_Foundation, "Foundation", Foundation);
|
|
|
|
|