Ticket #3102: t3102_survival_6.2.diff

File t3102_survival_6.2.diff, 18.7 KB (added by bb, 3 years ago)
  • binaries/data/mods/public/globalscripts/random.js

     
     1// TODO: rename/change these functions, so the bounds are more clear
     2
     3/*
     4 * Return a random floating point number using Math.random library
     5 *
     6 * If no parameter given, the returned float is in the interval [0, 1)
     7 * If one parameter given, it's maxval, and the returned float is in the interval [0, maxval)
     8 * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
     9 */
     10function randFloat()
     11{
     12    if (arguments.length == 0)
     13        return Math.random();
     14    else if (arguments.length == 1)
     15        return randFloat() * arguments[0];
     16    else if (arguments.length == 2)
     17    {
     18        let minVal = arguments[0];
     19        let maxVal = arguments[1];
     20        return minVal + randFloat() * (maxVal - minVal);
     21    }
     22    else
     23    {
     24        error("randFloat: invalid number of arguments: "+arguments.length);
     25        return undefined;
     26    }
     27}
     28
     29/*
     30 * Return a random integer using Math.random library
     31 *
     32 * If no parameter given, the returned integer is in the interval [0, 1]
     33 * If one parameter given, it's maxval, and the returned integer is in the interval [0, maxval)
     34 * If two parameters are given, they are minval and maxval, and the returned integer is in the interval [minval, maxval)
     35 */
     36function randInt()
     37{
     38    if (arguments.length == 0)
     39        return Math.round(randFloat());
     40    else if (arguments.length == 1)
     41        return Math.floor(randFloat(arguments[0]));
     42    else if (arguments.length == 2)
     43        return Math.floor(randFloat(arguments[0], arguments[1]));
     44    else
     45    {
     46        error("randInt: invalid number of arguments: "+arguments.length);
     47        return undefined;
     48    }
     49}
  • binaries/data/mods/public/gui/common/functions_utility.js

     
    33 */
    44var g_LastNickNotification = -1;
    55
    6 function getRandom(randomMin, randomMax)
    7 {
    8     // Returns a random whole number in a min..max range.
    9     // NOTE: There should probably be an engine function for this,
    10     // since we'd need to keep track of random seeds for replays.
    11 
    12     var randomNum = randomMin + (randomMax-randomMin)*Math.random();  // num is random, from A to B
    13     return Math.round(randomNum);
    14 }
    15 
    166// Get list of XML files in pathname with recursion, excepting those starting with _
    177function getXMLFileList(pathname)
    188{
  • binaries/data/mods/public/gui/common/music.js

     
    132132
    133133Music.prototype.getRandomTrack = function(tracks)
    134134{
    135     return tracks[getRandom(0, tracks.length-1)];
     135    return tracks[randInt(0, tracks.length)];
    136136};
    137137
    138138Music.prototype.startPlayList = function(tracks, fadeInPeriod, isLooping)
  • binaries/data/mods/public/gui/loading/loading.js

     
    1414    if (tipTextLoadingArray.length > 0)
    1515    {
    1616        // Set tip text
    17         let tipTextFilePath = tipTextLoadingArray[getRandom(0, tipTextLoadingArray.length-1)];
     17        let tipTextFilePath = tipTextLoadingArray[randInt(0, tipTextLoadingArray.length)];
    1818        let tipText = Engine.TranslateLines(Engine.ReadFile(tipTextFilePath));
    1919
    2020        if (tipText)
     
    6363
    6464    // Pick a random quote of the day (each line is a separate tip).
    6565    let quoteArray = Engine.ReadFileLines("gui/text/quotes.txt");
    66     Engine.GetGUIObjectByName("quoteText").caption = translate(quoteArray[getRandom(0, quoteArray.length-1)]);
     66    Engine.GetGUIObjectByName("quoteText").caption = translate(quoteArray[randInt(0, quoteArray.length)]);
    6767}
    6868
    6969function displayProgress()
  • binaries/data/mods/public/maps/random/rmgen/random.js

     
    1 // TODO: rename/change these functions, so the bounds are more clear
    2 
    3 /*
    4  * Return a random floating point number using Math.random library
    5  *
    6  * If no parameter given, the returned float is in the interval [0, 1)
    7  * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval)
    8  */
    9 function randFloat()
    10 {
    11     if (arguments.length == 0)
    12     {
    13         return Math.random();
    14     }
    15     else if (arguments.length == 2)
    16     {
    17         var minVal = arguments[0];
    18         var maxVal = arguments[1];
    19        
    20         return minVal + randFloat() * (maxVal - minVal);
    21     }
    22     else
    23     {
    24         error("randFloat: invalid number of arguments: "+arguments.length);
    25         return undefined;
    26     }
    27 }
    28 
    29 /*
    30  * Return a random integer using Math.random library
    31  *
    32  * If one parameter given, it's maxval, and the returned integer is in the interval [0, maxval)
    33  * If two parameters are given, they are minval and maxval, and the returned integer is in the interval [minval, maxval]
    34  */
    35 function randInt()
    36 {   
    37     if (arguments.length == 1)
    38     {
    39         var maxVal = arguments[0];
    40         return Math.floor(Math.random() * maxVal);
    41     }
    42     else if (arguments.length == 2)
    43     {
    44         var minVal = arguments[0];
    45         var maxVal = arguments[1];
    46        
    47         return minVal + randInt(maxVal - minVal + 1);
    48     }
    49     else
    50     {
    51         error("randInt: invalid number of arguments: "+arguments.length);
    52         return undefined;
    53     }
    54 }
  • binaries/data/mods/public/maps/random/survivalofthefittest.js

    Property changes on: binaries/data/mods/public/maps/random/rmgen/random.js
    ___________________________________________________________________
    Deleted: svn:eol-style
    ## -1 +0,0 ##
    -native
    \ No newline at end of property
     
    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, 15];
     5
     6/**
     7 * Time after which resources are distributed periodically.
     8 */
     9var provideResourcesOffset = [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[0], attackerWaveInterval[1]) * 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{
     175    // Set random offset on consts
     176    firstAttackWave = randFloat(firstAttackWave[0], firstAttackWave[1]);
     177    provideResourcesOffset = randFloat(provideResourcesOffset[0], provideResourcesOffset[1]);
     178
    135179    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
    136     // Find all of the civic centers, disable some structures
    137180    for (let i = 1; i < numberOfPlayers; ++i)
    138181    {
    139182        let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    140183        let playerEntities = cmpRangeManager.GetEntitiesByPlayer(i); // Get all of each player's entities
    141184
     185        let foundSeeker = false;
    142186        for (let entity of playerEntities)
     187        {
    143188            if (TriggerHelper.EntityHasClass(entity, "CivilCentre"))
    144189                cmpTrigger.playerCivicCenter[i] = entity;
     190
     191            if (TriggerHelper.EntityHasClass(entity, "Female") && !foundSeeker)
     192            {
     193                foundSeeker = true;
     194                let cmpDamageReceiver = Engine.QueryInterface(entity, IID_DamageReceiver);
     195                cmpDamageReceiver.SetInvulnerability(true);
     196
     197                let cmpHealth = Engine.QueryInterface(entity, IID_Health);
     198                cmpHealth.SetUndeletable(true);
     199            }
     200        }
    145201    }
    146202
    147203    // Fix alliances
     
    158214    // Make gaia black
    159215    QueryPlayerIDInterface(0).SetColor(0, 0, 0);
    160216
    161     // Place the treasures
    162217    this.PlaceTreasures();
    163218
    164219    // Disable farms, civic centers and walls for all players
     
    166221    {
    167222        let cmpPlayer = QueryPlayerIDInterface(i);
    168223        let civ = cmpPlayer.GetCiv();
     224
    169225        cmpPlayer.SetDisabledTemplates([
    170226            "structures/" + civ + "_field",
    171227            "structures/" + civ + "_corral",
     
    172228            "structures/" + civ + "_civil_centre",
    173229            "structures/" + civ + "_military_colony",
    174230            "structures/" + civ + "_wallset_stone",
     231            "structures/brit_crannog",
    175232            "other/wallset_palisade"
    176233        ]);
    177234    }
     
    183240    let triggerPoints = cmpTrigger.GetTriggerPoints(point);
    184241    for (let point of triggerPoints)
    185242    {
    186         let template = treasures[Math.floor(Math.random() * treasures.length)]
    187         TriggerHelper.SpawnUnits(point, template, 1, 0);
     243        let template = treasures[Math.floor(Math.random() * treasures.length)];
     244        let cmpPosition = Engine.QueryInterface(point, IID_Position);
     245        let ent = Engine.AddEntity(template);
     246
     247        let cmpEntOwnership = Engine.QueryInterface(ent, IID_Ownership);
     248        let cmpEntPosition = Engine.QueryInterface(ent, IID_Position);
     249
     250        if (cmpEntOwnership)
     251            cmpEntOwnership.SetOwner(0);
     252
     253        let xOffset = randInt(0, 23);
     254        let zOffset = randInt(0, 23);
     255
     256        if (Math.random() >= 0.8)
     257        {
     258            xOffset += randInt(5, 8);
     259            zOffset += randInt(5, 8);
     260        }
     261
     262        if (Math.round(Math.random()) == 1)
     263            xOffset = -xOffset;
     264
     265        if (Math.round(Math.random()) == 1)
     266            zOffset = -zOffset;
     267
     268        cmpEntPosition.JumpTo(cmpPosition.GetPosition().x + xOffset, cmpPosition.GetPosition().z - zOffset);
    188269    }
    189     cmpTrigger.DoAfterDelay(4*60*1000, "PlaceTreasures", {}); //Place more treasures after 4 minutes
     270
     271    cmpTrigger.DoAfterDelay(randFloat(treasureInterval[0], treasureInterval[1]) * minutes, "PlaceTreasures", {});
     272
     273    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     274    cmpGUIInterface.PushNotification({
     275        "message": markForTranslation("New treasures have been placed!"),
     276        "translateMessage": true
     277    });
    190278};
    191279
    192280Trigger.prototype.InitializeEnemyWaves = function()
    193281{
    194     let time = (5 + Math.round(Math.random() * 10)) * 60 * 1000;
    195282    let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     283
     284    cmpGUIInterface.PushNotification({
     285        "message": markForTranslation("Welcome to Survival of the Fittest"),
     286        "translateMessage": true
     287    });
     288
     289    cmpGUIInterface.PushNotification({
     290        "message": markForTranslation("Collect treasures with your woman to prepare for the enemies."),
     291        "translateMessage": true
     292    });
     293
     294    let time = firstAttackWave * minutes;
    196295    cmpGUIInterface.AddTimeNotification({
    197296        "message": markForTranslation("The first wave will start in %(time)s!"),
    198297        "translateMessage": true
     
    202301
    203302Trigger.prototype.DefeatPlayerOnceCCIsDestroyed = function(data)
    204303{
    205     // Defeat a player that has lost his civic center
    206     if (data.entity == cmpTrigger.playerCivicCenter[data.from])
    207     {
     304    if (data.entity == cmpTrigger.playerCivicCenter[data.from] && data.to == -1)
    208305        TriggerHelper.DefeatPlayer(data.from);
     306};
    209307
    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);
     308Trigger.prototype.ProvideResources = function(data)
     309{
     310    if (data.first)
     311    {
     312        let cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     313        cmpGUIInterface.PushNotification({
     314            "message": markForTranslation("From now on, all players will receive some resources from time to time."),
     315            "translateMessage": true
     316        });
    224317    }
     318
     319    let resources = {};
     320    for (let type of ["food", "wood", "stone", "metal"])
     321        resources[type] = randInt(resourceAmountInterval[0], resourceAmountInterval[1]);
     322
     323    let numberOfPlayers = TriggerHelper.GetNumberOfPlayers();
     324    for (let i = 1; i < numberOfPlayers; ++i)
     325        QueryPlayerIDInterface(i).AddResources(resources);
     326
     327    cmpTrigger.DoAfterDelay(randFloat(provideResourcesInterval[0], provideResourcesInterval[1]) * minutes, "ProvideResources", {});
    225328};
    226329
    227330var cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
    228331cmpTrigger.playerCivicCenter = {};
     332
    229333cmpTrigger.DoAfterDelay(0, "InitGame", {});
    230334cmpTrigger.DoAfterDelay(1000, "InitializeEnemyWaves", {});
     335cmpTrigger.DoAfterDelay(provideResourcesOffset * minutes, "ProvideResources", { "first": true });
    231336
    232337cmpTrigger.RegisterTrigger("OnOwnershipChanged", "DefeatPlayerOnceCCIsDestroyed", { "enabled": true });
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    31153115                this.SelectAnimation("walk", false, this.GetWalkSpeed());
    31163116                this.MoveRandomly(+this.template.RoamDistance);
    31173117                // Set a random timer to switch to feeding state
    3118                 this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
     3118                this.StartTimer(randInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax));
    31193119                this.SetFacePointAfterMove(false);
    31203120            },
    31213121
     
    31603160                // Stop and eat for a while
    31613161                this.SelectAnimation("feeding");
    31623162                this.StopMoving();
    3163                 this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
     3163                this.StartTimer(randInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax));
    31643164            },
    31653165
    31663166            "leave": function() {
  • binaries/data/mods/public/simulation/helpers/Random.js

     
    1 /**
    2  * Returns a random integer from min (inclusive) to max (exclusive)
    3  */
    4 function RandomInt(min, max)
    5 {
    6     return Math.floor(min + Math.random() * (max-min));
    7 }
    8 
    9 Engine.RegisterGlobal("RandomInt", RandomInt);