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