Post subject: R.C. Pro-Am II
MarbleousDave
He/Him
Player (12)
Joined: 9/12/2009
Posts: 1555
Wonder if someone would do a TAS of R.C. Pro-Am II. There are eight different tracks on three types of landscapes. You control a radio-controlled car by using the B button to accelerate and the D-pad to steer. You can buy upgrades and weapons with the money you get from the races. Use the A button to fire or use a nitro. Nitro's can be found in certain races. Bonus stages happen after races 8, 16, 24, and 30. The first race is free, so you don't have to worry about losing the race. If you play four players, you'll see the continue screen often. Lose the race and you have to use a continue. Run out of continues and it's game over. In a multiplayer game, CPU players take control of players that have run out of continues. In races 25 thru 36, if you lose, you have to retry the race. For the bonus games Tug-O-Truck and Drag Race, alternate presses of the A and B buttons. You get bonus money for getting a certain amount of points (increments of 10 points) A Simple TAS Goal: Aim for Maximum Score (376 pts., win every race)
Joined: 10/3/2005
Posts: 1332
I would love to see even a semi-optimized run if it aimed for the maximum score and bonuses, sacrificing time to collect stuff on the track (and possibly things dropped by enemies, as I seem to recall happening in this game.) Dominating the other racers as hard as possible would probably have broad appeal.
Player (242)
Joined: 8/10/2008
Posts: 113
I've taken an interest in this game lately. Right now I'm focusing on real-time attempts, but I'm not excluding working on a TAS at some point (but I hope no one is holding their breath for it). However, as of right now, some vital information is missing for both. I'm collecting the information I find here: https://kb.speeddemosarchive.com/R.C._Pro-Am_II/Game_Mechanics My main issue is how to approach the RNG. There might be several different RNGs in the works, but the most important one determines the letters, line-up position and traffic light timing. I know 043C is a key in this. When you press start at the shop screen, the value of this address determines all three of these. I'd like to know if the value of this address can be converted into which letters the next race will contain, the line-up order and the traffic light timing. I know it also depends on the initial state, so it's not "only" a case of mapping out the 256 possibilities for each race. It's of course possible to test all 256 possibilities over and over again from different initial states and try to find patterns, but it would in practice be extremely time-consuming. I've made a few attempts to look at the code, but I feel like I lack the necessary background for being able to extract the relevant information in a case like this. If anyone is interested in helping out understanding this aspect of the game mechanics, I've uploaded a movie file that might be useful for testing: http://tasvideos.org/userfiles/info/46245166692451240
Post subject: More info edited in
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
I had worked on this game already for some significant time. Your post convinced me that I really should be writing down what I've got, and I just put it off for way too long. Movie: http://tasvideos.org/userfiles/info/46246125573589327 My lua script is pretty much a glorified RAM Watch at the moment, so unless you want me to share that anyway, I don't see much of a point over just handing over the addresses. Addresses. Multiple addresses on a line indicate values that need two bytes (0-65535) or more (sub units and 0-65535), the first address is always the smallest unit, italics indicate I believe it to be a sub-unit. 0540,0504,050E - X position (player), signed 0545,0518,051D - Y position (player), signed 0592,0596 - Engine rev (base speed) 05B6,05B2 - Speed arrow bonus 0626 - Nitro bonus (did not check for sub-value) 05C2 - I suspect this is just engine noise, rev and arrow affects it, nitro doesn't 059E - Facing (player) 05A6,05A2 - Momentum (player) 0748 - Nitro count As for the speed, it is my experience that the game applies three factors and sums them together. No careful analysis made. * Your base engine rev * Speed arrow * Nitro However you crash or whatever, that only affects your base engine rev. If you crash badly enough, it can also set your speed arrow and nitro values to zero, but otherwise, anything not "major" just affects your rev, and nothing allows that to accelerate faster than a good upgrade. As for turning, I've analyzed the tires to simply affect base rate of how quickly momentum shifts to match your facing: 0.7500 - Standard (0x0C0, 192 per frame) 1.0000 - Skinny's (0x100, 256 per frame) 1.1250 - Nobblies (0x120, 288 per frame) 1.1875 - Dynafit (0x130, 304 per frame) 1.2500 - Scoopers (0x140, 320 per frame) As long as your facing and momentum are different, each frame, the game applies the above values, plus the immediate difference between facing and momentum that frame. For reference, a 90 degree difference is 64 units, so when steering that hard, you can add an extra 0.2500 to your steering rate. This is unlike the first game, and you're encouraged to steer pretty hard in most turns if you need to turn even slightly hard. There is an upper limit to the facing-momentum difference. When you hit that, momentum suddenly speeds up to keep up with further changes to your facing, which is 3.0000 per frame. While on ice, tires have no effect, and they all apply 0.0000 steering (Well, the Skinny's had zero effect). Only your facing-momentum difference will apply. Furthermore, the limit between facing and momentum no longer applies, and trying to steer past a full 180 degrees will cause you to spin out. Steering hard does drop your speed. At least, supposedly. In practice, if you're at maximum speed, apparently you keep your full engine rev? Well, after an upgrade or something. Not analyzed deeply. The side-challenges are button mashers. Try not to go beyond speed 40 in the Tug-o-Truck, I didn't notice the reset to speed 20-ish on my TAS. Black motor looks useful. Silver is a maybe. Gold and Hyper are definitely bad. I have not read most of the notes presented in the SDA link. I just wanted to get my side of things here. You seem to have some numbers for the motors already.
Player (242)
Joined: 8/10/2008
Posts: 113
I'm very glad this game is already in good hands! Thanks also for the information. I didn't know about the parameters governing the tires and I thought until now that 05C2 was the speed (probably not far from correct, except not taking into account the nitros, but your description seems to be the correct one). I'm wondering about your position addresses though. Are you sure about them? I use 0531/052C (x) and 053B/0536 (y) and haven't noticed any flaws with them. I've watched the wip and have a few comments: - I'm certain that the silver motor will pay off, even if it means going into race 3 without a motor upgrade and the risk of delaying mega by one race. - In a TAS, you should aim for getting the 1st car upgrade after race 4. In race 1, you get one letter, in race 2, you get 3 and then finally you get the 3 in race 4. - Unused nitros are converted into $250 at the end of the race. It looked like you hardly got any boost from some of nitros when using them right before the finish line, so it might be better to save them if it helps getting a purchase a race earlier. - When you purchase mega, wait a bit on the menu screen. The menu will after a few frames default to the next motor. So if you have the black motor, the menu will start on silver etc. - This might not be important, but in some races the opponents will miss collecting stuff, so you can grab it during the second lap. E.g. the upper dollar item before the finish line in race 3 is not always collected (very rarely though). If you end up just short of money, this might be good to keep in mind. - I'm guessing that red (1), skinny (2), silver (4) will be close to skinny (1), silver (3) and should therefore be tested. I didn't see anything about the RNG in your post, so I'm guessing you haven't looked too much into it. However, it's absolutely indispensable to take into account for the following reasons: 1. Get the letters you want. This will allow you to get the 1st car upgrade after race 4 and the second one after race 7 (should at least in theory be possible). 2. Manipulate the timer for the green light to be as short as possible. 3. Manipulate the car order on the starting line. Much of this will be TAS-only, but there are some patterns that are discernible even during real-time play. I'm hoping that a better understanding can produce some real-time strats as well.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
There appears to be two addresses for the pixel-level precision on both X and Y positions. My script is reading one I basically chose at random. I've been comparing the mirrors and never saw any difference, practical or otherwise. The 256pixel-level and sub-pixel-level addresses appear to be one-of-a-kind. (The fact the "pixels" are diagonal rather than aligned with the screen means calling them pixels is a bit of a misnomer, but for lack of a better word, that's what I chose) I have not studied the RNG. Only that delays affects it in some way, so I generally chose for faster starting lights and, with low priority, an earlier vehicle upgrade. It is almost certainly worth trying to get letters sooner. Mostly I charged forward so we have a view of later tracks, and can potentially work out the cash available for when we get upgrades. We can count how many tracks we're at Standard and Black before getting Mega engine, and how long we're on Standard, Silver, and finally Mega if we take that instead. Based on address 0596, Red is +8, Black is +12, Silver is +14, and Mega is +20. Getting Silver delays us one race in our finances, just as a ballpark measurement. If we could have Black one race earlier, Silver means we're at a "score" of -12. Since Silver is itself +14, each race we have that instead of Black means +2 per race. Each race we'd have Mega instead of Silver if we went Black, this is a deficit of -6. In my WIP, I managed Black ready by race 3, and was short a Mega by $410 by race 15. I also gain more than $4000 in race 15 as well, where if I went Silver, I'd be just $160 short by race 16. Let's assume I could have gotten the $410 difference, perhaps realizing nitros are worth cash like you said. So I'd have Black in races 3 to 14 (12 races), and Silver in races 4 to 15 (12 races). I'd be enjoying an extra +2 speed in 11 races, and suffering -12 and -6 for races 3 and 15, respectively. The total is a rather slim +4. Of course, this is all just a ballpark guess. The actual, exacting frame counts would certainly have some difference, particularly dependent on just how long races 3 and 15 are. Both engine routes are close enough together that it's hard to tell if Black or Silver is better, with a slight encouragement for Silver, at a glance. There's also the "pushy CPU" factor I've crashed into at race 15, which would help a slower engine more than it helps a fast engine, giving Silver an extra push toward making it worth picking as the Black route would have Mega by then. Oh, and it might affect the Scoopers purchase. Well, if the tires affect us meaningfully, anyway. I did have trouble keeping up with some of the curves, so yes, it might mean something. Skinny's is definitely worth taking early. I think I'll start picking apart the routine that determines the letters to deploy on the track. Getting at the actual assembly should catch a lot of the factors involved.
MarbleousDave
He/Him
Player (12)
Joined: 9/12/2009
Posts: 1555
The quickest way to enter your initials is by pressing start and will be displayed as 1UP, 2UP, 3UP, and 4UP depending on what respective controller you're using. I experimented getting the Scoopers before the Mega Motor and I found that way to be the hardest even after spelling out "PRO AM II" twice for the best car. Also, get all the flashing money bags as much as necessary. The solid money bags can only be picked up by certain players. Weapons The buckshot takes away the opponent's money so it will make it harder for him/her to get the upgrades. The missiles are a staple to the franchise. The bombs can now be placed on the ground instead of directly at close range. The oil slick can spin out opponents. The laser can shoot through multiple opponents. The mega pulse can mess up the opponents' movement. Items Ammo gives you more ammunition for the weapon that's currently selected. Nitro give you the opportunities to gain extra speed. You can also find nitro on some tracks. Shields allows you to bump your opponents or stop certain projectiles. Doesn't work on hazards like oil slicks and bombers. Roll cages don't protect you from the latter. Extra Continues can be bought and the price increases every time. They are cheaper with multiple players. There are extra continues on a handful of tracks and can be acquired on Drag Race by going near the maximum speed.
Post subject: Finding RNG calls, yo!
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
FatRatKnight wrote:
I think I'll start picking apart the routine that determines the letters to deploy on the track. Getting at the actual assembly should catch a lot of the factors involved.
Nailed it. By FCEUX's debugger, routine 01:F636 has our RNG function. Delicious. In short, you only have to look at addresses 0756 to 0759 to see if the game wanted an RNG. If they changed, the RNG function was called at least once. Every time it's called, addresses 0756, 0757, 0758, and 0759 are modified. The only entropy introduced to the RNG is the frame timer, 043C. Basically, I just looked for the race 1 letter package. When I got a different package, I looked for numbers that weren't equal. With rather few results (in the race itself, I searched for zero changes), I poked a new value on what I suspected was, indeed, the letter package (01CD). Yes, it was the one. I ran the debugger with a breakpoint looking for when 01CD was written to. Got a hit, judged the surrounding code not the right one I'm looking for, ran the game again and got another hit. That second one looked suspicious. It's part of a routine that iterates over a few different item slots, probably for multiple different letters. I did see a function call to some "random" spot in code. Well, by "random", I mean it's address was rather distant from where the caller is. Following my intuition, 043C was involved, alright. So were a number of other addresses. Okay, so what's the process? What new numbers are put into 0756 and friends? ... I'll let the code tags handle that.
01:F636 - Roll for random number function
    LDA $0757  ;r[1]
    PHA        ;For now, store that in stack
    ASL        ;Left shift; put the upper bit into carry
    LDA $0758  ;r[2]
    ROL $0758  ;r[2] is shifted one bit up; it also has upper bit of r[1]
    ROL $0759  ;r[3] is shifted up as well; it has upper bit of r[2]
    EOR $0759  ;The old r[2] is XOR'd with shifted r[3]
    STA $0757  ;r[1] now holds this XOR calculation
    PLA        ;Fetch the old r[1] intact
    STA $0759  ;r[3] now holds the old r[1]
    EOR $0758  ;This is old r[1] XOR shifted r[2].
    PHA        ;Stash it in stack for now
    LDA $0756  ;r[0]
    STA $0758  ;r[2] now holds old r[0]
    PLA        ;Now that we preserved r[0], fetch from stack
    ADC $043C  ;Add in frame timer; the carry from r[3]'s shift operation is added, too
    ROL        ;Left shift; The carry of the prior addition is placed in low bit
    STA $0756  ;r[0] now holds... a complicated mess I don't want to English.
    RTS
... Okay, so 0756 gets a complicated mix of RNG addresses plus the frame counter. 0758 simply takes whatever is stored in 0756. 0757 is some XOR mix of 0758 and some bits of each of 0758 and 0759. In turn, 0759 takes whatever is stored in 0757. Anyway, this function is only called whenever the game needs an RNG value. It doesn't appear to be frequently called, mostly just race starts. I have enough information off of this function to probably create a good RNG output script. Oh, and those lights you might have looked at in a later race could have been skewed by timing the earlier race's start differently. Well, now that I know of it, maybe I can find out how it's used for letters. Function 00:8BD3 looks rather important for that. It is called six times, even if there aren't six letters on the track. Actually, they cleverly saved a few bytes by simply placing that function straight over the end of the one picking out the item slots to fill, to save on an otherwise unnecessary JSR and RTS. In any case, I see a bunch of ASL and BCS, leading to LDA of some constant (for each of the letters), STA onto the item slot, and RTS to leave the function. As there is nominally a 50% chance that any particular bit is a 1, the BCS should trigger half the time, so each letter after the first has only half the chance. In short, this function call is telling me that P happens 50% of the time, R happens 25%, O happens 12.5%, A at 6.25%, M at 3.125%, and I at 3.125%. There may be other letter generation functions that skew the results differently. Just that this one I'm seeing at race 1 is doing what I'm seeing. EDIT: Alright, I set my script with memory.registerexec on the RNG function. It prints the current frame count so I can at least guess when things happen. 1 RNG call at name entry. 7 RNG calls when track loads. This includes the challenges. 1 RNG call just as the second red light becomes visible. Several RNG calls whenever a car spins out. Several RNG calls during the Tug-o-Truck challenge. I'm not sure what RNG a spin out needs, but it does mean we can manipulate luck by driving into an oily puddle. Not only that, but by varying the frame we enter such a puddle, we can also manipulate luck, due to how the frame counter interacts with the RNG addresses. Okay. The script so far hasn't picked up other RNG sources. I haven't identified the exact purposes to these RNG calls, but knowing what they're used for should help us focus on the right things. Incidentally, looking through the letter generation algorithm, there are seven JSR $F636 (the RNG call) in there. Well, strictly speaking, there's only two, but there are five JSR $8BD3 that immediately lead to a JSR $F636. One of the RNG calls is so the game can figure out which RNG address to use for a letter (specifically, the 6th one), and the seventh call is when the function naturally gets to 8BD3 without a JSR. So I can identify the seven RNG calls each time a track loads, to generate 6 different letters every time. Not sure where the game is determining the starting order, but it's probably not from these RNG addresses.
Post subject: Re: Finding RNG calls, yo!
Player (242)
Joined: 8/10/2008
Posts: 113
Very interesting read. What I've noticed in my real-time attempts is that the earlier letters ('P', 'R' and 'O') are easy to get in the first few races, while 'I' is usually the last one to complete the upgrade. However, once you reach race 9, the roles seem to be inversed. 'I' suddenly becomes extremely common, while 'O' and, especially, 'A' are the most likely to be the ones missing for the second upgrade. It's also noticeable that at least some letter items are skewed towards a specific letter. Especially letter items that tend to an 'I'. What I'm thinking is that maybe each letter item has a certain preferred start letter with the 50% chance. If that happens to be 'I', you could get a probability of 75% (50+25), which sounds reasonably close to what I'm observing. This is just pure speculation from my side, but I'd be very, very interested if your script could confirm this or find whatever else is the correct theory for this behavior.
Oh, and those lights you might have looked at in a later race could have been skewed by timing the earlier race's start differently.
Could you rephrase this or elaborate on what you refer to here?
In my WIP, I managed Black ready by race 3, and was short a Mega by $410 by race 15. I also gain more than $4000 in race 15 as well, where if I went Silver, I'd be just $160 short by race 16. Let's assume I could have gotten the $410 difference, perhaps realizing nitros are worth cash like you said. So I'd have Black in races 3 to 14 (12 races), and Silver in races 4 to 15 (12 races). I'd be enjoying an extra +2 speed in 11 races, and suffering -12 and -6 for races 3 and 15, respectively. The total is a rather slim +4.
According to this calculation, red (after 1), skinny (2), silver (4), mega (16) would be another +4 over skinny (1), silver (3), mega (15). That has to be balanced by not having skinny in race 2 though. From experience, the red motor is a significant improvement over the standard one, so it doesn't surprise me that this combination is a good choice on paper. But there is only one way to find out which combination is in fact the fastest... Luckily, it's only a few races that need to be tested. Edit: skinny (1), black (2), silver (4), mega (16) would be another +4 again. However, it would be balanced by not being able to use the nitros collected in race 3 and 4 and then you'd have to manipulate an additional money item. For example the upper dollar item before the finish line on race 3.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
Well, there is a little extra something the game does with letters. The game takes a look at some player's letters as part of the letter generation. I initially thought it took some "random" byte out of RNG, but for some reason I didn't look too closely at the LDA $07A1,X somehow. Looking at notes on SDA, that's the address involving player letters. So, the game takes the negative of someone's letters (XOR #$FF), ANDs it with an RNG address, then picks out a letter. Nifty. It explains why the I shows up more frequently around the time you start needing it. The game generates six random letters. It will always do so, even if there aren't that many letters on the field. The first four correspond to the four players, the fifth depends on which race you're on (player 1 for race 1, player 2 for race 2, ..., player 1 for race 5, player 2 for race 6, ...), and finally it picks a random player (RNG call) for the sixth letter. Also, computers "cheat" and pick up a letter at the end of a race even if the race had no letters on it. This actually works in our advantage as the generation algorithm is now less likely to pick that letter. In any case, if we can manipulate them picking up letters we won't care about, it means better manipulation for a later track. The race 1 letter depends on player 1 (01CD). Not that it matters -- No one has any letters! The race 2 letters depend on: * Lone straight letter: Random player (01D2) * First of three letters: P2 (01CE) * Upper left of three letters: Race (01D1) (P2) * Lower right of three letters: P3 (01CF) not DF. Crossing that t... The race 4 letters depend on: * Close to zipper letter: Race (01D1) (P4) * Far from zipper letter: P4 (01D0) * Letter past zipper: P1 (01CD) Let's see... PRO AM II... There are eight letters in the first four races and we need to manipulate seven to be what we want. Meep. It might actually help if we play as player 4, the yellow car. If the letters themselves don't pick random addresses, but always sample from what I spotted in my WIP, then we can at least guarantee two letters in race 4 will not be ones we collected in earlier races. ... We'd be hooking up the multitap just to play as one particular player. We may want to manipulate something rare in race 1, as then we'd have a better shot at getting three letters of sorts we can pick up in race 2. The RNG is somewhat stiff, giving 256 possible "worlds" for any given race 1 output we do. And well, one "world" is clearly 255 frames of wait compared to another "world". The oil slick we can find in race 2 gives us more "worlds" to pick from by race 4, though. In other news, I did look at the potential money we'd get if we didn't spend nitros like nuts. Ye, snap! That's not a small amount of money! We're talking Mega by race 11! ... If we somehow get like all the cash from all the races. I did spend a nitro at the very end of race 4, on a straight road just before the finish, and removing that takes 35 frames. If nitros never amount to more than 35 frames with Black motor and default car, 20 nitros is 700 frames or 5000 cash. I suppose asking whether getting Mega one race earlier is worth 700 frames is a fairly good question at this point. Nearly 12 seconds of difference on spamming the nitros on races 5, 8, or 10 looks unlikely to overcome. In any case, I'm wondering how I didn't notice unspent nitros are worth $250. There's actually several of them scattered about I didn't even try to pick up. Mega motor by race 13 (Black motor route) or 14 (Silver motor route) might actually be feasible without hoarding too many important nitros. But we definitely would need to do some amount of hoarding then.
Race WIP / Max   So... What I got in WIP,
R 1: 2950/ 3450  and maximum possible if I got it all.
R 2: 3600/ 3600
R 3: 3500/ 4200
R 4: 3300/ 3750
R 5: 3300/10050  Heavy nitros level
R 6: 2100/ 2100
R 7: 5050/ 5150
R 8: 2000/ 8250  Another heavy nitros level
ToT: 4990/.....
R 9: 4050/ 4650
R10: 3700/ 9300  There's our third nitros level
R11: 3950/ 3950
R12: 3950/ 4400
R13: 4600/ 6250
R14: 4050/ 5250
R15: 4250/ 4800
But first, we have the letter manipulation problem to deal with... What I mean about the lights is that, on your data, you've seen a different distribution of timings in later races. That distribution on your manipulation of race 2 later races was affected by your manipulation on race 1. In TAS conditions, steering bonuses from tires help, but since we have perfect control, the improvements would not come from fewer mistakes. Good tires are probably behind a good motor in importance, so it might even be prudent to go Red (1), Silver (3), Skinny's (4), then Mega from there. EDIT: Let's see... Race 6... Of the six letters, my WIP indicates they source from P1, P2, P3, race (P2), random, and random. Unfortunately, random and random means they actually use the same address, so those two letters must always be identical. Okay, since race 7 has only one letter, these two "random" ones must both be I for any shot at a race 7 vehicle upgrade. The initial group of three letters. Lower-left: P2 - Upper-right: P3 - Upper-left: Race (P2). First letter of straight: P1 Second letter of straight: Random player Zipper "side pit": Random player Race 7's letter uses P4. If we got the other six as yellow car, we have 50% chance of P here. It appears possible that, if we do select the yellow car, we can manipulate R O A M II from race 6. We can't manipulate P, as by then the CPU cars are all magically awarded the letter P and no letter will ask the yellow car for unspent letters, aside from the "random" ones we need on I. It seems possible. There is a small chance it is possible to get our second upgrade by race 7, but if it can be manipulated, then it will happen. I just need to see if there's enough "manipulation space" to make it happen, I suppose. By the way, the game will always allow I as a possible letter. It's why we wouldn't have 100% chance of P.
Player (242)
Joined: 8/10/2008
Posts: 113
So, the game takes the negative of someone's letters (XOR #$FF), ANDs it with an RNG address, then picks out a letter.
* First of three letters: P2 (01CE)
What does this mean? For example, let's say P2 has 'P', 'R' and 'M'. Does that mean 'O' is the most likely, followed by 'A' and 'I'? According to which probabilities? Are 'P', 'R' and 'M' impossible to be generated in this case?
The race 2 letters depend on: * Lone straight letter: Random player (01D2) * First of three letters: P2 (01CE) * Upper left of three letters: Race (01D1) (P2) * Lower right of three letters: P3 (01CF) not DF. Crossing that t... The race 4 letters depend on: * Close to zipper letter: Race (01D1) (P4) * Far from zipper letter: P4 (01D0) * Letter past zipper: P1 (01CD)
The initial group of three letters. Lower-left: P2 - Upper-right: P3 - Upper-left: Race (P2). First letter of straight: P1 Second letter of straight: Random player Zipper "side pit": Random player
I don't see the pattern between the 6 dependence possibilities and how these are attributed to the different letter items here. Is there a way for any given race to make a similar list of how the letters are generated for the individual letter items? (I'm mainly interested in race 9-14)
We may want to manipulate something rare in race 1, as then we'd have a better shot at getting three letters of sorts we can pick up in race 2. The RNG is somewhat stiff, giving 256 possible "worlds" for any given race 1 output we do. And well, one "world" is clearly 255 frames of wait compared to another "world". The oil slick we can find in race 2 gives us more "worlds" to pick from by race 4, though.
Just thinking loudly here, but couldn't you create a minor spin-out in race 1 to change the RNG the way you want it for race 2? If it's done right before the finish line, it can't be very time-consuming. At least surely less time-consuming than waiting at the map screen for an 'I'.
Ye, snap! That's not a small amount of money! We're talking Mega by race 11! ... If we somehow get like all the cash from all the races. I did spend a nitro at the very end of race 4, on a straight road just before the finish, and removing that takes 35 frames. If nitros never amount to more than 35 frames with Black motor and default car, 20 nitros is 700 frames or 5000 cash. I suppose asking whether getting Mega one race earlier is worth 700 frames is a fairly good question at this point. Nearly 12 seconds of difference on spamming the nitros on races 5, 8, or 10 looks unlikely to overcome.
I very much doubt sacrificing "cleanly" used nitros in order to buy Mega earlier will pay off. Unless of course it's really an edge-case, where you just need $250 or $500 more to get the purchase done for a particular race. But the first ones to go would obviously be where you spent a nitro in the wip right before the finish line and so on.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
ktwo wrote:
What does this mean? For example, let's say P2 has 'P', 'R' and 'M'. Does that mean 'O' is the most likely, followed by 'A' and 'I'? According to which probabilities? Are 'P', 'R' and 'M' impossible to be generated in this case?
The most likely letter is always 50% chance. Each step down is half as likely, until you get to I which takes whatever chance is left by then (regardless of whether the player already has two I). Skip letters that are already owned by the player. The "blank" case: P: 1/2 R: 1/4 O; 1/8 A: 1/16 M: 1/32 I: 1/32 If Player 2 has P, R, and M, a letter generated based on player 2 would have... P: No R: No O: 1/2 A: 1/4 M: No I: 1/4
ktwo wrote:
I don't see the pattern between the 6 dependence possibilities and how these are attributed to the different letter items here. Is there a way for any given race to make a similar list of how the letters are generated for the individual letter items? (I'm mainly interested in race 9-14)
It appears entirely dependent on the whims of the designer when they placed the item. I've been manipulating race 2 for a bit (not being successful with my trial-and-error so far), and so far the same dependencies I spotted earlier are what I'm seeing. Anyway, the game generates six random letters. Which of these six each letter package picks is based on that whimsy designer. The results fill six memory addresses: 01CD - Picks whatever player 1 didn't get 01CE - Player 2 01CF - Player 3 01D0 - Player 4 01D1 - Picks a player based on current race 01D2 - Picks a random player As for the value at the address (decimal): 103 - P 104 - R 105 - O 106 - A 107 - M 108 - I Probably the simplest way to check which letter belongs to which slot is to go into a race, and after the starting line is visible, edit addresses 01CD to 01D2 with numbers 103 (0x67) to 108 (0x6C), in order, then note that all the Ps you spot depend on player 1, and so forth. If you still want me to track down races 9 to 14, I'll take some time to look at some point.
ktwo wrote:
Just thinking loudly here, but couldn't you create a minor spin-out in race 1 to change the RNG the way you want it for race 2? If it's done right before the finish line, it can't be very time-consuming. At least surely less time-consuming than waiting at the map screen for an 'I'.
I'm... Interested to know of any method by which one can trigger a spin-out without oil slicks, ice, or roll cages.
ktwo wrote:
I very much doubt sacrificing "cleanly" used nitros in order to buy Mega earlier will pay off. Unless of course it's really an edge-case, where you just need $250 or $500 more to get the purchase done for a particular race. But the first ones to go would obviously be where you spent a nitro in the wip right before the finish line and so on.
Well, a single clean nitro (straight way without steering losses) got 35 frames with default car and Black motor. I spotted another clean nitro in my WIP with Black motor and second car that got only 32 frames. With the possibility of Silver motor in second/third car, we can expect slightly fewer frames saved. The question then becomes how much of a difference is Silver vs. Mega in each of the races where we can possibly get Mega? Almost certainly worth sacrificing two clean nitros. The Mega is worth more than 60 frames for one race, right? ... Well, probably, we need to make measurements at some point. If we TAS out a difference of 420 frames for a race, that tells us that's about 14 nitros of difference. If we TAS out only 200 frames for a race, it's more like 6, maybe 7 nitros. It is a thought I was playing around with. If you can think of things that can make a nitro worth more than 35 frames like in my test with 1st car + Black motor, then that would help to increase the value of using nitros as a speed boost rather than a cash boost.
Player (242)
Joined: 8/10/2008
Posts: 113
Thanks very much for the explanations. It makes perfect sense and fits well with what I've been observing. In real-time attempts, I think it's actually better to leave some of the letters alone and let the cpus collect them to avoid that their missing letters (i.e. 'I') pollute race after race. I'll map out races 9-14 myself, no worries. Well, by "spin out" I thought it was something along the lines of heavy turning and screeching tires. After your post about the RNG-addresses, I noticed that you could get them to change in race 1 by driving round in a circle (at least in some spots). I just tested it again and I couldn't change the RNG other than through very time-consuming maneuvers of heavy steering. In case this was news to you, you might want to check it out, but from what I can tell it's not going to be useful. In my real-time attempts, the mega saves around 2 seconds on race 22. Needless to say, the type of track and number of laps would impact this, but as a ballpark figure I think that's what one can expect. This is also in agreement with the following very rough calculation: 1500*(1-132/138). Even if one lap is a few hundred frames longer or shorter than 1500 frames, it's still very roughly a one second difference. So sacrificing a 30ish frame-saving nitro for only $250 is a poor trade imo. Regarding the nitros, I thought of something that I'm not sure you're aware of. You can go "out-of-bounds" if your speed is so high that the graphics aren't updated fast enough. See for example the following vid: https://www.youtube.com/watch?v=tSriFMRFsUM As far as I can tell, this is a fake oob. I haven't managed to clip into the landscape or something like that. I admit that I haven't studied this in more detail, so I'm not sure if there actually is some kind of shortcut taking place or if it's purely a visual glitch. You can create this effect even in the earlier races with the help of zippers and/or nitros, but the faster you go the more pronounced it becomes. Other than looking into the above, I can't immediately think of any ways to generally make nitros worth more frames. Since the nitro boost isn't impacted by obstacles, you should try to use them where you're anyways forced to lose speed though (driving through obstacles). However, the additional lag created by the nitros might cancel out the time save so it's not always the right place to use them.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
So, there is something RNG related in the track itself, aside from spin-outs. I took some time to look at this. I'm not sure if it's the steering itself that's causing the RNG related stuff. It could just as easily be letting opponents get ahead of you, which means sitting pretty for a few seconds until they convince the RNG to do something. Hard to be certain, and I don't want to investigate that piece of code yet. I have seen the "out of bounds" effect while TASing, particularly during a turbo+nitro+perfect steering moment. Indeed, I even saw random items on the track "swim" toward their normal spots from what looked like off the track. I agree that it's probably just a visual, but a curious visual nonetheless. Working out my RNG prediction script. Apparently, the game actually keeps multiple copies of the RNG function, in different banks, probably because bank switching is too inconvenient for the code at places. I was just looking for one specific copy of this function. Expanding my search for all instances where the memory is written to instead of when a particular function is executed is letting me catch more of those things I've been missing. Yep, there are copies of this RNG function I didn't see before. Copies, alright, everything's the same to the instruction, just in different spots in these different banks. Anyway, once the script is worked out, I should hope I can get a lovely prediction thing going on so I don't have to hunt for decent possibilities. So far, it's saying I should expect around 20 possibilities in race 2 for some given "world" of 256 possible timer values, playing as yellow car who picked up the letter P in race 1. I expect worse, worse stuff if I'm trying to manipulate 6 letters at race 6. Like, zero possibilities until I stumble across a "world" that might have a few. I think I've figured out 05C2 more precisely: It's actually used for the facing-momentum limit. I just noticed facing and momentum will not differ by more than whatever is in 05C2 (or the neighbors at 05C3, 05C4, or 05C5 for other cars). I did some quick calculations based on my WIP, and guessing how many frames would be saved with a better engine. On a few sample races where we could potentially get Mega, I've seen less than 200 frames going from Black to Mega, and that's not accounting for speed arrows and nitros that would reduce this number further. If we're about $1000 away from getting Mega one race earlier, four clean nitros is around 120 frames, and it's hard to even say we'll make up for the 120 frames with an early Mega. Less, clean, sorts of nitros, sure. Random spares I skipped in one race, of course! Clean ones where I make full use of it is a hard trade only worth it if we're close, like you say. Well, 3rd car Black's 130 speed and 3rd car Mega's 138 speed does leave a rather small 6.15% increase of speed. We're planning on Silver's 132, which is even smaller difference between it and Mega. Well. It seems likely hoarding what would be 4 clean nitros is a loss. Obviously, nitros in slow obstacle moments are ideal. They still won't stop the obstacle from reducing the base rev of the car, unless it's part of a jump that lets us clear the obstacle. The nitro bonus itself isn't affected by the obstacle, which means less time we're stuck in there, and thus the sooner we can get back up to speed.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
So, here's a yellow car with PRO AM II collected as race 4 is concluded. You get to see what race 5 looks like with that stuff. Well. I didn't even try to manipulate race 6. I have a lot of letters to manipulate just right, and the "random" two must be I. If it can work out, race 7's letter depends on player 4 anyway, so not much manipulation needed after that mess. It's the mess I'm worried about. I ended race 5 with 4 unspent nitros. I intentionally land in the water to deny the landing bounce. I didn't count frames to see how far ahead of my original WIP I was.
Player (242)
Joined: 8/10/2008
Posts: 113
It looks great! Excellent job so far. The money management seems to work out perfectly for red (1), sliver (3) and skinny (4), which is awesome. I can't say that I have any comments at all at this point. All I can say is good luck with race 6... I've been more focusing on implementing the recent findings into the real-time route. There are some interesting decisions that follow from better understanding the RNG. It's still a probability game, but the odds are slightly improved. After having read through your posts several times and tried to look into the code a bit, I'm however still not sure if I have understood how the RNG-addresses (756-759) end up in the letter addresses (1CD-1D2). Would you mind explaining that again or just quote yourself if there is something I'm overlooking in your previous posts?
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
ktwo wrote:
[...] I'm however still not sure if I have understood how the RNG-addresses (756-759) end up in the letter addresses (1CD-1D2). Would you mind explaining that again or just quote yourself if there is something I'm overlooking in your previous posts?
There is no direct RNG address to item conversion. Because a frame timer is involved, which is incorporated into the RNG, being one frame late on the first RNG call means your second RNG call will be completely different, and even if you got that one a frame early, your third RNG call will not be the same. Realtime manipulation will be essentially impossible. The assembly code I put down is basically the formula used to create a new RNG value. If the game wants a new RNG value, that function is called, then the value stored in 0756 is used for decision making (something I haven't mentioned up until now). There are seven RNG calls made each time the game wants to place items down: 1) One for Player 1 2) One for Player 2 3) One for Player 3 4) One for Player 4 5) One for a player based on current race (race 1 = P1, race 2 = P2, ...) 6) An RNG call to select player 1 to 4, at random 7) One letter for the randomly selected player When it comes time to deciding letters, the game takes an AND of the RNG value (at 0756) and whatever letters the player doesn't have (an inverse of 07A1 to 07A4, depending on player). If we have bit 0x40, generate a P. This only happens if the selected player doesn't have P, and the RNG has that particular bit set, thanks to that AND. If we don't have bit 0x40, check bit 0x20, and if set, generate an R. If not, check 0x10 and generate an O if set. It goes on to check 0x08 (A) and 0x04 (M) before finally giving up and generating an I if everything else turned up zero. Since there's always six addresses, the letter packs just pick from one of the six. In a few races, some letter packs pick the same address, and these ones will always show the same letter as each other on any given generation. Again, because of the interaction with the frame timer, this isn't something a realtime run can reliably manipulate. Ideally, you find out which players the game reads for the later races. After you find out who the letters favor at an important time, intentionally play as that car and you might get luckier.
Player (242)
Joined: 8/10/2008
Posts: 113
Ok, thanks. I think it's clear to me now. The reason I asked was because it didn't feel like I was always getting the expected percentages according to the 2^(-x) probability distribution (and with the rest going into 'I'). It was just based on a feeling though. It could then have been a sign of the RNG generation algorithm being imperfect so the distribution of of 0s and 1s in the "RNG-address" would be tilted one way or the other. But it's probably just me looking at a too small sample. If your number-crunching script notices anything of the sort, I'd be happy to know though. Since some letters will never be collected by the cpus, my current strat is to focus on collecting those, while avoiding some of the ones that are in their path. Even if this gets me slightly more out of the way than taking the shortest path, having the opponents on roughly the same letters as myself gives a better chance of seeing letters I don't have, instead of ending up with the 1x races being filled with 'I', which was often the case before. The room for picking and choosing letters is a bit limited though, so there is only so much that can be done. But I can definitely say that things have improved.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
Been dealing with emotional issues at home, no desire to go into details, but they are resolved now. I haven't been able to really work on this under the stress I was feeling. Took a brief look at the lights RNG. Apparently it's just a straight up 24 + RNG(0 to 63) timer. When the lights do their thing, it checks for specific light states, and when it gets to the second light, it branches to:
JSR $F636 ;RNG call
AND #$3F  ;0 to 63
CLC
ADC $06E2 ;Before the branch, a 24 is stored here
STA $06E2 ;We now have 24 to 87
Granted, observations of the lights may show a bias. If the distribution is perfectly uniform, then we should be seeing 4 possible lights out of 256 timer values where we get the same result. Of note, the RNG function is called seven times (for letters) between the time you finish shopping and the eighth RNG call at the light. Since there isn't really anything you can do to the timer between these eight calls, there's probably some skewing done by these eight calls. I haven't seen a different function call in the first few races. Basically, the lights function looks like it's meant to be unpredictable. Whether patterns develop would be from an artifact of the RNG function. No TASing progress to report.
Player (242)
Joined: 8/10/2008
Posts: 113
Glad to hear that the personal things have improved. Thanks for the info about the lights. I assume you were referring to my graphs in the guide that indicated the possibility of some bias that could possibly be race-dependent. Those graphs were done by me early on, but I don't recall the method. I've been sceptical about these for a while though. As I've gotten more experience from playing the game, it didn't feel like they reflected what I was seeing and I decided to redo them a few days ago. Suddenly the graphs just showed a seemingly random distribution and no bias. I'm pretty sure it was me who used some biased method in the previous set of graphs and that was what created the patterns. I think it's likely that the RNG-function is doing at least close to do what it's supposed to. Even though I guess you can never be really sure until you study it in detail. But imo, that's not worth the effort.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
So, here's the adventures of the yellow car. The second set of letters collected before Race 8. Mega motor paid for before Race 16. Got the Mega with 540 cash to spare. Well, that 40 isn't something we can spare due to not being a multiple of 50 (Tug-o-Truck is the only source of multiples finer than 50). But this suggests I picked up five money bags I didn't need, maybe there's some that are most out of the way I can avoid. I did gloss over the detail of how CPU cars cheat their own letters, but I'll make it a point to mention what I know. After Race 1: Red car (P1) gets P, if it's a CPU car After Race 2: Blue car (P2) gets P, if it's a CPU car After Race 3: Green car (P3) gets P, if CPU After Race 4: Yellow (P4) gets P, if CPU After Race 5: Red gets R After Race 6: Blue gets R ... And so on. A letter is not magically awarded if the target car already has the letter in question or the car is a human player. May as well reveal every potential advantage you can get.
Post subject: Just random mechanics analysis, nothing to see here.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
While browsing through the code, I spotted the routine that initializes car stats at the start of each race (by FCEUX debugger, 0B:DB8F). It includes things like maximum speed, turning rate, and all that stuff. Maximum speed is a table lookup of your current car/engine combo. Despite being a table lookup, there's code to arbitrarily add 32 on top of this, which is already seen in our top speeds. There's more code for each of the three CPU players to give them an arbitrary change in max speed, a table lookup for the three of them for each of the races. Actually three tables, looks like they get to choose between three max speeds mid-race? The penalty is as low as -20 for basically the first race and the bonus is as high as 20 for the end races, and they start getting positive numbers pretty early on. Turning rate is also a table lookup, but with only one dimension, so it's short. Apparently, there were supposed to be more tires, with turning rates 0x0070 to 0x0270, steps of 0x80 in between (0.4375 at first). There was supposed to be a secondary tires stat, in which these tires are better in, that would limit the Facing-Momentum difference, but the stat loaded (to 05C2) is overwritten by some formula with your speed before ever getting used (about 3/4 of base+zipper). Actually, it's hard to tell the intent of what the "extra five tires" were supposed to be, most likely they were scrapped before they finalized the tire numbers, so that would explain why the particularly wide turning rates between tires. It caught my fancy to also look at how the CPU cars shop. Apparently, they have six shopping lists implemented, but only three are ever used. I think? Lists 0, 2, and 3 are assigned to CPU players in order. They follow this list strictly, and only after they get each item in order do they look at the next. List 0: Red, Silver, Skinny's, Gold, Mega List 1: Black, Silver, Gold, Skinny's, Nobblies, Mega (unused) List 2: Skinny's, Silver, Gold, Dynafit, Hyper, Mega List 3: Black, Skinny's, Silver, Mega List 4: Red, Black, Skinny's, Silver, Nobblies, Mega (unused) List 5: Skinny's, Black, Nobblies, Mega, Dynafit (unused) The first available CPU car takes List 0. The second one takes List 2. The third takes List 3. Maybe the unused lists are taken if a player hits a game over? List selections are stored in 071C to 071F. Where they are in the list are stored in 0724 to 0727. By "first available CPU car", I mean the red one if that's not a player. If controller 1 already claimed the red car, then the "first available CPU car" is the blue one. Oh, but if it's a two-player game where both first and second controllers got these two cars, then the "first available CPU car" would be the green one. Predictably, players taking up the first three slots means that yellow car will take List 0. I may as well be thorough while I'm at it. Eh, I'm just analyzing things for the heck of it. CPU cars do make use of the money they get, although they do also get a bonus max speed on top of whatever zany stuff they have. Furthermore, I have observed the rubber band effect where it speeds them up by around +32 just because they're far behind you. For a few races, the blue car maintained a +16 rubber band bonus despite being on my tail, literally pushing me.
Player (242)
Joined: 8/10/2008
Posts: 113
I smiled when you broke the rubber band of the green car in race 6. It looked pretty disoriented when you lapped it. Overall, it looks great again. The manipulation in race 6 is crazy when you know what lies behind it. It's only a pity that you can't collect the lower of the three letters and take the zipper at the same time, but I don't see how that would be possible and it looks like you don't either. I don't have much to say other than what you already know (avoiding some of the money detours since you can buy Mega with less money). However, there are two things I'm wondering about: * How does the lap count work? I did some basic testing to see if I could single out an address or so, but without success. It could be worth quickly playing around with to make sure there is no exploit waiting to be discovered (along the lines of driving back and forth over the goal line instead of driving the intended way around the track). To be clear, I haven't seen any sign of such a thing being possible. * Similar to above, but for the tracks with intersecting paths. Any way to shortcut into the "wrong" path? Again, I have no indication of this being possible, so it's just an idea for the sake of excluding the possibility if you're anyways in "exploration mode". I didn't think of the 1up in race 13 to reduce lag. That will be useful in real-time speedruns as well. Unfortunately, I got a pb not long before I saw your post and I think that will stand for a while. I have to correct you regarding the free cpu letters. The cpu cars always get letters in the corresponding races. The letter they get is the next in order. So a car having P, R and M will get an O, regardless of it's race x, x+4 or x+8. The only exception I've seen is when they upgrade the car. Then they don't get a free letter for the new car.
Editor, Skilled player (1171)
Joined: 9/27/2008
Posts: 1085
00:BA6C -- Cheat letter to CPU player
      LDA $0750   ;Race ID
      AND #$03    ;0 to 3, use as a player select
      TAX
      LDA $0764,X
      BPL $BA9C   ;Escape if positive -- bit 0x80 is clear (a player!)
      LDA $07A1,X ;Letters collected
      CMP #$FD    ;253, special mark for "everything collected, twice"
      BEQ $BA9C   ;Escape if everything was collected, twice
      ASL         ;Shift out $80 -- Collected first set (unchecked)
      ASL         ;Shift out $40 -- P
      BCC $BA94   ;Carry bit states if we had P. If not, award that!
      ASL         ;Shift out $20 -- R
      BCC $BA9D   ;Carry holds if we had R. Again, award if not present.
      ASL         ;Shift out $10 -- O
      BCC $BAA6   ;You know the drill.
      ASL         ;Shift out $08 -- A
      BCC $BAAF
      ASL         ;Shift out $04 -- M
      BCC $BAB8
      ASL         ;Shift out $02 -- The first I
      BCC $BAC1
      JMP $BACA   ;Clearly, we're missing the second I

$BA94 LDA $07A1,X
      ORA #$40    ;Award letter P
      STA $07A1,X ;Make it official in memory now.
$BA9C RTS

;The next pile of lines are for the individual letters

$BACA LDA $07A1,X ;This is the last letter code, by the way
      ORA #$01    ;Award the second I
      STA $07A1,X
      RTS
Dang, you're right. The code itself agrees with you. CPU gets awarded their next missing letter, regardless of what it is. I have a habit of making an assumption and failing to test it. I need to crack that habit. According to this piece of code, though, CPU will still grab their free letters after each race after their first upgrade. Ran a breakpoint for Blue in my latest TAS, and it triggered on the end of Race 13 (or 14, if you count Tug-o-Truck). Incidentally, the code can trigger on the same race the CPU legitimately collects the final letter of the set. In this case, it will just OR in the second letter I, but since that's already set, it hardly matters. It just has a catch for when it's got the final upgrade settled in. Lap counter, oh... There's a segment counter at 0559 to 055C. No clue what would happen if that were cheated to 21 during the crossover in Race 7. The lap counter is over in 055E to 0561. Currently no ideas come to mind. Well, apart from throwing the debugger at it and the trace logger and looking at what the code is looking for when incrementing the lap counter. For the 1up collection to reduce lag, it probably depends on how many CPU are keeping up with you. Even with none, I experienced a few frames of lag. If you're getting a lot more lag, getting it will probably get rid of more lag, probably to help make up for the more chaotic difficulty of controlling your car in realtime. If I hit the zipper, I miss the letter, however close to the edge of the zipper I was. At a glance, it also looks infeasible to get the letter then back onto the zipper. Green's rubber band did break in that same race. Was puttering along at such a slow speed when I was well ahead, fun to see it's possible to get any lapping done at all.
MarbleousDave
He/Him
Player (12)
Joined: 9/12/2009
Posts: 1555
Alternating between A and B in Tug-O-Truck and Drag Race on each frame gives the player the max speed. 1 player it's just one human controlled player. 2 players if one human player falls behind the other, it catches up automatically. 3 players it's the same thing 4 players you'll see the continue screen often.