Ticket #3102: t3102_survival_5.diff

File t3102_survival_5.diff, 11.6 KB (added by bb, 3 years ago)

Cleanup based on work by elexis

  • binaries/data/mods/public/maps/random/survivalofthefittest.js

     
    198198    );
    199199    createArea(placer, [terrainPainter, elevationPainter, paintClass(clWater)], null);
    200200   
    201     //creating female citizens
     201    // Creating seeker woman (these need to have a lower ID than other starting woman for InitGame to identify them)
    202202    var femaleLocation = getTIPIADBON([ix, iz], [mapSize / 2, mapSize / 2], [-3 , 3.5], 1, 3);
    203203    if (femaleLocation !== undefined)
    204204    {
  • binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js

     
    1 var treasures =
    2 [
     1/**
     2 * Time in minutes to the first enemy wave.
     3 */
     4var firstAttackWave = 5 + 10 * Math.random();
     5
     6/**
     7 * Time after which resources are distributed periodically.
     8 */
     9var provideResourcesOffset = 14 + 2 * Math.random();
     10
     11/**
     12 * Time interval between enemy waves.
     13 */
     14var attackerWaveInterval = [2, 3];
     15
     16/**
     17 * Time interval when treasures are distributed periodically.
     18 */
     19var treasureInterval = [3, 4];
     20
     21/**
     22 * Time interval after which resources are distributed periodically.
     23 */
     24var provideResourcesInterval = [1.25, 1.75];
     25
     26/**
     27 * Amount of miliseconds in minute.
     28 */
     29const minutes = 60 * 1000;
     30
     31var treasures = [
    332    "gaia/special_treasure_food_barrel",
    433    "gaia/special_treasure_food_bin",
    534    "gaia/special_treasure_food_crate",
     
    1039    "gaia/special_treasure_wood",
    1140    "gaia/special_treasure_wood"
    1241];
    13 var attackerEntityTemplates =
    14 [
     42
     43/**
     44 * Templates of the attacking units, sorted by civ
     45 */
     46var attackerTemplates = [
    1547    [
    1648        "units/athen_champion_infantry",
    1749        "units/athen_champion_marine",
    1850        "units/athen_champion_ranged",
    19         "units/athen_siege_lithobolos_packed",
    20         "units/athen_siege_oxybeles_packed",
     51        "units/athen_mechanical_siege_lithobolos_packed",
     52        "units/athen_mechanical_siege_oxybeles_packed",
    2153    ],
    2254    [
    2355        "units/brit_champion_cavalry",
     
    88120Trigger.prototype.StartAnEnemyWave = function()
    89121{
    90122    let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    91     let attackerEntities = attackerEntityTemplates[Math.floor(Math.random() * attackerEntityTemplates.length)];
    92     // A soldier for each 2-3 minutes of the game. Should be waves of 20 soldiers after an hour
    93     let nextTime = Math.round(120000 + Math.random() * 60000);
    94     let attackerCount = Math.round(cmpTimer.GetTime() / nextTime / attackerEntities.length);
     123    let templates = attackerTemplates[Math.floor(Math.random() * attackerTemplates.length)];
     124    let nextTime = Math.round(RandomReal(attackerWaveInterval) * minutes);
     125    let attackerCount = Math.ceil(cmpTimer.GetTime() / nextTime / templates.length);
    95126
    96     // spawn attackers
    97     let attackers =  [];
    98     for (let attackerEntity of attackerEntities)
    99         attackers.push(TriggerHelper.SpawnUnitsFromTriggerPoints("A", attackerEntity, attackerCount, 0));
     127    let attackers = templates.map(ent =>
     128        TriggerHelper.SpawnUnitsFromTriggerPoints("A", ent, attackerCount, 0));
    100129
    101130    for (let entityType of attackers)
    102     {
    103131        for (let origin in entityType)
    104132        {
    105133            let cmpPlayer = QueryOwnerInterface(+origin, IID_Player);
    106             if (cmpPlayer.GetState() != "active")
     134            if (!cmpPlayer || !cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()])
    107135                continue;
    108136
    109             let cmpPosition =  Engine.QueryInterface(this.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
    110             // this shouldn't happen if the player is still active
     137            let cmpPosition = Engine.QueryInterface(cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
     138            // This shouldn't happen if the player is still active
    111139            if (!cmpPosition || !cmpPosition.IsInWorld)
    112140                continue;
    113141
    114             // store the x and z coordinates in the command
    115             let cmd = cmpPosition.GetPosition();
    116             cmd.type = "attack-walk";
    117             cmd.entities = entityType[origin];
    118             cmd.queued = true;
    119             cmd.targetClasses = undefined;
    120             // send the attack-walk command
    121             ProcessCommand(0, cmd);
     142            let pos = cmpPosition.GetPosition();
     143            ProcessCommand(0, {
     144                "type": "attack-walk",
     145                "entities": entityType[origin],
     146                "x": pos.x,
     147                "z": pos.z,
     148                "targetClasses": undefined,
     149                "queued": true
     150            });
    122151        }
    123     }
    124152
    125153    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    126154    cmpGUIInterface.PushNotification({
     
    127155        "message": markForTranslation("An enemy wave is attacking!"),
    128156        "translateMessage": true
    129157    });
    130     cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
     158    cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {});
    131159};
    132160
     161/**
     162 * Find all of the civic centers and females, disable some structures, setup activity watch.
     163 */
    133164Trigger.prototype.InitGame = function()
    134165{
    135166    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
    136     // Find all of the civic centers, disable some structures
    137167    for (let i = 1; i < numberOfPlayers; ++i)
    138168    {
    139169        let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    140170        let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
    141171
     172        let foundSeeker = false;
    142173        for (let entity of playerEntities)
     174        {
    143175            if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
    144176                cmpTrigger.playerCivicCenter[i] = entity;
     177
     178            if (TriggerHelper.EntityHasClass(entity, "Female") && !foundSeeker)
     179            {
     180                foundSeeker = true;
     181                let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
     182                cmpDamageReceiver.SetInvulnerability(true);
     183
     184                let cmpHealth = Engine.QueryInterface(entity, IID_Health);
     185                cmpHealth.SetUndeletable(true);
     186            }
     187        }
    145188    }
    146189
    147190    // Fix alliances
     
    158201    // Make gaia black
    159202    QueryPlayerIDInterface(0).SetColor(0, 0, 0);
    160203
    161     // Place the treasures
    162     this.PlaceTreasures();
     204    this.placeTreasures();
    163205
    164206    // Disable farms, civic centers and walls for all players
    165207    for (let i = 1; i < numberOfPlayers; ++i)
     
    166208    {
    167209        let cmpPlayer = QueryPlayerIDInterface(i);
    168210        let civ = cmpPlayer.GetCiv();
     211
    169212        cmpPlayer.SetDisabledTemplates([
    170213            "structures/" + civ + "_field",
    171214            "structures/" + civ + "_corral",
     
    177220    }
    178221};
    179222
    180 Trigger.prototype.PlaceTreasures = function()
     223Trigger.prototype.placeTreasures = function()
    181224{
    182225    let point = ["B", "C", "D"][Math.floor(Math.random() * 3)];
    183226    let triggerPoints = cmpTrigger.GetTriggerPoints(point);
    184227    for (let point of triggerPoints)
    185228    {
    186         let template = treasures[Math.floor(Math.random() * treasures.length)]
    187         TriggerHelper.SpawnUnits(point, template, 1, 0);
     229        let template = treasures[Math.floor(Math.random() * treasures.length)];
     230        let cmpPosition = Engine.QueryInterface(point, IID_Position);
     231        let ent = Engine.AddEntity(template);
     232
     233        let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
     234        let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
     235
     236        if (cmpEntOwnership)
     237            cmpEntOwnership.SetOwner(0);
     238
     239        let xOffset = RandomInt(0, 23);
     240        let zOffset = RandomInt(0, 23);
     241
     242        if (Math.random() >= 0.8)
     243        {
     244            xOffset += RandomInt(5, 8);
     245            zOffset += RandomInt(5, 8);
     246        }
     247
     248        if (Math.round(Math.random()) == 1)
     249            xOffset = -xOffset;
     250
     251        if (Math.round(Math.random()) == 1)
     252            zOffset = -zOffset;
     253
     254        cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
    188255    }
    189     cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
     256
     257    cmpTrigger.DoAfterDelay(RandomReal(treasureInterval) * minutes, "placeTreasures", {});
     258
     259    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     260    cmpGUIInterface.PushNotification({
     261        "message": markForTranslation("New treasures have been placed!"),
     262        "translateMessage": true
     263    });
    190264};
    191265
    192266Trigger.prototype.InitializeEnemyWaves = function()
    193267{
    194     let time = (5 + Math.round(Math.random() * 10)) * 60 * 1000;
    195268    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     269
     270    cmpGUIInterface.PushNotification({
     271        "message": markForTranslation("Welcome to Survival of the Fittest"),
     272        "translateMessage": true
     273    });
     274
     275    cmpGUIInterface.PushNotification({
     276        "message": markForTranslation("Collect treasures with your woman to prepare for the enemies."),
     277        "translateMessage": true
     278    });
     279
     280    let time = firstAttackWave * minutes;
    196281    cmpGUIInterface.AddTimeNotification({
    197282        "message": markForTranslation("The first wave will start in %(time)s!"),
    198283        "translateMessage": true
     
    200285    cmpTrigger.DoAfterDelay(time, "StartAnEnemyWave", {});
    201286};
    202287
    203 Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
     288Trigger.prototype.defeatPlayerOnceCCIsDestroyed = function(data)
    204289{
    205     // Defeat a player that has lost his civic center
    206     if (data.entity == cmpTrigger.playerCivicCenter[data.from])
    207     {
     290    if (data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
    208291        TriggerHelper.DefeatPlayer(data.from);
     292};
    209293
    210         // Check if only one player remains. He will be the winner.
    211         let lastPlayerStanding = 0;
    212         let numPlayersStanding = 0;
    213         let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
    214         for (let i = 1; i < numberOfPlayers; ++i)
    215         {
    216             if (QueryPlayerIDInterface(i).GetState() == "active")
    217             {
    218                 lastPlayerStanding = i;
    219                 ++numPlayersStanding;
    220             }
    221         }
    222         if (numPlayersStanding == 1)
    223             TriggerHelper.SetPlayerWon(lastPlayerStanding);
     294Trigger.prototype.provideResources = function(data)
     295{
     296    if (data.first)
     297    {
     298        let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     299        cmpGUIInterface.PushNotification({
     300            "message": markForTranslation("From now on, all players will receive some resources from time to time."),
     301            "translateMessage": true
     302        });
    224303    }
     304
     305    let resources = {};
     306    for (let type of ["food", "wood", "stone", "metal"])
     307        resources[type] = 50 + Math.round(Math.random() * 100);
     308
     309    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
     310    for (let i = 1; i < numberOfPlayers; ++i)
     311        QueryPlayerIDInterface(i).AddResources(resources);
     312
     313    cmpTrigger.DoAfterDelay(RandomReal(provideResourcesInterval) * minutes, "provideResources", {});
    225314};
    226315
    227316var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
    228317cmpTrigger.playerCivicCenter = {};
     318
    229319cmpTrigger.DoAfterDelay(0, "InitGame", {});
    230320cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
     321cmpTrigger.DoAfterDelay(provideResourcesOffset * minutes, "provideResourcesFirst", { "first": true });
    231322
    232 cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });
     323cmpTrigger.RegisterTrigger("OnOwnershipChanged", "defeatPlayerOnceCCIsDestroyed", { "enabled": true });
  • binaries/data/mods/public/simulation/helpers/Random.js

     
    11/**
     2 * Returns a random real in given interval.
     3 */
     4function RandomReal(interval)
     5{
     6    let min = Math.min(interval[0], interval[1]);
     7    let max = Math.max(interval[0], interval[1]);
     8    return min + (max - min) * Math.random();
     9}
     10
     11/**
    212 * Returns a random integer from min (inclusive) to max (exclusive)
    313 */
    414function RandomInt(min, max)
     
    616    return Math.floor(min + Math.random() * (max-min));
    717}
    818
     19Engine.RegisterGlobal("RandomReal", RandomReal);
    920Engine.RegisterGlobal("RandomInt", RandomInt);