1375 lines
45 KiB
C
1375 lines
45 KiB
C
/*
|
|
* 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<stdio.h>
|
|
#include<string.h>
|
|
#include<time.h>
|
|
#include<stdlib.h>
|
|
#include<unistd.h>
|
|
/*
|
|
* 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;
|
|
}
|