Ticket #1973: regenerative-resources-v2.patch

File regenerative-resources-v2.patch, 11.5 KB (added by alpha123, 11 years ago)

Change the formula for fish growth; clean some things up.

  • binaries/data/mods/public/simulation/components/ResourceSupply.js

     
    77        "<Type>food.meat</Type>" +
    88    "</a:example>" +
    99    "<element name='KillBeforeGather' a:help='Whether this entity must be killed (health reduced to 0) before its resources can be gathered'>" +
    10         "<data type='boolean'/>" +
    11     "</element>" +
    12     "<element name='Amount' a:help='Amount of resources available from this entity'>" +
    13         "<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" +
    14     "</element>" +
    15     "<element name='Type' a:help='Type of resources'>" +
    16         "<choice>" +
     10        "<data type='boolean'/>" +
     11    "</element>" +
     12    "<element name='Amount' a:help='Amount of resources available from this entity'>" +
     13        "<choice><data type='nonNegativeInteger'/><value>Infinity</value></choice>" +
     14    "</element>" +
     15    "<element name='Type' a:help='Type of resources'>" +
     16        "<choice>" +
    1717            "<value>wood.tree</value>" +
    1818            "<value>wood.ruins</value>" +
    1919            "<value>stone.rock</value>" +
     
    2929            "<value>treasure.metal</value>" +
    3030            "<value>treasure.food</value>" +
    3131        "</choice>" +
    32     "</element>" +
    33     "<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" +
    34         "<data type='nonNegativeInteger'/>" +
    35     "</element>" +
    36     "<optional>" +
    37         "<element name='DiminishingReturns' a:help='The rate at which adding more gatherers decreases overall efficiency. Lower numbers = faster dropoff. Leave the element out for no diminishing returns.'>" +
    38             "<ref name='positiveDecimal'/>" +
    39         "</element>" +
    40     "</optional>";
    41 
    42 ResourceSupply.prototype.Init = function()
    43 {
    44     // Current resource amount (non-negative)
    45     this.amount = this.GetMaxAmount();
    46     this.gatherers = [];    // list of IDs
    47     this.infinite = !isFinite(+this.template.Amount);
    48 };
    49 
    50 ResourceSupply.prototype.IsInfinite = function()
    51 {
    52     return this.infinite;
    53 };
    54 
    55 ResourceSupply.prototype.GetKillBeforeGather = function()
    56 {
    57     return (this.template.KillBeforeGather == "true");
     32    "</element>" +
     33    "<optional>" +
     34        "<element name='Regeneration' a:help='Controls whether this resource can regenerate its remaining amount.'>" +
     35            "<interleave>" +
     36                "<element name='Rate' a:help='Optional regeneration rate. Resources/second if the growth is linear or a constant controlling the rate of growth if the growth is sigmoid.'>" +
     37                    "<ref name='nonNegativeDecimal'/>" +
     38                "</element>" +
     39                "<optional>" +
     40                    "<element name='Acceleration' a:help='Controls the curve the regeneration rate will follow for sigmoid growth; does nothing for linear growth.'>" +
     41                        "<ref name='nonNegativeDecimal'/>" +
     42                    "</element>" +
     43                "</optional>" +
     44                "<element name='Delay' a:help='Seconds between when the number of gatherers hit 0 and the resource starts regenerating.'>" +
     45                    "<data type='nonNegativeInteger'/>" +
     46                "</element>" +
     47                "<element name='Growth' a:help='Growth formula for regeneration. Either linear or sigmoid. Linear continues at a steady rate, while sigmoid gets faster as more resources accumulate, then slows down as it approaches the maximum.'>" +
     48                    "<choice>" +
     49                        "<value>linear</value>" +
     50                        "<value>sigmoid</value>" +
     51                    "</choice>" +
     52                "</element>" +
     53            "</interleave>" +
     54        "</element>" +
     55    "</optional>" +
     56    "<element name='MaxGatherers' a:help='Amount of gatherers who can gather resources from this entity at the same time'>" +
     57        "<data type='nonNegativeInteger'/>" +
     58    "</element>" +
     59    "<optional>" +
     60        "<element name='DiminishingReturns' a:help='The rate at which adding more gatherers decreases overall efficiency. Lower numbers = faster dropoff. Leave the element out for no diminishing returns.'>" +
     61            "<ref name='positiveDecimal'/>" +
     62        "</element>" +
     63    "</optional>";
     64
     65ResourceSupply.prototype.Init = function()
     66{
     67    // Current resource amount (non-negative)
     68    this.amount = this.GetMaxAmount();
     69    this.gatherers = [];    // list of IDs
     70    this.infinite = !isFinite(+this.template.Amount);
     71    if (this.template.Regeneration) {
     72        this.regenRate = +this.template.Regeneration.Rate;
     73        if (this.template.Regeneration.Acceleration)
     74            this.regenAccel = +this.template.Regeneration.Acceleration;
     75        this.regenDelay = +this.template.Regeneration.Delay;
     76    }
     77    if (this.IsRegenerative())
     78        this.RegenerateResources();
    5879};
    5980
     81ResourceSupply.prototype.IsInfinite = function()
     82{
     83    return this.infinite;
     84};
     85
     86ResourceSupply.prototype.GetKillBeforeGather = function()
     87{
     88    return (this.template.KillBeforeGather == "true");
     89};
     90
    6091ResourceSupply.prototype.GetMaxAmount = function()
    6192{
    6293    return +this.template.Amount;
     
    74105
    75106ResourceSupply.prototype.GetGatherers = function()
    76107{
    77     return this.gatherers;
    78 };
    79 
    80 ResourceSupply.prototype.GetDiminishingReturns = function()
    81 {
    82     if ("DiminishingReturns" in this.template)
    83         return ApplyTechModificationsToEntity("ResourceSupply/DiminishingReturns", +this.template.DiminishingReturns, this.entity);
    84     return null;
    85 };
    86 
    87 ResourceSupply.prototype.TakeResources = function(rate)
    88 {
    89     if (this.infinite)
    90         return { "amount": rate, "exhausted": false };
    91 
    92     // 'rate' should be a non-negative integer
    93 
    94     var old = this.amount;
     108    return this.gatherers;
     109};
     110
     111ResourceSupply.prototype.GetDiminishingReturns = function()
     112{
     113    if ("DiminishingReturns" in this.template)
     114        return ApplyTechModificationsToEntity("ResourceSupply/DiminishingReturns", +this.template.DiminishingReturns, this.entity);
     115    return null;
     116};
     117
     118ResourceSupply.prototype.TakeResources = function(rate)
     119{
     120    if (this.infinite)
     121        return { "amount": rate, "exhausted": false };
     122
     123    // 'rate' should be a non-negative integer
     124
     125    var old = this.amount;
    95126    this.amount = Math.max(0, old - rate);
    96127    var change = old - this.amount;
    97128
    98129    // Remove entities that have been exhausted
    99     if (this.amount == 0)
     130    if (this.amount == 0 && !this.IsRegenerative())
    100131        Engine.DestroyEntity(this.entity);
    101132
    102133    Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": old, "to": this.amount });
    103134
    104     return { "amount": change, "exhausted": (this.amount == 0) };
     135    return { "amount": change, "exhausted": this.amount == 0 };
    105136};
    106137
     138ResourceSupply.prototype.RegenerateResources = function(data, lateness)
     139{
     140    var max = this.GetMaxAmount();
     141    if (this.gatherers.length == 0 && !this.regenDelayTimer && this.amount < max)
     142    {
     143        var old = this.amount;
     144        if (this.regenGrowth == "linear")
     145            this.amount = Math.min(max, this.amount + data.rate);
     146        else
     147            this.amount = Math.min(max, this.amount + Math.max(1, data.rate * max * (data.acceleration * this.amount / max -Math.pow(this.amount / max, 2)) / 100));
     148        Engine.PostMessage(this.entity, MT_ResourceSupplyChanged, { "from": old, "to": this.amount });
     149    }
     150    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     151    var regenRate = this.GetRegenerationRate();
     152    var absRegen = Math.abs(regenRate);
     153    if (Math.floor(regenRate) == regenRate || this.regenGrowth == "sigmoid")
     154        cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "RegenerateResources", 1000, { "rate": regenRate, "acceleration": this.GetRegenerationAcceleration() });
     155    else
     156        cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "RegenerateResources", 1000 / absRegen,
     157                { "rate": absRegen == regenRate ? 1 : -1 });
     158};
     159
     160ResourceSupply.prototype.StartRegenerationDelayTimer = function()
     161{
     162    if (!this.regenDelayTimer) {
     163        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     164        this.regenDelayTimer = cmpTimer.SetTimeout(this.entity, IID_ResourceSupply, "CancelRegenerationDelayTimer", this.GetRegenerationDelay() * 1000, null);
     165    }
     166};
     167
     168ResourceSupply.prototype.CancelRegenerationDelayTimer = function()
     169{
     170    var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     171    cmpTimer.CancelTimer(this.regenDelayTimer);
     172    this.regenDelayTimer = null;
     173};
     174
    107175ResourceSupply.prototype.GetType = function()
    108176{
    109177    // All resources must have both type and subtype
     
    119187    return false;
    120188};
    121189
     190ResourceSupply.prototype.IsRegenerative = function()
     191{
     192    return this.GetRegenerationRate() != 0;
     193};
     194
     195ResourceSupply.prototype.GetTerritoryOwner = function ()
     196{
     197    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     198    var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
     199    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     200    if (!(cmpPosition && cmpPosition.IsInWorld()))
     201        return 0;  // Something's wrong, just say we're in neutral territory.
     202    var pos = cmpPosition.GetPosition2D();
     203    return cmpPlayerManager.GetPlayerByID(cmpTerritoryManager.GetOwner(pos.x, pos.y));
     204};
     205
     206ResourceSupply.prototype.GetRegenerationRate = function()
     207{
     208    return ApplyTechModificationsToPlayer("ResourceSupply/Regeneration/Rate", this.regenRate, this.GetTerritoryOwner());
     209};
     210
     211ResourceSupply.prototype.GetRegenerationAcceleration = function()
     212{
     213    return ApplyTechModificationsToPlayer("ResourceSupply/Regeneration/Acceleration", this.regenAccel, this.GetTerritoryOwner());
     214};
     215
     216ResourceSupply.prototype.GetRegenerationDelay = function()
     217{
     218    return ApplyTechModificationsToPlayer("ResourcesSupply/Regeneration/Delay", this.regenDelay, this.GetTerritoryOwner());
     219};
     220
    122221ResourceSupply.prototype.AddGatherer = function(gathererID)
    123222{
    124223    if (!this.IsAvailable(gathererID))
    125224        return false;
    126    
     225
    127226    if (this.gatherers.indexOf(gathererID) === -1)
    128227    {
    129228        this.gatherers.push(gathererID);
     229        this.CancelRegenerationDelayTimer();
    130230        // broadcast message, mainly useful for the AIs.
    131231        Engine.PostMessage(this.entity, MT_ResourceSupplyGatherersChanged, { "to": this.gatherers });
    132232    }
    133    
     233
    134234    return true;
    135235};
    136236
     
    143243        // broadcast message, mainly useful for the AIs.
    144244        Engine.PostMessage(this.entity, MT_ResourceSupplyGatherersChanged, { "to": this.gatherers });
    145245    }
     246    if (this.gatherers.length == 0)
     247        this.StartRegenerationDelayTimer();
    146248};
    147249
    148250Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply);
  • binaries/data/mods/public/simulation/templates/template_gaia_flora_bush_berry.xml

     
    1919    <KillBeforeGather>false</KillBeforeGather>
    2020    <Amount>200</Amount>
    2121    <Type>food.fruit</Type>
    22     <MaxGatherers>8</MaxGatherers>
     22    <MaxGatherers>8</MaxGatherers>
     23    <Regeneration>
     24      <Rate>3</Rate>
     25      <Delay>10</Delay>
     26      <Growth>linear</Growth>
     27    </Regeneration>
    2328  </ResourceSupply>
    2429  <Selectable>
    2530    <EditorOnly disable=""/>
  • binaries/data/mods/public/simulation/templates/template_unit_fauna_fish.xml

     
    2222    <KillBeforeGather>false</KillBeforeGather>
    2323    <Amount>1000</Amount>
    2424    <Type>food.fish</Type>
    25     <MaxGatherers>4</MaxGatherers>
     25    <MaxGatherers>4</MaxGatherers>
     26    <Regeneration>
     27      <Rate>1</Rate>
     28      <Acceleration>1.03</Acceleration>
     29      <Delay>5</Delay>
     30      <Growth>sigmoid</Growth>
     31    </Regeneration>
    2632  </ResourceSupply>
    2733  <Selectable>
    2834    <Overlay>