/* * func2.c Phantasia support routines */ #include "phant.h" void decree(stat) /* king and valar stuff */ reg struct stats *stat; { FILE *fp; short arg; char aline[80], *cp; struct stats sbuf; struct nrgvoid vbuf; double temp1 = 0.0, temp2 = 0.0; int ch; reg int loc = 0; move(3,0); clrtoeol(); if (stat->typ < 20 && !su) /* king */ { addstr("1:Transport 2:Curse 3:Energy Void 4:Bestow 5:Collect Taxes "); ch = rgetch(); move(3,0); clrtoeol(); switch (ch) { case '1': arg = TRANSPORT; cp = "transport"; break; case '2': arg = CURSED; cp = "curse"; break; case '3': addstr("Enter the X Y coordinates of void ? "); getstring(aline,30); sscanf(aline,"%F %F",&temp1,&temp2); vbuf.x = floor(temp1); vbuf.y = floor(temp2); vbuf.active = TRUE; voidupdate(&vbuf,allocvoid()); goto EXIT; case '4': arg = GOLD; addstr("How much gold to bestow ? "); temp1 = inflt(); if (temp1 > stat->gld || temp1 < 0) { mvaddstr(6,0,"You don't have that !\n"); return; } stat->gld -= floor(temp1); cp = "give gold to"; break; case '5': fp = fopen(goldfile,"r"); fread((char *) &temp1,sizeof(double),1,fp); fclose(fp); mvprintw(6,0,"You have collected %.0f in gold.\n",temp1); stat->gld += floor(temp1); fp = fopen(goldfile,"w"); temp1 = 0.0; fwrite((char *) &temp1,sizeof(double),1,fp); fclose(fp); return; default: return; } } else /* council of wise, valar, etc. */ { addstr("1:Heal "); if (stat->pal || su) addstr("2:Seek Grail "); if (stat->typ == 99 || su) addstr("3:Throw Monster 4:Relocate 5:Bless "); if (su) addstr("6:Vaporize "); ch = rgetch(); if (!su && ch > '2' && stat->typ != 99) { illcmd(); return; } switch (ch) { case '1': arg = HEAL; cp = "heal"; break; case '2': if (stat->pal) { fp = fopen(voidfile,"r"); fread((char *) &vbuf,sizeof(vbuf),1,fp); fclose(fp); temp1 = hypot(stat->x - vbuf.x,stat->y - vbuf.y); temp1 = floor(temp1 + roll(-temp1/10.0,temp1/5.0)); mvprintw(6,0,"The palantir says the Grail is about %.0f away.\n",temp1); return; } else { mvaddstr(6,0,"You need a palantir to seek the Grail.\n"); return; } case '3': mvaddstr(3,0,"Which monster [0-99] ? "); temp1 = inflt(); temp1 = max(0,min(99,temp1)); cp = "throw a monster at"; arg = MONSTER; break; case '4': mvaddstr(3,0,"New X Y coordinates ? "); getstring(aline,30); sscanf(aline,"%F %F",&temp1,&temp2); cp = "relocate"; arg = MOVED; break; case '5': arg = BLESS; cp = "bless"; break; case '6': if (su) { cp = "vaporize"; arg = VAPORIZED; break; } default: return; } } mvprintw(3,0,"Who do you want to %s ? ",cp); getstring(aline,21); trunc(aline); if (strcmp(stat->name,aline)) { fp = fopen(peoplefile,"r"); while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) if (strcmp(aline,sbuf.name)) ++loc; else { fclose(fp); if (sbuf.tampered) { mvaddstr(6,0,"That person has something pending already.\n"); return; } else { sbuf.tampered = arg; sbuf.scratch1 = floor(temp1); sbuf.scratch2 = floor(temp2); update(&sbuf,loc); EXIT: mvaddstr(6,0,"It is done.\n"); return; } } fclose(fp); mvaddstr(6,0,"There is no one by that name.\n"); } else mvaddstr(6,0,"You may not do it to yourself!\n"); } void checktampered(stat) /* see if decree'd etc. */ reg struct stats *stat; { struct nrgvoid vbuf; struct stats sbuf; FILE *fp; reg int loc = 0; /* first check for energy voids */ fp = fopen(voidfile,"r"); while (fread((char *) &vbuf,sizeof(vbuf),1,fp)) if (vbuf.active && vbuf.x == stat->x && vbuf.y == stat->y) { fclose(fp); if (loc) { vbuf.active = FALSE; voidupdate(&vbuf,loc); tampered(stat,NRGVOID,&sbuf); } else if (stat->status != CLOAKED) tampered(stat,GRAIL,&sbuf); break; } else ++loc; fclose(fp); /* now check for other things */ statread(&sbuf,fileloc); if (sbuf.tampered) tampered(stat,sbuf.tampered,&sbuf); } void voidupdate(vp,loc) /* update an energy void */ reg struct nrgvoid *vp; reg int loc; { FILE *fp; fp = fopen(voidfile,ACCESS); fseek(fp,(long) loc*sizeof(*vp),0); fwrite((char *) vp,sizeof(*vp),1,fp); fclose(fp); } int allocvoid() /* find a space to put an energy void */ { FILE *fp; reg int loc = 0; struct nrgvoid vbuf; fp = fopen(voidfile,"r"); while (fread((char *) &vbuf,sizeof(vbuf),1,fp)) if (vbuf.active) ++loc; else { fclose(fp); return (loc); } fclose(fp); return (loc); } void statread(stat,loc) /* read a charac. structure */ reg struct stats *stat; reg int loc; { FILE *fp; fp = fopen(peoplefile,"r"); fseek(fp,(long) loc * sizeof(*stat),0); fread((char *) stat,sizeof(*stat),1,fp); fclose(fp); } void tampered(stat,what,bufp) /* decree'd, intervened, etc. */ reg struct stats *stat, *bufp; short what; { struct nrgvoid vbuf; reg int loc; struct stats sbuf; FILE *fp; changed = TRUE; move(6,0); stat->tampered = OFF; switch ((int) what) { case NRGVOID: addstr("You've hit an energy void !\n"); stat->man /= 3; stat->nrg /= 2; stat->gld = floor(stat->gld/1.25) + 0.1; stat->x += 10; break; case TRANSPORT: addstr("The king transported you ! "); if (stat->chm) { addstr("But your charm save you. . .\n"); --stat->chm; } else { stat->x += roll(-50,100) * circ(stat->x,stat->y); stat->y += roll(-50,100) * circ(stat->x,stat->y); addch('\n'); } break; case GOLD: printw("The king has bestowed %.0f gold pieces on you !\n",bufp->scratch1); stat->gld += bufp->scratch1; break; case CURSED: addstr("You've been cursed ! "); if (stat->bls) { addstr("But your blessing saved you. . .\n"); stat->bls = FALSE; } else { addch('\n'); stat->psn += 2; stat->nrg = 10; stat->mxn *= 0.95; stat->status = PLAYING; } break; case VAPORIZED: addstr("Woops! You've been vaporized!\n"); death(stat); break; case MONSTER: addstr("The Valar zapped you with a monster!\n"); paws(7); fight(stat,(int) bufp->scratch1); return; case BLESS: addstr("The Valar has blessed you!\n"); stat->nrg = (stat->mxn *= 1.05) + stat->shd; stat->man += 500; stat->str += 0.5; stat->brn += 0.5; stat->mag += 0.5; stat->psn = min(0.5,stat->psn); break; case MOVED: addstr("You've been relocated. . .\n"); stat->x = bufp->scratch1; stat->y = bufp->scratch2; break; case HEAL: addstr("You've been healed!\n"); stat->psn -= 0.25; stat->nrg = stat->mxn + stat->shd; break; case STOLEN: addstr("You'Ve been bumped off as Valar!\n"); stat->typ = 20 + roll(1,6); break; case GRAIL: addstr("You have found The Holy Grail!!\n"); if (stat->typ < 20) { addstr("However, you are not experienced enough to behold it.\n"); stat->sin *= stat->sin; stat->man += 1000; } else if (stat->typ == 99 || stat->typ == 90) { addstr("You have made it to the position of Valar once already.\n"); addstr("The Grail is of no more use to you now.\n"); } else { addstr("It is now time to see if you are worthy to behold it. . .\n"); refresh(); sleep(4); if (rnd() / 2.0 < stat->sin) { addstr("You blew this one!\n"); stat->str = stat->man = stat->quk = stat->nrg = stat->mxn = stat->x = stat->y = stat->mag = stat->brn = stat->exp =1; stat->lvl = 0; } else { addstr("You made to position of Valar!\n"); stat->typ = 99; fp = fopen(peoplefile,"r"); loc = 0; while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) if (sbuf.typ == 99) { sbuf.tampered = STOLEN; update(&sbuf,loc); break; } else ++loc; fclose(fp); } } vbuf.active = TRUE; vbuf.x = roll(-1e6,2e6); vbuf.y = roll(-1e6,2e6); voidupdate(&vbuf,0); break; } } void adjuststats(stat) /* make sure things are within limits, etc. */ reg struct stats *stat; { long ltemp; reg int temp; stat->x = floor(stat->x); stat->y = floor(stat->y); valhala = (stat->typ == 99); throne = (stat->x == 0.0 && stat->y == 0.0); temp = abs(stat->x)/400; if (temp > 16) temp = 0; if (stat->y == 0.0 && !throne && !valhala && temp == abs(stat->x)/400 && sgn(stat->x) == (int) pow(-1.0, (double) temp)) { if (!wmhl) stat->wormhole = temp; wmhl = TRUE; } else wmhl = FALSE; speed = stat->quk + stat->quks - spdcalc(stat->lvl,stat->gld,stat->gem); strength = stat->str + stat->swd - strcalc(stat->str,stat->psn); time(<emp); stat->age += ltemp - secs; secs = ltemp; stat->quks = min(99,stat->quks); stat->man = min(stat->man,stat->lvl*15 + 5000); stat->chm = min(stat->chm,stat->lvl + 10); stat->typ = (stat->crn && stat->typ < 10) ? -abs(stat->typ) : abs(stat->typ); if (level(stat->exp) > stat->lvl) movelvl(stat); stat->gld = floor(stat->gld) + 0.1; stat->gem = floor(stat->gem) + 0.1; if (stat->rng.type) stat->nrg = stat->mxn + stat->shd; if (stat->rng.type && stat->rng.duration <= 0) /* clean up rings */ switch (stat->rng.type) { case DLBAD: case NAZBAD: stat->rng.type = SPOILED; stat->rng.duration = roll(10,25); break; case NAZREG: stat->rng.type = NONE; break; case SPOILED: death(stat); break; } /* DLREG is ok, so do nothing with it */ stat->nrg += (stat->mxn+stat->shd)/15+stat->lvl/3+2; stat->nrg = min(stat->nrg,stat->mxn + stat->shd); if (stat->age > stat->degen * 2500) { ++stat->degen; if (stat->quk > 23) --stat->quk; stat->str *= 0.97; stat->brn *= 0.95; stat->mag *= 0.97; stat->mxn *= 0.95; if (stat->quks) --stat->quks; stat->swd *= 0.93; stat->shd *= 0.95; } } void checkinterm(stat) /* see if other person on same x,y */ reg struct stats *stat; { FILE *fp; struct stats sbuf; reg int foeloc = 0; users = 0; fp = fopen(peoplefile,"r"); while (fread((char *) &sbuf,sizeof(sbuf),1,fp)) { if (sbuf.status && (sbuf.status != CLOAKED || sbuf.typ != 99)) { ++users; if (stat->x == sbuf.x && stat->y == sbuf.y && foeloc != fileloc && sbuf.typ != 99 && stat->typ !=99 && !stat->wormhole && !sbuf.wormhole) { fclose(fp); interm(stat,foeloc); return; } } ++foeloc; } fclose(fp); } int gch(rngtyp) /* get a character from terminal, but check ring if crazy */ short rngtyp; { refresh(); if (abs(rngtyp) != SPOILED) return (getch()); else { getch(); return (roll(0,5) + '0'); } } int rngcalc(chartyp) /* pick a duration of a ring */ short chartyp; { static int rngtab[] = { 0, 10, 20, 13, 25, 40, 20}; if (chartyp > 10) chartyp -= 10; return (rngtab[chartyp - 1]); } void interm(stat,who) /* interterminal battle routine */ reg struct stats *stat; int who; { #define MAXWAIT 20 #define BLOCK sizeof(struct stats) #define RAN 1 #define STUCK 2 #define BLEWIT 3 #define KILLED 4 #define readfoe() fseek(fin,foeplace,0); \ fread((char *) foe,BLOCK,1,fin) #define updateme() fseek(fout,myplace,0); \ fwrite((char *) stat,BLOCK,1,fout); \ fflush(fout) FILE *fin, *fout; /* pointers for input, output */ double temp, foespeed, oldhits = 0.0, myhits; struct stats sbuf; reg struct stats *foe; reg int loop, lines = 5; int ch; long myplace, foeplace; short oldtags; bool luckout = FALSE; char foename[21]; fghting = TRUE; mvaddstr(4,0,"Preparing for battle!\n"); refresh(); /* set up variables, file, etc. */ myplace = fileloc * BLOCK; foeplace = who * BLOCK; fin = fopen(peoplefile,"r"); setbuf(fin, (char *) NULL); fout = fopen(peoplefile,ACCESS); stat->status = INBATTLE; myhits = stat->nrg; stat->tampered = oldtags = 1; /* this must be non-zero to prevent a king or valar from trashing it */ stat->scratch1 = stat->scratch2 = 0.0; updateme(); foe = &sbuf; readfoe(); foespeed = foe->quk + foe->quks - spdcalc(foe->lvl,foe->gld,foe->gem); if (abs(stat->lvl - foe->lvl) > 20) /* see if greatly mismatched */ { temp = ((double) (stat->lvl - foe->lvl))/((double) max(stat->lvl,foe->lvl)); if (temp > 0.5) /* this one outweighs his/her foe */ foespeed *= 2.0; else if (temp < -0.5) /* foe outweighs this one */ speed *= 2.0; } if (stat->blind) strcpy(foename,"someone"); else strcpy(foename,foe->name); mvprintw(3,0,"You have encountered %s Level: %d\n",foename,foe->lvl); refresh(); /* now wait for foe to respond */ for (loop = 1.5*MAXWAIT; foe->status != INBATTLE && loop; --loop) { readfoe(); sleep(1); } if (foe->status != INBATTLE) { mvprintw(4,0,"%s is not responding.\n",foename); goto LEAVE; } /* otherwise, everything is set to go */ move(4,0); clrtoeol(); /* check to see who goes first */ if (speed > foespeed) goto HITFOE; else if (foespeed > speed) goto WAIT; else if (stat->lvl > foe->lvl) goto HITFOE; else if (foe->lvl > stat->lvl) goto WAIT; else /* no one is faster */ { printw("You can't fight %s yet.",foename); goto LEAVE; } /* routine to hit, etc */ HITFOE: printstats(stat); mvprintw(1,26,"%20.0f",myhits); mvaddstr(4,0,"1:Fight 2:Run Away! 3:Power Blast "); if (luckout) clrtoeol(); else addstr("4:Luckout "); ch = gch(stat->rng.type); move(lines = 5,0); clrtobot(); switch (ch) { default: /* fight */ temp = roll(2,strength); HIT: mvprintw(lines++,0,"You hit %s %.0f times!",foename,temp); stat->sin += 0.5; stat->scratch1 += temp; stat->scratch2 = FALSE; break; case '2': /* run away */ --stat->scratch1; /* this value changes to indicate action */ if (rnd() > 0.25) { mvaddstr(lines++,0,"You got away!"); stat->scratch2 = RAN; goto LEAVE; } mvprintw(lines++,0,"%s is still after you!",foename); stat->scratch2 = STUCK; break; case '3': /* power blast */ temp = min(stat->man,stat->lvl*5); stat->man -= temp; temp = (rnd() + 0.5) * temp * stat->mag * 0.2 + 2; mvprintw(lines++,0,"You blasted %s !",foename); goto HIT; case '4': /* luckout */ if (luckout || rnd() > 0.1) { luckout = TRUE; mvaddstr(lines++,0,"Not this time..."); --stat->scratch1; stat->scratch2 = BLEWIT; } else { mvaddstr(lines++,0,"You just lucked out!"); stat->scratch1 = foe->nrg + 5; } break; } refresh(); stat->scratch1 = floor(stat->scratch1); /* clean up any mess */ if (stat->scratch1 > foe->nrg) stat->scratch2 = KILLED; else if (rnd() * speed < rnd() * foespeed) { /* foe's turn */ ++stat->tampered; updateme(); goto WAIT; } updateme(); if (((int) stat->scratch2) == KILLED) { mvprintw(lines++,0,"You killed %s!",foename); stat->exp += foe->exp; stat->crn += (stat->lvl < 1000) ? foe->crn : 0; stat->amu += foe->amu; stat->chm += foe->chm; stat->gld += foe->gld; stat->gem += foe->gem; stat->swd = max(stat->swd,foe->swd); stat->shd = max(stat->shd,foe->shd); stat->quks = max(stat->quks,foe->quks); sleep(3); /* give other person time to die */ goto LEAVE; } goto HITFOE; /* otherwise, my turn again */ /* routine to wait for foe to do something */ WAIT: printstats(stat); mvprintw(1,26,"%20.0f",myhits); mvaddstr(4,0,"Waiting...\n"); refresh(); for (loop = MAXWAIT; loop; --loop) { readfoe(); if (foe->scratch1 != oldhits) switch ((int) foe->scratch2) { case RAN: mvprintw(lines++,0,"%s ran away!",foename); goto LEAVE; case STUCK: mvprintw(lines++,0,"%s tried to run away.",foename); goto BOT; case BLEWIT: mvprintw(lines++,0,"%s tried to luckout!",foename); goto BOT; default: temp = foe->scratch1 - oldhits; mvprintw(lines++,0,"%s hit you %.0f times!",foename,temp); myhits -= temp; goto BOT; } sleep(1); } /* timeout */ mvaddstr(23,0,"Timeout: waiting for response. Do you want to wait ? "); refresh(); ch = getch(); move(23,0); clrtoeol(); if (toupper(ch) == 'Y') goto WAIT; goto LEAVE; /* routine to decide what happens next */ BOT: refresh(); if (lines > 21) { paws(lines); move(lines = 5,0); clrtobot(); } if (((int) foe->scratch2) == KILLED || myhits < 0.0) { myhits = -2; goto LEAVE; /* main will pick up death */ } oldhits = foe->scratch1; if (foe->tampered != oldtags) { oldtags = foe->tampered; goto HITFOE; } goto WAIT; /* routine to clean up things and leave */ LEAVE: updateme(); fclose(fin); fclose(fout); stat->x += roll(5,-10); stat->y += roll(5,-10); stat->nrg = myhits; stat->tampered = OFF; stat->status = PLAYING; changed = TRUE; paws(lines); move(3,0); clrtobot(); } int interrupt() /* call when break key is hit */ { char line[81]; reg int loop; int x, y, ch; #ifdef USG3 signal(SIGINT,SIG_IGN); #endif #ifdef USG5 signal(SIGINT,SIG_IGN); #endif getyx(stdscr,y,x); for (loop = 79; loop >= 0; --loop) /* snarf line */ { move(4,loop); line[loop] = inch(); } line[80] = '\0'; clrtoeol(); if (fghting) { move(4,0); clrtoeol(); addstr("Quitting now will automatically kill your character. Still want to ? "); ch = rgetch(); if (toupper(ch) == 'Y') longjmp(mainenv,DIE); } else { move(4,0); clrtoeol(); addstr("Do you really want to quit ? "); ch = rgetch(); if (toupper(ch) == 'Y') longjmp(mainenv,QUIT); } mvaddstr(4,0,line); /* return screen to previous state */ move(y,x); refresh(); #ifdef USG3 signal(SIGINT,interrupt); #endif #ifdef USG5 signal(SIGINT,interrupt); #endif } int rgetch() /* refresh, then get a char. */ { refresh(); return (getch()); } void purge() /* remove old players */ { FILE *fin, *fout; struct stats sbuf; reg int loc, today, temp; long ltime; loc = 0; time(<ime); today = localtime(<ime)->tm_yday; fin = fopen(peoplefile,"r"); fout = fopen(peoplefile,ACCESS); while(fread((char *) &sbuf,sizeof(sbuf),1,fin)) { temp = today - sbuf.lastused; if (temp < 0) temp += 365; if (temp > 9) /* ten days old --> delete */ { initchar(&sbuf); strcpy(sbuf.name,""); fseek(fout,(long) loc * sizeof(sbuf),0); fwrite((char *) &sbuf,sizeof(sbuf),1,fout); } ++loc; } fclose(fin); fclose(fout); }