Ticket #2242: swimmer-v2.diff

File swimmer-v2.diff, 29.6 KB (added by mimo, 10 years ago)

with EjectEntitiesOnDestroy removed and replaced by the new tag

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

     
    1313    "<element name='EjectHealth' a:help='Percentage of maximum health below which this holder no longer allows garrisoning'>" +
    1414        "<ref name='nonNegativeDecimal'/>" +
    1515    "</element>" +
    16     "<element name='EjectEntitiesOnDestroy' a:help='Whether the entity should eject or kill all garrisoned entities on destroy'>" +
    17         "<data type='boolean'/>" +
     16    "<element name='EjectClassesOnDestroy' a:help='Classes of entities to be ejected on destroy. Others are killed'>" +
     17        "<attribute name='datatype'>" +
     18            "<value>tokens</value>" +
     19        "</attribute>" +
     20        "<text/>" +
    1821    "</element>" +
    1922    "<element name='BuffHeal' a:help='Number of hit points that will be restored to this holder&apos;s garrisoned units each second'>" +
    2023        "<ref name='nonNegativeDecimal'/>" +
     
    105108    return ApplyValueModificationsToEntity("GarrisonHolder/BuffHeal", +this.template.BuffHeal, this.entity);
    106109};
    107110
    108 GarrisonHolder.prototype.EjectEntitiesOnDestroy = function()
    109 {
    110     return this.template.EjectEntitiesOnDestroy == "true";
    111 };
    112 
    113111/**
    114112 * Set this entity to allow or disallow garrisoning in
    115113 * Every component calling this function should do it with its own ID, and as long as one
     
    270268   
    271269    // Find spawning location
    272270    var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
    273     var pos = cmpFootprint.PickSpawnPoint(entity);
     271    var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
     272    var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     273    // If the garrisonHolder is a sinking ship, restrict the location to the intersection of both passabilities
     274    // TODO: should use passability classes to be more generic
     275    if ((!cmpHealth || cmpHealth.GetHitpoints() == 0) && cmpIdentity && cmpIdentity.HasClass("Ship"))
     276        var pos = cmpFootprint.PickSpawnPointBothPass(entity);
     277    else
     278        var pos = cmpFootprint.PickSpawnPoint(entity);
     279
    274280    if (pos.y < 0)
    275281    {
    276282        // Error: couldn't find space satisfying the unit's passability criteria
     
    602608    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    603609    // Eject the units which can be ejected (if not in world, it generally means this holder
    604610    // is inside a holder which kills its entities, so do not eject)
    605     if (cmpPosition.IsInWorld() && this.EjectEntitiesOnDestroy())
    606         this.PerformEject(entities, true);
     611    if (cmpPosition.IsInWorld())
     612    {
     613        var cmpGarrisonHolder = this;
     614        var ejectables = entities.filter(function(ent) { return cmpGarrisonHolder.IsEjectable(ent) });
     615        if (ejectables.length)
     616            this.PerformEject(ejectables, false);
     617    }
    607618
    608619    // And destroy all remaining entities
    609620    for each (var entity in entities)
     
    621632    this.UpdateGarrisonFlag();
    622633};
    623634
     635/**
     636 * Checks if an entity is ejectable on destroy if possible
     637 */
     638GarrisonHolder.prototype.IsEjectable = function(entity)
     639{
     640    var ejectableClasses = this.template.EjectClassesOnDestroy._string;
     641    ejectableClasses = ejectableClasses ? ejectableClasses.split(/\s+/) : [];
     642    var entityClasses = (Engine.QueryInterface(entity, IID_Identity)).GetClassesList();
     643    for each (var ejectableClass in ejectableClasses)
     644        if (entityClasses.indexOf(ejectableClass) != -1)
     645            return true;
     646
     647    return false;
     648};
     649
    624650Engine.RegisterComponentType(IID_GarrisonHolder, "GarrisonHolder", GarrisonHolder);
    625651
  • binaries/data/mods/public/simulation/templates/other/plane.xml

     
    2424    <List datatype="tokens">Support Infantry</List>
    2525    <BuffHeal>1</BuffHeal>
    2626    <LoadingRange>5</LoadingRange>
    27     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     27    <EjectClassesOnDestroy datatype="tokens" />
    2828  </GarrisonHolder>
    2929  <Decay>
    3030    <Inactive/>
  • binaries/data/mods/public/simulation/templates/structures/athen_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/cart_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/hele_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/mace_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/ptol_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/rome_tent.xml

     
    1616  <GarrisonHolder>
    1717    <Max>5</Max>
    1818    <EjectHealth>0.1</EjectHealth>
    19     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     19    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    2020    <List datatype="tokens">Support Infantry</List>
    2121    <BuffHeal>0</BuffHeal>
    2222    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/rome_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/structures/spart_wonder.xml

     
    77  <GarrisonHolder>
    88    <Max>30</Max>
    99    <EjectHealth>0.1</EjectHealth>
    10     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     10    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1111    <List datatype="tokens">Support Infantry Cavalry</List>
    1212    <BuffHeal>3</BuffHeal>
    1313    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml

     
    4949  <GarrisonHolder>
    5050    <Max>20</Max>
    5151    <EjectHealth>0.1</EjectHealth>
    52     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     52    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    5353    <List datatype="tokens">Support Infantry Cavalry</List>
    5454    <BuffHeal>1</BuffHeal>
    5555    <LoadingRange>1</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_house.xml

     
    1818    <Max>3</Max>
    1919    <BuffHeal>0</BuffHeal>
    2020    <EjectHealth>0.1</EjectHealth>
    21     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     21    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    2222    <List datatype="tokens">Support</List>
    2323    <LoadingRange>1</LoadingRange>
    2424  </GarrisonHolder>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_temple.xml

     
    2323  <GarrisonHolder>
    2424    <Max>20</Max>
    2525    <EjectHealth>0.1</EjectHealth>
    26     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     26    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    2727    <List datatype="tokens">Support Infantry Cavalry</List>
    2828    <BuffHeal>3</BuffHeal>
    2929    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_defense_tower.xml

     
    4646  <GarrisonHolder>
    4747    <Max>5</Max>
    4848    <EjectHealth>0.1</EjectHealth>
    49     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     49    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    5050    <List datatype="tokens">Support Infantry</List>
    5151    <BuffHeal>0</BuffHeal>
    5252    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_outpost.xml

     
    4444  <GarrisonHolder>
    4545    <Max>1</Max>
    4646    <EjectHealth>0.1</EjectHealth>
    47     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     47    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    4848    <List datatype="tokens">Support Infantry</List>
    4949    <BuffHeal>0</BuffHeal>
    5050    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_defense_wall_tower.xml

     
    4141  <GarrisonHolder>
    4242    <Max>5</Max>
    4343    <EjectHealth>0.1</EjectHealth>
    44     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     44    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    4545    <List datatype="tokens">Support Infantry</List>
    4646    <BuffHeal>0</BuffHeal>
    4747    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_military_barracks.xml

     
    1616  <GarrisonHolder>
    1717    <Max>10</Max>
    1818    <EjectHealth>0.1</EjectHealth>
    19     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     19    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    2020    <List datatype="tokens">Infantry Cavalry</List>
    2121    <BuffHeal>0</BuffHeal>
    2222    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_military_blacksmith.xml

     
    1616  <GarrisonHolder>
    1717    <Max>1</Max>
    1818    <EjectHealth>0.1</EjectHealth>
    19     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     19    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    2020    <List datatype="tokens">Infantry</List>
    2121    <BuffHeal>0</BuffHeal>
    2222    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_military_fortress.xml

     
    4646  <GarrisonHolder>
    4747    <Max>20</Max>
    4848    <EjectHealth>0.075</EjectHealth>
    49     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     49    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    5050    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    5151    <BuffHeal>0</BuffHeal>
    5252    <LoadingRange>6</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_resource_corral.xml

     
    1313  <GarrisonHolder>
    1414    <Max>10</Max>
    1515    <EjectHealth>0.1</EjectHealth>
    16     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     16    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    1717    <List datatype="tokens">Animal</List>
    1818    <BuffHeal>1</BuffHeal>
    1919    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_structure_special.xml

     
    2929  <GarrisonHolder>
    3030    <Max>5</Max>
    3131    <EjectHealth>0.1</EjectHealth>
    32     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     32    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    3333    <List datatype="tokens">Support Infantry Cavalry</List>
    3434    <BuffHeal>1</BuffHeal>
    3535    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_bireme.xml

     
    3333  <GarrisonHolder>
    3434    <Max>20</Max>
    3535    <EjectHealth>0</EjectHealth>
    36     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     36    <EjectClassesOnDestroy datatype="tokens">Female Infantry</EjectClassesOnDestroy>
    3737    <List datatype="tokens">Support Infantry Cavalry</List>
    3838    <BuffHeal>1</BuffHeal>
    3939    <LoadingRange>10</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_fishing.xml

     
    2222  <GarrisonHolder>
    2323    <Max>1</Max>
    2424    <EjectHealth>0</EjectHealth>
    25     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     25    <EjectClassesOnDestroy datatype="tokens">Female Infantry</EjectClassesOnDestroy>
    2626    <List datatype="tokens">Support Infantry</List>
    2727    <BuffHeal>1</BuffHeal>
    2828    <LoadingRange>10</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_merchant.xml

     
    1414  <GarrisonHolder>
    1515    <Max>15</Max>
    1616    <EjectHealth>0</EjectHealth>
    17     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     17    <EjectClassesOnDestroy datatype="tokens">Female Infantry</EjectClassesOnDestroy>
    1818    <List datatype="tokens">Support Infantry Cavalry</List>
    1919    <BuffHeal>1</BuffHeal>
    2020    <LoadingRange>10</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_quinquereme.xml

     
    4141  <GarrisonHolder>
    4242    <Max>50</Max>
    4343    <EjectHealth>0</EjectHealth>
    44     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     44    <EjectClassesOnDestroy datatype="tokens">Female Infantry</EjectClassesOnDestroy>
    4545    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    4646    <BuffHeal>1</BuffHeal>
    4747    <LoadingRange>10</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_ship_trireme.xml

     
    3333  <GarrisonHolder>
    3434    <Max>30</Max>
    3535    <EjectHealth>0</EjectHealth>
    36     <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     36    <EjectClassesOnDestroy datatype="tokens">Female Infantry</EjectClassesOnDestroy>
    3737    <List datatype="tokens">Support Infantry Cavalry Siege</List>
    3838    <BuffHeal>1</BuffHeal>
    3939    <LoadingRange>10</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_ram.xml

     
    4848  <GarrisonHolder>
    4949    <Max>5</Max>
    5050    <EjectHealth>0.1</EjectHealth>
    51     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     51    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    5252    <List datatype="tokens">Support Infantry</List>
    5353    <BuffHeal>1</BuffHeal>
    5454    <LoadingRange>2</LoadingRange>
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml

     
    4646  <GarrisonHolder>
    4747    <Max>20</Max>
    4848    <EjectHealth>0.1</EjectHealth>
    49     <EjectEntitiesOnDestroy>true</EjectEntitiesOnDestroy>
     49    <EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
    5050    <List datatype="tokens">Support Infantry</List>
    5151    <BuffHeal>0</BuffHeal>
    5252    <LoadingRange>2</LoadingRange>
  • source/simulation2/components/CCmpFootprint.cpp

     
    158158        CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
    159159        if (!cmpPathfinder)
    160160            return error;
    161        
     161
    162162        CFixedVector2D initialPos = cmpPosition->GetPosition2D();
    163163        entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
    164164
     
    250250
    251251        return error;
    252252    }
     253
     254    virtual CFixedVector3D PickSpawnPointBothPass(entity_id_t spawned)
     255    {
     256        // Try to find a free space inside and around this footprint
     257        // at the intersection between the footprint passability and the unit passability.
     258        // (useful for example for destroyed ships where the spawning point should be in the intersection
     259        // of the unit and ship passabilities).
     260        // As the overlap between these passabilities regions may be narrow, we need a small step (1 meter)
     261
     262        const CFixedVector3D error(fixed::FromInt(-1), fixed::FromInt(-1), fixed::FromInt(-1));
     263
     264        CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
     265        if (!cmpPosition || !cmpPosition->IsInWorld())
     266            return error;
     267
     268        CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
     269        if (!cmpObstructionManager)
     270            return error;
     271
     272        entity_pos_t spawnedRadius;
     273        ICmpObstructionManager::tag_t spawnedTag;
     274
     275        CmpPtr<ICmpObstruction> cmpSpawnedObstruction(GetSimContext(), spawned);
     276        if (cmpSpawnedObstruction)
     277        {
     278            spawnedRadius = cmpSpawnedObstruction->GetUnitRadius();
     279            spawnedTag = cmpSpawnedObstruction->GetObstruction();
     280        }
     281        // else use zero radius
     282
     283        // Get passability class from UnitMotion
     284        CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), spawned);
     285        if (!cmpUnitMotion)
     286            return error;
     287
     288        ICmpPathfinder::pass_class_t spawnedPass = cmpUnitMotion->GetPassabilityClass();
     289        CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
     290        if (!cmpPathfinder)
     291            return error;
     292
     293        // Get the Footprint entity passability
     294        CmpPtr<ICmpUnitMotion> cmpEntityMotion(GetEntityHandle());
     295        if (!cmpEntityMotion)
     296            return error;
     297        ICmpPathfinder::pass_class_t entityPass = cmpEntityMotion->GetPassabilityClass();
     298       
     299        CFixedVector2D initialPos = cmpPosition->GetPosition2D();
     300        entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
     301
     302        // Max spawning distance + 1 (in meters)
     303        const i32 maxSpawningDistance = 13;
     304
     305        if (m_Shape == CIRCLE)
     306        {
     307            // Expand outwards from foundation with a fixed step of 1 meter
     308            for (i32 dist = 0; dist <= maxSpawningDistance; ++dist)
     309            {
     310                // The spawn point should be far enough from this footprint to fit the unit, plus a little gap
     311                entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(1+dist);
     312                entity_pos_t radius = m_Size0 + clearance;
     313
     314                // Try equally-spaced points around the circle in alternating directions, starting from the front
     315                const i32 numPoints = 31 + 2*dist;
     316                for (i32 i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2]
     317                {
     318                    entity_angle_t angle = initialAngle + (entity_angle_t::Pi()*2).Multiply(entity_angle_t::FromInt(i)/(int)numPoints);
     319
     320                    fixed s, c;
     321                    sincos_approx(angle, s, c);
     322
     323                    CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius));
     324
     325                    SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
     326                    if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS &&
     327                        cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, entityPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
     328                        return pos; // this position is okay, so return it
     329                }
     330            }
     331        }
     332        else
     333        {
     334            fixed s, c;
     335            sincos_approx(initialAngle, s, c);
     336
     337            // Expand outwards from foundation with a fixed step of 1 meter
     338            for (i32 dist = 0; dist <= maxSpawningDistance; ++dist)
     339            {
     340                // The spawn point should be far enough from this footprint to fit the unit, plus a little gap
     341                entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(1+dist);
     342
     343                for (i32 edge = 0; edge < 4; ++edge)
     344                {
     345                    // Compute the direction and length of the current edge
     346                    CFixedVector2D dir;
     347                    fixed sx, sy;
     348                    switch (edge)
     349                    {
     350                    case 0:
     351                        dir = CFixedVector2D(c, -s);
     352                        sx = m_Size0;
     353                        sy = m_Size1;
     354                        break;
     355                    case 1:
     356                        dir = CFixedVector2D(-s, -c);
     357                        sx = m_Size1;
     358                        sy = m_Size0;
     359                        break;
     360                    case 2:
     361                        dir = CFixedVector2D(s, c);
     362                        sx = m_Size1;
     363                        sy = m_Size0;
     364                        break;
     365                    case 3:
     366                        dir = CFixedVector2D(-c, s);
     367                        sx = m_Size0;
     368                        sy = m_Size1;
     369                        break;
     370                    }
     371                    sx = sx/2 + clearance;
     372                    sy = sy/2 + clearance;
     373                    // Try equally-spaced (1 meter) points along the edge in alternating directions, starting from the middle
     374                    i32 numPoints = 1 + 2*sx.ToInt_RoundToNearest();
     375                    CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(sy);
     376                    for (i32 i = 0; i < (numPoints+1)/2; i = (i > 0 ? -i : 1-i)) // [0, +1, -1, +2, -2, ... (np-1)/2, -(np-1)/2]
     377                    {
     378                        CFixedVector2D pos (center + dir*i);
     379
     380                        SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
     381                        if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS &&
     382                            cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, entityPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
     383                                return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it
     384                    }
     385                }
     386            }
     387        }
     388
     389        return error;
     390    }
    253391};
    254392
    255393REGISTER_COMPONENT_TYPE(Footprint)
  • source/simulation2/components/ICmpFootprint.cpp

     
    6262
    6363BEGIN_INTERFACE_WRAPPER(Footprint)
    6464DEFINE_INTERFACE_METHOD_1("PickSpawnPoint", CFixedVector3D, ICmpFootprint, PickSpawnPoint, entity_id_t)
     65DEFINE_INTERFACE_METHOD_1("PickSpawnPointBothPass", CFixedVector3D, ICmpFootprint, PickSpawnPointBothPass, entity_id_t)
    6566DEFINE_INTERFACE_METHOD_0("GetShape", CScriptVal, ICmpFootprint, GetShape_wrapper)
    6667END_INTERFACE_WRAPPER(Footprint)
  • source/simulation2/components/ICmpFootprint.h

     
    6464     */
    6565    virtual CFixedVector3D PickSpawnPoint(entity_id_t spawned) = 0;
    6666
     67    /**
     68     * Pick a sensible position to place a newly-spawned entity near this footprint,
     69     * at the intersection between the footprint passability and the entity one.
     70     * @return the X and Z coordinates of the spawn point, with Y = 0; or the special value (-1, -1, -1) if there's no space
     71     */
     72    virtual CFixedVector3D PickSpawnPointBothPass(entity_id_t spawned) = 0;
     73
    6774    DECLARE_INTERFACE_TYPE(Footprint)
    6875};
    6976