Commit | Line | Data |
---|---|---|
aac37b12 KB |
1 | /* |
2 | * misc.c Phantasia miscellaneous support routines | |
3 | */ | |
4 | ||
5 | #include "include.h" | |
6 | ||
7 | /************************************************************************ | |
8 | / | |
9 | / FUNCTION NAME: movelevel() | |
10 | / | |
11 | / FUNCTION: move player to new level | |
12 | / | |
13 | / AUTHOR: E. A. Estes, 12/4/85 | |
14 | / | |
15 | / ARGUMENTS: none | |
16 | / | |
17 | / RETURN VALUE: none | |
18 | / | |
19 | / MODULES CALLED: death(), floor(), wmove(), drandom(), waddstr(), explevel() | |
20 | / | |
21 | / GLOBAL INPUTS: Player, *stdscr, *Statptr, Stattable[] | |
22 | / | |
23 | / GLOBAL OUTPUTS: Player, Changed | |
24 | / | |
25 | / DESCRIPTION: | |
26 | / Use lookup table to increment important statistics when | |
27 | / progressing to new experience level. | |
28 | / Players are rested to maximum as a bonus for making a new | |
29 | / level. | |
30 | / Check for council of wise, and being too big to be king. | |
31 | / | |
32 | /************************************************************************/ | |
33 | ||
34 | movelevel() | |
35 | { | |
36 | register struct charstats *statptr; /* for pointing into Stattable */ | |
37 | double new; /* new level */ | |
38 | double inc; /* increment between new and old levels */ | |
39 | ||
40 | Changed = TRUE; | |
41 | ||
42 | if (Player.p_type == C_EXPER) | |
43 | /* roll a type to use for increment */ | |
44 | statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)]; | |
45 | else | |
46 | statptr = Statptr; | |
47 | ||
48 | new = explevel(Player.p_experience); | |
49 | inc = new - Player.p_level; | |
50 | Player.p_level = new; | |
51 | ||
52 | /* add increments to statistics */ | |
53 | Player.p_strength += statptr->c_strength.increase * inc; | |
54 | Player.p_mana += statptr->c_mana.increase * inc; | |
55 | Player.p_brains += statptr->c_brains.increase * inc; | |
56 | Player.p_magiclvl += statptr->c_magiclvl.increase * inc; | |
57 | Player.p_maxenergy += statptr->c_energy.increase * inc; | |
58 | ||
59 | /* rest to maximum upon reaching new level */ | |
60 | Player.p_energy = Player.p_maxenergy + Player.p_shield; | |
61 | ||
62 | if (Player.p_crowns > 0 && Player.p_level >= 1000.0) | |
63 | /* no longer able to be king -- turn crowns into cash */ | |
64 | { | |
65 | Player.p_gold += ((double) Player.p_crowns) * 5000.0; | |
66 | Player.p_crowns = 0; | |
67 | } | |
68 | ||
69 | if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL) | |
70 | /* make a member of the council */ | |
71 | { | |
72 | mvaddstr(6, 0, "You have made it to the Council of the Wise.\n"); | |
73 | addstr("Good Luck on your search for the Holy Grail.\n"); | |
74 | ||
75 | Player.p_specialtype = SC_COUNCIL; | |
76 | ||
77 | /* no rings for council and above */ | |
78 | Player.p_ring.ring_type = R_NONE; | |
79 | Player.p_ring.ring_duration = 0; | |
80 | ||
81 | Player.p_lives = 3; /* three extra lives */ | |
82 | } | |
83 | ||
84 | if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR) | |
85 | death("Old age"); | |
86 | } | |
87 | /*\f*/ | |
88 | /************************************************************************ | |
89 | / | |
90 | / FUNCTION NAME: descrlocation() | |
91 | / | |
92 | / FUNCTION: return a formatted description of location | |
93 | / | |
94 | / AUTHOR: E. A. Estes, 12/4/85 | |
95 | / | |
96 | / ARGUMENTS: | |
97 | / struct player playerp - pointer to player structure | |
98 | / bool shortflag - set if short form is desired | |
99 | / | |
100 | / RETURN VALUE: pointer to string containing result | |
101 | / | |
102 | / MODULES CALLED: fabs(), floor(), sprintf(), distance() | |
103 | / | |
104 | / GLOBAL INPUTS: Databuf[] | |
105 | / | |
106 | / GLOBAL OUTPUTS: none | |
107 | / | |
108 | / DESCRIPTION: | |
109 | / Look at coordinates and return an appropriately formatted | |
110 | / string. | |
111 | / | |
112 | /************************************************************************/ | |
113 | ||
114 | char * | |
115 | descrlocation(playerp, shortflag) | |
116 | struct player *playerp; | |
117 | bool shortflag; | |
118 | { | |
119 | double circle; /* corresponding circle for coordinates */ | |
120 | register int quadrant; /* quandrant of grid */ | |
121 | register char *label; /* pointer to place name */ | |
122 | static char *nametable[4][4] = /* names of places */ | |
123 | { | |
124 | "Anorien", "Ithilien", "Rohan", "Lorien", | |
125 | "Gondor", "Mordor", "Dunland", "Rovanion", | |
126 | "South Gondor", "Khand", "Eriador", "The Iron Hills", | |
127 | "Far Harad", "Near Harad", "The Northern Waste", "Rhun" | |
128 | }; | |
129 | ||
130 | if (playerp->p_specialtype == SC_VALAR) | |
131 | return(" is in Valhala"); | |
132 | else if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) | |
133 | { | |
134 | if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND) | |
135 | label = "The Point of No Return"; | |
136 | else | |
137 | label = "The Ashen Mountains"; | |
138 | } | |
139 | else if (circle >= 55) | |
140 | label = "Morannon"; | |
141 | else if (circle >= 35) | |
142 | label = "Kennaquahair"; | |
143 | else if (circle >= 20) | |
144 | label = "The Dead Marshes"; | |
145 | else if (circle >= 9) | |
146 | label = "The Outer Waste"; | |
147 | else if (circle >= 5) | |
148 | label = "The Moors Adventurous"; | |
149 | else | |
150 | { | |
151 | if (playerp->p_x == 0.0 && playerp->p_y == 0.0) | |
152 | label = "The Lord's Chamber"; | |
153 | else | |
154 | { | |
155 | /* this expression is split to prevent compiler loop with some compilers */ | |
156 | quadrant = ((playerp->p_x > 0.0) ? 1 : 0); | |
157 | quadrant += ((playerp->p_y >= 0.0) ? 2 : 0); | |
158 | label = nametable[((int) circle) - 1][quadrant]; | |
159 | } | |
160 | } | |
161 | ||
162 | if (shortflag) | |
163 | sprintf(Databuf, "%.29s", label); | |
164 | else | |
165 | sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y); | |
166 | ||
167 | return(Databuf); | |
168 | } | |
169 | /*\f*/ | |
170 | /************************************************************************ | |
171 | / | |
172 | / FUNCTION NAME: tradingpost() | |
173 | / | |
174 | / FUNCTION: do trading post stuff | |
175 | / | |
176 | / AUTHOR: E. A. Estes, 12/4/85 | |
177 | / | |
178 | / ARGUMENTS: none | |
179 | / | |
180 | / RETURN VALUE: none | |
181 | / | |
182 | / MODULES CALLED: writerecord(), adjuststats(), fabs(), more(), sqrt(), | |
183 | / sleep(), floor(), wmove(), drandom(), wclear(), printw(), | |
184 | / altercoordinates(), infloat(), waddstr(), wrefresh(), mvprintw(), getanswer(), | |
185 | / wclrtoeol(), wclrtobot() | |
186 | / | |
187 | / GLOBAL INPUTS: Menu[], Circle, Player, *stdscr, Fileloc, Nobetter[] | |
188 | / | |
189 | / GLOBAL OUTPUTS: Player | |
190 | / | |
191 | / DESCRIPTION: | |
192 | / Different trading posts have different items. | |
193 | / Merchants cannot be cheated, but they can be dishonest | |
194 | / themselves. | |
195 | / | |
196 | / Shields, swords, and quicksilver are not cumulative. This is | |
197 | / one major area of complaint, but there are two reasons for this: | |
198 | / 1) It becomes MUCH too easy to make very large versions | |
199 | / of these items. | |
200 | / 2) In the real world, one cannot simply weld two swords | |
201 | / together to make a bigger one. | |
202 | / | |
203 | / At one time, it was possible to sell old weapons at half the purchase | |
204 | / price. This resulted in huge amounts of gold floating around, | |
205 | / and the game lost much of its challenge. | |
206 | / | |
207 | / Also, purchasing gems defeats the whole purpose of gold. Gold | |
208 | / is small change for lower level players. They really shouldn't | |
209 | / be able to accumulate more than enough gold for a small sword or | |
210 | / a few books. Higher level players shouldn't even bother to pick | |
211 | / up gold, except maybe to buy mana once in a while. | |
212 | / | |
213 | /************************************************************************/ | |
214 | ||
215 | tradingpost() | |
216 | { | |
217 | double numitems; /* number of items to purchase */ | |
218 | double cost; /* cost of purchase */ | |
219 | double blessingcost; /* cost of blessing */ | |
220 | int ch; /* input */ | |
221 | register int size; /* size of the trading post */ | |
222 | register int loop; /* loop counter */ | |
223 | int cheat = 0; /* number of times player has tried to cheat */ | |
224 | bool dishonest = FALSE;/* set when merchant is dishonest */ | |
225 | ||
226 | Player.p_status = S_TRADING; | |
227 | writerecord(&Player, Fileloc); | |
228 | ||
229 | clear(); | |
230 | addstr("You are at a trading post. All purchases must be made with gold."); | |
231 | ||
232 | size = sqrt(fabs(Player.p_x / 100)) + 1; | |
233 | size = MIN(7, size); | |
234 | ||
235 | /* set up cost of blessing */ | |
236 | blessingcost = 1000.0 * (Player.p_level + 5.0); | |
237 | ||
238 | /* print Menu */ | |
239 | move(7, 0); | |
240 | for (loop = 0; loop < size; ++loop) | |
241 | /* print Menu */ | |
242 | { | |
243 | if (loop == 6) | |
244 | cost = blessingcost; | |
245 | else | |
246 | cost = Menu[loop].cost; | |
247 | printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost); | |
248 | } | |
249 | ||
250 | mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? "); | |
251 | ||
252 | for (;;) | |
253 | { | |
254 | adjuststats(); /* truncate any bad values */ | |
255 | ||
256 | /* print some important statistics */ | |
257 | mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n", | |
258 | Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms); | |
259 | printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n", | |
260 | Player.p_shield, Player.p_sword, Player.p_quksilver, | |
261 | (Player.p_blessing ? " True" : "False")); | |
262 | printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana); | |
263 | ||
264 | move(5, 36); | |
265 | ch = getanswer("LPS", FALSE); | |
266 | move(15, 0); | |
267 | clrtobot(); | |
268 | switch(ch) | |
269 | { | |
270 | case 'L': /* leave */ | |
271 | case '\n': | |
272 | altercoordinates(0.0, 0.0, A_NEAR); | |
273 | return; | |
274 | ||
275 | case 'P': /* make purchase */ | |
276 | mvaddstr(15, 0, "What what would you like to buy ? "); | |
277 | ch = getanswer(" 1234567", FALSE); | |
278 | move(15, 0); | |
279 | clrtoeol(); | |
280 | ||
281 | if (ch - '0' > size) | |
282 | addstr("Sorry, this merchant doesn't have that."); | |
283 | else | |
284 | switch (ch) | |
285 | { | |
286 | case '1': | |
287 | printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ", | |
288 | Menu[0].cost, floor(Player.p_gold / Menu[0].cost)); | |
289 | cost = (numitems = floor(infloat())) * Menu[0].cost; | |
290 | ||
291 | if (cost > Player.p_gold || numitems < 0) | |
292 | ++cheat; | |
293 | else | |
294 | { | |
295 | cheat = 0; | |
296 | Player.p_gold -= cost; | |
297 | if (drandom() < 0.02) | |
298 | dishonest = TRUE; | |
299 | else | |
300 | Player.p_mana += numitems; | |
301 | } | |
302 | break; | |
303 | ||
304 | case '2': | |
305 | printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ", | |
306 | Menu[1].cost, floor(Player.p_gold / Menu[1].cost)); | |
307 | cost = (numitems = floor(infloat())) * Menu[1].cost; | |
308 | ||
309 | if (numitems == 0.0) | |
310 | break; | |
311 | else if (cost > Player.p_gold || numitems < 0) | |
312 | ++cheat; | |
313 | else if (numitems < Player.p_shield) | |
314 | NOBETTER(); | |
315 | else | |
316 | { | |
317 | cheat = 0; | |
318 | Player.p_gold -= cost; | |
319 | if (drandom() < 0.02) | |
320 | dishonest = TRUE; | |
321 | else | |
322 | Player.p_shield = numitems; | |
323 | } | |
324 | break; | |
325 | ||
326 | case '3': | |
327 | printw("A book costs %.0f gp. How many do you want (%.0f max) ? ", | |
328 | Menu[2].cost, floor(Player.p_gold / Menu[2].cost)); | |
329 | cost = (numitems = floor(infloat())) * Menu[2].cost; | |
330 | ||
331 | if (cost > Player.p_gold || numitems < 0) | |
332 | ++cheat; | |
333 | else | |
334 | { | |
335 | cheat = 0; | |
336 | Player.p_gold -= cost; | |
337 | if (drandom() < 0.02) | |
338 | dishonest = TRUE; | |
339 | else if (drandom() * numitems > Player.p_level / 10.0 | |
340 | && numitems != 1) | |
341 | { | |
342 | printw("\nYou blew your mind!\n"); | |
343 | Player.p_brains /= 5; | |
344 | } | |
345 | else | |
346 | { | |
347 | Player.p_brains += floor(numitems) * ROLL(20, 8); | |
348 | } | |
349 | } | |
350 | break; | |
351 | ||
352 | case '4': | |
353 | printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ", | |
354 | Menu[3].cost, floor(Player.p_gold / Menu[3].cost)); | |
355 | cost = (numitems = floor(infloat())) * Menu[3].cost; | |
356 | ||
357 | if (numitems == 0.0) | |
358 | break; | |
359 | else if (cost > Player.p_gold || numitems < 0) | |
360 | ++cheat; | |
361 | else if (numitems < Player.p_sword) | |
362 | NOBETTER(); | |
363 | else | |
364 | { | |
365 | cheat = 0; | |
366 | Player.p_gold -= cost; | |
367 | if (drandom() < 0.02) | |
368 | dishonest = TRUE; | |
369 | else | |
370 | Player.p_sword = numitems; | |
371 | } | |
372 | break; | |
373 | ||
374 | case '5': | |
375 | printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ", | |
376 | Menu[4].cost, floor(Player.p_gold / Menu[4].cost)); | |
377 | cost = (numitems = floor(infloat())) * Menu[4].cost; | |
378 | ||
379 | if (cost > Player.p_gold || numitems < 0) | |
380 | ++cheat; | |
381 | else | |
382 | { | |
383 | cheat = 0; | |
384 | Player.p_gold -= cost; | |
385 | if (drandom() < 0.02) | |
386 | dishonest = TRUE; | |
387 | else | |
388 | Player.p_charms += numitems; | |
389 | } | |
390 | break; | |
391 | ||
392 | case '6': | |
393 | printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ", | |
394 | Menu[5].cost, floor(Player.p_gold / Menu[5].cost)); | |
395 | cost = (numitems = floor(infloat())) * Menu[5].cost; | |
396 | ||
397 | if (numitems == 0.0) | |
398 | break; | |
399 | else if (cost > Player.p_gold || numitems < 0) | |
400 | ++cheat; | |
401 | else if (numitems < Player.p_quksilver) | |
402 | NOBETTER(); | |
403 | else | |
404 | { | |
405 | cheat = 0; | |
406 | Player.p_gold -= cost; | |
407 | if (drandom() < 0.02) | |
408 | dishonest = TRUE; | |
409 | else | |
410 | Player.p_quksilver = numitems; | |
411 | } | |
412 | break; | |
413 | ||
414 | case '7': | |
415 | if (Player.p_blessing) | |
416 | { | |
417 | addstr("You already have a blessing."); | |
418 | break; | |
419 | } | |
420 | ||
421 | printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost); | |
422 | ch = getanswer("NY", FALSE); | |
423 | ||
424 | if (ch == 'Y') | |
425 | if (Player.p_gold < blessingcost) | |
426 | ++cheat; | |
427 | else | |
428 | { | |
429 | cheat = 0; | |
430 | Player.p_gold -= blessingcost; | |
431 | if (drandom() < 0.02) | |
432 | dishonest = TRUE; | |
433 | else | |
434 | Player.p_blessing = TRUE; | |
435 | } | |
436 | break; | |
437 | } | |
438 | break; | |
439 | ||
440 | case 'S': /* sell gems */ | |
441 | mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ", | |
442 | (double) N_GEMVALUE, Player.p_gems); | |
443 | numitems = floor(infloat()); | |
444 | ||
445 | if (numitems > Player.p_gems || numitems < 0) | |
446 | ++cheat; | |
447 | else | |
448 | { | |
449 | cheat = 0; | |
450 | Player.p_gems -= numitems; | |
451 | Player.p_gold += numitems * N_GEMVALUE; | |
452 | } | |
453 | } | |
454 | ||
455 | if (cheat == 1) | |
456 | mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n"); | |
457 | else if (cheat == 2) | |
458 | { | |
459 | mvaddstr(17, 0, "You had your chance. This merchant happens to be\n"); | |
460 | printw("a %.0f level magic user, and you made %s mad!\n", | |
461 | ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her"); | |
462 | altercoordinates(0.0, 0.0, A_FAR); | |
463 | Player.p_energy /= 2.0; | |
464 | ++Player.p_sin; | |
465 | more(23); | |
466 | return; | |
467 | } | |
468 | else if (dishonest) | |
469 | { | |
470 | mvaddstr(17, 0, "The merchant stole your money!"); | |
471 | refresh(); | |
472 | altercoordinates(Player.p_x - Player.p_x / 10.0, | |
473 | Player.p_y - Player.p_y / 10.0, A_SPECIFIC); | |
474 | sleep(2); | |
475 | return; | |
476 | } | |
477 | } | |
478 | } | |
479 | /*\f*/ | |
480 | /************************************************************************ | |
481 | / | |
482 | / FUNCTION NAME: displaystats() | |
483 | / | |
484 | / FUNCTION: print out important player statistics | |
485 | / | |
486 | / AUTHOR: E. A. Estes, 12/4/85 | |
487 | / | |
488 | / ARGUMENTS: none | |
489 | / | |
490 | / RETURN VALUE: none | |
491 | / | |
492 | / MODULES CALLED: descrstatus(), descrlocation(), mvprintw() | |
493 | / | |
494 | / GLOBAL INPUTS: Users, Player | |
495 | / | |
496 | / GLOBAL OUTPUTS: none | |
497 | / | |
498 | / DESCRIPTION: | |
499 | / Important player statistics are printed on the screen. | |
500 | / | |
501 | /************************************************************************/ | |
502 | ||
503 | displaystats() | |
504 | { | |
505 | mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE)); | |
506 | mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n", | |
507 | Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield, | |
508 | Player.p_mana, Users); | |
509 | mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n", | |
510 | Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might, | |
511 | Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player)); | |
512 | } | |
513 | /*\f*/ | |
514 | /************************************************************************ | |
515 | / | |
516 | / FUNCTION NAME: allstatslist() | |
517 | / | |
518 | / FUNCTION: show player items | |
519 | / | |
520 | / AUTHOR: E. A. Estes, 12/4/85 | |
521 | / | |
522 | / ARGUMENTS: none | |
523 | / | |
524 | / RETURN VALUE: none | |
525 | / | |
526 | / MODULES CALLED: mvprintw(), descrtype() | |
527 | / | |
528 | / GLOBAL INPUTS: Player | |
529 | / | |
530 | / GLOBAL OUTPUTS: none | |
531 | / | |
532 | / DESCRIPTION: | |
533 | / Print out some player statistics of lesser importance. | |
534 | / | |
535 | /************************************************************************/ | |
536 | ||
537 | allstatslist() | |
538 | { | |
539 | static char *flags[] = /* to print value of some bools */ | |
540 | { | |
541 | "False", | |
542 | " True" | |
543 | }; | |
544 | ||
545 | mvprintw( 8, 0, "Type: %s\n", descrtype(&Player, FALSE)); | |
546 | ||
547 | mvprintw(10, 0, "Experience: %9.0f", Player.p_experience); | |
548 | mvprintw(11, 0, "Brains : %9.0f", Player.p_brains); | |
549 | mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl); | |
550 | mvprintw(13, 0, "Sin : %9.5f", Player.p_sin); | |
551 | mvprintw(14, 0, "Poison : %9.5f", Player.p_poison); | |
552 | mvprintw(15, 0, "Gems : %9.0f", Player.p_gems); | |
553 | mvprintw(16, 0, "Age : %9d", Player.p_age); | |
554 | mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater); | |
555 | mvprintw(11, 40, "Amulets : %9d", Player.p_amulets); | |
556 | mvprintw(12, 40, "Charms : %9d", Player.p_charms); | |
557 | mvprintw(13, 40, "Crowns : %9d", Player.p_crowns); | |
558 | mvprintw(14, 40, "Shield : %9.0f", Player.p_shield); | |
559 | mvprintw(15, 40, "Sword : %9.0f", Player.p_sword); | |
560 | mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver); | |
561 | ||
562 | mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s", | |
563 | flags[Player.p_blessing], flags[Player.p_ring.ring_type != R_NONE], | |
564 | flags[Player.p_virgin], flags[Player.p_palantir]); | |
565 | } | |
566 | /*\f*/ | |
567 | /************************************************************************ | |
568 | / | |
569 | / FUNCTION NAME: descrtype() | |
570 | / | |
571 | / FUNCTION: return a string specifying player type | |
572 | / | |
573 | / AUTHOR: E. A. Estes, 12/4/85 | |
574 | / | |
575 | / ARGUMENTS: | |
576 | / struct player playerp - pointer to structure for player | |
577 | / bool shortflag - set if short form is desired | |
578 | / | |
579 | / RETURN VALUE: pointer to string describing player type | |
580 | / | |
581 | / MODULES CALLED: strcpy() | |
582 | / | |
583 | / GLOBAL INPUTS: Databuf[] | |
584 | / | |
585 | / GLOBAL OUTPUTS: Databuf[] | |
586 | / | |
587 | / DESCRIPTION: | |
588 | / Return a string describing the player type. | |
589 | / King, council, valar, supercedes other types. | |
590 | / The first character of the string is '*' if the player | |
591 | / has a crown. | |
592 | / If 'shortflag' is TRUE, return a 3 character string. | |
593 | / | |
594 | /************************************************************************/ | |
595 | ||
596 | char * | |
597 | descrtype(playerp, shortflag) | |
598 | struct player *playerp; | |
599 | bool shortflag; | |
600 | { | |
601 | register int type; /* for caluculating result subscript */ | |
602 | static char *results[] = /* description table */ | |
603 | { | |
604 | " Magic User", " MU", | |
605 | " Fighter", " F ", | |
606 | " Elf", " E ", | |
607 | " Dwarf", " D ", | |
608 | " Halfling", " H ", | |
609 | " Experimento", " EX", | |
610 | " Super", " S ", | |
611 | " King", " K ", | |
612 | " Council of Wise", " CW", | |
613 | " Ex-Valar", " EV", | |
614 | " Valar", " V ", | |
615 | " ? ", " ? " | |
616 | }; | |
617 | ||
618 | type = playerp->p_type; | |
619 | ||
620 | switch (playerp->p_specialtype) | |
621 | { | |
622 | case SC_NONE: | |
623 | type = playerp->p_type; | |
624 | break; | |
625 | ||
626 | case SC_KING: | |
627 | type = 7; | |
628 | break; | |
629 | ||
630 | case SC_COUNCIL: | |
631 | type = 8; | |
632 | break; | |
633 | ||
634 | case SC_EXVALAR: | |
635 | type = 9; | |
636 | break; | |
637 | ||
638 | case SC_VALAR: | |
639 | type = 10; | |
640 | break; | |
641 | } | |
642 | ||
643 | type *= 2; /* calculate offset */ | |
644 | ||
645 | if (type > 20) | |
646 | /* error */ | |
647 | type = 22; | |
648 | ||
649 | if (shortflag) | |
650 | /* use short descriptions */ | |
651 | ++type; | |
652 | ||
653 | if (playerp->p_crowns > 0) | |
654 | { | |
655 | strcpy(Databuf, results[type]); | |
656 | Databuf[0] = '*'; | |
657 | return(Databuf); | |
658 | } | |
659 | else | |
660 | return(results[type]); | |
661 | } | |
662 | /*\f*/ | |
663 | /************************************************************************ | |
664 | / | |
665 | / FUNCTION NAME: findname() | |
666 | / | |
667 | / FUNCTION: find location in player file of given name | |
668 | / | |
669 | / AUTHOR: E. A. Estes, 12/4/85 | |
670 | / | |
671 | / ARGUMENTS: | |
672 | / char *name - name of character to look for | |
673 | / struct player *playerp - pointer of structure to fill | |
674 | / | |
675 | / RETURN VALUE: location of player if found, -1 otherwise | |
676 | / | |
677 | / MODULES CALLED: fread(), fseek(), strcmp() | |
678 | / | |
679 | / GLOBAL INPUTS: Wizard, *Playersfp | |
680 | / | |
681 | / GLOBAL OUTPUTS: none | |
682 | / | |
683 | / DESCRIPTION: | |
684 | / Search the player file for the player of the given name. | |
685 | / If player is found, fill structure with player data. | |
686 | / | |
687 | /************************************************************************/ | |
688 | ||
689 | long | |
690 | findname(name, playerp) | |
691 | register char *name; | |
692 | register struct player *playerp; | |
693 | { | |
694 | long loc = 0; /* location in the file */ | |
695 | ||
696 | fseek(Playersfp, 0L, 0); | |
697 | while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
698 | { | |
699 | if (strcmp(playerp->p_name, name) == 0) | |
700 | { | |
701 | if (playerp->p_status != S_NOTUSED || Wizard) | |
702 | /* found it */ | |
703 | return(loc); | |
704 | } | |
705 | loc += SZ_PLAYERSTRUCT; | |
706 | } | |
707 | ||
708 | return(-1); | |
709 | } | |
710 | /*\f*/ | |
711 | /************************************************************************ | |
712 | / | |
713 | / FUNCTION NAME: allocrecord() | |
714 | / | |
715 | / FUNCTION: find space in the player file for a new character | |
716 | / | |
717 | / AUTHOR: E. A. Estes, 12/4/85 | |
718 | / | |
719 | / ARGUMENTS: none | |
720 | / | |
721 | / RETURN VALUE: location of free space in file | |
722 | / | |
723 | / MODULES CALLED: initplayer(), writerecord(), fread(), fseek() | |
724 | / | |
725 | / GLOBAL INPUTS: Other, *Playersfp | |
726 | / | |
727 | / GLOBAL OUTPUTS: Player | |
728 | / | |
729 | / DESCRIPTION: | |
730 | / Search the player file for an unused entry. If none are found, | |
731 | / make one at the end of the file. | |
732 | / | |
733 | /************************************************************************/ | |
734 | ||
735 | long | |
736 | allocrecord() | |
737 | { | |
738 | long loc = 0L; /* location in file */ | |
739 | ||
740 | fseek(Playersfp, 0L, 0); | |
741 | while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) | |
742 | { | |
743 | if (Other.p_status == S_NOTUSED) | |
744 | /* found an empty record */ | |
745 | return(loc); | |
746 | else | |
747 | loc += SZ_PLAYERSTRUCT; | |
748 | } | |
749 | ||
750 | /* make a new record */ | |
751 | initplayer(&Other); | |
752 | Player.p_status = S_OFF; | |
753 | writerecord(&Other, loc); | |
754 | ||
755 | return(loc); | |
756 | } | |
757 | /*\f*/ | |
758 | /************************************************************************ | |
759 | / | |
760 | / FUNCTION NAME: freerecord() | |
761 | / | |
762 | / FUNCTION: free up a record on the player file | |
763 | / | |
764 | / AUTHOR: E. A. Estes, 2/7/86 | |
765 | / | |
766 | / ARGUMENTS: | |
767 | / struct player playerp - pointer to structure to free | |
768 | / long loc - location in file to free | |
769 | / | |
770 | / RETURN VALUE: none | |
771 | / | |
772 | / MODULES CALLED: writerecord() | |
773 | / | |
774 | / GLOBAL INPUTS: none | |
775 | / | |
776 | / GLOBAL OUTPUTS: none | |
777 | / | |
778 | / DESCRIPTION: | |
779 | / Mark structure as not used, and update player file. | |
780 | / | |
781 | /************************************************************************/ | |
782 | ||
783 | freerecord(playerp, loc) | |
784 | struct player *playerp; | |
785 | long loc; | |
786 | { | |
787 | playerp->p_name[0] = CH_MARKDELETE; | |
788 | playerp->p_status = S_NOTUSED; | |
789 | writerecord(playerp, loc); | |
790 | } | |
791 | /*\f*/ | |
792 | /************************************************************************ | |
793 | / | |
794 | / FUNCTION NAME: leavegame() | |
795 | / | |
796 | / FUNCTION: leave game | |
797 | / | |
798 | / AUTHOR: E. A. Estes, 12/4/85 | |
799 | / | |
800 | / ARGUMENTS: none | |
801 | / | |
802 | / RETURN VALUE: none | |
803 | / | |
804 | / MODULES CALLED: freerecord(), writerecord(), cleanup() | |
805 | / | |
806 | / GLOBAL INPUTS: Player, Fileloc | |
807 | / | |
808 | / GLOBAL OUTPUTS: Player | |
809 | / | |
810 | / DESCRIPTION: | |
811 | / Mark player as inactive, and cleanup. | |
812 | / Do not save players below level 1. | |
813 | / | |
814 | /************************************************************************/ | |
815 | ||
816 | leavegame() | |
817 | { | |
818 | ||
819 | if (Player.p_level < 1.0) | |
820 | /* delete character */ | |
821 | freerecord(&Player, Fileloc); | |
822 | else | |
823 | { | |
824 | Player.p_status = S_OFF; | |
825 | writerecord(&Player, Fileloc); | |
826 | } | |
827 | ||
828 | cleanup(TRUE); | |
829 | /*NOTREACHED*/ | |
830 | } | |
831 | /*\f*/ | |
832 | /************************************************************************ | |
833 | / | |
834 | / FUNCTION NAME: death() | |
835 | / | |
836 | / FUNCTION: death routine | |
837 | / | |
838 | / AUTHOR: E. A. Estes, 12/4/85 | |
839 | / | |
840 | / ARGUMENTS: | |
841 | / char *how - pointer to string describing cause of death | |
842 | / | |
843 | / RETURN VALUE: none | |
844 | / | |
845 | / MODULES CALLED: freerecord(), enterscore(), more(), exit(), fread(), | |
846 | / fseek(), execl(), fopen(), floor(), wmove(), drandom(), wclear(), strcmp(), | |
847 | / fwrite(), fflush(), printw(), strcpy(), fclose(), waddstr(), cleanup(), | |
848 | / fprintf(), wrefresh(), getanswer(), descrtype() | |
849 | / | |
850 | / GLOBAL INPUTS: Curmonster, Wizard, Player, *stdscr, Fileloc, *Monstfp, | |
851 | / Lastdead[], Gameprog[], Messfile[] | |
852 | / | |
853 | / GLOBAL OUTPUTS: Player | |
854 | / | |
855 | / DESCRIPTION: | |
856 | / Kill off current player. | |
857 | / Handle rings, and multiple lives. | |
858 | / Print an appropriate message. | |
859 | / Update scoreboard, lastdead, and let other players know about | |
860 | / the demise of their comrade. | |
861 | / | |
862 | /************************************************************************/ | |
863 | ||
864 | death(how) | |
865 | char *how; | |
866 | { | |
867 | FILE *fp; /* for updating various files */ | |
868 | int ch; /* input */ | |
869 | static char *deathmesg[] = | |
870 | /* add more messages here, if desired */ | |
871 | { | |
872 | "You have been wounded beyond repair. ", | |
873 | "You have been disemboweled. ", | |
874 | "You've been mashed, mauled, and spit upon. (You're dead.)\n", | |
875 | "You died! ", | |
876 | "You're a complete failure -- you've died!!\n", | |
877 | "You have been dealt a fatal blow! " | |
878 | }; | |
879 | ||
880 | clear(); | |
881 | ||
882 | if (strcmp(how, "Stupidity") != 0) | |
883 | { | |
884 | if (Player.p_level > 9999.0) | |
885 | /* old age */ | |
886 | addstr("Characters must be retired upon reaching level 10000. Sorry."); | |
887 | else if (Player.p_lives > 0) | |
888 | /* extra lives */ | |
889 | { | |
890 | addstr("You should be more cautious. You've been killed.\n"); | |
891 | printw("You only have %d more chance(s).\n", --Player.p_lives); | |
892 | more(3); | |
893 | Player.p_energy = Player.p_maxenergy; | |
894 | return; | |
895 | } | |
896 | else if (Player.p_specialtype == SC_VALAR) | |
897 | { | |
898 | addstr("You had your chances, but Valar aren't totally\n"); | |
899 | addstr("immortal. You are now left to wither and die . . .\n"); | |
900 | more(3); | |
901 | Player.p_brains = Player.p_level / 25.0; | |
902 | Player.p_energy = Player.p_maxenergy /= 5.0; | |
903 | Player.p_quksilver = Player.p_sword = 0.0; | |
904 | Player.p_specialtype = SC_COUNCIL; | |
905 | return; | |
906 | } | |
907 | else if (Player.p_ring.ring_inuse && | |
908 | (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG)) | |
909 | /* good ring in use - saved from death */ | |
910 | { | |
911 | mvaddstr(4, 0, "Your ring saved you from death!\n"); | |
912 | refresh(); | |
913 | Player.p_ring.ring_type = R_NONE; | |
914 | Player.p_energy = Player.p_maxenergy / 12.0 + 1.0; | |
915 | if (Player.p_crowns > 0) | |
916 | --Player.p_crowns; | |
917 | return; | |
918 | } | |
919 | else if (Player.p_ring.ring_type == R_BAD | |
920 | || Player.p_ring.ring_type == R_SPOILED) | |
921 | /* bad ring in possession; name idiot after player */ | |
922 | { | |
923 | mvaddstr(4, 0, | |
924 | "Your ring has taken control of you and turned you into a monster!\n"); | |
925 | fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0); | |
926 | fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); | |
927 | strcpy(Curmonster.m_name, Player.p_name); | |
928 | fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0); | |
929 | fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp); | |
930 | fflush(Monstfp); | |
931 | } | |
932 | } | |
933 | ||
934 | enterscore(); /* update score board */ | |
935 | ||
936 | /* put info in last dead file */ | |
937 | fp = fopen(Lastdead, "w"); | |
938 | fprintf(fp,"%s (%s, run by %s, level %.0f, killed by %s)", | |
939 | Player.p_name, descrtype(&Player, TRUE), | |
940 | Player.p_login, Player.p_level, how); | |
941 | fclose(fp); | |
942 | ||
943 | /* let other players know */ | |
944 | fp = fopen(Messfile, "w"); | |
945 | fprintf(fp, "%s was killed by %s.", Player.p_name, how); | |
946 | fclose(fp); | |
947 | ||
948 | freerecord(&Player, Fileloc); | |
949 | ||
950 | clear(); | |
951 | move(10, 0); | |
952 | addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]); | |
953 | addstr("Care to give it another try ? "); | |
954 | ch = getanswer("NY", FALSE); | |
955 | ||
956 | if (ch == 'Y') | |
957 | { | |
958 | cleanup(FALSE); | |
959 | execl(Gameprog, "phantasia", "-s", (Wizard ? "-S": (char *) NULL), 0); | |
960 | exit(0); | |
961 | /*NOTREACHED*/ | |
962 | } | |
963 | ||
964 | cleanup(TRUE); | |
965 | /*NOTREACHED*/ | |
966 | } | |
967 | /*\f*/ | |
968 | /************************************************************************ | |
969 | / | |
970 | / FUNCTION NAME: writerecord() | |
971 | / | |
972 | / FUNCTION: update structure in player file | |
973 | / | |
974 | / AUTHOR: E. A. Estes, 12/4/85 | |
975 | / | |
976 | / ARGUMENTS: | |
977 | / struct player *playerp - pointer to structure to write out | |
978 | / long place - location in file to updata | |
979 | / | |
980 | / RETURN VALUE: none | |
981 | / | |
982 | / MODULES CALLED: fseek(), fwrite(), fflush() | |
983 | / | |
984 | / GLOBAL INPUTS: *Playersfp | |
985 | / | |
986 | / GLOBAL OUTPUTS: none | |
987 | / | |
988 | / DESCRIPTION: | |
989 | / Update location in player file with given structure. | |
990 | / | |
991 | /************************************************************************/ | |
992 | ||
993 | writerecord(playerp, place) | |
994 | register struct player *playerp; | |
995 | long place; | |
996 | { | |
997 | fseek(Playersfp, place, 0); | |
998 | fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); | |
999 | fflush(Playersfp); | |
1000 | } | |
1001 | /*\f*/ | |
1002 | /************************************************************************ | |
1003 | / | |
1004 | / FUNCTION NAME: explevel() | |
1005 | / | |
1006 | / FUNCTION: calculate level based upon experience | |
1007 | / | |
1008 | / AUTHOR: E. A. Estes, 12/4/85 | |
1009 | / | |
1010 | / ARGUMENTS: | |
1011 | / double experience - experience to calculate experience level from | |
1012 | / | |
1013 | / RETURN VALUE: experience level | |
1014 | / | |
1015 | / MODULES CALLED: pow(), floor() | |
1016 | / | |
1017 | / GLOBAL INPUTS: none | |
1018 | / | |
1019 | / GLOBAL OUTPUTS: none | |
1020 | / | |
1021 | / DESCRIPTION: | |
1022 | / Experience level is a geometric progression. This has been finely | |
1023 | / tuned over the years, and probably should not be changed. | |
1024 | / | |
1025 | /************************************************************************/ | |
1026 | ||
1027 | double | |
1028 | explevel(experience) | |
1029 | double experience; | |
1030 | { | |
1031 | if (experience < 1.1e7) | |
1032 | return(floor(pow((experience / 1000.0), 0.4875))); | |
1033 | else | |
1034 | return(floor(pow((experience / 1250.0), 0.4865))); | |
1035 | } | |
1036 | /*\f*/ | |
1037 | /************************************************************************ | |
1038 | / | |
1039 | / FUNCTION NAME: truncstring() | |
1040 | / | |
1041 | / FUNCTION: truncate trailing blanks off a string | |
1042 | / | |
1043 | / AUTHOR: E. A. Estes, 12/4/85 | |
1044 | / | |
1045 | / ARGUMENTS: | |
1046 | / char *string - pointer to null terminated string | |
1047 | / | |
1048 | / RETURN VALUE: none | |
1049 | / | |
1050 | / MODULES CALLED: strlen() | |
1051 | / | |
1052 | / GLOBAL INPUTS: none | |
1053 | / | |
1054 | / GLOBAL OUTPUTS: none | |
1055 | / | |
1056 | / DESCRIPTION: | |
1057 | / Put nul characters in place of spaces at the end of the string. | |
1058 | / | |
1059 | /************************************************************************/ | |
1060 | ||
1061 | truncstring(string) | |
1062 | register char *string; | |
1063 | { | |
1064 | register int length; /* length of string */ | |
1065 | ||
1066 | length = strlen(string); | |
1067 | while (string[--length] == ' ') | |
1068 | string[length] = '\0'; | |
1069 | } | |
1070 | /*\f*/ | |
1071 | /************************************************************************ | |
1072 | / | |
1073 | / FUNCTION NAME: altercoordinates() | |
1074 | / | |
1075 | / FUNCTION: Alter x, y coordinates and set/check location flags | |
1076 | / | |
1077 | / AUTHOR: E. A. Estes, 12/16/85 | |
1078 | / | |
1079 | / ARGUMENTS: | |
1080 | / double xnew, ynew - new x, y coordinates | |
1081 | / int operation - operation to perform with coordinates | |
1082 | / | |
1083 | / RETURN VALUE: none | |
1084 | / | |
1085 | / MODULES CALLED: fabs(), floor(), drandom(), distance() | |
1086 | / | |
1087 | / GLOBAL INPUTS: Circle, Beyond, Player | |
1088 | / | |
1089 | / GLOBAL OUTPUTS: Marsh, Circle, Beyond, Throne, Player, Changed | |
1090 | / | |
1091 | / DESCRIPTION: | |
1092 | / This module is called whenever the player's coordinates are altered. | |
1093 | / If the player is beyond the point of no return, he/she is forced | |
1094 | / to stay there. | |
1095 | / | |
1096 | /************************************************************************/ | |
1097 | ||
1098 | altercoordinates(xnew, ynew, operation) | |
1099 | double xnew; | |
1100 | double ynew; | |
1101 | int operation; | |
1102 | { | |
1103 | switch (operation) | |
1104 | { | |
1105 | case A_FORCED: /* move with no checks */ | |
1106 | break; | |
1107 | ||
1108 | case A_NEAR: /* pick random coordinates near */ | |
1109 | xnew = Player.p_x + ROLL(1.0, 5.0); | |
1110 | ynew = Player.p_y - ROLL(1.0, 5.0); | |
1111 | /* fall through for check */ | |
1112 | ||
1113 | case A_SPECIFIC: /* just move player */ | |
1114 | if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND) | |
1115 | /* | |
1116 | * cannot move back from point of no return | |
1117 | * pick the largest coordinate to remain unchanged | |
1118 | */ | |
1119 | { | |
1120 | if (fabs(xnew) > fabs(ynew)) | |
1121 | xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND); | |
1122 | else | |
1123 | ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND); | |
1124 | } | |
1125 | break; | |
1126 | ||
1127 | case A_FAR: /* pick random coordinates far */ | |
1128 | xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle); | |
1129 | ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle); | |
1130 | break; | |
1131 | } | |
1132 | ||
1133 | /* now set location flags and adjust coordinates */ | |
1134 | Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew)); | |
1135 | ||
1136 | /* set up flags based upon location */ | |
1137 | Throne = Marsh = Beyond = FALSE; | |
1138 | ||
1139 | if (Player.p_x == 0.0 && Player.p_y == 0.0) | |
1140 | Throne = TRUE; | |
1141 | else if (Circle < 35 && Circle >= 20) | |
1142 | Marsh = TRUE; | |
1143 | else if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND) | |
1144 | Beyond = TRUE; | |
1145 | ||
1146 | Changed = TRUE; | |
1147 | } | |
1148 | /*\f*/ | |
1149 | /************************************************************************ | |
1150 | / | |
1151 | / FUNCTION NAME: readrecord() | |
1152 | / | |
1153 | / FUNCTION: read a player structure from file | |
1154 | / | |
1155 | / AUTHOR: E. A. Estes, 12/4/85 | |
1156 | / | |
1157 | / ARGUMENTS: | |
1158 | / struct player *playerp - pointer to structure to fill | |
1159 | / int loc - location of record to read | |
1160 | / | |
1161 | / RETURN VALUE: none | |
1162 | / | |
1163 | / MODULES CALLED: fread(), fseek() | |
1164 | / | |
1165 | / GLOBAL INPUTS: *Playersfp | |
1166 | / | |
1167 | / GLOBAL OUTPUTS: none | |
1168 | / | |
1169 | / DESCRIPTION: | |
1170 | / Read structure information from player file. | |
1171 | / | |
1172 | /************************************************************************/ | |
1173 | ||
1174 | readrecord(playerp, loc) | |
1175 | register struct player *playerp; | |
1176 | long loc; | |
1177 | { | |
1178 | fseek(Playersfp, loc, 0); | |
1179 | fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp); | |
1180 | } | |
1181 | /*\f*/ | |
1182 | /************************************************************************ | |
1183 | / | |
1184 | / FUNCTION NAME: adjuststats() | |
1185 | / | |
1186 | / FUNCTION: adjust player statistics | |
1187 | / | |
1188 | / AUTHOR: E. A. Estes, 12/4/85 | |
1189 | / | |
1190 | / ARGUMENTS: none | |
1191 | / | |
1192 | / RETURN VALUE: none | |
1193 | / | |
1194 | / MODULES CALLED: death(), floor(), drandom(), explevel(), movelevel() | |
1195 | / | |
1196 | / GLOBAL INPUTS: Player, *Statptr | |
1197 | / | |
1198 | / GLOBAL OUTPUTS: Circle, Player, Timeout | |
1199 | / | |
1200 | / DESCRIPTION: | |
1201 | / Handle adjustment and maximums on various player characteristics. | |
1202 | / | |
1203 | /************************************************************************/ | |
1204 | ||
1205 | adjuststats() | |
1206 | { | |
1207 | double dtemp; /* for temporary calculations */ | |
1208 | ||
1209 | if (explevel(Player.p_experience) > Player.p_level) | |
1210 | /* move one or more levels */ | |
1211 | { | |
1212 | movelevel(); | |
1213 | if (Player.p_level > 5.0) | |
1214 | Timeout = TRUE; | |
1215 | } | |
1216 | ||
1217 | if (Player.p_specialtype == SC_VALAR) | |
1218 | /* valar */ | |
1219 | Circle = Player.p_level / 5.0; | |
1220 | ||
1221 | /* calculate effective quickness */ | |
1222 | dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote | |
1223 | - Player.p_level;; | |
1224 | dtemp = MAX(0.0, dtemp); /* gold slows player down */ | |
1225 | Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp; | |
1226 | ||
1227 | /* calculate effective strength */ | |
1228 | if (Player.p_poison > 0.0) | |
1229 | /* poison makes player weaker */ | |
1230 | { | |
1231 | dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0; | |
1232 | dtemp = MAX(0.1, dtemp); | |
1233 | } | |
1234 | else | |
1235 | dtemp = 1.0; | |
1236 | Player.p_might = dtemp * Player.p_strength + Player.p_sword; | |
1237 | ||
1238 | /* insure that important things are within limits */ | |
1239 | Player.p_quksilver = MIN(99.0, Player.p_quksilver); | |
1240 | Player.p_mana = MIN(Player.p_mana, | |
1241 | Player.p_level * Statptr->c_maxmana + 1000.0); | |
1242 | Player.p_brains = MIN(Player.p_brains, | |
1243 | Player.p_level * Statptr->c_maxbrains + 200.0); | |
1244 | Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0); | |
1245 | ||
1246 | /* | |
1247 | * some implementations have problems with floating point compare | |
1248 | * we work around it with this stuff | |
1249 | */ | |
1250 | Player.p_gold = floor(Player.p_gold) + 0.1; | |
1251 | Player.p_gems = floor(Player.p_gems) + 0.1; | |
1252 | Player.p_mana = floor(Player.p_mana) + 0.1; | |
1253 | ||
1254 | if (Player.p_ring.ring_type != R_NONE) | |
1255 | /* do ring things */ | |
1256 | { | |
1257 | /* rest to max */ | |
1258 | Player.p_energy = Player.p_maxenergy + Player.p_shield; | |
1259 | ||
1260 | if (Player.p_ring.ring_duration <= 0) | |
1261 | /* clean up expired rings */ | |
1262 | switch (Player.p_ring.ring_type) | |
1263 | { | |
1264 | case R_BAD: /* ring drives player crazy */ | |
1265 | Player.p_ring.ring_type = R_SPOILED; | |
1266 | Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0); | |
1267 | break; | |
1268 | ||
1269 | case R_NAZREG: /* ring disappears */ | |
1270 | Player.p_ring.ring_type = R_NONE; | |
1271 | break; | |
1272 | ||
1273 | case R_SPOILED: /* ring kills player */ | |
1274 | death("A cursed ring"); | |
1275 | break; | |
1276 | ||
1277 | case R_DLREG: /* this ring doesn't expire */ | |
1278 | Player.p_ring.ring_duration = 0; | |
1279 | break; | |
1280 | } | |
1281 | } | |
1282 | ||
1283 | if (Player.p_age / N_AGE > Player.p_degenerated) | |
1284 | /* age player slightly */ | |
1285 | { | |
1286 | ++Player.p_degenerated; | |
1287 | if (Player.p_quickness > 23.0) | |
1288 | Player.p_quickness *= 0.99; | |
1289 | Player.p_strength *= 0.97; | |
1290 | Player.p_brains *= 0.95; | |
1291 | Player.p_magiclvl *= 0.97; | |
1292 | Player.p_maxenergy *= 0.95; | |
1293 | Player.p_quksilver *= 0.95; | |
1294 | Player.p_sword *= 0.93; | |
1295 | Player.p_shield *= 0.93; | |
1296 | } | |
1297 | } | |
1298 | /*\f*/ | |
1299 | /************************************************************************ | |
1300 | / | |
1301 | / FUNCTION NAME: initplayer() | |
1302 | / | |
1303 | / FUNCTION: initialize a character | |
1304 | / | |
1305 | / AUTHOR: E. A. Estes, 12/4/85 | |
1306 | / | |
1307 | / ARGUMENTS: | |
1308 | / struct player *playerp - pointer to structure to init | |
1309 | / | |
1310 | / RETURN VALUE: none | |
1311 | / | |
1312 | / MODULES CALLED: floor(), drandom() | |
1313 | / | |
1314 | / GLOBAL INPUTS: none | |
1315 | / | |
1316 | / GLOBAL OUTPUTS: none | |
1317 | / | |
1318 | / DESCRIPTION: | |
1319 | / Put a bunch of default values in the given structure. | |
1320 | / | |
1321 | /************************************************************************/ | |
1322 | ||
1323 | initplayer(playerp) | |
1324 | register struct player *playerp; | |
1325 | { | |
1326 | playerp->p_experience = | |
1327 | playerp->p_level = | |
1328 | playerp->p_strength = | |
1329 | playerp->p_sword = | |
1330 | playerp->p_might = | |
1331 | playerp->p_energy = | |
1332 | playerp->p_maxenergy = | |
1333 | playerp->p_shield = | |
1334 | playerp->p_quickness = | |
1335 | playerp->p_quksilver = | |
1336 | playerp->p_speed = | |
1337 | playerp->p_magiclvl = | |
1338 | playerp->p_mana = | |
1339 | playerp->p_brains = | |
1340 | playerp->p_poison = | |
1341 | playerp->p_gems = | |
1342 | playerp->p_sin = | |
1343 | playerp->p_1scratch = | |
1344 | playerp->p_2scratch = 0.0; | |
1345 | ||
1346 | playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */ | |
1347 | ||
1348 | playerp->p_x = ROLL(-125.0, 251.0); | |
1349 | playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */ | |
1350 | ||
1351 | /* clear ring */ | |
1352 | playerp->p_ring.ring_type = R_NONE; | |
1353 | playerp->p_ring.ring_duration = 0; | |
1354 | playerp->p_ring.ring_inuse = FALSE; | |
1355 | ||
1356 | playerp->p_age = 0L; | |
1357 | ||
1358 | playerp->p_degenerated = 1; /* don't degenerate initially */ | |
1359 | ||
1360 | playerp->p_type = C_FIGHTER; /* default */ | |
1361 | playerp->p_specialtype = SC_NONE; | |
1362 | playerp->p_lives = | |
1363 | playerp->p_crowns = | |
1364 | playerp->p_charms = | |
1365 | playerp->p_amulets = | |
1366 | playerp->p_holywater = | |
1367 | playerp->p_lastused = 0; | |
1368 | playerp->p_status = S_NOTUSED; | |
1369 | playerp->p_tampered = T_OFF; | |
1370 | playerp->p_istat = I_OFF; | |
1371 | ||
1372 | playerp->p_palantir = | |
1373 | playerp->p_blessing = | |
1374 | playerp->p_virgin = | |
1375 | playerp->p_blindness = FALSE; | |
1376 | ||
1377 | playerp->p_name[0] = | |
1378 | playerp->p_password[0] = | |
1379 | playerp->p_login[0] = '\0'; | |
1380 | } | |
1381 | /*\f*/ | |
1382 | /************************************************************************ | |
1383 | / | |
1384 | / FUNCTION NAME: readmessage() | |
1385 | / | |
1386 | / FUNCTION: read message from other players | |
1387 | / | |
1388 | / AUTHOR: E. A. Estes, 12/4/85 | |
1389 | / | |
1390 | / ARGUMENTS: none | |
1391 | / | |
1392 | / RETURN VALUE: none | |
1393 | / | |
1394 | / MODULES CALLED: fseek(), fgets(), wmove(), waddstr(), wclrtoeol() | |
1395 | / | |
1396 | / GLOBAL INPUTS: *stdscr, Databuf[], *Messagefp | |
1397 | / | |
1398 | / GLOBAL OUTPUTS: none | |
1399 | / | |
1400 | / DESCRIPTION: | |
1401 | / If there is a message from other players, print it. | |
1402 | / | |
1403 | /************************************************************************/ | |
1404 | ||
1405 | readmessage() | |
1406 | { | |
1407 | move(3, 0); | |
1408 | clrtoeol(); | |
1409 | fseek(Messagefp, 0L, 0); | |
1410 | if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL) | |
1411 | addstr(Databuf); | |
1412 | } | |
1413 | /*\f*/ | |
1414 | /************************************************************************ | |
1415 | / | |
1416 | / FUNCTION NAME: error() | |
1417 | / | |
1418 | / FUNCTION: process evironment error | |
1419 | / | |
1420 | / AUTHOR: E. A. Estes, 12/4/85 | |
1421 | / | |
1422 | / ARGUMENTS: | |
1423 | / char *whichfile - pointer to name of file which caused error | |
1424 | / | |
1425 | / RETURN VALUE: none | |
1426 | / | |
1427 | / MODULES CALLED: wclear(), cleanup() | |
1428 | / | |
1429 | / GLOBAL INPUTS: errno, *stdscr, printw(), printf(), Windows | |
1430 | / | |
1431 | / GLOBAL OUTPUTS: none | |
1432 | / | |
1433 | / DESCRIPTION: | |
1434 | / Print message about offending file, and exit. | |
1435 | / | |
1436 | /************************************************************************/ | |
1437 | ||
1438 | error(whichfile) | |
1439 | char *whichfile; | |
1440 | { | |
1441 | extern int errno; | |
1442 | extern printw(), printf(); | |
1443 | int (*funcp)(); | |
1444 | ||
1445 | if (Windows) | |
1446 | { | |
1447 | funcp = printw; | |
1448 | clear(); | |
1449 | } | |
1450 | else | |
1451 | funcp = printf; | |
1452 | ||
1453 | (*funcp)("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno); | |
1454 | (*funcp)("Please run 'setup' to determine the problem.\n"); | |
1455 | cleanup(TRUE); | |
1456 | /*NOTREACHED*/ | |
1457 | } | |
1458 | /*\f*/ | |
1459 | /************************************************************************ | |
1460 | / | |
1461 | / FUNCTION NAME: distance() | |
1462 | / | |
1463 | / FUNCTION: calculate distance between two points | |
1464 | / | |
1465 | / AUTHOR: E. A. Estes, 12/4/85 | |
1466 | / | |
1467 | / ARGUMENTS: | |
1468 | / double x1, y1 - x, y coordinates of first point | |
1469 | / double x2, y2 - x, y coordinates of second point | |
1470 | / | |
1471 | / RETURN VALUE: distance between the two points | |
1472 | / | |
1473 | / MODULES CALLED: sqrt() | |
1474 | / | |
1475 | / GLOBAL INPUTS: none | |
1476 | / | |
1477 | / GLOBAL OUTPUTS: none | |
1478 | / | |
1479 | / DESCRIPTION: | |
1480 | / This function is provided because someone's hypot() library function | |
1481 | / fails if x1 == x2 && y1 == y2. | |
1482 | / | |
1483 | /************************************************************************/ | |
1484 | ||
1485 | double | |
1486 | distance(x1, x2, y1, y2) | |
1487 | double x1, x2, y1, y2; | |
1488 | { | |
1489 | double deltax, deltay; | |
1490 | ||
1491 | deltax = x1 - x2; | |
1492 | deltay = y1 - y2; | |
1493 | return(sqrt(deltax * deltax + deltay * deltay)); | |
1494 | } | |
1495 | ||
1496 | /*\f*/ | |
1497 | /************************************************************************ | |
1498 | / | |
1499 | / FUNCTION NAME: ill_sig() | |
1500 | / | |
1501 | / FUNCTION: exit upon trapping an illegal signal | |
1502 | / | |
1503 | / AUTHOR: E. A. Estes, 12/4/85 | |
1504 | / | |
1505 | / ARGUMENTS: | |
1506 | / int whichsig - signal which occured to cause jump to here | |
1507 | / | |
1508 | / RETURN VALUE: none | |
1509 | / | |
1510 | / MODULES CALLED: wclear(), printw(), cleanup() | |
1511 | / | |
1512 | / GLOBAL INPUTS: *stdscr | |
1513 | / | |
1514 | / GLOBAL OUTPUTS: none | |
1515 | / | |
1516 | / DESCRIPTION: | |
1517 | / When an illegal signal is caught, print a message, and cleanup. | |
1518 | / | |
1519 | /************************************************************************/ | |
1520 | ||
1521 | ill_sig(whichsig) | |
1522 | int whichsig; | |
1523 | { | |
1524 | clear(); | |
1525 | if (!(whichsig == SIGINT || whichsig == SIGQUIT)) | |
1526 | printw("Error: caught signal # %d.\n", whichsig); | |
1527 | cleanup(TRUE); | |
1528 | /*NOTREACHED*/ | |
1529 | } | |
1530 | /*\f*/ | |
1531 | /************************************************************************ | |
1532 | / | |
1533 | / FUNCTION NAME: descrstatus() | |
1534 | / | |
1535 | / FUNCTION: return a string describing the player status | |
1536 | / | |
1537 | / AUTHOR: E. A. Estes, 3/3/86 | |
1538 | / | |
1539 | / ARGUMENTS: | |
1540 | / struct player playerp - pointer to player structure to describe | |
1541 | / | |
1542 | / RETURN VALUE: string describing player's status | |
1543 | / | |
1544 | / MODULES CALLED: none | |
1545 | / | |
1546 | / GLOBAL INPUTS: none | |
1547 | / | |
1548 | / GLOBAL OUTPUTS: none | |
1549 | / | |
1550 | / DESCRIPTION: | |
1551 | / Return verbal description of player status. | |
1552 | / If player status is S_PLAYING, check for low energy and blindness. | |
1553 | / | |
1554 | /************************************************************************/ | |
1555 | ||
1556 | char * | |
1557 | descrstatus(playerp) | |
1558 | register struct player *playerp; | |
1559 | { | |
1560 | switch (playerp->p_status) | |
1561 | { | |
1562 | case S_PLAYING: | |
1563 | if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield)) | |
1564 | return("Low Energy"); | |
1565 | else if (playerp->p_blindness) | |
1566 | return("Blind"); | |
1567 | else | |
1568 | return("In game"); | |
1569 | ||
1570 | case S_CLOAKED: | |
1571 | return("Cloaked"); | |
1572 | ||
1573 | case S_INBATTLE: | |
1574 | return("In Battle"); | |
1575 | ||
1576 | case S_MONSTER: | |
1577 | return("Encounter"); | |
1578 | ||
1579 | case S_TRADING: | |
1580 | return("Trading"); | |
1581 | ||
1582 | case S_OFF: | |
1583 | return("Off"); | |
1584 | ||
1585 | case S_HUNGUP: | |
1586 | return("Hung up"); | |
1587 | ||
1588 | default: | |
1589 | return(""); | |
1590 | } | |
1591 | } | |
1592 | /*\f*/ | |
1593 | /************************************************************************ | |
1594 | / | |
1595 | / FUNCTION NAME: drandom() | |
1596 | / | |
1597 | / FUNCTION: return a random floating point number from 0.0 < 1.0 | |
1598 | / | |
1599 | / AUTHOR: E. A. Estes, 2/7/86 | |
1600 | / | |
1601 | / ARGUMENTS: none | |
1602 | / | |
1603 | / RETURN VALUE: none | |
1604 | / | |
1605 | / MODULES CALLED: random() | |
1606 | / | |
1607 | / GLOBAL INPUTS: none | |
1608 | / | |
1609 | / GLOBAL OUTPUTS: none | |
1610 | / | |
1611 | / DESCRIPTION: | |
1612 | / Convert random integer from library routine into a floating | |
1613 | / point number, and divide by the largest possible random number. | |
1614 | / We mask large integers with 32767 to handle sites that return | |
1615 | / 31 bit random integers. | |
1616 | / | |
1617 | /************************************************************************/ | |
1618 | ||
1619 | double | |
1620 | drandom() | |
1621 | { | |
1622 | if (sizeof(int) != 2) | |
1623 | /* use only low bits */ | |
1624 | return((double) (random() & 0x7fff) / 32768.0); | |
1625 | else | |
1626 | return((double) random() / 32768.0); | |
1627 | } | |
1628 | /*\f*/ | |
1629 | /************************************************************************ | |
1630 | / | |
1631 | / FUNCTION NAME: collecttaxes() | |
1632 | / | |
1633 | / FUNCTION: collect taxes from current player | |
1634 | / | |
1635 | / AUTHOR: E. A. Estes, 2/7/86 | |
1636 | / | |
1637 | / ARGUMENTS: | |
1638 | / double gold - amount of gold to tax | |
1639 | / double gems - amount of gems to tax | |
1640 | / | |
1641 | / RETURN VALUE: none | |
1642 | / | |
1643 | / MODULES CALLED: fread(), fseek(), fopen(), floor(), fwrite(), fclose() | |
1644 | / | |
1645 | / GLOBAL INPUTS: Player, Goldfile[] | |
1646 | / | |
1647 | / GLOBAL OUTPUTS: Player | |
1648 | / | |
1649 | / DESCRIPTION: | |
1650 | / Pay taxes on gold and gems. If the player does not have enough | |
1651 | / gold to pay taxes on the added gems, convert some gems to gold. | |
1652 | / Add taxes to tax data base; add remaining gold and gems to | |
1653 | / player's cache. | |
1654 | / | |
1655 | /************************************************************************/ | |
1656 | ||
1657 | collecttaxes(gold, gems) | |
1658 | double gold; | |
1659 | double gems; | |
1660 | { | |
1661 | FILE *fp; /* to update Goldfile */ | |
1662 | double dtemp; /* for temporary calculations */ | |
1663 | double taxes; /* tax liability */ | |
1664 | ||
1665 | /* add to cache */ | |
1666 | Player.p_gold += gold; | |
1667 | Player.p_gems += gems; | |
1668 | ||
1669 | /* calculate tax liability */ | |
1670 | taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold); | |
1671 | ||
1672 | if (Player.p_gold < taxes) | |
1673 | /* not enough gold to pay taxes, must convert some gems to gold */ | |
1674 | { | |
1675 | dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to convert */ | |
1676 | ||
1677 | if (Player.p_gems >= dtemp) | |
1678 | /* player has enough to convert */ | |
1679 | { | |
1680 | Player.p_gems -= dtemp; | |
1681 | Player.p_gold += dtemp * N_GEMVALUE; | |
1682 | } | |
1683 | else | |
1684 | /* take everything; this should never happen */ | |
1685 | { | |
1686 | Player.p_gold += Player.p_gems * N_GEMVALUE; | |
1687 | Player.p_gems = 0.0; | |
1688 | taxes = Player.p_gold; | |
1689 | } | |
1690 | } | |
1691 | ||
1692 | Player.p_gold -= taxes; | |
1693 | ||
1694 | if ((fp = fopen(Goldfile, "r+")) != NULL) | |
1695 | /* update taxes */ | |
1696 | { | |
1697 | dtemp = 0.0; | |
1698 | fread((char *) &dtemp, sizeof(double), 1, fp); | |
1699 | dtemp += floor(taxes); | |
1700 | fseek(fp, 0L, 0); | |
1701 | fwrite((char *) &dtemp, sizeof(double), 1, fp); | |
1702 | fclose(fp); | |
1703 | } | |
1704 | } |