Ticket #2154: patch_townbell.2.diff

File patch_townbell.2.diff, 19.7 KB (added by Itms, 10 years ago)
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert.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>alarmalert.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalert.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert_end.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>alarmalertend.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalertend.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/audio/interface/alarm/alarm_alert_red.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>alarmalertred.ogg</Replacement>
     22    <Path>audio/interface/alarm/</Path>
     23    <Sound>alarmalertred.ogg</Sound>
     24</SoundGroup>
  • binaries/data/mods/public/gui/session/input.js

     
    18441844            case "back-to-work":
    18451845                backToWork();
    18461846                break;
     1847            case "raise-alert-yellow":
     1848                raiseYellowAlert();
     1849                break;
     1850            case "raise-alert-red":
     1851                raiseRedAlert();
     1852                break;
     1853            case "alert-end":
     1854                endOfAlert();
     1855                break;
    18471856            default:
    18481857                break;
    18491858            }
     
    21182127   
    21192128}
    21202129
     2130function raiseYellowAlert()
     2131{
     2132    var raisers = g_Selection.toList().filter(function(e) {
     2133        var state = GetEntityState(e);
     2134        if (state && state.alertRaiser && state.alertRaiser.level == "End")
     2135            return true;
     2136        return false;
     2137    });
     2138   
     2139    Engine.PostNetworkCommand({"type": "raise-alert-yellow", "entities": raisers});
     2140}
     2141
     2142function raiseRedAlert()
     2143{
     2144    var raisers = g_Selection.toList().filter(function(e) {
     2145        var state = GetEntityState(e);
     2146        if (state && state.alertRaiser && state.alertRaiser.level == "Yellow")
     2147            return true;
     2148        return false;
     2149    });
     2150   
     2151    Engine.PostNetworkCommand({"type": "raise-alert-red", "entities": raisers});
     2152}
     2153
     2154function endOfAlert()
     2155{
     2156    var raisers = g_Selection.toList().filter(function(e) {
     2157        var state = GetEntityState(e);
     2158        if (state && state.alertRaiser && (state.alertRaiser.level == "Yellow" || state.alertRaiser.level == "Red"))
     2159            return true;
     2160        return false;
     2161    });
     2162   
     2163    Engine.PostNetworkCommand({"type": "alert-end", "entities": raisers});
     2164}
     2165
    21212166function clearSelection()
    21222167{
    21232168    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        switch(entState.alertRaiser.level)
     309        {
     310            case "End":
     311                commands.push({
     312                    "name": "raise-alert-yellow",
     313                    "tooltip": "Alert : Garrison all female citizens in the first nearby building",
     314                    "icon": "bell_level1.png"
     315                });
     316                break;
     317            case "Yellow":
     318                commands.push({
     319                    "name": "raise-alert-red",
     320                    "tooltip": "Red Alert : Garrison also the citizen-soldiers",
     321                    "icon": "bell_level2.png"
     322                });
     323                commands.push({
     324                    "name": "alert-end",
     325                    "tooltip": "End of Alert",
     326                    "icon": "bell_level0.png"
     327                });
     328                break;
     329            case "Red":
     330                commands.push({
     331                    "name": "alert-end",
     332                    "tooltip": "End of Alert",
     333                    "icon": "bell_level0.png"
     334                });
     335                break;
     336            default:
     337                break;
     338        }
     339    }
    305340
    306341    return commands;
    307342}
  • binaries/data/mods/public/simulation/components/AlertRaiser.js

     
     1function AlertRaiser() {}
     2
     3AlertRaiser.prototype.Schema = "<element name='Range'><data type='nonNegativeInteger'/></element>";
     4
     5AlertRaiser.prototype.Init = function()
     6{
     7    this.level = "End";
     8   
     9    // Remember the units ordered to garrison
     10    this.garrisonedUnits = [];
     11    this.walkingUnits = [];
     12};
     13
     14AlertRaiser.prototype.GetLevel = function()
     15{
     16    return this.level;
     17};
     18
     19AlertRaiser.prototype.RaiseYellowAlert = function()
     20{   
     21    // Find units owned by this unit's player
     22    var players = [];
     23    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     24    if (cmpOwnership)
     25        players.push(cmpOwnership.GetOwner());
     26   
     27    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     28    var units = rangeMan.ExecuteQuery(this.entity, 0, this.template.Range, players, IID_UnitAI).filter( function(e){
     29        var cmpIdentity = Engine.QueryInterface(e, IID_Identity);
     30        return (cmpIdentity && cmpIdentity.HasClass("Female"));
     31        });
     32       
     33    this.level = "Yellow";
     34    PlaySound("alert", this.entity);
     35   
     36    for each(unit in units)
     37    {
     38        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     39        cmpUnitAI.ReplaceOrder("Alert", {"raiser": this.entity, "force": true});
     40        this.walkingUnits.push(unit);
     41    }
     42   
     43    return true;
     44};
     45
     46AlertRaiser.prototype.RaiseRedAlert = function()
     47{
     48    // Find units owned by this unit's player
     49    var players = [];
     50    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     51    if (cmpOwnership)
     52        players.push(cmpOwnership.GetOwner());
     53   
     54    // If a yellow alert has already been raised, only give orders to the units who don't already have orders.
     55    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     56    var units = rangeMan.ExecuteQuery(this.entity, 0, this.template.Range, players, IID_UnitAI).filter( function(e){
     57        var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
     58        return (!cmpUnitAI.IsUnderAlert() && !cmpUnitAI.IsAnimal());
     59        });
     60       
     61    this.level = "Red";
     62    PlaySound("alertred", this.entity);
     63   
     64    for each(unit in units)
     65    {
     66        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     67        cmpUnitAI.ReplaceOrder("Alert", {"raiser": this.entity, "force": true});
     68        this.walkingUnits.push(unit);
     69    }
     70   
     71    return true;
     72};
     73
     74AlertRaiser.prototype.OnUnitGarrisonedAfterAlert = function(msg)
     75{
     76    this.garrisonedUnits.push({"holder": msg.holder, "unit": msg.unit});
     77   
     78    var index = this.walkingUnits.indexOf(msg.unit);
     79    if (index != -1)
     80        this.walkingUnits.splice(index, 1);
     81   
     82}
     83
     84AlertRaiser.prototype.EndOfAlert = function()
     85{
     86    // First, handle units not yet garrisoned
     87    for each(unit in this.walkingUnits)
     88    {
     89        var cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
     90        if (cmpUnitAI)
     91        {
     92            cmpUnitAI.ResetAlert();
     93           
     94            if (cmpUnitAI.HasWorkOrders())
     95                cmpUnitAI.BackToWork();
     96            else
     97                cmpUnitAI.ReplaceOrder("Stop", undefined);
     98        }
     99    }
     100    this.walkingUnits = [];
     101   
     102    // Then, eject garrisoned units
     103    for each(slot in this.garrisonedUnits)
     104    {
     105        var cmpGarrisonHolder = Engine.QueryInterface(slot.holder, IID_GarrisonHolder);
     106        var cmpUnitAI = Engine.QueryInterface(slot.unit, IID_UnitAI);
     107       
     108        if(cmpGarrisonHolder)
     109        {
     110            var success = cmpGarrisonHolder.PerformEject([slot.unit], true);
     111            if (success && cmpUnitAI)
     112            {
     113                cmpUnitAI.ResetAlert();             
     114                if (cmpUnitAI.HasWorkOrders())
     115                    cmpUnitAI.BackToWork();
     116            }
     117        }
     118    }
     119    this.garrisonedUnits = [];
     120   
     121    this.level = "End";
     122    PlaySound("alertend", this.entity);
     123    return true;
     124};
     125
     126Engine.RegisterComponentType(IID_AlertRaiser, "AlertRaiser", AlertRaiser);
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    239239        cmpAura.ApplyGarrisonBonus(this.entity);   
    240240
    241241    Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {});
     242   
     243    var cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
     244    if (cmpUnitAI && cmpUnitAI.GetAlertRaiser())
     245        Engine.PostMessage(cmpUnitAI.GetAlertRaiser(), MT_UnitGarrisonedAfterAlert, {"holder": this.entity, "unit": entity});
     246   
    242247    return true;
    243248};
    244249
  • 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        };
     389    }
    381390
    382391    ret.visibility = cmpRangeManager.GetLosVisibility(ent, player, false);
    383392
  • 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

     
    663663        }
    664664    },
    665665
     666    "Order.Alert": function(msg) {
     667        this.alertRaiser = this.order.data.raiser;
     668       
     669        // Find a target to garrison into, if we don't already have one
     670        if(!this.garrisoningTarget)
     671        {
     672            var nearby = this.FindNearbyGarrisonHolder();
     673            if (nearby)
     674                this.garrisoningTarget = nearby;
     675            else
     676                this.FinishOrder();
     677        }
     678       
     679        this.ReplaceOrder("Garrison", {"target": this.garrisoningTarget});
     680    },
     681
    666682    "Order.Cheering": function(msg) {
    667683        this.SetNextState("INDIVIDUAL.CHEERING");
    668684    },
     
    23822398                },
    23832399
    23842400                "MoveCompleted": function() {
    2385                     this.SetNextState("GARRISONED");
     2401                    if(this.garrisoningTarget) // We're under Alert
     2402                    {
     2403                        // check that we can garrison in the building we're supposed to garrison in
     2404                        var cmpGarrisonHolder = Engine.QueryInterface(this.garrisoningTarget, IID_GarrisonHolder);
     2405                        if (!cmpGarrisonHolder || cmpGarrisonHolder.GetCapacity() <= cmpGarrisonHolder.GetEntities().length)
     2406                        {
     2407                            // Try to find another nearby building
     2408                            var nearby = this.FindNearbyGarrisonHolder();
     2409                            if (nearby)
     2410                            {
     2411                                this.garrisoningTarget = nearby;
     2412                                if (this.MoveToTarget(this.garrisoningTarget))
     2413                                    this.SetNextState("APPROACHING");
     2414                            }
     2415                            else
     2416                                this.FinishOrder();
     2417                        }
     2418                        else
     2419                            this.SetNextState("GARRISONED");
     2420                    }
     2421                    else
     2422                        this.SetNextState("GARRISONED");
    23862423                },
    23872424            },
    23882425
    23892426            "GARRISONED": {
    23902427                "enter": function() {
    2391                     var target = this.order.data.target;
     2428                    // Target is not handled the same way with Alert and direct garrisoning
     2429                    if(this.order.data.target)
     2430                        var target = this.order.data.target;
     2431                    else
     2432                    {   
     2433                        if(!this.garrisoningTarget)
     2434                        {
     2435                            // We've been unable to find a target nearby, so give up
     2436                            this.FinishOrder();
     2437                            return true;
     2438                        }
     2439                        var target = this.garrisoningTarget;
     2440                    }
     2441
    23922442                    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder);
    23932443
    23942444                    // Check that we can garrison here
     
    26952745    // Queue of remembered works
    26962746    this.workOrders = [];
    26972747
     2748    // "Town Bell" behaviour
     2749    this.alertRaiser = undefined;
     2750    this.garrisoningTarget = undefined;
     2751
    26982752    // For preventing increased action rate due to Stop orders or target death.
    26992753    this.lastAttacked = undefined;
    27002754    this.lastHealed = undefined;
     
    27022756    this.SetStance(this.template.DefaultStance);
    27032757};
    27042758
     2759UnitAI.prototype.IsUnderAlert = function()
     2760{
     2761    return (this.garrisoningTarget != undefined);
     2762};
     2763
     2764UnitAI.prototype.ResetAlert = function()
     2765{
     2766    this.garrisoningTarget = undefined;
     2767};
     2768
    27052769UnitAI.prototype.IsFormationController = function()
    27062770{
    27072771    return (this.template.FormationController == "true");
     
    33013365    this.workOrders = orders;
    33023366};
    33033367
     3368UnitAI.prototype.GetAlertRaiser = function()
     3369{
     3370    return this.alertRaiser;
     3371};
     3372
    33043373UnitAI.prototype.TimerHandler = function(data, lateness)
    33053374{
    33063375    // Reset the timer
     
    35453614};
    35463615
    35473616/**
     3617 * Returns the entity ID of the nearest building in which the unit can garrison,
     3618 * or undefined if none can be found close enough.
     3619 */
     3620UnitAI.prototype.FindNearbyGarrisonHolder = function()
     3621{
     3622    var range = 128; // TODO: what's a sensible number?
     3623
     3624    // Find buildings owned by this unit's player
     3625    var players = [];
     3626    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     3627    if (cmpOwnership)
     3628        players.push(cmpOwnership.GetOwner());
     3629
     3630    var rangeMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     3631    var nearby = rangeMan.ExecuteQuery(this.entity, 0, range, players, IID_GarrisonHolder);
     3632    for each (var ent in nearby)
     3633    {
     3634        var cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
     3635        // We only want to garrison in buildings, not in moving units like ships,...
     3636        var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
     3637        if (!cmpUnitAI && cmpGarrisonHolder.AllowedToGarrison(this.entity) && cmpGarrisonHolder.GetCapacity() > cmpGarrisonHolder.GetEntities().length)
     3638            return ent;
     3639    }
     3640
     3641    return undefined;
     3642};
     3643
     3644/**
    35483645 * Play a sound appropriate to the current entity.
    35493646 */
    35503647UnitAI.prototype.PlaySound = function(name)
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    399399                notifyUnloadFailure(player, garrisonHolder)
    400400        }
    401401        break;
     402   
     403    case "raise-alert-yellow":
     404        for each (var raiser in entities)
     405        {
     406            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     407            if (!cmpAlertRaiser || !cmpAlertRaiser.RaiseYellowAlert())
     408                notifyAlertFailure(player);
     409        }
     410        break;
     411   
     412    case "raise-alert-red":
     413        for each (var raiser in entities)
     414        {
     415            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     416            if (!cmpAlertRaiser || !cmpAlertRaiser.RaiseRedAlert())
     417                notifyAlertFailure(player);
     418        }
     419        break;
     420   
     421    case "alert-end":
     422        for each (var raiser in entities)
     423        {
     424            var cmpAlertRaiser = Engine.QueryInterface(raiser, IID_AlertRaiser);
     425            if (!cmpAlertRaiser || !cmpAlertRaiser.EndOfAlert())
     426                notifyAlertFailure(player);
     427        }
     428        break;
    402429
    403430    case "formation":
    404431        GetFormationUnitAIs(entities, player, cmd.name).forEach(function(cmpUnitAI) {
     
    538565}
    539566
    540567/**
     568 * Sends a GUI notification about Alerts that failed to be raised
     569 */
     570function notifyAlertFailure(player)
     571{
     572    var cmpPlayer = QueryPlayerIDInterface(player, IID_Player);
     573    var notification = {"player": cmpPlayer.GetPlayerID(), "message": "Unable to sound the horns" };
     574    var cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     575    cmpGUIInterface.PushNotification(notification);
     576}
     577
     578/**
    541579 * Get some information about the formations used by entities.
    542580 * The entities must have a UnitAI component.
    543581 */
  • 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      <alert>interface/alarm/alarm_alert.xml</alert>
     95      <alertred>interface/alarm/alarm_alert_red.xml</alertred>
     96      <alertend>interface/alarm/alarm_alert_end.xml</alertend>
    9497    </SoundGroups>
    9598  </Sound>
    9699  <TerritoryInfluence>
     
    98101    <Radius>140</Radius>
    99102    <Weight>65536</Weight>
    100103  </TerritoryInfluence>
     104  <AlertRaiser>
     105    <Range>140</Range>
     106  </AlertRaiser>
    101107  <Vision>
    102108    <Range>90</Range>
    103109  </Vision>