Posts for FatRatKnight

Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
TheAxeMan wrote:
Have you reexamined anything that you thought may have been too tough to manipulate before? It sounds like this just helps give you more ways to manipulate faster but is it possible that it could open any other options?
Nothing was "too tough" to manipulate before. But this lets us get what we did manipulate possibly in fewer frames, as this opens up other ways of tweaking the RNG. However, this doesn't actually open up new RNG options. If it did, I would get the stoning version of GAZE in a hurry, don't bother with POWER, skip the stone book, and turn SEI-RYU into instant art. We're currently investigating a new route possibility through World I. Out of curiosity, I decided to equip the KING sword to see how much faster we slay the single SKELETON. It beat the previous time by quite a significant amount, as we go through NO attack animations thanks to the CRITICAL HIT!! that shows up. So now we're looking to see if a route change for an earlier sword is worth it. Old route: Tower -> Bandit Cave -> TELEPOR -> Castle Armor -> TELEPOR -> Castle Sword -> TELEPOR -> Castle Shield -> Town -> TELEPOR and climb Tower New route: Tower -> Castle Sword -> TELEPOR -> Castle Shield -> Bandit Cave -> TELEPOR -> Castle Armor -> TELEPOR -> Town -> TELEPOR and climb Tower The new route, along with an earlier powerful weapon, will also save exactly one step. The early KING sword we get will let us bypass attack animations thanks to that CRITICAL HIT!! it does to so many things. So far, I figured out how to beat KINGSWRD while manipulating TELEPOR off of him. Only problem is that we have to do it somewhat messy, fighting an extra battle early for more Mana, and one of our fodder dies much earlier thanks to the difficult RNG. We'll see what this means as we work out this new route.
Post subject: MusicDelay, SaveDelay, and ResetDelay
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
We were looking at different ways to affect the RNG on reset. I had known that the sound processing affects the RNG in some sense, but now we have some hard definitions I want to put down here. MusicDelay - The count of frames we wait to begin the music we hear when we reset the game. This is defined to be zero when we transition to the music as soon as possible. SaveDelay - How long, in frames, we wait to save the game. If we save the game as soon as possible, this is defined to be zero. As the saving process begins playing a sound, this affects the RNG when we reset. ResetDelay - Number of "useless" frames between saving and the actual reset. If there are no spare frames between the moment we save the game and the A+B+start+select reset, we define it as zero. With these three controls, we can pick the frame count we reset at, what the music is doing at the moment, and what the save sound is doing at the moment. This should give a degree of control above what we were previously doing, and this means we might have to redo World I to see if we can tinker with the RNG even harder than what we've currently got. We'll see how much we can tighten up the manipulation. I'm hoping we can ensure no more than 20 wasted frames each time we reset.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
This is a post that is reviving an ancient thread. This is the .smv I was working on, a 100% kills and/or maximum score run, that beats the first area. This post will also list out a few things of note. The screen turns completely black at frame 9500. Any speed-related records I should be aware of? The game has assigned three different buttons to shoot with. This means that one can fire every single frame, basically 60 Hz. But a 3 onscreen bullet limit for the player generally means you're rather restricted in how often you can fire anyway. However, this also allows a way to shoot regular bullets while charging up a powered shot without any interruption, as demonstrated at the end of the .smv file, as I begin the second area. Against the second wave, I highly doubt there's any way to kill all enemies without flying "off-road", so to speak, so I'm forced to slow down. I expect worse cases later on. Against the third wave, the yellow blocks each have 3 HP. I need to shoot three times to destroy each one, and with the 3 bullet limit, a few has come frighteningly close. There was one moment in the TAS attempt where I had to optimize input at what is roughly the equivalent of sub-pixels in order to destroy one set of yellow blocks without slowing down. A little secret I accidentally discovered is the fact you can get an extra life by setting your speed to a specific value on area completion. This extra stock, unlike the kind you get at score thresholds, do not affect what ship you get for the later areas. This is demonstrated in the .smv file. Incidentally, this also answers a question I had since childhood as to why they display one more stock slot than there are possible stocks from score and starting amount.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I could always whip out something like this lua script to give you some onscreen comments. At this point in the run, we'll be luck-manipulating enemy encounters away, a LOT. I delegate this task to my good partner, Bobo the King, and this should give plenty of time for me to write up some comments about this section. So give me some time to comment up this run. And yeah, some delays were long enough that I start running the other way. Or play around with the hyper speed menu cursor. I figure we should at least confuse the viewer with this wait.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Our movies, by progress. Not important for viewing. Just skip down, but these are for curiosity. We certainly weren't too lazy here. ... Okay, stare at these comments. But this is the last piecewise WIP. World I progress. Look here, not those up there. Ah, the luck went more smoothly than I anticipated. Although there were three relatively long waits, I think things went pretty darn fast. We're definitely on track with our plans. Nothing unexpected that throws our plans out the window. ... Eh, just use the bold link up there and take a look, I guess.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I recall looking for rooms with visible "light sources" as part of the decor. And attempting to empty out my torch charges in one such room. No luck running my torch down. So any place where there are visible lit torches or other light sources seen in the room probably wouldn't reduce your torch life with any actions. I recall the sphinx room being one such place. Might help to narrow down the search a bit. Although, I also recall a room where you can light a fireplace and afterward run down your torches. Despite an open fire in the fireplace (which you created), it can go through the usual "you can't see, trip, then die horribly" sequence.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
BadPotato wrote:
Ok, I managed to get FCEUX working with the lastest version.
Great! Nice to know this script is capable.
BadPotato wrote:
Some feedback: As you said, it pretty much became an emu/editor with basic feature and this look great! I think your script deserve more attention.
It is good to know I'm getting feedback, even if I only get it long after I've released this script to the public in this thread. It's quite a capable text editor, indeed.
BadPotato wrote:
I tried the script with some other emulator and it's works almost perfectly with pcsxrr and the "RunWhilePaused" mode (in fact, it just add some unnecessary space as you write text but the pause is working pretty good). FBArr and gens(thought gens doesn't support the pause feature) are a bit offtrack to follow up the cursor and Psxjin has issue for drawing the box and cursor.
I'm surprised on how many emulators it works in. I only have tried a small handful, yet I produced a script that works decently in others. I intended for it to be general-purpose, and I'm glad it reaches beyond what I can test myself. As for the cursor/box wandering where the text isn't displayed, as though the offsets weren't set correctly, there's no way I could possibly guess the text width properly. If the emulators use fixed-width text, then find the WID near the top of the script and adjust that little number you see there. If they use variable-width text, it is impossible for me to have the display match up with the emulator's text. Not without knowing the specific width of each character. In that particular case, I would be rather encouraged to abuse other graphical functions (say, pixels and lines) in order to create my own custom text from the lua side.
BadPotato wrote:
Note: For making those emulator I just switch the "elseif FCEU", by the emulator name of the script above.
Not sure where in particular you mean.
BadPotato wrote:
Despite that I guess that more feature like a "delete" hotkey to get along with backspace or maybe somekind of basic hud interface would be awesome. Also, for the emulator without the pause feature support, I think that the DarkKolbold popup idea could be good. There's probably some other lua extension module that could do it.
Any ideas in mind for the interface? Some thoughts that do come to mind would be to display things like start or end frames of current subtitle. Which I miraculously fail to implement. As it stands, one can drag subtitles around, select them, and edit them. Though some of it feels unintuitive when I finally cracked open this script.
BadPotato wrote:
As for the rendering output(to match with your filename.lua), sometime the gui.text() font feel a bit crappy. I've been wondering how hard it would be to write a library that could load some font and draw the text, but this seem a bit off lua limit.
I'm sure it's possible. Even if it means a dozen calls to gui.pixel per character, I see no reason why it can't work. If the emulator has some capacity of putting an image on the window, like gui.gdoverlay, I could create a table of strings that represent every character. The construction would probably be pretty slow, but once everything's loaded, it would have my own images efficiently painted on. I hope.
BadPotato wrote:
Anyway, I know that currently it became a bit an old project of your, but do you plan to keep improving it ?
I had no plans before this day, mainly due to the fact I forgot it existed. Your posts may have revived some of my interests in this old script, but still no solid plans, I must say.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I spot an old (last post at 2005-08-22) TASVideos Hyperzone thread. Figured you'd want to be aware of it. As a personal project, I was trying a 100% kills run. I am not far into it and it is not high priority in my list of things to do.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
BadPotato wrote:
I give your script a try with FCEUX, while playing back a movie... but nothing seem to happen when I press "enter" or any key. Maybe I'm doing something wrong?
After starting the script, at least one frame needs to play in FCEUX for anything to appear. Beyond that, the default controls should let control+LeftClick create a new script-based subtitle. FCEUX has its own built-in subtitles, but this script does not work with that in particular. If you mean another script (I believe it's subtitler.lua as part of the FCEUX package), let me know if it's that instead.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Just posting to acknowledge that, yes, I confirm your post and will get myself ready. Hope to see you on IRC. Just had a little problem involving my computer's power supply frying on me. It's been replaced, and nothing else seems to be lost, thankfully.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
My goodness, what's happening to Captain Falcon's portrait? The one seen on the top-left corner of the screen during gameplay? I think these are speeds that break all sense of reason...
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Wow, I've been away from this game for long enough that I forgot just about everything related to the RNG. It will actually take a lot of effort from me to relearn enough to properly answer your question. Sorry about that, but I really have lost most recollection of what I've done here. Eh, the (J) run sort of scared me away from trying any further. Apparently, it's possible to fight Arsenal in an abnormal spot, but whether that causes any triggers is unknown. A glitched set of early powerful monsters seem necessary.
Post subject: Re: #3086: Mothrayas's PSX Grand Theft Auto 2 "kill 50 people" in 01:00.63
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Aims for highest killcount/time on the site
This thread has something to say. In particular, this post has a nice little screen shot of a lua scripted counter for a published TAS telling how many kills took place. As such, since you failed to achieve your goal, as a kill count of 7992 in 28:48 approximates 277 kills/minute, which your run fails to meet by a rather long shot, this does not show such a bright future for this run.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Don't bother looking for April Fools' pranks in here. Or maybe I'm just saying that so you'll specifically waste time looking for a prank where there is none, thus I am successful in a prank anyway! Anyway, turns out I needed to use the charged shot to hit the mail box a second time. Of all the power of a charged shot, ready to kill, it's spent on watching it vanish into the infinite depths of the mail box. Trust me, the fact it shakes is manipulating luck. I couldn't use a regular shot because I would be propelled upward by shooting down. Yet, a high-powered charged shot doesn't even have the kick of a gnat, let alone what the regular shots would do. Ah, the physics of this game. Where ultra-high powered shots have no recoil, whereas a pea-shooter is enough to significantly change your momentum.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I request an encode in the form of an animated image. As there generally isn't any sound in Nethack, there are relatively few colors to see, and how short this run is, I believe an animated image might actually work. Feel free to tell me otherwise if there's any barrier to such an encode.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Progress! But I am going insane with that last missed shot at frame 15820. Use my script, hold numpad7 for one frame, then run the movie to that frame. Note the hitboxes... The miracles that happened up to that point: - I kill an agent using a well-timed grenade. - Said grenaded agent got the right death animation to be counted in the 5-frame window of opportunity - Another agent managed to get hit by my charged shot before re-vanishing to the screen edge - The helpful kid spawned Weapon6, the purple auto-firing weapon with the shortest death animation - I managed to squeeze in one more shot while still rolling into scene 6 in time. I just need one more miracle, that is it. That "one more shot" needs to hit something. If that works out, I will likely hit the perfect theoretical limit for 1-3. There is no manipulating the agent elsewhere -- That agent WILL jump in from the left side. This is because the helpful kid forces the RNG to one of several specific values, thanks to how the silly RNG works. All changing the RNG (by no more than a few rolls) would do is change what the kid gives me, not where the agent spawns. So, anyone is free to try to beat what I've got. I don't know how I can change the circumstances a bit more at this point. I'm so close... So close.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
No real progress. Just dumping this script on to you for your viewing pleasure. There are two glitches with this script, but they are not of high priority to fix. Besides, said glitches are pretty out of the way for me anyway. EDIT: Some extra stuff to the script. Some of the additions are hacked in, but the current need is to identify helicopter stuff in 1-4. Download AHscan.lua
Language: lua

--Constants we might want to change: local MAX_RNGLIST= 20 --How many RNGs to show? --0x8AA7C5B0 6000 RNG rolls --0x3FB02DC9 6499 RNG rolls --Acmlm's piece of work identifying some things, with some changes from me. local types={ [ 0]={"Particle" }, [ 1]={"Player" ,color= 0x00FF00FF}, [ 2]={"1-1 boss 2's eye" }, [ 5]={"Back shots" }, [ 6]={"Monster" }, [ 7]={"Enemy" }, [ 8]={"Fire gunner 1" ,HP= 0xEE}, [ 9]={"Ice gunner 1" ,HP= 0xEE}, [ 10]={"Fire gunner 2" ,HP= 0xEE}, [ 11]={"Ice gunner 2" ,HP= 0xEE}, [ 14]={"Heli rider" }, [ 15]={"Tank rider" }, [ 16]={"Heli holding part",HP= 0xF0}, [ 17]={"Tower enemy" }, [ 18]={"KGB rider" }, [ 19]={"Jetpack guy" }, [ 20]={"Helicopter 1" ,HP= 0xEC}, [ 21]={"Helicopter 2" ,HP= 0xF0}, [ 22]={"KGB" }, [ 23]={"Metal wall" ,HP= 0xEA}, [ 24]={"Brick wall" }, [ 25]={"Bag wall" }, [ 26]={"Big missile" }, [ 27]={"Car" }, [ 28]={"3-2 boss" }, [ 29]={"Monster chain 1" }, [ 30]={"Monster chain 2" }, [ 31]={"Grenade thrower 1",HP= 0xEA}, [ 32]={"Grenade thrower 2"}, [ 33]={"Tank 1" ,HP= 0xEE}, [ 34]={"Tank 2" ,HP= 0xEE}, [ 41]={"Fly" }, [ 45]={"Crusher" }, [ 46]={"Runner" }, [ 47]={"1-1 boss 1" }, [ 48]={"1-1 boss 2" }, [ 53]={"Normal shot" ,color= -0x0000FF01}, [ 54]={"Bio shot" ,color= -0x0000FF01}, [ 55]={"Fire shot" ,color= -0x0000FF01}, [ 56]={"Ice shot" ,color= -0x0000FF01}, [ 57]={"Laser shot" ,color= -0x0000FF01}, [ 58]={"Ball shot" ,color= -0x0000FF01}, [ 59]={"3-shot" ,color= -0x0000FF01}, [ 60]={"Spread shot" ,color= -0x0000FF01}, [ 61]={"Charged shot" ,HP= 0xEC,color= -0x0000FF01}, [ 62]={"Fire splash" ,color= -0x0000FF01}, [ 63]={"Ice splash" ,color= -0x0000FF01}, [ 64]={"Grenade 1" ,color= -0x0000FF01}, [ 65]={"Grenade 2" ,color= -0x0000FF01}, [ 66]={"Grenade 3" ,color= -0x0000FF01}, [ 67]={"Grenade 4" ,color= -0x0000FF01}, [ 68]={"Grenade 5" ,color= -0x0000FF01}, [ 69]={"Grenade 6" ,color= -0x0000FF01}, [ 70]={"Grenade 7" ,color= -0x0000FF01}, [ 71]={"Grenade 8" ,color= -0x0000FF01}, [ 74]={"Monster grab" }, [ 75]={"Enemy bullet" }, [ 76]={"Enemy grab 1" }, [ 77]={"Enemy grab 2" }, [ 78]={"Thrown enemy" }, [ 79]={"Fire ball" }, [ 80]={"Ice ball" }, [ 81]={"Cannon ball" }, [ 82]={"Bullet" }, [ 83]={"Beam 1" }, [ 84]={"Beam 2" }, [ 85]={"Ground shake" }, [ 88]={"Missile" }, [ 89]={"Barrel bomb" }, [ 90]={"Mine" }, [ 91]={"Toxic barrel" }, [ 92]={"Building 1" ,HP= 0xEC}, [ 93]={"Building 2" ,HP= 0xEC}, [ 94]={"Building 3" ,HP= 0xEC}, [ 95]={"Building 4" ,HP= 0xEC}, [ 96]={"Building 5" ,HP= 0xEC}, [ 97]={"Building 6" ,HP= 0xEC}, [ 98]={"Building 7" ,HP= 0xEC}, [ 99]={"Building 8" ,HP= 0xEC}, [100]={"Building 9" ,HP= 0xEC}, [102]={"Building 11" ,HP= 0xEC}, [103]={"Building 12" ,HP= 0xEC}, [104]={"Building 13" ,HP= 0xEC}, [105]={"Building 14" ,HP= 0xEC}, [106]={"Building 15" ,HP= 0xEC}, [108]={"Vehicle 1" ,HP= 0xEC}, [109]={"Vehicle 2" }, [110]={"Bus 1" }, [111]={"Bus 2" ,HP= 0xEC}, [112]={"Bus 3" }, [122]={"Weapon gift" ,color= 0x00FFFFFF}, [123]={"Weapon drop" ,color= 0x00FFFFFF}, [132]={"Flower" ,color= 0x00FFFFFF}, [133]={"30 grenades" ,color= 0x00FFFFFF}, [134]={"Weapon giver 1" ,color= 0x00FFFF80}, [135]={"Weapon giver 2" ,color= 0x00FFFF80}, [157]={"Bullet shooter" }, [159]={"Tornado" }, [160]={"Scorpion" }, [161]={"Vulture" }, [162]={"Robot bomb" }, [163]={"Vulture feather" }, [164]={"Robot" }, [168]={"Sludge hand" }, [170]={"Falling sludge" }, [173]={"Big sludge" }, [176]={"Water splasher" }, [177]={"Pudding sign" }, [180]={"1-2 boss?" }, [181]={"2-3 boss" }, [185]={"2-3 boss missile" }, [186]={"2-1 boss part 1" }, [187]={"2-1 boss part 2" }, [188]={"2-1 boss part 3" }, [189]={"2-1 boss part 4" }, [195]={"2-2 boss" }, [199]={"2-2 boss small" }, [203]={"2-2 boss tiny" }, [205]={"3-1 boss head" }, [206]={"3-1 boss claws" }, [207]={"3-1 boss body" }, [208]={"3-1 boss tail" }, [214]={"Final boss" }, [219]={"Large shot" }, [222]={"Alien piece" }, [223]={"Large grenade" }, [224]={"Large red grenade"} } --Second, a few sanities I want to make: local R4s= memory.readdwordsigned --Read 4 bytes, signed local R4u= memory.readdword --Read 4 bytes, unsigned local R2u= memory.readword --Read 2 bytes, unsigned local green= 0x00FF00FF local green2= 0x00A000FF local cyan= 0x00FFFFFF local white= -0x00000001 local violet=-0x00FF0001 local red= -0x00DFFF01 local orange=-0x005FFF01 local fade= -0x00000080 local shade= 0x000000D0 local PXpos,PYpos,PXspd,PYspd= 0,0,0,0 local CamX = 0 local CamY = 0 local function NULLfn() end --***************************************************************************** local function RefreshStats() --***************************************************************************** spacemode= R2u(0x030016DB) if spacemode == 0 then cooldown = R2u(0x03000476) + R2u(0x03000478)*8 ammo = R2u(0x03000472) grenades = R2u(0x03000474) .. ":" .. R2u(0x03000310) CamX = R4s(0x03000170) CamY = R4s(0x03000370) -- CamY = 0x58000 if R2u(0x03000470) == 7 then ammo= ammo/6 end else cooldown = R2u(0x030016CC) ammo = R2u(0x030016B4) grenades = R2u(0x030016C8) CamX = R4s(0x03000248) CamY = R4s(0x0300024C) end charge = R2u(0x0300047E) scoreL = R4s(0x03000484) scoreT = R4s(0x03000134) tokill = R2u(0x03000328) bosshp = R2u(0x030003F6) end --############################################################################# --############################################################################# --Object detection Module local LinkSel= 3 local BaseLink= { {0x03000500, "Objects"}, --All ingame objects that need tracking is here. {0x0300050C, "Vehicle"}, --Naturally, these drive around. {0x03000518, "Hit me!"}, --Hitboxes. The kinds that are actually used! {0x03000524, "Shots" }, --Projectiles of all sorts. {0x03000530, "Enemy" }, --Apparently the low-class enemies. {0x0300053C, "Alt?" } --Alternate of "Objects". } --My favorite base is one marked as "Hit me!". --***************************************************************************** local function NextLink(ptr) --***************************************************************************** --Returns two values: An object pointer (possibly nil) and a link pointer. local PTR= R4s(ptr) local OBJ= R4s(PTR+8) if OBJ == 0 then OBJ= nil end return OBJ, PTR end local H= {} --***************************************************************************** local function PutHitbox(obj,index) --***************************************************************************** local Xpos,Ypos= R4s(obj+0x80),R4s(obj+0x84) local X_hitbox= R4s(obj+0x70) local Y_hitbox= R4s(obj+0x74) local Y_offset= R4s(obj+0x6C) local Left= Xpos - X_hitbox local Right= Xpos + X_hitbox local Up= Ypos - Y_hitbox/2 + Y_offset local Down= Ypos + Y_hitbox/2 + Y_offset local tbl= H[index] or {} tbl.obj= obj tbl.L= (Left -CamX)/1024 --By pixel, in relation to camera tbl.R= (Right-CamX)/1024 tbl.U= (Up -CamY)/1024 tbl.D= (Down -CamY)/1024 local T= types[R4s(R4s(obj+0x68))] if T then tbl.color= T.color or -0x00FFFF01 if T.HP then tbl.HP= R2u(obj+T.HP) else tbl.HP= nil end else tbl.color= 0x0080FFFF end H[index]= tbl end local PlPosX, PlPosY, HiPosX, HiPoxY, DistanceEst --***************************************************************************** local function WalkList() --***************************************************************************** local obj, ptr= NextLink(BaseLink[LinkSel][1]) local count= 0 PlPosX, PlPosY, HiPosX, HiPoxY= nil, nil, nil, nil while obj do count= count+1 if count > 200 then error("FRK goofed, shutting down") end --Panic. PutHitbox(obj,count) --H[count].HP= R4s(R4s(obj+0x68)) if R4s(R4s(obj+0x68)) == 1 then PlPosX,PlPosY= R4s(obj+0x80),R4s(obj+0x84) elseif R4s(R4s(obj+0x68)) == 16 then HiPosX,HiPosY= R4s(obj+0x80),R4s(obj+0x84) end obj, ptr= NextLink(ptr) end H[count+1]= nil if PlPosX and HiPosX then local Xdelta, Ydelta= PlPosX-HiPosX , PlPosY-HiPosY DistanceEst= (Xdelta^2 + Ydelta^2)^(0.5) else DistanceEst= nil end end --############################################################################# --############################################################################# --RNG Module local RNGaddr= 0x030019E0 local BigNum= 0xFFFFFFFF +1 --Using 0x100000000 directly fails somehow. --***************************************************************************** local function Roll(v) return ((v*0x0019660D)+0x3C6EF35F) % BigNum end -- function Unroll(v) return ((v*0xFEE058C5)+0x25D60FE5) % BigNum end --***************************************************************************** --***************************************************************************** local function Unroll(v) --***************************************************************************** --Inverse of Roll; Goes backwards through the RNG. --This expanded function is needed for the fact double-precision float fails. local LowWord= v % 0x10000 --Splitting the value into two. local HighWord= v - LowWord --Double-precision float not good enough! HighWord= (HighWord*0x011FA73B) % BigNum --Using the negative. Fewer LowWord= (LowWord *0x011FA73B) % BigNum --bits, but not enough... return ( 0x25D60FE5 - (HighWord + LowWord) ) % BigNum end local CurrentRNG= 0x00020080 local RNGcount= 0 local RNGpanic= false --***************************************************************************** local function CountRolls(RN) --***************************************************************************** if RN == CurrentRNG then return 0 end local Next,Prev= CurrentRNG, CurrentRNG for i= 1, 2000 do --Create a MAX_COUNTRNG variable? Next= Roll(Next) if Next == RN then return i end Prev= Unroll(Prev) if Prev == RN then return -i end end return false -- Uh, I'm not searching anymore, this is where you panic. end --***************************************************************************** local function CountRollsFromScratch() --***************************************************************************** local R= 0x00020080 local T= R4u(RNGaddr) for i= 0, 200000 do if R == T then RNGcount= i; return end R= Roll(R) end RNGcount= -99 end --***************************************************************************** local function FindType(RN) --***************************************************************************** --Takes in RNG state. --Returns new RNG state, and rolls to find type local rolls= 0 repeat rolls= rolls+1 RN= Roll(RN) until bit.band(RN,0x00070000) == 0x00070000 -- Known constant, but... return RN, rolls end --***************************************************************************** local function FindDrop(RN) --***************************************************************************** --Takes in RNG state. --Returns new RNG state, rolls to reach RNG state, and rolls to determine type. local rolls= 0 repeat rolls= rolls+1 RN= Roll(RN) until bit.band(RN,0x000F0000) == 0x00000000 -- Uh, might change... local junk, type= FindType(RN) return RN, rolls, type end local RList= {} local TList= {} TList[0]= 0 --***************************************************************************** local function RefreshRNGList(RN) --***************************************************************************** local rollR, rollT= 0, 0 local R2= RN for i= 1, MAX_RNGLIST do local roll, type RN, roll, type= FindDrop(RN) rollR= rollR + roll local tbl= RList[i] or {} tbl.roll= rollR tbl.type= type RList[i]= tbl R2, type= FindType(R2) rollT= rollT + type TList[i]= rollT end RList.RNG= RN TList.RNG= R2 end --***************************************************************************** local function AdvanceRNGList(rolls) --***************************************************************************** local len= MAX_RNGLIST if (RList[len].roll < rolls) then RefreshRNGList(CurrentRNG); return end local i= 1 while RList[i] do RList[i].roll= RList[i].roll-rolls if RList[i].roll <= 0 then table.insert(RList,table.remove(RList,i)) local R, rl, ty= FindDrop(RList.RNG) RList[len].roll= RList[len-1].roll+rl RList[len].type= ty RList.RNG= R else i= i+1 end end i= 1 while TList[i] do TList[i]= TList[i]-rolls if TList[i] <= 0 then table.remove(TList,i) local R, rl= FindType(TList.RNG) TList[len]= TList[len-1] + rl TList.RNG= R else i= i+1 end end end --***************************************************************************** local function HandleRNG() --***************************************************************************** local NewRNG= R4u(RNGaddr) local rolls= CountRolls(NewRNG) CurrentRNG= NewRNG if not rolls then RNGcount= 0 --Panic. Use some substitute. RefreshRNGList(NewRNG) --Full refresh. Can't even guess where we are. else RNGcount= RNGcount + rolls if rolls < 0 then RefreshRNGList(NewRNG) elseif rolls > 0 then AdvanceRNGList(rolls) end end end --Immediate code to execute. CountRollsFromScratch() CurrentRNG= memory.readdword(RNGaddr) RefreshRNGList(CurrentRNG) --0x8AA7C5B0 6000 RNG rolls --0x3FB02DC9 6499 RNG rolls --0x01E196B8 7000 RNG rolls --***************************************************************************** local function CheatModifyRNG(v) --***************************************************************************** local r= 0x01E196B8 for i= 1, v do r= Roll(r) end CurrentRNG= r if r >= 0x80000000 then r= r-BigNum end memory.writedword(RNGaddr,r) RNGcount= 7000+v end --############################################################################# --############################################################################# --Display Module --***************************************************************************** local function GuiTextRight(x,y,str,c1,c2) --***************************************************************************** str= tostring(str) x= x - (#str)*4 gui.text(x,y,str,c1,c2) end --***************************************************************************** local function HexStr(v) --***************************************************************************** local str= "" if v < 0 then str= "-" v= -v end return str .. string.upper(string.format("%x",v)) end --local zzxx= 0x00020080 --for i= 1, 7200 do -- zzxx= Roll(zzxx) --end --for i= 7201, 7226 do -- zzxx= Roll(zzxx) -- print(i .. " - " .. HexStr(zzxx) ) --end --***************************************************************************** local function HexVal(a) return HexStr(R4s(a)) end --***************************************************************************** local ObjTrace= nil --***************************************************************************** local function WatchObj() --***************************************************************************** if not ObjTrace then return end GuiTextRight(190, 0,HexStr(ObjTrace), green) GuiTextRight(190, 8,HexVal(ObjTrace+0x90)) GuiTextRight(190, 16,HexVal(ObjTrace+0x94)) GuiTextRight(190, 24,HexVal(ObjTrace+0x98)) GuiTextRight(190, 32,HexVal(ObjTrace+0x9C)) GuiTextRight(190, 40,HexVal(R4s(ObjTrace+0x68)),cyan) end local XSCR, YSCR= 240, 160 local offX, offY= 0, 0 local Sc= 1 --***************************************************************************** local function PaintHitboxes(scale) --***************************************************************************** if scale > 1 then gui.box(offX,offY,offX+XSCR/scale,offY+YSCR/scale,0,fade) end local i= 1 while H[i] do local x1= math.floor(H[i].L/scale)+offX local x2= math.floor(H[i].R/scale)+offX local y1= math.floor(H[i].U/scale)+offY local y2= math.floor(H[i].D/scale)+offY gui.box(x1,y1,x2,y2,0,H[i].color) if H[i].HP then gui.text(x1,y2+1,H[i].HP) end i=i+1 end end local TypeClr= { [0]= green, --Grenade pack green2,--Green cloud gun orange,--Flame cyan, --Ice fade, --Bleh fade, --Also Bleh violet,--Humn red, --Yay } --***************************************************************************** local function RNGHUD() --***************************************************************************** for i= 1, MAX_RNGLIST do local clr= TypeClr[RList[i].type%8] GuiTextRight(240,7*(i-1), string.format("%d:%2d",RList[i].roll,RList[i].type),clr,shade) clr= fade; if TList[i] >= TList[i-1]+8 then clr= white end GuiTextRight(210,7*(i-1), TList[i],clr,shade) end end local CrgLvl= {51,72,98,128,162,200 ,200} --***************************************************************************** local function BasicHUD() --***************************************************************************** -- gui.text(1,1,spacemode) WatchObj() if cooldown == 0 then gui.text(0,1,"Ready",green) else GuiTextRight(20,1,cooldown) end GuiTextRight( 20, 9,ammo) GuiTextRight( 20,17,grenades) GuiTextRight(240,152,HexStr(CamX)) -- GuiTextRight(180,152,HexStr(CamY)) --Later, I'll separate them out... local a= R2u(0x03000332) --Camera lock flag if bit.band(a,1) == 1 then gui.text(120,152,"LOCK",red) a= R2u(0x03000328) -- Kills left if a ~= 0 then gui.text(140,152,a,green) end end if charge ~= 0 then GuiTextRight(21,30,charge) local b= 7 for i= 1, 6 do if charge < CrgLvl[i] then b= i; break end end gui.text(21,30,string.format("/%3d",CrgLvl[b])) if b == 1 then GuiTextRight(21,38,"Wait",red) else GuiTextRight(21,38,b+3,green) end end a= R2u(0x0300031A) -- Enemy spawn timer if a == 30 then gui.text(120,144,"SPAWN",red) else gui.text(120,144,"Spawn") end a= string.format("Timer: %2d",a) gui.text(144,144,a) GuiTextRight(240,142,RNGcount,green) if bosshp ~= 0 then GuiTextRight(152,6,bosshp,fade,shade) end end --############################################################################# --############################################################################# --User Control Module local keys, lastkeys= input.get(), input.get() --So we have some default state --***************************************************************************** local function UpdateKeys() lastkeys= keys; keys= input.get() end local function Press(k) return keys[k] and not lastkeys[k] end --***************************************************************************** --***************************************************************************** local function Rescale(adj) --***************************************************************************** -- Affects the Display Module; Hitbox scaling for off-screen viewing. Sc= math.max(Sc+adj,1) offX= XSCR*(1 - 1/Sc) / 2 offY= YSCR*(1 - 1/Sc) / 2 end --***************************************************************************** local function Trace() --***************************************************************************** local i= 1 local mX, mY= keys.xmouse, keys.ymouse while H[i] do if (mX >= H[i].L) and (mX <= H[i].R) and (mY >= H[i].U) and (mY <= H[i].D) then ObjTrace= H[i].obj return end i= i+1 end end local Obox= 1 local OHUD= 1 local ShowBoxes= PaintHitboxes local ShowRNG= RNGHUD --***************************************************************************** local function KeyScan() --***************************************************************************** UpdateKeys() if keys.numpad6 then LinkSel= (LinkSel%6)+1 end if keys.numpad7 then Rescale( .125) end if keys.numpad1 then Rescale(-.125) end if keys.numpad8 then Obox= math.min(Obox+.125 , 1); ShowBoxes= PaintHitboxes end if keys.numpad2 then Obox= math.max(Obox-.125 , 0); if Obox <= 0 then ShowBoxes= NULLfn end end if keys.numpad9 then OHUD= math.min(OHUD+.125 , 1); ShowRNG= RNGHUD end if keys.numpad3 then OHUD= math.max(OHUD-.125 , 0); if OHUD <= 0 then ShowRNG= NULLfn end end if keys.leftclick then Trace() end if keys.numpad5 then CountRollsFromScratch() end if keys.numpad0 then RNGcount= 0 end end --############################################################################# --############################################################################# -- Immediate local zZz= 0 --***************************************************************************** local function Fn() --***************************************************************************** local h= R2u(0x020087C6) if h < 300 then gui.text(1,132,movie.framecount()-299+h,cyan) end end local ScM,ScE,ScB,ScS= 0, 0, 0, 0 --***************************************************************************** local function ScoreCalc() --***************************************************************************** -- Because I'm feeling silly today --*0484 -- Primary score --*0488 -- ( 11 E_S) Kill count --*048C -- Usual kills --*0490 -- Grenade kills --*0494 -- ( 51 __S) Bites --*0498 -- ( 5 E_S) Knife kills --*049C -- ?? --*04A0 -- ?? --*04A4 -- ( 11 _BS) Damage to bosses, for boss score --*04A8 -- (100 __S) Buildings destroyed --*04AC -- ?? ScM= R4s(0x03000484) ScE= 11*R4s(0x03000488) + 5*R4s(0x03000498) ScB= 11*R4s(0x030004A4) ScS= 51*R4s(0x03000494) +100*R4s(0x030004A8) + ScE + ScB end --***************************************************************************** local function DispScore() --***************************************************************************** GuiTextRight( 60, 1,ScM,cyan) GuiTextRight( 60, 9,ScE,red) GuiTextRight( 60, 17,ScB,violet) GuiTextRight( 60, 25,ScS,green) GuiTextRight( 60, 34,ScM+ScE+ScB+ScS) end --############################################################################# --############################################################################# --Main loop --***************************************************************************** local function GuiStuff() --***************************************************************************** gui.opacity(Obox); ShowBoxes(Sc) gui.opacity(OHUD); RNGHUD() gui.opacity(1); BasicHUD() -- Fn() -- DispScore() if DistanceEst then GuiTextRight( 60, 1,math.floor(DistanceEst/1024),fade) GuiTextRight( 60, 9,math.floor((PlPosX-HiPosX)/1024)) GuiTextRight( 60,17,math.floor((PlPosY-HiPosY)/1024)) GuiTextRight( 90, 9,PlPosX-HiPosX) GuiTextRight( 90,17,PlPosY-HiPosY) end end gui.register(GuiStuff) --***************************************************************************** local function FrameUpdates() --***************************************************************************** RefreshStats() -- ScoreCalc() KeyScan() WalkList() HandleRNG() -- if Press("Z") then CheatModifyRNG(zZz); zZz= zZz+1 end end emu.registerafter(FrameUpdates) FrameUpdates()
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Derakon wrote:
With TASE, by any chance is E dead at that point? Because then you'd have TAS, which is a clear winner. :)
We could instead have STAR -> RTAS for a nice subliminal message. Even better, it might even be within the first minute or so! Dead characters still have their names intact, I believe. Even so, E would not die at all in that particular formation.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Hey, Microstorage looks like it's back up! As for the letters AEST... SATE - 1234 Begin EATS - 4231 Immediate switch TESA - 3412 Pre SEI-RYU TSAE - 3124 Post SEI-RYU SATE - 1234 After Monster Trio EAST - 1234 Begin TASE - 4231 STEA - 3412 SEAT - 3124 EAST - 1234 Hrm... Don't forget we'll eventually get a 5th character, who will replace one of our dead party members. This lets us introduce a new letter while getting rid of an old one! Though, we could always go with the classic A B C D and E. We can also leave one character nameless and still know who's doing what well enough. If we can avoid tearing our hair out from luck manipulation twice over, maybe an alternate run with the fastest names of leaving them blank and see how that goes.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Bobo the King wrote:
Microstorage seems to be down currently, but I'll check these out as soon as reasonably possible. Tell me if the links work for you.
Nope. I'm having trouble. We may need to use an alternate method if this stays like this for long.
Bobo the King wrote:
Hmmm... I'm starting to think that the anagram thing may be too subtle and stupid. Have you determined the party order throughout the game? It will much more difficult to deduce a good anagram without knowing how the words rearrange themselves.
Start: 1234 (obviously, whatever we start with is our start order) Before first battle: 4231 At SEI-RYU: 3412 After SEI-RYU: 3124 (Due to death of 4) After Monster Trio: 1234 (Due to death of 3) After getting 5th member: ???? (We, uh... Will figure it out, I hope)
Bobo the King wrote:
What the... ah crap! HAHAHAHA! We spent, what, five pages deducing the RNG? I swear I searched for it in the ROM, but I guess I just didn't look hard enough.
Well, it was placed in RAM, nevermind what code generates it into RAM. But regardless, this was a surprise to hear the table sitting there.
Bobo the King wrote:
Edit 2: Also, I've figured out how to use IRC. I'm currently on the TASVideos channel, for what it's worth. I don't think there's any need to chat in realtime at the moment, but when the run starts ramping up, we may want to communicate via IRC or AIM. Tell me if you use an IM service at all and I'll PM you my screenname(s) (eventually).
I sat myself in IRC now. Now on #tasvideos channel. My IRC nick is pretty similar to the name I use here.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
nitsuja wrote:
[...] Although for all I know somebody broke emu.frameadvance in a later version (can somebody explain why the LuaScripting page says it's 'bugged'?).
Last I tried emu.frameadvance() in DeSmuME 0.9.6, it did not emulate frames when I tap the actual frame advance key. Even when all that's coded was while true do emu.frameadvance() end, the act of running that nearly empty script prevented emulating each frame one at a time. Works perfectly fine if the emulator isn't paused, which kind of conflicts with the point of TASing. And when I hit the frame advance key, the frame counter does increment... But there's no emulation taking place to go with the increment, at least on this computer. Skipping the usual loop involving emu.frameadvance and simply using the registers instead works just fine, though. I'm guessing this is why it's labeled 'bugged', basing it off my own experience. Can't say I know of any changes since then, due to the fact this computer can't run later versions.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Ah, lua scripting stuff is sort of a mess at times. I did some investigating with some quick scripts, and it looks as though sticking a gui.text( 1 , 1 , memory.readbyte(0x7E0000) ) (or some other memory address other than 7E0000) anywhere always reports what the value was one frame ago in Snes9x 1.51. I've checked the standard while true do [...] emu.frameadvance() end loop, as well as the three main registers one could use, emu.registerbefore, emu.registerafter, and gui.register. The results were all the same: I see what the value was one frame ago, not what it is now. Nothing wrong with your code. I just don't see any way of having it display up-to-date information in Snes9x, as it stands.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Found another three frames. Or maybe I removed them. Or perhaps saved them. Or... Gah, silly words. In any case, I just had to jump on that building. I thought something was fishy about it. And indeed, after messing with the RNG some more, an agent would conveniently drop a spread for me, and I reached the Tank4&5 scene a few frames earlier. I think it looks a touch more stylish, in any case. Now to look at 1-3 and see what sort of RNG I'll need to begin well.
Post subject: Dragon Dance
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Dragon Dance is a Breakout-style game, much like Arkanoid. Basically, you bounce a ball around to break colorful bricks, especially the most frustrating last one. .vbm quick test Your "paddle" is some sort of green Chinese dragon of some 2-5 segments in length. Losing the ball or getting hit by a hazard reduces this length by 1 block, and if you would go less than 2, you lose. The length carries over between stages, so you might be crippled for a while if you lose a ball or two. A shortened length is almost certainly not an issue in a TAS. One interesting control aspect is that you actually do have slight control over your height, which can give much finer control over where that ball ends up. In addition, if you destroy multiple blocks without the ball touching the paddle in the interim, a meter at the top of the screen fills up. When it has filled up enough, you can transform the dragon into other colored dragons! Triggering said transformation will empty out the meter and keep it emptied for as long as the change lasts (it expires over time, but it's a rather long time). However, this meter does carry over between stages, but not the transformations, do be aware. The first available transformation freezes the timer and lets you freeze the ball in place once. The "freeze the ball" part is recharged when the ball hits the "paddle". The next one lets you reflect the ball in mid-air once. If the ball is traveling upwards, it's a left-right reflection. If it's going down, it will reflect up. This reflection power is recharged when the ball hits the "paddle". The third effect produces a horizontal wall. Stays until you get rid of it. Recharges in a short time. The last one, when the meter is nearly full, lets you shoot fire. Classic Arkanoid lasers effect, really. When the meter fills up completely, a time-wasting scene takes place. It wastes time, and lots of it. Regardless, it could clear out random bricks (including otherwise indestructible ones), restore your "paddle's" length, or set your remaining time to 99. So before it fills up, I suggest you use a power to avoid such time-wasting scenes. There's 100 levels. 10 of them are sort of "boss battles" or something. The ball does travel quick at speed 10. I've noticed some lag while making a small TAS attempt up there. There's a significant wait at the end of each level, though. In that attempt, I actually did set REFLECT to SPECIAL (trust me. The graphics during the fade-out lies, I tell you!), which lets the RNG play a more prominent role in how the ball bounces. I'm just raising awareness of this game. I have no plans to make a full run myself. If it's interesting enough, great. If not, I wouldn't be upset at the loss of this thread anyway.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Don't you think frame 11995 would make for a neat picture? I sure think so. Up until the boss, I've shaved off 300 frames off T5's run and 131 frames off the more optimal T1's run. Adding 1-1 savings to that, it's a total of 313 frames off T5's run and 381 off T1. I do not wish to count the fact T1 didn't eat the boss. That's 3318 frames from the boss alone, by the way. I did try a slightly different path involving fire/ice shots. Didn't work out so well against the upcoming tanks compared to spread. Bah, the CloudStacking trick, as I call it, isn't advantageous here. I still have some things to check, though. I really hate that tank shot, in case you're curious. I may have to mess with the RNG a little for the next stage. T1 and T5 have 5929 and 5929 RNG rolls at this time, coincidentally enough. This run has 5286 RNG rolls, hundreds fewer than the noted runs, and I'm not sure how that's going to turn out.