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