Ticket #3488: 3488.15.diff

File 3488.15.diff, 12.8 KB (added by Stan, 8 years ago)

Fix the order of disposability of units, this was more complex than I thought because you add to make sure you could still ungarison units in any order.

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

     
    3737    for (let ent of msg.added)
    3838    {
    3939        let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
    40         if (!cmpIdentity)
     40        if (msg.visible[ent] || !cmpIdentity)
    4141            continue;
    4242        if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
    4343            ++this.archersGarrisoned;
     
    4646    for (let ent of msg.removed)
    4747    {
    4848        let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
    49         if (!cmpIdentity)
     49        if (msg.visible[ent] || !cmpIdentity)
    5050            continue;
    5151        if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
    5252            --this.archersGarrisoned;
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
     1/**
     2 * @class Defines an entity's ability to garrison units.
     3 */
    14function GarrisonHolder() {}
    25
    36GarrisonHolder.prototype.Schema =
     
    4548                        "<element name='Z'>" +
    4649                            "<data type='decimal'/>" +
    4750                        "</element>" +
     51                        "<element name='VisibleGarrisonAllowedClasses'>" +
     52                            "<attribute name='datatype'>" +
     53                                "<value>tokens</value>" +
     54                            "</attribute>" +
     55                            "<text/>" +
     56                        "</element>" +
    4857                    "</interleave>" +
    4958                "</element>" +
    5059            "</zeroOrMore>" +
     
    7281            o.x = +offset.X;
    7382            o.y = +offset.Y;
    7483            o.z = +offset.Z;
    75             this.visibleGarrisonPoints.push({"offset":o, "entity": null});
     84            this.visibleGarrisonPoints.push({ "offset": o, "entity": null, "allowedClass": offset.VisibleGarrisonAllowedClasses });
    7685        }
    7786    }
    7887};
     
    100109    return IsOwnedByPlayer(player, ent);
    101110};
    102111
    103 
    104112/**
    105113 * Return the list of entities garrisoned inside
    106114 */
     
    204212};
    205213
    206214/**
     215 * Returns true if the unit is allowed be visible on that garrison point, false otherwise.
     216 */
     217GarrisonHolder.prototype.AllowedToVisibleGarrisoning = function(visibleGarrisonPoint, entity)
     218{
     219    return MatchesClassList(Engine.QueryInterface(entity, IID_Identity).GetClassesList(), visibleGarrisonPoint.allowedClass._string);
     220};
     221
     222/**
    207223 * Garrison a unit inside.
    208224 * Returns true if successful, false if not
    209225 * The timer for AutoHeal is started here
     
    225241        {
    226242            if (vgp.entity)
    227243                continue;
    228             visibleGarrisonPoint = vgp;
    229             break;
     244            if (this.AllowedToVisibleGarrisoning(vgp, entity))
     245            {
     246                visibleGarrisonPoint = vgp;
     247                break;
     248            }
    230249        }
    231250    }
    232 
    233     if (visibleGarrisonPoint)
     251    if (visibleGarrisonPoint && this.AllowedToVisibleGarrisoning(visibleGarrisonPoint, entity))
    234252    {
    235253        visibleGarrisonPoint.entity = entity;
    236254        cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset);
     
    241259    else
    242260        cmpPosition.MoveOutOfWorld();
    243261
     262    let visible = {};
     263    visible[entity] = this.IsVisiblyGarrisoned(entity);
     264    // Should only be called after the garrison has been performed else the visible Garrison Points are not updated yet.
     265    Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     266        "added": [entity],
     267        "removed": [],
     268        "visible": visible
     269    });
    244270    return true;
    245271};
    246272
     273/**
     274 * Garrison units inside the entity
     275 * @return true if successful, false if not
     276 */
    247277GarrisonHolder.prototype.PerformGarrison = function(entity)
    248278{
    249279    if (!this.HasEnoughHealth())
     
    250280        return false;
    251281
    252282    // Check if the unit is allowed to be garrisoned inside the building
    253     if(!this.AllowedToGarrison(entity))
     283    if (!this.AllowedToGarrison(entity))
    254284        return false;
    255285
    256     // check the capacity
     286    // Check the capacity
    257287    var extraCount = 0;
    258288    var cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder);
    259289    if (cmpGarrisonHolder)
     
    278308    if (cmpAura && cmpAura.HasGarrisonAura())
    279309        cmpAura.ApplyGarrisonBonus(this.entity);
    280310
    281     Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [entity], "removed": [] });
    282 
    283311    var cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
    284312    if (cmpUnitAI && cmpUnitAI.IsUnderAlert())
    285313        Engine.PostMessage(cmpUnitAI.GetAlertRaiser(), MT_UnitGarrisonedAfterAlert, {"holder": this.entity, "unit": entity});
     
    326354
    327355    var cmpNewPosition = Engine.QueryInterface(entity, IID_Position);
    328356    this.entities.splice(entityIndex, 1);
    329 
     357   
     358    let visible = {};
     359    visible[entity] = this.IsVisiblyGarrisoned(entity);
     360    // Should only be called before the ejection has been performed else the visible Garrison Points will be empty.
     361    Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     362        "added": [],
     363        "removed": [entity],
     364        "visible": visible
     365    });
    330366    for (var vgp of this.visibleGarrisonPoints)
    331367    {
    332368        if (vgp.entity != entity)
     
    356392    cmpNewPosition.SetHeightOffset(0);
    357393    // TODO: what direction should they face in?
    358394
    359     Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [entity] });
    360395
    361396    return true;
    362397};
     
    454489 */
    455490GarrisonHolder.prototype.UnloadTemplate = function(extendedTemplate, all, forced)
    456491{
    457     var index = extendedTemplate.indexOf("&");
     492    let index = extendedTemplate.indexOf("&");
    458493    if (index == -1)
    459494        return false;
    460495
    461     var owner = +extendedTemplate.slice(1,index);
    462     var template = extendedTemplate.slice(index+1);
     496    let entities = [];
     497    let visibleEntities = [];
     498    let entitiesMatching = [];
     499    let entitiesNotOwned = [];
     500    let entitiesNotMatchingName = [];
     501    let owner = +extendedTemplate.slice(1, index);
     502    let template = extendedTemplate.slice(index + 1);
     503    let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
    463504
    464     var entities = [];
    465     var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
    466     for each (var entity in this.entities)
    467     {
    468         var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     505    entitiesNotOwned=  this.entities.filter(e =>  Engine.QueryInterface(e, IID_Ownership).GetOwner()  != owner);
     506    entitiesNotMatchingName = this.entities.filter(e =>  (Engine.QueryInterface(e, IID_Identity).GetSelectionGroupName() || cmpTemplateManager.GetCurrentTemplateName(e))  != template);
    469507
    470         // Units with multiple ranks are grouped together.
    471         var name = cmpIdentity.GetSelectionGroupName()
    472                    || cmpTemplateManager.GetCurrentTemplateName(entity);
     508    for (let entity of this.entities)
     509        if(!entitiesNotOwned.some(e=> e == entity) && ! entitiesNotMatchingName.some(e=> e == entity))
     510            entitiesMatching.push(entity);
    473511
    474         if (name != template)
    475             continue;
    476         if (owner != Engine.QueryInterface(entity, IID_Ownership).GetOwner())
    477             continue;
     512    for (let entity of entitiesMatching)
     513    {
     514        if (this.IsVisiblyGarrisoned(entity))
     515            visibleEntities.push(entity);
     516        else
     517            entities.push(entity);
    478518
    479         entities.push(entity);
     519        // If 'all' is false, only ungarrison the first matched unit and if possible,  one that 's not visible.
     520        if (!all)
     521        {
     522            if (!entities.length)
     523            {
     524                if (entitiesMatching.length !== visibleEntities.length)
     525                    continue;
    480526
    481         // If 'all' is false, only ungarrison the first matched unit.
    482         if (!all)
     527                if (visibleEntities.length)
     528                    entities.push(visibleEntities[0]);
     529            }
    483530            break;
     531        }
    484532    }
    485 
     533    if (all)
     534        entities.push.apply(entities,visibleEntities);
    486535    return this.PerformEject(entities, forced);
    487536};
    488537
     
    612661    }
    613662
    614663    // or on some of its garrisoned units
    615     var entityIndex = this.entities.indexOf(msg.entity);
     664    let entityIndex = this.entities.indexOf(msg.entity);
    616665    if (entityIndex != -1)
    617666    {
    618667        // If the entity is dead, remove it directly instead of ejecting the corpse
    619         var cmpHealth = Engine.QueryInterface(msg.entity, IID_Health);
     668        let cmpHealth = Engine.QueryInterface(msg.entity, IID_Health);
    620669        if (cmpHealth && cmpHealth.GetHitpoints() == 0)
    621670        {
    622671            this.entities.splice(entityIndex, 1);
    623             Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [msg.entity] });
     672            let visible = {};
     673            visible[msg.entity] = this.IsVisiblyGarrisoned(msg.entity);
     674            Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     675                "added": [],
     676                "removed": [msg.entity],
     677                "visible": visible
     678            });
    624679            this.UpdateGarrisonFlag();
    625680
    626681            for (var pt of this.visibleGarrisonPoints)
     
    634689
    635690/**
    636691 * Update list of garrisoned entities if one gets renamed (e.g. by promotion)
     692 * vgpEntity is only defined in some peculiar case where we want to reuse the same visibleGarrisonPoint,
     693 * in case of promotion for example, and thus should always be allowed.
    637694 */
    638695GarrisonHolder.prototype.OnGlobalEntityRenamed = function(msg)
    639696{
     
    670727    }
    671728};
    672729
    673 
    674730/**
    675731 * Eject all foreign garrisoned entities which are no more allied
    676732 */
     
    687743GarrisonHolder.prototype.EjectOrKill = function(entities)
    688744{
    689745    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    690     // Eject the units which can be ejected (if not in world, it generally means this holder
     746    // Eject the units which can be ejected (if not in world, it often means this holder
    691747    // is inside a holder which kills its entities, so do not eject)
    692748    if (cmpPosition.IsInWorld())
    693749    {
     
    710766        this.entities.splice(entityIndex, 1);
    711767        killedEntities.push(entity);
    712768    }
    713 
    714769    if (killedEntities.length > 0)
    715         Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed" : killedEntities });
     770    {
     771        let visibleEntitiesIds = {};
     772        for (let ent of killedEntities)
     773            visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent);
     774        Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     775            "added": [],
     776            "removed": killedEntities,
     777            "visible": visibleEntitiesIds
     778        });
     779    }
    716780    this.UpdateGarrisonFlag();
    717781};
    718782
    719783/**
     784 * Gives insight about the unit type of garrisoning.
     785 * @return{bool} returns true if the unit is visible on the structure
     786 * @param {int} the entity's id
     787 */
     788GarrisonHolder.prototype.IsVisiblyGarrisoned = function(entity)
     789{
     790    return this.visibleGarrisonPoints.some(point => point.entity == entity);
     791};
     792
     793/**
    720794 * Checks if an entity is ejectable on destroy if possible
    721795 */
    722796GarrisonHolder.prototype.IsEjectable = function(entity)
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.xml

     
    2020    <VisibleGarrisonPoints>
    2121      <Archer1>
    2222        <X>0</X><Y>11.5</Y><Z>0</Z>
     23        <VisibleGarrisonAllowedClasses datatype="tokens">
     24          Infantry+Ranged
     25        </VisibleGarrisonAllowedClasses>
    2326      </Archer1>
    2427      <Archer2>
    2528        <X>8</X><Y>11.5</Y><Z>0</Z>
     29        <VisibleGarrisonAllowedClasses datatype="tokens">
     30          Infantry+Ranged
     31        </VisibleGarrisonAllowedClasses>
    2632      </Archer2>
    2733      <Archer3>
    2834        <X>-8</X><Y>11.5</Y><Z>0</Z>
     35        <VisibleGarrisonAllowedClasses datatype="tokens">
     36          Infantry+Ranged
     37        </VisibleGarrisonAllowedClasses>
    2938      </Archer3>
    3039      <Archer4>
    3140        <X>4</X><Y>11.5</Y><Z>0</Z>
     41        <VisibleGarrisonAllowedClasses datatype="tokens">
     42          Infantry+Ranged
     43        </VisibleGarrisonAllowedClasses>
    3244      </Archer4>
    3345      <Archer5>
    3446        <X>-4</X><Y>11.5</Y><Z>0</Z>
     47        <VisibleGarrisonAllowedClasses datatype="tokens">
     48          Infantry+Ranged
     49        </VisibleGarrisonAllowedClasses>
    3550      </Archer5>
    3651    </VisibleGarrisonPoints>
    3752  </GarrisonHolder>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_medium.xml

     
    1717    <VisibleGarrisonPoints>
    1818      <Archer1>
    1919        <X>0</X><Y>11.5</Y><Z>0</Z>
     20        <VisibleGarrisonAllowedClasses datatype="tokens">
     21          Infantry+Ranged
     22        </VisibleGarrisonAllowedClasses>
    2023      </Archer1>
    2124      <Archer2>
    2225        <X>4</X><Y>11.5</Y><Z>0</Z>
     26        <VisibleGarrisonAllowedClasses datatype="tokens">
     27          Infantry+Ranged
     28        </VisibleGarrisonAllowedClasses>
    2329      </Archer2>
    2430      <Archer3>
    2531        <X>-4</X><Y>11.5</Y><Z>0</Z>
     32        <VisibleGarrisonAllowedClasses datatype="tokens">
     33          Infantry+Ranged
     34        </VisibleGarrisonAllowedClasses>
    2635      </Archer3>
    2736    </VisibleGarrisonPoints>
    2837  </GarrisonHolder>