Ticket #3102: t3102_survival_7b.diff

File t3102_survival_7b.diff, 10.8 KB (added by bb, 3 years ago)

survival part

  • 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 = randFloat(5, 15);
     5
     6/**
     7 * Time after which resources are distributed periodically.
     8 */
     9var provideResourcesOffset = randFloat(14, 16);
     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 interval of resources distributed.
     28 */
     29var resourceAmountInterval = [50, 150];
     30
     31/**
     32 * Amount of miliseconds in minute.
     33 */
     34const minutes = 60 * 1000;
     35
     36var treasures = [
    337    "gaia/special_treasure_food_barrel",
    438    "gaia/special_treasure_food_bin",
    539    "gaia/special_treasure_food_crate",
     
    1044    "gaia/special_treasure_wood",
    1145    "gaia/special_treasure_wood"
    1246];
    13 var attackerEntityTemplates =
    14 [
     47
     48/**
     49 * Templates of the attacking units, sorted by civ
     50 */
     51var attackerTemplates = [
    1552    [
    1653        "units/athen_champion_infantry",
    1754        "units/athen_champion_marine",
    1855        "units/athen_champion_ranged",
    19         "units/athen_siege_lithobolos_packed",
    20         "units/athen_siege_oxybeles_packed",
     56        "units/athen_mechanical_siege_lithobolos_packed",
     57        "units/athen_mechanical_siege_oxybeles_packed",
    2158    ],
    2259    [
    2360        "units/brit_champion_cavalry",
     
    88125Trigger.prototype.StartAnEnemyWave = function()
    89126{
    90127    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);
     128    let templates = attackerTemplates[Math.floor(Math.random() * attackerTemplates.length)];
     129    let nextTime = randFloat(...attackerWaveInterval) * minutes;
     130    let attackerCount = Math.ceil(cmpTimer.GetTime() / nextTime / templates.length);
    95131
    96     // spawn attackers
    97     let attackers =  [];
    98     for (let attackerEntity of attackerEntities)
    99         attackers.push(TriggerHelper.SpawnUnitsFromTriggerPoints("A", attackerEntity, attackerCount, 0));
     132    let attackers = templates.map(ent =>
     133        TriggerHelper.SpawnUnitsFromTriggerPoints("A", ent, attackerCount, 0));
    100134
    101135    for (let entityType of attackers)
    102     {
    103136        for (let origin in entityType)
    104137        {
     138            // Destroy attackers for non active players
    105139            let cmpPlayer = QueryOwnerInterface(+origin, IID_Player);
    106             if (cmpPlayer.GetState() != "active")
     140            if (!cmpPlayer || !cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()])
     141            {
     142                Engine.DestroyEntity(+entityType[origin])
    107143                continue;
     144            }
    108145
    109             let cmpPosition =  Engine.QueryInterface(this.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
    110             // this shouldn't happen if the player is still active
     146            let cmpPosition = Engine.QueryInterface(cmpTrigger.playerCivicCenter[cmpPlayer.GetPlayerID()], IID_Position);
     147            // This shouldn't happen if the player is still active
    111148            if (!cmpPosition || !cmpPosition.IsInWorld)
    112149                continue;
    113150
    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);
     151            let pos = cmpPosition.GetPosition();
     152            ProcessCommand(0, {
     153                "type": "attack-walk",
     154                "entities": entityType[origin],
     155                "x": pos.x,
     156                "z": pos.z,
     157                "targetClasses": undefined,
     158                "queued": true
     159            });
    122160        }
    123     }
    124161
    125162    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    126163    cmpGUIInterface.PushNotification({
     
    127164        "message": markForTranslation("An enemy wave is attacking!"),
    128165        "translateMessage": true
    129166    });
    130     cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {}); // The next wave will come in 3 minutes
     167    cmpTrigger.DoAfterDelay(nextTime, "StartAnEnemyWave", {});
    131168};
    132169
     170/**
     171 * Find all of the civic centers and females, disable some structures, setup activity watch.
     172 */
    133173Trigger.prototype.InitGame = function()
    134174{
    135175    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
    136     // Find all of the civic centers, disable some structures
    137176    for (let i = 1; i < numberOfPlayers; ++i)
    138177    {
    139178        let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    140179        let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
    141180
     181        let foundSeeker = false;
    142182        for (let entity of playerEntities)
     183        {
    143184            if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
    144185                cmpTrigger.playerCivicCenter[i] = entity;
     186
     187            if (TriggerHelper.EntityHasClass(entity, "Female") && !foundSeeker)
     188            {
     189                foundSeeker = true;
     190                let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
     191                cmpDamageReceiver.SetInvulnerability(true);
     192
     193                let cmpHealth = Engine.QueryInterface(entity, IID_Health);
     194                cmpHealth.SetUndeletable(true);
     195            }
     196        }
    145197    }
    146198
    147199    // Fix alliances
     
    158210    // Make gaia black
    159211    QueryPlayerIDInterface(0).SetColor(0, 0, 0);
    160212
    161     // Place the treasures
    162213    this.PlaceTreasures();
    163214
    164215    // Disable farms, civic centers and walls for all players
     
    166217    {
    167218        let cmpPlayer = QueryPlayerIDInterface(i);
    168219        let civ = cmpPlayer.GetCiv();
     220
    169221        cmpPlayer.SetDisabledTemplates([
    170222            "structures/" + civ + "_field",
    171223            "structures/" + civ + "_corral",
     
    172224            "structures/" + civ + "_civil_centre",
    173225            "structures/" + civ + "_military_colony",
    174226            "structures/" + civ + "_wallset_stone",
     227            "structures/brit_crannog",
    175228            "other/wallset_palisade"
    176229        ]);
    177230    }
     
    183236    let triggerPoints = cmpTrigger.GetTriggerPoints(point);
    184237    for (let point of triggerPoints)
    185238    {
    186         let template = treasures[Math.floor(Math.random() * treasures.length)]
    187         TriggerHelper.SpawnUnits(point, template, 1, 0);
     239        let template = treasures[Math.floor(Math.random() * treasures.length)];
     240        let cmpPosition = Engine.QueryInterface(point, IID_Position);
     241        let ent = Engine.AddEntity(template);
     242
     243        let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
     244        let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
     245
     246        if (cmpEntOwnership)
     247            cmpEntOwnership.SetOwner(0);
     248
     249        let xOffset = randInt(0, 23);
     250        let zOffset = randInt(0, 23);
     251
     252        if (Math.random() >= 0.8)
     253        {
     254            xOffset += randInt(5, 8);
     255            zOffset += randInt(5, 8);
     256        }
     257
     258        if (Math.round(Math.random()) == 1)
     259            xOffset = -xOffset;
     260
     261        if (Math.round(Math.random()) == 1)
     262            zOffset = -zOffset;
     263
     264        cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
    188265    }
    189     cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
     266
     267    cmpTrigger.DoAfterDelay(randFloat(...treasureInterval) * minutes, "PlaceTreasures", {});
     268
     269    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     270    cmpGUIInterface.PushNotification({
     271        "message": markForTranslation("New treasures have been placed!"),
     272        "translateMessage": true
     273    });
    190274};
    191275
    192276Trigger.prototype.InitializeEnemyWaves = function()
    193277{
    194     let time = (5 + Math.round(Math.random() * 10)) * 60 * 1000;
    195278    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     279
     280    cmpGUIInterface.PushNotification({
     281        "message": markForTranslation("Welcome to Survival of the Fittest"),
     282        "translateMessage": true
     283    });
     284
     285    cmpGUIInterface.PushNotification({
     286        "message": markForTranslation("Collect treasures with your woman to prepare for the enemies."),
     287        "translateMessage": true
     288    });
     289
     290    let time = firstAttackWave * minutes;
    196291    cmpGUIInterface.AddTimeNotification({
    197292        "message": markForTranslation("The first wave will start in %(time)s!"),
    198293        "translateMessage": true
     
    202297
    203298Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
    204299{
    205     // Defeat a player that has lost his civic center
    206     if (data.entity == cmpTrigger.playerCivicCenter[data.from])
    207     {
     300    if (data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
    208301        TriggerHelper.DefeatPlayer(data.from);
     302};
    209303
    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);
     304Trigger.prototype.ProvideResources = function(data)
     305{
     306    if (data.first)
     307    {
     308        let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     309        cmpGUIInterface.PushNotification({
     310            "message": markForTranslation("From now on, all players will receive some resources from time to time."),
     311            "translateMessage": true
     312        });
    224313    }
     314
     315    let resources = {};
     316    for (let type of ["food", "wood", "stone", "metal"])
     317        resources[type] = randInt(resourceAmountInterval[0], resourceAmountInterval[1]);
     318
     319    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
     320    for (let i = 1; i < numberOfPlayers; ++i)
     321        QueryPlayerIDInterface(i).AddResources(resources);
     322
     323    cmpTrigger.DoAfterDelay(randFloat(...provideResourcesInterval) * minutes, "ProvideResources", {});
    225324};
    226325
    227326var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
    228327cmpTrigger.playerCivicCenter = {};
     328
    229329cmpTrigger.DoAfterDelay(0, "InitGame", {});
    230330cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
     331cmpTrigger.DoAfterDelay(provideResourcesOffset * minutes, "ProvideResources", { "first": true });
    231332
    232333cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });