Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
It strikes me you don't have a lot of choice in your route, though.
In the Arcada, you start in logic 2, which calls random() once but doesn't act on it if it's the first time in the room.
West to logic 1, which has no randomness. The scientist is on a timer.
West to logic 4, which calls random() again upon entry. As long as you're on the top floor, you're safe. There's a 21% chance of a patrol appearing on the bottom; it may be fun to manipulate this happening, because many players don't know that this can occur.
West to logic 3. No randomness. Grab keycard, return to 4.
Logic 4 again. Turns out that if you come from the west on the top floor, no encounters can happen.
East to logic 2 again. By the current pathing, a guard appears but you make it to the elevator before he does. This has a 50% chance of happening.
Elevator to logic 5, which also calls random() upon entry. By the current pathing, you have to wait for the guard to leave. He has a 50% chance of showing up, so this could easily be manipulated away. It is notably the first point where randomness matters.
East to logic 6, which has no randomness.
East to logic 7, which again has a 50% chance for the guard to show up. And after that, you're clear.
Now let me check on the spider droid. It strikes me that on Kerona you don't really have a choice of paths either.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Ok, let's see what we can do with that. It is logic 33.
On loading, random() is called twice to set v34 and v35 between 5 and 30.
v34 is the delay until the next rock appears. It decrements, when it gets value 1 a rock is spawned; this calls random() to use v30 as the X coordinate from 80 to 136. Likewise, v35 is the delay until the other rock appears, which calls random() using v32 as the X coordinate between 20 and 70.
When each rock stops moving, the delay v34 or v35 is reset to a value between 3 and 30, governing when the next rock appears.
v42 is damage level. v43 and v44 combined are the distance; the sequence is indeed on a fixed length which cannot be manipulated. After 249 x 3 clock ticks, you arrive at your destination. Everything else is basically visuals (e.g. v46 for the village graphic in the distance).
While the player is not moving sideways, random() is called each tick; there's a one-in-nine chance of something happening with your shadow. This doesn't otherwise affect anything.
Since objects move at a fixed speed too (stored in v56) the main thing you can do here is e.g. manipulate so that no rocks appear in front of you and you can pass the sequence without moving at all. And, of course, the sequence calls random() a lot.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
That's because the seed is in the engine and the variable is in game data. Anyway it should stay intact over the course of your run.
Great!
Is that including the coupon?
Aw crap, seriously? Ok, I should be able to replicate that anyway, let me go check.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Oddly enough, it is not set when the game starts up, but the first time random() is called.
Due to random encounters, this is certainly when you enter the first playable room (logic 2); I haven't checked the title sequence to see if it does anything random.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
So how to approach this?
If you start your emulator and it's set up to directly open this game, then the intial value of random_seed should always be the same. We should double-check this; but it's obvious that if this weren't the case, then the run would desync at the first instance in the game where randomness matters (e.g. the skimmer sequence).
Aside from the slot machine, there's not a lot of places in the game where randomness actually matters to speedrunning. I'm pretty sure that the skimmer sequence is timed, and won't be any faster regardless of where exactly the rocks are. However, the first scene of the game (Arcada) and the last (Deltaur) have random encounters which could be manipulated away. Most importantly, of course, there's the slot machine.
It is important that every call to random() advances the seed by one step. Furthermore, just delaying for a couple frames will not advance the seed. This makes manipulating it much more straightforward. Finally, advancing the seed is hex-friendly; meaning that if you'd get one extra call to random() in the first room, the seed will have been advanced by precisely one step in the last room too. I'm not sure if the rest of the run is hex-friendly though, please confirm?
(this is not entirely true as in some instances a certain random() value may result in more random() calls, but it is usually true).
The easy way to advance the seed, which can be done at any time, is typing N + enter or Y + enter. These are the shortest inputs that give a randomized message (all other one-letter inputs are either not recognized, which give a non-random message, or are ignored). Of course, this does pop up a text box, wasting a couple frames to get rid of it. (edit) importantly, this works WHILE playing the slot machine, meaning that if there's a triple-skull in the seed sequence you can skip it.
Another way is that a number of rooms make a few random() calls when entered. For instance, entering the bar in Ulence Flats calls it twice, and 'entering' the slot machine calls it three more times. During the Arcada or Kerona sequences, you could advance the seed by swapping rooms a few times; I can compile a list if you like.
A third is with saved games. The random seed is explicitly NOT stored in a saved game, so it's possible to go to one place that advances the seed by a lot, then restore to an earlier game and you'll have that game position with the new seed.
Finally, and most importantly, JPC-RR has a parameter "Initial RTC time". Since the random seed is initialized as the amount of milliseconds since midnight, altering this parameter is an easy way to get a different pattern. I believe this is legit by the site rules, but we should probably check that.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
That is correct. v129 is the only one of the four that actually matters, the animation is window dressing. v64 is filled with the result from calling the random() function. v134 is used for an animation delay.
In logic 115, v64 is used for the payout, based on the earlier value of v129, and on v123 which is the amount of buckazoids you bet.
Note that if you win nothing, random() isl called once more to pick a random 'you lose' message in v247.
v26 and v20 determine where the text is displayed (using v246 and v245 as coordinates); this is not relevant to our purpose.
Entering the slot screen calls random() three times, to pick the initial position of the wheels.
Leaving (entering the bar again) calls random() once for the band, and once for the barkeeper's delay.
Playing the slots calls random() only once; turns out the spinning wheels are just for show, the result is picked immediately by generating a random number from 1 to 100 inclusive.
1-2: 000 kills you
4: 222 pays 20x
3,5: 333 pays 10x
6-9: 111 pays 5x
10-16: 11X pays 3x, and calls random(0,3) until it gets a value for X other than 1
17-32: 1XY pays 1x, and calls random(0,3) until it gets a value for X other than 1, then calls it precisely once more for Y
33-100: XYZ pays nothing, and calls random(0,3) until it gets a value for X other than 1, then precisely once more for Y, than calls random(0,3) for Z until is different from X or Y.
It is important to note that randomness does not increment unless the random() function is called, meaning that idling is not going to help you.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Run it from Dosbox.
I'm not surprised. If you have a decent mathematician on your game design team then he'll be implementing one of these.
The starting value is the amount of milliseconds since midnight.
Yes, that is correct. Then it prints either message 79 or message 80, both of which are variants of "I don't understand this input". For our purpose, it only matters that it advances the random seed by one step. In fact, every call to random() regardless of parameters will advance it by one step.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
AGIHACK. And yes, what creaothceann said.
Yes, it's correct for the seed but not for the return value.
I recommend a few lines of C code (or any C-related language, really).
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
I'm fine with using a password for extra courses but not so much with using it to skip to the last course. And, does the extra car you're getting make the game easier or harder to play? If harder, I'm all for it; if this car is simply better than other cars, not so much.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
That is correct.
Note that random(1,100) should equal 4, thefore the agi_rand_seed modulo 100 should equal 3.
Suppose it's 3. Then the next value is ((7C4D * 3) + 1) % 65536 = 29928. The third value is ((7C4D * 29928) + 1) % 65536 = 35273. Then 52598. And so on. (edit) wait no, I forgot about the >> in the return formula. Anyway you get the general idea.
Mathematically speaking, the way these chains are set up makes it impossible for a sequence of (say) 3, 3, 3, 3 to appear ever. A few lines of LUA or Java or whatnot should enable you to find a worthwhile chain.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Well, an AGI decompiler exists. Let's see...
Entering the slot screen calls random() three times, to pick the initial position of the wheels.
Leaving (entering the bar again) calls random() once for the band, and once for the barkeeper's delay.
Playing the slots calls random() only once; turns out the spinning wheels are just for show, the result is picked immediately by generating a random number from 1 to 100 inclusive.
1-2: 000 kills you
4: 222 pays 20x
3,5: 333 pays 10x
6-9: 111 pays 5x
10-16: 11X pays 3x, and calls random(0,3) until it gets a value for X other than 1
17-32: 1XY pays 1x, and calls random(0,3) until it gets a value for X other than 1, then calls it precisely once more for Y
33-100: XYZ pays nothing, and calls random(0,3) until it gets a value for X other than 1, then precisely once more for Y, than calls random(0,3) for Z until is different from X or Y.
It is important to note that randomness does not increment unless the random() function is called, meaning that idling is not going to help you.
Finally, the random function works like this:
int random (int min, int max) {
agi_rand_seed = 0x7C4D * agi_rand_seed + 1;
return ((agi_rand_seed ^ (agi_rand_seed>>8)) % (max - min + 1)) + min;
}
The initial seed is the amount of milliseconds since midnight. That should give you enough for a pattern analysis :)
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
I can't even find this issue on the site you refer to. Do you have a more specific link?
DOSbox emulates Hercules, CGA, EGA, and VGA (of course, these Sierra games don't do anything with VGA yet). I haven't been able to find info for JPC-rr.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
I concur.
I'm wondering though. There are easily dozens of different versions of the AGI interpreter, and there are three versions of Space Quest (1.0x, 1.1a, 2.2) that each use a different one. Does this font issue occur in all AGI version? This should be easy to check.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Great to see this classic game TAS'ed! If you've played the game before, the route and actions all look familiar and (unlike some DOS games) still play out slow enough to see them. So clearly a YES vote.
I'm not entirely happy with the font glitch, but this appears to be only a visual glitch and doesn't impede or alter gameplay in any way. Since in a run like this, the text boxes are closed too quickly to read them anyway, I don't see how this should block publication. Funnily you can still see the typed commands at the bottom.
Oh and yeah, "holy shit" is a cheat code. If you allow that, you might as well press Alt-D on the first screen to teleport to the endgame.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Just because the staff united to make a central definition for one category does not imply that this is required for every category. Some of them may simply be superfluous, or insufficiently distinct from another category.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
The obvious definition is 500 out of 500 points, that's the game's internal score, just like how (e.g.) Metroid games keep their own internal score of up to 100%. This is also the criterion used for RTA; I'm really not seeing any other options here.
To my best knowledge (and this is matched by speedrun.com) it is not actually possible to get more points through multiclassing, because you don't actually get points tasks outside your primary class. However, becoming a paladin (for non-thieves) ups the maximum score to 550 for QFG2 only.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
Oh wow, I've played so much of this game as a child and it's every bit as hard as the name suggests. It's hilarious to see a character that knows exactly where he's going. Definitely a yes vote, and I would also love to see a run of the C64 original.
Experienced Forum User, Published Author, Player
(26)
Joined: 8/29/2011
Posts: 1206
Location: Amsterdam
I found the running and hurdle events highly enjoyable. The other events, not so much. Personally I would prefer seeing the TAS get a world record on each event, instead of the bare minimum for qualifying.
Also I'm not a fan of ending the input one second early if that means the run lasts twenty seconds longer and those twenty seconds are really boring. While this is valid per the rules, I think it would be more entertaining to continue input for another second to complete the last event.