xref: /openbsd/games/phantasia/interplayer.c (revision 010ae45b)
1 /*	$OpenBSD: interplayer.c,v 1.8 2016/01/06 14:28:09 mestre 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 <curses.h>
9 #include <math.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include "macros.h"
15 #include "pathnames.h"
16 #include "phantdefs.h"
17 #include "phantglobs.h"
18 
19 /************************************************************************
20 /
21 / FUNCTION NAME: checkbattle()
22 /
23 / FUNCTION: check to see if current player should battle another
24 /
25 / AUTHOR: E. A. Estes, 12/4/85
26 /
27 / ARGUMENTS: none
28 /
29 / RETURN VALUE: none
30 /
31 / MODULES CALLED: battleplayer(), fread(), fseek()
32 /
33 / GLOBAL INPUTS: Other, Users, Player, Fileloc, *Playersfp
34 /
35 / GLOBAL OUTPUTS: Users
36 /
37 / DESCRIPTION:
38 /	Seach player file for a foe at the same coordinates as the
39 /	current player.
40 /	Also update user count.
41 /
42 *************************************************************************/
43 
44 void
checkbattle(void)45 checkbattle(void)
46 {
47 	long    foeloc = 0L;	/* location in file of person to fight */
48 
49 	Users = 0;
50 	fseek(Playersfp, 0L, SEEK_SET);
51 
52 	while (fread(&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
53 		if (Other.p_status != S_OFF
54 		    && Other.p_status != S_NOTUSED
55 		    && Other.p_status != S_HUNGUP
56 		    && (Other.p_status != S_CLOAKED || Other.p_specialtype != SC_VALAR))
57 			/* player is on and not a cloaked valar */
58 		{
59 			++Users;
60 
61 			if (Player.p_x == Other.p_x
62 			    && Player.p_y == Other.p_y
63 			/* same coordinates */
64 			    && foeloc != Fileloc
65 			/* not self */
66 			    && Player.p_status == S_PLAYING
67 			    && (Other.p_status == S_PLAYING || Other.p_status == S_INBATTLE)
68 			/* both are playing */
69 			    && Other.p_specialtype != SC_VALAR
70 			    && Player.p_specialtype != SC_VALAR)
71 				/* neither is valar */
72 			{
73 				battleplayer(foeloc);
74 				return;
75 			}
76 		}
77 		foeloc += SZ_PLAYERSTRUCT;
78 	}
79 }
80 /**/
81 /************************************************************************
82 /
83 / FUNCTION NAME: battleplayer()
84 /
85 / FUNCTION: inter-terminal battle with another player
86 /
87 / AUTHOR: E. A. Estes, 2/15/86
88 /
89 / ARGUMENTS:
90 /	long foeplace - location in player file of person to battle
91 /
92 / RETURN VALUE: none
93 /
94 / MODULES CALLED: readrecord(), readmessage(), writerecord(), collecttaxes(),
95 /	displaystats(), fabs(), more(), death(), sleep(), wmove(), waddch(), printw(),
96 /	myturn(), altercoordinates(), waddstr(), wrefresh(), mvprintw(),
97 /	getanswer(), wclrtoeol(), wclrtobot()
98 /
99 / GLOBAL INPUTS: Foestrikes, LINES, Lines, Other, Shield, Player, *stdscr,
100 /	Fileloc, *Enemyname
101 /
102 / GLOBAL OUTPUTS: Foestrikes, Lines, Shield, Player, Luckout, *Enemyname
103 /
104 / DESCRIPTION:
105 /	Inter-terminal battle is a very fragile and slightly klugy thing.
106 /	At any time, one player is master and the other is slave.
107 /	We pick who is master first by speed and level.  After that,
108 /	the slave waits for the master to relinquish its turn, and
109 /	the slave becomes master, and so on.
110 /
111 /	The items in the player structure which control the handshake are:
112 /	    p_tampered:
113 /		master increments this to relinquish control
114 /	    p_istat:
115 /		master sets this to specify particular action
116 /	    p_1scratch:
117 /		set to total damage inflicted so far; changes to indicate action
118 /
119 *************************************************************************/
120 
121 void
battleplayer(long foeplace)122 battleplayer(long foeplace)
123 {
124 	double  dtemp;		/* for temporary calculations */
125 	double  oldhits = 0.0;	/* previous damage inflicted by foe */
126 	int     loop;		/* for timing out */
127 	int     ch;		/* input */
128 	short   oldtampered;	/* old value of foe's p_tampered */
129 
130 	Lines = 8;
131 	Luckout = FALSE;
132 	mvaddstr(4, 0, "Preparing for battle!\n");
133 	refresh();
134 
135 	/* set up variables, file, etc. */
136 	Player.p_status = S_INBATTLE;
137 	Shield = Player.p_energy;
138 
139 	/* if p_tampered is not 0, someone else may try to change it (king,
140 	 * etc.) */
141 	Player.p_tampered = oldtampered = 1;
142 	Player.p_1scratch = 0.0;
143 	Player.p_istat = I_OFF;
144 
145 	readrecord(&Other, foeplace);
146 	if (fabs(Player.p_level - Other.p_level) > 20.0)
147 		/* see if players are greatly mismatched */
148 	{
149 		dtemp = (Player.p_level - Other.p_level) / MAX(Player.p_level, Other.p_level);
150 		if (dtemp < -0.5)
151 			/* foe outweighs this one */
152 			Player.p_speed *= 2.0;
153 	}
154 	writerecord(&Player, Fileloc);	/* write out all our info */
155 
156 	if (Player.p_blindness)
157 		Enemyname = "someone";
158 	else
159 		Enemyname = Other.p_name;
160 
161 	mvprintw(6, 0, "You have encountered %s   Level: %.0f\n", Enemyname, Other.p_level);
162 	refresh();
163 
164 	for (loop = 0; Other.p_status != S_INBATTLE && loop < 30; ++loop)
165 		/* wait for foe to respond */
166 	{
167 		readrecord(&Other, foeplace);
168 		sleep(1);
169 	}
170 
171 	if (Other.p_status != S_INBATTLE)
172 		/* foe did not respond */
173 	{
174 		mvprintw(5, 0, "%s is not responding.\n", Enemyname);
175 		goto LEAVE;
176 	}
177 	/* else, we are ready to battle */
178 
179 	move(4, 0);
180 	clrtoeol();
181 
182 	/*
183          * determine who is first master
184          * if neither player is faster, check level
185          * if neither level is greater, battle is not allowed
186          * (this should never happen, but we have to handle it)
187          */
188 	if (Player.p_speed > Other.p_speed)
189 		Foestrikes = FALSE;
190 	else if (Other.p_speed > Player.p_speed)
191 		Foestrikes = TRUE;
192 	else if (Player.p_level > Other.p_level)
193 		Foestrikes = FALSE;
194 	else if (Other.p_level > Player.p_level)
195 		Foestrikes = TRUE;
196 	else {
197 		/* no one is faster */
198 		printw("You can't fight %s yet.", Enemyname);
199 		goto LEAVE;
200 	}
201 
202 	for (;;) {
203 		displaystats();
204 		readmessage();
205 		mvprintw(1, 26, "%20.0f", Shield);	/* overprint energy */
206 
207 		if (!Foestrikes)
208 			/* take action against foe */
209 			myturn();
210 		else
211 			/* wait for foe to take action */
212 		{
213 			mvaddstr(4, 0, "Waiting...\n");
214 			clrtoeol();
215 			refresh();
216 
217 			for (loop = 0; loop < 20; ++loop)
218 				/* wait for foe to act */
219 			{
220 				readrecord(&Other, foeplace);
221 				if (Other.p_1scratch != oldhits)
222 					/* p_1scratch changes to indicate
223 					 * action */
224 					break;
225 				else
226 					/* wait and try again */
227 				{
228 					sleep(1);
229 					addch('.');
230 					refresh();
231 				}
232 			}
233 
234 			if (Other.p_1scratch == oldhits) {
235 				/* timeout */
236 				mvaddstr(22, 0, "Timeout: waiting for response.  Do you want to wait ? ");
237 				ch = getanswer("NY", FALSE);
238 				move(22, 0);
239 				clrtobot();
240 				if (ch == 'Y')
241 					continue;
242 				else
243 					break;
244 			} else
245 				/* foe took action */
246 			{
247 				switch (Other.p_istat) {
248 				case I_RAN:	/* foe ran away */
249 					mvprintw(Lines++, 0, "%s ran away!", Enemyname);
250 					break;
251 
252 				case I_STUCK:	/* foe tried to run, but
253 						 * couldn't */
254 					mvprintw(Lines++, 0, "%s tried to run away.", Enemyname);
255 					break;
256 
257 				case I_BLEWIT:	/* foe tried to luckout, but
258 						 * didn't */
259 					mvprintw(Lines++, 0, "%s tried to luckout!", Enemyname);
260 					break;
261 
262 				default:
263 					dtemp = Other.p_1scratch - oldhits;
264 					mvprintw(Lines++, 0, "%s hit you %.0f times!", Enemyname, dtemp);
265 					Shield -= dtemp;
266 					break;
267 				}
268 
269 				oldhits = Other.p_1scratch;	/* keep track of old
270 								 * hits */
271 
272 				if (Other.p_tampered != oldtampered)
273 					/* p_tampered changes to relinquish
274 					 * turn */
275 				{
276 					oldtampered = Other.p_tampered;
277 					Foestrikes = FALSE;
278 				}
279 			}
280 		}
281 
282 		/* decide what happens next */
283 		refresh();
284 		if (Lines > LINES - 2) {
285 			more(Lines);
286 			move(Lines = 8, 0);
287 			clrtobot();
288 		}
289 		if (Other.p_istat == I_KILLED || Shield < 0.0)
290 			/* we died */
291 		{
292 			Shield = -2.0;	/* insure this value is negative */
293 			break;
294 		}
295 		if (Player.p_istat == I_KILLED)
296 			/* we killed foe; award treasre */
297 		{
298 			mvprintw(Lines++, 0, "You killed %s!", Enemyname);
299 			Player.p_experience += Other.p_experience;
300 			Player.p_crowns += (Player.p_level < 1000.0) ? Other.p_crowns : 0;
301 			Player.p_amulets += Other.p_amulets;
302 			Player.p_charms += Other.p_charms;
303 			collecttaxes(Other.p_gold, Other.p_gems);
304 			Player.p_sword = MAX(Player.p_sword, Other.p_sword);
305 			Player.p_shield = MAX(Player.p_shield, Other.p_shield);
306 			Player.p_quksilver = MAX(Player.p_quksilver, Other.p_quksilver);
307 			if (Other.p_virgin && !Player.p_virgin) {
308 				mvaddstr(Lines++, 0, "You have rescued a virgin.  Will you be honorable ? ");
309 				if ((ch = getanswer("YN", FALSE)) == 'Y')
310 					Player.p_virgin = TRUE;
311 				else {
312 					++Player.p_sin;
313 					Player.p_experience += 8000.0;
314 				}
315 			}
316 			sleep(3);	/* give other person time to die */
317 			break;
318 		} else
319 			if (Player.p_istat == I_RAN || Other.p_istat == I_RAN)
320 				/* either player ran away */
321 				break;
322 	}
323 
324 LEAVE:
325 	/* clean up things and leave */
326 	writerecord(&Player, Fileloc);	/* update a final time */
327 	altercoordinates(0.0, 0.0, A_NEAR);	/* move away from battle site */
328 	Player.p_energy = Shield;	/* set energy to actual value */
329 	Player.p_tampered = T_OFF;	/* clear p_tampered */
330 
331 	more(Lines);		/* pause */
332 
333 	move(4, 0);
334 	clrtobot();		/* clear bottom area of screen */
335 
336 	if (Player.p_energy < 0.0)
337 		/* we are dead */
338 		death("Interterminal battle");
339 }
340 /**/
341 /************************************************************************
342 /
343 / FUNCTION NAME: myturn()
344 /
345 / FUNCTION: process players action against foe in battle
346 /
347 / AUTHOR: E. A. Estes, 2/7/86
348 /
349 / ARGUMENTS: none
350 /
351 / RETURN VALUE: none
352 /
353 / MODULES CALLED: writerecord(), inputoption(), floor(), wmove(), drandom(),
354 /	waddstr(), wrefresh(), mvprintw(), wclrtoeol(), wclrtobot()
355 /
356 / GLOBAL INPUTS: Lines, Other, Player, *stdscr, Fileloc, Luckout,
357 /	*Enemyname
358 /
359 / GLOBAL OUTPUTS: Foestrikes, Lines, Player, Luckout
360 /
361 / DESCRIPTION:
362 /	Take action action against foe, and decide who is master
363 /	for next iteration.
364 /
365 *************************************************************************/
366 
367 void
myturn(void)368 myturn(void)
369 {
370 	double  dtemp;		/* for temporary calculations */
371 	int     ch;		/* input */
372 
373 	mvaddstr(7, 0, "1:Fight  2:Run Away!  3:Power Blast  ");
374 	if (Luckout)
375 		clrtoeol();
376 	else
377 		addstr("4:Luckout  ");
378 
379 	ch = inputoption();
380 	move(Lines = 8, 0);
381 	clrtobot();
382 
383 	switch (ch) {
384 	default:		/* fight */
385 		dtemp = ROLL(2.0, Player.p_might);
386 HIT:
387 		mvprintw(Lines++, 0, "You hit %s %.0f times!", Enemyname, dtemp);
388 		Player.p_sin += 0.5;
389 		Player.p_1scratch += dtemp;
390 		Player.p_istat = I_OFF;
391 		break;
392 
393 	case '2':		/* run away */
394 		Player.p_1scratch -= 1.0;	/* change this to indicate
395 						 * action */
396 		if (drandom() > 0.25) {
397 			mvaddstr(Lines++, 0, "You got away!");
398 			Player.p_istat = I_RAN;
399 		} else {
400 			mvprintw(Lines++, 0, "%s is still after you!", Enemyname);
401 			Player.p_istat = I_STUCK;
402 		}
403 		break;
404 
405 	case '3':		/* power blast */
406 		dtemp = MIN(Player.p_mana, Player.p_level * 5.0);
407 		Player.p_mana -= dtemp;
408 		dtemp *= (drandom() + 0.5) * Player.p_magiclvl * 0.2 + 2.0;
409 		mvprintw(Lines++, 0, "You blasted %s !", Enemyname);
410 		goto HIT;
411 
412 	case '4':		/* luckout */
413 		if (Luckout || drandom() > 0.1) {
414 			if (Luckout)
415 				mvaddstr(Lines++, 0, "You already tried that!");
416 			else {
417 				mvaddstr(Lines++, 0, "Not this time . . .");
418 				Luckout = TRUE;
419 			}
420 
421 			Player.p_1scratch -= 1.0;
422 			Player.p_istat = I_BLEWIT;
423 		} else {
424 			mvaddstr(Lines++, 0, "You just lucked out!");
425 			Player.p_1scratch = Other.p_energy * 1.1;
426 		}
427 		break;
428 	}
429 
430 	refresh();
431 	Player.p_1scratch = floor(Player.p_1scratch);	/* clean up any mess */
432 
433 	if (Player.p_1scratch > Other.p_energy)
434 		Player.p_istat = I_KILLED;
435 	else
436 		if (drandom() * Player.p_speed < drandom() * Other.p_speed)
437 			/* relinquish control */
438 		{
439 			++Player.p_tampered;
440 			Foestrikes = TRUE;
441 		}
442 	writerecord(&Player, Fileloc);	/* let foe know what we did */
443 }
444 /**/
445 /************************************************************************
446 /
447 / FUNCTION NAME: checktampered()
448 /
449 / FUNCTION: check if current player has been tampered with
450 /
451 / AUTHOR: E. A. Estes, 12/4/85
452 /
453 / ARGUMENTS: none
454 /
455 / RETURN VALUE: none
456 /
457 / MODULES CALLED: readrecord(), fread(), fseek(), tampered(), writevoid()
458 /
459 / GLOBAL INPUTS: *Energyvoidfp, Other, Player, Fileloc, Enrgyvoid
460 /
461 / GLOBAL OUTPUTS: Enrgyvoid
462 /
463 / DESCRIPTION:
464 /	Check for energy voids, holy grail, and tampering by other
465 /	players.
466 /
467 *************************************************************************/
468 
469 void
checktampered(void)470 checktampered(void)
471 {
472 	long    loc = 0L;	/* location in energy void file */
473 
474 	/* first check for energy voids */
475 	fseek(Energyvoidfp, 0L, SEEK_SET);
476 	while (fread(&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
477 		if (Enrgyvoid.ev_active
478 		    && Enrgyvoid.ev_x == Player.p_x
479 		    && Enrgyvoid.ev_y == Player.p_y)
480 			/* sitting on one */
481 		{
482 			if (loc > 0L)
483 				/* not the holy grail; inactivate energy void */
484 			{
485 				Enrgyvoid.ev_active = FALSE;
486 				writevoid(&Enrgyvoid, loc);
487 				tampered(T_NRGVOID, 0.0, 0.0);
488 			} else
489 				if (Player.p_status != S_CLOAKED)
490 					/* holy grail */
491 					tampered(T_GRAIL, 0.0, 0.0);
492 			break;
493 		} else
494 			loc += SZ_VOIDSTRUCT;
495 
496 	/* now check for other things */
497 	readrecord(&Other, Fileloc);
498 	if (Other.p_tampered != T_OFF)
499 		tampered(Other.p_tampered, Other.p_1scratch, Other.p_2scratch);
500 }
501 /**/
502 /************************************************************************
503 /
504 / FUNCTION NAME: tampered()
505 /
506 / FUNCTION: take care of tampering by other players
507 /
508 / AUTHOR: E. A. Estes, 12/4/85
509 /
510 / ARGUMENTS:
511 /	int what - what type of tampering
512 /	double arg1, arg2 - rest of tampering info
513 /
514 / RETURN VALUE: none
515 /
516 / MODULES CALLED: writerecord(), more(), fread(), death(), fseek(), sleep(),
517 /	floor(), wmove(), waddch(), drandom(), printw(), altercoordinates(),
518 /	waddstr(), wrefresh(), encounter(), writevoid()
519 /
520 / GLOBAL INPUTS: Other, Player, *stdscr, Enrgyvoid, *Playersfp
521 /
522 / GLOBAL OUTPUTS: Other, Player, Changed, Enrgyvoid
523 /
524 / DESCRIPTION:
525 /	Take care of energy voids, holy grail, decree and intervention
526 /	action on current player.
527 /
528 *************************************************************************/
529 
530 void
tampered(int what,double arg1,double arg2)531 tampered(int what, double arg1, double arg2)
532 {
533 	long    loc;		/* location in file of other players */
534 
535 	Changed = TRUE;
536 	move(4, 0);
537 
538 	Player.p_tampered = T_OFF;	/* no longer tampered with */
539 
540 	switch (what) {
541 	case T_NRGVOID:
542 		addstr("You've hit an energy void !\n");
543 		Player.p_mana /= 3.0;
544 		Player.p_energy /= 2.0;
545 		Player.p_gold = floor(Player.p_gold / 1.25) + 0.1;
546 		altercoordinates(0.0, 0.0, A_NEAR);
547 		break;
548 
549 	case T_TRANSPORT:
550 		addstr("The king transported you !  ");
551 		if (Player.p_charms > 0) {
552 			addstr("But your charm saved you. . .\n");
553 			--Player.p_charms;
554 		} else {
555 			altercoordinates(0.0, 0.0, A_FAR);
556 			addch('\n');
557 		}
558 		break;
559 
560 	case T_BESTOW:
561 		printw("The king has bestowed %.0f gold pieces on you !\n", arg1);
562 		Player.p_gold += arg1;
563 		break;
564 
565 	case T_CURSED:
566 		addstr("You've been cursed !  ");
567 		if (Player.p_blessing) {
568 			addstr("But your blessing saved you. . .\n");
569 			Player.p_blessing = FALSE;
570 		} else {
571 			addch('\n');
572 			Player.p_poison += 2.0;
573 			Player.p_energy = 10.0;
574 			Player.p_maxenergy *= 0.95;
575 			Player.p_status = S_PLAYING;	/* no longer cloaked */
576 		}
577 		break;
578 
579 	case T_VAPORIZED:
580 		addstr("You have been vaporized!\n");
581 		more(7);
582 		death("Vaporization");
583 		break;
584 
585 	case T_MONSTER:
586 		addstr("The Valar zapped you with a monster!\n");
587 		more(7);
588 		encounter((int) arg1);
589 		return;
590 
591 	case T_BLESSED:
592 		addstr("The Valar has blessed you!\n");
593 		Player.p_energy = (Player.p_maxenergy *= 1.05) + Player.p_shield;
594 		Player.p_mana += 500.0;
595 		Player.p_strength += 0.5;
596 		Player.p_brains += 0.5;
597 		Player.p_magiclvl += 0.5;
598 		Player.p_poison = MIN(0.5, Player.p_poison);
599 		break;
600 
601 	case T_RELOCATE:
602 		addstr("You've been relocated. . .\n");
603 		altercoordinates(arg1, arg2, A_FORCED);
604 		break;
605 
606 	case T_HEAL:
607 		addstr("You've been healed!\n");
608 		Player.p_poison -= 0.25;
609 		Player.p_energy = Player.p_maxenergy + Player.p_shield;
610 		break;
611 
612 	case T_EXVALAR:
613 		addstr("You are no longer Valar!\n");
614 		Player.p_specialtype = SC_COUNCIL;
615 		break;
616 
617 	case T_GRAIL:
618 		addstr("You have found The Holy Grail!!\n");
619 		if (Player.p_specialtype < SC_COUNCIL)
620 			/* must be council of wise to behold grail */
621 		{
622 			addstr("However, you are not experienced enough to behold it.\n");
623 			Player.p_sin *= Player.p_sin;
624 			Player.p_mana += 1000;
625 		} else
626 			if (Player.p_specialtype == SC_VALAR
627 			    || Player.p_specialtype == SC_EXVALAR) {
628 				addstr("You have made it to the position of Valar once already.\n");
629 				addstr("The Grail is of no more use to you now.\n");
630 			} else {
631 				addstr("It is now time to see if you are worthy to behold it. . .\n");
632 				refresh();
633 				sleep(4);
634 
635 				if (drandom() / 2.0 < Player.p_sin) {
636 					addstr("You have failed!\n");
637 					Player.p_strength =
638 					    Player.p_mana =
639 					    Player.p_energy =
640 					    Player.p_maxenergy =
641 					    Player.p_magiclvl =
642 					    Player.p_brains =
643 					    Player.p_experience =
644 					    Player.p_quickness = 1.0;
645 
646 					altercoordinates(1.0, 1.0, A_FORCED);
647 					Player.p_level = 0.0;
648 				} else {
649 					addstr("You made to position of Valar!\n");
650 					Player.p_specialtype = SC_VALAR;
651 					Player.p_lives = 5;
652 					fseek(Playersfp, 0L, SEEK_SET);
653 					loc = 0L;
654 					while (fread(&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
655 						/* search for existing valar */
656 						if (Other.p_specialtype == SC_VALAR
657 						    && Other.p_status != S_NOTUSED)
658 							/* found old valar */
659 						{
660 							Other.p_tampered = T_EXVALAR;
661 							writerecord(&Other, loc);
662 							break;
663 						} else
664 							loc += SZ_PLAYERSTRUCT;
665 				}
666 			}
667 
668 		/* move grail to new location */
669 		Enrgyvoid.ev_active = TRUE;
670 		Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6);
671 		Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6);
672 		writevoid(&Enrgyvoid, 0L);
673 		break;
674 	}
675 	refresh();
676 	sleep(2);
677 }
678 /**/
679 /************************************************************************
680 /
681 / FUNCTION NAME: userlist()
682 /
683 / FUNCTION: print list of players and locations
684 /
685 / AUTHOR: E. A. Estes, 2/28/86
686 /
687 / ARGUMENTS:
688 /	bool ingameflag - set if called while playing
689 /
690 / RETURN VALUE: none
691 /
692 / MODULES CALLED: descrstatus(), descrlocation(), more(), fread(), fseek(),
693 /	floor(), wmove(), printw(), waddstr(), distance(), wrefresh(),
694 /	descrtype(), wclrtobot()
695 /
696 / GLOBAL INPUTS: LINES, Other, Circle, Wizard, Player, *stdscr, *Playersfp
697 /
698 / GLOBAL OUTPUTS: none
699 /
700 / DESCRIPTION:
701 /	We can only see the coordinate of those closer to the origin
702 /	from us.
703 /	Kings and council of the wise can see and can be seen by everyone.
704 /	Palantirs are good for seeing everyone; and the valar can use
705 /	one to see through a 'cloak' spell.
706 /	The valar has no coordinates, and is completely invisible if
707 /	cloaked.
708 /
709 *************************************************************************/
710 
711 void
userlist(bool ingameflag)712 userlist(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(&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
throneroom(void)802 throneroom(void)
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(&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(&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp);
848 		fp = fopen(_PATH_VOID, "w");
849 		fwrite(&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
dotampered(void)883 dotampered(void)
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(&temp1, sizeof(double), 1, fp);
948 				fseek(fp, 0L, SEEK_SET);
949 				/* clear out value */
950 				temp2 = 0.0;
951 				fwrite(&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(&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
writevoid(struct energyvoid * vp,long loc)1115 writevoid(struct energyvoid *vp, long loc)
1116 {
1117 
1118 	fseek(Energyvoidfp, loc, SEEK_SET);
1119 	fwrite(vp, SZ_VOIDSTRUCT, 1, Energyvoidfp);
1120 	fflush(Energyvoidfp);
1121 	fseek(Energyvoidfp, 0L, SEEK_SET);
1122 }
1123 /**/
1124 /************************************************************************
1125 /
1126 / FUNCTION NAME: allocvoid()
1127 /
1128 / FUNCTION: allocate space for a new energy void
1129 /
1130 / AUTHOR: E. A. Estes, 12/4/85
1131 /
1132 / ARGUMENTS: none
1133 /
1134 / RETURN VALUE: location of new energy void space
1135 /
1136 / MODULES CALLED: fread(), fseek()
1137 /
1138 / GLOBAL INPUTS: *Energyvoidfp, Enrgyvoid
1139 /
1140 / GLOBAL OUTPUTS: none
1141 /
1142 / DESCRIPTION:
1143 /	Search energy void file for an inactive entry and return its
1144 /	location.
1145 /	If no inactive ones are found, return one more than last location.
1146 /
1147 *************************************************************************/
1148 
1149 long
allocvoid(void)1150 allocvoid(void)
1151 {
1152 	long    loc = 0L;	/* location of new energy void */
1153 
1154 	fseek(Energyvoidfp, 0L, SEEK_SET);
1155 	while (fread(&Enrgyvoid, SZ_VOIDSTRUCT, 1, Energyvoidfp) == 1)
1156 		if (Enrgyvoid.ev_active)
1157 			loc += SZ_VOIDSTRUCT;
1158 		else
1159 			break;
1160 
1161 	return (loc);
1162 }
1163