Page MenuHomeWildfire Games
Paste P169

Repairable class
ActivePublic

Authored by elexis on Sep 6 2019, 2:10 AM.
class Repairable
{
get Schema()
{
return "<a:help>Deals with repairable structures and units.</a:help>" +
"<a:example>" +
"<RepairTimeRatio>2.0</RepairTimeRatio>" +
"</a:example>" +
"<element name='RepairTimeRatio' a:help='repair time ratio relative to building (or production) time.'>" +
"<ref name='positiveDecimal'/>" +
"</element>";
}
Init()
{
this.builders = new Map(); // Map of builder entities to their work per second
this.totalBuilderRate = 0; // Total amount of work the builders do each second
this.buildMultiplier = 1; // Multiplier for the amount of work builders do
this.buildTimePenalty = 0.7; // Penalty for having multiple builders
this.repairTimeRatio = +this.template.RepairTimeRatio;
}
/**
* Returns the current build progress in a [0,1] range.
*/
GetBuildProgress()
{
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
if (!cmpHealth)
return 0;
var hitpoints = cmpHealth.GetHitpoints();
var maxHitpoints = cmpHealth.GetMaxHitpoints();
return hitpoints / maxHitpoints;
}
GetNumBuilders()
{
return this.builders.size;
}
AddBuilder(builderEnt)
{
if (this.builders.has(builderEnt))
return;
this.builders.set(builderEnt, Engine.QueryInterface(builderEnt, IID_Builder).GetRate());
this.totalBuilderRate += this.builders.get(builderEnt);
this.SetBuildMultiplier();
}
RemoveBuilder(builderEnt)
{
if (!this.builders.has(builderEnt))
return;
this.totalBuilderRate -= this.builders.get(builderEnt);
this.builders.delete(builderEnt);
this.SetBuildMultiplier();
}
/**
* The build multiplier is a penalty that is applied to each builder.
* For example, ten women build at a combined rate of 10^0.7 = 5.01 instead of 10.
*/
CalculateBuildMultiplier(num)
{
// Avoid division by zero, in particular 0/0 = NaN which isn't reliably serialized
return num < 2 ? 1 : Math.pow(num, this.buildTimePenalty) / num;
}
SetBuildMultiplier()
{
this.buildMultiplier = this.CalculateBuildMultiplier(this.GetNumBuilders());
}
GetBuildTime()
{
let timeLeft = (1 - this.GetBuildProgress()) * Engine.QueryInterface(this.entity, IID_Cost).GetBuildTime() * this.repairTimeRatio;
let rate = this.totalBuilderRate * this.buildMultiplier;
// The rate if we add another woman to the repairs
let rateNew = (this.totalBuilderRate + 1) * this.CalculateBuildMultiplier(this.GetNumBuilders() + 1);
return {
// Avoid division by zero, in particular 0/0 = NaN which isn't reliably serialized
"timeRemaining": rate ? timeLeft / rate : 0,
"timeRemainingNew": timeLeft / rateNew
}
}
// TODO: should we have resource costs?
Repair(builderEnt, rate)
{
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
let cmpCost = Engine.QueryInterface(this.entity, IID_Cost);
if (!cmpHealth || !cmpCost)
return;
let damage = cmpHealth.GetMaxHitpoints() - cmpHealth.GetHitpoints();
if (damage <= 0)
return;
// Calculate the amount of hitpoints that will be added (using diminishing rate when several builders)
let work = rate * this.buildMultiplier * this.GetRepairRate();
let amount = Math.min(damage, work);
cmpHealth.Increase(amount);
// Update the total builder rate
this.totalBuilderRate += rate - this.builders.get(builderEnt);
this.builders.set(builderEnt, rate);
// If we repaired all the damage, send a message to entities to stop repairing this building
if (amount >= damage)
Engine.PostMessage(this.entity, MT_ConstructionFinished, { "entity": this.entity, "newentity": this.entity });
}
GetRepairRate()
{
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
let cmpCost = Engine.QueryInterface(this.entity, IID_Cost);
let repairTime = this.repairTimeRatio * cmpCost.GetBuildTime();
return repairTime ? cmpHealth.GetMaxHitpoints() / repairTime : 1;
}
}
Engine.RegisterComponentType(IID_Repairable, "Repairable", Repairable);

Event Timeline

elexis created this paste.Sep 6 2019, 2:10 AM
Stan added a subscriber: Stan.EditedSep 6 2019, 8:26 AM

Is there a way we can play a I will repair sound instead of I will build ? Or is that in UnitAI ?

EDIT1: JSDOC would be nice.
EDIT2: does the get Schema work ?

Angen added a subscriber: Angen.EditedSep 6 2019, 7:13 PM

@Stan
units have different sound for order_repair and order_build at least in templates
issue is that i unit_actions.js is only command repair and so always is used and played order_repair even if target is just foundation and not damaged building

and unitAi does not differentiate these commands too

elexis added a comment.Sep 6 2019, 7:38 PM

What do you think why I uploaded this paste?

elexis changed the visibility from "All Users" to "Public (No Login Required)".Sep 6 2019, 9:08 PM
Stan added a comment.Sep 6 2019, 11:12 PM
In P169#1367, @Angen wrote:

@Stan
units have different sound for order_repair and order_build at least in templates
issue is that i unit_actions.js is only command repair and so always is used and played order_repair even if target is just foundation and not damaged building
and unitAi does not differentiate these commands too

Thanks for the explanation

In P169#1368, @elexis wrote:

What do you think why I uploaded this paste?

Sorry, indeed I misunderstood your intent here.

elexis added a comment.Sep 7 2019, 2:24 AM

refs IRClogs yesterday and today, and lobby logs today.
The file contains the same code as currently committed, but uses the class syntax.

The Schema uses the getter syntax, i.e. performs the function if the property is referenced, i.e. .Schema as usual, not .Schema(). It works, has been uncharted territory for me too.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

elexis added a comment.Sep 7 2019, 1:04 PM

As reported on the lobby yesterday, another feature of the class keyword is that it throws an error if one calls a constructor without new:

TypeError: class constructors must be invoked with |new|

elexis added a comment.EditedSep 9 2019, 10:38 AM

Class keyword discussion with Krinkle on:
http://irclogs.wildfiregames.com/2019-08/2019-08-31-QuakeNet-%230ad-dev.log

Class keyword comments by smiley on lobby on September 1st and 6th

Class keyword discussion with Krinkle, nani, Chakakhan, bb, fpre:
http://irclogs.wildfiregames.com/2019-09/2019-09-05-QuakeNet-%230ad-dev.log

Class keyword disussion with wraitii on:
http://irclogs.wildfiregames.com/2019-09/2019-09-07-QuakeNet-%230ad-dev.log

First use of class keyword in rP22854 / D2240.

GUI to be rewritten from procedural code to OOP code in #5387, hence the necessary decision.

To make it consistent the AI, simulation and rmgen would be considered as well.

Brief class keyword discussion with Vladislav:
http://irclogs.wildfiregames.com/2019-09/2019-09-16-QuakeNet-%230ad-dev.log