Ticket #3102: t3102_survival_4.diff

File t3102_survival_4.diff, 12.7 KB (added by elexis, 3 years ago)

rebased and fixed a good number of the things mentioned

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

    for (var i = 0; i < numPlayers; i++) 
    196196        3,              // elevation
    197197        4               // blend radius
    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    {
    205205        placeObject(femaleLocation[0], femaleLocation[1], "skirmish/units/default_support_female_citizen", id, playerAngle[i] + PI);
    206206        addToClass(floor(femaleLocation[0]), floor(femaleLocation[1]), clWomen);
  • binaries/data/mods/public/maps/random/survivalofthefittest_triggers.js

     
    1 var treasures =
    2 [
     1// Time in minutes when treasures are distributed periodically without random offset.
     2var treasureTime = 3;
     3
     4// Time in minutes when resources are distributed periodically without random offset.
     5var provideResourcesTime = 1.25;
     6
     7// Time in minutes after which resources are distributed periodically.
     8var provideResourcesOffset = 14 + 2 * Math.random();
     9
     10var treasures = [
    311    "gaia/special_treasure_food_barrel",
    412    "gaia/special_treasure_food_bin",
    513    "gaia/special_treasure_food_crate",
    614    "gaia/special_treasure_food_jars",
    715    "gaia/special_treasure_metal",
    816    "gaia/special_treasure_stone",
    917    "gaia/special_treasure_wood",
    1018    "gaia/special_treasure_wood",
    1119    "gaia/special_treasure_wood"
    1220];
    13 var attackerEntityTemplates =
    14 [
     21
     22var resourceMessage = false;
     23
     24// Templates of the attacking units, sorted by civ
     25var attackerEntityTemplates = [
    1526    [
    1627        "units/athen_champion_infantry",
    1728        "units/athen_champion_marine",
    1829        "units/athen_champion_ranged",
    19         "units/athen_siege_lithobolos_packed",
    20         "units/athen_siege_oxybeles_packed",
     30        "units/athen_mechanical_siege_lithobolos_packed",
     31        "units/athen_mechanical_siege_oxybeles_packed"
    2132    ],
    2233    [
    2334        "units/brit_champion_cavalry",
    2435        "units/brit_champion_infantry",
    25         "units/brit_mechanical_siege_ram",
     36        "units/brit_mechanical_siege_ram"
    2637    ],
    2738    [
    2839        "units/cart_champion_cavalry",
    2940        "units/cart_champion_elephant",
    3041        "units/cart_champion_infantry",
    31         "units/cart_champion_pikeman",
     42        "units/cart_champion_pikeman"
    3243    ],
    3344    [
    3445        "units/gaul_champion_cavalry",
    3546        "units/gaul_champion_fanatic",
    3647        "units/gaul_champion_infantry",
    37         "units/gaul_mechanical_siege_ram",
     48        "units/gaul_mechanical_siege_ram"
    3849    ],
    3950    [
    4051        "units/iber_champion_cavalry",
    4152        "units/iber_champion_infantry",
    42         "units/iber_mechanical_siege_ram",
     53        "units/iber_mechanical_siege_ram"
    4354    ],
    4455    [
    4556        "units/mace_champion_cavalry",
    4657        "units/mace_champion_infantry_a",
    4758        "units/mace_champion_infantry_e",
    4859        "units/mace_mechanical_siege_lithobolos_packed",
    49         "units/mace_mechanical_siege_oxybeles_packed",
     60        "units/mace_mechanical_siege_oxybeles_packed"
    5061    ],
    5162    [
    5263        "units/maur_champion_chariot",
    5364        "units/maur_champion_elephant",
    5465        "units/maur_champion_infantry",
    5566        "units/maur_champion_maiden",
    56         "units/maur_champion_maiden_archer",
     67        "units/maur_champion_maiden_archer"
    5768    ],
    5869    [
    5970        "units/pers_champion_cavalry",
    60         "units/pers_champion_infantry",
    6171        "units/pers_champion_elephant",
     72        "units/pers_champion_infantry"
    6273    ],
    6374    [
    6475        "units/ptol_champion_cavalry",
    65         "units/ptol_champion_elephant",
     76        "units/ptol_champion_elephant"
    6677    ],
    6778    [
    6879        "units/rome_champion_cavalry",
    6980        "units/rome_champion_infantry",
    7081        "units/rome_mechanical_siege_ballista_packed",
    71         "units/rome_mechanical_siege_scorpio_packed",
     82        "units/rome_mechanical_siege_scorpio_packed"
    7283    ],
    7384    [
    7485        "units/sele_champion_cavalry",
    7586        "units/sele_champion_chariot",
    7687        "units/sele_champion_elephant",
    7788        "units/sele_champion_infantry_pikeman",
    78         "units/sele_champion_infantry_swordsman",
     89        "units/sele_champion_infantry_swordsman"
    7990    ],
    8091    [
    8192        "units/spart_champion_infantry_pike",
    8293        "units/spart_champion_infantry_spear",
    8394        "units/spart_champion_infantry_sword",
    84         "units/spart_mechanical_siege_ram",
     95        "units/spart_mechanical_siege_ram"
    8596    ],
    8697];
    8798
    8899Trigger.prototype.StartAnEnemyWave = function()
    89100{
    90101    let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
    91102    let attackerEntities = attackerEntityTemplates[Math.floor(Math.random() * attackerEntityTemplates.length)];
    92103    // 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);
     104    let nextTime = Math.round(120000 + Math.random() * 60 * 1000);
    94105    let attackerCount = Math.round(cmpTimer.GetTime() / nextTime / attackerEntities.length);
    95106
    96     // spawn attackers
    97     let attackers =  [];
    98     for (let attackerEntity of attackerEntities)
    99         attackers.push(TriggerHelper.SpawnUnitsFromTriggerPoints("A", attackerEntity, attackerCount, 0));
     107    let attackers = attackerEntities.map(ent =>
     108        TriggerHelper.SpawnUnitsFromTriggerPoints("A", ent, attackerCount, 0));
    100109
    101110    for (let entityType of attackers)
    102111    {
    103112        for (let origin in entityType)
    104113        {
    105114            let cmpPlayer = QueryOwnerInterface(+origin, IID_Player);
    106             if (cmpPlayer.GetState() != "active")
     115            if (!cmpPlayer || !cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()])
    107116                continue;
    108117
    109             let cmpPosition =  Engine.QueryInterface(this.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
    110             // this shouldn't happen if the player is still active
     118            let cmpPosition = Engine.QueryInterface(cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
     119            // This shouldn't happen if the player is still active
    111120            if (!cmpPosition || !cmpPosition.IsInWorld)
    112121                continue;
    113122
    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);
     123            let pos = cmpPosition.GetPosition();
     124            ProcessCommand(0, {
     125                "type": "attack-walk",
     126                "entities": entityType[origin],
     127                "x": pos.x,
     128                "z": pos.z,
     129                "queued": true
     130            });
    122131        }
    123132    }
    124133
    125134    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    126135    cmpGUIInterface.PushNotification({
    Trigger.prototype.StartAnEnemyWave = fun 
    128137        "translateMessage": true
    129138    });
    130139    cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
    131140};
    132141
     142/**
     143 * Find all of the civic centers and females, disable some structures, setup activity watch.
     144 */
    133145Trigger.prototype.InitGame = function()
    134146{
    135147    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
    136     // Find all of the civic centers, disable some structures
    137148    for (let i = 1; i < numberOfPlayers; ++i)
    138149    {
    139150        let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    140151        let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
    141152
     153        let foundSeeker = false;
    142154        for (let entity of playerEntities)
     155        {
    143156            if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
    144157                cmpTrigger.playerCivicCenter[i] = entity;
     158
     159            if (TriggerHelper.EntityHasClass(entity, "Female") && !foundSeeker)
     160            {
     161                foundSeeker = true;
     162                let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
     163                cmpDamageReceiver.SetInvulnerability(true);
     164
     165                let cmpHealth = Engine.QueryInterface(entity, IID_Health);
     166                cmpHealth.SetUndeletable(true);
     167            }
     168        }
    145169    }
    146170
    147171    // Fix alliances
    148172    /* Until we can do something about limiting the victory conditions available for this map to "None"
    149173    for (let i = 1; i < numberOfPlayers; ++i)
    Trigger.prototype.InitGame = function() 
    156180    }*/
    157181
    158182    // Make gaia black
    159183    QueryPlayerIDInterface(0).SetColor(0, 0, 0);
    160184
    161     // Place the treasures
    162185    this.PlaceTreasures();
    163186
    164187    // Disable farms, civic centers and walls for all players
    165188    for (let i = 1; i < numberOfPlayers; ++i)
    166189    {
    167190        let cmpPlayer = QueryPlayerIDInterface(i);
    168191        let civ = cmpPlayer.GetCiv();
     192
    169193        cmpPlayer.SetDisabledTemplates([
    170194            "structures/" + civ + "_field",
    171195            "structures/" + civ + "_corral",
    172196            "structures/" + civ + "_civil_centre",
    173197            "structures/" + civ + "_military_colony",
    Trigger.prototype.PlaceTreasures = funct 
    181205{
    182206    let point = ["B", "C", "D"][Math.floor(Math.random() * 3)];
    183207    let triggerPoints = cmpTrigger.GetTriggerPoints(point);
    184208    for (let point of triggerPoints)
    185209    {
    186         let template = treasures[Math.floor(Math.random() * treasures.length)]
    187         TriggerHelper.SpawnUnits(point, template, 1, 0);
     210        let template = treasures[Math.floor(Math.random() * treasures.length)];
     211        let cmpPosition = Engine.QueryInterface(point, IID_Position);
     212        let ent = Engine.AddEntity(template);
     213
     214        let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
     215        let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
     216
     217        if (cmpEntOwnership)
     218            cmpEntOwnership.SetOwner(0);
     219
     220        let xOffset = RandomInt(0, 23);
     221        let zOffset = RandomInt(0, 23);
     222
     223        if (Math.random() >= 0.8)
     224        {
     225            xOffset += RandomInt(5, 8);
     226            zOffset += RandomInt(5, 8);
     227        }
     228
     229        if (Math.round(Math.random()) == 1)
     230            xOffset = -xOffset;
     231
     232        if (Math.round(Math.random()) == 1)
     233            zOffset = -zOffset;
     234
     235        cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
    188236    }
    189     cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
     237
     238    cmpTrigger.DoAfterDelay((treasureTime + Math.random()) * 60 * 1000, "PlaceTreasures", {});
     239
     240    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     241    cmpGUIInterface.PushNotification({
     242        "message": markForTranslation("New treasures have been placed!"),
     243        "translateMessage": true
     244    });
    190245};
    191246
    192247Trigger.prototype.InitializeEnemyWaves = function()
    193248{
    194249    let time = (5 + Math.round(Math.random() * 10)) * 60 * 1000;
    195250    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     251    cmpGUIInterface.PushNotification({
     252        "message": markForTranslation("Welcome to Survival of the Fittest"),
     253        "translateMessage": true
     254    });
     255    cmpGUIInterface.PushNotification({
     256        "message": markForTranslation("Collect treasures with your woman to prepare for the enemies."),
     257        "translateMessage": true
     258    });
    196259    cmpGUIInterface.AddTimeNotification({
    197260        "message": markForTranslation("The first wave will start in %(time)s!"),
    198261        "translateMessage": true
    199262    }, time);
     263
    200264    cmpTrigger.DoAfterDelay(time, "StartAnEnemyWave", {});
    201265};
    202266
    203267Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
    204268{
    205     // Defeat a player that has lost his civic center
    206     if (data.entity == cmpTrigger.playerCivicCenter[data.from])
    207     {
     269    if (data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
    208270        TriggerHelper.DefeatPlayer(data.from);
     271};
    209272
    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);
     273Trigger.prototype.provideResources = function(data)
     274{
     275    if (!resourceMessage)
     276    {
     277        let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     278        cmpGUIInterface.PushNotification({
     279            "message": markForTranslation("From now on, all players will receive some resources from time to time."),
     280            "translateMessage": true
     281        });
     282        resourceMessage = true;
     283    }
     284
     285    let resources = {};
     286    for (let type of ["food", "wood", "stone", "metal"])
     287        resources[type] = 50 + Math.round(Math.random() * 100);
     288
     289    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
     290    for (let i = 1; i < numberOfPlayers; ++i)
     291    {
     292        let cmpPlayer = QueryPlayerIDInterface(i);
     293        cmpPlayer.AddResources(resources);
    224294    }
     295
     296    cmpTrigger.DoAfterDelay((provideResourcesTime +  Math.random() / 2) * 60 * 1000, "provideResources" , {});
    225297};
    226298
    227299var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
    228300cmpTrigger.playerCivicCenter = {};
     301
    229302cmpTrigger.DoAfterDelay(0, "InitGame", {});
    230303cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
     304cmpTrigger.DoAfterDelay(provideResourcesOffset * 60 * 1000, "provideResources" , {});
    231305
    232306cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });