/* * Here I will guide all you sinning Oregon Trailblazers, at least a little bit. * Very little as the case seems to be given how much the code changed since I * did this one. Can YOU blame me for not trying to keep this updated? If you * can try looking at prog.c again. * * Please note that the order of events (the q = x(0,23)) might be in a * different order than the prog.c as some were added quite late and I just * pushed them in in prog.c without much thinking (which actually caused some * problems that had to be fixed). In prog.c the event numbers are 0,22 (a bug * in the submitted code was fixed - the switch was x(0,23) but there is no case * 23 there) but here you see it's 0,23 and the order is different. The son * mocking you if you eat his frozen body is not tied to an event in prog.c but * it is here. * * Finally this code is from an earlier version so some of it might be missing, * not just the events, and not just the gotos, but potentially other things * too, possibly bugs that were fixed in prog.c but are not here (and no more * bugs remain in prog.c). But I believe this is more than enough to give you an * idea though if that is the case. If that's not clear... * * WARNING: this code and its comments are not up to date. I wrote 116 before * filtered through the cpp and 134 after the cpp and I didn't wish to * repeatedly revisit this file trying to explain everything. As it is I barely * finished this in time. After publication this was updated with the complete * version as well. */ #include #include #include #include #include /* * this is rand(from, to) and is used strictly to save bytes. This comes * before the variables to shut up some compilers warning about 'shadowing * variables', despite the fact that would be rather on theme of this program. */ long x(long y, long z){ return (rand()%((z)-(y)+1))+(y); } unsigned m,D,Q,v,l,Y,f,X,z,B,i,h, /* * notice the spelling out of 'rude' and (with the type 'long' and below it * ends up spelling out rude long OREGON TRAIL. This is all true and in some * senses of the word rude the real thing was too, although I did try and keep * it as classy as possible with the parody of 'A Pact With the Devil' (with * sometimes dark and biting irony and mostly full of jokes). */ r,u,d,e; long /* * Yes it's perfectly legal to have the same variable more than once as long * as it's the same type. This was useful to spell out OREGON TRAIL. * * The o array, which spells out OREGON used to be TRAIL but to save bytes for * something else I undid this. It looks cleaner now anyway. * * Also notice that the prog.c does not make use of the variable 'I' for * bullets. Instead it just manipulates E in a different way. That was added * with under two weeks left in the contest to yet again shave off more bytes to * get even more gotos in. Yes I am seriously disturbed not only in that I can * figure this out but more importantly that I even considered it. Yes this also * means that the 'j'' macro is not there either. I don't believe this * enhancement is in the alt code either but maybe it is. */ O,R,E,G,O,N, T,R,A,I,L, *o[]={ &O,&R,&E,&G,&O,&N,&I} ,a,t[7],q,M, b=666,c,W; /* * y is the data file buffer, K is the data FILE *, J is * the length read (which we don't actually care about the J as long as * getdelim() does not return < 0). */ char *y; FILE *K; size_t J; /* * saves bytes - every time bullets are used we have to update how much was * spent on them in case one goes to the fort. */ #define j E=I/5; /* * Death macro. This is not the same as the winning death macro, however, * although one always 'goes to hell' - and as you'll see there is an obscene * amount of gotos in this file - just like the original BASIC version. I am not * sure if I can explain it all because it's that twisted. */ #define w(i) { V(i); V(4); goto hell; } /* * Z determines where in the single char * that holds the (currently) 172 NUL * terminated char * strings. These strings are always of the same size but they * can have any value as long as it retains its value when XORed with 127. * * Oh actually the first string is NOT NUL terminated. This is because it's not * needed; it's not part of the game but only a padding and part of * misdirection. * * This also saves bytes. */ long Z(long x){ return x *1663; } /* * this scanf macro gets past an annoying issue with scanf() where it does not * consume input on invalid input which will cause the same input to be read * which in this case causes an infinite loop, flooding the screen. Not having * this as a macro has led to other problems btw. */ #define S(x,z) while(scanf(&y[Z(x)],&z)!=1)while(getchar()!='\n'); /* * I am quite proud of the concept here, although it's the encrypted version * (not this submission) that is really quite something (and very thematic). * Anyway here the nice thing is as briefly mentioned above, near 200 char * can * be in a single char *!. As I already explained this in detail * in the remarks.md I refer you to it. */ void V(long x) { printf("%s",&y[Z(x)]); } /* * shoot success function. I is number of bullets, Y is the number of times you * shot (so it gets better as you shoot more though it's still chance). 'a' is * non-zero if you got sick and could afford the doctor (a is if you got * dysentery but can't afford the doctor). 'f' is injured (and can't afford * the doctor). What that means is that if you get injured or sick a second time * if you can't afford the doctor you will be penalised. NO: there is no flag for * injured but saw the doctor; that was a choice I had to make even if in some * cases it might not make sense (keep in mind that depending on the type of * wound it might not affect your ability to hunt or shoot at all but with * dysentery if you are sick you're sick). */ long k(void) { ++Y; return I> 0 ? x(1, 101) + Y> 53 + a ? 9 : 0 + f ? 9 : 0 : 0; } int main(void) { srand(time(0)); /* * the DATA macro allows for portability for systems that do not have emoji * support (like one system of mine - yes even modern systems might not, * console only especially). It could also be used to place the original * strings but that would ruin the theme of parody - but it could work as * long as the order and blocksize is the same (padded with addpadding.c). */ K = fopen(DATA, "r"); /* * getdelim() with EOF is the magic point: it allows for NUL bytes to be in a * single char *. This is how I managed it and with the macro (S) and function * (V) above as well as printf (which I use in a couple places) everything is * set up perfectly to not go beyond the valid contents of the string. Yes the * fact printf and scanf are used does mean that some strings are not encrypted: * those that start with a BEL byte ('\a') or those that start with '%'. */ if (!K || getdelim(&y, &J, EOF, K) < 0) goto hell; /* * yes basically immediately goto hell beings. * * Please don't ask a tortured soul to try and parse all the jumping. There * are 60 gotos in this file (well as part of the code - not the comments * obviously). I will try explaining the code as we get there but not the * gotos themselves. Obviously I'm a tortured soul having done what I have * done and I don't want to torture myself more. */ goto s; /* * this label is devious - a huge chain that goes from the beginning of * main() to the end to the beginning to the ..to the middle (or somewhere * between the two ends). */ aa:goto dd; u: goto M; /* * this is actually part of the 'aa' above */ ee:goto ff; jj:goto kk; /* * this is the purchasing code, either at the fort or original purchasing * (if z != 0 it's at the fort) */ N: for (X = 1; X < 6; ++X) { /* * this funny construct evaluates to X+5. The reason we need + 5 is the * string location in the data file. Remember that V() is based on a * blocksize and the NUL byte (that stops it from going beyond the data * we care about). It so happens that the strings we need are +5 in the * file. That means that instead of printing by byte location we print * by string number. */ x: V(X+--(int) { 6 } ); /* * z == at fort */ if (z) { /* * 3 is %ld */ S(3, t[X]) /* * no negative numbers and no number> 666 (playing into the theme * more) */ if (t[X] < 0 || t[X]> 666) { /* * 14 is the error message with a joke at the end: 'Or 0, if you * trust the Devil'. */ V(14); /* * x shows the prompt again and wants valid input */ goto x; /* * no this is not a mistake although I believe in parts of this * code this is kind of done anyway where two gotos are next to * each other and they actually both jump, due to a label in * between. * * Instead this is a joke: heaven is unobtainable for someone * who 'signed the Devil's book' (we know this because that's * what those in the past have said). But as you'll see later * the heaven label is actually in between a 'while' and the * death macro. The point is you never can 'goto' heaven and you * ALWAYS go to hell (though sometimes implicit goto). */ goto heaven; l:goto C; JJ:goto W; qq:goto rr; } /* * T == how much money you started out with (1666, also thematic) * and L is the temporary value of that so we can verify you don't * overspend at the fort */ L = T; /* * u is a temporary value here: t is the array that corresponds to * o. We have to do it this way as otherwise we'd mess up the original values * (O,R,E,G,O,N). This loop just subtracts the amount spent per item and if it * ever goes below < 0 you overspent. */ for (u = 0; u < 6; ++u) L -= t[u]; if (L < 0) { /* * overspent at fort message */ V(46); /* * we have to clear out the array for them to try again */ memset(&t, 0, sizeof t); goto v; ZZ:goto II; } } /* end fort */ /* initial purchases */ else { /* * not at the fort: original purchase. Again 3 is %ld and o[X] * (yes it's fun it spells out 'ox' with an upper case X as one of * the things you can buy are oxen. Anyway X (see above) just is the * index into the array so we can verify values (and set them of * course). */ S(3, *(o[X])) if (*o[X] < 0 || *o[X]> 666) { V(14); goto x; } /* * 1666 is the start value of money (well actually 6666 but you have * to read the first string or play to figure out what happens) so * this just checks that you don't overspend. The -0 takes two extra * bytes but it's totally worth it to be thematic. */ T=1666-O-R-E-G-0-N; /* * overspent, start over */ if (T < 0) { /* * right away there is a message that not only questions the * morality (or 'morality') of the PC (player character) but ALSO * the narrator: in ambiguous ways of course. */ V(46); /* * I wanted to do: * * O=R=E=G=O=N=0 * but this is multiple unsequenced modifications which is * undefined behaviour (UB). And although it would be * fitting in theme for the character it is not a good idea * to invoke UB so I did not (and it allowed yet another * goto). */ O=R=E=G=N=0; /* * nasty gotos here */ goto v; c: goto d; oo:goto pp; } } } /* end purchasing code */ /* * z == at fort - simply return to where we started (the prompt or rather * right after it). This was the first goto in the code when I programmed * this and it was very early on. */ if (z) goto A; /* * in this case we have to set I to a value based on E but that's only * done when purchasing. Yes this means that I/E modify each other * depending on where we are in the code */ B: I = E * 5; /* * tell player how much money left after spending */ printf(&y[Z(12)], T); /* * go back to 'fort' choice. * * Yes we get here even though the if (z) above might suggest it * otherwise. I'll explain what that code does when we're there. On the other * hand...there is some code you might want to carefully analyse when we do get * to F:. */ if (z) goto F; /* * bastardised Duff's device */ switch(1) { /* * with a number of twists including a label before the case (you'll see * this again). No this does not mean that when the switch starts we * goto cc first; that only happens when the code does a goto dd;! */ dd:goto cc; I: goto R; default: do { /* * b == hp/stamina, M == mileage. The Oregon Trail was 2170 miles * (the original game had it at 2040 but this is historically * inaccurate). If it goes below 0 you also are done, just like the * original game. */ if (b < 1 || M < 0 || M> 2169) break; /* * Yes I'm probably disturbed. But can you blame me after looking at * the BASIC? Perhaps you would like to 'pray for me'? No. Don't. But * you get the idea. If you don't yet you will! */ goto i; e: goto D; P: for (X = 1; X < 7; ++X) if (*o[X] < 0) * o[X] = 0; /* * print stats: food, ammo, clothing, oxen, supplies, money, * hp/stamina, miles */ printf(&y[Z(11)],R,I,G,O,N,T,b,M); /* * this range might be smaller than the original: not sure if it * is even part of the original. */ if (x(0, 1)) goto Q; /* * it's merely coincidence that the label R is checking if R < * 14. * * Anyway R is food. If < 14 it tells you you better do some * hunting or buy some food soon before you starve. Or don't. * Because let's face it, you'd deserve it. The character in the * game obviously! */ R: if (R < 14) V(37); if (z) { /* * make choices at fort */ /* * do you want to hunt or continue? (2 == %u). * * Somewhere here I noted how F: will goto f; which will set z to 0. So the * question is can this actually be reached? Another question: what is the point * of it? Why ask in one place if you want to hunt or continue and another place * if you want to hunt, stop at the next fort or continue? The latter makes more * sense but in order for this code to be reached we have to invert the logic of * the if above (make it !z). One compiler thinks this is reached but the * question you have to ask yourself is: is it? Or perhaps: can you figure out * how to trigger it? What I am doing is intentional but it's very confusing. */ r: V(43); S(2, r) switch (r) { /* * yes a label before a case again. If memory serves me * right this is the nasty one that is 8 levels of gotos (I * think 8). */ H: goto G; /* * black cat, case 13! */ case 1: goto T; /* hunt */ /* * what, a label between the case statements before a * break that actually does not exist (see below, no * break but two gotos, counting the above goto T!)? Yup. */ i: /* * if oxen < 1 and you haven't seen the message yet (will * reset it if oxen are brought above 0 again), tell the * player that they have run out of oxen and they must * walk the rest of the way (or else they can buy some if * they have any money left). In the original game I * think no oxen == you lose but in reality one might be * able to buy (or in this case - though it's not done I * don't think unfortunately as I only just thought of it * and it's too late now, unless it is done - steal). * Plus the will to survive is something that you might * not really understand (and this is a theme later on) * where you'll (until you lose all hope) do anything * even crawl. */ if (O < 1) { if (!v) V(v=15); O = 0; } else v = 0; goto e; /* * Yes there's a goto after the label before the next case * outside of the if! */ case 2: goto X; nn:goto oo; /* * yes another label. */ F: /* * so here we go to f. What does that do? It sets * z=0; so the question is can the if(z) check that * does S(2,r) (after V(43), label r) can be * reached. At least one compiler got confused by * what does or does not happen, warning about it. * I'll say more there too. */ goto f; a: goto c; default: goto r; O:goto E; } } else { /* outside the fort: do you want to stop at the next fort, hunt * or continue (1, 2, 3) */ y: V(42); /* * 2 == %u and r is an unsigned int */ S(2,r) switch (r) { /* * yup another label inside a switch that's not a case */ M: V(1); /* * t is the array that is used for purchasing but I'm not sure * now how we got here because it's so messed up. The labels are * below us and above us. */ v: memset(&t, 0, sizeof t); goto N; /* * why case 3 first? It's not needed now admittedly but at first * it might have been for a fall through; not sure. It seems * unlikely as I think I always had a goto but I don't know. */ case 3: /* continue */ goto X; case 1: /* go to fort */ z = 1; M -= 45; /* remove 45 miles (yes I think it's a strange system too but one of the few carry-overs) */ /* * L is below us but it just jumps to v which is above * us, kind of like hell and heaven (purportedly) */ goto L; A: /* * Remember the if(z) goto A; ? Well that's after purchasing at * the fort (no rest in the original game, nothing else, just * purchasing). What we're doing here is updating the amount * spent (at the fort we already verified they had enough money * and it's almost the same logic as initial purchases) */ for (X = 1; X < 7; ++X) { /* * o == the array of values spent plus how many bullets (I == how many bullets, * E == how much spent on them; in the prog.c E is both). The t array is how * much spent at the fort on each item which is why we add to the cost spent */ *o[X] += t[X]; /* * T is total money left and X[t] is how much was spent at * the fort */ T -= X[t]; } /* * this will update how many bullets one has. If you go * back to the B label you'll then see how and why we had * two checks of if (z) even with a goto for each. You * can also figure out that the stats are printed prior * to jumping back into the Duff's device (the * bastardised one) loop (game loop). It does (I think) a * goto F; which then does a goto f; */ goto B; case 2: /* hunting */ goto T; default: /* invalid input, try again */ goto y; } } /* * when choosing fort option we goto L; and that does a goto v; * and v is at the top of the function (very early on) */ L: goto v; /* * when l == 1 the character is hunting. */ T: l = 1; /* * require 9 bullets; if < 9 it's a (as often is the case) a * mocking message. */ if (I < 9) V(16); else { /* * otherwise: enough bullets; remember k() is the success of * hunting */ if (k()) { if (x(1,10)> 5) { /* * 52 == best shot in hunting. But it also is a chance * of poisoning by the devil. */ V(52); /* increase food */ R += 23; if (!x(0, 9)) /* * poisoned. But why 17? Because that's the * message number for it. I'll say more when we * get there. You'll notice that other times I * also do something like V(a=...); to save * bytes and to compact code. */ i = 17; } else { /* * 51 is a reference to a scene (episode 2 I think) * of Miracle Workers: The Oregon Trail. You can * read it in strings.loc.txt or play until it * happens. */ V(51); R += 18; } } else /* * mock user for missing a helpless animal standing * still */ V(53); /* * take 9 bullets either way */ I -= 9; /* * j updates E based on I */ j /* * lose 45 miles. Yes that means that if one were low on * food they would have to go quite a distance in order to * get food which means they would have a hard time to get * it which makes the jokes more ironic. */ M -= 45; } /* * no longer hunting */ l = 0; /* * no longer at fort */ f: z = 0; /* * if no food we do something that many people might not want to * think about but the character would have no qualms about it * either way. Assuming of course that they have any oxen left... */ X: if (R < 1) { /* * if 40+ oxen (spent on, not amount) left... */ if (O> 39) { /* * eat an ox and show the message of its ghost. Over time the * ghost of the ox(or in some cases the ghosts of oxen) will * taunt the character as they progress. There are two * different messages though: one vengeful over a petty thing * and one for food. The vengeful one happens as another * event in the alt code though; I put it here too because it * was good enough to have in the main prog.c and I could not * fit it in otherwise. As it is I had to change some code * about to fit it in. */ V(e=x(0,1)?18:19); /* * remove oxen amount */ O -= 40; /* * hold on: no food added? Well one might argue it was all eaten * but check out q. Note it adds 40 but during the feeding stage * of the loop some food will be taken away. Notice too how q * is inside a nested switch's case! */ goto q; o: goto Y; ii:goto l; } /* * starve to death message. Yes I know people don't starve right * away. I also know that if one has not eaten in a certain amount * of time then eating too much right away can kill you. But this * is how it ends up being in the original. Actually in the * original you don't even get the chance to eat an oxen and if you * run out of oxen I think you also die even though that's totally * unrealistic. */ w(24) } else goto K; /* * regular events outside of the mountains */ Y: switch (q = x(0, 23)) { /* * yes more goto labels inside a switch not connected to a * case. * */ s: goto h; case 23: /* * a dark one: if your son gets lost and freezes to death * you have free food. Yeah I know. But it happened (if * not exactly this way) on the trail. The ghost of the * son mocks you at this point. */ if (d) V(39); /* * e == ate an ox, the ghost mocks you */ if (e) V(25); break; case 1: /* * Indians show you where to find...a heart attack * on a plate. Fast food. Something that did not * exist at the time (at least not like this). */ V(95); R += 5; break; S: /* * if you have too much ammo and this event is triggered * you're going to die. Yes the event is at S but we goto S via * goto g; to get to the actual code so that the code for the * event is not at the case itself but where it jumps back to. * The 'g' is past the return 666; of main(). * * Yes an event from a case is not in that case but at a * label inside a switch. This event is a fire but your wagon * train has so much ammo it blows up. */ if (I> 1999) w(27) /* * if there isn't too much ammo just report a fire and * reduce certain things like mileage, supplies and food. */ V(82); M -= 9; N -= 5; R -= 20; /* * okay this is devious. Where is Z? Right after the goto g * (which does goto S;) and the Z is simply 'break' so that it * goes back to the switch only to go to the next part of the * code! */ goto Z; /* * Casper! */ case 18:V(26); break; case 13:V(28); break; /* black cat */ case 2: /* * if O> 0 and no flat oxen yet a flat oxen (like a flat * tyre - a reference to Miracle Workers: The Oregon Trail). * Actually though - it's not quite that. Even if you don't have * any oxen it still shows a message. You have to check it out to * understand why. */ O -= 40; V(71); break; mm:goto nn; case 3: /* * unpotable water == dysentery */ V(a = 76); b -= 70; /* * yes this skips the mountains part. They go straight to the * doctor. There is a thematic joke with it but this means they lose * a turn. They will have to 'continue' on their journey on the next * turn. I think I bring this up a bit more in the remarks.md. */ goto W; case 4: /* * ironic joke with heavy rains */ V(77); /* * lose supplies and miles */ N -= 7; M -= 7; break; case 5: case 10: /* * yes q is one of two values (or at least two, in some cases in * this switch I believe there are other values it can be as well, * including one nested switch setting the value again for more * confusion) and this determines the event */ if (q < 6) { /* * Blackbeard attacks */ V(78); if (k()) { /* * drive off Blackbeard, gain food and supplies */ V(81); R += 9; N += 3; } else { /* * got injured due to lousy shot. * * Lose money and lose all bullets. */ V(f = 79); b -= 80; T /= 3; I = E = 0; } } else { /* * riders ahead - they don't look hostile. Why don't you rob * them blind? */ V(56); if (k()) { /* * a really ironic and somewhat dark joke occurs here */ V(a = 29); /* * gain some money */ T += 70; goto W; cc:goto ee; } else { /* * well it was foolish to try and rob them apparently. 'f' is * injury but we set it to 62 (non-zero) in 'V()' because 62 is * the message to print. */ V(f=62); /* * lose miles and health/stamina */ M -= 50; b -= 35; } } break; case 9:case 19:V(30); break; /* ox just kicked a bucket */ case 20:V(32); break; /* devil in mirror */ case 21: V(31); break; case 6: /* * yes the entire event is at label S which is in another switch (partly for * obscurity and partly as I was running out of places to put them). Then it * jumps back to Z for the break so that the mountains code can happen! That's * assuming you don't have too much ammo of course... If you do the wagon train * blows up from the flames. Otherwise you just lose bullets, food, mileage and * maybe something else (or maybe something else than these entirely - not * sure). */ goto g; Z: break; case 22:V(49); /* Elf event */ /* ox stuck in a hole - thankfully not a donkey! */ case 17: V(72); break; case 7: V(83); /* * lost your way in heavy fog but due to a strange map in the last book you read * you didn't lose much time. */ M -= 10; break; /* * label between cases. It seems that this is a chain of gotos but which one I * do not know. It does seem like it's early in the game loop and resets stats < * 0 back to 0 prior to printing them but how many gotos are involved I do not * know. Anyway it'll go back to P which is at the beginning of * the loop and it'll reset the stats and print them. */ D:goto P; case 8: /* * wagon train gets swamped fording river - but with a reference to a historical * event (72 or so years after this game takes place) as well as a nod to * Jurassic Park(not the only one) */ V(86); /* * food */ R -= 30; /* * clothing */ G -= 20; /* * oxen */ O -= 40; /* * this one is devious: the goto V comes outside and after this switch. I think * it first sets 'q' (the switched value) to another value first. It is then * abused in nested switches. Please do not ask me to parse these. It's a * nightmare and I've had enough of that. I already explained a lot of this in * the remarks.md and I also am disturbed enough to write it; isn't that enough? */ break; V: switch (x(1, 9)) { case 2: if (q> 9) { switch (x(1,2)) { q: R += 40; goto o; case 1: switch (x(2,3)) { case 2: V(a = 54); goto m; b:w(48) case 3: goto J; } case 2: V(5); } goto E; ll:goto mm; J: V(a=54); } goto O; KK:goto JJ; m: goto E; default: if (q> 10) goto E; if (q> 7) { if (N < 5) /* * death due to lack of medical supplies and * Devil on holiday/business in Heaven. */ w(99) /* * mild illness, meds used */ V(13); N -= 5; } break; } /* * mileage lost. Why? I'm afraid I haven't the foggiest clue now except to say * it is supposed to happen. Remember this is (I think) in several nested * switches. */ M -= 17; break; C:goto k; /* * eat! */ K: R -= R> 23 ? 23 : R> 18 ? 18 : R> 13 ? 13 : R; goto Y; /* * Barghest */ case 14: V(74); break; /* * Werewolf scare. */ case 15: V(x(0,1)?69:68); break; /* * no clue where goto d comes from */ d: goto I; case 11: /* * not enough clothing check */ if (G < 25) /* * V is above the nested switches */ goto V; break; kk:goto ll; case 12: /* * hail storm - and another ironic joke */ V(94); /* * lose mileage, hp/stamina, supplies */ M -= 5; b -= 19; N -= 5; break; /* * yes again another label inside a switch that's not a case */ G: goto a; case 0: /* * another joke that is only a message and has no need to check for it * again: this is one of the reasons I made it extended family and wagon * trains, besides historically large groups travelled and in wagon trains */ V(20); } /* end outer switch - well this switch that has the nested switches */ /* * ox looks at you funny. Yes that means both could in theory * happen. Wait. How is it possible the above one could trigger? * Well I leave you to figure that one out! */ if(O>39){ V(e = 19); O -= 40; R+=40; } /* * mountains check. * * BTW: for all I know the distance is wrong; the original game had 2040 miles I * think and that is incorrect: the real trail was a fair bit longer than that. * But I only made the game make you travel further and did not try and make * geography better (or worse) */ if (M < 951) /* * W is medical related things - I mentioned some of this before */ goto W; /* * clothing check in mountains */ if (G < 36) goto b; if (x(0,9)>4) goto n; /* skip rugged mountains */ /* * rugged mountains: an event that at one point happened a lot on my * system due to the old calculation. Now it's much more simplified * but I'm not sure exactly what difference it makes other than it * does give me more bytes which I used for better gameplay. */ V(96); /* lost? */ if (x(0,1)) goto p; /* * lose time asking the Devil for directions to the crossroads; yes a * cultural reference to a famous legend about an amazing guitarist * who supposedly 'went to the crossroads' and sold his soul to the * Devil for musical talent. Robert Johnson of course! But there is * also a historical joke (about the Oregon Trail itself - from a * historian on how you had to be a complete moron to lose your way * on the trail) in this besides the crossroads joke. */ V(97); M -= 60; goto n; p: if (x(0,9) < 5) goto t; /* wagon train damaged - lose time resupplying from the Devil */ V(21); M -= 99; goto n; t: /* * time stops - another reference to the Great Molasses Flood (which * happens when you get stuck fording a river). This event happened 72 years * after this game takes place and also not even close to the Oregon Trail * (far as I know). Apparently this is where the Americanism 'slow as * molasses' comes from, though there were tragic deaths as well. */ V(22); M -= 85; n: if(m) goto z; m = 1; if (x(0, 9) < 5) goto w; /* * made it safely through South Pass - no snow (this was a real place on the * trail) */ V(23); z: if (M < 1951 || W) goto U; /* * cleared Blue Mountains */ W = 1; if (!d && !x(0,9)) { /* * rather ironic joke and the ghost mocks you (and not the only time it might * happen) */ V(75); d = 1; /* * I don't know if I should say this but as it's part of the joke and this type * of thing did happen: yes this is food */ R += 50; } if (!x(0, 4)) /* * yes dragons exist. Oh and the Earth is flat and the Sun is crazy... A * reference to Miracle Workers: Dark Ages (except that the dragons is in * there the devil). Anyway: 84 == dragon eats you, 34 == * runaway bed rhyme death, 33 == Tyrannosaurs attack. Doing it * this way saves bytes - it used to be case 16 in the events but * it was too frequent so I changed it to here - which only * happens if !x(0,7). */ w(x(0,5)?84:x(0,3)?33:34) if (x(0,9) < 5) goto w; U: goto W; w: /* * blizzard in mountain pass - waste time asking Devil for help restocking. * Unfortunately the unfaithful monster only gives you one measly bullet. */ V(35); c = 1; M -= 101; I += 1; j k: /* * miles lost */ M -= 10; goto U; W: if (d && x(0,1)) /* * ghost of frozen son */ V(39); /* * yes this is legal. And 'i' is set to the right value earlier on. Devil * poisoned you. The 'heaven' reference is a joke especially as the only way * you go there (and not really) is when poisoned. The 'goto heaven;' is * never reached. Compilers whine about this because they don't like code * like this. */ while(i)heaven:w(i) /* * B non zero == can't afford doctor. This is so the player is not flooded * with the message. Once is enough * * 'f' is injury; 'a' is illness; 'Q' is treated for illness but you're not * completely better. Arguably this should happen with injuries too but I * decided against it. */ if (!B && (f || a )) { if (d && a) /* * food poisoning, maybe. Well no but it's part of the joke */ V(91); if (T < 666) /* * doctor's bill is 666ドル and you can't afford it. */ V(B=38); else { /* * record whether the person is sick */ Q = a ? 1 : Q; /* * record if injured */ h = f ? 1 : h; /* * injury and illness back to 0 */ f = a = 0; /* * doctor bill is 666ドル */ V(93); T -= 666; } } /* * if injured and no medical care lose 15 hp, else if injured and got * care lose 5, else 0. */ b -= f ? 15 : h ? 5 : 0; /* * if you were sick (and not completely recovered) lose only 5hp; * otherwise if sick 15 and otherwise 0 */ b -= a ? 15 : Q ? 5 : 0; /* * usual mileage gain in the round: way higher than they travelled * in real life but this has to be the case */ M += 170; /* * if oxen> 99 add 30 miles, otherwise subtract 99. Yes this is * arbitrary but it forces one to be careful with what they have * spent on oxen (and whether or not they need to not spend as much * on something else). * * Remember: the original game gives you only 700ドル and you must spend *>= 200 && <= 300 on oxen and you do not get a chance to buy any * more after that; if they die you're out of luck. But in my * parody: you start with 1666ドル after your vague and ambiguous * 'sinful night' and you can buy oxen on the way (more realistic). I * don't have the option to steal oxen from riders because I deem * them as horse riders and the player character is too reckless * anyway, choosing to eat the body rather than a horse. * * This parody as the remarks.md say has 'flat oxen'. Originally * this set them to 0 but this was not good; it slows you down but * you can always get more just as if you lost them all (or ate them * all). * * With these bonuses and penalties it is possible to both win and * lose. I have even on an occasion won with no oxen and that's why I * made this more severe (this way if you don't have> 99 you only * go at the very most 71 per turn, at least as far as the end of the * game loop goes and before other penalties). Whether one can still * win on 0 oxen is beyond me. I subtracted 100 if < 200 but that * seemed really harsh given some of the events that can be * devastating to oxen and other penalties to mileage. */ M += O> 99 ? 30 : -99; /* * lose 10 hp every turn. */ b -= 10; } /* * A == turn. I went beyond the number of weeks than the original. * If I were to do it again I would have actually removed the * message about 5-6 months and let it go longer: but that would * mean another joke could not land and also it's less realistic. * Still could be fun if that joke could be integrated somehow (and * I don't see how it could be due to what the message is). So * perhaps I would not do it again. Still I believe this is one or * two more turns than the original BASIC game - by design. */ while (A++ < 21); } /* * outside the game loop finally */ if (b < 1) { /* * death by dysentery. * * why not die of dysentery if you were treated but still sick? * Well that has to be because of string 45. Another joke. */ if (a) { w(40) XX:goto ZZ; } /* * death of injuries */ if (f) w(41) /* * death from boredom. This is why I did not have the * character die if they had been treated. */ w(45) } /* * yup, always die even at the end. The alt code has a more * ironic twist if you make it the whole way */ w(M>2169?47:36) /* * welcome to your new forever home: hell! */ hell: /* * couldn't do without this, could we? */ return 666; /* * this might seem like dead code but of course it's not. It is an actual * case: the fire in wagon train one. It first does a 'goto g;' and then here * at 'g:' we do 'goto S;' which does the event and then, assuming that the * death doesn't happen, after the fire, it does a goto Z; and Z is right * after the goto g;. In other words the event jumps out of the loop and then * to another unusual place, the event is performed and then it jumps back to * the break! */ g:goto S; h:goto u; /* this one is quite sneaky as it does goto l; but there are other places * that go directly to l! That in turn goes somewhere else which in turn * goes somewhere else - the final destination! */ g:goto S; h:goto u; E:goto aa; Q: goto H; ff:goto ii; pp: goto qq; rr:goto XX; }

AltStyle によって変換されたページ (->オリジナル) /