xref: /netbsd-src/games/phantasia/gamesupport.c (revision e28fc9086cd7f59ab0a7363c8a37303b5a0d04a0)
1 /*	$NetBSD: gamesupport.c,v 1.11 2009/08/31 08:27:16 dholland Exp $	*/
2 
3 /*
4  * gamesupport.c - auxiliary routines for support of Phantasia
5  */
6 
7 #include <setjmp.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <time.h>
11 
12 #include "phantdefs.h"
13 #include "phantstruct.h"
14 #include "phantglobs.h"
15 #include "pathnames.h"
16 
17 #undef bool
18 #include <curses.h>
19 
20 void
changestats(phbool ingameflag)21 changestats(phbool ingameflag)
22 {
23 	static char flag[2] =	/* for printing values of bools */
24 	{'F', 'T'};
25 	struct player *playerp;	/* pointer to structure to alter */
26 	const char   *prompt;		/* pointer to prompt string */
27 	int     c;		/* input */
28 	int     today;		/* day of year of today */
29 	int     temp;		/* temporary variable */
30 	long    loc;		/* location in player file */
31 	time_t  now;		/* time now */
32 	double  dtemp;		/* temporary variable */
33 	phbool *bptr;		/* pointer to bool item to change */
34 	double *dptr;		/* pointer to double item to change */
35 	short  *sptr;		/* pointer to short item to change */
36 
37 	clear();
38 
39 	for (;;)
40 		/* get name of player to examine/alter */
41 	{
42 		mvaddstr(5, 0, "Which character do you want to look at ? ");
43 		getstring(Databuf, SZ_DATABUF);
44 		truncstring(Databuf);
45 
46 		if (Databuf[0] == '\0')
47 			userlist(ingameflag);
48 		else
49 			break;
50 	}
51 
52 	loc = -1L;
53 
54 	if (!ingameflag)
55 		/* use 'Player' structure */
56 		playerp = &Player;
57 	else
58 		if (strcmp(Databuf, Player.p_name) == 0)
59 			/* alter/examine current player */
60 		{
61 			playerp = &Player;
62 			loc = Fileloc;
63 		} else
64 			/* use 'Other' structure */
65 			playerp = &Other;
66 
67 	/* find player on file */
68 	if (loc < 0L && (loc = findname(Databuf, playerp)) < 0L)
69 		/* didn't find player */
70 	{
71 		clear();
72 		mvaddstr(11, 0, "Not found.");
73 		return;
74 	}
75 	time(&now);
76 	today = localtime(&now)->tm_yday;
77 
78 	clear();
79 
80 	for (;;)
81 		/* print player structure, and prompt for action */
82 	{
83 		mvprintw(0, 0, "A:Name         %s\n", playerp->p_name);
84 
85 		if (Wizard)
86 			printw("B:Password     %s\n", playerp->p_password);
87 		else
88 			addstr("B:Password     XXXXXXXX\n");
89 
90 		printw(" :Login        %s\n", playerp->p_login);
91 
92 		printw("C:Experience   %.0f\n", playerp->p_experience);
93 		printw("D:Level        %.0f\n", playerp->p_level);
94 		printw("E:Strength     %.0f\n", playerp->p_strength);
95 		printw("F:Sword        %.0f\n", playerp->p_sword);
96 		printw(" :Might        %.0f\n", playerp->p_might);
97 		printw("G:Energy       %.0f\n", playerp->p_energy);
98 		printw("H:Max-Energy   %.0f\n", playerp->p_maxenergy);
99 		printw("I:Shield       %.0f\n", playerp->p_shield);
100 		printw("J:Quickness    %.0f\n", playerp->p_quickness);
101 		printw("K:Quicksilver  %.0f\n", playerp->p_quksilver);
102 		printw(" :Speed        %.0f\n", playerp->p_speed);
103 		printw("L:Magic Level  %.0f\n", playerp->p_magiclvl);
104 		printw("M:Mana         %.0f\n", playerp->p_mana);
105 		printw("N:Brains       %.0f\n", playerp->p_brains);
106 
107 		if (Wizard || playerp->p_specialtype != SC_VALAR)
108 			mvaddstr(0, 40, descrstatus(playerp));
109 
110 		mvprintw(1, 40, "O:Poison       %0.3f\n", playerp->p_poison);
111 		mvprintw(2, 40, "P:Gold         %.0f\n", playerp->p_gold);
112 		mvprintw(3, 40, "Q:Gem          %.0f\n", playerp->p_gems);
113 		mvprintw(4, 40, "R:Sin          %0.3f\n", playerp->p_sin);
114 		if (Wizard) {
115 			mvprintw(5, 40, "S:X-coord      %.0f\n", playerp->p_x);
116 			mvprintw(6, 40, "T:Y-coord      %.0f\n", playerp->p_y);
117 		} else {
118 			mvaddstr(5, 40, "S:X-coord      ?\n");
119 			mvaddstr(6, 40, "T:Y-coord      ?\n");
120 		}
121 
122 		mvprintw(7, 40, "U:Age          %ld\n", playerp->p_age);
123 		mvprintw(8, 40, "V:Degenerated  %d\n", playerp->p_degenerated);
124 
125 		mvprintw(9, 40, "W:Type         %d (%s)\n",
126 		    playerp->p_type, descrtype(playerp, FALSE) + 1);
127 		mvprintw(10, 40, "X:Special Type %d\n", playerp->p_specialtype);
128 		mvprintw(11, 40, "Y:Lives        %d\n", playerp->p_lives);
129 		mvprintw(12, 40, "Z:Crowns       %d\n", playerp->p_crowns);
130 		mvprintw(13, 40, "0:Charms       %d\n", playerp->p_charms);
131 		mvprintw(14, 40, "1:Amulets      %d\n", playerp->p_amulets);
132 		mvprintw(15, 40, "2:Holy Water   %d\n", playerp->p_holywater);
133 
134 		temp = today - playerp->p_lastused;
135 		if (temp < 0)
136 			/* last year */
137 			temp += 365;
138 		mvprintw(16, 40, "3:Lastused     %d  (%d)\n", playerp->p_lastused, temp);
139 
140 		mvprintw(18, 8, "4:Palantir %c  5:Blessing %c  6:Virgin %c  7:Blind %c",
141 		    flag[(int)playerp->p_palantir],
142 		    flag[(int)playerp->p_blessing],
143 		    flag[(int)playerp->p_virgin],
144 		    flag[(int)playerp->p_blindness]);
145 
146 		if (!Wizard)
147 			mvprintw(19, 8, "8:Ring    %c",
148 			    flag[playerp->p_ring.ring_type != R_NONE]);
149 		else
150 			mvprintw(19, 8, "8:Ring    %d  9:Duration %d",
151 			    playerp->p_ring.ring_type, playerp->p_ring.ring_duration);
152 
153 		if (!Wizard
154 		/* not wizard */
155 		    && (ingameflag || strcmp(Login, playerp->p_login) != 0))
156 			/* in game or not examining own character */
157 		{
158 			if (ingameflag) {
159 				more(LINES - 1);
160 				clear();
161 				return;
162 			} else
163 				cleanup(TRUE);
164 			/* NOTREACHED */
165 		}
166 		mvaddstr(20, 0, "!:Quit       ?:Delete");
167 		mvaddstr(21, 0, "What would you like to change ? ");
168 
169 		if (Wizard)
170 			c = getanswer(" ", TRUE);
171 		else
172 			/* examining own player; allow to change name and
173 			 * password */
174 			c = getanswer("!BA", FALSE);
175 
176 		switch (c) {
177 		case 'A':	/* change name */
178 		case 'B':	/* change password */
179 			if (!Wizard)
180 				/* prompt for password */
181 			{
182 				mvaddstr(23, 0, "Password ? ");
183 				Echo = FALSE;
184 				getstring(Databuf, 9);
185 				Echo = TRUE;
186 				if (strcmp(Databuf, playerp->p_password) != 0)
187 					continue;
188 			}
189 			if (c == 'A')
190 				/* get new name */
191 			{
192 				mvaddstr(23, 0, "New name: ");
193 				getstring(Databuf, SZ_NAME);
194 				truncstring(Databuf);
195 				if (Databuf[0] != '\0')
196 					if (Wizard || findname(Databuf, &Other) < 0L)
197 						strcpy(playerp->p_name, Databuf);
198 			} else
199 				/* get new password */
200 			{
201 				if (!Wizard)
202 					Echo = FALSE;
203 
204 				do
205 					/* get two copies of new password
206 					 * until they match */
207 				{
208 					/* get first copy */
209 					mvaddstr(23, 0, "New password ? ");
210 					getstring(Databuf, SZ_PASSWORD);
211 					if (Databuf[0] == '\0')
212 						break;
213 
214 					/* get second copy */
215 					mvaddstr(23, 0, "One more time ? ");
216 					getstring(playerp->p_password, SZ_PASSWORD);
217 				}
218 				while (strcmp(playerp->p_password, Databuf) != 0);
219 
220 				Echo = TRUE;
221 			}
222 
223 			continue;
224 
225 		case 'C':	/* change experience */
226 			prompt = "experience";
227 			dptr = &playerp->p_experience;
228 			goto DALTER;
229 
230 		case 'D':	/* change level */
231 			prompt = "level";
232 			dptr = &playerp->p_level;
233 			goto DALTER;
234 
235 		case 'E':	/* change strength */
236 			prompt = "strength";
237 			dptr = &playerp->p_strength;
238 			goto DALTER;
239 
240 		case 'F':	/* change swords */
241 			prompt = "sword";
242 			dptr = &playerp->p_sword;
243 			goto DALTER;
244 
245 		case 'G':	/* change energy */
246 			prompt = "energy";
247 			dptr = &playerp->p_energy;
248 			goto DALTER;
249 
250 		case 'H':	/* change maximum energy */
251 			prompt = "max energy";
252 			dptr = &playerp->p_maxenergy;
253 			goto DALTER;
254 
255 		case 'I':	/* change shields */
256 			prompt = "shield";
257 			dptr = &playerp->p_shield;
258 			goto DALTER;
259 
260 		case 'J':	/* change quickness */
261 			prompt = "quickness";
262 			dptr = &playerp->p_quickness;
263 			goto DALTER;
264 
265 		case 'K':	/* change quicksilver */
266 			prompt = "quicksilver";
267 			dptr = &playerp->p_quksilver;
268 			goto DALTER;
269 
270 		case 'L':	/* change magic */
271 			prompt = "magic level";
272 			dptr = &playerp->p_magiclvl;
273 			goto DALTER;
274 
275 		case 'M':	/* change mana */
276 			prompt = "mana";
277 			dptr = &playerp->p_mana;
278 			goto DALTER;
279 
280 		case 'N':	/* change brains */
281 			prompt = "brains";
282 			dptr = &playerp->p_brains;
283 			goto DALTER;
284 
285 		case 'O':	/* change poison */
286 			prompt = "poison";
287 			dptr = &playerp->p_poison;
288 			goto DALTER;
289 
290 		case 'P':	/* change gold */
291 			prompt = "gold";
292 			dptr = &playerp->p_gold;
293 			goto DALTER;
294 
295 		case 'Q':	/* change gems */
296 			prompt = "gems";
297 			dptr = &playerp->p_gems;
298 			goto DALTER;
299 
300 		case 'R':	/* change sin */
301 			prompt = "sin";
302 			dptr = &playerp->p_sin;
303 			goto DALTER;
304 
305 		case 'S':	/* change x coord */
306 			prompt = "x";
307 			dptr = &playerp->p_x;
308 			goto DALTER;
309 
310 		case 'T':	/* change y coord */
311 			prompt = "y";
312 			dptr = &playerp->p_y;
313 			goto DALTER;
314 
315 		case 'U':	/* change age */
316 			mvprintw(23, 0, "age = %ld; age = ", playerp->p_age);
317 			dtemp = infloat();
318 			if (dtemp != 0.0)
319 				playerp->p_age = (long) dtemp;
320 			continue;
321 
322 		case 'V':	/* change degen */
323 			mvprintw(23, 0, "degen = %d; degen = ", playerp->p_degenerated);
324 			dtemp = infloat();
325 			if (dtemp != 0.0)
326 				playerp->p_degenerated = (int) dtemp;
327 			continue;
328 
329 		case 'W':	/* change type */
330 			prompt = "type";
331 			sptr = &playerp->p_type;
332 			goto SALTER;
333 
334 		case 'X':	/* change special type */
335 			prompt = "special type";
336 			sptr = &playerp->p_specialtype;
337 			goto SALTER;
338 
339 		case 'Y':	/* change lives */
340 			prompt = "lives";
341 			sptr = &playerp->p_lives;
342 			goto SALTER;
343 
344 		case 'Z':	/* change crowns */
345 			prompt = "crowns";
346 			sptr = &playerp->p_crowns;
347 			goto SALTER;
348 
349 		case '0':	/* change charms */
350 			prompt = "charm";
351 			sptr = &playerp->p_charms;
352 			goto SALTER;
353 
354 		case '1':	/* change amulet */
355 			prompt = "amulet";
356 			sptr = &playerp->p_amulets;
357 			goto SALTER;
358 
359 		case '2':	/* change holy water */
360 			prompt = "holy water";
361 			sptr = &playerp->p_holywater;
362 			goto SALTER;
363 
364 		case '3':	/* change last-used */
365 			prompt = "last-used";
366 			sptr = &playerp->p_lastused;
367 			goto SALTER;
368 
369 		case '4':	/* change palantir */
370 			prompt = "palantir";
371 			bptr = &playerp->p_palantir;
372 			goto BALTER;
373 
374 		case '5':	/* change blessing */
375 			prompt = "blessing";
376 			bptr = &playerp->p_blessing;
377 			goto BALTER;
378 
379 		case '6':	/* change virgin */
380 			prompt = "virgin";
381 			bptr = &playerp->p_virgin;
382 			goto BALTER;
383 
384 		case '7':	/* change blindness */
385 			prompt = "blindness";
386 			bptr = &playerp->p_blindness;
387 			goto BALTER;
388 
389 		case '8':	/* change ring type */
390 			prompt = "ring-type";
391 			sptr = &playerp->p_ring.ring_type;
392 			goto SALTER;
393 
394 		case '9':	/* change ring duration */
395 			prompt = "ring-duration";
396 			sptr = &playerp->p_ring.ring_duration;
397 			goto SALTER;
398 
399 		case '!':	/* quit, update */
400 			if (Wizard &&
401 			    (!ingameflag || playerp != &Player))
402 				/* turn off status if not modifying self */
403 			{
404 				playerp->p_status = S_OFF;
405 				playerp->p_tampered = T_OFF;
406 			}
407 			writerecord(playerp, loc);
408 			clear();
409 			return;
410 
411 		case '?':	/* delete player */
412 			if (ingameflag && playerp == &Player)
413 				/* cannot delete self */
414 				continue;
415 
416 			freerecord(playerp, loc);
417 			clear();
418 			return;
419 
420 		default:
421 			continue;
422 		}
423 DALTER:
424 		mvprintw(23, 0, "%s = %f; %s = ", prompt, *dptr, prompt);
425 		dtemp = infloat();
426 		if (dtemp != 0.0)
427 			*dptr = dtemp;
428 		continue;
429 
430 SALTER:
431 		mvprintw(23, 0, "%s = %d; %s = ", prompt, *sptr, prompt);
432 		dtemp = infloat();
433 		if (dtemp != 0.0)
434 			*sptr = (short) dtemp;
435 		continue;
436 
437 BALTER:
438 		mvprintw(23, 0, "%s = %c; %s = ", prompt, flag[(int)*bptr],
439 		    prompt);
440 		c = getanswer("\nTF", TRUE);
441 		if (c == 'T')
442 			*bptr = TRUE;
443 		else
444 			if (c == 'F')
445 				*bptr = FALSE;
446 		continue;
447 	}
448 }
449 
450 void
monstlist(void)451 monstlist(void)
452 {
453 	int     count = 0;	/* count in file */
454 
455 	puts(" #)  Name                 Str  Brain  Quick  Energy  Exper  Treas  Type  Flock%\n");
456 	fseek(Monstfp, 0L, SEEK_SET);
457 	while (fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp) == 1)
458 		printf("%2d)  %-20.20s%4.0f   %4.0f     %2.0f   %5.0f  %5.0f     %2d    %2d     %3.0f\n", count++,
459 		    Curmonster.m_name, Curmonster.m_strength, Curmonster.m_brains,
460 		    Curmonster.m_speed, Curmonster.m_energy, Curmonster.m_experience,
461 		    Curmonster.m_treasuretype, Curmonster.m_type, Curmonster.m_flock);
462 }
463 
464 void
scorelist(void)465 scorelist(void)
466 {
467 	struct scoreboard sbuf;	/* for reading entries */
468 	FILE   *fp;		/* to open the file */
469 
470 	if ((fp = fopen(_PATH_SCORE, "r")) != NULL) {
471 		while (fread((char *) &sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
472 			printf("%-20s   (%-9s)  Level: %6.0f  Type: %s\n",
473 			    sbuf.sb_name, sbuf.sb_login, sbuf.sb_level, sbuf.sb_type);
474 		fclose(fp);
475 	}
476 }
477 
478 void
activelist(void)479 activelist(void)
480 {
481 	fseek(Playersfp, 0L, SEEK_SET);
482 	printf("Current characters on file are:\n\n");
483 
484 	while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
485 		if (Other.p_status != S_NOTUSED)
486 			printf("%-20s   (%-9s)  Level: %6.0f  %s  (%s)\n",
487 			    Other.p_name, Other.p_login, Other.p_level,
488 			    descrtype(&Other, FALSE), descrstatus(&Other));
489 
490 }
491 
492 void
purgeoldplayers(void)493 purgeoldplayers(void)
494 {
495 	int     today;		/* day of year for today */
496 	int     daysold;	/* how many days since the character has been
497 				 * used */
498 	time_t  ltime;		/* time in seconds */
499 	long    loc = 0L;	/* location in file */
500 
501 	time(&ltime);
502 	today = localtime(&ltime)->tm_yday;
503 
504 	for (;;) {
505 		fseek(Playersfp, loc, SEEK_SET);
506 		if (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) != 1)
507 			break;
508 
509 		daysold = today - Other.p_lastused;
510 		if (daysold < 0)
511 			daysold += 365;
512 
513 		if (daysold > N_DAYSOLD)
514 			/* player hasn't been used in a while; delete */
515 			freerecord(&Other, loc);
516 
517 		loc += SZ_PLAYERSTRUCT;
518 	}
519 }
520 
521 void
enterscore(void)522 enterscore(void)
523 {
524 	struct scoreboard sbuf;	/* buffer to read in scoreboard entries */
525 	FILE   *fp;		/* to open scoreboard file */
526 	long    loc = 0L;	/* location in scoreboard file */
527 	bool    found = FALSE;	/* set if we found an entry for this login */
528 
529 	if ((fp = fopen(_PATH_SCORE, "r+")) != NULL) {
530 		while (fread((char *) &sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
531 			if (strcmp(Player.p_login, sbuf.sb_login) == 0) {
532 				found = TRUE;
533 				break;
534 			} else
535 				loc += SZ_SCORESTRUCT;
536 	} else {
537 		error(_PATH_SCORE);
538 		/* NOTREACHED */
539 	}
540 
541 	/*
542          * At this point, 'loc' will either indicate a point beyond
543          * the end of file, or the place where the previous entry
544          * was found.
545          */
546 
547 	if ((!found) || Player.p_level > sbuf.sb_level)
548 		/* put new entry in for this login */
549 	{
550 		strcpy(sbuf.sb_login, Player.p_login);
551 		strcpy(sbuf.sb_name, Player.p_name);
552 		sbuf.sb_level = Player.p_level;
553 		strcpy(sbuf.sb_type, descrtype(&Player, TRUE));
554 	}
555 	/* update entry */
556 	fseek(fp, loc, SEEK_SET);
557 	fwrite((char *) &sbuf, SZ_SCORESTRUCT, 1, fp);
558 	fclose(fp);
559 }
560