Ticket #3488: 3488.16.diff

File 3488.16.diff, 14.6 KB (added by Stan, 7 years ago)

Basic Feature, tested by wowgetoffyourcellphone

  • 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
     
    607656    }
    608657
    609658    // or on some of its garrisoned units
    610     var entityIndex = this.entities.indexOf(msg.entity);
     659    let entityIndex = this.entities.indexOf(msg.entity);
    611660    if (entityIndex != -1)
    612661    {
    613662        // If the entity is dead, remove it directly instead of ejecting the corpse
    614         var cmpHealth = Engine.QueryInterface(msg.entity, IID_Health);
     663        let cmpHealth = Engine.QueryInterface(msg.entity, IID_Health);
    615664        if (cmpHealth && cmpHealth.GetHitpoints() == 0)
    616665        {
    617666            this.entities.splice(entityIndex, 1);
    618             Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [msg.entity] });
     667            let visible = {};
     668            visible[msg.entity] = this.IsVisiblyGarrisoned(msg.entity);
     669            Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     670                "added": [],
     671                "removed": [msg.entity],
     672                "visible": visible
     673            });
    619674            this.UpdateGarrisonFlag();
    620675
    621676            for (var pt of this.visibleGarrisonPoints)
     
    629684
    630685/**
    631686 * Update list of garrisoned entities if one gets renamed (e.g. by promotion)
     687 * vgpEntity is only defined in some peculiar case where we want to reuse the same visibleGarrisonPoint,
     688 * in case of promotion for example, and thus should always be allowed.
    632689 */
    633690GarrisonHolder.prototype.OnGlobalEntityRenamed = function(msg)
    634691{
     
    665722    }
    666723};
    667724
    668 
    669725/**
    670726 * Eject all foreign garrisoned entities which are no more allied
    671727 */
     
    682738GarrisonHolder.prototype.EjectOrKill = function(entities)
    683739{
    684740    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    685     // Eject the units which can be ejected (if not in world, it generally means this holder
     741    // Eject the units which can be ejected (if not in world, it often means this holder
    686742    // is inside a holder which kills its entities, so do not eject)
    687743    if (cmpPosition.IsInWorld())
    688744    {
     
    705761        this.entities.splice(entityIndex, 1);
    706762        killedEntities.push(entity);
    707763    }
    708 
    709764    if (killedEntities.length > 0)
    710         Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed" : killedEntities });
     765    {
     766        let visibleEntitiesIds = {};
     767        for (let ent of killedEntities)
     768            visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent);
     769        Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
     770            "added": [],
     771            "removed": killedEntities,
     772            "visible": visibleEntitiesIds
     773        });
     774    }
    711775    this.UpdateGarrisonFlag();
    712776};
    713777
    714778/**
     779 * Gives insight about the unit type of garrisoning.
     780 * @return{bool} returns true if the unit is visible on the structure
     781 * @param {int} the entity's id
     782 */
     783GarrisonHolder.prototype.IsVisiblyGarrisoned = function(entity)
     784{
     785    return this.visibleGarrisonPoints.some(point => point.entity == entity);
     786};
     787
     788/**
    715789 * Checks if an entity is ejectable on destroy if possible
    716790 */
    717791GarrisonHolder.prototype.IsEjectable = function(entity)
  • binaries/data/mods/public/simulation/templates/structures/maur_fortress.xml

     
    55    <SpecificName>Durg</SpecificName>
    66    <Tooltip>Train heroes and champion units.</Tooltip>
    77  </Identity>
     8  <GarrisonHolder>
     9    <Max>150</Max>
     10    <List datatype="tokens">
     11      Ranged
     12      Infantry
     13      Cavalry
     14      Elephant
     15      Ranged
     16      Catapult
     17    </List>
     18    <EjectHealth>0.1</EjectHealth>
     19    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
     20    <BuffHeal>0</BuffHeal>
     21    <LoadingRange>2</LoadingRange>
     22    <VisibleGarrisonPoints>
     23      <Archer1>
     24        <X>10.5</X><Y>13.75</Y><Z>-9.5</Z>
     25        <VisibleGarrisonAllowedClasses datatype="tokens">
     26          Infantry+Ranged
     27        </VisibleGarrisonAllowedClasses>
     28      </Archer1>
     29      <Archer2>
     30        <X>-10.5</X><Y>13.75</Y><Z>9.5</Z>
     31        <VisibleGarrisonAllowedClasses datatype="tokens">
     32          Infantry+Ranged
     33        </VisibleGarrisonAllowedClasses>
     34      </Archer2>
     35      <Archer3>
     36        <X>-10.5</X><Y>13.75</Y><Z>-9.5</Z>
     37        <VisibleGarrisonAllowedClasses datatype="tokens">
     38          Infantry+Ranged
     39        </VisibleGarrisonAllowedClasses>
     40      </Archer3>
     41      <Archer4>
     42        <X>10.5</X><Y>13.75</Y><Z>9.5</Z>
     43        <VisibleGarrisonAllowedClasses datatype="tokens">
     44          Ranged+Catapult
     45        </VisibleGarrisonAllowedClasses>
     46      </Archer4>
     47    </VisibleGarrisonPoints>
     48  </GarrisonHolder>
    849  <ProductionQueue>
    950    <Entities datatype="tokens">
    1051      units/{civ}_hero_chanakya
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_long.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>8</X><Y>11.5</Y><Z>0</Z>
     26        <VisibleGarrisonAllowedClasses datatype="tokens">
     27          Infantry+Ranged
     28        </VisibleGarrisonAllowedClasses>
    2329      </Archer2>
    2430      <Archer3>
    2531        <X>-8</X><Y>11.5</Y><Z>0</Z>
     32        <VisibleGarrisonAllowedClasses datatype="tokens">
     33          Infantry+Ranged
     34        </VisibleGarrisonAllowedClasses>
    2635      </Archer3>
    2736      <Archer4>
    2837        <X>4</X><Y>11.5</Y><Z>0</Z>
     38        <VisibleGarrisonAllowedClasses datatype="tokens">
     39          Infantry+Ranged
     40        </VisibleGarrisonAllowedClasses>
    2941      </Archer4>
    3042      <Archer5>
    3143        <X>-4</X><Y>11.5</Y><Z>0</Z>
     44        <VisibleGarrisonAllowedClasses datatype="tokens">
     45          Infantry+Ranged
     46        </VisibleGarrisonAllowedClasses>
    3247      </Archer5>
    3348    </VisibleGarrisonPoints>
    3449  </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>