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