1 /**
2 * \file player-calcs.c
3 * \brief Player status calculation, signalling ui events based on
4 * status changes.
5 *
6 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7 * Copyright (c) 2014 Nick McConnell
8 *
9 * This work is free software; you can redistribute it and/or modify it
10 * under the terms of either:
11 *
12 * a) the GNU General Public License as published by the Free Software
13 * Foundation, version 2, or
14 *
15 * b) the "Angband licence":
16 * This software may be copied and distributed for educational, research,
17 * and not for profit purposes provided that this copyright and statement
18 * are included in all such copies. Other copyrights may also apply.
19 */
20
21 #include "angband.h"
22 #include "cave.h"
23 #include "game-event.h"
24 #include "game-input.h"
25 #include "game-world.h"
26 #include "init.h"
27 #include "mon-msg.h"
28 #include "mon-util.h"
29 #include "obj-curse.h"
30 #include "obj-gear.h"
31 #include "obj-ignore.h"
32 #include "obj-knowledge.h"
33 #include "obj-power.h"
34 #include "obj-tval.h"
35 #include "obj-util.h"
36 #include "player-calcs.h"
37 #include "player-spell.h"
38 #include "player-timed.h"
39 #include "player-util.h"
40
41 /**
42 * Stat Table (INT) -- Magic devices
43 */
44 static const int adj_int_dev[STAT_RANGE] =
45 {
46 0 /* 3 */,
47 0 /* 4 */,
48 0 /* 5 */,
49 0 /* 6 */,
50 0 /* 7 */,
51 1 /* 8 */,
52 1 /* 9 */,
53 1 /* 10 */,
54 1 /* 11 */,
55 1 /* 12 */,
56 1 /* 13 */,
57 1 /* 14 */,
58 2 /* 15 */,
59 2 /* 16 */,
60 2 /* 17 */,
61 3 /* 18/00-18/09 */,
62 3 /* 18/10-18/19 */,
63 3 /* 18/20-18/29 */,
64 3 /* 18/30-18/39 */,
65 3 /* 18/40-18/49 */,
66 4 /* 18/50-18/59 */,
67 4 /* 18/60-18/69 */,
68 5 /* 18/70-18/79 */,
69 5 /* 18/80-18/89 */,
70 6 /* 18/90-18/99 */,
71 6 /* 18/100-18/109 */,
72 7 /* 18/110-18/119 */,
73 7 /* 18/120-18/129 */,
74 8 /* 18/130-18/139 */,
75 8 /* 18/140-18/149 */,
76 9 /* 18/150-18/159 */,
77 9 /* 18/160-18/169 */,
78 10 /* 18/170-18/179 */,
79 10 /* 18/180-18/189 */,
80 11 /* 18/190-18/199 */,
81 11 /* 18/200-18/209 */,
82 12 /* 18/210-18/219 */,
83 13 /* 18/220+ */
84 };
85
86 /**
87 * Stat Table (WIS) -- Saving throw
88 */
89 static const int adj_wis_sav[STAT_RANGE] =
90 {
91 0 /* 3 */,
92 0 /* 4 */,
93 0 /* 5 */,
94 0 /* 6 */,
95 0 /* 7 */,
96 1 /* 8 */,
97 1 /* 9 */,
98 1 /* 10 */,
99 1 /* 11 */,
100 1 /* 12 */,
101 1 /* 13 */,
102 1 /* 14 */,
103 2 /* 15 */,
104 2 /* 16 */,
105 2 /* 17 */,
106 3 /* 18/00-18/09 */,
107 3 /* 18/10-18/19 */,
108 3 /* 18/20-18/29 */,
109 3 /* 18/30-18/39 */,
110 3 /* 18/40-18/49 */,
111 4 /* 18/50-18/59 */,
112 4 /* 18/60-18/69 */,
113 5 /* 18/70-18/79 */,
114 5 /* 18/80-18/89 */,
115 6 /* 18/90-18/99 */,
116 7 /* 18/100-18/109 */,
117 8 /* 18/110-18/119 */,
118 9 /* 18/120-18/129 */,
119 10 /* 18/130-18/139 */,
120 11 /* 18/140-18/149 */,
121 12 /* 18/150-18/159 */,
122 13 /* 18/160-18/169 */,
123 14 /* 18/170-18/179 */,
124 15 /* 18/180-18/189 */,
125 16 /* 18/190-18/199 */,
126 17 /* 18/200-18/209 */,
127 18 /* 18/210-18/219 */,
128 19 /* 18/220+ */
129 };
130
131
132 /**
133 * Stat Table (DEX) -- disarming
134 */
135 static const int adj_dex_dis[STAT_RANGE] =
136 {
137 0 /* 3 */,
138 0 /* 4 */,
139 0 /* 5 */,
140 0 /* 6 */,
141 0 /* 7 */,
142 1 /* 8 */,
143 1 /* 9 */,
144 1 /* 10 */,
145 1 /* 11 */,
146 1 /* 12 */,
147 1 /* 13 */,
148 1 /* 14 */,
149 2 /* 15 */,
150 2 /* 16 */,
151 2 /* 17 */,
152 3 /* 18/00-18/09 */,
153 3 /* 18/10-18/19 */,
154 3 /* 18/20-18/29 */,
155 4 /* 18/30-18/39 */,
156 4 /* 18/40-18/49 */,
157 5 /* 18/50-18/59 */,
158 6 /* 18/60-18/69 */,
159 7 /* 18/70-18/79 */,
160 8 /* 18/80-18/89 */,
161 9 /* 18/90-18/99 */,
162 10 /* 18/100-18/109 */,
163 10 /* 18/110-18/119 */,
164 11 /* 18/120-18/129 */,
165 12 /* 18/130-18/139 */,
166 13 /* 18/140-18/149 */,
167 14 /* 18/150-18/159 */,
168 15 /* 18/160-18/169 */,
169 16 /* 18/170-18/179 */,
170 17 /* 18/180-18/189 */,
171 18 /* 18/190-18/199 */,
172 19 /* 18/200-18/209 */,
173 19 /* 18/210-18/219 */,
174 19 /* 18/220+ */
175 };
176
177
178 /**
179 * Stat Table (INT) -- disarming
180 */
181 static const int adj_int_dis[STAT_RANGE] =
182 {
183 0 /* 3 */,
184 0 /* 4 */,
185 0 /* 5 */,
186 0 /* 6 */,
187 0 /* 7 */,
188 1 /* 8 */,
189 1 /* 9 */,
190 1 /* 10 */,
191 1 /* 11 */,
192 1 /* 12 */,
193 1 /* 13 */,
194 1 /* 14 */,
195 2 /* 15 */,
196 2 /* 16 */,
197 2 /* 17 */,
198 3 /* 18/00-18/09 */,
199 3 /* 18/10-18/19 */,
200 3 /* 18/20-18/29 */,
201 4 /* 18/30-18/39 */,
202 4 /* 18/40-18/49 */,
203 5 /* 18/50-18/59 */,
204 6 /* 18/60-18/69 */,
205 7 /* 18/70-18/79 */,
206 8 /* 18/80-18/89 */,
207 9 /* 18/90-18/99 */,
208 10 /* 18/100-18/109 */,
209 10 /* 18/110-18/119 */,
210 11 /* 18/120-18/129 */,
211 12 /* 18/130-18/139 */,
212 13 /* 18/140-18/149 */,
213 14 /* 18/150-18/159 */,
214 15 /* 18/160-18/169 */,
215 16 /* 18/170-18/179 */,
216 17 /* 18/180-18/189 */,
217 18 /* 18/190-18/199 */,
218 19 /* 18/200-18/209 */,
219 19 /* 18/210-18/219 */,
220 19 /* 18/220+ */
221 };
222
223 /**
224 * Stat Table (DEX) -- bonus to ac
225 */
226 static const int adj_dex_ta[STAT_RANGE] =
227 {
228 -4 /* 3 */,
229 -3 /* 4 */,
230 -2 /* 5 */,
231 -1 /* 6 */,
232 0 /* 7 */,
233 0 /* 8 */,
234 0 /* 9 */,
235 0 /* 10 */,
236 0 /* 11 */,
237 0 /* 12 */,
238 0 /* 13 */,
239 0 /* 14 */,
240 1 /* 15 */,
241 1 /* 16 */,
242 1 /* 17 */,
243 2 /* 18/00-18/09 */,
244 2 /* 18/10-18/19 */,
245 2 /* 18/20-18/29 */,
246 2 /* 18/30-18/39 */,
247 2 /* 18/40-18/49 */,
248 3 /* 18/50-18/59 */,
249 3 /* 18/60-18/69 */,
250 3 /* 18/70-18/79 */,
251 4 /* 18/80-18/89 */,
252 5 /* 18/90-18/99 */,
253 6 /* 18/100-18/109 */,
254 7 /* 18/110-18/119 */,
255 8 /* 18/120-18/129 */,
256 9 /* 18/130-18/139 */,
257 9 /* 18/140-18/149 */,
258 10 /* 18/150-18/159 */,
259 11 /* 18/160-18/169 */,
260 12 /* 18/170-18/179 */,
261 13 /* 18/180-18/189 */,
262 14 /* 18/190-18/199 */,
263 15 /* 18/200-18/209 */,
264 15 /* 18/210-18/219 */,
265 15 /* 18/220+ */
266 };
267
268 /**
269 * Stat Table (STR) -- bonus to dam
270 */
271 const int adj_str_td[STAT_RANGE] =
272 {
273 -2 /* 3 */,
274 -2 /* 4 */,
275 -1 /* 5 */,
276 -1 /* 6 */,
277 0 /* 7 */,
278 0 /* 8 */,
279 0 /* 9 */,
280 0 /* 10 */,
281 0 /* 11 */,
282 0 /* 12 */,
283 0 /* 13 */,
284 0 /* 14 */,
285 0 /* 15 */,
286 1 /* 16 */,
287 2 /* 17 */,
288 2 /* 18/00-18/09 */,
289 2 /* 18/10-18/19 */,
290 3 /* 18/20-18/29 */,
291 3 /* 18/30-18/39 */,
292 3 /* 18/40-18/49 */,
293 3 /* 18/50-18/59 */,
294 3 /* 18/60-18/69 */,
295 4 /* 18/70-18/79 */,
296 5 /* 18/80-18/89 */,
297 5 /* 18/90-18/99 */,
298 6 /* 18/100-18/109 */,
299 7 /* 18/110-18/119 */,
300 8 /* 18/120-18/129 */,
301 9 /* 18/130-18/139 */,
302 10 /* 18/140-18/149 */,
303 11 /* 18/150-18/159 */,
304 12 /* 18/160-18/169 */,
305 13 /* 18/170-18/179 */,
306 14 /* 18/180-18/189 */,
307 15 /* 18/190-18/199 */,
308 16 /* 18/200-18/209 */,
309 18 /* 18/210-18/219 */,
310 20 /* 18/220+ */
311 };
312
313
314 /**
315 * Stat Table (DEX) -- bonus to hit
316 */
317 const int adj_dex_th[STAT_RANGE] =
318 {
319 -3 /* 3 */,
320 -2 /* 4 */,
321 -2 /* 5 */,
322 -1 /* 6 */,
323 -1 /* 7 */,
324 0 /* 8 */,
325 0 /* 9 */,
326 0 /* 10 */,
327 0 /* 11 */,
328 0 /* 12 */,
329 0 /* 13 */,
330 0 /* 14 */,
331 0 /* 15 */,
332 1 /* 16 */,
333 2 /* 17 */,
334 3 /* 18/00-18/09 */,
335 3 /* 18/10-18/19 */,
336 3 /* 18/20-18/29 */,
337 3 /* 18/30-18/39 */,
338 3 /* 18/40-18/49 */,
339 4 /* 18/50-18/59 */,
340 4 /* 18/60-18/69 */,
341 4 /* 18/70-18/79 */,
342 4 /* 18/80-18/89 */,
343 5 /* 18/90-18/99 */,
344 6 /* 18/100-18/109 */,
345 7 /* 18/110-18/119 */,
346 8 /* 18/120-18/129 */,
347 9 /* 18/130-18/139 */,
348 9 /* 18/140-18/149 */,
349 10 /* 18/150-18/159 */,
350 11 /* 18/160-18/169 */,
351 12 /* 18/170-18/179 */,
352 13 /* 18/180-18/189 */,
353 14 /* 18/190-18/199 */,
354 15 /* 18/200-18/209 */,
355 15 /* 18/210-18/219 */,
356 15 /* 18/220+ */
357 };
358
359
360 /**
361 * Stat Table (STR) -- bonus to hit
362 */
363 static const int adj_str_th[STAT_RANGE] =
364 {
365 -3 /* 3 */,
366 -2 /* 4 */,
367 -1 /* 5 */,
368 -1 /* 6 */,
369 0 /* 7 */,
370 0 /* 8 */,
371 0 /* 9 */,
372 0 /* 10 */,
373 0 /* 11 */,
374 0 /* 12 */,
375 0 /* 13 */,
376 0 /* 14 */,
377 0 /* 15 */,
378 0 /* 16 */,
379 0 /* 17 */,
380 1 /* 18/00-18/09 */,
381 1 /* 18/10-18/19 */,
382 1 /* 18/20-18/29 */,
383 1 /* 18/30-18/39 */,
384 1 /* 18/40-18/49 */,
385 1 /* 18/50-18/59 */,
386 1 /* 18/60-18/69 */,
387 2 /* 18/70-18/79 */,
388 3 /* 18/80-18/89 */,
389 4 /* 18/90-18/99 */,
390 5 /* 18/100-18/109 */,
391 6 /* 18/110-18/119 */,
392 7 /* 18/120-18/129 */,
393 8 /* 18/130-18/139 */,
394 9 /* 18/140-18/149 */,
395 10 /* 18/150-18/159 */,
396 11 /* 18/160-18/169 */,
397 12 /* 18/170-18/179 */,
398 13 /* 18/180-18/189 */,
399 14 /* 18/190-18/199 */,
400 15 /* 18/200-18/209 */,
401 15 /* 18/210-18/219 */,
402 15 /* 18/220+ */
403 };
404
405
406 /**
407 * Stat Table (STR) -- weight limit in deca-pounds
408 */
409 static const int adj_str_wgt[STAT_RANGE] =
410 {
411 5 /* 3 */,
412 6 /* 4 */,
413 7 /* 5 */,
414 8 /* 6 */,
415 9 /* 7 */,
416 10 /* 8 */,
417 11 /* 9 */,
418 12 /* 10 */,
419 13 /* 11 */,
420 14 /* 12 */,
421 15 /* 13 */,
422 16 /* 14 */,
423 17 /* 15 */,
424 18 /* 16 */,
425 19 /* 17 */,
426 20 /* 18/00-18/09 */,
427 22 /* 18/10-18/19 */,
428 24 /* 18/20-18/29 */,
429 26 /* 18/30-18/39 */,
430 28 /* 18/40-18/49 */,
431 30 /* 18/50-18/59 */,
432 30 /* 18/60-18/69 */,
433 30 /* 18/70-18/79 */,
434 30 /* 18/80-18/89 */,
435 30 /* 18/90-18/99 */,
436 30 /* 18/100-18/109 */,
437 30 /* 18/110-18/119 */,
438 30 /* 18/120-18/129 */,
439 30 /* 18/130-18/139 */,
440 30 /* 18/140-18/149 */,
441 30 /* 18/150-18/159 */,
442 30 /* 18/160-18/169 */,
443 30 /* 18/170-18/179 */,
444 30 /* 18/180-18/189 */,
445 30 /* 18/190-18/199 */,
446 30 /* 18/200-18/209 */,
447 30 /* 18/210-18/219 */,
448 30 /* 18/220+ */
449 };
450
451
452 /**
453 * Stat Table (STR) -- weapon weight limit in pounds
454 */
455 const int adj_str_hold[STAT_RANGE] =
456 {
457 4 /* 3 */,
458 5 /* 4 */,
459 6 /* 5 */,
460 7 /* 6 */,
461 8 /* 7 */,
462 10 /* 8 */,
463 12 /* 9 */,
464 14 /* 10 */,
465 16 /* 11 */,
466 18 /* 12 */,
467 20 /* 13 */,
468 22 /* 14 */,
469 24 /* 15 */,
470 26 /* 16 */,
471 28 /* 17 */,
472 30 /* 18/00-18/09 */,
473 30 /* 18/10-18/19 */,
474 35 /* 18/20-18/29 */,
475 40 /* 18/30-18/39 */,
476 45 /* 18/40-18/49 */,
477 50 /* 18/50-18/59 */,
478 55 /* 18/60-18/69 */,
479 60 /* 18/70-18/79 */,
480 65 /* 18/80-18/89 */,
481 70 /* 18/90-18/99 */,
482 80 /* 18/100-18/109 */,
483 80 /* 18/110-18/119 */,
484 80 /* 18/120-18/129 */,
485 80 /* 18/130-18/139 */,
486 80 /* 18/140-18/149 */,
487 90 /* 18/150-18/159 */,
488 90 /* 18/160-18/169 */,
489 90 /* 18/170-18/179 */,
490 90 /* 18/180-18/189 */,
491 90 /* 18/190-18/199 */,
492 100 /* 18/200-18/209 */,
493 100 /* 18/210-18/219 */,
494 100 /* 18/220+ */
495 };
496
497
498 /**
499 * Stat Table (STR) -- digging value
500 */
501 static const int adj_str_dig[STAT_RANGE] =
502 {
503 0 /* 3 */,
504 0 /* 4 */,
505 1 /* 5 */,
506 2 /* 6 */,
507 3 /* 7 */,
508 4 /* 8 */,
509 4 /* 9 */,
510 5 /* 10 */,
511 5 /* 11 */,
512 6 /* 12 */,
513 6 /* 13 */,
514 7 /* 14 */,
515 7 /* 15 */,
516 8 /* 16 */,
517 8 /* 17 */,
518 9 /* 18/00-18/09 */,
519 10 /* 18/10-18/19 */,
520 12 /* 18/20-18/29 */,
521 15 /* 18/30-18/39 */,
522 20 /* 18/40-18/49 */,
523 25 /* 18/50-18/59 */,
524 30 /* 18/60-18/69 */,
525 35 /* 18/70-18/79 */,
526 40 /* 18/80-18/89 */,
527 45 /* 18/90-18/99 */,
528 50 /* 18/100-18/109 */,
529 55 /* 18/110-18/119 */,
530 60 /* 18/120-18/129 */,
531 65 /* 18/130-18/139 */,
532 70 /* 18/140-18/149 */,
533 75 /* 18/150-18/159 */,
534 80 /* 18/160-18/169 */,
535 85 /* 18/170-18/179 */,
536 90 /* 18/180-18/189 */,
537 95 /* 18/190-18/199 */,
538 100 /* 18/200-18/209 */,
539 100 /* 18/210-18/219 */,
540 100 /* 18/220+ */
541 };
542
543
544 /**
545 * Stat Table (STR) -- help index into the "blow" table
546 */
547 const int adj_str_blow[STAT_RANGE] =
548 {
549 3 /* 3 */,
550 4 /* 4 */,
551 5 /* 5 */,
552 6 /* 6 */,
553 7 /* 7 */,
554 8 /* 8 */,
555 9 /* 9 */,
556 10 /* 10 */,
557 11 /* 11 */,
558 12 /* 12 */,
559 13 /* 13 */,
560 14 /* 14 */,
561 15 /* 15 */,
562 16 /* 16 */,
563 17 /* 17 */,
564 20 /* 18/00-18/09 */,
565 30 /* 18/10-18/19 */,
566 40 /* 18/20-18/29 */,
567 50 /* 18/30-18/39 */,
568 60 /* 18/40-18/49 */,
569 70 /* 18/50-18/59 */,
570 80 /* 18/60-18/69 */,
571 90 /* 18/70-18/79 */,
572 100 /* 18/80-18/89 */,
573 110 /* 18/90-18/99 */,
574 120 /* 18/100-18/109 */,
575 130 /* 18/110-18/119 */,
576 140 /* 18/120-18/129 */,
577 150 /* 18/130-18/139 */,
578 160 /* 18/140-18/149 */,
579 170 /* 18/150-18/159 */,
580 180 /* 18/160-18/169 */,
581 190 /* 18/170-18/179 */,
582 200 /* 18/180-18/189 */,
583 210 /* 18/190-18/199 */,
584 220 /* 18/200-18/209 */,
585 230 /* 18/210-18/219 */,
586 240 /* 18/220+ */
587 };
588
589
590 /**
591 * Stat Table (DEX) -- index into the "blow" table
592 */
593 static const int adj_dex_blow[STAT_RANGE] =
594 {
595 0 /* 3 */,
596 0 /* 4 */,
597 0 /* 5 */,
598 0 /* 6 */,
599 0 /* 7 */,
600 0 /* 8 */,
601 0 /* 9 */,
602 1 /* 10 */,
603 1 /* 11 */,
604 1 /* 12 */,
605 1 /* 13 */,
606 1 /* 14 */,
607 1 /* 15 */,
608 1 /* 16 */,
609 2 /* 17 */,
610 2 /* 18/00-18/09 */,
611 2 /* 18/10-18/19 */,
612 3 /* 18/20-18/29 */,
613 3 /* 18/30-18/39 */,
614 4 /* 18/40-18/49 */,
615 4 /* 18/50-18/59 */,
616 5 /* 18/60-18/69 */,
617 5 /* 18/70-18/79 */,
618 6 /* 18/80-18/89 */,
619 6 /* 18/90-18/99 */,
620 7 /* 18/100-18/109 */,
621 7 /* 18/110-18/119 */,
622 8 /* 18/120-18/129 */,
623 8 /* 18/130-18/139 */,
624 8 /* 18/140-18/149 */,
625 9 /* 18/150-18/159 */,
626 9 /* 18/160-18/169 */,
627 9 /* 18/170-18/179 */,
628 10 /* 18/180-18/189 */,
629 10 /* 18/190-18/199 */,
630 11 /* 18/200-18/209 */,
631 11 /* 18/210-18/219 */,
632 11 /* 18/220+ */
633 };
634
635
636 /**
637 * Stat Table (DEX) -- chance of avoiding "theft" and "falling"
638 */
639 const int adj_dex_safe[STAT_RANGE] =
640 {
641 0 /* 3 */,
642 1 /* 4 */,
643 2 /* 5 */,
644 3 /* 6 */,
645 4 /* 7 */,
646 5 /* 8 */,
647 5 /* 9 */,
648 6 /* 10 */,
649 6 /* 11 */,
650 7 /* 12 */,
651 7 /* 13 */,
652 8 /* 14 */,
653 8 /* 15 */,
654 9 /* 16 */,
655 9 /* 17 */,
656 10 /* 18/00-18/09 */,
657 10 /* 18/10-18/19 */,
658 15 /* 18/20-18/29 */,
659 15 /* 18/30-18/39 */,
660 20 /* 18/40-18/49 */,
661 25 /* 18/50-18/59 */,
662 30 /* 18/60-18/69 */,
663 35 /* 18/70-18/79 */,
664 40 /* 18/80-18/89 */,
665 45 /* 18/90-18/99 */,
666 50 /* 18/100-18/109 */,
667 60 /* 18/110-18/119 */,
668 70 /* 18/120-18/129 */,
669 80 /* 18/130-18/139 */,
670 90 /* 18/140-18/149 */,
671 100 /* 18/150-18/159 */,
672 100 /* 18/160-18/169 */,
673 100 /* 18/170-18/179 */,
674 100 /* 18/180-18/189 */,
675 100 /* 18/190-18/199 */,
676 100 /* 18/200-18/209 */,
677 100 /* 18/210-18/219 */,
678 100 /* 18/220+ */
679 };
680
681
682 /**
683 * Stat Table (CON) -- base regeneration rate
684 */
685 const int adj_con_fix[STAT_RANGE] =
686 {
687 0 /* 3 */,
688 0 /* 4 */,
689 0 /* 5 */,
690 0 /* 6 */,
691 0 /* 7 */,
692 0 /* 8 */,
693 0 /* 9 */,
694 0 /* 10 */,
695 0 /* 11 */,
696 0 /* 12 */,
697 0 /* 13 */,
698 1 /* 14 */,
699 1 /* 15 */,
700 1 /* 16 */,
701 1 /* 17 */,
702 2 /* 18/00-18/09 */,
703 2 /* 18/10-18/19 */,
704 2 /* 18/20-18/29 */,
705 2 /* 18/30-18/39 */,
706 2 /* 18/40-18/49 */,
707 3 /* 18/50-18/59 */,
708 3 /* 18/60-18/69 */,
709 3 /* 18/70-18/79 */,
710 3 /* 18/80-18/89 */,
711 3 /* 18/90-18/99 */,
712 4 /* 18/100-18/109 */,
713 4 /* 18/110-18/119 */,
714 5 /* 18/120-18/129 */,
715 6 /* 18/130-18/139 */,
716 6 /* 18/140-18/149 */,
717 7 /* 18/150-18/159 */,
718 7 /* 18/160-18/169 */,
719 8 /* 18/170-18/179 */,
720 8 /* 18/180-18/189 */,
721 8 /* 18/190-18/199 */,
722 9 /* 18/200-18/209 */,
723 9 /* 18/210-18/219 */,
724 9 /* 18/220+ */
725 };
726
727
728 /**
729 * Stat Table (CON) -- extra 1/100th hitpoints per level
730 */
731 static const int adj_con_mhp[STAT_RANGE] =
732 {
733 -250 /* 3 */,
734 -150 /* 4 */,
735 -100 /* 5 */,
736 -75 /* 6 */,
737 -50 /* 7 */,
738 -25 /* 8 */,
739 -10 /* 9 */,
740 -5 /* 10 */,
741 0 /* 11 */,
742 5 /* 12 */,
743 10 /* 13 */,
744 25 /* 14 */,
745 50 /* 15 */,
746 75 /* 16 */,
747 100 /* 17 */,
748 150 /* 18/00-18/09 */,
749 175 /* 18/10-18/19 */,
750 200 /* 18/20-18/29 */,
751 225 /* 18/30-18/39 */,
752 250 /* 18/40-18/49 */,
753 275 /* 18/50-18/59 */,
754 300 /* 18/60-18/69 */,
755 350 /* 18/70-18/79 */,
756 400 /* 18/80-18/89 */,
757 450 /* 18/90-18/99 */,
758 500 /* 18/100-18/109 */,
759 550 /* 18/110-18/119 */,
760 600 /* 18/120-18/129 */,
761 650 /* 18/130-18/139 */,
762 700 /* 18/140-18/149 */,
763 750 /* 18/150-18/159 */,
764 800 /* 18/160-18/169 */,
765 900 /* 18/170-18/179 */,
766 1000 /* 18/180-18/189 */,
767 1100 /* 18/190-18/199 */,
768 1250 /* 18/200-18/209 */,
769 1250 /* 18/210-18/219 */,
770 1250 /* 18/220+ */
771 };
772
773 static const int adj_mag_study[STAT_RANGE] =
774 {
775 0 /* 3 */,
776 0 /* 4 */,
777 10 /* 5 */,
778 20 /* 6 */,
779 30 /* 7 */,
780 40 /* 8 */,
781 50 /* 9 */,
782 60 /* 10 */,
783 70 /* 11 */,
784 80 /* 12 */,
785 85 /* 13 */,
786 90 /* 14 */,
787 95 /* 15 */,
788 100 /* 16 */,
789 105 /* 17 */,
790 110 /* 18/00-18/09 */,
791 115 /* 18/10-18/19 */,
792 120 /* 18/20-18/29 */,
793 130 /* 18/30-18/39 */,
794 140 /* 18/40-18/49 */,
795 150 /* 18/50-18/59 */,
796 160 /* 18/60-18/69 */,
797 170 /* 18/70-18/79 */,
798 180 /* 18/80-18/89 */,
799 190 /* 18/90-18/99 */,
800 200 /* 18/100-18/109 */,
801 210 /* 18/110-18/119 */,
802 220 /* 18/120-18/129 */,
803 230 /* 18/130-18/139 */,
804 240 /* 18/140-18/149 */,
805 250 /* 18/150-18/159 */,
806 250 /* 18/160-18/169 */,
807 250 /* 18/170-18/179 */,
808 250 /* 18/180-18/189 */,
809 250 /* 18/190-18/199 */,
810 250 /* 18/200-18/209 */,
811 250 /* 18/210-18/219 */,
812 250 /* 18/220+ */
813 };
814
815 /**
816 * Stat Table (INT/WIS) -- extra 1/100 mana-points per level
817 */
818 static const int adj_mag_mana[STAT_RANGE] =
819 {
820 0 /* 3 */,
821 10 /* 4 */,
822 20 /* 5 */,
823 30 /* 6 */,
824 40 /* 7 */,
825 50 /* 8 */,
826 60 /* 9 */,
827 70 /* 10 */,
828 80 /* 11 */,
829 90 /* 12 */,
830 100 /* 13 */,
831 110 /* 14 */,
832 120 /* 15 */,
833 130 /* 16 */,
834 140 /* 17 */,
835 150 /* 18/00-18/09 */,
836 160 /* 18/10-18/19 */,
837 170 /* 18/20-18/29 */,
838 180 /* 18/30-18/39 */,
839 190 /* 18/40-18/49 */,
840 200 /* 18/50-18/59 */,
841 225 /* 18/60-18/69 */,
842 250 /* 18/70-18/79 */,
843 300 /* 18/80-18/89 */,
844 350 /* 18/90-18/99 */,
845 400 /* 18/100-18/109 */,
846 450 /* 18/110-18/119 */,
847 500 /* 18/120-18/129 */,
848 550 /* 18/130-18/139 */,
849 600 /* 18/140-18/149 */,
850 650 /* 18/150-18/159 */,
851 700 /* 18/160-18/169 */,
852 750 /* 18/170-18/179 */,
853 800 /* 18/180-18/189 */,
854 800 /* 18/190-18/199 */,
855 800 /* 18/200-18/209 */,
856 800 /* 18/210-18/219 */,
857 800 /* 18/220+ */
858 };
859
860 /**
861 * This table is used to help calculate the number of blows the player can
862 * make in a single round of attacks (one player turn) with a normal weapon.
863 *
864 * This number ranges from a single blow/round for weak players to up to six
865 * blows/round for powerful warriors.
866 *
867 * Note that certain artifacts and ego-items give "bonus" blows/round.
868 *
869 * First, from the player class, we extract some values:
870 *
871 * Warrior --> num = 6; mul = 5; div = MAX(30, weapon_weight);
872 * Mage --> num = 4; mul = 2; div = MAX(40, weapon_weight);
873 * Priest --> num = 4; mul = 3; div = MAX(35, weapon_weight);
874 * Rogue --> num = 5; mul = 4; div = MAX(30, weapon_weight);
875 * Ranger --> num = 5; mul = 4; div = MAX(35, weapon_weight);
876 * Paladin --> num = 5; mul = 5; div = MAX(30, weapon_weight);
877 * (all specified in class.txt now)
878 *
879 * To get "P", we look up the relevant "adj_str_blow[]" (see above),
880 * multiply it by "mul", and then divide it by "div", rounding down.
881 *
882 * To get "D", we look up the relevant "adj_dex_blow[]" (see above).
883 *
884 * Then we look up the energy cost of each blow using "blows_table[P][D]".
885 * The player gets blows/round equal to 100/this number, up to a maximum of
886 * "num" blows/round, plus any "bonus" blows/round.
887 */
888 static const int blows_table[12][12] =
889 {
890 /* P */
891 /* D: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11+ */
892 /* DEX: 3, 10, 17, /20, /40, /60, /80, /100,/120,/150,/180,/200 */
893
894 /* 0 */
895 { 100, 100, 95, 85, 75, 60, 50, 42, 35, 30, 25, 23 },
896
897 /* 1 */
898 { 100, 95, 85, 75, 60, 50, 42, 35, 30, 25, 23, 21 },
899
900 /* 2 */
901 { 95, 85, 75, 60, 50, 42, 35, 30, 26, 23, 21, 20 },
902
903 /* 3 */
904 { 85, 75, 60, 50, 42, 36, 32, 28, 25, 22, 20, 19 },
905
906 /* 4 */
907 { 75, 60, 50, 42, 36, 33, 28, 25, 23, 21, 19, 18 },
908
909 /* 5 */
910 { 60, 50, 42, 36, 33, 30, 27, 24, 22, 21, 19, 17 },
911
912 /* 6 */
913 { 50, 42, 36, 33, 30, 27, 25, 23, 21, 20, 18, 17 },
914
915 /* 7 */
916 { 42, 36, 33, 30, 28, 26, 24, 22, 20, 19, 18, 17 },
917
918 /* 8 */
919 { 36, 33, 30, 28, 26, 24, 22, 21, 20, 19, 17, 16 },
920
921 /* 9 */
922 { 35, 32, 29, 26, 24, 22, 21, 20, 19, 18, 17, 16 },
923
924 /* 10 */
925 { 34, 30, 27, 25, 23, 22, 21, 20, 19, 18, 17, 16 },
926
927 /* 11+ */
928 { 33, 29, 26, 24, 22, 21, 20, 19, 18, 17, 16, 15 },
929 /* DEX: 3, 10, 17, /20, /40, /60, /80, /100,/120,/150,/180,/200 */
930 };
931
932 /**
933 * Decide which object comes earlier in the standard inventory listing,
934 * defaulting to the first if nothing separates them.
935 *
936 * \return whether to replace the original object with the new one
937 */
earlier_object(struct object * orig,struct object * new,bool store)938 bool earlier_object(struct object *orig, struct object *new, bool store)
939 {
940 /* Check we have actual objects */
941 if (!new) return false;
942 if (!orig) return true;
943
944 if (!store) {
945 /* Readable books always come first */
946 if (obj_can_browse(orig) && !obj_can_browse(new)) return false;
947 if (!obj_can_browse(orig) && obj_can_browse(new)) return true;
948 }
949
950 /* Usable ammo is before other ammo */
951 if (tval_is_ammo(orig) && tval_is_ammo(new)) {
952 /* First favour usable ammo */
953 if ((player->state.ammo_tval == orig->tval) &&
954 (player->state.ammo_tval != new->tval))
955 return false;
956 if ((player->state.ammo_tval != orig->tval) &&
957 (player->state.ammo_tval == new->tval))
958 return true;
959 }
960
961 /* Objects sort by decreasing type */
962 if (orig->tval > new->tval) return false;
963 if (orig->tval < new->tval) return true;
964
965 if (!store) {
966 /* Non-aware (flavored) items always come last (default to orig) */
967 if (!object_flavor_is_aware(new)) return false;
968 if (!object_flavor_is_aware(orig)) return true;
969 }
970
971 /* Objects sort by increasing sval */
972 if (orig->sval < new->sval) return false;
973 if (orig->sval > new->sval) return true;
974
975 if (!store) {
976 /* Unaware objects always come last (default to orig) */
977 if (new->kind->flavor && !object_flavor_is_aware(new)) return false;
978 if (orig->kind->flavor && !object_flavor_is_aware(orig)) return true;
979
980 /* Lights sort by decreasing fuel */
981 if (tval_is_light(orig)) {
982 if (orig->pval > new->pval) return false;
983 if (orig->pval < new->pval) return true;
984 }
985 }
986
987 /* Objects sort by decreasing value, except ammo */
988 if (tval_is_ammo(orig)) {
989 if (object_value(orig, 1) < object_value(new, 1))
990 return false;
991 if (object_value(orig, 1) > object_value(new, 1))
992 return true;
993 } else {
994 if (object_value(orig, 1) > object_value(new, 1))
995 return false;
996 if (object_value(orig, 1) < object_value(new, 1))
997 return true;
998 }
999
1000 /* No preference */
1001 return false;
1002 }
1003
equipped_item_slot(struct player_body body,struct object * item)1004 int equipped_item_slot(struct player_body body, struct object *item)
1005 {
1006 int i;
1007
1008 if (item == NULL) return body.count;
1009
1010 /* Look for an equipment slot with this item */
1011 for (i = 0; i < body.count; i++)
1012 if (item == body.slots[i].obj) break;
1013
1014 /* Correct slot, or body.count if not equipped */
1015 return i;
1016 }
1017
1018 /**
1019 * Put the player's inventory and quiver into easily accessible arrays. The
1020 * pack may be overfull by one item
1021 */
calc_inventory(struct player_upkeep * upkeep,struct object * gear,struct player_body body)1022 void calc_inventory(struct player_upkeep *upkeep, struct object *gear,
1023 struct player_body body)
1024 {
1025 int i;
1026 int old_inven_cnt = upkeep->inven_cnt;
1027 struct object **old_quiver = mem_zalloc(z_info->quiver_size *
1028 sizeof(struct object *));
1029 struct object **old_pack = mem_zalloc(z_info->pack_size *
1030 sizeof(struct object *));
1031
1032 /* Prepare to fill the quiver */
1033 upkeep->quiver_cnt = 0;
1034
1035 /* Copy the current quiver */
1036 for (i = 0; i < z_info->quiver_size; i++)
1037 if (upkeep->quiver[i])
1038 old_quiver[i] = upkeep->quiver[i];
1039 else
1040 old_quiver[i] = NULL;
1041
1042 /* First, allocate inscribed items */
1043 for (i = 0; i < z_info->quiver_size; i++) {
1044 struct object *current;
1045
1046 /* Start with an empty slot */
1047 upkeep->quiver[i] = NULL;
1048
1049 /* Find the first quiver object with the correct label */
1050 for (current = gear; current; current = current->next) {
1051 bool throwing = of_has(current->flags, OF_THROWING);
1052
1053 /* Only allow ammo and throwing weapons */
1054 if (!(tval_is_ammo(current) || throwing)) continue;
1055
1056 /* Allocate inscribed objects if it's the right slot */
1057 if (current->note) {
1058 const char *s = strchr(quark_str(current->note), '@');
1059 if (s && (s[1] == 'f' || s[1] == 'v')) {
1060 int choice = s[2] - '0';
1061
1062 /* Correct slot, fill it straight away */
1063 if (choice == i) {
1064 int mult = tval_is_ammo(current) ? 1 : 5;
1065 upkeep->quiver[i] = current;
1066 upkeep->quiver_cnt += current->number * mult;
1067
1068 /* In the quiver counts as worn */
1069 object_learn_on_wield(player, current);
1070
1071 /* Done with this slot */
1072 break;
1073 }
1074 }
1075 }
1076 }
1077 }
1078
1079 /* Now fill the rest of the slots in order */
1080 for (i = 0; i < z_info->quiver_size; i++) {
1081 struct object *current, *first = NULL;
1082 int j;
1083
1084 /* If the slot is full, move on */
1085 if (upkeep->quiver[i]) continue;
1086
1087 /* Find the first quiver object not yet allocated */
1088 for (current = gear; current; current = current->next) {
1089 bool already = false;
1090
1091 /* Ignore non-ammo */
1092 if (!tval_is_ammo(current)) continue;
1093
1094 /* Ignore stuff already quivered */
1095 for (j = 0; j < z_info->quiver_size; j++)
1096 if (upkeep->quiver[j] == current)
1097 already = true;
1098 if (already) continue;
1099
1100 /* Choose the first in order */
1101 if (earlier_object(first, current, false)) {
1102 first = current;
1103 }
1104 }
1105
1106 /* Stop looking if there's nothing left */
1107 if (!first) break;
1108
1109 /* If we have an item, slot it */
1110 upkeep->quiver[i] = first;
1111 upkeep->quiver_cnt += first->number;
1112
1113 /* In the quiver counts as worn */
1114 object_learn_on_wield(player, first);
1115 }
1116
1117 /* Note reordering */
1118 if (character_dungeon)
1119 for (i = 0; i < z_info->quiver_size; i++)
1120 if (old_quiver[i] && (upkeep->quiver[i] != old_quiver[i])) {
1121 msg("You re-arrange your quiver.");
1122 break;
1123 }
1124
1125 /* Copy the current pack */
1126 for (i = 0; i < z_info->pack_size; i++)
1127 old_pack[i] = upkeep->inven[i];
1128
1129 /* Prepare to fill the inventory */
1130 upkeep->inven_cnt = 0;
1131
1132 for (i = 0; i <= z_info->pack_size; i++) {
1133 struct object *current, *first = NULL;
1134 for (current = gear; current; current = current->next) {
1135 bool possible = true;
1136 int j;
1137
1138 /* Skip equipment */
1139 if (object_is_equipped(body, current))
1140 possible = false;
1141
1142 /* Skip quivered objects */
1143 for (j = 0; j < z_info->quiver_size; j++)
1144 if (upkeep->quiver[j] == current)
1145 possible = false;
1146
1147 /* Skip objects already allocated to the inventory */
1148 for (j = 0; j < upkeep->inven_cnt; j++)
1149 if (upkeep->inven[j] == current)
1150 possible = false;
1151
1152 /* If still possible, choose the first in order */
1153 if (!possible)
1154 continue;
1155 else if (earlier_object(first, current, false)) {
1156 first = current;
1157 }
1158 }
1159
1160 /* Allocate */
1161 upkeep->inven[i] = first;
1162 if (first)
1163 upkeep->inven_cnt++;
1164 }
1165
1166 /* Note reordering */
1167 if (character_dungeon && (upkeep->inven_cnt == old_inven_cnt))
1168 for (i = 0; i < z_info->pack_size; i++)
1169 if (old_pack[i] && (upkeep->inven[i] != old_pack[i]) &&
1170 !object_is_equipped(body, old_pack[i])) {
1171 msg("You re-arrange your pack.");
1172 break;
1173 }
1174
1175 mem_free(old_quiver);
1176 mem_free(old_pack);
1177 }
1178
update_inventory(struct player * p)1179 static void update_inventory(struct player *p)
1180 {
1181 calc_inventory(p->upkeep, p->gear, p->body);
1182 }
1183
1184 /**
1185 * Average of the player's spell stats across all the realms they can cast
1186 * from, rounded up
1187 *
1188 * If the player can only cast from a single realm, this is simple the stat
1189 * for that realm
1190 */
average_spell_stat(struct player * p,struct player_state * state)1191 static int average_spell_stat(struct player *p, struct player_state *state)
1192 {
1193 int i, count, sum = 0;
1194 struct magic_realm *realm = class_magic_realms(p->class, &count), *r_next;
1195
1196 for (i = count; i > 0; i--) {
1197 sum += state->stat_ind[realm->stat];
1198 r_next = realm->next;
1199 mem_free(realm);
1200 realm = r_next;
1201 }
1202 return (sum + count - 1) / count;
1203 }
1204
1205 /**
1206 * Calculate number of spells player should have, and forget,
1207 * or remember, spells until that number is properly reflected.
1208 *
1209 * Note that this function induces various "status" messages,
1210 * which must be bypasses until the character is created.
1211 */
calc_spells(struct player * p)1212 static void calc_spells(struct player *p)
1213 {
1214 int i, j, k, levels;
1215 int num_allowed, num_known, num_total = p->class->magic.total_spells;
1216 int percent_spells;
1217
1218 const struct class_spell *spell;
1219
1220 s16b old_spells;
1221
1222 /* Hack -- must be literate */
1223 if (!p->class->magic.total_spells) return;
1224
1225 /* Hack -- wait for creation */
1226 if (!character_generated) return;
1227
1228 /* Hack -- handle partial mode */
1229 if (p->upkeep->only_partial) return;
1230
1231 /* Save the new_spells value */
1232 old_spells = p->upkeep->new_spells;
1233
1234 /* Determine the number of spells allowed */
1235 levels = p->lev - p->class->magic.spell_first + 1;
1236
1237 /* Hack -- no negative spells */
1238 if (levels < 0) levels = 0;
1239
1240 /* Number of 1/100 spells per level (or something - needs clarifying) */
1241 percent_spells = adj_mag_study[average_spell_stat(p, &p->state)];
1242
1243 /* Extract total allowed spells (rounded up) */
1244 num_allowed = (((percent_spells * levels) + 50) / 100);
1245
1246 /* Assume none known */
1247 num_known = 0;
1248
1249 /* Count the number of spells we know */
1250 for (j = 0; j < num_total; j++)
1251 if (p->spell_flags[j] & PY_SPELL_LEARNED)
1252 num_known++;
1253
1254 /* See how many spells we must forget or may learn */
1255 p->upkeep->new_spells = num_allowed - num_known;
1256
1257 /* Forget spells which are too hard */
1258 for (i = num_total - 1; i >= 0; i--) {
1259 /* Get the spell */
1260 j = p->spell_order[i];
1261
1262 /* Skip non-spells */
1263 if (j >= 99) continue;
1264
1265 /* Get the spell */
1266 spell = spell_by_index(j);
1267
1268 /* Skip spells we are allowed to know */
1269 if (spell->slevel <= p->lev) continue;
1270
1271 /* Is it known? */
1272 if (p->spell_flags[j] & PY_SPELL_LEARNED) {
1273 /* Mark as forgotten */
1274 p->spell_flags[j] |= PY_SPELL_FORGOTTEN;
1275
1276 /* No longer known */
1277 p->spell_flags[j] &= ~PY_SPELL_LEARNED;
1278
1279 /* Message */
1280 msg("You have forgotten the %s of %s.", spell->realm->spell_noun,
1281 spell->name);
1282
1283 /* One more can be learned */
1284 p->upkeep->new_spells++;
1285 }
1286 }
1287
1288 /* Forget spells if we know too many spells */
1289 for (i = num_total - 1; i >= 0; i--) {
1290 /* Stop when possible */
1291 if (p->upkeep->new_spells >= 0) break;
1292
1293 /* Get the (i+1)th spell learned */
1294 j = p->spell_order[i];
1295
1296 /* Skip unknown spells */
1297 if (j >= 99) continue;
1298
1299 /* Get the spell */
1300 spell = spell_by_index(j);
1301
1302 /* Forget it (if learned) */
1303 if (p->spell_flags[j] & PY_SPELL_LEARNED) {
1304 /* Mark as forgotten */
1305 p->spell_flags[j] |= PY_SPELL_FORGOTTEN;
1306
1307 /* No longer known */
1308 p->spell_flags[j] &= ~PY_SPELL_LEARNED;
1309
1310 /* Message */
1311 msg("You have forgotten the %s of %s.", spell->realm->spell_noun,
1312 spell->name);
1313
1314 /* One more can be learned */
1315 p->upkeep->new_spells++;
1316 }
1317 }
1318
1319 /* Check for spells to remember */
1320 for (i = 0; i < num_total; i++) {
1321 /* None left to remember */
1322 if (p->upkeep->new_spells <= 0) break;
1323
1324 /* Get the next spell we learned */
1325 j = p->spell_order[i];
1326
1327 /* Skip unknown spells */
1328 if (j >= 99) break;
1329
1330 /* Get the spell */
1331 spell = spell_by_index(j);
1332
1333 /* Skip spells we cannot remember */
1334 if (spell->slevel > p->lev) continue;
1335
1336 /* First set of spells */
1337 if (p->spell_flags[j] & PY_SPELL_FORGOTTEN) {
1338 /* No longer forgotten */
1339 p->spell_flags[j] &= ~PY_SPELL_FORGOTTEN;
1340
1341 /* Known once more */
1342 p->spell_flags[j] |= PY_SPELL_LEARNED;
1343
1344 /* Message */
1345 msg("You have remembered the %s of %s.", spell->realm->spell_noun,
1346 spell->name);
1347
1348 /* One less can be learned */
1349 p->upkeep->new_spells--;
1350 }
1351 }
1352
1353 /* Assume no spells available */
1354 k = 0;
1355
1356 /* Count spells that can be learned */
1357 for (j = 0; j < num_total; j++) {
1358 /* Get the spell */
1359 spell = spell_by_index(j);
1360
1361 /* Skip spells we cannot remember or don't exist */
1362 if (!spell) continue;
1363 if (spell->slevel > p->lev || spell->slevel == 0) continue;
1364
1365 /* Skip spells we already know */
1366 if (p->spell_flags[j] & PY_SPELL_LEARNED)
1367 continue;
1368
1369 /* Count it */
1370 k++;
1371 }
1372
1373 /* Cannot learn more spells than exist */
1374 if (p->upkeep->new_spells > k) p->upkeep->new_spells = k;
1375
1376 /* Spell count changed */
1377 if (old_spells != p->upkeep->new_spells) {
1378 /* Message if needed */
1379 if (p->upkeep->new_spells) {
1380 int count;
1381 struct magic_realm *r = class_magic_realms(p->class, &count), *r1;
1382 char buf[120];
1383
1384 my_strcpy(buf, r->spell_noun, sizeof(buf));
1385 if (p->upkeep->new_spells > 1) {
1386 my_strcat(buf, "s", sizeof(buf));
1387 }
1388 r1 = r->next;
1389 mem_free(r);
1390 r = r1;
1391 if (count > 1) {
1392 while (r) {
1393 count--;
1394 if (count) {
1395 my_strcat(buf, ", ", sizeof(buf));
1396 } else {
1397 my_strcat(buf, " or ", sizeof(buf));
1398 }
1399 my_strcat(buf, r->spell_noun, sizeof(buf));
1400 if (p->upkeep->new_spells > 1) {
1401 my_strcat(buf, "s", sizeof(buf));
1402 }
1403 r1 = r->next;
1404 mem_free(r);
1405 r = r1;
1406 }
1407 }
1408 /* Message */
1409 msg("You can learn %d more %s.", p->upkeep->new_spells, buf);
1410 }
1411
1412 /* Redraw Study Status */
1413 p->upkeep->redraw |= (PR_STUDY | PR_OBJECT);
1414 }
1415 }
1416
1417
1418 /**
1419 * Calculate maximum mana. You do not need to know any spells.
1420 * Note that mana is lowered by heavy (or inappropriate) armor.
1421 *
1422 * This function induces status messages.
1423 */
calc_mana(struct player * p,struct player_state * state,bool update)1424 static void calc_mana(struct player *p, struct player_state *state, bool update)
1425 {
1426 int i, msp, levels, cur_wgt, max_wgt;
1427
1428 /* Must be literate */
1429 if (!p->class->magic.total_spells) {
1430 p->msp = 0;
1431 p->csp = 0;
1432 p->csp_frac = 0;
1433 return;
1434 }
1435
1436 /* Extract "effective" player level */
1437 levels = (p->lev - p->class->magic.spell_first) + 1;
1438 if (levels > 0) {
1439 msp = 1;
1440 msp += adj_mag_mana[average_spell_stat(p, state)] * levels / 100;
1441 } else {
1442 levels = 0;
1443 msp = 0;
1444 }
1445
1446 /* Assume player not encumbered by armor */
1447 state->cumber_armor = false;
1448
1449 /* Weigh the armor */
1450 cur_wgt = 0;
1451 for (i = 0; i < p->body.count; i++) {
1452 struct object *obj_local = slot_object(p, i);
1453
1454 /* Ignore non-armor */
1455 if (slot_type_is(i, EQUIP_WEAPON)) continue;
1456 if (slot_type_is(i, EQUIP_BOW)) continue;
1457 if (slot_type_is(i, EQUIP_RING)) continue;
1458 if (slot_type_is(i, EQUIP_AMULET)) continue;
1459 if (slot_type_is(i, EQUIP_LIGHT)) continue;
1460
1461 /* Add weight */
1462 if (obj_local)
1463 cur_wgt += obj_local->weight;
1464 }
1465
1466 /* Determine the weight allowance */
1467 max_wgt = p->class->magic.spell_weight;
1468
1469 /* Heavy armor penalizes mana */
1470 if (((cur_wgt - max_wgt) / 10) > 0) {
1471 /* Encumbered */
1472 state->cumber_armor = true;
1473
1474 /* Reduce mana */
1475 msp -= ((cur_wgt - max_wgt) / 10);
1476 }
1477
1478 /* Mana can never be negative */
1479 if (msp < 0) msp = 0;
1480
1481 /* Return if no updates */
1482 if (!update) return;
1483
1484 /* Maximum mana has changed */
1485 if (p->msp != msp) {
1486 /* Save new limit */
1487 p->msp = msp;
1488
1489 /* Enforce new limit */
1490 if (p->csp >= msp) {
1491 p->csp = msp;
1492 p->csp_frac = 0;
1493 }
1494
1495 /* Display mana later */
1496 p->upkeep->redraw |= (PR_MANA);
1497 }
1498 }
1499
1500
1501 /**
1502 * Calculate the players (maximal) hit points
1503 *
1504 * Adjust current hitpoints if necessary
1505 */
calc_hitpoints(struct player * p)1506 static void calc_hitpoints(struct player *p)
1507 {
1508 long bonus;
1509 int mhp;
1510
1511 /* Get "1/100th hitpoint bonus per level" value */
1512 bonus = adj_con_mhp[p->state.stat_ind[STAT_CON]];
1513
1514 /* Calculate hitpoints */
1515 mhp = p->player_hp[p->lev-1] + (bonus * p->lev / 100);
1516
1517 /* Always have at least one hitpoint per level */
1518 if (mhp < p->lev + 1) mhp = p->lev + 1;
1519
1520 /* New maximum hitpoints */
1521 if (p->mhp != mhp) {
1522 /* Save new limit */
1523 p->mhp = mhp;
1524
1525 /* Enforce new limit */
1526 if (p->chp >= mhp) {
1527 p->chp = mhp;
1528 p->chp_frac = 0;
1529 }
1530
1531 /* Display hitpoints (later) */
1532 p->upkeep->redraw |= (PR_HP);
1533 }
1534 }
1535
1536
1537 /**
1538 * Calculate and set the current light radius.
1539 *
1540 * The light radius will be the total of all lights carried.
1541 */
calc_light(struct player * p,struct player_state * state,bool update)1542 static void calc_light(struct player *p, struct player_state *state,
1543 bool update)
1544 {
1545 int i;
1546
1547 /* Assume no light */
1548 state->cur_light = 0;
1549
1550 /* Ascertain lightness if in the town */
1551 if (!p->depth && is_daytime() && update) {
1552 /* Update the visuals if necessary*/
1553 if (p->state.cur_light != state->cur_light)
1554 p->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
1555
1556 return;
1557 }
1558
1559 /* Examine all wielded objects, use the brightest */
1560 for (i = 0; i < p->body.count; i++) {
1561 int amt = 0;
1562 struct object *obj = slot_object(p, i);
1563
1564 /* Skip empty slots */
1565 if (!obj) continue;
1566
1567 /* Light radius - innate plus modifier */
1568 if (of_has(obj->flags, OF_LIGHT_2)) {
1569 amt = 2;
1570 } else if (of_has(obj->flags, OF_LIGHT_3)) {
1571 amt = 3;
1572 }
1573 amt += obj->modifiers[OBJ_MOD_LIGHT];
1574
1575 /* Adjustment to allow UNLIGHT players to use +1 LIGHT gear */
1576 if ((obj->modifiers[OBJ_MOD_LIGHT] > 0) && player_has(p, PF_UNLIGHT)) {
1577 amt--;
1578 }
1579
1580 /* Examine actual lights */
1581 if (tval_is_light(obj) && !of_has(obj->flags, OF_NO_FUEL) &&
1582 obj->timeout == 0)
1583 /* Lights without fuel provide no light */
1584 amt = 0;
1585
1586 /* Alter p->state.cur_light if reasonable */
1587 state->cur_light += amt;
1588 }
1589 }
1590
1591 /**
1592 * Populates `chances` with the player's chance of digging through
1593 * the diggable terrain types in one turn out of 1600.
1594 */
calc_digging_chances(struct player_state * state,int chances[DIGGING_MAX])1595 void calc_digging_chances(struct player_state *state, int chances[DIGGING_MAX])
1596 {
1597 int i;
1598
1599 chances[DIGGING_RUBBLE] = state->skills[SKILL_DIGGING] * 8;
1600 chances[DIGGING_MAGMA] = (state->skills[SKILL_DIGGING] - 10) * 4;
1601 chances[DIGGING_QUARTZ] = (state->skills[SKILL_DIGGING] - 20) * 2;
1602 chances[DIGGING_GRANITE] = (state->skills[SKILL_DIGGING] - 40) * 1;
1603 /* Approximate a 1/1200 chance per skill point over 30 */
1604 chances[DIGGING_DOORS] = (state->skills[SKILL_DIGGING] * 4 - 119) / 3;
1605
1606 /* Don't let any negative chances through */
1607 for (i = 0; i < DIGGING_MAX; i++)
1608 chances[i] = MAX(0, chances[i]);
1609 }
1610
1611 /**
1612 * Calculate the blows a player would get.
1613 *
1614 * \param obj is the object for which we are calculating blows
1615 * \param state is the player state for which we are calculating blows
1616 * \param extra_blows is the number of +blows available from this object and
1617 * this state
1618 *
1619 * N.B. state->num_blows is now 100x the number of blows.
1620 */
calc_blows(struct player * p,const struct object * obj,struct player_state * state,int extra_blows)1621 int calc_blows(struct player *p, const struct object *obj,
1622 struct player_state *state, int extra_blows)
1623 {
1624 int blows;
1625 int str_index, dex_index;
1626 int div;
1627 int blow_energy;
1628
1629 int weight = (obj == NULL) ? 0 : obj->weight;
1630 int min_weight = p->class->min_weight;
1631
1632 /* Enforce a minimum "weight" (tenth pounds) */
1633 div = (weight < min_weight) ? min_weight : weight;
1634
1635 /* Get the strength vs weight */
1636 str_index = adj_str_blow[state->stat_ind[STAT_STR]] *
1637 p->class->att_multiply / div;
1638
1639 /* Maximal value */
1640 if (str_index > 11) str_index = 11;
1641
1642 /* Index by dexterity */
1643 dex_index = MIN(adj_dex_blow[state->stat_ind[STAT_DEX]], 11);
1644
1645 /* Use the blows table to get energy per blow */
1646 blow_energy = blows_table[str_index][dex_index];
1647
1648 blows = MIN((10000 / blow_energy), (100 * p->class->max_attacks));
1649
1650 /* Require at least one blow, two for O-combat */
1651 return MAX(blows + (100 * extra_blows),
1652 OPT(p, birth_percent_damage) ? 200 : 100);
1653 }
1654
1655
1656 /**
1657 * Computes current weight limit.
1658 */
weight_limit(struct player_state * state)1659 static int weight_limit(struct player_state *state)
1660 {
1661 int i;
1662
1663 /* Weight limit based only on strength */
1664 i = adj_str_wgt[state->stat_ind[STAT_STR]] * 100;
1665
1666 /* Return the result */
1667 return (i);
1668 }
1669
1670
1671 /**
1672 * Computes weight remaining before burdened.
1673 */
weight_remaining(struct player * p)1674 int weight_remaining(struct player *p)
1675 {
1676 int i;
1677
1678 /* Weight limit based only on strength */
1679 i = 60 * adj_str_wgt[p->state.stat_ind[STAT_STR]]
1680 - p->upkeep->total_weight - 1;
1681
1682 /* Return the result */
1683 return (i);
1684 }
1685
1686
1687 /**
1688 * Calculate the effect of a shapechange on player state
1689 */
calc_shapechange(struct player_state * state,struct player_shape * shape,int * blows,int * shots,int * might,int * moves)1690 static void calc_shapechange(struct player_state *state,
1691 struct player_shape *shape,
1692 int *blows, int *shots, int *might, int *moves)
1693 {
1694 int i;
1695
1696 /* Combat stats */
1697 state->to_a += shape->to_a;
1698 state->to_h += shape->to_h;
1699 state->to_d += shape->to_d;
1700
1701 /* Skills */
1702 for (i = 0; i < SKILL_MAX; i++) {
1703 state->skills[i] += shape->skills[i];
1704 }
1705
1706 /* Object flags */
1707 of_union(state->flags, shape->flags);
1708
1709 /* Player flags */
1710 pf_union(state->pflags, shape->pflags);
1711
1712 /* Stats */
1713 for (i = 0; i < STAT_MAX; i++) {
1714 state->stat_add[i] += shape->modifiers[i];
1715 }
1716
1717 /* Other modifiers */
1718 state->skills[SKILL_STEALTH] += shape->modifiers[OBJ_MOD_STEALTH];
1719 state->skills[SKILL_SEARCH] += (shape->modifiers[OBJ_MOD_SEARCH] * 5);
1720 state->see_infra += shape->modifiers[OBJ_MOD_INFRA];
1721 state->skills[SKILL_DIGGING] += (shape->modifiers[OBJ_MOD_TUNNEL] * 20);
1722 state->speed += shape->modifiers[OBJ_MOD_SPEED];
1723 state->dam_red += shape->modifiers[OBJ_MOD_DAM_RED];
1724 *blows += shape->modifiers[OBJ_MOD_BLOWS];
1725 *shots += shape->modifiers[OBJ_MOD_SHOTS];
1726 *might += shape->modifiers[OBJ_MOD_MIGHT];
1727 *moves += shape->modifiers[OBJ_MOD_MOVES];
1728
1729 /* Resists and vulnerabilities */
1730 for (i = 0; i < ELEM_MAX; i++) {
1731 if (state->el_info[i].res_level == 0) {
1732 /* Simple, just apply shape res/vuln */
1733 state->el_info[i].res_level = shape->el_info[i].res_level;
1734 } else if (state->el_info[i].res_level == -1) {
1735 /* Shape resists cancel, immunities trump, vulnerabilities */
1736 if (shape->el_info[i].res_level == 1) {
1737 state->el_info[i].res_level = 0;
1738 } else if (shape->el_info[i].res_level == 3) {
1739 state->el_info[i].res_level = 3;
1740 }
1741 } else if (state->el_info[i].res_level == 1) {
1742 /* Shape vulnerabilities cancel, immunities enhance, resists */
1743 if (shape->el_info[i].res_level == -1) {
1744 state->el_info[i].res_level = 0;
1745 } else if (shape->el_info[i].res_level == 3) {
1746 state->el_info[i].res_level = 3;
1747 }
1748 } else if (state->el_info[i].res_level == 3) {
1749 /* Immmunity, shape has no effect */
1750 }
1751 }
1752
1753 }
1754
1755 /**
1756 * Calculate the players current "state", taking into account
1757 * not only race/class intrinsics, but also objects being worn
1758 * and temporary spell effects.
1759 *
1760 * See also calc_mana() and calc_hitpoints().
1761 *
1762 * Take note of the new "speed code", in particular, a very strong
1763 * player will start slowing down as soon as he reaches 150 pounds,
1764 * but not until he reaches 450 pounds will he be half as fast as
1765 * a normal kobold. This both hurts and helps the player, hurts
1766 * because in the old days a player could just avoid 300 pounds,
1767 * and helps because now carrying 300 pounds is not very painful.
1768 *
1769 * The "weapon" and "bow" do *not* add to the bonuses to hit or to
1770 * damage, since that would affect non-combat things. These values
1771 * are actually added in later, at the appropriate place.
1772 *
1773 * If known_only is true, calc_bonuses() will only use the known
1774 * information of objects; thus it returns what the player _knows_
1775 * the character state to be.
1776 */
calc_bonuses(struct player * p,struct player_state * state,bool known_only,bool update)1777 void calc_bonuses(struct player *p, struct player_state *state, bool known_only,
1778 bool update)
1779 {
1780 int i, j, hold;
1781 int extra_blows = 0;
1782 int extra_shots = 0;
1783 int extra_might = 0;
1784 int extra_moves = 0;
1785 struct object *launcher = equipped_item_by_slot_name(p, "shooting");
1786 struct object *weapon = equipped_item_by_slot_name(p, "weapon");
1787 bitflag f[OF_SIZE];
1788 bitflag collect_f[OF_SIZE];
1789 bool vuln[ELEM_MAX];
1790
1791 /* Hack to allow calculating hypothetical blows for extra STR, DEX - NRM */
1792 int str_ind = state->stat_ind[STAT_STR];
1793 int dex_ind = state->stat_ind[STAT_DEX];
1794
1795 /* Reset */
1796 memset(state, 0, sizeof *state);
1797
1798 /* Set various defaults */
1799 state->speed = 110;
1800 state->num_blows = 100;
1801
1802 /* Extract race/class info */
1803 state->see_infra = p->race->infra;
1804 for (i = 0; i < SKILL_MAX; i++) {
1805 state->skills[i] = p->race->r_skills[i] + p->class->c_skills[i];
1806 }
1807 for (i = 0; i < ELEM_MAX; i++) {
1808 vuln[i] = false;
1809 if (p->race->el_info[i].res_level == -1) {
1810 vuln[i] = true;
1811 } else {
1812 state->el_info[i].res_level = p->race->el_info[i].res_level;
1813 }
1814 }
1815
1816 /* Base pflags */
1817 pf_wipe(state->pflags);
1818 pf_copy(state->pflags, p->race->pflags);
1819 pf_union(state->pflags, p->class->pflags);
1820
1821 /* Extract the player flags */
1822 player_flags(p, collect_f);
1823
1824 /* Analyze equipment */
1825 for (i = 0; i < p->body.count; i++) {
1826 int index = 0;
1827 struct object *obj = slot_object(p, i);
1828 struct curse_data *curse = obj ? obj->curses : NULL;
1829
1830 while (obj) {
1831 int dig = 0;
1832
1833 /* Extract the item flags */
1834 if (known_only) {
1835 object_flags_known(obj, f);
1836 } else {
1837 object_flags(obj, f);
1838 }
1839 of_union(collect_f, f);
1840
1841 /* Apply modifiers */
1842 state->stat_add[STAT_STR] += obj->modifiers[OBJ_MOD_STR]
1843 * p->obj_k->modifiers[OBJ_MOD_STR];
1844 state->stat_add[STAT_INT] += obj->modifiers[OBJ_MOD_INT]
1845 * p->obj_k->modifiers[OBJ_MOD_INT];
1846 state->stat_add[STAT_WIS] += obj->modifiers[OBJ_MOD_WIS]
1847 * p->obj_k->modifiers[OBJ_MOD_WIS];
1848 state->stat_add[STAT_DEX] += obj->modifiers[OBJ_MOD_DEX]
1849 * p->obj_k->modifiers[OBJ_MOD_DEX];
1850 state->stat_add[STAT_CON] += obj->modifiers[OBJ_MOD_CON]
1851 * p->obj_k->modifiers[OBJ_MOD_CON];
1852 state->skills[SKILL_STEALTH] += obj->modifiers[OBJ_MOD_STEALTH]
1853 * p->obj_k->modifiers[OBJ_MOD_STEALTH];
1854 state->skills[SKILL_SEARCH] += (obj->modifiers[OBJ_MOD_SEARCH] * 5)
1855 * p->obj_k->modifiers[OBJ_MOD_SEARCH];
1856
1857 state->see_infra += obj->modifiers[OBJ_MOD_INFRA]
1858 * p->obj_k->modifiers[OBJ_MOD_INFRA];
1859 if (tval_is_digger(obj)) {
1860 if (of_has(obj->flags, OF_DIG_1))
1861 dig = 1;
1862 else if (of_has(obj->flags, OF_DIG_2))
1863 dig = 2;
1864 else if (of_has(obj->flags, OF_DIG_3))
1865 dig = 3;
1866 }
1867 dig += obj->modifiers[OBJ_MOD_TUNNEL]
1868 * p->obj_k->modifiers[OBJ_MOD_TUNNEL];
1869 state->skills[SKILL_DIGGING] += (dig * 20);
1870 state->speed += obj->modifiers[OBJ_MOD_SPEED]
1871 * p->obj_k->modifiers[OBJ_MOD_SPEED];
1872 state->dam_red += obj->modifiers[OBJ_MOD_DAM_RED]
1873 * p->obj_k->modifiers[OBJ_MOD_DAM_RED];
1874 extra_blows += obj->modifiers[OBJ_MOD_BLOWS]
1875 * p->obj_k->modifiers[OBJ_MOD_BLOWS];
1876 extra_shots += obj->modifiers[OBJ_MOD_SHOTS]
1877 * p->obj_k->modifiers[OBJ_MOD_SHOTS];
1878 extra_might += obj->modifiers[OBJ_MOD_MIGHT]
1879 * p->obj_k->modifiers[OBJ_MOD_MIGHT];
1880 extra_moves += obj->modifiers[OBJ_MOD_MOVES]
1881 * p->obj_k->modifiers[OBJ_MOD_MOVES];
1882
1883 /* Apply element info, noting vulnerabilites for later processing */
1884 for (j = 0; j < ELEM_MAX; j++) {
1885 if (!known_only || obj->known->el_info[j].res_level) {
1886 if (obj->el_info[j].res_level == -1)
1887 vuln[j] = true;
1888
1889 /* OK because res_level hasn't included vulnerability yet */
1890 if (obj->el_info[j].res_level > state->el_info[j].res_level)
1891 state->el_info[j].res_level = obj->el_info[j].res_level;
1892 }
1893 }
1894
1895 /* Apply combat bonuses */
1896 state->ac += obj->ac;
1897 if (!known_only || obj->known->to_a)
1898 state->to_a += obj->to_a;
1899 if (!slot_type_is(i, EQUIP_WEAPON) && !slot_type_is(i, EQUIP_BOW)) {
1900 if (!known_only || obj->known->to_h) {
1901 state->to_h += obj->to_h;
1902 }
1903 if (!known_only || obj->known->to_d) {
1904 state->to_d += obj->to_d;
1905 }
1906 }
1907
1908 /* Move to any unprocessed curse object */
1909 if (curse) {
1910 index++;
1911 obj = NULL;
1912 while (index < z_info->curse_max) {
1913 if (curse[index].power) {
1914 obj = curses[index].obj;
1915 break;
1916 } else {
1917 index++;
1918 }
1919 }
1920 } else {
1921 obj = NULL;
1922 }
1923 }
1924 }
1925
1926 /* Apply the collected flags */
1927 of_union(state->flags, collect_f);
1928
1929 /* Now deal with vulnerabilities */
1930 for (i = 0; i < ELEM_MAX; i++) {
1931 if (vuln[i] && (state->el_info[i].res_level < 3))
1932 state->el_info[i].res_level--;
1933 }
1934
1935 /* Add shapechange info */
1936 calc_shapechange(state, p->shape, &extra_blows, &extra_shots, &extra_might,
1937 &extra_moves);
1938
1939 /* Calculate light */
1940 calc_light(p, state, update);
1941
1942 /* Unlight - needs change if anything but resist is introduced for dark */
1943 if (player_has(p, PF_UNLIGHT) && character_dungeon) {
1944 state->el_info[ELEM_DARK].res_level = 1;
1945 }
1946
1947 /* Evil */
1948 if (player_has(p, PF_EVIL) && character_dungeon) {
1949 state->el_info[ELEM_NETHER].res_level = 1;
1950 state->el_info[ELEM_HOLY_ORB].res_level = -1;
1951 }
1952
1953 /* Combat Regeneration */
1954 if (player_has(p, PF_COMBAT_REGEN) && character_dungeon) {
1955 of_on(state->flags, OF_IMPAIR_HP);
1956 }
1957
1958 /* Calculate the various stat values */
1959 for (i = 0; i < STAT_MAX; i++) {
1960 int add, use, ind;
1961
1962 add = state->stat_add[i];
1963 add += (p->race->r_adj[i] + p->class->c_adj[i]);
1964 state->stat_top[i] = modify_stat_value(p->stat_max[i], add);
1965 use = modify_stat_value(p->stat_cur[i], add);
1966
1967 state->stat_use[i] = use;
1968
1969 if (use <= 3) {/* Values: n/a */
1970 ind = 0;
1971 } else if (use <= 18) {/* Values: 3, 4, ..., 18 */
1972 ind = (use - 3);
1973 } else if (use <= 18+219) {/* Ranges: 18/00-18/09, ..., 18/210-18/219 */
1974 ind = (15 + (use - 18) / 10);
1975 } else {/* Range: 18/220+ */
1976 ind = (37);
1977 }
1978
1979 assert((0 <= ind) && (ind < STAT_RANGE));
1980
1981 /* Hack for hypothetical blows - NRM */
1982 if (!update) {
1983 if (i == STAT_STR) {
1984 ind += str_ind;
1985 ind = MIN(ind, 37);
1986 ind = MAX(ind, 3);
1987 } else if (i == STAT_DEX) {
1988 ind += dex_ind;
1989 ind = MIN(ind, 37);
1990 ind = MAX(ind, 3);
1991 }
1992 }
1993
1994 /* Save the new index */
1995 state->stat_ind[i] = ind;
1996 }
1997
1998 /* Effects of food outside the "Fed" range */
1999 if (!player_timed_grade_eq(p, TMD_FOOD, "Fed")) {
2000 int excess = p->timed[TMD_FOOD] - PY_FOOD_FULL;
2001 int lack = PY_FOOD_HUNGRY - p->timed[TMD_FOOD];
2002 if ((excess > 0) && !p->timed[TMD_ATT_VAMP]) {
2003 /* Scale to units 1/10 of the range and subtract from speed */
2004 excess = (excess * 10) / (PY_FOOD_MAX - PY_FOOD_FULL);
2005 state->speed -= excess;
2006 } else if (lack > 0) {
2007 /* Scale to units 1/20 of the range */
2008 lack = (lack * 20) / PY_FOOD_HUNGRY;
2009
2010 /* Apply effects progressively */
2011 state->to_h -= lack;
2012 state->to_d -= lack;
2013 if ((lack > 10) && (lack <= 15)) {
2014 state->skills[SKILL_DEVICE] *= 9;
2015 state->skills[SKILL_DEVICE] /= 10;
2016 } else if ((lack > 15) && (lack <= 18)) {
2017 state->skills[SKILL_DEVICE] *= 8;
2018 state->skills[SKILL_DEVICE] /= 10;
2019 state->skills[SKILL_DISARM_PHYS] *= 9;
2020 state->skills[SKILL_DISARM_PHYS] /= 10;
2021 state->skills[SKILL_DISARM_MAGIC] *= 9;
2022 state->skills[SKILL_DISARM_MAGIC] /= 10;
2023 } else if (lack > 18) {
2024 state->skills[SKILL_DEVICE] *= 7;
2025 state->skills[SKILL_DEVICE] /= 10;
2026 state->skills[SKILL_DISARM_PHYS] *= 8;
2027 state->skills[SKILL_DISARM_PHYS] /= 10;
2028 state->skills[SKILL_DISARM_MAGIC] *= 8;
2029 state->skills[SKILL_DISARM_MAGIC] /= 10;
2030 state->skills[SKILL_SAVE] *= 9;
2031 state->skills[SKILL_SAVE] /= 10;
2032 state->skills[SKILL_SEARCH] *=9;
2033 state->skills[SKILL_SEARCH] /= 10;
2034 }
2035 }
2036 }
2037
2038 /* Other timed effects */
2039 player_flags_timed(p, state->flags);
2040
2041 if (player_timed_grade_eq(p, TMD_STUN, "Heavy Stun")) {
2042 state->to_h -= 20;
2043 state->to_d -= 20;
2044 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10;
2045 if (update) {
2046 p->timed[TMD_FASTCAST] = 0;
2047 }
2048 } else if (player_timed_grade_eq(p, TMD_STUN, "Stun")) {
2049 state->to_h -= 5;
2050 state->to_d -= 5;
2051 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 9 / 10;
2052 if (update) {
2053 p->timed[TMD_FASTCAST] = 0;
2054 }
2055 }
2056 if (p->timed[TMD_INVULN]) {
2057 state->to_a += 100;
2058 }
2059 if (p->timed[TMD_BLESSED]) {
2060 state->to_a += 5;
2061 state->to_h += 10;
2062 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 105 / 100;
2063 }
2064 if (p->timed[TMD_SHIELD]) {
2065 state->to_a += 50;
2066 }
2067 if (p->timed[TMD_STONESKIN]) {
2068 state->to_a += 40;
2069 state->speed -= 5;
2070 }
2071 if (p->timed[TMD_HERO]) {
2072 state->to_h += 12;
2073 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 105 / 100;
2074 }
2075 if (p->timed[TMD_SHERO]) {
2076 state->skills[SKILL_TO_HIT_MELEE] += 75;
2077 state->to_a -= 10;
2078 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 9 / 10;
2079 }
2080 if (p->timed[TMD_FAST] || p->timed[TMD_SPRINT]) {
2081 state->speed += 10;
2082 }
2083 if (p->timed[TMD_SLOW]) {
2084 state->speed -= 10;
2085 }
2086 if (p->timed[TMD_SINFRA]) {
2087 state->see_infra += 5;
2088 }
2089 if (p->timed[TMD_TERROR]) {
2090 state->speed += 10;
2091 }
2092 if (p->timed[TMD_OPP_ACID] && (state->el_info[ELEM_ACID].res_level < 2)) {
2093 state->el_info[ELEM_ACID].res_level++;
2094 }
2095 if (p->timed[TMD_OPP_ELEC] && (state->el_info[ELEM_ELEC].res_level < 2)) {
2096 state->el_info[ELEM_ELEC].res_level++;
2097 }
2098 if (p->timed[TMD_OPP_FIRE] && (state->el_info[ELEM_FIRE].res_level < 2)) {
2099 state->el_info[ELEM_FIRE].res_level++;
2100 }
2101 if (p->timed[TMD_OPP_COLD] && (state->el_info[ELEM_COLD].res_level < 2)) {
2102 state->el_info[ELEM_COLD].res_level++;
2103 }
2104 if (p->timed[TMD_OPP_POIS] && (state->el_info[ELEM_POIS].res_level < 2)) {
2105 state->el_info[ELEM_POIS].res_level++;
2106 }
2107 if (p->timed[TMD_CONFUSED]) {
2108 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 75 / 100;
2109 }
2110 if (p->timed[TMD_AMNESIA]) {
2111 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10;
2112 }
2113 if (p->timed[TMD_POISONED]) {
2114 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 95 / 100;
2115 }
2116 if (p->timed[TMD_IMAGE]) {
2117 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 8 / 10;
2118 }
2119 if (p->timed[TMD_BLOODLUST]) {
2120 state->to_d += p->timed[TMD_BLOODLUST] / 2;
2121 extra_blows += p->timed[TMD_BLOODLUST] / 20;
2122 }
2123 if (p->timed[TMD_STEALTH]) {
2124 state->skills[SKILL_STEALTH] += 10;
2125 }
2126
2127 /* Analyze flags - check for fear */
2128 if (of_has(state->flags, OF_AFRAID)) {
2129 state->to_h -= 20;
2130 state->to_a += 8;
2131 state->skills[SKILL_DEVICE] = state->skills[SKILL_DEVICE] * 95 / 100;
2132 }
2133
2134 /* Analyze weight */
2135 j = p->upkeep->total_weight;
2136 i = weight_limit(state);
2137 if (j > i / 2)
2138 state->speed -= ((j - (i / 2)) / (i / 10));
2139 if (state->speed < 0)
2140 state->speed = 0;
2141 if (state->speed > 199)
2142 state->speed = 199;
2143
2144 /* Apply modifier bonuses (Un-inflate stat bonuses) */
2145 state->to_a += adj_dex_ta[state->stat_ind[STAT_DEX]];
2146 state->to_d += adj_str_td[state->stat_ind[STAT_STR]];
2147 state->to_h += adj_dex_th[state->stat_ind[STAT_DEX]];
2148 state->to_h += adj_str_th[state->stat_ind[STAT_STR]];
2149
2150
2151 /* Modify skills */
2152 state->skills[SKILL_DISARM_PHYS] += adj_dex_dis[state->stat_ind[STAT_DEX]];
2153 state->skills[SKILL_DISARM_MAGIC] += adj_int_dis[state->stat_ind[STAT_INT]];
2154 state->skills[SKILL_DEVICE] += adj_int_dev[state->stat_ind[STAT_INT]];
2155 state->skills[SKILL_SAVE] += adj_wis_sav[state->stat_ind[STAT_WIS]];
2156 state->skills[SKILL_DIGGING] += adj_str_dig[state->stat_ind[STAT_STR]];
2157 for (i = 0; i < SKILL_MAX; i++)
2158 state->skills[i] += (p->class->x_skills[i] * p->lev / 10);
2159
2160 if (state->skills[SKILL_DIGGING] < 1) state->skills[SKILL_DIGGING] = 1;
2161 if (state->skills[SKILL_STEALTH] > 30) state->skills[SKILL_STEALTH] = 30;
2162 if (state->skills[SKILL_STEALTH] < 0) state->skills[SKILL_STEALTH] = 0;
2163 hold = adj_str_hold[state->stat_ind[STAT_STR]];
2164
2165
2166 /* Analyze launcher */
2167 state->heavy_shoot = false;
2168 if (launcher) {
2169 if (hold < launcher->weight / 10) {
2170 state->to_h += 2 * (hold - launcher->weight / 10);
2171 state->heavy_shoot = true;
2172 }
2173
2174 state->num_shots = 10;
2175
2176 /* Type of ammo */
2177 if (kf_has(launcher->kind->kind_flags, KF_SHOOTS_SHOTS))
2178 state->ammo_tval = TV_SHOT;
2179 else if (kf_has(launcher->kind->kind_flags, KF_SHOOTS_ARROWS))
2180 state->ammo_tval = TV_ARROW;
2181 else if (kf_has(launcher->kind->kind_flags, KF_SHOOTS_BOLTS))
2182 state->ammo_tval = TV_BOLT;
2183
2184 /* Multiplier */
2185 state->ammo_mult = launcher->pval;
2186
2187 /* Apply special flags */
2188 if (!state->heavy_shoot) {
2189 state->num_shots += extra_shots;
2190 state->ammo_mult += extra_might;
2191 if (player_has(p, PF_FAST_SHOT) && (state->ammo_tval == TV_ARROW)) {
2192 state->num_shots += p->lev / 3;
2193 }
2194 }
2195
2196 /* Require at least one shot */
2197 if (state->num_shots < 10) state->num_shots = 10;
2198 }
2199
2200
2201 /* Analyze weapon */
2202 state->heavy_wield = false;
2203 state->bless_wield = false;
2204 if (weapon) {
2205 /* It is hard to hold a heavy weapon */
2206 if (hold < weapon->weight / 10) {
2207 state->to_h += 2 * (hold - weapon->weight / 10);
2208 state->heavy_wield = true;
2209 }
2210
2211 /* Normal weapons */
2212 if (!state->heavy_wield) {
2213 state->num_blows = calc_blows(p, weapon, state, extra_blows);
2214 state->skills[SKILL_DIGGING] += (weapon->weight / 10);
2215 }
2216
2217 /* Divine weapon bonus for blessed weapons */
2218 if (player_has(p, PF_BLESS_WEAPON) && of_has(state->flags, OF_BLESSED)){
2219 state->to_h += 2;
2220 state->to_d += 2;
2221 state->bless_wield = true;
2222 }
2223 } else {
2224 /* Unarmed */
2225 state->num_blows = calc_blows(p, NULL, state, extra_blows);
2226 }
2227
2228 /* Mana */
2229 calc_mana(p, state, update);
2230 if (!p->msp) {
2231 pf_on(state->pflags, PF_NO_MANA);
2232 }
2233
2234 /* Movement speed */
2235 state->num_moves = extra_moves;
2236
2237 return;
2238 }
2239
2240 /**
2241 * Calculate bonuses, and print various things on changes.
2242 */
update_bonuses(struct player * p)2243 static void update_bonuses(struct player *p)
2244 {
2245 int i;
2246
2247 struct player_state state = p->state;
2248 struct player_state known_state = p->known_state;
2249
2250
2251 /* ------------------------------------
2252 * Calculate bonuses
2253 * ------------------------------------ */
2254
2255 calc_bonuses(p, &state, false, true);
2256 calc_bonuses(p, &known_state, true, true);
2257
2258
2259 /* ------------------------------------
2260 * Notice changes
2261 * ------------------------------------ */
2262
2263 /* Analyze stats */
2264 for (i = 0; i < STAT_MAX; i++) {
2265 /* Notice changes */
2266 if (state.stat_top[i] != p->state.stat_top[i])
2267 /* Redisplay the stats later */
2268 p->upkeep->redraw |= (PR_STATS);
2269
2270 /* Notice changes */
2271 if (state.stat_use[i] != p->state.stat_use[i])
2272 /* Redisplay the stats later */
2273 p->upkeep->redraw |= (PR_STATS);
2274
2275 /* Notice changes */
2276 if (state.stat_ind[i] != p->state.stat_ind[i]) {
2277 /* Change in CON affects Hitpoints */
2278 if (i == STAT_CON)
2279 p->upkeep->update |= (PU_HP);
2280
2281 /* Change in stats may affect Mana/Spells */
2282 p->upkeep->update |= (PU_MANA | PU_SPELLS);
2283 }
2284 }
2285
2286
2287 /* Hack -- Telepathy Change */
2288 if (of_has(state.flags, OF_TELEPATHY) !=
2289 of_has(p->state.flags, OF_TELEPATHY))
2290 /* Update monster visibility */
2291 p->upkeep->update |= (PU_MONSTERS);
2292 /* Hack -- See Invis Change */
2293 if (of_has(state.flags, OF_SEE_INVIS) !=
2294 of_has(p->state.flags, OF_SEE_INVIS))
2295 /* Update monster visibility */
2296 p->upkeep->update |= (PU_MONSTERS);
2297
2298 /* Redraw speed (if needed) */
2299 if (state.speed != p->state.speed)
2300 p->upkeep->redraw |= (PR_SPEED);
2301
2302 /* Redraw armor (if needed) */
2303 if ((known_state.ac != p->known_state.ac) ||
2304 (known_state.to_a != p->known_state.to_a))
2305 p->upkeep->redraw |= (PR_ARMOR);
2306
2307 /* Notice changes in the "light radius" */
2308 if (p->state.cur_light != state.cur_light) {
2309 /* Update the visuals */
2310 p->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
2311 }
2312
2313 /* Hack -- handle partial mode */
2314 if (!p->upkeep->only_partial) {
2315 /* Take note when "heavy bow" changes */
2316 if (p->state.heavy_shoot != state.heavy_shoot) {
2317 /* Message */
2318 if (state.heavy_shoot)
2319 msg("You have trouble wielding such a heavy bow.");
2320 else if (equipped_item_by_slot_name(p, "shooting"))
2321 msg("You have no trouble wielding your bow.");
2322 else
2323 msg("You feel relieved to put down your heavy bow.");
2324 }
2325
2326 /* Take note when "heavy weapon" changes */
2327 if (p->state.heavy_wield != state.heavy_wield) {
2328 /* Message */
2329 if (state.heavy_wield)
2330 msg("You have trouble wielding such a heavy weapon.");
2331 else if (equipped_item_by_slot_name(p, "weapon"))
2332 msg("You have no trouble wielding your weapon.");
2333 else
2334 msg("You feel relieved to put down your heavy weapon.");
2335 }
2336
2337 /* Take note when "illegal weapon" changes */
2338 if (p->state.bless_wield != state.bless_wield) {
2339 /* Message */
2340 if (state.bless_wield) {
2341 msg("You feel attuned to your weapon.");
2342 } else if (equipped_item_by_slot_name(p, "weapon")) {
2343 msg("You feel less attuned to your weapon.");
2344 }
2345 }
2346
2347 /* Take note when "armor state" changes */
2348 if (p->state.cumber_armor != state.cumber_armor) {
2349 /* Message */
2350 if (state.cumber_armor)
2351 msg("The weight of your armor encumbers your movement.");
2352 else
2353 msg("You feel able to move more freely.");
2354 }
2355 }
2356
2357 memcpy(&p->state, &state, sizeof(state));
2358 memcpy(&p->known_state, &known_state, sizeof(known_state));
2359 }
2360
2361
2362
2363
2364 /**
2365 * ------------------------------------------------------------------------
2366 * Monster and object tracking functions
2367 * ------------------------------------------------------------------------ */
2368
2369 /**
2370 * Track the given monster
2371 */
health_track(struct player_upkeep * upkeep,struct monster * mon)2372 void health_track(struct player_upkeep *upkeep, struct monster *mon)
2373 {
2374 upkeep->health_who = mon;
2375 upkeep->redraw |= PR_HEALTH;
2376 }
2377
2378 /**
2379 * Track the given monster race
2380 */
monster_race_track(struct player_upkeep * upkeep,struct monster_race * race)2381 void monster_race_track(struct player_upkeep *upkeep, struct monster_race *race)
2382 {
2383 /* Save this monster ID */
2384 upkeep->monster_race = race;
2385
2386 /* Window stuff */
2387 upkeep->redraw |= (PR_MONSTER);
2388 }
2389
2390 /**
2391 * Track the given object
2392 */
track_object(struct player_upkeep * upkeep,struct object * obj)2393 void track_object(struct player_upkeep *upkeep, struct object *obj)
2394 {
2395 upkeep->object = obj;
2396 upkeep->object_kind = NULL;
2397 upkeep->redraw |= (PR_OBJECT);
2398 }
2399
2400 /**
2401 * Track the given object kind
2402 */
track_object_kind(struct player_upkeep * upkeep,struct object_kind * kind)2403 void track_object_kind(struct player_upkeep *upkeep, struct object_kind *kind)
2404 {
2405 upkeep->object = NULL;
2406 upkeep->object_kind = kind;
2407 upkeep->redraw |= (PR_OBJECT);
2408 }
2409
2410 /**
2411 * Cancel all object tracking
2412 */
track_object_cancel(struct player_upkeep * upkeep)2413 void track_object_cancel(struct player_upkeep *upkeep)
2414 {
2415 upkeep->object = NULL;
2416 upkeep->object_kind = NULL;
2417 upkeep->redraw |= (PR_OBJECT);
2418 }
2419
2420 /**
2421 * Is the given item tracked?
2422 */
tracked_object_is(struct player_upkeep * upkeep,struct object * obj)2423 bool tracked_object_is(struct player_upkeep *upkeep, struct object *obj)
2424 {
2425 return (upkeep->object == obj);
2426 }
2427
2428
2429
2430 /**
2431 * ------------------------------------------------------------------------
2432 * Generic "deal with" functions
2433 * ------------------------------------------------------------------------ */
2434
2435 /**
2436 * Handle "player->upkeep->notice"
2437 */
notice_stuff(struct player * p)2438 void notice_stuff(struct player *p)
2439 {
2440 /* Notice stuff */
2441 if (!p->upkeep->notice) return;
2442
2443 /* Deal with ignore stuff */
2444 if (p->upkeep->notice & PN_IGNORE) {
2445 p->upkeep->notice &= ~(PN_IGNORE);
2446 ignore_drop();
2447 }
2448
2449 /* Combine the pack */
2450 if (p->upkeep->notice & PN_COMBINE) {
2451 p->upkeep->notice &= ~(PN_COMBINE);
2452 combine_pack();
2453 }
2454
2455 /* Dump the monster messages */
2456 if (p->upkeep->notice & PN_MON_MESSAGE) {
2457 p->upkeep->notice &= ~(PN_MON_MESSAGE);
2458
2459 /* Make sure this comes after all of the monster messages */
2460 show_monster_messages();
2461 }
2462 }
2463
2464 /**
2465 * Handle "player->upkeep->update"
2466 */
update_stuff(struct player * p)2467 void update_stuff(struct player *p)
2468 {
2469 /* Update stuff */
2470 if (!p->upkeep->update) return;
2471
2472
2473 if (p->upkeep->update & (PU_INVEN)) {
2474 p->upkeep->update &= ~(PU_INVEN);
2475 update_inventory(p);
2476 }
2477
2478 if (p->upkeep->update & (PU_BONUS)) {
2479 p->upkeep->update &= ~(PU_BONUS);
2480 update_bonuses(p);
2481 }
2482
2483 if (p->upkeep->update & (PU_TORCH)) {
2484 p->upkeep->update &= ~(PU_TORCH);
2485 calc_light(p, &p->state, true);
2486 }
2487
2488 if (p->upkeep->update & (PU_HP)) {
2489 p->upkeep->update &= ~(PU_HP);
2490 calc_hitpoints(p);
2491 }
2492
2493 if (p->upkeep->update & (PU_MANA)) {
2494 p->upkeep->update &= ~(PU_MANA);
2495 calc_mana(p, &p->state, true);
2496 }
2497
2498 if (p->upkeep->update & (PU_SPELLS)) {
2499 p->upkeep->update &= ~(PU_SPELLS);
2500 if (p->class->magic.total_spells > 0) {
2501 calc_spells(p);
2502 }
2503 }
2504
2505 /* Character is not ready yet, no map updates */
2506 if (!character_generated) return;
2507
2508 /* Map is not shown, no map updates */
2509 if (!map_is_visible()) return;
2510
2511 if (p->upkeep->update & (PU_UPDATE_VIEW)) {
2512 p->upkeep->update &= ~(PU_UPDATE_VIEW);
2513 update_view(cave, p);
2514 }
2515
2516 if (p->upkeep->update & (PU_DISTANCE)) {
2517 p->upkeep->update &= ~(PU_DISTANCE);
2518 p->upkeep->update &= ~(PU_MONSTERS);
2519 update_monsters(true);
2520 }
2521
2522 if (p->upkeep->update & (PU_MONSTERS)) {
2523 p->upkeep->update &= ~(PU_MONSTERS);
2524 update_monsters(false);
2525 }
2526
2527
2528 if (p->upkeep->update & (PU_PANEL)) {
2529 p->upkeep->update &= ~(PU_PANEL);
2530 event_signal(EVENT_PLAYERMOVED);
2531 }
2532 }
2533
2534
2535
2536 struct flag_event_trigger
2537 {
2538 u32b flag;
2539 game_event_type event;
2540 };
2541
2542
2543
2544 /**
2545 * Events triggered by the various flags.
2546 */
2547 static const struct flag_event_trigger redraw_events[] =
2548 {
2549 { PR_MISC, EVENT_RACE_CLASS },
2550 { PR_TITLE, EVENT_PLAYERTITLE },
2551 { PR_LEV, EVENT_PLAYERLEVEL },
2552 { PR_EXP, EVENT_EXPERIENCE },
2553 { PR_STATS, EVENT_STATS },
2554 { PR_ARMOR, EVENT_AC },
2555 { PR_HP, EVENT_HP },
2556 { PR_MANA, EVENT_MANA },
2557 { PR_GOLD, EVENT_GOLD },
2558 { PR_HEALTH, EVENT_MONSTERHEALTH },
2559 { PR_DEPTH, EVENT_DUNGEONLEVEL },
2560 { PR_SPEED, EVENT_PLAYERSPEED },
2561 { PR_STATE, EVENT_STATE },
2562 { PR_STATUS, EVENT_STATUS },
2563 { PR_STUDY, EVENT_STUDYSTATUS },
2564 { PR_DTRAP, EVENT_DETECTIONSTATUS },
2565 { PR_FEELING, EVENT_FEELING },
2566 { PR_LIGHT, EVENT_LIGHT },
2567
2568 { PR_INVEN, EVENT_INVENTORY },
2569 { PR_EQUIP, EVENT_EQUIPMENT },
2570 { PR_MONLIST, EVENT_MONSTERLIST },
2571 { PR_ITEMLIST, EVENT_ITEMLIST },
2572 { PR_MONSTER, EVENT_MONSTERTARGET },
2573 { PR_OBJECT, EVENT_OBJECTTARGET },
2574 { PR_MESSAGE, EVENT_MESSAGE },
2575 };
2576
2577 /**
2578 * Handle "player->upkeep->redraw"
2579 */
redraw_stuff(struct player * p)2580 void redraw_stuff(struct player *p)
2581 {
2582 size_t i;
2583 u32b redraw = p->upkeep->redraw;
2584
2585 /* Redraw stuff */
2586 if (!redraw) return;
2587
2588 /* Character is not ready yet, no screen updates */
2589 if (!character_generated) return;
2590
2591 /* Map is not shown, subwindow updates only */
2592 if (!map_is_visible())
2593 redraw &= PR_SUBWINDOW;
2594
2595 /* Hack - rarely update while resting or running, makes it over quicker */
2596 if (((player_resting_count(p) % 100) || (p->upkeep->running % 100))
2597 && !(redraw & (PR_MESSAGE | PR_MAP)))
2598 return;
2599
2600 /* For each listed flag, send the appropriate signal to the UI */
2601 for (i = 0; i < N_ELEMENTS(redraw_events); i++) {
2602 const struct flag_event_trigger *hnd = &redraw_events[i];
2603
2604 if (redraw & hnd->flag)
2605 event_signal(hnd->event);
2606 }
2607
2608 /* Then the ones that require parameters to be supplied. */
2609 if (redraw & PR_MAP) {
2610 /* Mark the whole map to be redrawn */
2611 event_signal_point(EVENT_MAP, -1, -1);
2612 }
2613
2614 p->upkeep->redraw &= ~redraw;
2615
2616 /* Map is not shown, subwindow updates only */
2617 if (!map_is_visible()) return;
2618
2619 /*
2620 * Do any plotting, etc. delayed from earlier - this set of updates
2621 * is over.
2622 */
2623 event_signal(EVENT_END);
2624 }
2625
2626
2627 /**
2628 * Handle "player->upkeep->update" and "player->upkeep->redraw"
2629 */
handle_stuff(struct player * p)2630 void handle_stuff(struct player *p)
2631 {
2632 if (p->upkeep->update) update_stuff(p);
2633 if (p->upkeep->redraw) redraw_stuff(p);
2634 }
2635
2636