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