Commit | Line | Data |
---|---|---|
0d6fffca KB |
1 | /* |
2 | * interplayer.c - player to player routines for Phantasia | |
3 | */ | |
4 | ||
5 | #include "include.h" | |
6 | ||
7 | /************************************************************************ | |
8 | / | |
9 | / FUNCTION NAME: checkbattle() | |
10 | / | |
11 | / FUNCTION: check to see if current player should battle another | |
12 | / | |
13 | / AUTHOR: E. A. Estes, 12/4/85 | |
14 | / | |
15 | / ARGUMENTS: none | |
16 | / | |
17 | / RETURN VALUE: none | |
18 | / | |
19 | / MODULES CALLED: battleplayer(), fread(), fseek() | |
20 | / | |
21 | / GLOBAL INPUTS: Other, Users, Player, Fileloc, *Playersfp | |
22 | / | |
23 | / GLOBAL OUTPUTS: Users | |
24 | / | |
25 | / DESCRIPTION: | |
26 | / Seach player file for a foe at the same coordinates as the | |
27 | / current player. | |
28 | / Also update user count. | |
29 | / | |
30 | /************************************************************************/ | |
31 | ||
32 | checkbattle() | |
33 | { | |
34 | long foeloc = 0L; /* location in file of person to fight */ | |
35 | ||
36 | Users = 0; | |
37 | fseek(Playersfp, 0L, 0); | |
38 | ||
39 | while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
40 | { | |
41 | if (Other.p_status != S_OFF | |
42 | && Other.p_status != S_NOTUSED | |
43 | && Other.p_status != S_HUNGUP | |
44 | && (Other.p_status != S_CLOAKED || Other.p_specialtype != SC_VALAR)) | |
45 | /* player is on and not a cloaked valar */ | |
46 | { | |
47 | ++Users; | |
48 | ||
49 | if (Player.p_x == Other.p_x | |
50 | && Player.p_y == Other.p_y | |
51 | /* same coordinates */ | |
52 | && foeloc != Fileloc | |
53 | /* not self */ | |
54 | && Player.p_status == S_PLAYING | |
55 | && (Other.p_status == S_PLAYING || Other.p_status == S_INBATTLE) | |
56 | /* both are playing */ | |
57 | && Other.p_specialtype != SC_VALAR | |
58 | && Player.p_specialtype != SC_VALAR) | |
59 | /* neither is valar */ | |
60 | { | |
61 | battleplayer(foeloc); | |
62 | return; | |
63 | } | |
64 | } | |
65 | foeloc += SZ_PLAYERSTRUCT; | |
66 | } | |
67 | } | |
68 | /*\f*/ | |
69 | /************************************************************************ | |
70 | / | |
71 | / FUNCTION NAME: battleplayer() | |
72 | / | |
73 | / FUNCTION: inter-terminal battle with another player | |
74 | / | |
75 | / AUTHOR: E. A. Estes, 2/15/86 | |
76 | / | |
77 | / ARGUMENTS: | |
78 | / long foeplace - location in player file of person to battle | |
79 | / | |
80 | / RETURN VALUE: none | |
81 | / | |
82 | / MODULES CALLED: readrecord(), readmessage(), writerecord(), collecttaxes(), | |
83 | / displaystats(), fabs(), more(), death(), sleep(), wmove(), waddch(), printw(), | |
84 | / myturn(), altercoordinates(), waddstr(), wrefresh(), mvprintw(), | |
85 | / getanswer(), wclrtoeol(), wclrtobot() | |
86 | / | |
87 | / GLOBAL INPUTS: Foestrikes, LINES, Lines, Other, Shield, Player, *stdscr, | |
88 | / Fileloc, *Enemyname | |
89 | / | |
90 | / GLOBAL OUTPUTS: Foestrikes, Lines, Shield, Player, Luckout, *Enemyname | |
91 | / | |
92 | / DESCRIPTION: | |
93 | / Inter-terminal battle is a very fragile and slightly klugy thing. | |
94 | / At any time, one player is master and the other is slave. | |
95 | / We pick who is master first by speed and level. After that, | |
96 | / the slave waits for the master to relinquish its turn, and | |
97 | / the slave becomes master, and so on. | |
98 | / | |
99 | / The items in the player structure which control the handshake are: | |
100 | / p_tampered: | |
101 | / master increments this to relinquish control | |
102 | / p_istat: | |
103 | / master sets this to specify particular action | |
104 | / p_1scratch: | |
105 | / set to total damage inflicted so far; changes to indicate action | |
106 | / | |
107 | /************************************************************************/ | |
108 | ||
109 | battleplayer(foeplace) | |
110 | long foeplace; | |
111 | { | |
112 | double dtemp; /* for temporary calculations */ | |
113 | double oldhits = 0.0; /* previous damage inflicted by foe */ | |
114 | register int loop; /* for timing out */ | |
115 | int ch; /* input */ | |
116 | short oldtampered; /* old value of foe's p_tampered */ | |
117 | ||
118 | Lines = 8; | |
119 | Luckout = FALSE; | |
120 | mvaddstr(4, 0, "Preparing for battle!\n"); | |
121 | refresh(); | |
122 | ||
123 | #ifdef SYS5 | |
124 | flushinp(); | |
125 | #endif | |
126 | ||
127 | /* set up variables, file, etc. */ | |
128 | Player.p_status = S_INBATTLE; | |
129 | Shield = Player.p_energy; | |
130 | ||
131 | /* if p_tampered is not 0, someone else may try to change it (king, etc.) */ | |
132 | Player.p_tampered = oldtampered = 1; | |
133 | Player.p_1scratch = 0.0; | |
134 | Player.p_istat = I_OFF; | |
135 | ||
136 | readrecord(&Other, foeplace); | |
137 | if (fabs(Player.p_level - Other.p_level) > 20.0) | |
138 | /* see if players are greatly mismatched */ | |
139 | { | |
140 | dtemp = (Player.p_level - Other.p_level) / MAX(Player.p_level, Other.p_level); | |
141 | if (dtemp < -0.5) | |
142 | /* foe outweighs this one */ | |
143 | Player.p_speed *= 2.0; | |
144 | } | |
145 | ||
146 | writerecord(&Player, Fileloc); /* write out all our info */ | |
147 | ||
148 | if (Player.p_blindness) | |
149 | Enemyname = "someone"; | |
150 | else | |
151 | Enemyname = Other.p_name; | |
152 | ||
153 | mvprintw(6, 0, "You have encountered %s Level: %.0f\n", Enemyname, Other.p_level); | |
154 | refresh(); | |
155 | ||
156 | for (loop = 0; Other.p_status != S_INBATTLE && loop < 30; ++loop) | |
157 | /* wait for foe to respond */ | |
158 | { | |
159 | readrecord(&Other, foeplace); | |
160 | sleep(1); | |
161 | } | |
162 | ||
163 | if (Other.p_status != S_INBATTLE) | |
164 | /* foe did not respond */ | |
165 | { | |
166 | mvprintw(5, 0, "%s is not responding.\n", Enemyname); | |
167 | goto LEAVE; | |
168 | } | |
169 | /* else, we are ready to battle */ | |
170 | ||
171 | move(4, 0); | |
172 | clrtoeol(); | |
173 | ||
174 | /* | |
175 | * determine who is first master | |
176 | * if neither player is faster, check level | |
177 | * if neither level is greater, battle is not allowed | |
178 | * (this should never happen, but we have to handle it) | |
179 | */ | |
180 | if (Player.p_speed > Other.p_speed) | |
181 | Foestrikes = FALSE; | |
182 | else if (Other.p_speed > Player.p_speed) | |
183 | Foestrikes = TRUE; | |
184 | else if (Player.p_level > Other.p_level) | |
185 | Foestrikes = FALSE; | |
186 | else if (Other.p_level > Player.p_level) | |
187 | Foestrikes = TRUE; | |
188 | else | |
189 | /* no one is faster */ | |
190 | { | |
191 | printw("You can't fight %s yet.", Enemyname); | |
192 | goto LEAVE; | |
193 | } | |
194 | ||
195 | for (;;) | |
196 | { | |
197 | displaystats(); | |
198 | readmessage(); | |
199 | mvprintw(1, 26, "%20.0f", Shield); /* overprint energy */ | |
200 | ||
201 | if (!Foestrikes) | |
202 | /* take action against foe */ | |
203 | myturn(); | |
204 | else | |
205 | /* wait for foe to take action */ | |
206 | { | |
207 | mvaddstr(4, 0, "Waiting...\n"); | |
208 | clrtoeol(); | |
209 | refresh(); | |
210 | ||
211 | for (loop = 0; loop < 20; ++loop) | |
212 | /* wait for foe to act */ | |
213 | { | |
214 | readrecord(&Other, foeplace); | |
215 | if (Other.p_1scratch != oldhits) | |
216 | /* p_1scratch changes to indicate action */ | |
217 | break; | |
218 | else | |
219 | /* wait and try again */ | |
220 | { | |
221 | sleep(1); | |
222 | addch('.'); | |
223 | refresh(); | |
224 | } | |
225 | } | |
226 | ||
227 | if (Other.p_1scratch == oldhits) | |
228 | { | |
229 | /* timeout */ | |
230 | mvaddstr(22, 0, "Timeout: waiting for response. Do you want to wait ? "); | |
231 | ch = getanswer("NY", FALSE); | |
232 | move(22, 0); | |
233 | clrtobot(); | |
234 | if (ch == 'Y') | |
235 | continue; | |
236 | else | |
237 | break; | |
238 | } | |
239 | else | |
240 | /* foe took action */ | |
241 | { | |
242 | switch (Other.p_istat) | |
243 | { | |
244 | case I_RAN: /* foe ran away */ | |
245 | mvprintw(Lines++, 0, "%s ran away!", Enemyname); | |
246 | break; | |
247 | ||
248 | case I_STUCK: /* foe tried to run, but couldn't */ | |
249 | mvprintw(Lines++, 0, "%s tried to run away.", Enemyname); | |
250 | break; | |
251 | ||
252 | case I_BLEWIT: /* foe tried to luckout, but didn't */ | |
253 | mvprintw(Lines++, 0, "%s tried to luckout!", Enemyname); | |
254 | break; | |
255 | ||
256 | default: | |
257 | dtemp = Other.p_1scratch - oldhits; | |
258 | mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, dtemp); | |
259 | Shield -= dtemp; | |
260 | break; | |
261 | } | |
262 | ||
263 | oldhits = Other.p_1scratch; /* keep track of old hits */ | |
264 | ||
265 | if (Other.p_tampered != oldtampered) | |
266 | /* p_tampered changes to relinquish turn */ | |
267 | { | |
268 | oldtampered = Other.p_tampered; | |
269 | Foestrikes = FALSE; | |
270 | } | |
271 | } | |
272 | } | |
273 | ||
274 | /* decide what happens next */ | |
275 | refresh(); | |
276 | if (Lines > LINES - 2) | |
277 | { | |
278 | more(Lines); | |
279 | move(Lines = 8, 0); | |
280 | clrtobot(); | |
281 | } | |
282 | ||
283 | if (Other.p_istat == I_KILLED || Shield < 0.0) | |
284 | /* we died */ | |
285 | { | |
286 | Shield = -2.0; /* insure this value is negative */ | |
287 | break; | |
288 | } | |
289 | ||
290 | if (Player.p_istat == I_KILLED) | |
291 | /* we killed foe; award treasre */ | |
292 | { | |
293 | mvprintw(Lines++, 0, "You killed %s!", Enemyname); | |
294 | Player.p_experience += Other.p_experience; | |
295 | Player.p_crowns += (Player.p_level < 1000.0) ? Other.p_crowns : 0; | |
296 | Player.p_amulets += Other.p_amulets; | |
297 | Player.p_charms += Other.p_charms; | |
298 | collecttaxes(Other.p_gold, Other.p_gems); | |
299 | Player.p_sword = MAX(Player.p_sword, Other.p_sword); | |
300 | Player.p_shield = MAX(Player.p_shield, Other.p_shield); | |
301 | Player.p_quksilver = MAX(Player.p_quksilver, Other.p_quksilver); | |
302 | if (Other.p_virgin && !Player.p_virgin) | |
303 | { | |
304 | mvaddstr(Lines++, 0, "You have rescued a virgin. Will you be honorable ? "); | |
305 | if ((ch = getanswer("YN", FALSE)) == 'Y') | |
306 | Player.p_virgin = TRUE; | |
307 | else | |
308 | { | |
309 | ++Player.p_sin; | |
310 | Player.p_experience += 8000.0; | |
311 | } | |
312 | } | |
313 | sleep(3); /* give other person time to die */ | |
314 | break; | |
315 | } | |
316 | else if (Player.p_istat == I_RAN || Other.p_istat == I_RAN) | |
317 | /* either player ran away */ | |
318 | break; | |
319 | } | |
320 | ||
321 | LEAVE: | |
322 | /* clean up things and leave */ | |
323 | writerecord(&Player, Fileloc); /* update a final time */ | |
324 | altercoordinates(0.0, 0.0, A_NEAR); /* move away from battle site */ | |
325 | Player.p_energy = Shield; /* set energy to actual value */ | |
326 | Player.p_tampered = T_OFF; /* clear p_tampered */ | |
327 | ||
328 | more(Lines); /* pause */ | |
329 | ||
330 | move(4, 0); | |
331 | clrtobot(); /* clear bottom area of screen */ | |
332 | ||
333 | if (Player.p_energy < 0.0) | |
334 | /* we are dead */ | |
335 | death("Interterminal battle"); | |
336 | } | |
337 | /*\f*/ | |
338 | /************************************************************************ | |
339 | / | |
340 | / FUNCTION NAME: myturn() | |
341 | / | |
342 | / FUNCTION: process players action against foe in battle | |
343 | / | |
344 | / AUTHOR: E. A. Estes, 2/7/86 | |
345 | / | |
346 | / ARGUMENTS: none | |
347 | / | |
348 | / RETURN VALUE: none | |
349 | / | |
350 | / MODULES CALLED: writerecord(), inputoption(), floor(), wmove(), drandom(), | |
351 | / waddstr(), wrefresh(), mvprintw(), wclrtoeol(), wclrtobot() | |
352 | / | |
353 | / GLOBAL INPUTS: Lines, Other, Player, *stdscr, Fileloc, Luckout, | |
354 | / *Enemyname | |
355 | / | |
356 | / GLOBAL OUTPUTS: Foestrikes, Lines, Player, Luckout | |
357 | / | |
358 | / DESCRIPTION: | |
359 | / Take action action against foe, and decide who is master | |
360 | / for next iteration. | |
361 | / | |
362 | /************************************************************************/ | |
363 | ||
364 | myturn() | |
365 | { | |
366 | double dtemp; /* for temporary calculations */ | |
367 | int ch; /* input */ | |
368 | ||
369 | mvaddstr(7, 0, "1:Fight 2:Run Away! 3:Power Blast "); | |
370 | if (Luckout) | |
371 | clrtoeol(); | |
372 | else | |
373 | addstr("4:Luckout "); | |
374 | ||
375 | ch = inputoption(); | |
376 | move(Lines = 8, 0); | |
377 | clrtobot(); | |
378 | ||
379 | switch (ch) | |
380 | { | |
381 | default: /* fight */ | |
382 | dtemp = ROLL(2.0, Player.p_might); | |
383 | HIT: | |
384 | mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, dtemp); | |
385 | Player.p_sin += 0.5; | |
386 | Player.p_1scratch += dtemp; | |
387 | Player.p_istat = I_OFF; | |
388 | break; | |
389 | ||
390 | case '2': /* run away */ | |
391 | Player.p_1scratch -= 1.0; /* change this to indicate action */ | |
392 | if (drandom() > 0.25) | |
393 | { | |
394 | mvaddstr(Lines++, 0, "You got away!"); | |
395 | Player.p_istat = I_RAN; | |
396 | } | |
397 | else | |
398 | { | |
399 | mvprintw(Lines++, 0, "%s is still after you!", Enemyname); | |
400 | Player.p_istat = I_STUCK; | |
401 | } | |
402 | break; | |
403 | ||
404 | case '3': /* power blast */ | |
405 | dtemp = MIN(Player.p_mana, Player.p_level * 5.0); | |
406 | Player.p_mana -= dtemp; | |
407 | dtemp *= (drandom() + 0.5) * Player.p_magiclvl * 0.2 + 2.0; | |
408 | mvprintw(Lines++, 0, "You blasted %s !", Enemyname); | |
409 | goto HIT; | |
410 | ||
411 | case '4': /* luckout */ | |
412 | if (Luckout || drandom() > 0.1) | |
413 | { | |
414 | if (Luckout) | |
415 | mvaddstr(Lines++, 0, "You already tried that!"); | |
416 | else | |
417 | { | |
418 | mvaddstr(Lines++, 0, "Not this time . . ."); | |
419 | Luckout = TRUE; | |
420 | } | |
421 | ||
422 | Player.p_1scratch -= 1.0; | |
423 | Player.p_istat = I_BLEWIT; | |
424 | } | |
425 | else | |
426 | { | |
427 | mvaddstr(Lines++, 0, "You just lucked out!"); | |
428 | Player.p_1scratch = Other.p_energy * 1.1; | |
429 | } | |
430 | break; | |
431 | } | |
432 | ||
433 | refresh(); | |
434 | Player.p_1scratch = floor(Player.p_1scratch); /* clean up any mess */ | |
435 | ||
436 | if (Player.p_1scratch > Other.p_energy) | |
437 | Player.p_istat = I_KILLED; | |
438 | else if (drandom() * Player.p_speed < drandom() * Other.p_speed) | |
439 | /* relinquish control */ | |
440 | { | |
441 | ++Player.p_tampered; | |
442 | Foestrikes = TRUE; | |
443 | } | |
444 | ||
445 | writerecord(&Player, Fileloc); /* let foe know what we did */ | |
446 | } | |
447 | /*\f*/ | |
448 | /************************************************************************ | |
449 | / | |
450 | / FUNCTION NAME: checktampered() | |
451 | / | |
452 | / FUNCTION: check if current player has been tampered with | |
453 | / | |
454 | / AUTHOR: E. A. Estes, 12/4/85 | |
455 | / | |
456 | / ARGUMENTS: none | |
457 | / | |
458 | / RETURN VALUE: none | |
459 | / | |
460 | / MODULES CALLED: readrecord(), fread(), fseek(), tampered(), writevoid() | |
461 | / | |
462 | / GLOBAL INPUTS: *Energyvoidfp, Other, Player, Fileloc, Enrgyvoid | |
463 | / | |
464 | / GLOBAL OUTPUTS: Enrgyvoid | |
465 | / | |
466 | / DESCRIPTION: | |
467 | / Check for energy voids, holy grail, and tampering by other | |
468 | / players. | |
469 | / | |
470 | /************************************************************************/ | |
471 | ||
472 | checktampered() | |
473 | { | |
474 | long loc = 0L; /* location in energy void file */ | |
475 | ||
476 | /* first check for energy voids */ | |
477 | fseek(Energyvoidfp, 0L, 0); | |
478 | while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1) | |
479 | if (Enrgyvoid.ev_active | |
480 | && Enrgyvoid.ev_x == Player.p_x | |
481 | && Enrgyvoid.ev_y == Player.p_y) | |
482 | /* sitting on one */ | |
483 | { | |
484 | if (loc > 0L) | |
485 | /* not the holy grail; inactivate energy void */ | |
486 | { | |
487 | Enrgyvoid.ev_active = FALSE; | |
488 | writevoid(&Enrgyvoid, loc); | |
489 | tampered(T_NRGVOID, 0.0, 0.0); | |
490 | } | |
491 | else if (Player.p_status != S_CLOAKED) | |
492 | /* holy grail */ | |
493 | tampered(T_GRAIL, 0.0, 0.0); | |
494 | break; | |
495 | } | |
496 | else | |
497 | loc += SZ_VOIDSTRUCT; | |
498 | ||
499 | /* now check for other things */ | |
500 | readrecord(&Other, Fileloc); | |
501 | if (Other.p_tampered != T_OFF) | |
502 | tampered(Other.p_tampered, Other.p_1scratch, Other.p_2scratch); | |
503 | } | |
504 | /*\f*/ | |
505 | /************************************************************************ | |
506 | / | |
507 | / FUNCTION NAME: tampered() | |
508 | / | |
509 | / FUNCTION: take care of tampering by other players | |
510 | / | |
511 | / AUTHOR: E. A. Estes, 12/4/85 | |
512 | / | |
513 | / ARGUMENTS: | |
514 | / int what - what type of tampering | |
515 | / double arg1, arg2 - rest of tampering info | |
516 | / | |
517 | / RETURN VALUE: none | |
518 | / | |
519 | / MODULES CALLED: writerecord(), more(), fread(), death(), fseek(), sleep(), | |
520 | / floor(), wmove(), waddch(), drandom(), printw(), altercoordinates(), | |
521 | / waddstr(), wrefresh(), encounter(), writevoid() | |
522 | / | |
523 | / GLOBAL INPUTS: Other, Player, *stdscr, Enrgyvoid, *Playersfp | |
524 | / | |
525 | / GLOBAL OUTPUTS: Other, Player, Changed, Enrgyvoid | |
526 | / | |
527 | / DESCRIPTION: | |
528 | / Take care of energy voids, holy grail, decree and intervention | |
529 | / action on current player. | |
530 | / | |
531 | /************************************************************************/ | |
532 | ||
533 | tampered(what, arg1, arg2) | |
534 | int what; | |
535 | double arg1; | |
536 | double arg2; | |
537 | { | |
538 | long loc; /* location in file of other players */ | |
539 | ||
540 | Changed = TRUE; | |
541 | move(4,0); | |
542 | ||
543 | Player.p_tampered = T_OFF; /* no longer tampered with */ | |
544 | ||
545 | switch (what) | |
546 | { | |
547 | case T_NRGVOID: | |
548 | addstr("You've hit an energy void !\n"); | |
549 | Player.p_mana /= 3.0; | |
550 | Player.p_energy /= 2.0; | |
551 | Player.p_gold = floor(Player.p_gold/1.25) + 0.1; | |
552 | altercoordinates(0.0, 0.0, A_NEAR); | |
553 | break; | |
554 | ||
555 | case T_TRANSPORT: | |
556 | addstr("The king transported you ! "); | |
557 | if (Player.p_charms > 0) | |
558 | { | |
559 | addstr("But your charm saved you. . .\n"); | |
560 | --Player.p_charms; | |
561 | } | |
562 | else | |
563 | { | |
564 | altercoordinates(0.0, 0.0, A_FAR); | |
565 | addch('\n'); | |
566 | } | |
567 | break; | |
568 | ||
569 | case T_BESTOW: | |
570 | printw("The king has bestowed %.0f gold pieces on you !\n", arg1); | |
571 | Player.p_gold += arg1; | |
572 | break; | |
573 | ||
574 | case T_CURSED: | |
575 | addstr("You've been cursed ! "); | |
576 | if (Player.p_blessing) | |
577 | { | |
578 | addstr("But your blessing saved you. . .\n"); | |
579 | Player.p_blessing = FALSE; | |
580 | } | |
581 | else | |
582 | { | |
583 | addch('\n'); | |
584 | Player.p_poison += 2.0; | |
585 | Player.p_energy = 10.0; | |
586 | Player.p_maxenergy *= 0.95; | |
587 | Player.p_status = S_PLAYING; /* no longer cloaked */ | |
588 | } | |
589 | break; | |
590 | ||
591 | case T_VAPORIZED: | |
592 | addstr("You have been vaporized!\n"); | |
593 | more(7); | |
594 | death("Vaporization"); | |
595 | break; | |
596 | ||
597 | case T_MONSTER: | |
598 | addstr("The Valar zapped you with a monster!\n"); | |
599 | more(7); | |
600 | encounter((int) arg1); | |
601 | return; | |
602 | ||
603 | case T_BLESSED: | |
604 | addstr("The Valar has blessed you!\n"); | |
605 | Player.p_energy = (Player.p_maxenergy *= 1.05) + Player.p_shield; | |
606 | Player.p_mana += 500.0; | |
607 | Player.p_strength += 0.5; | |
608 | Player.p_brains += 0.5; | |
609 | Player.p_magiclvl += 0.5; | |
610 | Player.p_poison = MIN(0.5, Player.p_poison); | |
611 | break; | |
612 | ||
613 | case T_RELOCATE: | |
614 | addstr("You've been relocated. . .\n"); | |
615 | altercoordinates(arg1, arg2, A_FORCED); | |
616 | break; | |
617 | ||
618 | case T_HEAL: | |
619 | addstr("You've been healed!\n"); | |
620 | Player.p_poison -= 0.25; | |
621 | Player.p_energy = Player.p_maxenergy + Player.p_shield; | |
622 | break; | |
623 | ||
624 | case T_EXVALAR: | |
625 | addstr("You are no longer Valar!\n"); | |
626 | Player.p_specialtype = SC_COUNCIL; | |
627 | break; | |
628 | ||
629 | case T_GRAIL: | |
630 | addstr("You have found The Holy Grail!!\n"); | |
631 | if (Player.p_specialtype < SC_COUNCIL) | |
632 | /* must be council of wise to behold grail */ | |
633 | { | |
634 | addstr("However, you are not experienced enough to behold it.\n"); | |
635 | Player.p_sin *= Player.p_sin; | |
636 | Player.p_mana += 1000; | |
637 | } | |
638 | else if (Player.p_specialtype == SC_VALAR | |
639 | || Player.p_specialtype == SC_EXVALAR) | |
640 | { | |
641 | addstr("You have made it to the position of Valar once already.\n"); | |
642 | addstr("The Grail is of no more use to you now.\n"); | |
643 | } | |
644 | else | |
645 | { | |
646 | addstr("It is now time to see if you are worthy to behold it. . .\n"); | |
647 | refresh(); | |
648 | sleep(4); | |
649 | ||
650 | if (drandom() / 2.0 < Player.p_sin) | |
651 | { | |
652 | addstr("You have failed!\n"); | |
653 | Player.p_strength = | |
654 | Player.p_mana = | |
655 | Player.p_energy = | |
656 | Player.p_maxenergy = | |
657 | Player.p_magiclvl = | |
658 | Player.p_brains = | |
659 | Player.p_experience = | |
660 | Player.p_quickness = 1.0; | |
661 | ||
662 | altercoordinates(1.0, 1.0, A_FORCED); | |
663 | Player.p_level = 0.0; | |
664 | } | |
665 | else | |
666 | { | |
667 | addstr("You made to position of Valar!\n"); | |
668 | Player.p_specialtype = SC_VALAR; | |
669 | Player.p_lives = 5; | |
670 | fseek(Playersfp, 0L, 0); | |
671 | loc = 0L; | |
672 | while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
673 | /* search for existing valar */ | |
674 | if (Other.p_specialtype == SC_VALAR | |
675 | && Other.p_status != S_NOTUSED) | |
676 | /* found old valar */ | |
677 | { | |
678 | Other.p_tampered = T_EXVALAR; | |
679 | writerecord(&Other, loc); | |
680 | break; | |
681 | } | |
682 | else | |
683 | loc += SZ_PLAYERSTRUCT; | |
684 | } | |
685 | } | |
686 | ||
687 | /* move grail to new location */ | |
688 | Enrgyvoid.ev_active = TRUE; | |
689 | Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6); | |
690 | Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6); | |
691 | writevoid(&Enrgyvoid, 0L); | |
692 | break; | |
693 | } | |
694 | refresh(); | |
695 | sleep(2); | |
696 | } | |
697 | /*\f*/ | |
698 | /************************************************************************ | |
699 | / | |
700 | / FUNCTION NAME: userlist() | |
701 | / | |
702 | / FUNCTION: print list of players and locations | |
703 | / | |
704 | / AUTHOR: E. A. Estes, 2/28/86 | |
705 | / | |
706 | / ARGUMENTS: | |
707 | / bool ingameflag - set if called while playing | |
708 | / | |
709 | / RETURN VALUE: none | |
710 | / | |
711 | / MODULES CALLED: descrstatus(), descrlocation(), more(), fread(), fseek(), | |
712 | / floor(), wmove(), printw(), waddstr(), distance(), wrefresh(), | |
713 | / descrtype(), wclrtobot() | |
714 | / | |
715 | / GLOBAL INPUTS: LINES, Other, Circle, Wizard, Player, *stdscr, *Playersfp | |
716 | / | |
717 | / GLOBAL OUTPUTS: none | |
718 | / | |
719 | / DESCRIPTION: | |
720 | / We can only see the coordinate of those closer to the origin | |
721 | / from us. | |
722 | / Kings and council of the wise can see and can be seen by everyone. | |
723 | / Palantirs are good for seeing everyone; and the valar can use | |
724 | / one to see through a 'cloak' spell. | |
725 | / The valar has no coordinates, and is completely invisible if | |
726 | / cloaked. | |
727 | / | |
728 | /************************************************************************/ | |
729 | ||
730 | userlist(ingameflag) | |
731 | bool ingameflag; | |
732 | { | |
733 | register int numusers = 0; /* number of users on file */ | |
734 | ||
735 | if (ingameflag && Player.p_blindness) | |
736 | { | |
737 | mvaddstr(8, 0, "You cannot see anyone.\n"); | |
738 | return; | |
739 | } | |
740 | ||
741 | fseek(Playersfp, 0L, 0); | |
742 | mvaddstr(8, 0, | |
743 | "Name X Y Lvl Type Login Status\n"); | |
744 | ||
745 | while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
746 | { | |
747 | if (Other.p_status == S_NOTUSED | |
748 | /* record is unused */ | |
749 | || (Other.p_specialtype == SC_VALAR && Other.p_status == S_CLOAKED)) | |
750 | /* cloaked valar */ | |
751 | { | |
752 | if (!Wizard) | |
753 | /* wizard can see everything on file */ | |
754 | continue; | |
755 | } | |
756 | ||
757 | ++numusers; | |
758 | ||
759 | if (ingameflag && | |
760 | /* must be playing for the rest of these conditions */ | |
761 | (Player.p_specialtype >= SC_KING | |
762 | /* kings and higher can see others */ | |
763 | || Other.p_specialtype >= SC_KING | |
764 | /* kings and higher can be seen by others */ | |
765 | || Circle >= CIRCLE(Other.p_x, Other.p_y) | |
766 | /* those nearer the origin can be seen */ | |
767 | || Player.p_palantir) | |
768 | /* palantir enables one to see others */ | |
769 | && (Other.p_status != S_CLOAKED | |
770 | || (Player.p_specialtype == SC_VALAR && Player.p_palantir)) | |
771 | /* not cloaked; valar can see through cloak with a palantir */ | |
772 | && Other.p_specialtype != SC_VALAR) | |
773 | /* not a valar */ | |
774 | /* coordinates should be printed */ | |
775 | printw("%-20s %8.0f %8.0f ", | |
776 | Other.p_name, Other.p_x, Other.p_y); | |
777 | else | |
778 | /* cannot see player's coordinates */ | |
779 | printw("%-20s %19.19s ", | |
780 | Other.p_name, descrlocation(&Other, TRUE)); | |
781 | ||
782 | printw("%6.0f %s %-9.9s%s\n", Other.p_level, descrtype(&Other, TRUE), | |
783 | Other.p_login, descrstatus(&Other)); | |
784 | ||
785 | if ((numusers % (LINES - 10)) == 0) | |
786 | { | |
787 | more(LINES - 1); | |
788 | move(9, 0); | |
789 | clrtobot(); | |
790 | } | |
791 | } | |
792 | ||
793 | printw("Total players on file = %d\n", numusers); | |
794 | refresh(); | |
795 | } | |
796 | /*\f*/ | |
797 | /************************************************************************ | |
798 | / | |
799 | / FUNCTION NAME: throneroom() | |
800 | / | |
801 | / FUNCTION: king stuff upon entering throne | |
802 | / | |
803 | / AUTHOR: E. A. Estes, 12/16/85 | |
804 | / | |
805 | / ARGUMENTS: none | |
806 | / | |
807 | / RETURN VALUE: none | |
808 | / | |
809 | / MODULES CALLED: writerecord(), fread(), fseek(), fopen(), wmove(), fclose(), | |
810 | / fwrite(), altercoordinates(), waddstr(), fprintf() | |
811 | / | |
812 | / GLOBAL INPUTS: *Energyvoidfp, Other, Player, *stdscr, Voidfile[], | |
813 | / Messfile[], Enrgyvoid, *Playersfp | |
814 | / | |
815 | / GLOBAL OUTPUTS: Other, Player, Changed | |
816 | / | |
817 | / DESCRIPTION: | |
818 | / If player is not already king, make him/her so if the old king | |
819 | / is not playing. | |
820 | / Clear energy voids with new king. | |
821 | / Print 'decree' prompt. | |
822 | / | |
823 | /************************************************************************/ | |
824 | ||
825 | throneroom() | |
826 | { | |
827 | FILE *fp; /* to clear energy voids */ | |
828 | long loc = 0L; /* location of old king in player file */ | |
829 | ||
830 | if (Player.p_specialtype < SC_KING) | |
831 | /* not already king -- assumes crown */ | |
832 | { | |
833 | fseek(Playersfp, 0L, 0); | |
834 | while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
835 | if (Other.p_specialtype == SC_KING && Other.p_status != S_NOTUSED) | |
836 | /* found old king */ | |
837 | { | |
838 | if (Other.p_status != S_OFF) | |
839 | /* old king is playing */ | |
840 | { | |
841 | mvaddstr( 4, 0, "The king is playing, so you cannot steal his throne\n"); | |
842 | altercoordinates(0.0, 0.0, A_NEAR); | |
843 | move(6, 0); | |
844 | return; | |
845 | } | |
846 | else | |
847 | /* old king is not playing - remove him/her */ | |
848 | { | |
849 | Other.p_specialtype = SC_NONE; | |
850 | if (Other.p_crowns) | |
851 | --Other.p_crowns; | |
852 | writerecord(&Other, loc); | |
853 | break; | |
854 | } | |
855 | } | |
856 | else | |
857 | loc += SZ_PLAYERSTRUCT; | |
858 | ||
859 | /* make player new king */ | |
860 | Changed = TRUE; | |
861 | Player.p_specialtype = SC_KING; | |
862 | mvaddstr(4, 0, "You have become king!\n"); | |
863 | ||
864 | /* let everyone else know */ | |
865 | fp = fopen(Messfile, "w"); | |
866 | fprintf(fp, "All hail the new king!"); | |
867 | fclose(fp); | |
868 | ||
869 | /* clear all energy voids; retain location of holy grail */ | |
870 | fseek(Energyvoidfp, 0L, 0); | |
871 | fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp); | |
872 | fp = fopen(Voidfile, "w"); | |
873 | fwrite((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, fp); | |
874 | fclose(fp); | |
875 | } | |
876 | ||
877 | mvaddstr(6, 0, "0:Decree "); | |
878 | } | |
879 | /*\f*/ | |
880 | /************************************************************************ | |
881 | / | |
882 | / FUNCTION NAME: dotampered() | |
883 | / | |
884 | / FUNCTION: king and valar special options | |
885 | / | |
886 | / AUTHOR: E. A. Estes, 2/28/86 | |
887 | / | |
888 | / ARGUMENTS: none | |
889 | / | |
890 | / RETURN VALUE: none | |
891 | / | |
892 | / MODULES CALLED: writerecord(), truncstring(), fread(), fseek(), fopen(), | |
893 | / floor(), wmove(), drandom(), fclose(), fwrite(), sscanf(), strcmp(), | |
894 | / infloat(), waddstr(), findname(), distance(), userlist(), mvprintw(), | |
895 | / allocvoid(), getanswer(), getstring(), wclrtoeol(), writevoid() | |
896 | / | |
897 | / GLOBAL INPUTS: *Energyvoidfp, Other, Illcmd[], Wizard, Player, *stdscr, | |
898 | / Databuf[], Goldfile[], Enrgyvoid | |
899 | / | |
900 | / GLOBAL OUTPUTS: Other, Player, Enrgyvoid | |
901 | / | |
902 | / DESCRIPTION: | |
903 | / Tamper with other players. Handle king/valar specific options. | |
904 | / | |
905 | /************************************************************************/ | |
906 | ||
907 | dotampered() | |
908 | { | |
909 | short tamper; /* value for tampering with other players */ | |
910 | char *option; /* pointer to option description */ | |
911 | double temp1 = 0.0, temp2 = 0.0; /* other tampering values */ | |
912 | int ch; /* input */ | |
913 | long loc; /* location in energy void file */ | |
914 | FILE *fp; /* for opening gold file */ | |
915 | ||
916 | move(6, 0); | |
917 | clrtoeol(); | |
918 | if (Player.p_specialtype < SC_COUNCIL && !Wizard) | |
919 | /* king options */ | |
920 | { | |
921 | addstr("1:Transport 2:Curse 3:Energy Void 4:Bestow 5:Collect Taxes "); | |
922 | ||
923 | ch = getanswer(" ", TRUE); | |
924 | move(6, 0); | |
925 | clrtoeol(); | |
926 | move(4, 0); | |
927 | switch (ch) | |
928 | { | |
929 | case '1': /* transport someone */ | |
930 | tamper = T_TRANSPORT; | |
931 | option = "transport"; | |
932 | break; | |
933 | ||
934 | case '2': /* curse another */ | |
935 | tamper = T_CURSED; | |
936 | option = "curse"; | |
937 | break; | |
938 | ||
939 | case '3': /* create energy void */ | |
940 | if ((loc = allocvoid()) > 20L * SZ_VOIDSTRUCT) | |
941 | /* can only have 20 void active at once */ | |
942 | mvaddstr(5, 0, "Sorry, void creation limit reached.\n"); | |
943 | else | |
944 | { | |
945 | addstr("Enter the X Y coordinates of void ? "); | |
946 | getstring(Databuf, SZ_DATABUF); | |
4266ed4a | 947 | sscanf(Databuf, "%lf %lf", &temp1, &temp2); |
0d6fffca KB |
948 | Enrgyvoid.ev_x = floor(temp1); |
949 | Enrgyvoid.ev_y = floor(temp2); | |
950 | Enrgyvoid.ev_active = TRUE; | |
951 | writevoid(&Enrgyvoid, loc); | |
952 | mvaddstr(5, 0, "It is done.\n"); | |
953 | } | |
954 | return; | |
955 | ||
956 | case '4': /* bestow gold to subject */ | |
957 | tamper = T_BESTOW; | |
958 | addstr("How much gold to bestow ? "); | |
959 | temp1 = infloat(); | |
960 | if (temp1 > Player.p_gold || temp1 < 0) | |
961 | { | |
962 | mvaddstr(5, 0, "You don't have that !\n"); | |
963 | return; | |
964 | } | |
965 | ||
966 | /* adjust gold after we are sure it will be given to someone */ | |
967 | option = "give gold to"; | |
968 | break; | |
969 | ||
970 | case '5': /* collect accumulated taxes */ | |
971 | if ((fp = fopen(Goldfile, "r+")) != NULL) | |
972 | /* collect taxes */ | |
973 | { | |
974 | fread((char *) &temp1, sizeof(double), 1, fp); | |
975 | fseek(fp, 0L, 0); | |
976 | /* clear out value */ | |
977 | temp2 = 0.0; | |
978 | fwrite((char *) &temp2, sizeof(double), 1, fp); | |
979 | fclose(fp); | |
980 | } | |
981 | ||
982 | mvprintw(4, 0, "You have collected %.0f in gold.\n", temp1); | |
983 | Player.p_gold += floor(temp1); | |
984 | return; | |
985 | ||
986 | default: | |
987 | return; | |
988 | } | |
989 | /* end of king options */ | |
990 | } | |
991 | else | |
992 | /* council of wise, valar, wizard options */ | |
993 | { | |
994 | addstr("1:Heal "); | |
995 | if (Player.p_palantir || Wizard) | |
996 | addstr("2:Seek Grail "); | |
997 | if (Player.p_specialtype == SC_VALAR || Wizard) | |
998 | addstr("3:Throw Monster 4:Relocate 5:Bless "); | |
999 | if (Wizard) | |
1000 | addstr("6:Vaporize "); | |
1001 | ||
1002 | ch = getanswer(" ", TRUE); | |
1003 | if (!Wizard) | |
1004 | { | |
1005 | if (ch > '2' && Player.p_specialtype != SC_VALAR) | |
1006 | { | |
1007 | ILLCMD(); | |
1008 | return; | |
1009 | } | |
1010 | ||
1011 | if (Player.p_mana < MM_INTERVENE) | |
1012 | { | |
1013 | mvaddstr(5, 0, "No mana left.\n"); | |
1014 | return; | |
1015 | } | |
1016 | else | |
1017 | Player.p_mana -= MM_INTERVENE; | |
1018 | } | |
1019 | ||
1020 | switch (ch) | |
1021 | { | |
1022 | case '1': /* heal another */ | |
1023 | tamper = T_HEAL; | |
1024 | option = "heal"; | |
1025 | break; | |
1026 | ||
1027 | case '2': /* seek grail */ | |
1028 | if (Player.p_palantir) | |
1029 | /* need a palantir to seek */ | |
1030 | { | |
1031 | fseek(Energyvoidfp, 0L, 0); | |
1032 | fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp); | |
1033 | temp1 = distance(Player.p_x, Enrgyvoid.ev_x, Player.p_y, Enrgyvoid.ev_y); | |
1034 | temp1 += ROLL(-temp1 / 10.0, temp1 / 5.0); /* add some error */ | |
1035 | mvprintw(5, 0, "The palantir says the Grail is about %.0f away.\n", temp1); | |
1036 | } | |
1037 | else | |
1038 | /* no palantir */ | |
1039 | mvaddstr(5, 0, "You need a palantir to seek the Grail.\n"); | |
1040 | return; | |
1041 | ||
1042 | case '3': /* lob monster at someone */ | |
1043 | mvaddstr(4, 0, "Which monster [0-99] ? "); | |
1044 | temp1 = infloat(); | |
1045 | temp1 = MAX(0.0, MIN(99.0, temp1)); | |
1046 | tamper = T_MONSTER; | |
1047 | option = "throw a monster at"; | |
1048 | break; | |
1049 | ||
1050 | case '4': /* move another player */ | |
1051 | mvaddstr(4, 0, "New X Y coordinates ? "); | |
1052 | getstring(Databuf, SZ_DATABUF); | |
4266ed4a | 1053 | sscanf(Databuf, "%lf %lf", &temp1, &temp2); |
0d6fffca KB |
1054 | tamper = T_RELOCATE; |
1055 | option = "relocate"; | |
1056 | break; | |
1057 | ||
1058 | case '5': /* bless a player */ | |
1059 | tamper = T_BLESSED; | |
1060 | option = "bless"; | |
1061 | break; | |
1062 | ||
1063 | case '6': /* kill off a player */ | |
1064 | if (Wizard) | |
1065 | { | |
1066 | tamper = T_VAPORIZED; | |
1067 | option = "vaporize"; | |
1068 | break; | |
1069 | } | |
1070 | else | |
1071 | return; | |
1072 | ||
1073 | default: | |
1074 | return; | |
1075 | } | |
1076 | ||
1077 | /* adjust age after we are sure intervention will be done */ | |
1078 | /* end of valar, etc. options */ | |
1079 | } | |
1080 | ||
1081 | for (;;) | |
1082 | /* prompt for player to affect */ | |
1083 | { | |
1084 | mvprintw(4, 0, "Who do you want to %s ? ", option); | |
1085 | getstring(Databuf, SZ_DATABUF); | |
1086 | truncstring(Databuf); | |
1087 | ||
1088 | if (Databuf[0] == '\0') | |
1089 | userlist(TRUE); | |
1090 | else | |
1091 | break; | |
1092 | } | |
1093 | ||
1094 | if (strcmp(Player.p_name, Databuf) != 0) | |
1095 | /* name other than self */ | |
1096 | { | |
1097 | if ((loc = findname(Databuf, &Other)) >= 0L) | |
1098 | { | |
1099 | if (Other.p_tampered != T_OFF) | |
1100 | { | |
1101 | mvaddstr(5, 0, "That person has something pending already.\n"); | |
1102 | return; | |
1103 | } | |
1104 | else | |
1105 | { | |
1106 | if (tamper == T_RELOCATE | |
1107 | && CIRCLE(temp1, temp2) < CIRCLE(Other.p_x, Other.p_y) | |
1108 | && !Wizard) | |
1109 | mvaddstr(5, 0, "Cannot move someone closer to the Lord's Chamber.\n"); | |
1110 | else | |
1111 | { | |
1112 | if (tamper == T_BESTOW) Player.p_gold -= floor(temp1); | |
1113 | if (!Wizard && (tamper == T_HEAL || tamper == T_MONSTER || | |
1114 | tamper == T_RELOCATE || tamper == T_BLESSED)) | |
1115 | Player.p_age += N_AGE; /* age penalty */ | |
1116 | Other.p_tampered = tamper; | |
1117 | Other.p_1scratch = floor(temp1); | |
1118 | Other.p_2scratch = floor(temp2); | |
1119 | writerecord(&Other, loc); | |
1120 | mvaddstr(5, 0, "It is done.\n"); | |
1121 | } | |
1122 | return; | |
1123 | } | |
1124 | } | |
1125 | else | |
1126 | /* player not found */ | |
1127 | mvaddstr(5, 0, "There is no one by that name.\n"); | |
1128 | } | |
1129 | else | |
1130 | /* self */ | |
1131 | mvaddstr(5, 0, "You may not do it to yourself!\n"); | |
1132 | } | |
1133 | /*\f*/ | |
1134 | /************************************************************************ | |
1135 | / | |
1136 | / FUNCTION NAME: writevoid() | |
1137 | / | |
1138 | / FUNCTION: update energy void entry in energy void file | |
1139 | / | |
1140 | / AUTHOR: E. A. Estes, 12/4/85 | |
1141 | / | |
1142 | / ARGUMENTS: | |
1143 | / struct energyvoid *vp - pointer to structure to write to file | |
1144 | / long loc - location in file to update | |
1145 | / | |
1146 | / RETURN VALUE: none | |
1147 | / | |
1148 | / MODULES CALLED: fseek(), fwrite(), fflush() | |
1149 | / | |
1150 | / GLOBAL INPUTS: *Energyvoidfp | |
1151 | / | |
1152 | / GLOBAL OUTPUTS: none | |
1153 | / | |
1154 | / DESCRIPTION: | |
1155 | / Write out energy void structure at specified location. | |
1156 | / | |
1157 | /************************************************************************/ | |
1158 | ||
1159 | writevoid(vp, loc) | |
1160 | register struct energyvoid *vp; | |
1161 | long loc; | |
1162 | { | |
1163 | ||
1164 | fseek(Energyvoidfp, loc, 0); | |
1165 | fwrite((char *) vp, SZ_VOIDSTRUCT, 1, Energyvoidfp); | |
1166 | fflush(Energyvoidfp); | |
1167 | fseek(Energyvoidfp, 0L, 0); | |
1168 | } | |
1169 | /*\f*/ | |
1170 | /************************************************************************ | |
1171 | / | |
1172 | / FUNCTION NAME: allocvoid() | |
1173 | / | |
1174 | / FUNCTION: allocate space for a new energy void | |
1175 | / | |
1176 | / AUTHOR: E. A. Estes, 12/4/85 | |
1177 | / | |
1178 | / ARGUMENTS: none | |
1179 | / | |
1180 | / RETURN VALUE: location of new energy void space | |
1181 | / | |
1182 | / MODULES CALLED: fread(), fseek() | |
1183 | / | |
1184 | / GLOBAL INPUTS: *Energyvoidfp, Enrgyvoid | |
1185 | / | |
1186 | / GLOBAL OUTPUTS: none | |
1187 | / | |
1188 | / DESCRIPTION: | |
1189 | / Search energy void file for an inactive entry and return its | |
1190 | / location. | |
1191 | / If no inactive ones are found, return one more than last location. | |
1192 | / | |
1193 | /************************************************************************/ | |
1194 | ||
1195 | long | |
1196 | allocvoid() | |
1197 | { | |
1198 | long loc = 0L; /* location of new energy void */ | |
1199 | ||
1200 | fseek(Energyvoidfp, 0L, 0); | |
1201 | while (fread((char *) &Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1) | |
1202 | if (Enrgyvoid.ev_active) | |
1203 | loc += SZ_VOIDSTRUCT; | |
1204 | else | |
1205 | break; | |
1206 | ||
1207 | return(loc); | |
1208 | } |