1 /**
2 * \file player.c
3 * \brief Player implementation
4 *
5 * Copyright (c) 2011 elly+angband@leptoquark.net. See COPYING.
6 *
7 * This work is free software; you can redistribute it and/or modify it
8 * under the terms of either:
9 *
10 * a) the GNU General Public License as published by the Free Software
11 * Foundation, version 2, or
12 *
13 * b) the "Angband licence":
14 * This software may be copied and distributed for educational, research,
15 * and not for profit purposes provided that this copyright and statement
16 * are included in all such copies. Other copyrights may also apply.
17 */
18
19 #include "effects.h"
20 #include "init.h"
21 #include "obj-pile.h"
22 #include "obj-util.h"
23 #include "player-birth.h"
24 #include "player-calcs.h"
25 #include "player-history.h"
26 #include "player-quest.h"
27 #include "player-spell.h"
28 #include "player-timed.h"
29 #include "z-color.h"
30 #include "z-util.h"
31
32 /**
33 * Pointer to the player struct
34 */
35 struct player *player = NULL;
36
37 struct player_body *bodies;
38 struct player_race *races;
39 struct player_shape *shapes;
40 struct player_class *classes;
41 struct player_ability *player_abilities;
42 struct magic_realm *realms;
43
44 /**
45 * Base experience levels, may be adjusted up for race and/or class
46 */
47 const s32b player_exp[PY_MAX_LEVEL] =
48 {
49 10,
50 25,
51 45,
52 70,
53 100,
54 140,
55 200,
56 280,
57 380,
58 500,
59 650,
60 850,
61 1100,
62 1400,
63 1800,
64 2300,
65 2900,
66 3600,
67 4400,
68 5400,
69 6800,
70 8400,
71 10200,
72 12500,
73 17500,
74 25000,
75 35000L,
76 50000L,
77 75000L,
78 100000L,
79 150000L,
80 200000L,
81 275000L,
82 350000L,
83 450000L,
84 550000L,
85 700000L,
86 850000L,
87 1000000L,
88 1250000L,
89 1500000L,
90 1800000L,
91 2100000L,
92 2400000L,
93 2700000L,
94 3000000L,
95 3500000L,
96 4000000L,
97 4500000L,
98 5000000L
99 };
100
101
102 static const char *stat_name_list[] = {
103 #define STAT(a) #a,
104 #include "list-stats.h"
105 #undef STAT
106 "MAX",
107 NULL
108 };
109
stat_name_to_idx(const char * name)110 int stat_name_to_idx(const char *name)
111 {
112 int i;
113 for (i = 0; stat_name_list[i]; i++) {
114 if (!my_stricmp(name, stat_name_list[i]))
115 return i;
116 }
117
118 return -1;
119 }
120
stat_idx_to_name(int type)121 const char *stat_idx_to_name(int type)
122 {
123 assert(type >= 0);
124 assert(type < STAT_MAX);
125
126 return stat_name_list[type];
127 }
128
lookup_realm(const char * name)129 const struct magic_realm *lookup_realm(const char *name)
130 {
131 struct magic_realm *realm = realms;
132 while (realm) {
133 if (!my_stricmp(name, realm->name)) {
134 return realm;
135 }
136 realm = realm->next;
137 }
138
139 /* Fail horribly */
140 quit_fmt("Failed to find %s magic realm", name);
141 return realm;
142 }
143
player_stat_inc(struct player * p,int stat)144 bool player_stat_inc(struct player *p, int stat)
145 {
146 int v = p->stat_cur[stat];
147
148 if (v >= 18 + 100)
149 return false;
150 if (v < 18) {
151 p->stat_cur[stat]++;
152 } else if (v < 18 + 90) {
153 int gain = (((18 + 100) - v) / 2 + 3) / 2;
154 if (gain < 1)
155 gain = 1;
156 p->stat_cur[stat] += randint1(gain) + gain / 2;
157 if (p->stat_cur[stat] > 18 + 99)
158 p->stat_cur[stat] = 18 + 99;
159 } else {
160 p->stat_cur[stat] = 18 + 100;
161 }
162
163 if (p->stat_cur[stat] > p->stat_max[stat])
164 p->stat_max[stat] = p->stat_cur[stat];
165
166 p->upkeep->update |= PU_BONUS;
167 return true;
168 }
169
player_stat_dec(struct player * p,int stat,bool permanent)170 bool player_stat_dec(struct player *p, int stat, bool permanent)
171 {
172 int cur, max, res = false;
173
174 cur = p->stat_cur[stat];
175 max = p->stat_max[stat];
176
177 if (cur > 18+10)
178 cur -= 10;
179 else if (cur > 18)
180 cur = 18;
181 else if (cur > 3)
182 cur -= 1;
183
184 res = (cur != p->stat_cur[stat]);
185
186 if (permanent) {
187 if (max > 18+10)
188 max -= 10;
189 else if (max > 18)
190 max = 18;
191 else if (max > 3)
192 max -= 1;
193
194 res = (max != p->stat_max[stat]);
195 }
196
197 if (res) {
198 p->stat_cur[stat] = cur;
199 p->stat_max[stat] = max;
200 p->upkeep->update |= (PU_BONUS);
201 p->upkeep->redraw |= (PR_STATS);
202 }
203
204 return res;
205 }
206
adjust_level(struct player * p,bool verbose)207 static void adjust_level(struct player *p, bool verbose)
208 {
209 if (p->exp < 0)
210 p->exp = 0;
211
212 if (p->max_exp < 0)
213 p->max_exp = 0;
214
215 if (p->exp > PY_MAX_EXP)
216 p->exp = PY_MAX_EXP;
217
218 if (p->max_exp > PY_MAX_EXP)
219 p->max_exp = PY_MAX_EXP;
220
221 if (p->exp > p->max_exp)
222 p->max_exp = p->exp;
223
224 p->upkeep->redraw |= PR_EXP;
225
226 handle_stuff(p);
227
228 while ((p->lev > 1) &&
229 (p->exp < (player_exp[p->lev-2] * p->expfact / 100L)))
230 p->lev--;
231
232
233 while ((p->lev < PY_MAX_LEVEL) &&
234 (p->exp >= (player_exp[p->lev-1] * p->expfact / 100L))) {
235 char buf[80];
236
237 p->lev++;
238
239 /* Save the highest level */
240 if (p->lev > p->max_lev)
241 p->max_lev = p->lev;
242
243 if (verbose) {
244 /* Log level updates */
245 strnfmt(buf, sizeof(buf), "Reached level %d", p->lev);
246 history_add(p, buf, HIST_GAIN_LEVEL);
247
248 /* Message */
249 msgt(MSG_LEVEL, "Welcome to level %d.", p->lev);
250 }
251
252 effect_simple(EF_RESTORE_STAT, source_none(), "0", STAT_STR, 0, 0, 0, 0, NULL);
253 effect_simple(EF_RESTORE_STAT, source_none(), "0", STAT_INT, 0, 0, 0, 0, NULL);
254 effect_simple(EF_RESTORE_STAT, source_none(), "0", STAT_WIS, 0, 0, 0, 0, NULL);
255 effect_simple(EF_RESTORE_STAT, source_none(), "0", STAT_DEX, 0, 0, 0, 0, NULL);
256 effect_simple(EF_RESTORE_STAT, source_none(), "0", STAT_CON, 0, 0, 0, 0, NULL);
257 }
258
259 while ((p->max_lev < PY_MAX_LEVEL) &&
260 (p->max_exp >= (player_exp[p->max_lev-1] * p->expfact / 100L)))
261 p->max_lev++;
262
263 p->upkeep->update |= (PU_BONUS | PU_HP | PU_SPELLS);
264 p->upkeep->redraw |= (PR_LEV | PR_TITLE | PR_EXP | PR_STATS);
265 handle_stuff(p);
266 }
267
player_exp_gain(struct player * p,s32b amount)268 void player_exp_gain(struct player *p, s32b amount)
269 {
270 p->exp += amount;
271 if (p->exp < p->max_exp)
272 p->max_exp += amount / 10;
273 adjust_level(p, true);
274 }
275
player_exp_lose(struct player * p,s32b amount,bool permanent)276 void player_exp_lose(struct player *p, s32b amount, bool permanent)
277 {
278 if (p->exp < amount)
279 amount = p->exp;
280 p->exp -= amount;
281 if (permanent)
282 p->max_exp -= amount;
283 adjust_level(p, true);
284 }
285
286 /**
287 * Obtain object flags for the player
288 */
player_flags(struct player * p,bitflag f[OF_SIZE])289 void player_flags(struct player *p, bitflag f[OF_SIZE])
290 {
291 /* Add racial flags */
292 memcpy(f, p->race->flags, sizeof(p->race->flags));
293 of_union(f, p->class->flags);
294
295 /* Some classes become immune to fear at a certain plevel */
296 if (player_has(p, PF_BRAVERY_30) && p->lev >= 30) {
297 of_on(f, OF_PROT_FEAR);
298 }
299 }
300
301
302 /**
303 * Combine any flags due to timed effects on the player into those in f.
304 */
player_flags_timed(struct player * p,bitflag f[OF_SIZE])305 void player_flags_timed(struct player *p, bitflag f[OF_SIZE])
306 {
307 if (p->timed[TMD_BOLD] || p->timed[TMD_HERO] || p->timed[TMD_SHERO]) {
308 of_on(f, OF_PROT_FEAR);
309 }
310 if (p->timed[TMD_TELEPATHY]) {
311 of_on(f, OF_TELEPATHY);
312 }
313 if (p->timed[TMD_SINVIS]) {
314 of_on(f, OF_SEE_INVIS);
315 }
316 if (p->timed[TMD_FREE_ACT]) {
317 of_on(f, OF_FREE_ACT);
318 }
319 if (p->timed[TMD_AFRAID] || p->timed[TMD_TERROR]) {
320 of_on(f, OF_AFRAID);
321 }
322 if (p->timed[TMD_OPP_CONF]) {
323 of_on(f, OF_PROT_CONF);
324 }
325 }
326
327
player_hp_attr(struct player * p)328 byte player_hp_attr(struct player *p)
329 {
330 byte attr;
331
332 if (p->chp >= p->mhp)
333 attr = COLOUR_L_GREEN;
334 else if (p->chp > (p->mhp * p->opts.hitpoint_warn) / 10)
335 attr = COLOUR_YELLOW;
336 else
337 attr = COLOUR_RED;
338
339 return attr;
340 }
341
player_sp_attr(struct player * p)342 byte player_sp_attr(struct player *p)
343 {
344 byte attr;
345
346 if (p->csp >= p->msp)
347 attr = COLOUR_L_GREEN;
348 else if (p->csp > (p->msp * p->opts.hitpoint_warn) / 10)
349 attr = COLOUR_YELLOW;
350 else
351 attr = COLOUR_RED;
352
353 return attr;
354 }
355
player_restore_mana(struct player * p,int amt)356 bool player_restore_mana(struct player *p, int amt) {
357 int old_csp = p->csp;
358
359 p->csp += amt;
360 if (p->csp > p->msp) {
361 p->csp = p->msp;
362 }
363 p->upkeep->redraw |= PR_MANA;
364
365 msg("You feel some of your energies returning.");
366
367 return p->csp != old_csp;
368 }
369
370 /**
371 * Return a version of the player's name safe for use in filesystems.
372 *
373 * XXX This does not belong here.
374 */
player_safe_name(char * safe,size_t safelen,const char * name,bool strip_suffix)375 void player_safe_name(char *safe, size_t safelen, const char *name, bool strip_suffix)
376 {
377 size_t i;
378 size_t limit = 0;
379
380 if (name) {
381 char *suffix = find_roman_suffix_start(name);
382
383 if (suffix) {
384 limit = suffix - name - 1; /* -1 for preceding space */
385 } else {
386 limit = strlen(name);
387 }
388 }
389
390 /* Limit to maximum size of safename buffer */
391 limit = MIN(limit, safelen);
392
393 for (i = 0; i < limit; i++) {
394 char c = name[i];
395
396 /* Convert all non-alphanumeric symbols */
397 if (!isalpha((unsigned char)c) && !isdigit((unsigned char)c))
398 c = '_';
399
400 /* Build "base_name" */
401 safe[i] = c;
402 }
403
404 /* Terminate */
405 safe[i] = '\0';
406
407 /* Require a "base" name */
408 if (!safe[0])
409 my_strcpy(safe, "PLAYER", safelen);
410 }
411
412
413 /**
414 * Release resources allocated for fields in the player structure.
415 */
player_cleanup_members(struct player * p)416 void player_cleanup_members(struct player *p)
417 {
418 /* Free the history */
419 history_clear(p);
420
421 /* Free the things that are always initialised */
422 if (p->obj_k) {
423 object_free(p->obj_k);
424 }
425 mem_free(p->timed);
426 if (p->upkeep) {
427 mem_free(p->upkeep->quiver);
428 mem_free(p->upkeep->inven);
429 mem_free(p->upkeep);
430 p->upkeep = NULL;
431 }
432
433 /* Free the things that are only sometimes initialised */
434 if (p->quests) {
435 player_quests_free(p);
436 }
437 if (p->spell_flags) {
438 player_spells_free(p);
439 }
440 if (p->gear) {
441 object_pile_free(p->gear);
442 object_pile_free(p->gear_k);
443 }
444 if (p->body.slots) {
445 for (int i = 0; i < p->body.count; i++)
446 string_free(p->body.slots[i].name);
447 mem_free(p->body.slots);
448 }
449 string_free(p->body.name);
450 string_free(p->history);
451 if (p->cave) {
452 cave_free(p->cave);
453 p->cave = NULL;
454 }
455 }
456
457
458 /**
459 * Initialise player struct
460 */
init_player(void)461 static void init_player(void) {
462 /* Create the player array, initialised with 0 */
463 player = mem_zalloc(sizeof *player);
464
465 /* Allocate player sub-structs */
466 player->upkeep = mem_zalloc(sizeof(struct player_upkeep));
467 player->upkeep->inven = mem_zalloc((z_info->pack_size + 1) * sizeof(struct object *));
468 player->upkeep->quiver = mem_zalloc(z_info->quiver_size * sizeof(struct object *));
469 player->timed = mem_zalloc(TMD_MAX * sizeof(s16b));
470 player->obj_k = object_new();
471 player->obj_k->brands = mem_zalloc(z_info->brand_max * sizeof(bool));
472 player->obj_k->slays = mem_zalloc(z_info->slay_max * sizeof(bool));
473 player->obj_k->curses = mem_zalloc(z_info->curse_max *
474 sizeof(struct curse_data));
475
476 options_init_defaults(&player->opts);
477 }
478
479 /**
480 * Free player struct
481 */
cleanup_player(void)482 static void cleanup_player(void) {
483 if (!player) return;
484
485 player_cleanup_members(player);
486
487 /* Free the basic player struct */
488 mem_free(player);
489 player = NULL;
490 }
491
492 struct init_module player_module = {
493 .name = "player",
494 .init = init_player,
495 .cleanup = cleanup_player
496 };
497