Ticket #2154: patch_townbell.5.diff

File patch_townbell.5.diff, 21.2 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

     
    18441844            case "back-to-work":
    18451845                backToWork();
    18461846                break;
     1847            case "increase-alert-level":
     1848                increaseAlertLevel();
     1849                break;
     1850            case "alert-end":
     1851                endOfAlert();
     1852                break;
    18471853            default:
    18481854                break;
    18491855            }
     
    21062112   
    21072113}
    21082114
     2115function increaseAlertLevel()
     2116{
     2117    var raisers = g_Selection.toList().filter(function(e) {
     2118        var state = GetEntityState(e);
     2119        return (state && state.alertRaiser && state.alertRaiser.canIncreaseLevel);
     2120    });
     2121   
     2122    Engine.PostNetworkCommand({"type": "increase-alert-level", "entities": raisers});   
     2123}
     2124
     2125function endOfAlert()
     2126{
     2127    var raisers = g_Selection.toList().filter(function(e) {
     2128        var state = GetEntityState(e);
     2129        return (state && state.alertRaiser && state.alertRaiser.hasRaisedAlert);
     2130    });
     2131   
     2132    Engine.PostNetworkCommand({"type": "alert-end", "entities": raisers});
     2133}
     2134
    21092135function clearSelection()
    21102136{
    21112137    if(inputState==INPUT_BUILDING_PLACEMENT || inputState==INPUT_BUILDING_WALL_PATHING)
  • binaries/data/mods/public/gui/session/utility_functions.js

     
    302302            "icon": "production.png"
    303303        });
    304304    }
     305   
     306    if(entState.alertRaiser)
     307    {
     308        if(entState.alertRaiser.canIncreaseLevel)
     309            commands.push({
     310                    "name": "increase-alert-level",
     311                    "tooltip": "Raise the alert ! Or raise it again to protect more units.",
     312                    "icon": "bell_level1.png"
     313                });
     314       
     315        if(entState.alertRaiser.hasRaisedAlert)
     316            commands.push({
     317                    "name": "alert-end",
     318                    "tooltip": "End of alert.",
     319                    "icon": "bell_level0.png"
     320                });
     321    }
    305322
    306323    return commands;
    307324}
  • 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
     52    // If an alert has already been raised, only give orders to the units who don't already have orders.
     53    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     54    var level = this.GetLevel();
     55    var units = rangeMan.ExecuteQuery(this.entity, 0, this.template.Range, players, IID_UnitAI).filter( function(e){
     56        var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
     57        return (!cmpUnitAI.IsUnderAlert() && !cmpUnitAI.IsDomestic() && cmpUnitAI.ReactsToAlert(level));
     58        });
     59   
     60    for each(unit in units)
     61    {
     62        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     63        cmpUnitAI.ReplaceOrder("Alert", {"raiser": this.entity, "force": true});
     64        this.walkingUnits.push(unit);
     65    }
     66   
     67    return true;
     68};
     69
     70AlertRaiser.prototype.OnUnitGarrisonedAfterAlert = function(msg)
     71{
     72    this.garrisonedUnits.push({"holder": msg.holder, "unit": msg.unit});
     73   
     74    var index = this.walkingUnits.indexOf(msg.unit);
     75    if (index != -1)
     76        this.walkingUnits.splice(index, 1);
     77   
     78}
     79
     80AlertRaiser.prototype.EndOfAlert = function()
     81{
     82    this.level = 0;
     83    this.SoundAlert();
     84   
     85    // First, handle units not yet garrisoned
     86    for each(unit in this.walkingUnits)
     87    {
     88        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     89       
     90        cmpUnitAI.ResetAlert();
     91           
     92        if (cmpUnitAI.HasWorkOrders())
     93            cmpUnitAI.BackToWork();
     94        else
     95            cmpUnitAI.ReplaceOrder("Stop", undefined);
     96    }
     97    this.walkingUnits = [];
     98   
     99    // Then, eject garrisoned units
     100    for each(slot in this.garrisonedUnits)
     101    {
     102        var cmpGarrisonHolder = Engine.QueryInterface(slot.holder, IID_GarrisonHolder);
     103        var cmpUnitAI = Engine.QueryInterface(slot.unit, IID_UnitAI);
     104       
     105        if(cmpGarrisonHolder && cmpGarrisonHolder.PerformEject([slot.unit], true))
     106        {
     107            cmpUnitAI.ResetAlert();             
     108            if (cmpUnitAI.HasWorkOrders())
     109                cmpUnitAI.BackToWork();
     110        }
     111    }
     112    this.garrisonedUnits = [];
     113   
     114    return true;
     115};
     116
     117Engine.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

     
    350350            "state": cmpUnitAI.GetCurrentState(),
    351351            "orders": cmpUnitAI.GetOrders(),
    352352            "hasWorkOrders": cmpUnitAI.HasWorkOrders(),
     353            "isUnderAlert": cmpUnitAI.IsUnderAlert(),
    353354        };
    354355        // Add some information needed for ungarrisoning
    355356        if (cmpUnitAI.isGarrisoned && ret.player !== undefined)
     
    378379            "healableClasses": cmpHeal.GetHealableClasses(),
    379380        };
    380381    }
     382   
     383    var cmpAlertRaiser = Engine.QueryInterface(ent, IID_AlertRaiser);
     384    if(cmpAlertRaiser)
     385    {
     386        ret.alertRaiser = {
     387            "level": cmpAlertRaiser.GetLevel(),
     388            "canIncreaseLevel": cmpAlertRaiser.CanIncreaseLevel(),
     389            "hasRaisedAlert": cmpAlertRaiser.HasRaisedAlert(),
     390        };
     391    }
    381392
    382393    ret.visibility = cmpRangeManager.GetLosVisibility(ent, player, false);
    383394
  • 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>" +
     
    664667        this.SetNextState("INDIVIDUAL.AUTOGARRISON");
    665668    },
    666669
     670    "Order.Alert": function(msg) {
     671        this.alertRaiser = this.order.data.raiser;
     672       
     673        // Find a target to garrison into, if we don't already have one
     674        if(!this.alertGarrisoningTarget)
     675        {
     676            var nearby = this.FindNearbyGarrisonHolder();
     677            if (nearby)
     678                this.alertGarrisoningTarget = nearby;
     679            else
     680                this.FinishOrder();
     681        }
     682       
     683        this.ReplaceOrder("Garrison", {"target": this.alertGarrisoningTarget});
     684    }, 
     685   
    667686    "Order.Cheering": function(msg) {
    668687        this.SetNextState("INDIVIDUAL.CHEERING");
    669688    },
     
    23832402                },
    23842403
    23852404                "MoveCompleted": function() {
    2386                     this.SetNextState("GARRISONED");
     2405                    if(this.IsUnderAlert())
     2406                    {
     2407                        // check that we can garrison in the building we're supposed to garrison in
     2408                        var cmpGarrisonHolder = Engine.QueryInterface(this.alertGarrisoningTarget, IID_GarrisonHolder);
     2409                        if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull())
     2410                        {
     2411                            // Try to find another nearby building
     2412                            var nearby = this.FindNearbyGarrisonHolder();
     2413                            if (nearby)
     2414                            {
     2415                                this.alertGarrisoningTarget = nearby;
     2416                                if (this.MoveToTarget(this.alertGarrisoningTarget))
     2417                                    this.SetNextState("APPROACHING");
     2418                            }
     2419                            else
     2420                                this.FinishOrder();
     2421                        }
     2422                        else
     2423                            this.SetNextState("GARRISONED");
     2424                    }
     2425                    else
     2426                        this.SetNextState("GARRISONED");
    23872427                },
    23882428            },
    23892429
    23902430            "GARRISONED": {
    23912431                "enter": function() {
    2392                     var target = this.order.data.target;
     2432                    // Target is not handled the same way with Alert and direct garrisoning
     2433                    if(this.order.data.target)
     2434                        var target = this.order.data.target;
     2435                    else
     2436                    {   
     2437                        if(!this.alertGarrisoningTarget)
     2438                        {
     2439                            // We've been unable to find a target nearby, so give up
     2440                            this.FinishOrder();
     2441                            return true;
     2442                        }
     2443                        var target = this.alertGarrisoningTarget;
     2444                    }
     2445
    23932446                    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
    23942447
    23952448                    // Check that we can garrison here
     
    27122765    // Queue of remembered works
    27132766    this.workOrders = [];
    27142767
     2768    // "Town Bell" behaviour
     2769    this.alertRaiser = undefined;
     2770    this.alertGarrisoningTarget = undefined;
     2771
    27152772    // For preventing increased action rate due to Stop orders or target death.
    27162773    this.lastAttacked = undefined;
    27172774    this.lastHealed = undefined;
     
    27192776    this.SetStance(this.template.DefaultStance);
    27202777};
    27212778
     2779UnitAI.prototype.ReactsToAlert = function(level)
     2780{
     2781    return this.template.AlertReactiveLevel <= level;
     2782};
     2783
     2784UnitAI.prototype.IsUnderAlert = function()
     2785{
     2786    return this.alertGarrisoningTarget != undefined;
     2787};
     2788
     2789UnitAI.prototype.ResetAlert = function()
     2790{
     2791    this.alertGarrisoningTarget = undefined;
     2792};
     2793
    27222794UnitAI.prototype.IsFormationController = function()
    27232795{
    27242796    return (this.template.FormationController == "true");
     
    33183390    this.workOrders = orders;
    33193391};
    33203392
     3393UnitAI.prototype.GetAlertRaiser = function()
     3394{
     3395    return this.alertRaiser;
     3396};
     3397
    33213398UnitAI.prototype.TimerHandler = function(data, lateness)
    33223399{
    33233400    // Reset the timer
     
    35043581    var players = [];
    35053582    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    35063583    if (cmpOwnership)
    3507         players.push(cmpOwnership.GetOwner());
     3584        players = [cmpOwnership.GetOwner()];
    35083585
    35093586    // Ships are unable to reach land dropsites and shouldn't attempt to do so.
    35103587    var excludeLand = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
     
    35423619    var players = [];
    35433620    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
    35443621    if (cmpOwnership)
    3545         players.push(cmpOwnership.GetOwner());
     3622        players = [cmpOwnership.GetOwner()];
    35463623
    35473624    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    35483625    var nearby = rangeMan.ExecuteQuery(this.entity, 0, range, players, IID_Foundation);
     
    35623639};
    35633640
    35643641/**
     3642 * Returns the entity ID of the nearest building in which the unit can garrison,
     3643 * or undefined if none can be found close enough.
     3644 */
     3645UnitAI.prototype.FindNearbyGarrisonHolder = function()
     3646{
     3647    var range = 128; // TODO: what's a sensible number?
     3648
     3649    // Find buildings owned by this unit's player
     3650    var players = [];
     3651    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     3652    if (cmpOwnership)
     3653        players = [cmpOwnership.GetOwner()];
     3654
     3655    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     3656    var nearby = rangeMan.ExecuteQuery(this.entity, 0, range, players, IID_GarrisonHolder);
     3657    for each (var ent in nearby)
     3658    {
     3659        var cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
     3660        // We only want to garrison in buildings, not in moving units like ships,...
     3661        var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     3662        if (!cmpUnitAI && cmpGarrisonHolder.AllowedToGarrison(this.entity) && !cmpGarrisonHolder.IsFull())
     3663            return ent;
     3664    }
     3665
     3666    return undefined;
     3667};
     3668
     3669/**
    35653670 * Play a sound appropriate to the current entity.
    35663671 */
    35673672UnitAI.prototype.PlaySound = function(name)
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    399399                notifyUnloadFailure(player, garrisonHolder)
    400400        }
    401401        break;
     402   
     403    case "increase-alert-level":
     404        for each (var raiser in entities)
     405        {
     406            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     407            if (!cmpAlertRaiser || !cmpAlertRaiser.IncreaseAlertLevel())
     408                notifyAlertFailure(player);
     409        }
     410        break;
     411   
     412    case "alert-end":
     413        for each (var raiser in entities)
     414        {
     415            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     416            if (cmpAlertRaiser)
     417                cmpAlertRaiser.EndOfAlert();
     418        }
     419        break;
    402420
    403421    case "formation":
    404422        GetFormationUnitAIs(entities, player, cmd.name).forEach(function(cmpUnitAI) {
     
    538556}
    539557
    540558/**
     559 * Sends a GUI notification about Alerts that failed to be raised
     560 */
     561function notifyAlertFailure(player)
     562{
     563    var cmpPlayer = QueryPlayerIDInterface(player, IID_Player);
     564    var notification = {"player": cmpPlayer.GetPlayerID(), "message": "You can't raise the alert to a higher level !" };
     565    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     566    cmpGUIInterface.PushNotification(notification);
     567}
     568
     569/**
    541570 * Get some information about the formations used by entities.
    542571 * The entities must have a UnitAI component.
    543572 */
  • binaries/data/mods/public/simulation/templates/special/formation.xml

     
    1414    <TurnRate>6.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

     
    9191      <constructed>interface/complete/building/complete_civ_center.xml</constructed>
    9292      <attack>attack/weapon/arrowfly.xml</attack>
    9393      <death>attack/destruction/building_collapse_large.xml</death>
     94      <alert0>interface/alarm/alarm_alert_0.xml</alert0>
     95      <alert1>interface/alarm/alarm_alert_1.xml</alert1>
     96      <alert2>interface/alarm/alarm_alert_2.xml</alert2>
    9497    </SoundGroups>
    9598  </Sound>
    9699  <TerritoryInfluence>
     
    98101    <Radius>140</Radius>
    99102    <Weight>65536</Weight>
    100103  </TerritoryInfluence>
     104  <AlertRaiser>
     105    <MaximumLevel>2</MaximumLevel>
     106    <Range>140</Range>
     107  </AlertRaiser>
    101108  <Vision>
    102109    <Range>90</Range>
    103110  </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

     
    8686  <Stamina>
    8787    <Max>500</Max>
    8888  </Stamina>
     89  <UnitAI>
     90    <AlertReactiveLevel>1</AlertReactiveLevel>
     91  </UnitAI>
    8992  <UnitMotion>
    9093    <WalkSpeed>8.0</WalkSpeed>
    9194    <Run>