From 08fbf223f682a0fc8fe9259f2931ea71b9b26e34 Mon Sep 17 00:00:00 2001 From: elexis Date: Fri, 3 Mar 2017 21:13:10 +0000 Subject: [PATCH] Unify random integer and float helper functions of GUI, Simulation and AI. Patch By: bb Differential Revision: D121 Refs: #4326 Removes the Random.js simulation helper and randomFloat function of the random map scripts library. Adds randomIntInclusive and randomIntExclusive to make the calls more readable and fix and prevent off-by-one mistakes. Adds randBool and use it in an AI occurance. It will be used in many places by the random map scripts. Use the pickRandom function introduced in 3c56638e8b in more applicable occurances. Replace remaining occurances of Math.random() with the new functions to easily test completeness. Cleanup of the random map script functions will come in a separate commit. This was SVN commit r19270. --- .../data/mods/public/globalscripts/random.js | 43 ++++++++++++++++++- .../data/mods/public/globalscripts/utility.js | 2 +- .../public/gui/common/functions_utility.js | 10 ----- binaries/data/mods/public/gui/common/music.js | 7 +-- .../mods/public/gui/gamesetup/gamesetup.js | 14 +++--- .../data/mods/public/gui/loading/loading.js | 4 +- .../data/mods/public/gui/pregame/mainmenu.js | 25 ++++++----- .../data/mods/public/gui/session/placement.js | 2 +- .../data/mods/public/gui/session/session.js | 2 +- .../mods/public/maps/random/rmgen/random.js | 26 ----------- .../public/simulation/ai/petra/attackPlan.js | 8 ++-- .../mods/public/simulation/ai/petra/config.js | 6 +-- .../simulation/ai/petra/diplomacyManager.js | 6 +-- .../simulation/ai/petra/headquarters.js | 10 ++--- .../simulation/ai/petra/researchManager.js | 4 +- .../simulation/components/BuildingAI.js | 2 +- .../public/simulation/components/Formation.js | 12 ++---- .../public/simulation/components/Player.js | 2 +- .../public/simulation/components/UnitAI.js | 8 ++-- .../mods/public/simulation/helpers/Random.js | 9 ---- .../public/simulation/helpers/WeightedList.js | 6 +-- 21 files changed, 97 insertions(+), 111 deletions(-) delete mode 100644 binaries/data/mods/public/simulation/helpers/Random.js diff --git a/binaries/data/mods/public/globalscripts/random.js b/binaries/data/mods/public/globalscripts/random.js index 7c9af9bc3e..29c6d169a9 100644 --- a/binaries/data/mods/public/globalscripts/random.js +++ b/binaries/data/mods/public/globalscripts/random.js @@ -16,9 +16,50 @@ function randomNormal2D() } /** - * Return a random element of the source array + * Return a random element of the source array. */ function pickRandom(source) { return source.length ? source[Math.floor(source.length * Math.random())] : undefined; } + +/** + * Return a random floating point number. + * + * If two parameters are given, and the returned float is in the interval [min, max). + * If no parameter is given, the returned float is in the interval [0, 1). + */ +function randFloat(min = 0, max = 1) +{ + return min + Math.random() * (max - min); +} + +/** + * Return a random integer of the interval [floor(min) .. ceil(max)] using Math.random library. + * + * If an argument is not integer, the uniform distribution is cut off at that endpoint. + * For example randIntInclusive(1.5, 2.5) yields 50% chance to get 2 and 25% chance for 1 and 3. + */ +function randIntInclusive(min, max) +{ + return Math.floor(min + Math.random() * (max + 1 - min)); +} + +/** + * Return a random integer of the interval [floor(min) .. ceil(max-1)]. + * + * If an argument is not integer, the uniform distribution is cut off at that endpoint. + * For example randIntExclusive(1.5, 3.5) yields 50% chance to get 2 and 25% chance for 1 and 3. + */ +function randIntExclusive(min, max) +{ + return Math.floor(min + Math.random() * (max - min)); +} + +/** + * Returns true or false randomly. + */ +function randBool() +{ + return Math.random() < 0.5; +} diff --git a/binaries/data/mods/public/globalscripts/utility.js b/binaries/data/mods/public/globalscripts/utility.js index cb854d1761..dea0a6ef22 100644 --- a/binaries/data/mods/public/globalscripts/utility.js +++ b/binaries/data/mods/public/globalscripts/utility.js @@ -28,7 +28,7 @@ function shuffleArray(source) let result = [source[0]]; for (let i = 1; i < source.length; ++i) { - let j = Math.floor(Math.random() * (i+1)); + let j = randIntInclusive(0, i); result[i] = result[j]; result[j] = source[i]; } diff --git a/binaries/data/mods/public/gui/common/functions_utility.js b/binaries/data/mods/public/gui/common/functions_utility.js index e93770ce0a..991fbd0904 100644 --- a/binaries/data/mods/public/gui/common/functions_utility.js +++ b/binaries/data/mods/public/gui/common/functions_utility.js @@ -3,16 +3,6 @@ */ var g_LastNickNotification = -1; -function getRandom(randomMin, randomMax) -{ - // Returns a random whole number in a min..max range. - // NOTE: There should probably be an engine function for this, - // since we'd need to keep track of random seeds for replays. - - var randomNum = randomMin + (randomMax-randomMin)*Math.random(); // num is random, from A to B - return Math.round(randomNum); -} - // Get list of XML files in pathname with recursion, excepting those starting with _ function getXMLFileList(pathname) { diff --git a/binaries/data/mods/public/gui/common/music.js b/binaries/data/mods/public/gui/common/music.js index 1f45471d73..44e8532762 100644 --- a/binaries/data/mods/public/gui/common/music.js +++ b/binaries/data/mods/public/gui/common/music.js @@ -79,7 +79,7 @@ Music.prototype.updateState = function() break; case this.states.MENU: - this.switchMusic(this.getRandomTrack(this.tracks.MENU), 0.0, true); + this.switchMusic(pickRandom(this.tracks.MENU), 0, true); break; case this.states.PEACE: @@ -130,11 +130,6 @@ Music.prototype.storeTracks = function(civMusic) } }; -Music.prototype.getRandomTrack = function(tracks) -{ - return tracks[getRandom(0, tracks.length-1)]; -}; - Music.prototype.startPlayList = function(tracks, fadeInPeriod, isLooping) { Engine.ClearPlaylist(); diff --git a/binaries/data/mods/public/gui/gamesetup/gamesetup.js b/binaries/data/mods/public/gui/gamesetup/gamesetup.js index 40c4d97687..4ddc770a2d 100644 --- a/binaries/data/mods/public/gui/gamesetup/gamesetup.js +++ b/binaries/data/mods/public/gui/gamesetup/gamesetup.js @@ -1298,8 +1298,7 @@ function launchGame() { let victoryScriptsSelected = g_GameAttributes.settings.VictoryScripts; let gameTypeSelected = g_GameAttributes.settings.GameType; - selectMap(Engine.GetGUIObjectByName("mapSelection").list_data[Math.floor(Math.random() * - (Engine.GetGUIObjectByName("mapSelection").list.length - 1)) + 1]); + selectMap(pickRandom(Engine.GetGUIObjectByName("mapSelection").list_data.slice(1))); g_GameAttributes.settings.VictoryScripts = victoryScriptsSelected; g_GameAttributes.settings.GameType = gameTypeSelected; } @@ -1322,9 +1321,8 @@ function launchGame() let chosenCiv = g_GameAttributes.settings.PlayerData[i].Civ || "random"; if (chosenCiv == "random") { - let culture = cultures[Math.floor(Math.random() * cultures.length)]; - let civs = Object.keys(g_CivData).filter(civ => g_CivData[civ].Culture == culture); - chosenCiv = civs[Math.floor(Math.random() * civs.length)]; + let culture = pickRandom(cultures); + chosenCiv = pickRandom(Object.keys(g_CivData).filter(civ => g_CivData[civ].Culture == culture)); } g_GameAttributes.settings.PlayerData[i].Civ = chosenCiv; @@ -1332,7 +1330,7 @@ function launchGame() if (g_GameAttributes.mapType === "scenario" || !g_GameAttributes.settings.PlayerData[i].AI) continue; - let chosenName = g_CivData[chosenCiv].AINames[Math.floor(Math.random() * g_CivData[chosenCiv].AINames.length)]; + let chosenName = pickRandom(g_CivData[chosenCiv].AINames); if (!g_IsNetworked) chosenName = translate(chosenName); @@ -1352,8 +1350,8 @@ function launchGame() } // Seed used for both map generation and simulation - g_GameAttributes.settings.Seed = Math.floor(Math.random() * Math.pow(2, 32)); - g_GameAttributes.settings.AISeed = Math.floor(Math.random() * Math.pow(2, 32)); + g_GameAttributes.settings.Seed = randIntExclusive(0, Math.pow(2, 32)); + g_GameAttributes.settings.AISeed = randIntExclusive(0, Math.pow(2, 32)); // Used for identifying rated game reports for the lobby g_GameAttributes.matchID = Engine.GetMatchID(); diff --git a/binaries/data/mods/public/gui/loading/loading.js b/binaries/data/mods/public/gui/loading/loading.js index 24e8aa4db6..826301b7c3 100644 --- a/binaries/data/mods/public/gui/loading/loading.js +++ b/binaries/data/mods/public/gui/loading/loading.js @@ -13,7 +13,7 @@ function init(data) if (tipTextLoadingArray.length > 0) { // Set tip text - let tipTextFilePath = tipTextLoadingArray[getRandom(0, tipTextLoadingArray.length-1)]; + let tipTextFilePath = pickRandom(tipTextLoadingArray); let tipText = Engine.TranslateLines(Engine.ReadFile(tipTextFilePath)); if (tipText) @@ -62,7 +62,7 @@ function init(data) // Pick a random quote of the day (each line is a separate tip). let quoteArray = Engine.ReadFileLines("gui/text/quotes.txt"); - Engine.GetGUIObjectByName("quoteText").caption = translate(quoteArray[getRandom(0, quoteArray.length-1)]); + Engine.GetGUIObjectByName("quoteText").caption = translate(pickRandom(quoteArray)); } function displayProgress() diff --git a/binaries/data/mods/public/gui/pregame/mainmenu.js b/binaries/data/mods/public/gui/pregame/mainmenu.js index 37b1204cbc..a1ec09ec63 100644 --- a/binaries/data/mods/public/gui/pregame/mainmenu.js +++ b/binaries/data/mods/public/gui/pregame/mainmenu.js @@ -1,11 +1,19 @@ var userReportEnabledText; // contains the original version with "$status" placeholder var currentSubmenuType; // contains submenu type const MARGIN = 4; // menu border size -var g_BackgroundCode; // Background type. var g_ShowSplashScreens; + +/** + * Available backdrops + */ var g_BackgroundLayerData = []; +/** + * Chosen backdrop + */ +var g_BackgroundLayerset; + var g_T0 = +(new Date()); var g_LastTickTime = new Date(); @@ -26,13 +34,12 @@ function init(initData, hotloadData) g_ShowSplashScreens = hotloadData ? hotloadData.showSplashScreens : initData && initData.isStartup; // Pick a random background and initialise it - g_BackgroundCode = Math.floor(Math.random() * g_BackgroundLayerData.length); - var layerset = g_BackgroundLayerData[g_BackgroundCode]; - for (var i = 0; i < layerset.length; ++i) + g_BackgroundLayerset = pickRandom(g_BackgroundLayerData); + for (let i = 0; i < g_BackgroundLayerset.length; ++i) { var guiObj = Engine.GetGUIObjectByName("background["+i+"]"); guiObj.hidden = false; - guiObj.sprite = layerset[i].sprite; + guiObj.sprite = g_BackgroundLayerset[i].sprite; guiObj.z = i; } } @@ -44,10 +51,8 @@ function getHotloadData() function scrollBackgrounds() { - var layerset = g_BackgroundLayerData[g_BackgroundCode]; - for (var i = 0; i < layerset.length; ++i) + for (let i = 0; i < g_BackgroundLayerset.length; ++i) { - var layer = layerset[i]; var guiObj = Engine.GetGUIObjectByName("background["+i+"]"); var screen = guiObj.parent.getComputedSize(); @@ -56,8 +61,8 @@ function scrollBackgrounds() var iw = h * 2; var time = (new Date() - g_T0) / 1000; - var offset = layer.offset(time, w); - if (layer.tiling) + var offset = g_BackgroundLayerset[i].offset(time, w); + if (g_BackgroundLayerset[i].tiling) { var left = offset % iw; if (left >= 0) diff --git a/binaries/data/mods/public/gui/session/placement.js b/binaries/data/mods/public/gui/session/placement.js index 3ebc3965c5..95be00ff60 100644 --- a/binaries/data/mods/public/gui/session/placement.js +++ b/binaries/data/mods/public/gui/session/placement.js @@ -36,7 +36,7 @@ PlacementSupport.prototype.SetDefaultAngle = function() PlacementSupport.prototype.RandomizeActorSeed = function() { - this.actorSeed = Math.floor(65535 * Math.random()); + this.actorSeed = randIntExclusive(0, Math.pow(2, 16)); }; var placementSupport = new PlacementSupport(); diff --git a/binaries/data/mods/public/gui/session/session.js b/binaries/data/mods/public/gui/session/session.js index 2d0e1c9109..63d707d0d8 100644 --- a/binaries/data/mods/public/gui/session/session.js +++ b/binaries/data/mods/public/gui/session/session.js @@ -1257,7 +1257,7 @@ function updateAdditionalHighlight() function playAmbient() { - Engine.PlayAmbientSound(g_Ambient[Math.floor(Math.random() * g_Ambient.length)], true); + Engine.PlayAmbientSound(pickRandom(g_Ambient), true); } function getBuildString() diff --git a/binaries/data/mods/public/maps/random/rmgen/random.js b/binaries/data/mods/public/maps/random/rmgen/random.js index 3ece081dd8..b22ddfacfc 100644 --- a/binaries/data/mods/public/maps/random/rmgen/random.js +++ b/binaries/data/mods/public/maps/random/rmgen/random.js @@ -1,31 +1,5 @@ // TODO: rename/change these functions, so the bounds are more clear -/* - * Return a random floating point number using Math.random library - * - * If no parameter given, the returned float is in the interval [0, 1) - * If two parameters are given, they are minval and maxval, and the returned float is in the interval [minval, maxval) - */ -function randFloat() -{ - if (arguments.length == 0) - { - return Math.random(); - } - else if (arguments.length == 2) - { - var minVal = arguments[0]; - var maxVal = arguments[1]; - - return minVal + randFloat() * (maxVal - minVal); - } - else - { - error("randFloat: invalid number of arguments: "+arguments.length); - return undefined; - } -} - /* * Return a random integer using Math.random library * diff --git a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js index 6ebe9f63b9..f96864011c 100644 --- a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js +++ b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js @@ -158,7 +158,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data) } // Put some randomness on the attack size - let variation = 0.8 + 0.4*Math.random(); + let variation = randFloat(0.8, 1.2); // and lower priority and smaller sizes for easier difficulty levels if (this.Config.difficulty < 2) { @@ -1444,7 +1444,7 @@ m.AttackPlan.prototype.update = function(gameState, events) ent.attack(mStruct[0].id(), m.allowCapture(gameState, ent, mStruct[0])); else { - let rand = Math.floor(Math.random() * mStruct.length * 0.2); + let rand = randIntExclusive(0, mStruct.length * 0.2); ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand])); } } @@ -1502,7 +1502,7 @@ m.AttackPlan.prototype.update = function(gameState, events) valb -= 20000; return valb - vala; }); - let rand = Math.floor(Math.random() * mUnit.length * 0.1); + let rand = randIntExclusive(0, mUnit.length * 0.1); ent.attack(mUnit[rand].id(), m.allowCapture(gameState, ent, mUnit[rand])); } else if (this.isBlocked) @@ -1553,7 +1553,7 @@ m.AttackPlan.prototype.update = function(gameState, events) ent.attack(mStruct[0].id(), false); else { - let rand = Math.floor(Math.random() * mStruct.length * 0.2); + let rand = randIntExclusive(0, mStruct.length * 0.2); ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand])); } } diff --git a/binaries/data/mods/public/simulation/ai/petra/config.js b/binaries/data/mods/public/simulation/ai/petra/config.js index dfd931b22a..b22f492554 100644 --- a/binaries/data/mods/public/simulation/ai/petra/config.js +++ b/binaries/data/mods/public/simulation/ai/petra/config.js @@ -131,9 +131,9 @@ m.Config.prototype.setConfig = function(gameState) // initialize personality traits if (this.difficulty > 1) { - this.personality.aggressive = Math.random(); - this.personality.cooperative = Math.random(); - this.personality.defensive = Math.random(); + this.personality.aggressive = randFloat(0, 1); + this.personality.cooperative = randFloat(0, 1); + this.personality.defensive = randFloat(0, 1); } else { diff --git a/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js b/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js index 1ea965ebb5..434cbe1897 100644 --- a/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js @@ -216,7 +216,7 @@ m.DiplomacyManager.prototype.lastManStandingCheck = function(gameState) // wait a bit before turning if (!this.waitingToBetray) { - this.betrayLapseTime = gameState.ai.elapsedTime + Math.random() * 100 + 10; + this.betrayLapseTime = gameState.ai.elapsedTime + randFloat(10, 110); this.waitingToBetray = true; return; } @@ -277,7 +277,7 @@ m.DiplomacyManager.prototype.handleDiplomacyRequest = function(gameState, player let moreEnemiesThanAllies = gameState.getEnemies().length > gameState.getMutualAllies().length; // For any given diplomacy request be likely to permanently decline - if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && Math.random() > 0.4 || + if (!request && gameState.getPlayerCiv() !== gameState.getPlayerCiv(player) && randFloat(0, 1) > 0.4 || !moreEnemiesThanAllies || gameState.ai.HQ.attackManager.currentEnemyPlayer === player) { this.diplomacyRequests.set(player, { "requestType": requestType, "status": "declinedRequest" }); @@ -296,7 +296,7 @@ m.DiplomacyManager.prototype.handleDiplomacyRequest = function(gameState, player } } else if (requestType === "ally" && gameState.getEntities(player).length < gameState.getOwnEntities().length && - Math.random() > 0.6 || requestType === "neutral" && moreEnemiesThanAllies && Math.random() > 0.2) + randFloat(0, 1) > 0.6 || requestType === "neutral" && moreEnemiesThanAllies && randFloat(0, 1) > 0.2) { response = "accept"; this.changePlayerDiplomacy(gameState, player, requestType); diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index a0bc23ab36..dcf7f1cf7a 100644 --- a/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -504,12 +504,8 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues) requirements = [ ["strength", 1] ]; let classes = ["CitizenSoldier", "Infantry"]; - let proba = Math.random(); - // we require at least 30% ranged and 30% melee - if ( proba < 0.3 ) - classes.push("Ranged"); - else if ( proba < 0.6 ) - classes.push("Melee"); + // We want at least 33% ranged and 33% melee + classes.push(pickRandom(["Ranged", "Melee", "Infantry"])); template = this.findBestTrainableUnit(gameState, classes, requirements); } @@ -1770,7 +1766,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions) } let autogarrison = numGarrisoned < nearestAnchor.garrisonMax() && nearestAnchor.hitpoints() > nearestAnchor.garrisonEjectHealth() * nearestAnchor.maxHitpoints(); - let rangedWanted = Math.random() > 0.5 && autogarrison; + let rangedWanted = randBool() && autogarrison; let total = gameState.getResources(); let templateFound; diff --git a/binaries/data/mods/public/simulation/ai/petra/researchManager.js b/binaries/data/mods/public/simulation/ai/petra/researchManager.js index 7fedfa16d4..7a90947d03 100644 --- a/binaries/data/mods/public/simulation/ai/petra/researchManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/researchManager.js @@ -235,9 +235,9 @@ m.ResearchManager.prototype.update = function(gameState, queues) } if (!techs.length) return; + // randomly pick one. No worries about pairs in that case. - let p = Math.floor(Math.random()*techs.length); - queues.minorTech.addPlan(new m.ResearchPlan(gameState, techs[p][0])); + queues.minorTech.addPlan(new m.ResearchPlan(gameState, pickRandom(techs)[0])); }; m.ResearchManager.prototype.CostSum = function(cost) diff --git a/binaries/data/mods/public/simulation/components/BuildingAI.js b/binaries/data/mods/public/simulation/components/BuildingAI.js index efacf79c5f..7869a99cfb 100644 --- a/binaries/data/mods/public/simulation/components/BuildingAI.js +++ b/binaries/data/mods/public/simulation/components/BuildingAI.js @@ -300,7 +300,7 @@ BuildingAI.prototype.FireArrows = function() arrowsToFire = this.arrowsLeft; else arrowsToFire = Math.min( - Math.round(2 * Math.random() * this.GetArrowCount() / roundCount), + randIntInclusive(0, 2 * this.GetArrowCount() / roundCount), this.arrowsLeft ); diff --git a/binaries/data/mods/public/simulation/components/Formation.js b/binaries/data/mods/public/simulation/components/Formation.js index d80e755aa4..4d2303c521 100644 --- a/binaries/data/mods/public/simulation/components/Formation.js +++ b/binaries/data/mods/public/simulation/components/Formation.js @@ -667,7 +667,7 @@ Formation.prototype.ComputeFormationOffsets = function(active, positions) for (var i = 0; i < count; ++i) { - var obj = new Vector2D(Math.random()*width, Math.random()*width); + var obj = new Vector2D(randFloat(0, width), randFloat(0, width)); obj.row = 1; obj.column = i + 1; offsets.push(obj); @@ -720,13 +720,9 @@ Formation.prototype.ComputeFormationOffsets = function(active, positions) x += side * centerGap / 2; } var column = Math.ceil(n/2) + Math.ceil(c/2) * side; - var r1 = 0; - var r2 = 0; - if (this.sloppyness != 0) - { - r1 = (Math.random() * 2 - 1) * this.sloppyness; - r2 = (Math.random() * 2 - 1) * this.sloppyness; - } + var r1 = randFloat(-1, 1) * this.sloppyness; + var r2 = randFloat(-1, 1) * this.sloppyness; + offsets.push(new Vector2D(x + r1, z + r2)); offsets[offsets.length - 1].row = r+1; offsets[offsets.length - 1].column = column; diff --git a/binaries/data/mods/public/simulation/components/Player.js b/binaries/data/mods/public/simulation/components/Player.js index 1c017bc309..58771fad68 100644 --- a/binaries/data/mods/public/simulation/components/Player.js +++ b/binaries/data/mods/public/simulation/components/Player.js @@ -308,7 +308,7 @@ Player.prototype.TrySubtractResources = function(amounts) Player.prototype.GetNextTradingGoods = function() { - var value = 100*Math.random(); + var value = randFloat(0, 100); var last = this.tradingGoods.length - 1; var sumProba = 0; for (var i = 0; i < last; ++i) diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index 1ede2f69b8..a6cee5e991 100644 --- a/binaries/data/mods/public/simulation/components/UnitAI.js +++ b/binaries/data/mods/public/simulation/components/UnitAI.js @@ -3225,7 +3225,7 @@ UnitAI.prototype.UnitFsmSpec = { this.SelectAnimation("walk", false, this.GetWalkSpeed()); this.MoveRandomly(+this.template.RoamDistance); // Set a random timer to switch to feeding state - this.StartTimer(RandomInt(+this.template.RoamTimeMin, +this.template.RoamTimeMax)); + this.StartTimer(randIntInclusive(+this.template.RoamTimeMin, +this.template.RoamTimeMax)); this.SetFacePointAfterMove(false); }, @@ -3270,7 +3270,7 @@ UnitAI.prototype.UnitFsmSpec = { // Stop and eat for a while this.SelectAnimation("feeding"); this.StopMoving(); - this.StartTimer(RandomInt(+this.template.FeedTimeMin, +this.template.FeedTimeMax)); + this.StartTimer(randIntInclusive(+this.template.FeedTimeMin, +this.template.FeedTimeMax)); }, "leave": function() { @@ -5989,8 +5989,8 @@ UnitAI.prototype.MoveRandomly = function(distance) // Randomly adjust the range's center a bit, so we tend to prefer // moving in random directions (if there's nothing in the way) - var tx = pos.x + (2*Math.random()-1)*jitter; - var tz = pos.z + (2*Math.random()-1)*jitter; + var tx = pos.x + randFloat(-1, 1) * jitter; + var tz = pos.z + randFloat(-1, 1) * jitter; var cmpMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); cmpMotion.MoveToPointRange(tx, tz, distance, distance); diff --git a/binaries/data/mods/public/simulation/helpers/Random.js b/binaries/data/mods/public/simulation/helpers/Random.js deleted file mode 100644 index 254084c83d..0000000000 --- a/binaries/data/mods/public/simulation/helpers/Random.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Returns a random integer from min (inclusive) to max (exclusive) - */ -function RandomInt(min, max) -{ - return Math.floor(min + Math.random() * (max-min)); -} - -Engine.RegisterGlobal("RandomInt", RandomInt); diff --git a/binaries/data/mods/public/simulation/helpers/WeightedList.js b/binaries/data/mods/public/simulation/helpers/WeightedList.js index 5fe0646b17..3a51fabf29 100644 --- a/binaries/data/mods/public/simulation/helpers/WeightedList.js +++ b/binaries/data/mods/public/simulation/helpers/WeightedList.js @@ -31,9 +31,9 @@ WeightedList.prototype.itemAt = function(index) }; WeightedList.prototype.randomIndex = function() { - var element, - targetWeight = Math.random() * this.totalWeight, - cumulativeWeight = 0; + var element; + var targetWeight = randFloat(0, this.totalWeight); + var cumulativeWeight = 0; for (var index = 0; index < this.elements.length; index++) { element = this.elements[index];