1 /* $NetBSD: diag.c,v 1.13 2012/06/19 05:30:43 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.13 2012/06/19 05:30:43 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(char *fname) 180 { 181 int i, k; 182 struct sphere *sp; 183 struct stat statbuf; 184 185 nosignal = 1; 186 lflush(); 187 savelevel(); 188 ointerest(); 189 if (lcreat(fname) < 0) { 190 lcreat((char *) 0); 191 lprintf("\nCan't open file <%s> to save game\n", fname); 192 nosignal = 0; 193 return (-1); 194 } 195 set_score_output(); 196 lwrite((char *) beenhere, MAXLEVEL + MAXVLEVEL); 197 for (k = 0; k < MAXLEVEL + MAXVLEVEL; k++) 198 if (beenhere[k]) 199 lwrite((char *) &cell[k * MAXX * MAXY], sizeof(struct cel) * MAXY * MAXX); 200 times(&cputime); /* get cpu time */ 201 c[CPUTIME] += (cputime.tms_utime + cputime.tms_stime) / 60; 202 lwrite((char *) &c[0], 100 * sizeof(long)); 203 lprint((long) gltime); 204 lprc(level); 205 lprc(playerx); 206 lprc(playery); 207 lwrite((char *) iven, 26); 208 lwrite((char *) ivenarg, 26 * sizeof(short)); 209 for (k = 0; k < MAXSCROLL; k++) 210 lprc(scrollname[k][0]); 211 for (k = 0; k < MAXPOTION; k++) 212 lprc(potionname[k][0]); 213 lwrite((char *) spelknow, SPNUM); 214 lprc(wizard); 215 lprc(rmst); /* random monster generation counter */ 216 for (i = 0; i < 90; i++) 217 lprc(itm[i].qty); 218 lwrite((char *) course, 25); 219 lprc(cheat); 220 lprc(VERSION); 221 for (i = 0; i < MAXMONST; i++) 222 lprc(monster[i].genocided); /* genocide info */ 223 for (sp = spheres; sp; sp = sp->p) 224 lwrite((char *) sp, sizeof(struct sphere)); /* save spheres of 225 * annihilation */ 226 time(&zzz); 227 lprint((long) (zzz - initialtime)); 228 lwrite((char *) &zzz, sizeof(long)); 229 if (fstat(io_outfd, &statbuf) < 0) 230 lprint(0L); 231 else 232 lprint((long) statbuf.st_ino); /* inode # */ 233 lwclose(); 234 lastmonst[0] = 0; 235 #ifndef VT100 236 setscroll(); 237 #endif /* VT100 */ 238 lcreat((char *) 0); 239 nosignal = 0; 240 return (0); 241 } 242 243 void 244 restoregame(char *fname) 245 { 246 int i, k; 247 struct sphere *sp, *sp2; 248 struct stat filetimes; 249 cursors(); 250 lprcat("\nRestoring . . ."); 251 lflush(); 252 if (lopen(fname) <= 0) { 253 lcreat((char *) 0); 254 lprintf("\nCan't open file <%s>to restore game\n", fname); 255 nap(2000); 256 c[GOLD] = c[BANKACCOUNT] = 0; 257 died(-265); 258 return; 259 } 260 lrfill((char *) beenhere, MAXLEVEL + MAXVLEVEL); 261 for (k = 0; k < MAXLEVEL + MAXVLEVEL; k++) 262 if (beenhere[k]) 263 lrfill((char *) &cell[k * MAXX * MAXY], sizeof(struct cel) * MAXY * MAXX); 264 265 lrfill((char *) &c[0], 100 * sizeof(long)); 266 gltime = larn_lrint(); 267 level = c[CAVELEVEL] = lgetc(); 268 playerx = lgetc(); 269 playery = lgetc(); 270 lrfill((char *) iven, 26); 271 lrfill((char *) ivenarg, 26 * sizeof(short)); 272 for (k = 0; k < MAXSCROLL; k++) 273 scrollname[k] = lgetc() ? scrollhide[k] : ""; 274 for (k = 0; k < MAXPOTION; k++) 275 potionname[k] = lgetc() ? potionhide[k] : ""; 276 lrfill((char *) spelknow, SPNUM); 277 wizard = lgetc(); 278 rmst = lgetc(); /* random monster creation flag */ 279 280 for (i = 0; i < 90; i++) 281 itm[i].qty = lgetc(); 282 lrfill((char *) course, 25); 283 cheat = lgetc(); 284 if (VERSION != lgetc()) { /* version number */ 285 cheat = 1; 286 lprcat("Sorry, But your save file is for an older version of larn\n"); 287 nap(2000); 288 c[GOLD] = c[BANKACCOUNT] = 0; 289 died(-266); 290 return; 291 } 292 for (i = 0; i < MAXMONST; i++) 293 monster[i].genocided = lgetc(); /* genocide info */ 294 for (sp = 0, i = 0; i < c[SPHCAST]; i++) { 295 sp2 = sp; 296 sp = (struct sphere *) malloc(sizeof(struct sphere)); 297 if (sp == 0) { 298 write(2, "Can't malloc() for sphere space\n", 32); 299 break; 300 } 301 lrfill((char *) sp, sizeof(struct sphere)); /* get spheres of 302 * annihilation */ 303 sp->p = 0; /* null out pointer */ 304 if (i == 0) 305 spheres = sp; /* beginning of list */ 306 else 307 sp2->p = sp; 308 } 309 310 time(&zzz); 311 initialtime = zzz - larn_lrint(); 312 /* get the creation and modification time of file */ 313 fstat(io_infd, &filetimes); 314 lrfill((char *) &zzz, sizeof(long)); 315 zzz += 6; 316 if (filetimes.st_ctime > zzz) 317 fsorry(); /* file create time */ 318 else if (filetimes.st_mtime > zzz) 319 fsorry(); /* file modify time */ 320 if (c[HP] < 0) { 321 died(284); 322 return; 323 } /* died a post mortem death */ 324 oldx = oldy = 0; 325 /* XXX the following will break on 64-bit inode numbers */ 326 i = larn_lrint(); /* inode # */ 327 if (i && (filetimes.st_ino != (ino_t) i)) 328 fsorry(); 329 lrclose(); 330 if (strcmp(fname, ckpfile) == 0) { 331 if (lappend(fname) < 0) 332 fcheat(); 333 else { 334 lprc(' '); 335 lwclose(); 336 } 337 lcreat((char *) 0); 338 } else if (unlink(fname) < 0) 339 fcheat(); /* can't unlink save file */ 340 /* for the greedy cheater checker */ 341 for (k = 0; k < 6; k++) 342 if (c[k] > 99) 343 greedy(); 344 if (c[HPMAX] > 999 || c[SPELLMAX] > 125) 345 greedy(); 346 if (c[LEVEL] == 25 && c[EXPERIENCE] > skill[24]) { /* if patch up lev 25 347 * player */ 348 long tmp; 349 tmp = c[EXPERIENCE] - skill[24]; /* amount to go up */ 350 c[EXPERIENCE] = skill[24]; 351 raiseexperience((long) tmp); 352 } 353 getlevel(); 354 lasttime = gltime; 355 } 356 357 /* 358 subroutine to not allow greedy cheaters 359 */ 360 static void 361 greedy(void) 362 { 363 #if WIZID 364 if (wizard) 365 return; 366 #endif 367 368 lprcat("\n\nI am so sorry, but your character is a little TOO good! Since this\n"); 369 lprcat("cannot normally happen from an honest game, I must assume that you cheated.\n"); 370 lprcat("In that you are GREEDY as well as a CHEATER, I cannot allow this game\n"); 371 lprcat("to continue.\n"); 372 nap(5000); 373 c[GOLD] = c[BANKACCOUNT] = 0; 374 died(-267); 375 return; 376 } 377 378 /* 379 subroutine to not allow altered save files and terminate the attempted 380 restart 381 */ 382 static void 383 fsorry(void) 384 { 385 lprcat("\nSorry, but your savefile has been altered.\n"); 386 lprcat("However, seeing as I am a good sport, I will let you play.\n"); 387 lprcat("Be advised though, you won't be placed on the normal scoreboard."); 388 cheat = 1; 389 nap(4000); 390 } 391 392 /* 393 subroutine to not allow game if save file can't be deleted 394 */ 395 static void 396 fcheat(void) 397 { 398 #if WIZID 399 if (wizard) 400 return; 401 #endif 402 403 lprcat("\nSorry, but your savefile can't be deleted. This can only mean\n"); 404 lprcat("that you tried to CHEAT by protecting the directory the savefile\n"); 405 lprcat("is in. Since this is unfair to the rest of the larn community, I\n"); 406 lprcat("cannot let you play this game.\n"); 407 nap(5000); 408 c[GOLD] = c[BANKACCOUNT] = 0; 409 died(-268); 410 return; 411 } 412