| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| cw4:4rpl_tools [2024/09/10 21:41] – Updated manipulateUnitPosition and added SetTerrainHigherThan20 Vertu | cw4:4rpl_tools [2025/08/29 21:04] (current) – [Pseudo RNG based on Linear congruential generator (LCG)] kalli |
|---|
| endonce | endonce |
| endif | endif |
| | </code> |
| | |
| | </hidden> |
| | |
| | ---- |
| | |
| | |
| | ===== Request Viable Build- or Move-Cell ===== |
| | |
| | <hidden click here for source code> |
| | |
| | This script allows for other scripts to SEND A MESSAGE TO REQUEST A VIABLE BUILD- OR MOVE-CELL. |
| | |
| | The script is a compromise between high performance and high fidelity. The reason that it's setup to run as a separate script and not as a function, is so that it can take move/build requests from multiple sources into account: by default it won't recheck cells that were recently rejected + new searches will continue where recent previous queries stopped after finding a solution. A very high performance version exists for 3x3 units in my SQUADS map. |
| | |
| | |
| | How to use in a cpack: |
| | Run the script as a global script in Pre. Do not run while paused. |
| | |
| | |
| | Use example for building miners: |
| | |
| | |
| | <code 4rpl example.4rpl>500 0 do |
| | "requestWxWviableCell" 0 5 3 128 128 v2 256 0 0 0 0 1 0 1 1 0 14 listN sendmsg # Length > width = x direction. |
| | <-*WxWviableCellFound if |
| | "miner" <-*WxWviableCell ev2 0 createunitonterrain dup 1 SetUnitOccupiesLand 999 constructunit |
| | # Unlike existing units that move, newly build units do not instantly occupy the cells that they were created on, so we force a refresh of that with SetUnitOccupiesLand. |
| | endif |
| | loop |
| | |
| | 500 0 do |
| | "requestWxWviableCell" 0 3 5 128 128 v2 256 0 0 0 0 1 0 1 1 0 14 listN sendmsg # Length > width = z direction. With Z-direction we also need to change the orientation below. |
| | <-*WxWviableCellFound if |
| | "miner" <-*WxWviableCell ev2 0 createunitonterrain dup dup 1 setunitorientation 1 SetUnitOccupiesLand 999 constructunit |
| | endif |
| | loop</code> |
| | |
| | INPUT variables explained: |
| | |
| | <-moveUID: can be left 0, but it's needed if you want to allow a unit to check if it's current location is viable. |
| | |
| | <-unitLength: footprint length in X direction. |
| | |
| | <-unitWidth: footprint length in Z direction. |
| | |
| | <-cellV2: V2 vector. The cell where your requesting script wants to build/move the unit. |
| | |
| | <-searchRange: the cell distance around the requested cell location, where the function will look for a viable build/move cell. |
| | |
| | <-maxCreeperDepth: this will check the average creeper depth in a circle with range 4. |
| | |
| | <-noMesh: set to 1 to not allow solutions with ACTIVE mesh. |
| | |
| | <-likePlatform: the unit can be placed in the void. |
| | |
| | <-likeBeacon: the unit can be placed in the void and on uneven terrain. |
| | |
| | <-likeMiner: the unit can only be placed on resource special terrain that covers atleast 75% of the unit footprint. |
| | |
| | <-likeNullifier: the unit has to be placed within nullification range of an enemy creeper. The creeper enemey has to be known to a list inside the function script. |
| | |
| | <-ignoreCooldown: set to 1 to ignore time based computation optimizations. Best left at 0 when the function is called by an AI script (more optimized) and set to 1 when it's initiated by the player (feels more responsive). |
| | |
| | <-noSkip: set to 1 for max placement coverage, but slower computations. If left at 0, then the script will not check cells that are likely to not have a proper solution, but it will also mistakenly not check some cells that do have a proper solution. For spamming 3x3 units, "1" tends to be 40% slower, while only placing about 10% more units. |
| | |
| | <-resetSearch: if set to 1, then all previous search history will be forgotten. |
| | |
| | |
| | |
| | <code 4rpl LxW-FindViableCell-NRP-Pre.4rpl> |
| | # --LxW-FindViableCell-NRP-Pre-- |
| | |
| | # INPUTS: "requestWxWviableCell" <-moveUID <-unitLength <-unitWidth <-cellV2 <-searchRange <-maxCreeperDepth <-noMesh <-likePlatform <-likeBeacon <-likeMiner <-likeNullifier <-ignoreCooldown <-noSkip <-resetSearch 14 listN |
| | # OUTPUT: global varialbles named <-*WxWviableCellFound <-*WxWviableCell |
| | |
| | # Contains snapping tool movecell requests, so that multiple units can request a viable cell from a single source, without double checking cells. |
| | # BASED ON SNAPPING TOOL CODE, but without the Indicator unit or the Mouse commands, and only for SQUARE units. |
| | |
| | $radiusLandingSpot:4 # INTEGER. The creeper threshhold will be checked as an average over more than the unit landing location. |
| | $cellsWithinLandingRange:69 # INTEGER, see previous radius. The creeper threshhold will be checked as an average over more than the unit landing location. |
| | |
| | $$defaultSearchRange:20 # INTEGER. The floodfill distance. If no searchRange is send in the message, this is the range that will be used. |
| | |
| | $groupDist:7 # Integer or float distance. Requests that are closer together than this distance, will be grouped together, so that later searches can continue on from previous searches. |
| | $blockCellTimer:90 # INTEGER. Amount of frames under which queries will be grouped together & searches around cells that were found to be blocked, will not be done again. |
| | $clearCellTimer:270 # INTEGER. Amount of frames after which the blocked cells will be forgotten. In between these 2 values, searches will only be done again if there are less units around than when the cell was last found to be blocked. |
| | |
| | $$contSlot:8 # VALUE EDITOR SETTING. Units cannot be placed on this terrain slot. 8 is the default contaminant slot. |
| | $$resoSlot:1 # VALUE EDITOR SETTING. Miners can only be placed on resource terrain. 1 is the default resource slot. |
| | $$meshSlot:6 # VALUE EDITOR SETTING. Units that can be placed in the void, cannot be placed on mesh inside the void. 6 is the default mesh slot. |
| | |
| | $$nullifyUnits:" emitter; airsaccauldron; blobnest; darktower; skimmerfactory; sporelauncher" # Enemy units that would be suppressed by building a nullifier near them. |
| | |
| | :requestWxWviableCellFunction |
| | <-_DATA[0] 0 setunitoccupiesland # With this line, an existing unit's current cell will be a possible result from the search for a viable cell. |
| | <-_DATA ListToStack @searchWxWviableCell ->*WxWviableCellFound ->*WxWviableCell |
| | <-_DATA[0] 1 setunitoccupiesland |
| | |
| | :once |
| | # listening channels: |
| | "requestWxWviableCell" "requestWxWviableCellFunction" registerformsg |
| | 1 ->resetSearch |
| | 1 ->ignoreCooldown |
| | |
| | # When the loop was ran through fully without finding a resolution, remember that cell for 90 frames before trying the same cell again. |
| | list ->blockedCellV2List |
| | list ->blockedCellTimeList |
| | list ->nearbyUnitsCountList |
| | |
| | <-nullifyUnits removewhitespace ";" split ->suppressList |
| | |
| | :searchWxWviableCell # Output: viableCell as v2 + true/false |
| | # See vanilla snapping tool cpack for full commments. |
| | ->resetSearch |
| | ->noSkip |
| | ->ignoreCooldown |
| | ->checkN |
| | ->checkR |
| | ->placeA |
| | ->placeV |
| | ->noMesh |
| | ->creDepth |
| | ->searchRange |
| | ->cell |
| | ->width |
| | ->length |
| | pop # The UID has no further use. |
| | |
| | # The following switch checks if the search should start from scratch (=1), or if it should continue (=0) on from a previous search. |
| | switch |
| | <-resetSearch case 1 endcase |
| | <-length <-prevLength neq case 1 endcase |
| | <-width <-prevWidth neq case 1 endcase |
| | <-checkN <-prevCheckN neq case 1 endcase |
| | <-checkR <-prevCheckR neq case 1 endcase |
| | <-placeA <-prevPlaceA neq case 1 endcase |
| | <-placeV <-prevPlaceV neq case 1 endcase |
| | <-cell ev2 <-prevSearchCell ev2 distancecell <-groupDist gt if 1 else |
| | <-prevSearchCell ->cell # Group the search query together with previous closeby queries. |
| | <-ignoreCooldown if getgametickcount else getgameupdatecount endif dup <-prevSearchUpdateCount gt if |
| | ->prevSearchUpdateCount |
| | 1 |
| | else |
| | pop |
| | 0 |
| | endif |
| | endif |
| | endswitch if # If the search starts from scratch, then the new settings have to be remembered for the next function call. |
| | # Adjust the footprint array depending on the requested width in the function call. |
| | <-width dup <-prevWidth neq if |
| | dup ->prevWidth |
| | 1 add 2.0 div asint dup ->rHz 1 sub ->rLz # For the footprint loop. |
| | else pop endif |
| | <-length dup <-prevLength neq if |
| | dup ->prevLength |
| | 1 add 2.0 div asint dup ->rHx 1 sub ->rLx # For the footprint loop. |
| | else pop endif |
| | |
| | <-checkN ->prevCheckN |
| | <-checkR ->prevCheckR |
| | <-placeA ->prevPlaceA |
| | <-placeV ->prevPlaceV |
| | <-cell ->prevSearchCell |
| | |
| | # Recreate the area to search: |
| | <-searchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange |
| | <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells |
| | 0 ->startLoop |
| | 0 ->skip |
| | |
| | # If the search is being reset, then clear the blocked lists. |
| | <-resetSearch If |
| | 1 ->ignoreCooldown |
| | <-blockedCellV2List clearlist |
| | <-blockedCellTimeList clearlist |
| | <-nearbyUnitsCountList clearlist |
| | endif |
| | else |
| | # If the search continues on from before, but the search range was changed, then the potential cells will need to be adjusted, without adjusting the start of the loop. |
| | <-searchRange dup <-prevSearchRange neq if |
| | dup ->prevSearchRange 1 sub dup dup mul swap add 2 mul 1 add ->floodRange |
| | <-cell ev2 0 21 <-floodRange floodfillterrain dup getlistcount ->potentialCellCount ->potentialCells |
| | else pop endif |
| | endif |
| | |
| | # If the new searchRange is larger than the old one, then do not check if the cell was recently found to be blocked. |
| | <-searchRange <-prevSearchRange gt <-ignoreCooldown OR not if |
| | # Check if the cell is not on the list of blocked cells. |
| | <-blockedCellV2List <-cell getlistindex dup -1 eq if pop else |
| | ->index |
| | |
| | getgameupdatecount ->updateCount |
| | # Try to purge a few old blocked cells from the lists, otherwise the list bloats. |
| | -1 <-index 1 sub do |
| | <-blockedCellTimeList[i] <-clearCellTimer add <-updateCount lt if |
| | <-blockedCellV2List i removelistelement |
| | <-blockedCellTimeList i removelistelement |
| | <-nearbyUnitsCountList <-index removelistelement |
| | <-index 1 sub ->index |
| | endif |
| | loop |
| | |
| | switch |
| | # The last check on this spot was less than 3 seconds ago, so we're not checking it again now. |
| | <-blockedCellTimeList[<-index] <-blockCellTimer add <-updateCount gt case |
| | -1 -1 v2 false return |
| | endcase |
| | # The last check on this spot was longer than 9 seconds ago, so we can check it again now. |
| | <-blockedCellTimeList[<-index] <-clearCellTimer add <-updateCount lt case |
| | <-blockedCellV2List <-index removelistelement |
| | <-blockedCellTimeList <-index removelistelement |
| | <-nearbyUnitsCountList <-index removelistelement |
| | endcase |
| | # Check the cell again if there are now less units nearby than when it was blocked. |
| | <-cell ev2 fromcell 13 0 0 0 0 0 0 getunitsinrange getlistcount <-nearbyUnitsCountList[<-index] lt case |
| | <-blockedCellV2List <-index removelistelement |
| | <-blockedCellTimeList <-index removelistelement |
| | <-nearbyUnitsCountList <-index removelistelement |
| | endcase |
| | # Too recent and still the same amount of units nearby, so don't check again: |
| | -1 -1 v2 false return |
| | endswitch |
| | endif |
| | endif |
| | |
| | <-potentialCellCount <-startLoop do |
| | <-skip if |
| | <-skip 1 sub ->skip |
| | else |
| | <-potentialCells[i] ev2 @checkCenterCell if |
| | @checkFootPrint if |
| | i <-noSkip if 1 else <-width endif add ->startLoop # Optimization for mass placement. When placing the next unit, skip the next few potential cells. |
| | <-potentialCells[i] true return # LEFT ON STACK. |
| | endif |
| | else |
| | <-noSkip if 0 else <-width 3 div asint 1 add endif ->skip # If the center cell was blocked, then also skip the next X potential cells. |
| | endif |
| | endif |
| | loop |
| | <-potentialCellCount ->startLoop |
| | # If the loop was not interrupted by return, then all cells were blocked in some way. |
| | <-blockedCellV2List <-cell appendtolist |
| | <-blockedCellTimeList getgameupdatecount appendtolist |
| | <-nearbyUnitsCountList <-cell ev2 fromcell 13 0 0 0 0 0 0 getunitsinrange getlistcount appendtolist |
| | -1 -1 v2 false # LEFT ON STACK. |
| | |
| | :checkCenterCell # Inputs: x and z of cell. |
| | dup2 <-radiusLandingSpot 0 1 0 getcreeperinrange <-cellsWithinLandingRange div <-creDepth gt if pop pop false return endif |
| | dup2 getterrain dup ->height if |
| | <-placeV if pop pop false return endif |
| | 0 ->checkO |
| | else |
| | <-placeV <-placeA OR if 0 else 1 endif ->checkO |
| | endif |
| | <-checkR if 0 ->minePot endif |
| | # dup2 is still on the stack. |
| | switch |
| | dup2 getcelloccupiedcount <-checkO neq case pop pop false return endcase |
| | # dup2 getterrain <-height neq case pop pop false return endcase # Useless on center cell. |
| | # dup2 getcreeper <-creDepth gt case pop pop false return endcase |
| | dup2 getmeshhealth gt0 <-noMesh AND case pop pop false return endcase |
| | dup2 getterraformmarker gt0 case pop pop false return endcase |
| | dup2 getterrainspecial dup ->special <-contSlot eq case pop pop false return endcase |
| | <-special <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Units cannot be placed on mesh in the void. |
| | ->cZ ->cX # Used in checkFootPrint. |
| | <-checkR if <-special <-resoSlot eq if |
| | <-minePot 1 add ->minePot |
| | else |
| | pop pop false return |
| | endif endif |
| | <-checkO if |
| | "platform" <-cX 0 <-cZ v3 2.9 0 0 0 2 1 0 getunits 0 getlistelement |
| | getunitcell <-cX <-cZ distancecell 2.828427 approximately not if pop pop false return endif |
| | endif |
| | <-checkN if |
| | <-suppressList <-cX 0 <-cZ v3 9 0 0 0 1 0 1 getunitsinrange 0 getlistelement getunittype listcontains not if pop pop false return endif |
| | endif |
| | endswitch |
| | true |
| | |
| | :checkFootPrint |
| | # See vanilla snapping tool cpack for full commments. |
| | |
| | <-cZ <-rHz add <-cZ <-rLz sub do |
| | <-cX <-rHx add <-cX <-rLx sub do |
| | switch |
| | i j |
| | # dup2 <-cZ eq swap <-cX eq AND case pop pop endcase # The center cell was already checked and OK. |
| | dup2 getcelloccupiedcount <-checkO neq case pop pop false return endcase |
| | dup2 getterrain <-height neq case pop pop false return endcase |
| | # dup2 getcreeper <-creDepth gt case pop pop false return endcase |
| | dup2 getmeshhealth gt0 <-noMesh AND case pop pop false return endcase |
| | dup2 getterraformmarker gt0 case pop pop false return endcase |
| | dup2 getterrainspecial dup ->special <-contSlot eq case pop pop false return endcase |
| | # dup2 getterrainspecial <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Prevents platforms from being placed on mesh in the void. Not relevant for this script. |
| | <-special <-meshSlot eq <-height 0 eq AND case pop pop false return endcase # Units cannot be placed on mesh in the void. |
| | <-placeA case pop pop endcase |
| | pop pop |
| | <-checkR if <-special <-resoSlot eq if <-minePot 1 add ->minePot endif endif |
| | endswitch |
| | loop |
| | loop |
| | <-checkR if <-minePot <-length <-width mul 0.75 mul lt if false return endif endif |
| | true |
| | |
| | </code> |
| | |
| | </hidden> |
| | |
| | ---- |
| | |
| | |
| | ===== Pseudo Random Number Generator, based on sinus ===== |
| | |
| | <hidden click here for source code> |
| | |
| | Several basic functions based on Grabz' rng lite function of "<-seed sinus 10000 mul dup floor sub". |
| | |
| | |
| | Copy the functions directly into your script or run the below script in your cpack and have other scripts send messages to request a randfloat or randint. |
| | |
| | |
| | Difference between the functions: |
| | * "seeded": provide a seed to the generator. The generated number will always be the same for the same seed. |
| | * "index": these seeds are sequenced. In the same map for the same index, the generated number 1,2,3,... will be the same after map restart. |
| | * "spiked": the generator is seeded with the elapsedtime of the gaming session, making the outcome uncontrollable. |
| | * No prefix: these are sequenced seeds and they use index 0. |
| | |
| | Example code with messages: |
| | <code example.4rpl> |
| | 12345 ->int |
| | 1 ->index |
| | 0 ->first |
| | 100 ->last # The last integer itself will be excluded. |
| | "sinRandInt" <-first <-last 2 listN sendmsg |
| | <-*sinRandInt trace |
| | "sinRand01" 0 sendmsg |
| | <-*sinRand01 trace |
| | "indexSinRandInt" <-index <-first <-last 3 listN sendmsg |
| | <-*sinRandInt trace |
| | "indexSinRand01" <-index sendmsg |
| | <-*sinRand01 trace |
| | "spikedSinRandInt" <-first <-last 2 listN sendmsg |
| | <-*sinRandInt trace |
| | "spikedSinRand01" 0 sendmsg |
| | <-*sinRand01 trace |
| | "seededSinRandInt" <-seed <-first <-last 3 listN sendmsg |
| | <-*sinRandInt trace |
| | "seededSinRand01" <-seed sendmsg |
| | <-*sinRand01 trace |
| | </code> |
| | |
| | ---- |
| | |
| | <code SinusRNG.4rpl> |
| | :once |
| | # Creating lists and a starting mapconstant for the seed sequences. |
| | createlist ->prevSeedList |
| | createlist ->seedCountList |
| | getmapsize 2 div swap 2 div swap dup2 getterrain 1 add dup 99999 floodfillterrain getlistcount ->mapConstant |
| | |
| | # Setting up the messages so that other scripts can request a random seed. |
| | "sinRandInt" "sinRandInt_CALL" registerformsg |
| | "sinRand01" "sinRand01_CALL" registerformsg |
| | "indexSinRandInt" "indexSinRandInt_CALL" registerformsg |
| | "indexSinRand01" "indexSinRand01_CALL" registerformsg |
| | "spikedSinRandInt" "spikedSinRandInt_CALL" registerformsg |
| | "spikedSinRand01" "spikedSinRand01_CALL" registerformsg |
| | "seededSinRandInt" "seededSinRandInt_CALL" registerformsg |
| | "seededSinRand01" "seededSinRand01_CALL" registerformsg |
| | |
| | :sinRandInt_CALL |
| | <-_DATA listtostack @sinRandInt ->*sinRandInt |
| | :sinRand01_CALL |
| | @sinRand01 ->*sinRand01 |
| | :indexSinRandInt_CALL |
| | <-_DATA listtostack @indexSinRandInt ->*sinRandInt |
| | :indexSinRand01_CALL |
| | <-_DATA @indexSinRand01 ->*sinRand01 |
| | :spikedSinRandInt_CALL |
| | <-_DATA listtostack @spikedSinRandInt ->*sinRandInt |
| | :spikedSinRand01_CALL |
| | @spikedSinRand01 ->*sinRand01 |
| | :seededSinRandInt_CALL |
| | <-_DATA listtostack @seededSinRandInt ->*sinRandInt |
| | :seededSinRand01_CALL |
| | <-_DATA @seededSinRand01 ->*sinRand01 |
| | |
| | :sinRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | 0 @indexSinRand01 <-last <-first sub mul <-first add asint |
| | |
| | :sinRand01 # INPUT: none. |
| | 0 @indexSinRand01 |
| | |
| | :indexSinRandInt # INPUT: the index of the seed sequence + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | @indexSinRand01 <-last <-first sub mul <-first add asint |
| | |
| | :indexSinRand01 # INPUT: the "index" of the seed sequence. OUTPUT: the next seed from that sequence. |
| | # The random numbers will be generated with the previous seed that is stored under that index. |
| | ->i |
| | <-prevSeedList[<-i] eq0 if |
| | <-i <-mapConstant add 2357 mul @seededSinRand01 dup 10000000 mul 1 add asint ->prevSeedList[<-i] |
| | 1 ->seedCountList[<-i] |
| | else |
| | <-prevSeedList[<-i] @seededSinRand01 dup 10000000 mul <-seedCountList[<-i] 1 add dup ->seedCountList[<-i] add asint ->prevSeedList[<-i] |
| | endif |
| | |
| | :spikedSinRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | elapsedtime asint @seededSinRand01 <-last <-first sub mul <-first add asint |
| | |
| | :spikedSinRand01 |
| | elapsedtime asint @seededSinRand01 |
| | |
| | :seededSinRandInt # INPUT: integer seed + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | @seededSinRand01 <-last <-first sub mul <-first add asint |
| | |
| | :seededSinRand01 |
| | # abs <-power pow <-add add sin <-sinMul mul dup floor sub |
| | 1.05 pow 99419 sub sin 619 mul dup floor sub |
| | </code> |
| | |
| | </hidden> |
| | |
| | ---- |
| | |
| | |
| | ===== Pseudo RNG based on Linear congruential generator (LCG) ===== |
| | |
| | The downside of the above sinus based functions, is that they have few resulting digits. They are more than adequate to pick a random cell on a map (max 512 possibilities), but unsuited for generating random numbers larger than a few thousand. |
| | |
| | The below LCG functions should work for up to 6 digits = 10^6, but I've only done a test up to 10^5. Rolling 1 million random integers between 0 and 10^5 with @lcgRandInt, missed only 8 possible results. The same test with @sinRandInt missed 42458 possible results. |
| | |
| | <hidden click here for source code> |
| | |
| | <code LinearCongruentialGenerator.4rpl> |
| | # Quick Example. |
| | 0 10000 @lcgRandInt |
| | |
| | :lcgRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | 0 @indexLcgRand01 <-last <-first sub mul <-first add asint |
| | |
| | :lcgRand01 # INPUT: none. |
| | 0 @indexLcgRand01 |
| | |
| | :indexLcgRandInt # INPUT: the index of the seed sequence + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | @indexLcgRand01 <-last <-first sub mul <-first add asint |
| | |
| | :indexLcgRand01 # INPUT: the "index" of the seed sequence. OUTPUT: the next seed from that sequence. |
| | # The random numbers will be generated with the previous seed that is stored under that index. |
| | ->i |
| | <-prevSeedList[<-i] eq0 if |
| | <-i <-mapConstant add 13 mul @seededLcgRand01 dup 10000000 mul 1 add asint ->prevSeedList[<-i] |
| | 1 ->seedCountList[<-i] |
| | else |
| | <-prevSeedList[<-i] @seededLcgRand01 dup 10000000 mul <-seedCountList[<-i] 1 add dup ->seedCountList[<-i] add asint ->prevSeedList[<-i] |
| | endif |
| | |
| | :clearIndexSinLcgRand |
| | <-seedCountList clearlist |
| | <-prevSeedList clearlist |
| | |
| | :spikedLcgRandInt # INPUT: integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | elapsedtime dup 10 log ceil 7 sub neg 10 swap pow mul asint <-spikedLcgAdd 1 add dup ->spikedLcgAdd mul @seededLcgRand01 <-last <-first sub mul <-first add asint |
| | |
| | :spikedLcgRand01 |
| | elapsedtime dup 10 log ceil 7 sub neg 10 swap pow mul asint <-spikedLcgAdd 1 add dup ->spikedLcgAdd mul @seededLcgRand01 |
| | |
| | :seededLcgRandInt # INPUT: integer seed + integer first randInt + integer last randInt. OUTPUT: an integer in between the first and last randInt, excluding the last randInt. |
| | ->last |
| | ->first |
| | @seededLcgRand01 <-last <-first sub mul <-first add asint |
| | |
| | :seededLcgRand01 |
| | asint 1103515245 mul 12345 add abs asfloat 2147483647 div 10 mul dup floor sub |
| | |
| | :once |
| | # Creating lists and a starting mapconstant for the seed sequences. |
| | createlist ->prevSeedList |
| | createlist ->seedCountList |
| | getmapsize 2 div swap 2 div swap dup2 getterrain 1 add dup 99999 floodfillterrain getlistcount ->mapConstant |
| | # <-SEED ->mapconstant # Alternative for map constant. |
| </code> | </code> |
| |