Posts for FatRatKnight

Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
zeromus: Fair enough. BizHawk is mostly trying to advance in getting the best in emulation into a single TASing platform (my impressions), which left various features underdeveloped as of this time. There's a lot of things about BizHawk's lua that frustrates me, as even the emulua in non-lsnes emulators seem to be superior in a few aspects than BizHawk. I'll downsize my complaints: Why the distinction of signed/unsigned memory writes? Why isn't the complete memory map (BUS?) the default memory region? Why does gui.drawText have no background color? There probably isn't need to go into detail as of this moment, unless someone is actively rewriting the lua implementation, but it feels like I need some trial and error workaround just to have consistently readable text displayed. In any case, lua's a mess, you got the point, my complaints aren't going to speed things up, so just wait, or if I have the time, see if I can fix it myself. Apologies for any annoyance, I do rather want to stay quiet until work elsewhere is finished and there is time set aside to work on the lua back end. Just that I believe an idea I have will more likely remain existing if I post it somewhere public rather than keeping it with me until I forgot it completely.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
lsnes has gui.<class>_gap(number gap) (more specifically, gui.left_gap, gui.right_gap, gui.top_gap, and gui.bottom_gap) that can be experimented with. A replication of this set of functions is another useful request, but a separate one. The gap functions add some extra drawing space off to the specified side. I have a write-up of it somewhere in this tutorial. (I really need to get back into playing with lsnes lua some more, one of these days) lsnes also allows one to pick a custom font by selecting a file. Generate a font file that matches what the game uses, and you can use a style consistent with the game, too! I could always post a topic of my complaints with lua as implemented in BizHawk, with all my criticisms as well, and I'm considering posting my write-up for gui.drawText. There's a bit of work that can be done to make it closer to the ideal stuff I see, I would say.
Post subject: Lua function request: External drawing canvas
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
CANVASOBJECT SomeFamily.newCanvas(integer SizeX, integer SizeY, [color_spec InitialColor]) Perhaps the SomeFamily may be forms, but I don't know the best fit. The function should spawn a new window large enough to contain the drawing area (which means figuring out some way to decide how large the window itself needs to be, based on the boarder size of the scheme). The drawing area will simply be a rectangle of color InitialColor, or straight black if that parameter isn't provided. The function should return an object. Not a handle number like with form calls, an actual object that can be indexed like a table. A list of indices this object should have: CANVASOBJECT.open -- Boolean value that becomes false if window is closed CANVASOBJECT.onClose -- Starts nil; Can be assigned a function to call when window is closed CANVASOBJECT.autoClear -- Starts false; If assigned true, clears canvas every frame CANVASOBJECT.InitialColor -- Used for clearGraphics; Alpha should be ignored CANVASOBJECT:clearGraphics CANVASOBJECT:draw<various> -- I expect all related gui functions here A call to CANVASOBJECT:drawRectangle should have an effect virtually identical to the similarly named gui.drawRectangle, except that the target area would be this canvas we created earlier. Extrapolate this example with other such draw functions. If you're confused as to the use of this CANVASOBJECT, I will provide a sample code:
Language: lua

local MyCanvas = SomeFamily.newCanvas(200,200) MyCanvas.autoClear = true while MyCanvas.open do MyCanvas:drawText(0,0,"Hello World") MyCanvas:drawBox(10,30,190,190,0xFFFFFFFF,0xFF0000FF) MyCanvas:drawText(12,32,memory.read_s8(0x0080)) emu.frameadvance() end
In case it is necessary for those who don't know lua syntax, SomeTable:FunctionCall(x,y,z) is the same as SomeTable.FunctionCall(SomeTable,x,y,z) -- Note the colon or period. This will allow a way for the attached function to identify the object in question. Although, generating a new function that "already knows" when spawning multiple canvas objects would mean we don't need the colon, but it might be best to have the identifier. If such a function already exists, please point me to such function, since I missed it while looking through the functions list.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Between assisting in a guide and dealing with things at home, it left little time to focus on this. Still, I did work out a script to read the RNG. Take the 32-bit values R1 and R2. After the randomization, take the lower 16 bits of each, call them r1 and r2. Take the sum of r1*16 + r2, and finally a modulo based on the size of the dice (or some other type of RNG roll). The first battle against the five kobolds begin with a total of 22 RNG rolls: R01 - Player 1 Initiative R02 - ? R03 - Player 1 Hide check R04 - Player 2 Initiative R05 - ? R06 - Player 2 Hide check R07 - Player 3 Initiative R08 - ? R09 - Player 3 Hide check R10 - Player 4 Initiative R11 - ? R12 - Player 4 Hide check R13 - Kobold 1 Initiative R14 - Kobold 1 Hit Dice roll R15 - Kobold 2 Initiative R16 - Kobold 2 Hit Dice roll R17 - Kobold 3 Initiative R18 - Kobold 3 Hit Dice roll R19 - Kobold 4 Initiative R20 - Kobold 4 Hit Dice roll R21 - Kobold 5 Initiative R22 - Kobold 5 Hit Dice roll This is what I believe what the RNG rolls are initially used for in that battle. It's pretty nice being able to figure out exactly how many RNG rolls are being made, then comparing the rolls to some of the internal memory watch I can make. Is it just me, or are the Kobolds getting +3 initiative bonus? I don't know where they're getting it from, really. Their dexterity says they should get +1, and I don't know where the other +2 is coming from. I've looked pretty deeply into the internals, really. Anyway, there is scripting progress, at least. The first set of battles can really do with some speeding up, and that's what I plan to TAS through, should I continue.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Just felt like creating this simple script. If anyone cares to watch the whole thing again, well hey. New script to play with, I guess. It is interesting to see the route essentially works to produce Valor as quickly as possible. Most of the time you spend outside waiting is not wasted as you've got this virtue to build up anyway. Any path you spend less dungeon time is certainly prioritized. This path you took looks pretty robust. The subtitles certainly help. Definitely a good valid use of them. Alas, a few of them seem to wrap around and fill the second line just slightly, making the occasional one more difficult to read, but it's still overall an insightful read. ... Other than echoing the praises you've already gotten, I don't have much to say, really. I just wanted to share some script I pulled together real quick.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Language: lua

function map(f, arr) for index,value in pairs(arr) do result[index] = f(index,value) end return result end
The variable result is not defined anywhere in your code. Lua looks for a global result and can only find nil, and indexing nil should instead throw an error, generally putting your code to a screeching halt. Check the output on the lua console. This would happen even if the function given to map returns nothing. Adding "local result = {}" somewhere in there, preferably inside the function before the for loop, might fix things. This would make result into a table which can be indexed, and the lua will use that local result you put in the function. Outside of that, I can't spot anything else that would break it. This would be my approach when trying to paint boxes, at least to start:
Language: lua

local function ShowSprites() gui.drawRectangle(memory.readbyte(0x000B88),memory.readbyte(0x000B8C),5,5) for i= 0, 25 do local addr= 0x000BD8 + i*0x50 gui.drawRectangle( memory.readbyte(addr ), --X memory.readbyte(addr+ 2), --Y 5, 5 ) end end
... I'm just making this analysis with total blindness to the game itself. I'm only looking at the code you produced and making my own interpretations on what it means. Hope it helps.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
DiscoRico wrote:
Omnigamer wrote:
Also, I'm not sure of precedent, but since this is a "Max Score" run instead of for time, I wouldn't mind if the movie were extended out to add in initials.
I second this, if it's possible! Even if it's just "TAS" at the end, I think it'd add more value than a true "last frame input" movie.
A TAS I submitted has two separate files; One which had a final input that is enough to see the ending and credits, and a second file that plays around with the initials for a bit, long after the "proper end" of the movie. The submitted file, naturally, would be for record purposes, and the secondary one does add a little something at the end and preserving the input-free ending and credits. The secondary file is the one encoded to video.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
When I say you can't spell-heal a downed character, the option to cast Cure Wounds on them do not exist at all. The only way to fix the dying status is either get lucky with each turn or hope the turn(s) you use up on other characters using the Heal skill works. Or end battle real quick and somehow get 100% recovery rate to 1 HP instantly. Might be fun to figure out where 3.0 and this game are different. If, you know, you want to figure out the sort of mess this game really is. I've been poking at BizHawk's lua for a bit and getting frustrated. I did find out a few more things about the RNG, though. 03004D5C,4x - RNG1 03004D60,4x - RNG2 Every time the game needs a new RNG... Well, break it up into a pair of two-byte chunks... 0xHHHHLLLL - Original value (pretend you see hexadecimal stuff; Either RNG1 or RNG2, as respective of later calculations) 0x0000LLLL * 0x00004650 + 0x0000HHHH = New RNG1 0x0000LLLL * 0x000078B7 + 0x0000HHHH = New RNG2 As far as I can tell, right after this calculation, you take RNG1*16 + RNG2, then use a modulo depending on which dice you're using. Not positive, yet. Usually, you only have one degree of freedom with the RNG -- Make the extra rolls using the above formula or don't. A second degree of freedom takes place in the title menu, since at that time, it appears the game sets RNG2 to a specific value based on a frame counter, giving a new seed then and there. This means the first battle really should only give two kobolds one turn each, enough to get a character dead for better experience distribution. Figuring out all the nuances will take a while, though.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Another thing about attacks of opportunity is that when enemies walk to a square one step diagonal from one of your guys, they don't realize they're close enough, and if they still have movement points left, will continue walking -- Attack of opportunity! One can, of course, make full use of this when the situation comes up. Enemies prefer going east/west first, then north/south. If you can't tell from the isometric view what east is, it is a slightly rotated view from the in-game map you can view. If, you know, Intuit Direction succeeds and orients the map correctly. This sort of thing is certainly useful to know when your spells can't completely do the job. As for how accurately it portrays 3.0, it seems to slip on a few details. Turn Undead outright destroys undead of similar HD as the cleric, rather than scaring them. It seems all physical attacks against a helpless target are automatically "coup de grace", even at range and enemies are nearby to bother you (this still takes a standard action and doesn't provoke attacks of opportunity). You can't cast spells on the defensive to avoid attacks of opportunity, and touch range spells must be cast up close to be used at all and are wasted if they miss. You can't heal the unconscious with spells, so once down, they stay down until the battle ends. Are any of these true in the pen & paper? Lets not get into the fact a few items and spells use the wrong dice, some touch spells bypass dodge, item specials stop working after one step, and... Yeesh, there are so many things just wrong that it's hard to list them all. I'll just state that Lesser Restoration does the opposite it should, "curing" your Bull's Strength while leaving actual stat damage alone. This is still not the worst of it.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
User movie #21139027649081064 Just checking a route. This looks pretty good, just needs cleaner luck manipulation. Combat is very slow, but field movement is very fast. I probably should equip the Sling earlier, to avoid walking to the sleeping Kobolds. I need a Cleric with high Charisma. The Swords file begins with Garon, a Cleric with 18 Charisma. Also useful is the fact he is small, which makes it more likely to begin combat with the Hide Flag set. The file also has Wobby, and I generate two "fodder" Wizards to kill early on, but I pick up Knucklebone and swap Wobby out for experience related issues. Curiously, Wobby and Knucklebone has the same miniature, so unless you play this frame-by-frame, you can't tell I swapped characters. You can move and turn at the same time: Forward/backward takes place first, then you turn. You can also repeatedly turn while moving through hallways to manipulate luck without losing time. You can also press A and move at the same time: Some doors can be moved through in the same frame without a soft-lock, others you might need to back up. A and B simultaneously can open doors and open the menu, useful for times where you can't otherwise move to bypass the door animation, a very useful fail-safe, as you can close the menu and move right away regardless of whether the animation is still going or an undesirable soft-lock if you do move. Walking forwards can trigger encounters from a long distance; Walking backwards will only trigger an encounter if you end up next to one. Additionally, it adjusts the formation based on the direction you're facing, so picking forward/backward can give a better position for combat. Sleep is overpowered. Note its use early on. My follow-up attacks against sleeping targets are not manipulated -- They will always hit, and always deal damage equal to remaining HP. The Sleep spell itself does need manipulation, though. A Sling deals 1d4 damage with no way to normally exceed 4 damage, yet it did 6 damage to a sleeping target at range thanks to this odd mechanic. Sleeping targets pass their turns faster than non-sleeping ones, which is another boon. The Hide Flag is a very important flag. At combat start, Hide checks are done with each member of your party. If your entire party starts hidden, enemies will pass their turns very quickly, so even if initiative is not in your favor, being hidden means you only lose a short number of frames waiting. Experience is distributed among members who were alive at some point during battle. Because useful spells like Snilloc's Snow. Swarm and stat-boosting spells don't show until level 3, I'm strongly encouraged to kill some members to give the EXP to my Cleric and primary Wizard. The result is that I get access to Snow. Swarm early enough to deal with the Kobold Miner group. Thus, it is prudent to spend significant time to suicide created Wizards with low HP early on. Annoyingly, it's difficult to kill them off on the enemy's turn, as being unconscious denies enemy targeting unless everyone else is hidden, so the "fodder" needs to withstand the enemy's turn, then I have to abuse their Attacks of Opportunity for one hit to KO, then the next for that "coup de grace" that always kills. The power of Turn Undead should be noted, since right after dealing with Kobolds, it's rather refreshing to see skeletons and zombies falling apart the instant combat starts. Charisma lets you hit larger undead hordes and more likely to destroy the higher HD (well, "level" if you prefer) ones. The Baneguard have annoyingly high HD, requiring some hefty manipulation to defeat them. The Specials Unequip glitch is certainly pretty handy to use for going even faster. It requires a detour through two skeleton groups to get the Rusty chest holding the Magical Cape. When worn, it adds a special, and when removed, it screws up the first special slot. These special slots are used, among other things, to determine what stats to revert to normal when the special is removed. Since it screws up whatever is in the first slot, things like Bull's Strength, Endurance, and Eagle's Splendor becomes a lot more interesting. I make it a point to have it equipped before I camp, so that it can screw up the first slot again without first putting its own special in that slot when I equip it. Glitched Strength should give handy one-hit kills with physical attacks, particularly important versus Albrik and other tough monsters. Glitched Dexterity gives initiative and ridiculous number of Attacks of Opportunities with Combat Reflexes, in case I can't Fireball everything dead. Glitched Constitution is garbage. Glitched Charisma lets Turn Undead hit larger undead hordes, as well as make it more likely to hit the tougher ones, in case the RNG is a mess. In any case, it looks like the route I'm thinking of will work. There's enough experience for a two-person party to get the necessary spells, so things should go real smooth after that. EDIT: Some addresses of note. These addresses were obtained through VBA, but they should match up with the BUS addresses in BizHawk (I have trouble working out the mappings of other regions). 03004D60 : 4 bytes - RNG 03002140 - X position 03002144 - Y position 0300041C : 56 bytes : Unknown count - Combatant information +00,1u - Index number? +01,1u - X position +02,1u - Y position /\/\ +07,1s - Initiative /\/\ +09,1s - HP +0A,1s - HP max +0B,1x - Actions available (bit map: 123xxxxx: 1= 5-foot step ; 2= move-equiv. ; 3= Standard) /\/\ +0D,1x - Hide Flag +0E,1x - Flatfoot Flag +0F,1u - Attacks of Opportunity left /\/\ +18,4x - Pointer to ? +1C,4x - Pointer to ? /\/\ +2C,4x - Pointer to character definition /\/\ +34,4x - Pointer to status field (72 bytes) 0300217C : 304 bytes : Unknown count - Character information 0837D89A - BDAT information begins here (ROM) 083A3CB6 - BDAT information ends here (ROM) I have a lot of information on the internals. Rather voluminous for a single post, really. My lists on GameFAQs are largely based on the BDAT I found, and some significant VBA scripting to extract it to a readable format. It's been a while since I last used my extraction script, so I'm not sure how it's set up right now.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Language: lua

function correction(screen,x,name) if screen == 0 then name = x end if screen == 1 then name = x + 255 end end
The function modifies name, but name is merely a copy of whatever was passed to the function, and not the same variable from whoever called this function. Once this function implicitly returns, this copy is discarded, and there is no change to whoever passed name to the function. Let's see this snippet...
Language: lua

--Player 3: --Coordinates: p3X = memory.readbyte(0x00A7) correction(p3s,p3X,p3Xc) p3Y = memory.readbyte(0x00D1) p3Z = memory.readbyte(0x00BC)
Perhaps we should try this?
Language: lua

function correction(screen,x) if screen == 0 then return x end if screen == 1 then return x + 255 end end --Elsewhere... Just pretend I copied everything else here. --Player 3: --Coordinates: p3X = memory.readbyte(0x00A7) p3Xc= correction(p3s,p3X) p3Y = memory.readbyte(0x00D1) p3Z = memory.readbyte(0x00BC)
Basically, have the function return something, rather than trying to modify a value passed to it, as a modified value will never be seen by something calling the function. I suppose you could use tables, but that's a whole other mess to get into. The function call, once it finishes, essentially becomes whatever it returns, rather than a function object. Obviously, you're getting a number from memory-readbyte calls rather than the function itself, similar thing here when you use a return statement (or nil, if returning nothing or never using a return statement). This may be a late response, but hopefully this quick glance over your code is enough to answer your question. ... On a side note, it was confusing with the leading whitespace with your function statements. With the end statement that signifies the end of the function, I recommend having zero leading whitespaces, as you're now back at the top level, so to speak. Between that end statement for your first function and the start of the second function, you're not "inside" anything, so there's no need for leading whitespace.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
http://www.gamefaqs.com/boards/561612-dungeons-and-dragons-eye-of-the-beholder Info. Here. You might want to investigate this for a little bit. I've been theorizing a route: * Begin with a Wizard, a Cleric, and two fodder * Kill the fodder soon -- You need EXP for your spellcasters. * Abuse Sleep on living targets (stops their actions and allows instant death fun with follow-up physical attacks -- against a group per casting!) * Abuse Turn Undead against... Um, undeads. Also instantly slays stuff for fun and profit. * Grab Knucklebones and ditch the starter Wizard, she starts with some useful EXP. * Work your way to the third level, skill-open the rusty chest, get the Magical Cape * Get to level 3 for access to Bull's Strength and other stat-buff spells * Glitch-boost Strength to phenomenal levels (and other stats if necessary) * Get Akordia at floor 6 and ditch the starter Cleric -- Again, EXP issues * Waltz to the endgame with ridiculous stats If necessary, it is viable to purchase Cone of Cold scrolls and get some Lv1 Wizards to use 'em on large groups, though this takes luck. The RNG (address 03004D60 through VBA) is affected by waiting on the title menu and by moving two steps. I haven't worked out the particulars of it other than it is only called when needed, but having the address should help out. Doors can be opened faster by moving backwards on the same frame you press A to open it. Turning instead soft-locks the game, usually. You can move backwards towards monster encounters in order to get closer to them before the battle properly begins. In one case I'm aware of, this can allow you to skip a battle! Sleep is funny stuff -- When an enemy is asleep, any physical attack, even from a lowly Sling and bullet at range, will hit 100% of the time and will always set HP to zero. It also stops action, but alas, you still have to wait for the enemy to decide on doing nothing for a second. Nice thing about Sleep is that it also strikes an area, targeting 2 to 8 HD worth, and most kobolds act as 0 HD for some reason. Study up on this GameFAQs topic and ask yourself what 200 Strength can do. This would be a very good time to figure out the Attacks of Opportunity mechanic and have the whole group of enemies just systematically walk to their deaths against your Wizard with pointy dagger. You might want Combat Reflexes, to have more than one attack, and enough Dexterity to get the necessary number of attacks. Strength has an obvious use: Do more damage! Dexterity supports Combat Reflexes by allowing more Attacks of Opportunity. Also affects initiative, which can help with manipulation of some form. Constitution actively wants your TAS to fail. Wisdom is useful for Cleric spells -- Which you're not rightly going to care about. Intelligence gives you an extra shot of Fireball between camps. Knucklebones has 18 here, and it can't be glitch-boosted anyway. Charisma turns your lone Cleric into a walking aura of pure destruction versus any undead. Might be necessary to glitch-boost to chew through the larger hordes. Floor 1: At your first branch, take the northern route. The game secretly changes the maze slightly when you open one of these two doors, and the northern one looks much more forgiving than the eastern/southern one. Also, there's a "debug chamber" that I've never figured out how to enter, and it probably has funny teleporters to everywhere. Floor 2: Of the three Gold Keys, the pit puzzle has two ways: either take the hidden stairs down, Turn Undead stuff away, then climb a pit to bypass the puzzle proper, or fight the large kobold group who are immune to Turn Undead then go to the puzzle. The teleporter maze can be "solved" really fast without encounters. I can't think of any other surprises. Floor 3: Albrik is here. Thankfully, you can access the Magical Cape before fighting him, and this, along with Lv3 spellcasters, means you can glitch-boost four of your stats to the skies. I don't know if you still need a +1 weapon with 200 Strength to grind Albrik to dust with, but his little army won't last anyway. Floor 4: Take the southern ladder to this floor. The only way to properly reach floor 5 is this way anyway -- The pits in the northern half of this floor leads to an area in floor 5 that's blocked off by a teleporter you can't sneak by. Floor 5: There's two ways to navigate your way to floor 6, and it is possible to take the "wrong" way to floor 6 by skill-opening a rather tough door, but I think the "proper" way in the northeast section is still faster. Floor 6: Akordia is here, and he probably has more EXP over your Cleric, and it might be a good idea to get a Lv7 Cleric for Xanathar's undead bodyguards. Someone will have to work out the numbers to see if replacing a cleric is worth it, though. In any case, glitch-boosted Charisma might be necessary to defeat Albrik 2's massive army in a single Turn Undead, then a lovely whack from Knucklebone backed by 200 Strength should do the trick. Floor 7: Mmm... There are a few hidden passages. Whichever path minimizes encounters would be ideal. The hounds are fire-immune, so Lv5 Wizard can't roast them in a flash. I believe the doors you need to get through can be skill-opened, which is handy for avoiding more encounters. Floor 8: Most of the cells can be skill-opened. Go directly to the one with the required key and use that to open the one cell you can't open. It looks like a pretty fast floor. Floor 9: Ghaunadan are mean. Nothing tricky about the teleporter maze I can think of, other than the fact you'll probably crash into every encounter on the way. The last piece of the teleporter maze, which is the last set that leads to floor 10, can probably be skipped due to skills. Floor 10: Once again, I can't think of anything too tricky. Rather than finish the teleporter maze, just take the stairs to here and skill-open any doors in the way. To get past the Death Tyrants, back up one step toward them rather than facing them. For style points, Xanathar can be manipulated to start battle with too many hit points, and die to a single 1d4+1 Magic Missile damage, in case the 200 Strength stab isn't normally enough. The two Death Tyrants can be hit by Turn Undead from a Lv7 Cleric. I've studied this version almost to pieces by now. I might need more time to figure out what other nuggets of information I've got.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I did believe having a script conveniently decode the RNG in shops for you would go a long way into speeding up your search. Good to see confirmation that this belief proved true. I may get pretty quiet for a while, as I can't think of any particular help you'd need from lua scripts in battles. And considering I have no real knowledge of good strategies in this game, the only thing I can really offer is cheering for your progress. I will watch for any progress. I expect great things. I have enjoyed seeing your TAS so far.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
That proves there's a lot I haven't figured out about BizHawk's lua in my short time looking through it. And memory domains. Anyway, the main thing is we have made progress. Whether someone would have come by anyway or it was instigated by my mistakes doesn't matter too much. If the script works, great. I want to see things done.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Some results. This should get pretty close to what you need. Unfortunately, I couldn't find an appropriate mirror of gui.opacity, so I changed a fair number of colors around to have the alpha in them. Aside from that, I probably did not get the display neatly aligned, as I wasn't actually running Mario & Luigi while getting the script converted, so I only had 1s and -1s showing instead of larger, more appropriate values. I'm there most of the way, and I'm hoping the script is intact enough that your own changes won't be too difficult to remove any alignment problems. Just in case it is needed, a list of BizHawk functions are here. I have made minimal tweaks to the script itself, editing the stuff that I didn't like seeing, but otherwise left the script mostly intact. When running BizHawk, Tools -> Lua Console, and in the Lua Console window, Script -> Open Script... will let you load the file. If you need to restart it, I've double-clicked the file in the list (now it's off), then double-clicked again (turn it back on), as a method to restart the script. I hope this gives a decent enough start into BizHawk. What I've given isn't perfect, but if you can't make further tweaks yourself, I may need to rethink the sort of help I've given. On a side note, I haven't noticed any functions that let you create your own images from within the script, but apparently there are some that reads up an image file to paint that.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Language: lua

while true do gui.drawBox(0,0,100,100,0xFF000000,0xFF000000) gui.drawText(0,0,1) emu.frameadvance() end
On this laptop, I'm seeing some kinds of colors for what should be a perfectly white 1. May have to do with my font settings, apparently some kind of cleartype. It seems there may be inconsistency of what is displayed between systems. Weird blending of sorts for colors horizontally, but spot on vertically. Likely related to some display settings, but for this sort of application, this loses consistency from system to system. I doubt this image will help debug things, but... (temporary link removed; Served its purpose)
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
... I'll take a look. I'm probably the most qualified to make the conversion. (I hope this isn't my ego speaking) Considering no one else has stepped forward to say something, I'll provide some hope now by making this post, and then results later when I have the time to touch up the script. Depending on how long it takes me to get used to BizHawk, and how compatible the two emulators are, we'll see how soon I get things together.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I finally used my data collection script to... Well, collect data. Here's what I've got: The ratios of map card values have remained fairly constant, whichever battle I picked from the existing TAS. The chance of values have been generally as follows: 0 - 10% :: 1 - _5% :: 2 - _5% :: 3 - 15% :: 4 - 15% 5 - 15% :: 6 - 15% :: 7 - 10% :: 8 - _5% :: 9 - _5% As well, here's some rough approximations for each area and how often I've been picking up each type of card: 1F Traverse Town 17% - _0:Teeming Darkness 17% - _1:Tranquil Darkness 17% - _4:Sleeping Darkness 17% - _6:Feeble Darkness 32% - 14:Meeting Ground 2F ~ 5F _7% _0:Teeming Darkness _7% _1:Tranquil Darkness _7% _4:Sleeping Darkness _7% _5:Moment's Reprieve _7% _6:Feeble Darkness 21% _8:Calm Bounty _7% 10:Moogle Room ??% 11:Sorcerous Waking ??% 12:Martial Waking ??% 13:Alchemic Waking _1% 14:Meeting Ground ??% 16:Strong Initiative ??% 17:Lasting Daze _7% 18:Stagnant Space _1% 19:Premium Room _1% 20:White Room _1% 21:Black Room The five ??% I listed are either roughly 20% or 1%, depending on what you used for the floor. The following gets 20%: Olympus: Martial Waking Wonderland: Strong Initiative Agrabah: Sorcerous Waking Monstro: Alchemic Waking Holloween Town: Lasting Daze Curiously, Lasting Daze was entirely absent in Monstro. Any enforced battles from the story will use the Traverse Town list. The TAS doesn't fight any normal battles on 7F. So, here's what I got on 8F: 12% _2:Guarded Trove 12% _3:Looming Darkness _1% _5:Moment's Reprieve 12% _7:Almighty Darkness 12% _9:False Bounty 12% 10:Moogle Room _1% 11:Sorcerous Waking _1% 12:Martial Waking _1% 13:Alchemic Waking _1% 14:Meeting Ground _1% 16:Strong Initiative _1% 17:Lasting Daze _1% 19:Premium Room 20% 20:White Room _1% 21:Black Room _9% 25:Key to Rewards For a TASer, this is helpful mainly to know what is possible. For RTA, this should give a pretty good idea what to expect. Keep in mind these percents are just estimates. The bot isn't exactly perfect, here.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Hah, my improved data collection script! Now with less running off the screen edge, better identification, and a brand new feature of using the Output Console to dump collected data for copy/paste. As for the card generation algorithm, I'm now finally getting a rough idea of what's going on, although it's all educated guesses. First, if you lack Map Cards, the game will skip generating an enemy card and go straight to producing a zero-value Map Card. Now, if you have any Map Cards, a single 100-sided roll is made to determine whether it should generate an enemy card. If so, make it. If not, start rolling for map cards. If it picks a Map Card ID that it doesn't like, then it will roll dice again until it comes up with an allowed Map Card ID. This "roll until success" method generally skews the chances of other cards showing up, and will also explain why it apparently rolls a random number of times based on my tweaks to the RNG itself. Besides, while running the bot, I've seen streaks of the exact same card showing up repeatedly, where previously I've not been seeing any of that card for many, many hundreds of RNG rolls. If rolls #0 ~ #6 did not generate an allowed card, then the game will ultimately end up picking RNG roll #7 no matter which of #0 ~ #6 you started it at. Which would explain these streaks In any case, if this theory is correct, then there's simply one list that identifies the card, and as you progress in the game, different stuff in that list gets allowed. Aside from skews caused by "roll until success", the relative probabilities of finding this one type of card versus finding this other type should remain roughly equal. So find the floor with the most blue cards and the least of other cards, and you're good! ... These are all guesses, though.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Putting that concept to use. Needs refinement. I select out a moment in the TAS: The battle where it first gets the Red Nocturne. After letting it run for a while, it collected this data:
   0    1    4    6   14  To. Card IDs
-----------------------------
 171  214  193  215  413 1206  0
  41   57   56   65  123  342  1
  80   67   98   78  137  460  2
 254  270  277  312  463 1576  3
 231  236  231  238  372 1308  4
 166  197  191  176  372 1102  5
 276  269  290  251  443 1529  6
 151  168  143  152  309  923  7
  60   40   44   38  108  290  8
 107   87   85  104  187  570  9

1537 1605 1608 1629 2927 9306  Totals

459: 694 - Enemy card

No errors
I stopped it at 10000 trials in that battle. Apparently, there's a 7% chance of an enemy card in Teeming Darkness? I haven't taken too close a look at what Map Card each ID maps to, but I recall ID 13 is a green card, I believe Meeting Ground. I have a start in my search. When I have time, I'll continue this.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Proof of concept script for locating combat objects in memory. Watch the TAS on VBA, and run the script. I also slipped in a piece of code that extracts some other information, but it's commented out. Any text editor should work in modifying the script to remove the comment markers. Of course, it's just a concept. I can now get object data easily. Reading it is another thing entirely, but working out the information contained within shouldn't be too hard, now that I know where precisely to look. They even have internal names conveniently left in for me to read and get some kind of clue what they relate to! In any case, the prize cards actually use different objects entirely between map cards and enemy cards. "PrizeCardInit" is used for map card prizes, and "Heartless card" is used for enemy card prizes. I did spot "PrizeCard" somewhere, but this is linked to from "PrizeCardInit". In any case, it's a mess of pointers in there. But I figured out the crazy system in there, I hope.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Alright, I have been figuring out the data structure of the internals to figure out how to have my bot successfully detect which card shows up. Which was proving difficult, as it uses entirely separate objects for "PrizeCard" (sub-object) and "Heartless card" (main-object). Now that I have the way to detect all combat objects, I should be able to produce a bot that edits the RNG and collect a bunch of data. While the bot may not tell exactly how the game determines the prize, it will know how to identify what it is we're getting and put that information somewhere. By no means is it perfect, but my usual methods of messing with the RNG isn't getting me anywhere, as I don't have any good clues as to which RNG roll out of dozens is being used to determine the card. As a side-effect of all this, I can probably get a script to identify other sorts of objects that the game may be using in combat. I don't know how useful that would be, but I can probably have a realtime script give some information for combat. As for what information I would display... That is another matter entirely.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
I figured out something that made my attempts even rougher: The game rolls the RNG some number of times based on the RNG. I make a save state just moments before dice are rolled to determine the card drop. The only thing that is different when I load state is that I cheat the RNG. My script is saying the RNG advances by varying amounts. 11 dice rolls here, 28 if I cheat the RNG this way, ... So, perhaps the easiest thing I can do is just throw a bot at it and analyze what the game gives in return. At the point where the TAS gets a Red Nocturne card, I tell my script to artificially advance the RNG and tell me what it gets. In rough order of frequency from lowest to highest: 8 & 9, 1 & 2, 4 & 5, 0 & 7, and 3 & 6. There are also five different identifiers I'm getting. I'm not sure if I can work out the data structure to get a better analysis, particularly since I still haven't figured out how to identify an enemy card separate from this. The problem is a lot more complicated than I hoped it would be.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Mostly, the bouncy stuff calls the RNG every so often. I'll have to work out which RNG call is for the card itself, or whether it's because something decided to bounce at an inconvenient time. The end result is that I get annoyed. In any case, the TAS file should give me plenty of battles in various locations to look at.
Editor, Experienced Forum User, Published Author, Skilled player (1173)
Joined: 9/27/2008
Posts: 1085
Ghostwheel wrote:
Really like the new shop script. Unfortunately it's going to be a while before I'll have time to do my own emulator testing and even if so, I don't feel confident in my ability to manipulate the RNG address. If I give you a save file, Fat Rat Knight, can you fill in the rest of the table? If not, I'll just work all this out later.
An endgame file would be lovely. You can also start a movie file anchored to a save state (the "record from now" option) and not do too much with it. The resulting movie file should be able to upload just fine here, if you want to use the TASVideos site to store a file for me. The scripts I have should give enough information relating to what's happening underneath all that randomness, so even if you aren't confident in manipulating the RNG, you should still be perfectly capable of reading the dice being rolled. One thing that might help in reading it is the fact the game isn't "rolling dice" when you're just sitting around in a room without enemies, or in any sort of menu. Still, getting access to endgame stuff myself means I can continue to fill out my tables. I'm pretty sure I know the exact percent chance of the remaining attack and magic cards, assuming I can trust the numbers of that FAQ after I reorder them, yet it's not enough to fill out the tables in my scripts. As for your request to Tounet01, I'll just create a handy blank table to fill out:
            |    Damage Dealt    |  Frames of Delay   |
Attack      |Strike:Thrust:Finish|Strike:Thrust:Finish|
------------+------:------:------+------:------:------+
Kingdom Key |      :      :      |      :      :      |
Three Wishes|      :      :      |      :      :      |
Pumpkinhead |      :      :      |      :      :      |
Wishing Star|      :      :      |      :      :      |
Lady Luck   |      :      :      |      :      :      |
Olympia     |      :      :      |      :      :      |
Fairy Harp  |      :      :      |      :      :      |
Crabclaw    |      :      :      |      :      :      |
Divine Rose |      :      :      |      :      :      |
Oathkeeper  |      :      :      |      :      :      |
Oblivion    |      :      :      |      :      :      |
Might as well add in asking what Berserk and Attack Haste does for you. (EDIT: Ah... I guess you already asked that. The names and effects use different words. Yeesh...) Hmm... As for the probabilities of finding a particular card from a battle, sounds like something I can casually look into in my spare time. I'll just pick some battle in the TAS, make a save state just as the last enemy goes down, and then cheat-edit the RNG values as I please. ... I'm going to hate the bouncing experience pellets.