xref: /openbsd/games/phantasia/gamesupport.c (revision 898184e3)
1 /*	$OpenBSD: gamesupport.c,v 1.7 2010/12/15 06:40:39 tedu Exp $	*/
2 /*	$NetBSD: gamesupport.c,v 1.3 1995/04/24 12:24:28 cgd Exp $	*/
3 
4 /*
5  * gamesupport.c - auxiliary routines for support of Phantasia
6  */
7 
8 #include "include.h"
9 
10 /************************************************************************
11 /
12 / FUNCTION NAME: changestats()
13 /
14 / FUNCTION: examine/change statistics for a player
15 /
16 / AUTHOR: E. A. Estes, 12/4/85
17 /
18 / ARGUMENTS:
19 /	bool ingameflag - set if called while playing game (Wizard only)
20 /
21 / RETURN VALUE: none
22 /
23 / MODULES CALLED: freerecord(), writerecord(), descrstatus(), truncstring(),
24 /	time(), more(), wmove(), wclear(), strcmp(), printw(), strlcpy(),
25 /	infloat(), waddstr(), cleanup(), findname(), userlist(), mvprintw(),
26 /	localtime(), getanswer(), descrtype(), getstring()
27 /
28 / GLOBAL INPUTS: LINES, *Login, Other, Wizard, Player, *stdscr, Databuf[],
29 /	Fileloc
30 /
31 / GLOBAL OUTPUTS: Echo
32 /
33 / DESCRIPTION:
34 /	Prompt for player name to examine/change.
35 /	If the name is NULL, print a list of all players.
36 /	If we are called from within the game, check for the
37 /	desired name being the same as the current player's name.
38 /	Only the 'Wizard' may alter players.
39 /	Items are changed only if a non-zero value is specified.
40 /	To change an item to 0, use 0.1; it will be truncated later.
41 /
42 /	Players may alter their names and passwords, if the following
43 /	are true:
44 /	    - current login matches the character's logins
45 /	    - the password is known
46 /	    - the player is not in the middle of the game (ingameflag == FALSE)
47 /
48 /	The last condition is imposed for two reasons:
49 /	    - the game could possibly get a bit hectic if a player were
50 /	      continually changing his/her name
51 /	    - another player structure would be necessary to check for names
52 /	      already in use
53 /
54 *************************************************************************/
55 
56 void
57 changestats(ingameflag)
58 	bool    ingameflag;
59 {
60 	static char flag[2] =	/* for printing values of bools */
61 	{'F', 'T'};
62 	struct player *playerp;	/* pointer to structure to alter */
63 	char   *prompt;		/* pointer to prompt string */
64 	int     c;		/* input */
65 	int     today;		/* day of year of today */
66 	int     temp;		/* temporary variable */
67 	long    loc;		/* location in player file */
68 	time_t  now;		/* time now */
69 	double  dtemp;		/* temporary variable */
70 	bool   *bptr;		/* pointer to bool item to change */
71 	double *dptr;		/* pointer to double item to change */
72 	short  *sptr;		/* pointer to short item to change */
73 
74 	clear();
75 
76 	for (;;)
77 		/* get name of player to examine/alter */
78 	{
79 		mvaddstr(5, 0, "Which character do you want to look at ? ");
80 		getstring(Databuf, SZ_DATABUF);
81 		truncstring(Databuf);
82 
83 		if (Databuf[0] == '\0')
84 			userlist(ingameflag);
85 		else
86 			break;
87 	}
88 
89 	loc = -1L;
90 
91 	if (!ingameflag)
92 		/* use 'Player' structure */
93 		playerp = &Player;
94 	else
95 		if (strcmp(Databuf, Player.p_name) == 0)
96 			/* alter/examine current player */
97 		{
98 			playerp = &Player;
99 			loc = Fileloc;
100 		} else
101 			/* use 'Other' structure */
102 			playerp = &Other;
103 
104 	/* find player on file */
105 	if (loc < 0L && (loc = findname(Databuf, playerp)) < 0L)
106 		/* didn't find player */
107 	{
108 		clear();
109 		mvaddstr(11, 0, "Not found.");
110 		return;
111 	}
112 	time(&now);
113 	today = localtime(&now)->tm_yday;
114 
115 	clear();
116 
117 	for (;;)
118 		/* print player structure, and prompt for action */
119 	{
120 		mvprintw(0, 0, "A:Name         %s\n", playerp->p_name);
121 
122 		if (Wizard)
123 			printw("B:Password     %s\n", playerp->p_password);
124 		else
125 			addstr("B:Password     XXXXXXXX\n");
126 
127 		printw(" :Login        %s\n", playerp->p_login);
128 
129 		printw("C:Experience   %.0f\n", playerp->p_experience);
130 		printw("D:Level        %.0f\n", playerp->p_level);
131 		printw("E:Strength     %.0f\n", playerp->p_strength);
132 		printw("F:Sword        %.0f\n", playerp->p_sword);
133 		printw(" :Might        %.0f\n", playerp->p_might);
134 		printw("G:Energy       %.0f\n", playerp->p_energy);
135 		printw("H:Max-Energy   %.0f\n", playerp->p_maxenergy);
136 		printw("I:Shield       %.0f\n", playerp->p_shield);
137 		printw("J:Quickness    %.0f\n", playerp->p_quickness);
138 		printw("K:Quicksilver  %.0f\n", playerp->p_quksilver);
139 		printw(" :Speed        %.0f\n", playerp->p_speed);
140 		printw("L:Magic Level  %.0f\n", playerp->p_magiclvl);
141 		printw("M:Mana         %.0f\n", playerp->p_mana);
142 		printw("N:Brains       %.0f\n", playerp->p_brains);
143 
144 		if (Wizard || playerp->p_specialtype != SC_VALAR)
145 			mvaddstr(0, 40, descrstatus(playerp));
146 
147 		mvprintw(1, 40, "O:Poison       %0.3f\n", playerp->p_poison);
148 		mvprintw(2, 40, "P:Gold         %.0f\n", playerp->p_gold);
149 		mvprintw(3, 40, "Q:Gem          %.0f\n", playerp->p_gems);
150 		mvprintw(4, 40, "R:Sin          %0.3f\n", playerp->p_sin);
151 		if (Wizard) {
152 			mvprintw(5, 40, "S:X-coord      %.0f\n", playerp->p_x);
153 			mvprintw(6, 40, "T:Y-coord      %.0f\n", playerp->p_y);
154 		} else {
155 			mvaddstr(5, 40, "S:X-coord      ?\n");
156 			mvaddstr(6, 40, "T:Y-coord      ?\n");
157 		}
158 
159 		mvprintw(7, 40, "U:Age          %ld\n", playerp->p_age);
160 		mvprintw(8, 40, "V:Degenerated  %d\n", playerp->p_degenerated);
161 
162 		mvprintw(9, 40, "W:Type         %d (%s)\n",
163 		    playerp->p_type, descrtype(playerp, FALSE) + 1);
164 		mvprintw(10, 40, "X:Special Type %d\n", playerp->p_specialtype);
165 		mvprintw(11, 40, "Y:Lives        %d\n", playerp->p_lives);
166 		mvprintw(12, 40, "Z:Crowns       %d\n", playerp->p_crowns);
167 		mvprintw(13, 40, "0:Charms       %d\n", playerp->p_charms);
168 		mvprintw(14, 40, "1:Amulets      %d\n", playerp->p_amulets);
169 		mvprintw(15, 40, "2:Holy Water   %d\n", playerp->p_holywater);
170 
171 		temp = today - playerp->p_lastused;
172 		if (temp < 0)
173 			/* last year */
174 			temp += 365;
175 		mvprintw(16, 40, "3:Lastused     %d  (%d)\n", playerp->p_lastused, temp);
176 
177 		mvprintw(18, 8, "4:Palantir %c  5:Blessing %c  6:Virgin %c  7:Blind %c",
178 		    flag[(int)playerp->p_palantir],
179 		    flag[(int)playerp->p_blessing],
180 		    flag[(int)playerp->p_virgin],
181 		    flag[(int)playerp->p_blindness]);
182 
183 		if (!Wizard)
184 			mvprintw(19, 8, "8:Ring    %c",
185 			    flag[playerp->p_ring.ring_type != R_NONE]);
186 		else
187 			mvprintw(19, 8, "8:Ring    %d  9:Duration %d",
188 			    playerp->p_ring.ring_type, playerp->p_ring.ring_duration);
189 
190 		if (!Wizard
191 		/* not wizard */
192 		    && (ingameflag || strcmp(Login, playerp->p_login) != 0))
193 			/* in game or not examining own character */
194 		{
195 			if (ingameflag) {
196 				more(LINES - 1);
197 				clear();
198 				return;
199 			} else
200 				cleanup(TRUE);
201 			/* NOTREACHED */
202 		}
203 		mvaddstr(20, 0, "!:Quit       ?:Delete");
204 		mvaddstr(21, 0, "What would you like to change ? ");
205 
206 		if (Wizard)
207 			c = getanswer(" ", TRUE);
208 		else
209 			/* examining own player; allow to change name and
210 			 * password */
211 			c = getanswer("!BA", FALSE);
212 
213 		switch (c) {
214 		case 'A':	/* change name */
215 		case 'B':	/* change password */
216 			if (!Wizard)
217 				/* prompt for password */
218 			{
219 				mvaddstr(23, 0, "Password ? ");
220 				Echo = FALSE;
221 				getstring(Databuf, 9);
222 				Echo = TRUE;
223 				if (strcmp(Databuf, playerp->p_password) != 0)
224 					continue;
225 			}
226 			if (c == 'A')
227 				/* get new name */
228 			{
229 				mvaddstr(23, 0, "New name: ");
230 				getstring(Databuf, SZ_NAME);
231 				truncstring(Databuf);
232 				if (Databuf[0] != '\0')
233 					if (Wizard || findname(Databuf, &Other) < 0L)
234 						strlcpy(playerp->p_name, Databuf,
235 						    sizeof playerp->p_name);
236 			} else
237 				/* get new password */
238 			{
239 				if (!Wizard)
240 					Echo = FALSE;
241 
242 				do
243 					/* get two copies of new password
244 					 * until they match */
245 				{
246 					/* get first copy */
247 					mvaddstr(23, 0, "New password ? ");
248 					getstring(Databuf, SZ_PASSWORD);
249 					if (Databuf[0] == '\0')
250 						break;
251 
252 					/* get second copy */
253 					mvaddstr(23, 0, "One more time ? ");
254 					getstring(playerp->p_password, SZ_PASSWORD);
255 				}
256 				while (strcmp(playerp->p_password, Databuf) != 0);
257 
258 				Echo = TRUE;
259 			}
260 
261 			continue;
262 
263 		case 'C':	/* change experience */
264 			prompt = "experience";
265 			dptr = &playerp->p_experience;
266 			goto DALTER;
267 
268 		case 'D':	/* change level */
269 			prompt = "level";
270 			dptr = &playerp->p_level;
271 			goto DALTER;
272 
273 		case 'E':	/* change strength */
274 			prompt = "strength";
275 			dptr = &playerp->p_strength;
276 			goto DALTER;
277 
278 		case 'F':	/* change swords */
279 			prompt = "sword";
280 			dptr = &playerp->p_sword;
281 			goto DALTER;
282 
283 		case 'G':	/* change energy */
284 			prompt = "energy";
285 			dptr = &playerp->p_energy;
286 			goto DALTER;
287 
288 		case 'H':	/* change maximum energy */
289 			prompt = "max energy";
290 			dptr = &playerp->p_maxenergy;
291 			goto DALTER;
292 
293 		case 'I':	/* change shields */
294 			prompt = "shield";
295 			dptr = &playerp->p_shield;
296 			goto DALTER;
297 
298 		case 'J':	/* change quickness */
299 			prompt = "quickness";
300 			dptr = &playerp->p_quickness;
301 			goto DALTER;
302 
303 		case 'K':	/* change quicksilver */
304 			prompt = "quicksilver";
305 			dptr = &playerp->p_quksilver;
306 			goto DALTER;
307 
308 		case 'L':	/* change magic */
309 			prompt = "magic level";
310 			dptr = &playerp->p_magiclvl;
311 			goto DALTER;
312 
313 		case 'M':	/* change mana */
314 			prompt = "mana";
315 			dptr = &playerp->p_mana;
316 			goto DALTER;
317 
318 		case 'N':	/* change brains */
319 			prompt = "brains";
320 			dptr = &playerp->p_brains;
321 			goto DALTER;
322 
323 		case 'O':	/* change poison */
324 			prompt = "poison";
325 			dptr = &playerp->p_poison;
326 			goto DALTER;
327 
328 		case 'P':	/* change gold */
329 			prompt = "gold";
330 			dptr = &playerp->p_gold;
331 			goto DALTER;
332 
333 		case 'Q':	/* change gems */
334 			prompt = "gems";
335 			dptr = &playerp->p_gems;
336 			goto DALTER;
337 
338 		case 'R':	/* change sin */
339 			prompt = "sin";
340 			dptr = &playerp->p_sin;
341 			goto DALTER;
342 
343 		case 'S':	/* change x coord */
344 			prompt = "x";
345 			dptr = &playerp->p_x;
346 			goto DALTER;
347 
348 		case 'T':	/* change y coord */
349 			prompt = "y";
350 			dptr = &playerp->p_y;
351 			goto DALTER;
352 
353 		case 'U':	/* change age */
354 			mvprintw(23, 0, "age = %ld; age = ", playerp->p_age);
355 			dtemp = infloat();
356 			if (dtemp != 0.0)
357 				playerp->p_age = (long) dtemp;
358 			continue;
359 
360 		case 'V':	/* change degen */
361 			mvprintw(23, 0, "degen = %d; degen = ", playerp->p_degenerated);
362 			dtemp = infloat();
363 			if (dtemp != 0.0)
364 				playerp->p_degenerated = (int) dtemp;
365 			continue;
366 
367 		case 'W':	/* change type */
368 			prompt = "type";
369 			sptr = &playerp->p_type;
370 			goto SALTER;
371 
372 		case 'X':	/* change special type */
373 			prompt = "special type";
374 			sptr = &playerp->p_specialtype;
375 			goto SALTER;
376 
377 		case 'Y':	/* change lives */
378 			prompt = "lives";
379 			sptr = &playerp->p_lives;
380 			goto SALTER;
381 
382 		case 'Z':	/* change crowns */
383 			prompt = "crowns";
384 			sptr = &playerp->p_crowns;
385 			goto SALTER;
386 
387 		case '0':	/* change charms */
388 			prompt = "charm";
389 			sptr = &playerp->p_charms;
390 			goto SALTER;
391 
392 		case '1':	/* change amulet */
393 			prompt = "amulet";
394 			sptr = &playerp->p_amulets;
395 			goto SALTER;
396 
397 		case '2':	/* change holy water */
398 			prompt = "holy water";
399 			sptr = &playerp->p_holywater;
400 			goto SALTER;
401 
402 		case '3':	/* change last-used */
403 			prompt = "last-used";
404 			sptr = &playerp->p_lastused;
405 			goto SALTER;
406 
407 		case '4':	/* change palantir */
408 			prompt = "palantir";
409 			bptr = &playerp->p_palantir;
410 			goto BALTER;
411 
412 		case '5':	/* change blessing */
413 			prompt = "blessing";
414 			bptr = &playerp->p_blessing;
415 			goto BALTER;
416 
417 		case '6':	/* change virgin */
418 			prompt = "virgin";
419 			bptr = &playerp->p_virgin;
420 			goto BALTER;
421 
422 		case '7':	/* change blindness */
423 			prompt = "blindness";
424 			bptr = &playerp->p_blindness;
425 			goto BALTER;
426 
427 		case '8':	/* change ring type */
428 			prompt = "ring-type";
429 			sptr = &playerp->p_ring.ring_type;
430 			goto SALTER;
431 
432 		case '9':	/* change ring duration */
433 			prompt = "ring-duration";
434 			sptr = &playerp->p_ring.ring_duration;
435 			goto SALTER;
436 
437 		case '!':	/* quit, update */
438 			if (Wizard &&
439 			    (!ingameflag || playerp != &Player))
440 				/* turn off status if not modifying self */
441 			{
442 				playerp->p_status = S_OFF;
443 				playerp->p_tampered = T_OFF;
444 			}
445 			writerecord(playerp, loc);
446 			clear();
447 			return;
448 
449 		case '?':	/* delete player */
450 			if (ingameflag && playerp == &Player)
451 				/* cannot delete self */
452 				continue;
453 
454 			freerecord(playerp, loc);
455 			clear();
456 			return;
457 
458 		default:
459 			continue;
460 		}
461 DALTER:
462 		mvprintw(23, 0, "%s = %f; %s = ", prompt, *dptr, prompt);
463 		dtemp = infloat();
464 		if (dtemp != 0.0)
465 			*dptr = dtemp;
466 		continue;
467 
468 SALTER:
469 		mvprintw(23, 0, "%s = %d; %s = ", prompt, *sptr, prompt);
470 		dtemp = infloat();
471 		if (dtemp != 0.0)
472 			*sptr = (short) dtemp;
473 		continue;
474 
475 BALTER:
476 		mvprintw(23, 0, "%s = %c; %s = ", prompt, flag[(int)*bptr],
477 		    prompt);
478 		c = getanswer("\nTF", TRUE);
479 		if (c == 'T')
480 			*bptr = TRUE;
481 		else
482 			if (c == 'F')
483 				*bptr = FALSE;
484 		continue;
485 	}
486 }
487 /**/
488 /************************************************************************
489 /
490 / FUNCTION NAME: monstlist()
491 /
492 / FUNCTION: print a monster listing
493 /
494 / AUTHOR: E. A. Estes, 2/27/86
495 /
496 / ARGUMENTS: none
497 /
498 / RETURN VALUE: none
499 /
500 / MODULES CALLED: puts(), fread(), fseek(), printf()
501 /
502 / GLOBAL INPUTS: Curmonster, *Monstfp
503 /
504 / GLOBAL OUTPUTS: none
505 /
506 / DESCRIPTION:
507 /	Read monster file, and print a monster listing on standard output.
508 /
509 *************************************************************************/
510 
511 void
512 monstlist()
513 {
514 	int     count = 0;	/* count in file */
515 
516 	puts(" #)  Name                 Str  Brain  Quick  Energy  Exper  Treas  Type  Flock%\n");
517 	fseek(Monstfp, 0L, SEEK_SET);
518 	while (fread(&Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp) == 1)
519 		printf("%2d)  %-20.20s%4.0f   %4.0f     %2.0f   %5.0f  %5.0f     %2d    %2d     %3.0f\n", count++,
520 		    Curmonster.m_name, Curmonster.m_strength, Curmonster.m_brains,
521 		    Curmonster.m_speed, Curmonster.m_energy, Curmonster.m_experience,
522 		    Curmonster.m_treasuretype, Curmonster.m_type, Curmonster.m_flock);
523 }
524 /**/
525 /************************************************************************
526 /
527 / FUNCTION NAME: scorelist()
528 /
529 / FUNCTION: print player score board
530 /
531 / AUTHOR: E. A. Estes, 12/4/85
532 /
533 / ARGUMENTS: none
534 /
535 / RETURN VALUE: none
536 /
537 / MODULES CALLED: fread(), fopen(), printf(), fclose()
538 /
539 / GLOBAL INPUTS:
540 /
541 / GLOBAL OUTPUTS: none
542 /
543 / DESCRIPTION:
544 /	Read the scoreboard file and print the contents.
545 /
546 *************************************************************************/
547 
548 void
549 scorelist()
550 {
551 	struct scoreboard sbuf;	/* for reading entries */
552 	FILE   *fp;		/* to open the file */
553 
554 	if ((fp = fopen(_PATH_SCORE, "r")) != NULL) {
555 		while (fread(&sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
556 			printf("%-20s   (%-9s)  Level: %6.0f  Type: %s\n",
557 			    sbuf.sb_name, sbuf.sb_login, sbuf.sb_level, sbuf.sb_type);
558 		fclose(fp);
559 	}
560 }
561 /**/
562 /************************************************************************
563 /
564 / FUNCTION NAME: activelist()
565 /
566 / FUNCTION: print list of active players to standard output
567 /
568 / AUTHOR: E. A. Estes, 3/7/86
569 /
570 / ARGUMENTS: none
571 /
572 / RETURN VALUE: none
573 /
574 / MODULES CALLED: descrstatus(), fread(), fseek(), printf(), descrtype()
575 /
576 / GLOBAL INPUTS: Other, *Playersfp
577 /
578 / GLOBAL OUTPUTS: none
579 /
580 / DESCRIPTION:
581 /	Read player file, and print list of active records to standard output.
582 /
583 *************************************************************************/
584 
585 void
586 activelist()
587 {
588 	fseek(Playersfp, 0L, SEEK_SET);
589 	printf("Current characters on file are:\n\n");
590 
591 	while (fread(&Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
592 		if (Other.p_status != S_NOTUSED)
593 			printf("%-20s   (%-9s)  Level: %6.0f  %s  (%s)\n",
594 			    Other.p_name, Other.p_login, Other.p_level,
595 			    descrtype(&Other, FALSE), descrstatus(&Other));
596 
597 }
598 /**/
599 /************************************************************************
600 /
601 / FUNCTION NAME: purgeoldplayers()
602 /
603 / FUNCTION: purge inactive players from player file
604 /
605 / AUTHOR: E. A. Estes, 12/4/85
606 /
607 / ARGUMENTS: none
608 /
609 / RETURN VALUE: none
610 /
611 / MODULES CALLED: freerecord(), time(), fread(), fseek(), localtime()
612 /
613 / GLOBAL INPUTS: Other, *Playersfp
614 /
615 / GLOBAL OUTPUTS: none
616 /
617 / DESCRIPTION:
618 /	Delete characters which have not been used with the last
619 /	three weeks.
620 /
621 *************************************************************************/
622 
623 void
624 purgeoldplayers()
625 {
626 	int     today;		/* day of year for today */
627 	int     daysold;	/* how many days since the character has been
628 				 * used */
629 	time_t  ltime;		/* time in seconds */
630 	long    loc = 0L;	/* location in file */
631 
632 	time(&ltime);
633 	today = localtime(&ltime)->tm_yday;
634 
635 	for (;;) {
636 		fseek(Playersfp, loc, SEEK_SET);
637 		if (fread(&Other, SZ_PLAYERSTRUCT, 1, Playersfp) != 1)
638 			break;
639 
640 		daysold = today - Other.p_lastused;
641 		if (daysold < 0)
642 			daysold += 365;
643 
644 		if (daysold > N_DAYSOLD)
645 			/* player hasn't been used in a while; delete */
646 			freerecord(&Other, loc);
647 
648 		loc += SZ_PLAYERSTRUCT;
649 	}
650 }
651 /**/
652 /************************************************************************
653 /
654 / FUNCTION NAME: enterscore()
655 /
656 / FUNCTION: enter player into scoreboard
657 /
658 / AUTHOR: E. A. Estes, 12/4/85
659 /
660 / ARGUMENTS: none
661 /
662 / RETURN VALUE: none
663 /
664 / MODULES CALLED: fread(), fseek(), fopen(), error(), strcmp(), fclose(),
665 /	strlcpy(), fwrite(), descrtype()
666 /
667 / GLOBAL INPUTS: Player
668 /
669 / GLOBAL OUTPUTS: none
670 /
671 / DESCRIPTION:
672 /	The scoreboard keeps track of the highest character on a
673 /	per-login basis.
674 /	Search the scoreboard for an entry for the current login,
675 /	if an entry is found, and it is lower than the current player,
676 /	replace it, otherwise create an entry.
677 /
678 *************************************************************************/
679 
680 void
681 enterscore()
682 {
683 	struct scoreboard sbuf;	/* buffer to read in scoreboard entries */
684 	FILE   *fp;		/* to open scoreboard file */
685 	long    loc = 0L;	/* location in scoreboard file */
686 	bool    found = FALSE;	/* set if we found an entry for this login */
687 
688 	if ((fp = fopen(_PATH_SCORE, "r+")) != NULL) {
689 		while (fread(&sbuf, SZ_SCORESTRUCT, 1, fp) == 1)
690 			if (strcmp(Player.p_login, sbuf.sb_login) == 0) {
691 				found = TRUE;
692 				break;
693 			} else
694 				loc += SZ_SCORESTRUCT;
695 	} else {
696 		error(_PATH_SCORE);
697 		/* NOTREACHED */
698 	}
699 
700 	/*
701          * At this point, 'loc' will either indicate a point beyond
702          * the end of file, or the place where the previous entry
703          * was found.
704          */
705 
706 	if ((!found) || Player.p_level > sbuf.sb_level)
707 		/* put new entry in for this login */
708 	{
709 		strlcpy(sbuf.sb_login, Player.p_login,
710 		    sizeof sbuf.sb_login);
711 		strlcpy(sbuf.sb_name, Player.p_name,
712 		    sizeof sbuf.sb_name);
713 		sbuf.sb_level = Player.p_level;
714 		strlcpy(sbuf.sb_type, descrtype(&Player, TRUE),
715 		    sizeof sbuf.sb_type);
716 	}
717 	/* update entry */
718 	fseek(fp, loc, SEEK_SET);
719 	fwrite(&sbuf, SZ_SCORESTRUCT, 1, fp);
720 	fclose(fp);
721 }
722