xref: /netbsd/games/larn/diag.c (revision bf9ec67e)
1 /*	$NetBSD: diag.c,v 1.9 2000/07/03 03:57:42 matt Exp $	*/
2 
3 /* diag.c		Larn is copyrighted 1986 by Noah Morgan. */
4 #include <sys/cdefs.h>
5 #ifndef lint
6 __RCSID("$NetBSD: diag.c,v 1.9 2000/07/03 03:57:42 matt Exp $");
7 #endif				/* not lint */
8 
9 #include <sys/types.h>
10 #include <sys/times.h>
11 #include <sys/stat.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "header.h"
16 #include "extern.h"
17 static struct tms cputime;
18 /*
19 	***************************
20 	DIAG -- dungeon diagnostics
21 	***************************
22 
23 	subroutine to print out data for debugging
24  */
25 #ifdef EXTRA
26 static int      rndcount[16];
27 void
28 diag()
29 {
30 	int    i, j;
31 	int             hit, dam;
32 	cursors();
33 	lwclose();
34 	if (lcreat(diagfile) < 0) {	/* open the diagnostic file	 */
35 		lcreat((char *) 0);
36 		lprcat("\ndiagnostic failure\n");
37 		return (-1);
38 	}
39 	write(1, "\nDiagnosing . . .\n", 18);
40 	lprcat("\n\nBeginning of DIAG diagnostics ----------\n");
41 
42 	/* for the character attributes	 */
43 
44 	lprintf("\n\nPlayer attributes:\n\nHit points: %2d(%2d)", (long) c[HP], (long) c[HPMAX]);
45 	lprintf("\ngold: %d  Experience: %d  Character level: %d  Level in caverns: %d",
46 	(long) c[GOLD], (long) c[EXPERIENCE], (long) c[LEVEL], (long) level);
47 	lprintf("\nTotal types of monsters: %d", (long) MAXMONST + 8);
48 
49 	lprcat("\f\nHere's the dungeon:\n\n");
50 
51 	i = level;
52 	for (j = 0; j < MAXLEVEL + MAXVLEVEL; j++) {
53 		newcavelevel(j);
54 		lprintf("\nMaze for level %s:\n", levelname[level]);
55 		diagdrawscreen();
56 	}
57 	newcavelevel(i);
58 
59 	lprcat("\f\nNow for the monster data:\n\n");
60 	lprcat("   Monster Name      LEV  AC   DAM  ATT  DEF    GOLD   HP     EXP   \n");
61 	lprcat("--------------------------------------------------------------------------\n");
62 	for (i = 0; i <= MAXMONST + 8; i++) {
63 		lprintf("%19s  %2d  %3d ", monster[i].name, (long) monster[i].level, (long) monster[i].armorclass);
64 		lprintf(" %3d  %3d  %3d  ", (long) monster[i].damage, (long) monster[i].attack, (long) monster[i].defense);
65 		lprintf("%6d  %3d   %6d\n", (long) monster[i].gold, (long) monster[i].hitpoints, (long) monster[i].experience);
66 	}
67 
68 	lprcat("\n\nHere's a Table for the to hit percentages\n");
69 	lprcat("\n     We will be assuming that players level = 2 * monster level");
70 	lprcat("\n     and that the players dexterity and strength are 16.");
71 	lprcat("\n    to hit: if (rnd(22) < (2[monst AC] + your level + dex + WC/8 -1)/2) then hit");
72 	lprcat("\n    damage = rund(8) + WC/2 + STR - c[HARDGAME] - 4");
73 	lprcat("\n    to hit:  if rnd(22) < to hit  then player hits\n");
74 	lprcat("\n    Each entry is as follows:  to hit / damage / number hits to kill\n");
75 	lprcat("\n          monster     WC = 4         WC = 20        WC = 40");
76 	lprcat("\n---------------------------------------------------------------");
77 	for (i = 0; i <= MAXMONST + 8; i++) {
78 		hit = 2 * monster[i].armorclass + 2 * monster[i].level + 16;
79 		dam = 16 - c[HARDGAME];
80 		lprintf("\n%20s   %2d/%2d/%2d       %2d/%2d/%2d       %2d/%2d/%2d",
81 			monster[i].name,
82 			(long) (hit / 2), (long) max(0, dam + 2), (long) (monster[i].hitpoints / (dam + 2) + 1),
83 			(long) ((hit + 2) / 2), (long) max(0, dam + 10), (long) (monster[i].hitpoints / (dam + 10) + 1),
84 			(long) ((hit + 5) / 2), (long) max(0, dam + 20), (long) (monster[i].hitpoints / (dam + 20) + 1));
85 	}
86 
87 	lprcat("\n\nHere's the list of available potions:\n\n");
88 	for (i = 0; i < MAXPOTION; i++)
89 		lprintf("%20s\n", &potionhide[i][1]);
90 	lprcat("\n\nHere's the list of available scrolls:\n\n");
91 	for (i = 0; i < MAXSCROLL; i++)
92 		lprintf("%20s\n", &scrollhide[i][1]);
93 	lprcat("\n\nHere's the spell list:\n\n");
94 	lprcat("spell          name           description\n");
95 	lprcat("-------------------------------------------------------------------------------------------\n\n");
96 	for (j = 0; j < SPNUM; j++) {
97 		lprc(' ');
98 		lprcat(spelcode[j]);
99 		lprintf(" %21s  %s\n", spelname[j], speldescript[j]);
100 	}
101 
102 	lprcat("\n\nFor the c[] array:\n");
103 	for (j = 0; j < 100; j += 10) {
104 		lprintf("\nc[%2d] = ", (long) j);
105 		for (i = 0; i < 9; i++)
106 			lprintf("%5d ", (long) c[i + j]);
107 	}
108 
109 	lprcat("\n\nTest of random number generator ----------------");
110 	lprcat("\n    for 25,000 calls divided into 16 slots\n\n");
111 
112 	for (i = 0; i < 16; i++)
113 		rndcount[i] = 0;
114 	for (i = 0; i < 25000; i++)
115 		rndcount[rund(16)]++;
116 	for (i = 0; i < 16; i++) {
117 		lprintf("  %5d", (long) rndcount[i]);
118 		if (i == 7)
119 			lprc('\n');
120 	}
121 
122 	lprcat("\n\n");
123 	lwclose();
124 	lcreat((char *) 0);
125 	lprcat("Done Diagnosing . . .");
126 	return (0);
127 }
128 /*
129 	subroutine to count the number of occurrences of an object
130  */
131 int
132 dcount(l)
133 	int l;
134 {
135 	int i, j, p;
136 	int k;
137 	k = 0;
138 	for (i = 0; i < MAXX; i++)
139 		for (j = 0; j < MAXY; j++)
140 			for (p = 0; p < MAXLEVEL; p++)
141 				if (cell[p * MAXX * MAXY + i * MAXY + j].item == l)
142 					k++;
143 	return (k);
144 }
145 
146 /*
147 	subroutine to draw the whole screen as the player knows it
148  */
149 void
150 diagdrawscreen()
151 {
152 	int    i, j, k;
153 
154 	for (i = 0; i < MAXY; i++)
155 		/* for the east west walls of this line	 */
156 	{
157 		for (j = 0; j < MAXX; j++)
158 			if (k = mitem[j][i])
159 				lprc(monstnamelist[k]);
160 			else
161 				lprc(objnamelist[item[j][i]]);
162 		lprc('\n');
163 	}
164 }
165 #endif
166 
167 
168 /*
169 	to save the game in a file
170  */
171 static time_t   zzz = 0;
172 int
173 savegame(fname)
174 	char *fname;
175 {
176 	int    i, k;
177 	struct sphere *sp;
178 	struct stat     statbuf;
179 
180 	nosignal = 1;
181 	lflush();
182 	savelevel();
183 	ointerest();
184 	if (lcreat(fname) < 0) {
185 		lcreat((char *) 0);
186 		lprintf("\nCan't open file <%s> to save game\n", fname);
187 		nosignal = 0;
188 		return (-1);
189 	}
190 	set_score_output();
191 	lwrite((char *) beenhere, MAXLEVEL + MAXVLEVEL);
192 	for (k = 0; k < MAXLEVEL + MAXVLEVEL; k++)
193 		if (beenhere[k])
194 			lwrite((char *) &cell[k * MAXX * MAXY], sizeof(struct cel) * MAXY * MAXX);
195 	times(&cputime);	/* get cpu time */
196 	c[CPUTIME] += (cputime.tms_utime + cputime.tms_stime) / 60;
197 	lwrite((char *) &c[0], 100 * sizeof(long));
198 	lprint((long) gltime);
199 	lprc(level);
200 	lprc(playerx);
201 	lprc(playery);
202 	lwrite((char *) iven, 26);
203 	lwrite((char *) ivenarg, 26 * sizeof(short));
204 	for (k = 0; k < MAXSCROLL; k++)
205 		lprc(scrollname[k][0]);
206 	for (k = 0; k < MAXPOTION; k++)
207 		lprc(potionname[k][0]);
208 	lwrite((char *) spelknow, SPNUM);
209 	lprc(wizard);
210 	lprc(rmst);		/* random monster generation counter */
211 	for (i = 0; i < 90; i++)
212 		lprc(itm[i].qty);
213 	lwrite((char *) course, 25);
214 	lprc(cheat);
215 	lprc(VERSION);
216 	for (i = 0; i < MAXMONST; i++)
217 		lprc(monster[i].genocided);	/* genocide info */
218 	for (sp = spheres; sp; sp = sp->p)
219 		lwrite((char *) sp, sizeof(struct sphere));	/* save spheres of
220 								 * annihilation */
221 	time(&zzz);
222 	lprint((long) (zzz - initialtime));
223 	lwrite((char *) &zzz, sizeof(long));
224 	if (fstat(lfd, &statbuf) < 0)
225 		lprint(0L);
226 	else
227 		lprint((long) statbuf.st_ino);	/* inode # */
228 	lwclose();
229 	lastmonst[0] = 0;
230 #ifndef VT100
231 	setscroll();
232 #endif	/* VT100 */
233 	lcreat((char *) 0);
234 	nosignal = 0;
235 	return (0);
236 }
237 
238 void
239 restoregame(fname)
240 	char           *fname;
241 {
242 	int    i, k;
243 	struct sphere *sp, *sp2;
244 	struct stat     filetimes;
245 	cursors();
246 	lprcat("\nRestoring . . .");
247 	lflush();
248 	if (lopen(fname) <= 0) {
249 		lcreat((char *) 0);
250 		lprintf("\nCan't open file <%s>to restore game\n", fname);
251 		nap(2000);
252 		c[GOLD] = c[BANKACCOUNT] = 0;
253 		died(-265);
254 		return;
255 	}
256 	lrfill((char *) beenhere, MAXLEVEL + MAXVLEVEL);
257 	for (k = 0; k < MAXLEVEL + MAXVLEVEL; k++)
258 		if (beenhere[k])
259 			lrfill((char *) &cell[k * MAXX * MAXY], sizeof(struct cel) * MAXY * MAXX);
260 
261 	lrfill((char *) &c[0], 100 * sizeof(long));
262 	gltime = lrint();
263 	level = c[CAVELEVEL] = lgetc();
264 	playerx = lgetc();
265 	playery = lgetc();
266 	lrfill((char *) iven, 26);
267 	lrfill((char *) ivenarg, 26 * sizeof(short));
268 	for (k = 0; k < MAXSCROLL; k++)
269 		scrollname[k] = lgetc() ? scrollhide[k] : "";
270 	for (k = 0; k < MAXPOTION; k++)
271 		potionname[k] = lgetc() ? potionhide[k] : "";
272 	lrfill((char *) spelknow, SPNUM);
273 	wizard = lgetc();
274 	rmst = lgetc();		/* random monster creation flag */
275 
276 	for (i = 0; i < 90; i++)
277 		itm[i].qty = lgetc();
278 	lrfill((char *) course, 25);
279 	cheat = lgetc();
280 	if (VERSION != lgetc()) {	/* version number  */
281 		cheat = 1;
282 		lprcat("Sorry, But your save file is for an older version of larn\n");
283 		nap(2000);
284 		c[GOLD] = c[BANKACCOUNT] = 0;
285 		died(-266);
286 		return;
287 	}
288 	for (i = 0; i < MAXMONST; i++)
289 		monster[i].genocided = lgetc();	/* genocide info */
290 	for (sp = 0, i = 0; i < c[SPHCAST]; i++) {
291 		sp2 = sp;
292 		sp = (struct sphere *) malloc(sizeof(struct sphere));
293 		if (sp == 0) {
294 			write(2, "Can't malloc() for sphere space\n", 32);
295 			break;
296 		}
297 		lrfill((char *) sp, sizeof(struct sphere));	/* get spheres of
298 								 * annihilation */
299 		sp->p = 0;	/* null out pointer */
300 		if (i == 0)
301 			spheres = sp;	/* beginning of list */
302 		else
303 			sp2->p = sp;
304 	}
305 
306 	time(&zzz);
307 	initialtime = zzz - lrint();
308 	fstat(fd, &filetimes);	/* get the creation and modification time of
309 				 * file	 */
310 	lrfill((char *) &zzz, sizeof(long));
311 	zzz += 6;
312 	if (filetimes.st_ctime > zzz)
313 		fsorry();	/* file create time	 */
314 	else if (filetimes.st_mtime > zzz)
315 		fsorry();	/* file modify time	 */
316 	if (c[HP] < 0) {
317 		died(284);
318 		return;
319 	}			/* died a post mortem death */
320 	oldx = oldy = 0;
321 	i = lrint();		/* inode # */
322 	if (i && (filetimes.st_ino != i))
323 		fsorry();
324 	lrclose();
325 	if (strcmp(fname, ckpfile) == 0) {
326 		if (lappend(fname) < 0)
327 			fcheat();
328 		else {
329 			lprc(' ');
330 			lwclose();
331 		}
332 		lcreat((char *) 0);
333 	} else if (unlink(fname) < 0)
334 		fcheat();	/* can't unlink save file */
335 	/* for the greedy cheater checker	 */
336 	for (k = 0; k < 6; k++)
337 		if (c[k] > 99)
338 			greedy();
339 	if (c[HPMAX] > 999 || c[SPELLMAX] > 125)
340 		greedy();
341 	if (c[LEVEL] == 25 && c[EXPERIENCE] > skill[24]) {	/* if patch up lev 25
342 								 * player */
343 		long            tmp;
344 		tmp = c[EXPERIENCE] - skill[24];	/* amount to go up */
345 		c[EXPERIENCE] = skill[24];
346 		raiseexperience((long) tmp);
347 	}
348 	getlevel();
349 	lasttime = gltime;
350 }
351 
352 /*
353 	subroutine to not allow greedy cheaters
354  */
355 void
356 greedy()
357 {
358 #if WIZID
359 	if (wizard)
360 		return;
361 #endif
362 
363 	lprcat("\n\nI am so sorry, but your character is a little TOO good!  Since this\n");
364 	lprcat("cannot normally happen from an honest game, I must assume that you cheated.\n");
365 	lprcat("In that you are GREEDY as well as a CHEATER, I cannot allow this game\n");
366 	lprcat("to continue.\n");
367 	nap(5000);
368 	c[GOLD] = c[BANKACCOUNT] = 0;
369 	died(-267);
370 	return;
371 }
372 
373 /*
374 	subroutine to not allow altered save files and terminate the attempted
375 	restart
376  */
377 void
378 fsorry()
379 {
380 	lprcat("\nSorry, but your savefile has been altered.\n");
381 	lprcat("However, seeing as I am a good sport, I will let you play.\n");
382 	lprcat("Be advised though, you won't be placed on the normal scoreboard.");
383 	cheat = 1;
384 	nap(4000);
385 }
386 
387 /*
388 	subroutine to not allow game if save file can't be deleted
389  */
390 void
391 fcheat()
392 {
393 #if WIZID
394 	if (wizard)
395 		return;
396 #endif
397 
398 	lprcat("\nSorry, but your savefile can't be deleted.  This can only mean\n");
399 	lprcat("that you tried to CHEAT by protecting the directory the savefile\n");
400 	lprcat("is in.  Since this is unfair to the rest of the larn community, I\n");
401 	lprcat("cannot let you play this game.\n");
402 	nap(5000);
403 	c[GOLD] = c[BANKACCOUNT] = 0;
404 	died(-268);
405 	return;
406 }
407