Ticket #2154: patch_townbell.8.diff

File patch_townbell.8.diff, 21.0 KB (added by Itms, 10 years ago)
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert_0.xml

     
     1<?xml version="1.0" encoding="utf-8" standalone="no" ?>
     2<SoundGroup>
     3    <Omnipresent>1</Omnipresent>
     4    <HeardBy>owner</HeardBy>
     5    <Gain>0.25</Gain>
     6    <Pitch>1</Pitch>
     7    <Priority>100</Priority>
     8    <ConeGain>1</ConeGain>
     9    <ConeInner>360</ConeInner>
     10    <ConeOuter>360</ConeOuter>
     11    <Looping>0</Looping>
     12    <RandOrder>1</RandOrder>
     13    <RandGain>1</RandGain>
     14    <GainUpper>0.25</GainUpper>
     15    <GainLower>0.2</GainLower>
     16    <RandPitch>1</RandPitch>
     17    <PitchUpper>1.1</PitchUpper>
     18    <PitchLower>0.9</PitchLower>
     19    <Threshold>1</Threshold>
     20    <Decay>3</Decay>
     21    <Replacement>alarmalert0.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalert0.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert_1.xml

     
     1<?xml version="1.0" encoding="utf-8" standalone="no" ?>
     2<SoundGroup>
     3    <Omnipresent>1</Omnipresent>
     4    <HeardBy>owner</HeardBy>
     5    <Gain>0.25</Gain>
     6    <Pitch>1</Pitch>
     7    <Priority>100</Priority>
     8    <ConeGain>1</ConeGain>
     9    <ConeInner>360</ConeInner>
     10    <ConeOuter>360</ConeOuter>
     11    <Looping>0</Looping>
     12    <RandOrder>1</RandOrder>
     13    <RandGain>1</RandGain>
     14    <GainUpper>0.25</GainUpper>
     15    <GainLower>0.2</GainLower>
     16    <RandPitch>1</RandPitch>
     17    <PitchUpper>1.1</PitchUpper>
     18    <PitchLower>0.9</PitchLower>
     19    <Threshold>1</Threshold>
     20    <Decay>3</Decay>
     21    <Replacement>alarmalert1.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalert1.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert_2.xml

     
     1<?xml version="1.0" encoding="utf-8" standalone="no" ?>
     2<SoundGroup>
     3    <Omnipresent>1</Omnipresent>
     4    <HeardBy>owner</HeardBy>
     5    <Gain>0.25</Gain>
     6    <Pitch>1</Pitch>
     7    <Priority>100</Priority>
     8    <ConeGain>1</ConeGain>
     9    <ConeInner>360</ConeInner>
     10    <ConeOuter>360</ConeOuter>
     11    <Looping>0</Looping>
     12    <RandOrder>1</RandOrder>
     13    <RandGain>1</RandGain>
     14    <GainUpper>0.25</GainUpper>
     15    <GainLower>0.2</GainLower>
     16    <RandPitch>1</RandPitch>
     17    <PitchUpper>1.1</PitchUpper>
     18    <PitchLower>0.9</PitchLower>
     19    <Threshold>1</Threshold>
     20    <Decay>3</Decay>
     21    <Replacement>alarmalert2.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalert2.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/gui/session/input.js

     
    19061906            case "back-to-work":
    19071907                backToWork();
    19081908                break;
     1909            case "increase-alert-level":
     1910                increaseAlertLevel();
     1911                break;
     1912            case "alert-end":
     1913                endOfAlert();
     1914                break;
    19091915            default:
    19101916                break;
    19111917            }
     
    21792185    Engine.PostNetworkCommand({"type": "remove-guard", "entities": entities});
    21802186}
    21812187
     2188function increaseAlertLevel()
     2189{
     2190    var raisers = g_Selection.toList().filter(function(e) {
     2191        var state = GetEntityState(e);
     2192        return (state && state.alertRaiser && state.alertRaiser.canIncreaseLevel);
     2193    });
     2194   
     2195    Engine.PostNetworkCommand({"type": "increase-alert-level", "entities": raisers});   
     2196}
     2197
     2198function endOfAlert()
     2199{
     2200    var raisers = g_Selection.toList().filter(function(e) {
     2201        var state = GetEntityState(e);
     2202        return (state && state.alertRaiser && state.alertRaiser.hasRaisedAlert);
     2203    });
     2204   
     2205    Engine.PostNetworkCommand({"type": "alert-end", "entities": raisers});
     2206}
     2207
    21822208function clearSelection()
    21832209{
    21842210    if(inputState==INPUT_BUILDING_PLACEMENT || inputState==INPUT_BUILDING_WALL_PATHING)
  • binaries/data/mods/public/gui/session/utility_functions.js

     
    320320            "icon": "remove-guard.png"
    321321        });
    322322    }
     323   
     324    if(entState.alertRaiser)
     325    {
     326        if(entState.alertRaiser.canIncreaseLevel)
     327            commands.push({
     328                    "name": "increase-alert-level",
     329                    "tooltip": "Raise the alert ! Or raise it again to protect more units.",
     330                    "icon": "bell_level1.png"
     331                });
     332       
     333        if(entState.alertRaiser.hasRaisedAlert)
     334            commands.push({
     335                    "name": "alert-end",
     336                    "tooltip": "End of alert.",
     337                    "icon": "bell_level0.png"
     338                });
     339    }
    323340
    324341    return commands;
    325342}
  • binaries/data/mods/public/simulation/components/AlertRaiser.js

     
     1function AlertRaiser() {}
     2
     3AlertRaiser.prototype.Schema = 
     4    "<element name='MaximumLevel'><data type='nonNegativeInteger'/></element>" +
     5    "<element name='Range'><data type='nonNegativeInteger'/></element>";
     6
     7AlertRaiser.prototype.Init = function()
     8{
     9    this.level = 0;
     10   
     11    // Remember the units ordered to garrison
     12    this.garrisonedUnits = [];
     13    this.walkingUnits = [];
     14};
     15
     16AlertRaiser.prototype.GetLevel = function()
     17{
     18    return this.level;
     19};
     20
     21AlertRaiser.prototype.HasRaisedAlert = function()
     22{
     23    return this.level > 0;
     24};
     25
     26AlertRaiser.prototype.CanIncreaseLevel = function()
     27{
     28    return this.template.MaximumLevel > this.level;
     29};
     30
     31AlertRaiser.prototype.SoundAlert = function()
     32{
     33    var alertString = "alert" + this.level;
     34    PlaySound(alertString, this.entity);
     35};
     36
     37AlertRaiser.prototype.IncreaseAlertLevel = function()
     38{
     39    if(!this.CanIncreaseLevel())
     40        return false;
     41   
     42    // Find units owned by this unit's player
     43    var players = [];
     44    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     45    if (cmpOwnership)
     46        players = [cmpOwnership.GetOwner()];
     47       
     48    this.level++;
     49    this.SoundAlert();
     50   
     51    // Select units to put under alert, ignoring domestic animals (NB : war dogs are not domestic)
     52    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     53    var level = this.GetLevel();
     54    var units = rangeMan.ExecuteQuery(this.entity, 0, this.template.Range, players, IID_UnitAI).filter( function(e){
     55        var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
     56        return (cmpUnitAI.ReactsToAlert(level) && !cmpUnitAI.IsDomestic());
     57        });
     58   
     59    for each(var unit in units)
     60    {
     61        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     62        cmpUnitAI.ReplaceOrder("Alert", {"raiser": this.entity, "force": true});
     63        this.walkingUnits.push(unit);
     64    }
     65   
     66    return true;
     67};
     68
     69AlertRaiser.prototype.OnUnitGarrisonedAfterAlert = function(msg)
     70{
     71    this.garrisonedUnits.push({"holder": msg.holder, "unit": msg.unit});
     72   
     73    var index = this.walkingUnits.indexOf(msg.unit);
     74    if (index != -1)
     75        this.walkingUnits.splice(index, 1);
     76   
     77}
     78
     79AlertRaiser.prototype.EndOfAlert = function()
     80{
     81    this.level = 0;
     82    this.SoundAlert();
     83   
     84    // First, handle units not yet garrisoned
     85    for each(var unit in this.walkingUnits)
     86    {
     87        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     88       
     89        cmpUnitAI.ResetAlert();
     90           
     91        if (cmpUnitAI.HasWorkOrders())
     92            cmpUnitAI.BackToWork();
     93        else
     94            cmpUnitAI.ReplaceOrder("Stop", undefined);
     95    }
     96    this.walkingUnits = [];
     97   
     98    // Then, eject garrisoned units
     99    for each(var slot in this.garrisonedUnits)
     100    {
     101        var cmpGarrisonHolder = Engine.QueryInterface(slot.holder, IID_GarrisonHolder);
     102        var cmpUnitAI = Engine.QueryInterface(slot.unit, IID_UnitAI);
     103       
     104        if(cmpGarrisonHolder && cmpGarrisonHolder.PerformEject([slot.unit], true))
     105        {
     106            cmpUnitAI.ResetAlert();             
     107            if (cmpUnitAI.HasWorkOrders())
     108                cmpUnitAI.BackToWork();
     109        }
     110    }
     111    this.garrisonedUnits = [];
     112   
     113    return true;
     114};
     115
     116Engine.RegisterComponentType(IID_AlertRaiser, "AlertRaiser", AlertRaiser);
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    247247        cmpAura.ApplyGarrisonBonus(this.entity);   
    248248
    249249    Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {});
     250   
     251    var cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
     252    if (cmpUnitAI && cmpUnitAI.GetAlertRaiser())
     253        Engine.PostMessage(cmpUnitAI.GetAlertRaiser(), MT_UnitGarrisonedAfterAlert, {"holder": this.entity, "unit": entity});
     254   
    250255    return true;
    251256};
    252257
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    375375        ret.resourceGatherRates = cmpResourceGatherer.GetGatherRates();
    376376        ret.resourceCarrying = cmpResourceGatherer.GetCarryingStatus();
    377377    }
     378   
     379    var cmpAlertRaiser = Engine.QueryInterface(ent, IID_AlertRaiser);
     380    if(cmpAlertRaiser)
     381    {
     382        ret.alertRaiser = {
     383            "level": cmpAlertRaiser.GetLevel(),
     384            "canIncreaseLevel": cmpAlertRaiser.CanIncreaseLevel(),
     385            "hasRaisedAlert": cmpAlertRaiser.HasRaisedAlert(),
     386        };
     387    }
    378388
    379389    var cmpResourceDropsite = Engine.QueryInterface(ent, IID_ResourceDropsite);
    380390    if (cmpResourceDropsite)
  • binaries/data/mods/public/simulation/components/interfaces/AlertRaiser.js

     
     1Engine.RegisterInterface("AlertRaiser");
     2 No newline at end of file
  • binaries/data/mods/public/simulation/components/interfaces/GarrisonHolder.js

     
    44// sent to the current entity whenever the garrisoned units change.
    55Engine.RegisterMessageType("GarrisonedUnitsChanged");
    66
     7// Message of the form { "holder": this.entity, "unit" : unit } sent to the AlertRaiser
     8// which ordered the unit "unit" to garrison.
     9Engine.RegisterMessageType("UnitGarrisonedAfterAlert");
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    33UnitAI.prototype.Schema =
    44    "<a:help>Controls the unit's movement, attacks, etc, in response to commands from the player.</a:help>" +
    55    "<a:example/>" +
     6    "<element name='AlertReactiveLevel'>" +
     7        "<data type='nonNegativeInteger'/>" +
     8    "</element>" +
    69    "<element name='DefaultStance'>" +
    710        "<choice>" +
    811            "<value>violent</value>" +
     
    684687        this.SetNextState("INDIVIDUAL.AUTOGARRISON");
    685688    },
    686689
     690    "Order.Alert": function(msg) {
     691        this.alertRaiser = this.order.data.raiser;
     692       
     693        // Find a target to garrison into, if we don't already have one
     694        if(!this.alertGarrisoningTarget)
     695            this.alertGarrisoningTarget = this.FindNearbyGarrisonHolder();
     696       
     697        if(this.alertGarrisoningTarget)
     698            this.ReplaceOrder("Garrison", {"target": this.alertGarrisoningTarget});
     699        else
     700            this.FinishOrder();
     701    }, 
     702   
    687703    "Order.Cheering": function(msg) {
    688704        this.SetNextState("INDIVIDUAL.CHEERING");
    689705    },
     
    25462562                },
    25472563
    25482564                "MoveCompleted": function() {
    2549                     this.SetNextState("GARRISONED");
     2565                    if(this.IsUnderAlert())
     2566                    {
     2567                        // check that we can garrison in the building we're supposed to garrison in
     2568                        var cmpGarrisonHolder = Engine.QueryInterface(this.alertGarrisoningTarget, IID_GarrisonHolder);
     2569                        if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull())
     2570                        {
     2571                            // Try to find another nearby building
     2572                            var nearby = this.FindNearbyGarrisonHolder();
     2573                            if (nearby)
     2574                            {
     2575                                this.alertGarrisoningTarget = nearby;
     2576                                if (this.MoveToTarget(this.alertGarrisoningTarget))
     2577                                    this.SetNextState("APPROACHING");
     2578                            }
     2579                            else
     2580                                this.FinishOrder();
     2581                        }
     2582                        else
     2583                            this.SetNextState("GARRISONED");
     2584                    }
     2585                    else
     2586                        this.SetNextState("GARRISONED");
    25502587                },
    25512588            },
    25522589
    25532590            "GARRISONED": {
    25542591                "enter": function() {
    2555                     var target = this.order.data.target;
     2592                    // Target is not handled the same way with Alert and direct garrisoning
     2593                    if(this.order.data.target)
     2594                        var target = this.order.data.target;
     2595                    else
     2596                    {   
     2597                        if(!this.alertGarrisoningTarget)
     2598                        {
     2599                            // We've been unable to find a target nearby, so give up
     2600                            this.FinishOrder();
     2601                            return true;
     2602                        }
     2603                        var target = this.alertGarrisoningTarget;
     2604                    }
     2605
    25562606                    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
    25572607
    25582608                    // Check that we can garrison here
     
    28772927
    28782928    this.isGuardOf = undefined;
    28792929
     2930    // "Town Bell" behaviour
     2931    this.alertRaiser = undefined;
     2932    this.alertGarrisoningTarget = undefined;
     2933
    28802934    // For preventing increased action rate due to Stop orders or target death.
    28812935    this.lastAttacked = undefined;
    28822936    this.lastHealed = undefined;
     
    28842938    this.SetStance(this.template.DefaultStance);
    28852939};
    28862940
     2941UnitAI.prototype.ReactsToAlert = function(level)
     2942{
     2943    return this.template.AlertReactiveLevel <= level;
     2944};
     2945
     2946UnitAI.prototype.IsUnderAlert = function()
     2947{
     2948    return this.alertGarrisoningTarget != undefined;
     2949};
     2950
     2951UnitAI.prototype.ResetAlert = function()
     2952{
     2953    this.alertGarrisoningTarget = undefined;
     2954};
     2955
    28872956UnitAI.prototype.IsFormationController = function()
    28882957{
    28892958    return (this.template.FormationController == "true");
     
    34823551    this.workOrders = orders;
    34833552};
    34843553
     3554UnitAI.prototype.GetAlertRaiser = function()
     3555{
     3556    return this.alertRaiser;
     3557};
     3558
    34853559UnitAI.prototype.TimerHandler = function(data, lateness)
    34863560{
    34873561    // Reset the timer
     
    36783752    var players = [];
    36793753    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    36803754    if (cmpOwnership)
    3681         players.push(cmpOwnership.GetOwner());
     3755        players = [cmpOwnership.GetOwner()];
    36823756
    36833757    // Ships are unable to reach land dropsites and shouldn't attempt to do so.
    36843758    var excludeLand = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
     
    37163790    var players = [];
    37173791    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    37183792    if (cmpOwnership)
    3719         players.push(cmpOwnership.GetOwner());
     3793        players = [cmpOwnership.GetOwner()];
    37203794
    37213795    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    37223796    var nearby = rangeMan.ExecuteQuery(this.entity, 0, range, players, IID_Foundation);
     
    37363810};
    37373811
    37383812/**
     3813 * Returns the entity ID of the nearest building in which the unit can garrison,
     3814 * or undefined if none can be found close enough.
     3815 */
     3816UnitAI.prototype.FindNearbyGarrisonHolder = function()
     3817{
     3818    var range = 128; // TODO: what's a sensible number?
     3819
     3820    // Find buildings owned by this unit's player
     3821    var players = [];
     3822    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     3823    if (cmpOwnership)
     3824        players = [cmpOwnership.GetOwner()];
     3825
     3826    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     3827    var nearby = rangeMan.ExecuteQuery(this.entity, 0, range, players, IID_GarrisonHolder);
     3828    for each (var ent in nearby)
     3829    {
     3830        var cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
     3831        // We only want to garrison in buildings, not in moving units like ships,...
     3832        var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     3833        if (!cmpUnitAI && cmpGarrisonHolder.AllowedToGarrison(this.entity) && !cmpGarrisonHolder.IsFull())
     3834            return ent;
     3835    }
     3836
     3837    return undefined;
     3838};
     3839
     3840/**
    37393841 * Play a sound appropriate to the current entity.
    37403842 */
    37413843UnitAI.prototype.PlaySound = function(name)
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    422422                notifyUnloadFailure(player, garrisonHolder)
    423423        }
    424424        break;
     425   
     426    case "increase-alert-level":
     427        for each (var raiser in entities)
     428        {
     429            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     430            if (!cmpAlertRaiser || !cmpAlertRaiser.IncreaseAlertLevel())
     431                notifyAlertFailure(player);
     432        }
     433        break;
     434   
     435    case "alert-end":
     436        for each (var raiser in entities)
     437        {
     438            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     439            if (cmpAlertRaiser)
     440                cmpAlertRaiser.EndOfAlert();
     441        }
     442        break;
    425443
    426444    case "formation":
    427445        GetFormationUnitAIs(entities, player, cmd.name).forEach(function(cmpUnitAI) {
     
    561579}
    562580
    563581/**
     582 * Sends a GUI notification about Alerts that failed to be raised
     583 */
     584function notifyAlertFailure(player)
     585{
     586    var cmpPlayer = QueryPlayerIDInterface(player, IID_Player);
     587    var notification = {"player": cmpPlayer.GetPlayerID(), "message": "You can't raise the alert to a higher level !" };
     588    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     589    cmpGUIInterface.PushNotification(notification);
     590}
     591
     592/**
    564593 * Get some information about the formations used by entities.
    565594 * The entities must have a UnitAI component.
    566595 */
  • binaries/data/mods/public/simulation/templates/special/formation.xml

     
    1414    <TurnRate>3.0</TurnRate>
    1515  </Position>
    1616  <UnitAI>
     17    <AlertReactiveLevel>2</AlertReactiveLevel>
    1718    <DefaultStance>aggressive</DefaultStance>
    1819    <FleeDistance>12.0</FleeDistance>
    1920    <FormationController>true</FormationController>
  • binaries/data/mods/public/simulation/templates/template_structure_civic_civil_centre.xml

     
    9898      <constructed>interface/complete/building/complete_civ_center.xml</constructed>
    9999      <attack>attack/weapon/arrowfly.xml</attack>
    100100      <death>attack/destruction/building_collapse_large.xml</death>
     101      <alert0>interface/alarm/alarm_alert_0.xml</alert0>
     102      <alert1>interface/alarm/alarm_alert_1.xml</alert1>
     103      <alert2>interface/alarm/alarm_alert_2.xml</alert2>
    101104    </SoundGroups>
    102105  </Sound>
    103106  <TerritoryInfluence>
     
    105108    <Radius>140</Radius>
    106109    <Weight>65536</Weight>
    107110  </TerritoryInfluence>
     111  <AlertRaiser>
     112    <MaximumLevel>2</MaximumLevel>
     113    <Range>140</Range>
     114  </AlertRaiser>
    108115  <Vision>
    109116    <Range>90</Range>
    110117  </Vision>
  • binaries/data/mods/public/simulation/templates/template_unit.xml

     
    9999    <HeightOffset>5.0</HeightOffset>
    100100  </StatusBars>
    101101  <UnitAI>
     102    <AlertReactiveLevel>2</AlertReactiveLevel>
    102103    <DefaultStance>aggressive</DefaultStance>
    103104    <FleeDistance>12.0</FleeDistance>
    104105    <FormationController>false</FormationController>
  • binaries/data/mods/public/simulation/templates/template_unit_support_female_citizen.xml

     
    9595  <Stamina>
    9696    <Max>500</Max>
    9797  </Stamina>
     98  <UnitAI>
     99    <AlertReactiveLevel>1</AlertReactiveLevel>
     100  </UnitAI>
    98101  <UnitMotion>
    99102    <WalkSpeed>8.0</WalkSpeed>
    100103    <Run>