Ticket #2067: mustang.patch

File mustang.patch, 12.5 KB (added by scythetwirler, 11 years ago)
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    3232    this.entities = [];
    3333    this.spaceOccupied = 0;
    3434    this.timer = undefined;
     35    this.allowGarrisoning = {};
    3536};
    3637
    3738/**
     
    8586}
    8687
    8788/**
     89 * Set this entity to allow or disallow garrisoning in
     90 * Every component calling this function should do it with its own ID, and as long as one
     91 * component doesn't allow this entity to garrison, it can't be garrisoned
     92 * When this entity already contains garrisoned soldiers,
     93 * these will not be able to ungarrison until the flag is set to true again.
     94 *
     95 * This more usefull in modern-day features. Like you can't garrison in or ungarrison out
     96 * of a driving vehicle or plane.
     97 */
     98GarrisonHolder.prototype.AllowGarrisoning = function(allow, callerID)
     99{
     100    this.allowGarrisoning[callerID] = allow;
     101}
     102
     103/**
     104 * Check if no component of this entity blocks garrisoning
     105 * (f.e. because the vehicle is moving too fast)
     106 */
     107GarrisonHolder.prototype.IsGarrisoningAllowed = function()
     108{
     109    var allow = true;
     110    for each (var b in this.allowGarrisoning)
     111        allow = allow && b;
     112    return allow;
     113}
     114
     115/**
    88116 * Get number of garrisoned units capable of shooting arrows
    89117 * Not necessarily archers
    90118 */
     
    107135 */
    108136GarrisonHolder.prototype.AllowedToGarrison = function(entity)
    109137{
     138    if (!this.IsGarrisoningAllowed())
     139        return false;
     140
    110141    var allowedClasses = this.GetAllowedClassesList();
    111142    var entityClasses = (Engine.QueryInterface(entity, IID_Identity)).GetClassesList();
    112143    // Check if the unit is allowed to be garrisoned inside the building
     
    167198 */
    168199GarrisonHolder.prototype.Eject = function(entity, forced)
    169200{
     201
    170202    var entityIndex = this.entities.indexOf(entity);
     203    // Error: invalid entity ID, usually it's already been ejected
    171204    if (entityIndex == -1)
    172     {   // Error: invalid entity ID, usually it's already been ejected
    173205        return false; // Fail
    174     }
    175206   
    176207    // Find spawning location
    177208    var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
     
    237268 */
    238269GarrisonHolder.prototype.PerformEject = function(entities, forced)
    239270{
     271    if (!this.IsGarrisoningAllowed() && !forced)
     272        return false
    240273    var ejectedEntities = [];
    241274    var success = true;
    242275    for each (var entity in entities)
  • binaries/data/mods/public/simulation/components/UnitMotionFlying.js

     
    11// (A serious implementation of this might want to use C++ instead of JS
    22// for performance; this is just for fun.)
    3 const shortFinal = 2.5;
     3const SHORT_FINAL = 2.5;
    44function UnitMotionFlying() {}
    55
    66UnitMotionFlying.prototype.Schema =
     
    3333    "</element>" +
    3434    "<element name='ClimbRate'>" +
    3535        "<ref name='nonNegativeDecimal'/>" +
     36    "</element>" +
     37    "<element name='DiesInWater'>" +
     38        "<data type='boolean'/>" +
    3639    "</element>";
    3740
    3841UnitMotionFlying.prototype.Init = function()
     
    4649    this.speed = 0;
    4750    this.landing = false;
    4851    this.onGround = true;
     52    this.pitch = 0;
     53    this.roll = 0;
     54    this.waterDeath = false;
    4955};
    5056
    5157UnitMotionFlying.prototype.OnUpdate = function(msg)
    5258{
    5359    var turnLength = msg.turnLength;
    54 
    5560    if (!this.hasTarget)
    5661        return;
    57 
     62    var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
     63    var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
    5864    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    5965    var pos = cmpPosition.GetPosition();
    60     var angle = cmpPosition.GetRotation().y;
    61 
     66    var angle = cmpPosition.GetRotation().y;   
     67    var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     68    var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
     69    var ground = Math.max(cmpTerrain.GetGroundLevel(pos.x, pos.z), cmpWaterManager.GetWaterLevel(pos.x, pos.z));
     70    var newangle = angle;
    6271    var canTurn = true;
    63 
    64     if (!this.landing)
     72    if (this.landing)
    6573    {
    66         // If we haven't reached max speed yet then we're still on the ground;
    67         // otherwise we're taking off or flying
    68         // this.onGround in case of a go-around after landing (but not fully stopped)
    69         var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    70         var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
    71         if (this.speed < this.template.TakeoffSpeed && this.onGround)
    72         {
    73             // Accelerate forwards
    74             this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
    75             canTurn = false;
    76             // Clamp to ground if below it, or descend if above
    77             if (pos.y < ground)
    78                 pos.y = ground;
    79             else if (pos.y > ground)
    80                 pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
    81         }
    82         else
    83         {
    84             this.onGround = false;
    85             // Climb/sink to max height above ground
    86             this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
    87             var targetHeight = ground + (+this.template.FlyingHeight);
    88             if (pos.y < targetHeight)
    89                 pos.y = Math.min(targetHeight, pos.y + turnLength * this.template.ClimbRate);
    90             else if (pos.y > targetHeight)
    91                 pos.y = Math.max(targetHeight, pos.y - turnLength * this.template.ClimbRate);           
    92         }
    93         cmpPosition.SetHeightFixed(pos.y);
    94     }
    95     else
    96     {
    9774        if (this.speed > 0 && this.onGround)
    98         {
     75        {           
     76            this.pitch = 0;
    9977            // Deaccelerate forwards...at a very reduced pace.
    100             this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate);
     78            if (this.waterDeath)
     79                this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate * 10);
     80            else
     81                this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate);
    10182            canTurn = false;
    102             // Clamp to ground if below it, or descend if above
    103             var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    104             var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
     83            // Clamp to ground if below it, or descend if above         
    10584            if (pos.y < ground)
    10685                pos.y = ground;
    10786            else if (pos.y > ground)
    108                 pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
    109             cmpPosition.SetHeightFixed(pos.y);         
     87                pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
    11088        }
    111         else if (this.speed == 0)
     89        else if (this.speed == 0 && this.onGround)
    11290        {
     91            if (this.waterDeath)
     92                cmpHealth.Kill();
     93            this.pitch = 0;
    11394            // We've stopped.
     95            cmpGarrisonHolder.AllowGarrisoning(true,"UnitMotionFlying")
    11496            canTurn = false;
    11597            this.hasTarget = false;
    11698            this.landing = false;                   
     
    120102            // Final Approach
    121103            // We need to slow down to land!
    122104            this.speed = Math.max(this.template.LandingSpeed, this.speed - turnLength * this.template.SlowingRate);
    123             canTurn = false;
    124             var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    125             var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
     105            canTurn = false;           
    126106            var targetHeight = ground;
    127107            // Steep, then gradual descent.
    128             var descentRate = ((pos.y - targetHeight) / this.template.FlyingHeight * this.template.ClimbRate + shortFinal) * shortFinal;
     108            if ((pos.y - targetHeight) / this.template.FlyingHeight > 1 / SHORT_FINAL)
     109                this.pitch = - Math.PI / 18;
     110            else
     111                this.pitch = Math.PI / 18;
     112            var descentRate = ((pos.y - targetHeight) / this.template.FlyingHeight * this.template.ClimbRate + SHORT_FINAL) * SHORT_FINAL;
    129113            if (pos.y < targetHeight)
    130114                pos.y = Math.max(targetHeight, pos.y + turnLength * descentRate);
    131115            else if (pos.y > targetHeight)
    132116                pos.y = Math.max(targetHeight, pos.y - turnLength * descentRate);
    133117            if (targetHeight == pos.y)
    134                 this.onGround = true;
    135             cmpPosition.SetHeightFixed(pos.y);
     118            {
     119                this.onGround = true;   
     120                if (targetHeight == cmpWaterManager.GetWaterLevel(pos.x, pos.z) && this.template.DiesInWater)
     121                    this.waterDeath = true;             
     122            }
    136123        }       
    137124    }
     125    else
     126    {
     127        // If we haven't reached max speed yet then we're still on the ground;
     128        // otherwise we're taking off or flying
     129        // this.onGround in case of a go-around after landing (but not fully stopped)
    138130
     131        if (this.speed < this.template.TakeoffSpeed && this.onGround)
     132        {
     133            cmpGarrisonHolder.AllowGarrisoning(false,"UnitMotionFlying")   
     134            this.pitch = 0;
     135            // Accelerate forwards
     136            this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
     137            canTurn = false;
     138            // Clamp to ground if below it, or descend if above
     139            if (pos.y < ground)
     140                pos.y = ground;
     141            else if (pos.y > ground)
     142                pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
     143        }
     144        else
     145        {
     146            this.onGround = false;
     147            // Climb/sink to max height above ground
     148            this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
     149            var targetHeight = ground + (+this.template.FlyingHeight);
     150            if (Math.abs(pos.y-targetHeight) > this.template.FlyingHeight/5)
     151            {
     152                this.pitch = Math.PI / 9;
     153                canTurn = false;
     154            }
     155            else
     156                this.pitch = 0;
     157            if (pos.y < targetHeight)
     158                pos.y = Math.min(targetHeight, pos.y + turnLength * this.template.ClimbRate);
     159            else if (pos.y > targetHeight)
     160            {
     161                pos.y = Math.max(targetHeight, pos.y - turnLength * this.template.ClimbRate);   
     162                this.pitch = -1 * this.pitch;
     163            }           
     164        }
     165    }
     166   
    139167    // If we're in range of the target then tell people that we've reached it
    140168    // (TODO: quantisation breaks this)
    141169    var distFromTarget = Math.sqrt(Math.pow(this.targetX - pos.x, 2) + Math.pow(this.targetZ - pos.z, 2));
     
    165193        var deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate * turnLength), this.template.TurnRate * turnLength);
    166194        // Calculate new orientation, in a peculiar way in order to make sure the
    167195        // result gets close to targetAngle (rather than being n*2*pi out)
    168         angle = targetAngle + deltaClamped - delta;
     196        newangle = targetAngle + deltaClamped - delta;
     197        if (newangle - angle > Math.PI / 18)
     198            this.roll = Math.PI / 9;
     199        else if (newangle - angle < -Math.PI / 18)
     200            this.roll = - Math.PI / 9;
     201        else
     202            this.roll = newangle - angle;
    169203    }
     204    else
     205        this.roll = 0;
    170206
    171207    pos.x += this.speed * turnLength * Math.sin(angle);
    172208    pos.z += this.speed * turnLength * Math.cos(angle);
    173 
    174     cmpPosition.TurnTo(angle);
     209    cmpPosition.SetHeightFixed(pos.y);
     210    cmpPosition.TurnTo(newangle);
     211    cmpPosition.SetXZRotation(this.pitch, this.roll);
    175212    cmpPosition.MoveTo(pos.x, pos.z);
    176213};
    177214
     
    251288UnitMotionFlying.prototype.StopMoving = function()
    252289{
    253290    //Invert
    254     this.landing = !this.landing;
     291    if (!this.waterDeath)
     292        this.landing = !this.landing;
     293
    255294};
    256295
    257296UnitMotionFlying.prototype.SetDebugOverlay = function(enabled)
  • binaries/data/mods/public/simulation/templates/other/plane.xml

     
    1313      <Spread>1.5</Spread>
    1414    </Ranged>
    1515  </Attack>
     16  <BuildingAI>
     17    <DefaultArrowCount>3</DefaultArrowCount>
     18    <GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
     19    <GarrisonArrowClasses>Infantry</GarrisonArrowClasses>
     20  </BuildingAI>
     21  <GarrisonHolder>
     22    <Max>1</Max>
     23    <EjectHealth>0</EjectHealth>
     24    <List datatype="tokens">Support Infantry</List>
     25    <BuffHeal>1</BuffHeal>
     26    <LoadingRange>5</LoadingRange>
     27    <EjectEntitiesOnDestroy>false</EjectEntitiesOnDestroy>
     28  </GarrisonHolder>
     29  <Decay>
     30    <Inactive/>
     31    <SinkingAnim/>
     32    <DelayTime>0.0</DelayTime>
     33    <SinkRate>3.0</SinkRate>
     34    <SinkAccel>7.0</SinkAccel>
     35  </Decay>
    1636  <Identity>
    1737    <Civ>hele</Civ>
    1838    <SpecificName>P-51 Mustang</SpecificName>
     
    2141    <Icon>units/global_mustang.png</Icon>
    2242    <Formations datatype="tokens" replace=""/>
    2343  </Identity>
     44  <Health>
     45     <Max>100</Max>
     46    <Unhealable>true</Unhealable>
     47    <Repairable>true</Repairable>
     48  </Health>
    2449  <Obstruction disable=""/>
    2550  <Position>
    2651    <TurnRate>1.0</TurnRate>
     52    <Floating>true</Floating>
    2753  </Position>
    2854  <UnitMotion disable=""/>
    2955  <UnitMotionFlying>
     
    3662    <TurnRate>1.0</TurnRate>
    3763    <OvershootTime>2.0</OvershootTime>
    3864    <FlyingHeight>50.0</FlyingHeight>
    39     <ClimbRate>5.0</ClimbRate>
     65    <ClimbRate>15.0</ClimbRate>
     66    <DiesInWater>true</DiesInWater>
    4067  </UnitMotionFlying>
    4168  <Vision>
    4269    <Range>100</Range>