2010-02-05 23:00:39 +01:00
|
|
|
function Health() {}
|
|
|
|
|
2010-04-09 21:02:39 +02:00
|
|
|
Health.prototype.Schema =
|
2010-04-23 18:09:03 +02:00
|
|
|
"<a:help>Deals with hitpoints and death.</a:help>" +
|
|
|
|
"<a:example>" +
|
|
|
|
"<Max>100</Max>" +
|
|
|
|
"<RegenRate>1.0</RegenRate>" +
|
|
|
|
"<DeathType>corpse</DeathType>" +
|
|
|
|
"</a:example>" +
|
|
|
|
"<element name='Max' a:help='Maximum hitpoints'>" +
|
2010-04-09 21:02:39 +02:00
|
|
|
"<data type='positiveInteger'/>" +
|
|
|
|
"</element>" +
|
|
|
|
"<optional>" +
|
2010-04-23 18:09:03 +02:00
|
|
|
"<element name='Initial' a:help='Initial hitpoints. Default if unspecified is equal to Max'>" +
|
2010-04-09 21:02:39 +02:00
|
|
|
"<data type='positiveInteger'/>" +
|
|
|
|
"</element>" +
|
|
|
|
"</optional>" +
|
|
|
|
"<optional>" +
|
2010-04-23 18:09:03 +02:00
|
|
|
"<element name='RegenRate' a:help='Hitpoint regeneration rate per second. Not yet implemented'>" +
|
2010-04-09 21:02:39 +02:00
|
|
|
"<ref name='positiveDecimal'/>" +
|
|
|
|
"</element>" +
|
|
|
|
"</optional>" +
|
2010-04-23 18:09:03 +02:00
|
|
|
"<element name='DeathType' a:help='Graphical behaviour when the unit dies'>" +
|
|
|
|
"<choice>" +
|
|
|
|
"<value a:help='Disappear instantly'>vanish</value>" +
|
|
|
|
"<value a:help='Turn into a corpse'>corpse</value>" +
|
|
|
|
"</choice>" +
|
|
|
|
"</element>";
|
2010-04-09 21:02:39 +02:00
|
|
|
|
2010-02-05 23:00:39 +01:00
|
|
|
Health.prototype.Init = function()
|
|
|
|
{
|
2010-03-12 22:41:40 +01:00
|
|
|
// Default to <Initial>, but use <Max> if it's undefined or zero
|
|
|
|
// (Allowing 0 initial HP would break our death detection code)
|
|
|
|
this.hitpoints = +(this.template.Initial || this.GetMaxHitpoints());
|
2010-02-05 23:00:39 +01:00
|
|
|
};
|
|
|
|
|
2010-03-07 21:14:30 +01:00
|
|
|
//// Interface functions ////
|
|
|
|
|
2010-02-05 23:00:39 +01:00
|
|
|
Health.prototype.GetHitpoints = function()
|
|
|
|
{
|
|
|
|
return this.hitpoints;
|
|
|
|
};
|
|
|
|
|
2010-02-28 22:45:09 +01:00
|
|
|
Health.prototype.GetMaxHitpoints = function()
|
|
|
|
{
|
|
|
|
return +this.template.Max;
|
|
|
|
};
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
Health.prototype.SetHitpoints = function(value)
|
|
|
|
{
|
|
|
|
// If we're already dead, don't allow resurrection
|
|
|
|
if (this.hitpoints == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.hitpoints = Math.max(1, Math.min(this.GetMaxHitpoints(), value));
|
|
|
|
}
|
|
|
|
|
2010-02-05 23:00:39 +01:00
|
|
|
Health.prototype.Reduce = function(amount)
|
|
|
|
{
|
|
|
|
if (amount >= this.hitpoints)
|
|
|
|
{
|
2010-03-07 21:14:30 +01:00
|
|
|
// If this is the first time we reached 0, then die.
|
|
|
|
// (The entity will exist a little while after calling DestroyEntity so this
|
|
|
|
// might get called multiple times)
|
|
|
|
if (this.hitpoints)
|
|
|
|
{
|
2010-04-04 23:24:39 +02:00
|
|
|
PlaySound("death", this.entity);
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
if (this.template.DeathType == "corpse")
|
|
|
|
this.CreateCorpse();
|
|
|
|
|
2010-03-07 21:14:30 +01:00
|
|
|
Engine.DestroyEntity(this.entity);
|
|
|
|
}
|
|
|
|
|
2010-02-05 23:00:39 +01:00
|
|
|
this.hitpoints = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.hitpoints -= amount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-12 22:41:40 +01:00
|
|
|
Health.prototype.Increase = function(amount)
|
|
|
|
{
|
|
|
|
// If we're already dead, don't allow resurrection
|
|
|
|
if (this.hitpoints == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.hitpoints = Math.min(this.hitpoints + amount, this.GetMaxHitpoints());
|
|
|
|
}
|
|
|
|
|
2010-03-07 21:14:30 +01:00
|
|
|
//// Private functions ////
|
|
|
|
|
|
|
|
Health.prototype.CreateCorpse = function()
|
|
|
|
{
|
|
|
|
// Create a static local version of the current entity
|
|
|
|
var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
|
|
|
var templateName = cmpTempMan.GetCurrentTemplateName(this.entity);
|
|
|
|
var corpse = Engine.AddLocalEntity("preview|" + templateName);
|
|
|
|
// (Maybe this should be some kind of "corpse|" instead of "preview|", if we want
|
|
|
|
// to add things like corpse-removal timers and change the terrain conformance mode)
|
|
|
|
|
|
|
|
// Copy various parameters so it looks just like us
|
|
|
|
|
|
|
|
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
|
|
|
var cmpCorpsePosition = Engine.QueryInterface(corpse, IID_Position);
|
|
|
|
var pos = cmpPosition.GetPosition();
|
|
|
|
cmpCorpsePosition.JumpTo(pos.x, pos.z);
|
|
|
|
var rot = cmpPosition.GetRotation();
|
|
|
|
cmpCorpsePosition.SetYRotation(rot.y);
|
|
|
|
cmpCorpsePosition.SetXZRotation(rot.x, rot.z);
|
|
|
|
|
|
|
|
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
|
|
|
var cmpCorpseOwnership = Engine.QueryInterface(corpse, IID_Ownership);
|
|
|
|
cmpCorpseOwnership.SetOwner(cmpOwnership.GetOwner());
|
|
|
|
|
|
|
|
// Make it fall over
|
|
|
|
var cmpCorpseVisual = Engine.QueryInterface(corpse, IID_Visual);
|
|
|
|
cmpCorpseVisual.SelectAnimation("death", true);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-02-05 23:00:39 +01:00
|
|
|
Engine.RegisterComponentType(IID_Health, "Health", Health);
|