Ticket #2038: spawn_point.diff

File spawn_point.diff, 7.0 KB (added by sanderd17, 11 years ago)
  • binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_tower.xml

     
    3333  <Footprint replace="">
    3434    <Square width="15.0" depth="15.0"/>
    3535    <Height>20.0</Height>
     36    <SpawnPoint x='0' z='15'/>
    3637  </Footprint>
    3738  <GarrisonHolder>
    3839    <Max>20</Max>
  • binaries/data/mods/public/simulation/templates/units/hele_mechanical_siege_tower.xml

     
    44    <Civ>hele</Civ>
    55    <SpecificName>Helépolis</SpecificName>
    66    <Tooltip>Siege Tower.
    7 Garrison up to 20 units inside for massive firepower.</Tooltip>
     7Garrison up to 20 units inside for massive firepower. Stand in front of a wall and ungarrison your units over the wall.</Tooltip>
    88    <History>When Demetrius Poliorcetes besieged Salamis, in Cyprus, he instructed that a machine be constructed, which he called "the taker of cities." Its form was that of a square tower, each side 90 cubits high and 45 wide. It rested on four wheels, each eight cubits high. It was divided into nine stories, the lower of which contained machines for throwing great stones, the middle large catapults for throwing spears, and the highest, other machines for throwing smaller stones, together with smaller catapults. It was manned with 200 soldiers, besides those that moved it by pushing the parallel beams at the bottom.</History>
    99    <Icon>units/hele_mechanical_siege_tower.png</Icon>
    1010  </Identity>
  • binaries/data/mods/public/simulation/templates/units/mace_mechanical_siege_tower.xml

     
    44    <Civ>mace</Civ>
    55    <SpecificName>Helépolis</SpecificName>
    66    <Tooltip>Siege Tower.
    7 Garrison up to 20 units inside for massive firepower.</Tooltip>
     7Garrison up to 20 units inside for massive firepower. Stand in front of a wall, and ungarrison your units over the wall.</Tooltip>
    88    <History>When Demetrius Poliorcetes besieged Salamis, in Cyprus, he instructed that a machine be constructed, which he called "the taker of cities." Its form was that of a square tower, each side 90 cubits high and 45 wide. It rested on four wheels, each eight cubits high. It was divided into nine stories, the lower of which contained machines for throwing great stones, the middle large catapults for throwing spears, and the highest, other machines for throwing smaller stones, together with smaller catapults. It was manned with 200 soldiers, besides those that moved it by pushing the parallel beams at the bottom.</History>
    99    <Icon>units/hele_mechanical_siege_tower.png</Icon>
    1010  </Identity>
  • source/simulation2/components/CCmpFootprint.cpp

     
    4343    entity_pos_t m_Size1; // height/radius
    4444    entity_pos_t m_Height;
    4545
     46    CFixedVector2D m_SpawnPoint;
     47
     48    bool m_SpawnPointSet;
     49
    4650    static std::string GetSchema()
    4751    {
    4852        return
     
    7377            "</choice>"
    7478            "<element name='Height' a:help='Vertical extent of the footprint (in metres)'>"
    7579                "<ref name='nonNegativeDecimal'/>"
    76             "</element>";
     80            "</element>"
     81            "<optional>"
     82                "<element name='SpawnPoint' a:help='let units spawn to an explicit spawn position (relative to this entity)'>"
     83                    "<attribute name='x'>"
     84                        "<data type='decimal'/>"
     85                    "</attribute>"
     86                    "<attribute name='z'>"
     87                        "<data type='decimal'/>"
     88                    "</attribute>"
     89                "</element>"
     90            "</optional>";
    7791    }
    7892
    7993    virtual void Init(const CParamNode& paramNode)
     
    97111        }
    98112
    99113        m_Height = paramNode.GetChild("Height").ToFixed();
     114
     115        if (paramNode.GetChild("SpawnPoint").IsOk())
     116        {
     117            entity_pos_t startX = paramNode.GetChild("SpawnPoint").GetChild("@x").ToFixed();
     118            entity_pos_t startZ = paramNode.GetChild("SpawnPoint").GetChild("@z").ToFixed();
     119            m_SpawnPoint = CFixedVector2D(startX, startZ);
     120            m_SpawnPointSet = true;
     121        }
     122        else
     123        {
     124            m_SpawnPointSet = false;
     125        }
    100126    }
    101127
    102128    virtual void Deinit()
     
    165191        // Max spawning distance in tiles
    166192        const i32 maxSpawningDistance = 4;
    167193
     194        if (m_SpawnPointSet)
     195        {
     196            fixed s, c;
     197            sincos_approx(initialAngle, s, c);
     198
     199            CFixedVector2D v = m_SpawnPoint;
     200            v = v.Rotate(initialAngle);
     201            initialPos = initialPos + v;
     202
     203            // try initial position as a start
     204            SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
     205            if (cmpPathfinder->CheckUnitPlacement(filter, initialPos.X, initialPos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
     206                return CFixedVector3D(initialPos.X, fixed::Zero(), initialPos.Y); // this position is okay, so return it
     207
     208            // Expand outwards from initial position
     209            for (i32 dist = 0; dist <= maxSpawningDistance; ++dist)
     210            {
     211                // The spawn point should be far enough from this footprint to fit the unit, plus a little gap
     212                entity_pos_t clearance = spawnedRadius + entity_pos_t::FromInt(2 + (int)TERRAIN_TILE_SIZE*dist);
     213
     214                for (i32 edge = 0; edge < 4; ++edge)
     215                {
     216                    // Try equally-spaced points along the edge in alternating directions, starting from the middle
     217                    const i32 numPoints = 9 + 2*dist;
     218
     219                    // Compute the direction and length of the current edge
     220                    CFixedVector2D dir;
     221                    switch (edge)
     222                    {
     223                    case 0:
     224                        dir = CFixedVector2D(c, -s);
     225                        break;
     226                    case 1:
     227                        dir = CFixedVector2D(-s, -c);
     228                        break;
     229                    case 2:
     230                        dir = CFixedVector2D(s, c);
     231                        break;
     232                    case 3:
     233                        dir = CFixedVector2D(-c, s);
     234                        break;
     235                    }
     236                    CFixedVector2D center = initialPos - dir.Perpendicular().Multiply(clearance);
     237                    dir = dir.Multiply((clearance*2) / (int)(numPoints-1));
     238
     239                    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]
     240                    {
     241                        CFixedVector2D pos (center + dir*i);
     242
     243                        SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
     244                        if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
     245                            return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it
     246                    }
     247                }
     248            }
     249        }
     250       
     251        // try spawning around footprint
    168252        if (m_Shape == CIRCLE)
    169253        {
    170254            // Expand outwards from foundation