Ticket #4355: ResourceSupply.js.patch

File ResourceSupply.js.patch, 6.5 KB (added by Teiresias, 7 years ago)

New attempt to solve the bug based on calling GetNumGatherersByPlayer()

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

     
    8181    return this.gatherers.reduce((a, b) => a + b.length, 0);
    8282};
    8383
     84/**
     85 * @summary Fetches the number of gatherers of a given player currently associated with the resource.
     86 * @param playerId {Number} The id of the player whose gatherers are to be counted.
     87 * @return {Number} Number of gatherers of the specified player currently associated with the resource.
     88 */
     89ResourceSupply.prototype.GetNumGatherersByPlayer = function (playerId)
     90{
     91    return this.gatherers[playerId] ? this.gatherers[playerId].length : 0;
     92};
     93
    8494/* The rate of each additionnal gatherer rate follow a geometric sequence, with diminishingReturns as common ratio. */
    8595ResourceSupply.prototype.GetDiminishingReturns = function()
    8696{
     
    128138    return this.cachedType;
    129139};
    130140
     141/**
     142 * @summary Tests whether a particular unit may gather from this resource supply.
     143 * @param player {Number} Id of the player the gatherer belongs to
     144 * @param gathererID {Number} Id of the entity which is tested for gathering.
     145 * @return {Boolean} true iff the tested gatherer may, at the current time, gather
     146 *                   from this resource supply.
     147 */
    131148ResourceSupply.prototype.IsAvailable = function(player, gathererID)
    132149{
    133     if (this.GetNumGatherers() < this.GetMaxGatherers() || this.gatherers[player].indexOf(gathererID) !== -1)
     150    if (this.gatherers[player].indexOf(gathererID) == -1)
     151    {
     152        if (this.cachedType.generic == "treasure")
     153        {
     154            return (this.GetNumGatherersByPlayer(player) < this.GetMaxGatherers());
     155        }
     156        else
     157        {
     158            return (this.GetNumGatherers() < this.GetMaxGatherers());
     159        }
     160    }
     161    else
     162    {
     163        // Unit is already gathering
    134164        return true;
    135     return false;
     165    }
    136166};
    137167
    138168ResourceSupply.prototype.AddGatherer = function(player, gathererID)
  • binaries/data/mods/public/simulation/components/tests/test_ResourceSupply.js

     
     1// This stub must be already present when loading ResourceSupply.js as it is
     2// needed for the ResourceSupply schema definition which is built on load
     3Resources =
     4{
     5    "BuildChoicesSchema" : function () { },
     6    "GetNames" : function () { return {"type1":{}}; },
     7    "GetResource" :
     8        function () {
     9            return {
     10                "subtypes": {"type1" : {}}
     11            };
     12        }
     13};
     14
     15Engine.LoadComponentScript("interfaces/ResourceSupply.js");
     16Engine.LoadComponentScript("ResourceSupply.js");
     17
     18/**
     19 * @summary Ensures consistent behavior of IsAvailable() for already-gathering units
     20 * @description When a gatherer has been attached to a resource supply, IsAvailable()
     21 *              shall still return true for that gatherer, so a simple test of "max
     22 *              number of gatherers &lt; actual number of gatherers" is not sufficient:
     23 *              The resource supply may be crowded up and don't accept any futher
     24 *              gatherers, but these already present may continue to work
     25 * @param template {Object} DOM of the ResourceSupply template definition (as if loaded
     26 *                          from XML files)
     27 * @return undefined
     28 */
     29function entityGatheringCanContinue(template) {
     30    ResetState();
     31
     32    AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
     33        GetNumPlayers: function() { return 1; }
     34    });
     35
     36    var gathererId = 3;
     37    var playerId = 1;
     38    var treasureId = 2;
     39
     40    var testSupply = ConstructComponent(treasureId, "ResourceSupply", template);
     41
     42    TS_ASSERT(testSupply.IsAvailable(playerId));
     43    testSupply.AddGatherer(playerId, gathererId);
     44   
     45    TS_ASSERT_EQUALS(testSupply.GetNumGatherers(), 1);
     46    TS_ASSERT_EQUALS(testSupply.GetMaxGatherers(), 1);
     47    TS_ASSERT(testSupply.IsAvailable(playerId, gathererId));
     48};
     49
     50// Test cases to ensure that gatherers already working on a resource are granted
     51// subsequent access to it
     52entityGatheringCanContinue(
     53    {
     54        "Amount" : 100,
     55        "MaxGatherers" : 1,
     56        "Type" : "treasure.type1"
     57    });
     58entityGatheringCanContinue(
     59    {
     60        "Amount" : 100,
     61        "MaxGatherers" : 1,
     62        "Type" : "generic.type1"
     63    });
     64
     65/**
     66 * @summary Ensures normal resource supplies allow only as many concurrent gatherers
     67 *          as defined in the template, not caring who they are.
     68 * @return undefined
     69 */
     70function normalResourcesAllowOnlyMaxGatherersConcurrently() {
     71    ResetState();
     72
     73    AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
     74        GetNumPlayers: function() { return 2; }
     75    });
     76
     77    var gathererId1_Player1 = 3;
     78    var gathererId2_Player1 = 5;
     79    var gathererId_Player2 = 4;
     80    var treasureId = 2;
     81
     82    var testSupply = ConstructComponent(treasureId, "ResourceSupply",
     83        {
     84            "Amount" : 100,
     85            "MaxGatherers" : 1,
     86            "Type" : "generic.type1"
     87        });
     88    // Player 1 approaches it
     89    testSupply.AddGatherer(1, gathererId1_Player1);
     90    // and no second gatherer from player 1 is allowed
     91    TS_ASSERT(!testSupply.IsAvailable(1, gathererId2_Player1));
     92    // also, no other player may access it at the same time
     93    TS_ASSERT(!testSupply.IsAvailable(1, gathererId_Player2));
     94};
     95
     96normalResourcesAllowOnlyMaxGatherersConcurrently();
     97
     98/**
     99 * @summary Ensures that treasures grant access to multiple players independently.
     100 * @description Usual treasure max limit is 1 (since they are instant pick-up), so
     101 *              using the same gathering limits as for normal resources would allow
     102 *              a player to hold out a treasure of all other players while he tries
     103 *              to grab it.
     104 *              Instead, each player may send up to one gatherer to it and the fastest
     105 *              one wins.
     106 * @return undefined
     107 */
     108function multiplePlayersMayHuntForSameTreasureConcurrently() {
     109    ResetState();
     110
     111    AddMock(SYSTEM_ENTITY, IID_PlayerManager, {
     112        GetNumPlayers: function() { return 2; }
     113    });
     114
     115    var gathererId_Player1 = 3;
     116    var gathererId_Player2 = 4;
     117    var treasureId = 2;
     118
     119    var testSupply = ConstructComponent(treasureId, "ResourceSupply",
     120        {
     121            "Amount" : 100,
     122            "MaxGatherers" : 1,
     123            "Type" : "treasure.type1"
     124        });
     125    // Player 1 approaches it
     126    testSupply.AddGatherer(1, gathererId_Player1);
     127    // and player 2 is still allowed to try as well
     128    TS_ASSERT(testSupply.IsAvailable(2, gathererId_Player2));
     129};
     130
     131multiplePlayersMayHuntForSameTreasureConcurrently();
     132