|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T c
Length: 23773 (0x5cdd) Types: TextFile Names: »cvmain.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Crystal/cvmain.c«
/* cvmain.c ************************************************************************/ #define SHORT 50 #include <stdio.h> #include <string.h> #include <fcntl.h> #include "cvobj.h" #include "cvlocs.h" #include "cvocab.h" #include "cvmsg.h" #include "random.h" #include "cvorcs.h" #include "cvmisc.h" #include "cvcode.h" extern char etext; extern char edata; extern char end; extern char _etext; extern char _edata; extern char _end; extern char *rmsg[] ; extern int actspk[] ; extern struct cmsg ctext[] ; extern struct cvocab vtab [] ; extern int maxloc ; extern void exit(); extern void carry(); extern void move(); extern void move2(); extern void destry(); extern void getin(); extern void juggle(); extern void juggl2(); extern void checkobj(); extern void checkloc(); extern void fixrmsg(); extern void motd(); extern void rspeak(); extern void pspeak(); extern void mspeak(); extern void putcode(); extern int yes(); extern struct cvloc *moveme(); int saved = 0; /* this defines the un-initialized state */ char *word1, *word2; char *vword, *oword; struct cvobj *lastobj ; struct cvloc *loc = NULL; struct cvloc *newloc, *oldloc, *knfloc, *oldlc2; int dflag = 0, demo = 0, score = 0, mxscore = 0, limit = 0, /* how long his lamp will last on current power */ setup = 0, /* state of setup */ tally = 0, /* count of treasures yet to see */ tally2 = 0, /* count of treasures you'll never see */ inorth = 0, /* # of times he said NORTH instead of N */ detail = 0, /* # of times we said "not allowed . . */ numdie = 0, /* # of times he died so far */ maxdie = 0, /* # of ways to resurrect him */ holding = 0, /* # objects he's carrying */ dkill = 0, /* # of dwarves killed */ turns = 0, nxtchr = 0, abbnum = 0, /* how often he gets long description */ clock1 = 0, /* time from last treasure to closing */ clock2 = 0, /* time from closing to closed */ /* LOGICALS FOLLOW */ bonus = FALSE, /* gets bonus for correct finish */ closing = FALSE, /* are we closing? */ panic = FALSE, /* has he panicked */ wzdark = FALSE, closed = FALSE, gaveup = FALSE, scoring = FALSE, mltcmd = FALSE, blklin = FALSE, samvrb = FALSE, finish = FALSE, lmwarn = FALSE; \f struct monster orcs[] = { {0}, /* spider */ /* monsters first */ {0}, /* dragon */ {0}, /* king */ {0}, /* djinni */ {0}, /* kobold */ {0}, /* bugbear */ {0}, /* unicorn */ {0}, /* giant orc */ {0}, /* balrog */ {62,1}, /* dwarf in pool hall */ /* dwarves next */ {78,1}, /* dwarf in privy chamber */ {85,1}, /* dwarf at window in secret passage */ {100,1}, /* dwarf in the time maze */ {126,1}, /* dwarf in the harem */ {130,1}, /* dwarf at the shelf */ {87}, /* pirate at where he hides his chest */ /* then these */ {0}, /* *YOU* */ {-1}}; \f void locchg() { if (dodwarf()) die(); } static void dohint(hint) register struct hint *hint; { switch (hint-hints) { case 4: if (O_GATE->prop != 0 || HERE(WALLET)) hint->lc = 0; break; case 5: if (DAM->prop != 0) hint->lc = 0; break; case 6: if (holding <= 1 || loc->atloc.link != NULL || oldlc2->atloc.link != NULL || oldloc->atloc.link != NULL) hint->lc = 0; break; } /* end of switch for special tests */ if (hint->lc == 0) return; hint->lc = 0; if (!yes(hint->quest,0,54)) return; printf("I am prepared to give you a hint, but it will cost you %d \ points.",hint->points); hint->hinted = yes(175,hint->hmsg,54); if (hint->hinted && limit>30) limit += 30*hint->points; return; } void bug(num) int num; { register long a; (void) printf("\nFatal error number %d, see source code for\n\ interpretation.\n",num); a = *((long *) 1); exit(1); } void mkill(monster,object) register struct monster *monster; register struct cvobj *object; { object->prop = 0; move(object,loc); object->conn2.where = FIXED ; monster->dseen = FALSE ; monster->dloc = DEAD ; } void showroom() { putcode(( !(loc->abb++ % abbnum) || (loc->sdesc == NULL)) ? loc->ldesc : loc->sdesc); } void what(word) register int word; { if (word && PCT(60)) {rspeak(60); return;} if (PCT(20)) {rspeak(61); return;} rspeak(13); return; } static void capchk(word) register char *word; { if (!strcmp(word,"indian") || !strcmp(word,"persian") || !strcmp(word,"coke") || !strcmp(word,"kobold") || !strcmp(word,"balrog") || !strcmp(word,"sears") || !strcmp(word,"rick") ) { *word = toupper(*word); } } \f main(argc, argv) int argc; char * argv[]; { { register int r; if (!saved && argc == 2) { cvinit(argc,argv); exit(0); } else if (argc != 1 || saved != 1) { exit(1); } } /********** * do initialization (some of it just in case): * set all objects * nowhere (both ways) * to their initial properties * not linked to any location * set all locations * to get long message next * to have flags = C_FORCED if there's a forced motion ***********/ { register struct cvobj *object; for (object = &(cvobj[1]); object->desc != NULL ; object++ ) { object->conn1.where = object->conn2.where = LOST ; object->prop = object->iprop ; object->conn1.link = object->conn2.link = NULL ; object->conn1.who = object->conn2.who = object ; object->conn1.where = object->conn2.where = LOST ; } lastobj = object - 1 ; } { register struct cvloc *curloc; for (curloc = &cvloc[1]; curloc->travel != NULL; curloc++ ) { register struct cvtrav *curtrv; curloc->abb = 0; curloc->atloc.link = NULL ; curtrv = curloc->travel ; if (curtrv->word == 1) curloc->flags = C_FORCED ; } } /************ * set up the location arrays to that objects are at their indicated * places. We use drop, which puts things on the head of the list, so * we run this backwards. Things with two locations are dropped twice, * and since these are normally best described last, we do them first. ************/ { register struct cvobj *object; #define ILOC(obj) (((obj)->iloc) ? (&(cvloc[(obj)->iloc])) : LOST ) for (object = lastobj; ONUM(object); object--) { if (object->iloc2 > 0 ) { move2(object,&(cvloc[object->iloc2])); move(object, ILOC(object) ); } } for (object = lastobj; ONUM(object); object-- ) { if (object->iloc2 <= 0 ) { move(object, ILOC(object) ); object->conn2.where = object->iloc2 ? FIXED : LOST; } } } /************************************************************************* * clear the hint stuff. loc is how long he's been at a loc with the * cond bit set. hinted is true if the hint has already been given. *************************************************************************/ { register struct hint *hint; for (hint = hints; hint->turns >= 0; ++hint) { hint->lc = 0; hint->hinted = FALSE ; } } /************************************************************************* * initialize the monsters. * they are all known generically as dwarves because they all move like * dwarves, though the adventurer never really knows this. * * dloc is current location * oloc is old location * dseen is a flag. If on, this dwarf has the adventurer in sight and * is in hot pursuit. * dflag indicates the level of activity: * 0 no monster stuff yet (wait until pool hall is reached) * 1 no monsters met yet (thus, no axe) * 2 have axe, but no knives yet. most dwarves moving. * 3 first knives thrown (first set always miss) * 3+ dwarves are mad (and thus more accurate) * some dwarves don't look much like dwarves * 1 is grendl the spider * 2 is the dragon * 3 is the king * 4 is the djinni * 5 is the kobold * 6 is the bugbear * 7 is the unicorn * 8 is the giant orc * 9 is the balrog * 10-15 are just dwarves * 16 is the pirate. * 17 is *you* * no two of the initial locations for 10-16 are adjacent. The others * only start as part of a pre-set encounter. *************************************************************************/ dflag = 0; { register struct monster *cre; for (cre = orcs ; (cre->iloc) != -1; cre++) { cre->dloc = &cvloc[cre->iloc] ; cre->dseen = FALSE ; } } /************************************************************************* * 'tally' keeps track of how many treasures are yet to be found so we * know when to close the cave. 'tally2' keeps track of how many can * never be found because the adventurer klutzed out (e.g. lost the * scroll in the maze). * ***** tally2 is not yet implemented ***** * the objects must be assigned numbers in the following order * treasures * end-game weapons * artifacts in outer cave * other objects *************************************************************************/ tally = tally2 = 0 ; { register struct cvobj *object; for (object = MINTRS ; object != ENDTRS ; ++object ) { object->prop = -1 ; ++tally ; } } BATTER->prop = -1 ; oldlc2 = knfloc = LOST ; inorth = /* # of times he said NORTH instead of N */ detail = /* # of times we said "not allowed . . */ numdie = /* # of times he died so far */ holding = /* # objects he's carrying */ dkill = /* # of dwarves killed */ turns = nxtchr = 0; abbnum = 5 ; /* how often he gets long description */ clock1 = 30 ; /* time from last treasure to closing */ clock2 = 50 ; /* time from closing to closed */ bonus = /* gets bonus for correct finish */ closing = /* are we closing? */ panic = /* has he panicked */ closed = gaveup = scoring = mltcmd = samvrb = finish = lmwarn = FALSE ; { register int i; for (i=0 ; i<=4; ++i) if ( rmsg[2*i+81] != NULL ) maxdie = i+1 ; } saved = saved == 1 ? -1 : 2 ; /************************************************************************* * OK, we're close now. Get a couple more things set. *************************************************************************/ demo = FALSE; /* everyone's a class 1 user here */ motd(FALSE); /* message of the day? */ hints[3].hinted = yes(65,1,0); /* instructions? */ newloc = &(cvloc[1]) ; /* start here */ oldloc = DEAD ; /* make lint happy */ wzdark = FALSE ; setup = 3 ; /* in full swing */ limit = hints[3].hinted ? 1000 : 330 ; juggl2(O_GATE); juggle(BEAR); juggle(HANG); /************************************************************************* * begin the real stuff *************************************************************************/ dodwarf(); while (!finish) /* motion loop */ { register struct cvobj *object; int verb, oldvrb, obj ; blklin = TRUE ; if (loc == DEAD) {die(); continue; } ; if (FORCED(loc)) { showroom(); verb = 1; /* for the benefit of a later switch */ } else { /* motion not forced */ if (DARK) { if (wzdark && PCT(35)) { rspeak(23); oldlc2 = loc; {die(); continue; }; } else rspeak(16); } else { /* not dark: describe objects found here */ register struct conn *curcon, *lastcon; if (DARKRM) pspeak(UNICRN,6); /* that must be the light */ showroom(); if (TOTING(BOAT)) pspeak(BOAT,BOAT->prop); if (TOTING(RUG) && (RUG->prop == 1)) pspeak(RUG,1); curcon = &(loc->atloc); while (curcon->link != NULL) { register struct cvobj *adobj; register int i; lastcon = curcon; curcon = curcon->link ; adobj = curcon->who ; if (curcon->where != loc) bug(32); if (adobj->prop < 0) { adobj->prop = adobj->iprop; if (IFTREAS(adobj)) --tally; if ((tally == tally2) && tally) limit = MIN(limit,35); } i = adobj->prop ; /* handle special cases */ /* tell about the inside of the gate, if the dummy's there */ if ((adobj == O_GATE) && (O_GATE->conn2.where == loc)) i = 1; /* funny way to tell what happened to the container */ if (((adobj == CUP) || (adobj == BOTTLE)) && (adobj->conn2.where == FIXED) && (BEAR->prop == 0) && (HERE(BEAR)) ) i = 13 ; pspeak(adobj,i) ; blklin = FALSE ; /* seeing the poo close up means there are footprints in it */ if (adobj == CRAP) adobj->prop = 1 ; /* remove ranger from gate after the first time he's seen */ if (adobj == RICK) { RICK->prop++ ; destry(RICK); curcon = lastcon; } } /* end showing adobjs */ } /* end describing objects here */ goto okay; /* stuff for when you can't find the indicated object (it may be too dark) */ dark: ; capchk(word1); /* capitalize some proper nouns */ (void) printf("I see no %s here.\n",word1); mltcmd = FALSE ; /* loop here when you say "okay" and such -- less dangerous place than * most, but still must watch the skeleton, the lamp, etc. */ okay: ; blklin = TRUE ; /* if the skeleton's active, it can kill you */ if (SKELTN->prop == 1) { if (PCT(25)) { rspeak(102); oldlc2 = loc ; {die(); continue; }; } rspeak(101); } miss: if (TOTING(MEDAL) && (loc->flags & SECRET)) rspeak(112); if ((loc->flags & RANGER) && (RICK->prop == 0) && (DAM->prop == 0) && (PCT(25) || (loc->atloc.link != NULL)) ) { pspeak(RICK,6); RICK->prop = 3; destry(RICK); loc = &(cvloc[O_GATE->iloc]); break; } /* finds you hanging in there? */ if ((LNUM(loc) == 144) && PCT(25)) { rspeak(217) ; if (PCT(50)) rspeak(218); } /* when we don't understand, we come back here for a relatively safe retry. */ huh: oldvrb = verb ; verb = 0; newobj: obj = 0; object = NULL ; /* if he left off the verb, we let him come back here to say it. */ getvrb: ; /* check if this place is eligible for any hints. If the sucker has been * here long enough, perform the help section. */ { register struct hint *hint; for (hint = hints+4; hint->turns != -1; ++hint) { if (!(hint->hinted)) { if (!(loc->flags & hint->bit)) hint->lc = -1 ; ++(hint->lc); if (hint->lc >= hint->turns) dohint(hint); } } } /* end of hint block */ /* if closing this turn, check for any objects being toted with prop<0. * set the prop to -1-prop. This way objects won't be described until * they've been picked up and put down separate from their respective * piles. Don't let any of this happen unless well into the cave. */ if (closed) { register struct cvobj *adobj; for (adobj=cvobj;adobj->desc != NULL; ++adobj) if (TOTING(adobj) && (adobj->prop < 0)) adobj->prop = -adobj->prop - 1; } wzdark = DARK ; if ((knfloc != LOST) & (knfloc != loc)) knfloc = FIXED; /* get input */ getin() ; /* set word1, word2 */ if (!(turns++) && !strcmp("magic",word1) && !strcmp("mode",word2) ) { maint(argv[0]); } /* demo games are ended by the wizard */ if (demo && (turns >= SHORT)) { mspeak(1); {finish = TRUE; continue; }; } if (samvrb) verb = oldvrb ; if ((verb == SAY) && (word2 != NULL)) verb = 0 ; if (verb == SAY) goto process ; /* detect closing, closed, etc */ if ((LNUM(loc) >= 31) && !tally && !(--clock1)) { register struct monster *cre; DOOR->prop = 0; if (O_GATE->prop != 2) O_GATE->prop = 3; for (cre = orcs; cre->iloc != -1; ++cre) { cre->dloc = DEAD ; cre->dseen = FALSE ; } if (BEAR->prop) destry(BEAR); if (CHAIN->prop == 2) CHAIN->prop = 1; AXE->prop = 0 ; AXE->conn2.where = DEAD; rspeak(129); clock1 = -1; closing = TRUE ; } if (clock1 < 0 && !(--clock2)) { register struct cvobj *curobj; loc = oldloc = newloc = OFFICE ; /* Put him there "naked" except for compass */ for (curobj=cvobj; curobj->desc != NULL; ++curobj) { if (TOTING(curobj) && curobj != COMPASS) destry(curobj); } move(AXE,REPOS); rspeak(132); closed = TRUE; {locchg(); continue; }; } /* one way to get to the end of the game is for the lamp to give out. * When it gets close, we warn him. If the lamp and fresh batteries are * handy, we replace the batteries for him. Otherwise, he may be in * trouble, depending on where he is. */ if ((LAMP->prop == 1) && (--limit <= 30) && HERE(BATTER) && !(BATTER->prop) && HERE(LAMP) ) { rspeak(188); BATTER->prop = 1 ; if (TOTING(BATTER)) move(BATTER,loc) ; limit += 500 ; lmwarn = FALSE ; } /* if lamp runs out */ if (!limit) { limit = -1; LAMP->prop = 0 ; if (HERE(LAMP)) rspeak(184) ; } /* if it's dark and he's outside the cave proper, he just gives up */ if ((limit < 0) && (LNUM(loc) <= 30)) { rspeak(185) ; gaveup = TRUE; {finish = TRUE; continue; } ; } /* give warning about dim lamp */ if ((limit <= 30) && HERE(LAMP) && !lmwarn) { lmwarn = TRUE ; if ((BATTER->prop == 1) || (BATTER->conn1.where == LOST)) rspeak(189); else if (BATTER->prop == 0) rspeak(183); else rspeak(187); } /* now for the real work: we have to figure out what he means by what * he just said. */ for ( ; word1 != NULL; word1=word2, word2=NULL) { register int i; if (!strcmp(word1,"north")) if (++inorth == 10) rspeak(17); i = vocab(word1,-1); if (i == -1) { what(TRUE); /* some form of not understanding */ goto huh; } /* if he says ENTER, he may not really go anywhere because of some special * cases. Going into the water just gets him wet. Going into the boat * is treated as "take boat", so we change his verb. */ if ((i == ENTER) && (word2 != NULL)) { if (!strcmp(word2,"stream") || !strcmp(word2,"water") || !strcmp(word2,"river") ) { if (LIQLOC(loc) == _WATER) rspeak(70); /* wet feet! */ else rspeak(43); /* Where? */ goto okay ; /* maybe this should just be moved */ } else if (!strcmp(word2,"boat")) { obj = _BOAT; object = OBJ(obj) ; i = TAKE; } } switch(i/1000) { /* this is one of the big holes in the parser here. Motion words are * hardly checked for syntax at all. The object is usually not even * looked at, if given. There are just a few special cases, and they * do not go through the normal vocabulary stuff. */ case 0: /* motion word */ if (obj || (verb && (verb != WALK))) {what(FALSE); goto huh; } if ((i == OUT) && (!strcmp(word2,"boat"))) { i = DROP ; } /* deal with word ambiguity here */ if (i == OUT && TOTING(BOAT) && (word2 == NULL || !strcmp(word2,"")) && obj == 0) { i = DROP ; object = OBJ(obj = _BOAT); } verb = i ; /* this sets dispatch switch */ break; /* for objects, we make sure that there are not two objects being named, * and that the object is here. Also, if there's another word, we clear * 'verb' which may have been set by the operation of 'samvrb'. */ case 1: /* object */ oword = word1; if (obj != i) { if (obj || (verb && (word2 != NULL))) { what(FALSE); /* don't understand */ goto huh; } } object = OBJ(obj = i) ; if (word2 != NULL) verb = 0; /* defeat samvrb */ if ((object->conn2.where != loc) && !HERE(object)) /* object maybe not here */ { register int flag; flag = FALSE ; if ((obj == _DWARF) && (dflag > 1)) { register struct monster *cre; for (cre = orcs; cre->iloc >= 0; ++cre) { if (cre->dloc == loc) { flag = TRUE ; break; } } } if (flag || (obj == LIQLOC(loc)) || ((obj == LIQ(BOTTLE)) && HERE(BOTTLE)) || ((obj == LIQ(CUP)) && HERE(CUP) ) || ((object == SPIDER) && (GRENDL->dloc == loc)) || ((object == DRAGON) && (PUFF->dloc == loc)) || ((object == DJINN) && (JEANNIE->dloc == loc)) || ((object == KOBOLD) && (SLASHER->dloc == loc)) || ((object == BALROG) && (BALLY->dloc == loc)) || ((object == SELF) && (ME->dloc == loc)) ) ; /* okay to keep going */ else if ((object == KNIFE) && (knfloc == loc)) { knfloc = LOST; rspeak(116); /* sorry about them knives */ goto okay ; } else if ((object == ROPE) && (HERE(ROPE2))) { object = ROPE2 ; ; /* substitute the "other" rope */ } else if ((object == ROPE) && (HERE(EROPE))) { object = EROPE ; } else if ((object == ROPE) && (HERE(EROPE2))) { object = EROPE2; } else if ( (word2 == NULL) && ((verb == FIND) || (verb == INVENT) || (verb == DESCRB) || (verb == TOUCH) ) ) { ; /* allow questions about things not here */ } else { if (!verb && (word2 == NULL)) /* this test is sensitive to verb funnies */ { register int k; if ((k=vocab(word1,3)) > 0) { rspeak(k%1000); /* word has msg num */ goto okay ; } } goto dark; } } /* end of the case the object is not here */ if ((object == TOMB) && (HELM->prop)) object = HELM ; /* actually a synonym */ if (word2 != NULL) break; if (verb) break ; { register int k; if ((k=vocab(word1,3)) >0) { rspeak(k%1000); /* word has msg num in it */ goto okay; } } capchk(word1); /* capitialize some proper nouns */ (void) printf( "What do you want to do with the %s?",word1); mltcmd = FALSE ; goto getvrb ; case 2: /* action (verb) */ vword = word1; if ((verb == TAKE) && ((i == INVENT) || (i == verb))) { verb = 0; /* destroy old verb */ } if (verb && !obj && (word2 == NULL)) { what(FALSE); /* two verbs */ goto huh; } if (word2 != NULL) {obj = 0 ; object = NULL ; } verb = i; if (word2 != NULL) if (verb == SAY) { obj = 1; goto process; } break; case 3: /* special (just gets message) */ verb = i ; /* this sets dispatch switch */ break; } /* end of word-type switch */ } /* end of word analysis */ } /* end of getting new instructions (motion not forced) */ process: switch (verb/1000) { case 0: /* motion verb */ newloc = moveme(loc,verb) ; locchg(); continue ; case 2: /* true verb */ if (verb == SAY) { if (word2 != NULL) word1 = word2; obj = vocab(word1,-1); /* what would happen? */ if (obj == HOPE || obj == BANIS || obj == MISFO) { verb = obj; obj = 0; object = NULL; } else { printf("Okay, \"%s\".\n",word1); goto okay; } } switch (cvact(verb,obj,object)) { case S_okay: goto okay; case S_miss: goto miss; case S_move: break; case S_obj: goto newobj; case S_what: *vword = toupper(*vword); printf("%s what?\n",vword); mltcmd = FALSE; goto newobj; case S_light: if (!DARK && wzdark) continue; goto okay; case S_show: continue; case S_dark: goto dark; default: bug(40); } locchg(); continue; case 3: /* magic word */ rspeak(verb%1000); goto okay; default: /* how could this be? */ bug(1); } } /* end of motion loop */ getscore(); (void) printf("\nYou scored %d out of a possible %d, using %d turns.\n", score,mxscore,turns); { register struct cmsg *cmsg; for (cmsg = ctext;cmsg->score != -1; ++cmsg) ; for (--cmsg; cmsg - ctext; --cmsg) { if (cmsg->score <= 0) cmsg->score += mxscore ; if (cmsg->score <= score) break; } (void) fputs(cmsg->msg,stdout); if ((cmsg+1)->score == -1) { (void) fputs("To achieve the next higher rating would be a\ neat trick!\n\n Congratulations!\n",stdout); }else{ (void) printf("To achieve the next higher rating, you need %d \ more point%s.\n",(cmsg+1)->score - score, ((cmsg+1)->score - score > 1) ? "s" : ""); } } /* end of figuring the appropriate message */ puts("\nTouch ENTER to continue.\n"); { auto char answer[5]; fgets(answer,4,stdin); } }