Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //initial "rngseed" is set to 1993 + I_GetRandomTimeSeed() + gametic
- //I_GetRandomTimeSeed() is the OS time, gametic is 0 when recording a demo
- //in a TAS we can just set this value in the demo header
- let rngseed=12
- let seed=0 //unsigned int, 0-4,294,967,295
- let rng={seed:[]}
- let boom
- /*
- https://github.com/kraflab/dsda-doom/blob/356e3d7e031be592c89338d70b8c7a69b6d888d7/prboom2/src/m_random.c
- */
- function M_ClearRandom(){
- seed = (rngseed*2+1)%4294967296;
- for(let i=0; i<51; i++){ //the only class used, "all_in_one", is [49]
- seed=(seed*69069)%4294967296
- rng.seed[i] = seed;
- }
- }
- M_ClearRandom()
- function P_Random(){
- boom = rng.seed[49]; //unsigned long
- //rng.seed[49] = ((boom*1664525) + 221297 + (49*2))%4294967296;
- rng.seed[49] = ((boom*1664525) + 221395)%4294967296;
- boom >>= 20
- return boom&255;
- }
- function getNextRNGValue(n=rng.seed[49]){ //emulates P_Random without modifying global vars
- return ((n*1664525) + 221395)%4294967296;
- }
- //-----------------
- //generic utilities
- //-----------------
- //inp needs to be an array of objects
- //keys will be grabbed from index of template
- function printForExcel(inp,template=0,includen=false){
- let ikeys=Object.keys(inp[template])
- let outpstring=ikeys[0]
- if(includen){
- outpstring="n "+outpstring
- }
- for(let i=1;i<ikeys.length;i++){
- outpstring=outpstring+" "+ikeys[i]
- }
- for(let i=0;i<inp.length;i++){
- if(includen){
- outpstring=outpstring+"\n"+i+" "+(inp[i][ikeys[0]] ?? "")
- }else{
- outpstring=outpstring+"\n"+(inp[i][ikeys[0]] ?? "")
- }
- for(let j=1;j<ikeys.length;j++){
- outpstring=outpstring+" "+(inp[i][ikeys[j]] ?? "")
- }
- }
- console.log(outpstring)
- }
- //----------------------
- //holding on to the past
- //----------------------
- //find x values, n before a specific rng.seed[49] value
- function getPrecedingValues(val=rng.seed[49],n=100,x=n){
- for(let i=0;i<n;i++){
- val = getPreviousValue(val)
- }
- let Ordered=[val]
- for(let i=0;i<x;i++){
- val=getNextRNGValue(val)
- Ordered[Ordered.length]=val
- }
- return Ordered
- }
- function getPreviousValue(n=rng.seed[49]){
- return Number((BigInt((n-221395)%4294967296)*4276115653n)%4294967296n)
- }
- //find initial rngseed from rng.seed[49] value
- function getSeedFromValue(n=rng.seed[49]){
- if(n%2==0){return -1} //odd numbers only
- return (Number((BigInt(n)*3602842457n)%4294967296n)-1)/2
- }
- //---------------------
- //looking to the future
- //---------------------
- //NOTE FOR THESE ROLLS:
- //if the enemy is asleep it can wake up after the first pellet and call RNG 3(?) times, this should be accounted for, eventually
- function getSGRoll(n=rng.seed[49]){
- let temprng=rng.seed[49]
- rng.seed[49]=n
- //rng calls are as follows:
- //1: P_GunShot rolls for damage
- //3: P_GunShot rolls twice for horizontal offset
- //5: P_SpawnBlood rolls twice for Z offset
- //6: P_SpawnMobj rolls when blood is spawned to pick a random player target
- //7: P_SpawnBlood rolls for animation tic delay
- //enemy is damaged
- //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
- //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
- //if the enemy dies: P_DamageMobj RETURNS now
- //if the enemy survives:
- //8: P_DamageMobj rolls for pain chance
- let dmgsum=0;
- for(let i=0;i<7;i++){
- dmgsum+=((P_Random()%3)+1)*5
- for(let d=0;d<7;d++){P_Random()}
- }
- rng.seed[49]=temprng
- return dmgsum
- }
- function getSSGRoll(n=rng.seed[49]){
- let temprng=rng.seed[49]
- rng.seed[49]=n
- //rng calls are as follows:
- //1: A_FireShotgun2 rolls for damage
- //3: A_FireShotgun2 rolls twice for horizontal offset
- //5: A_FireShotgun2 rolls twice for vertical offset
- //7: P_SpawnBlood rolls twice for Z offset
- //8: P_SpawnMobj rolls when blood is spawned to pick a random player target
- //9: P_SpawnBlood rolls for animation tic delay
- //enemy is damaged
- //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
- //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
- //if the enemy dies: P_DamageMobj RETURNS now
- //if the enemy survives:
- //10: P_DamageMobj rolls for pain chance
- let dmgsum=0;
- for(let i=0;i<20;i++){
- dmgsum+=((P_Random()%3)+1)*5
- for(let d=0;d<9;d++){P_Random()}
- }
- rng.seed[49]=temprng
- return dmgsum
- }
- function getBFGRoll(n=rng.seed[49]){
- let temprng=rng.seed[49]
- rng.seed[49]=n
- //rng calls per tracer are as follows:
- //1: P_SpawnMobj rolls for random player target
- //16: 15 rolls(!!!) for damage sum - 1-8 dmg per roll
- //enemy is damaged
- //if the enemy dies: 1 extra call for tic delay on death animation, another call if it is 64 units above you & dmg is under 40???? does RNG get called if the checks fail?
- //if the enemy drops a weapon or ammo, the new thing will call RNG to pick a random player target
- //if the enemy dies: P_DamageMobj RETURNS now
- //if the enemy survives:
- //17: P_DamageMobj rolls for pain chance
- let dmgsum=0;
- for(let i=0;i<40;i++){
- P_Random()
- let tsum=0;
- for(let k=0;k<15;k++){
- tsum+=(P_Random()%8)+1
- }
- dmgsum+=tsum
- P_Random()
- }
- rng.seed[49]=temprng
- return dmgsum
- }
- //get output of P_Random from this rng value
- function getRoll(n=rng.seed[49]){
- let temprng = n
- temprng >>= 20
- return temprng&255;
- }
- //make a nice table of all the outcomes from a range of rng values
- function predictRollsFromValue(testval=rng.seed[49],n=100,excelprint=false){
- let temprng=rng.seed[49]
- rng.seed[49]=testval
- let rseed=getSeedFromValue(testval)
- if(rseed==-1){rseed=""}
- let outp=[{Index:0,RNG:testval,Result:getRoll(testval),SG:getSGRoll(testval),SSG:getSSGRoll(testval),BFG:getBFGRoll(testval),Seed:rseed}]
- for(let i=1;i<=n;i++){
- P_Random()
- rseed=getSeedFromValue()
- if(rseed==-1){rseed=""}
- outp[i]={
- Index:i,
- RNG:rng.seed[49],
- Result:getRoll(rng.seed[49]),
- SG:getSGRoll(rng.seed[49]),
- SSG:getSSGRoll(rng.seed[49]),
- BFG:getBFGRoll(rng.seed[49]),
- Seed:rseed
- }
- }
- if(excelprint){
- printForExcel(outp)
- }
- rng.seed[49]=temprng
- return outp
- }
- //do the same but from an initial RNG seed
- function predictRollsFromSeed(testseed=0,n=100,excelprint=false){
- rngseed=testseed
- M_ClearRandom()
- return predictRollsFromValue(rng.seed[49],n,excelprint)
- }
- //trawl through rng to find some good rolls
- //find n rolls >= goal
- //note if startrng input is passed, the "index" in the output will be the amt of rolls since startrng, not the index from 0 as used in other functions
- //weapon should be "SSG", "SG" or "BFG"
- function findHighRolls(goal,weapon,n=100,startrng=0){
- let temprng=rng.seed[49]
- rng.seed[49]=startrng
- let outp=[]
- for(let i=0;i<4294967296;i++){
- if(weapon=="SSG"){
- let roll=getSSGRoll(rng.seed[49])
- if(roll>=goal){
- outp[outp.length]={
- Index:i,
- RNG:rng.seed[49],
- SSG:roll
- }
- }
- }
- if(weapon=="SG"){
- let roll=getSGRoll(rng.seed[49])
- if(roll>=goal){
- outp[outp.length]={
- Index:i,
- RNG:rng.seed[49],
- SG:roll
- }
- }
- }
- if(weapon=="BFG"){
- let roll=getBFGRoll(rng.seed[49])
- if(roll>=goal){
- outp[outp.length]={
- Index:i,
- RNG:rng.seed[49],
- BFG:roll
- }
- }
- }
- if(outp.length>=n){
- rng.seed[49]=temprng
- return outp
- }
- P_Random()
- }
- console.log("couldn't find enough of them!")
- rng.seed[49]=temprng
- return outp
- }
- //---------------------
- //an example use case
- //---------------------
- //used for d5da5 19 max
- for(let initseed = 0;initseed<1000000;initseed++){
- rngseed=initseed
- M_ClearRandom()
- for(let i=0;i<9;i++){
- P_Random()
- }
- totaldmg=getSSGRoll()
- for(let i=0;i<248;i++){
- P_Random()
- }
- totaldmg+=getSSGRoll()
- if(totaldmg>=500){
- console.log(initseed)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement