root/trunk/src/history.c

Revision 653, 9.0 kB (checked in by takkaria, 4 months ago)

Further work on #430:

  • Clean up object_desc() calls by using the new ODESC_* constants.
  • Add "mode 1" to object_desc() again to only display basename + combat bonuses.
Line 
1 /*
2  * File: history.c
3  * Purpose: Character auto-history creation, management, and display
4  *
5  * Copyright (c) 2007 J.D. White
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 #include "angband.h"
19
20
21
22 /*
23  * Number of slots available at birth in the player history list.  Defaults to
24  * 10 and will expand automatically as new history entries are added, up the
25  * the maximum defined value.
26  */
27 #define HISTORY_BIRTH_SIZE  10
28 #define HISTORY_MAX 5000
29
30
31
32 /* The historical list for the character */
33 history_info *history_list;
34
35 /* Index of first writable entry */
36 static size_t history_ctr;
37
38 /* Current size of history list */
39 static size_t history_size;
40
41
42 #define LIMITLOW(a, b) if (a < b) a = b;
43 #define LIMITHI(a, b) if (a > b) a = b;
44
45
46
47 /*
48  * Initialise an empty history list.
49  */
50 static void history_init(size_t entries)
51 {
52         if (history_list)
53                 FREE(history_list);
54
55         history_ctr = 0;
56         history_size = entries;
57         history_list = C_ZNEW(history_size, history_info);
58 }
59
60
61 /*
62  * Clear any existing history.
63  */
64 void history_clear(void)
65 {
66         if (!history_list) return;
67
68         FREE(history_list);
69         history_ctr = 0;
70         history_size = 0;
71 }
72
73
74 /*
75  * Set the number of history items.
76  */
77 static bool history_set_num(size_t num)
78 {
79         history_info *new_list;
80
81         if (num > HISTORY_MAX)
82                 num = HISTORY_MAX;
83
84         if (num < history_size)  return FALSE;
85         if (num == history_size) return FALSE;
86
87         /* Allocate new memory, copy across */
88         /* XXX Should use mem_realloc() */
89         new_list = C_ZNEW(num, history_info);
90         C_COPY(new_list, history_list, history_ctr, history_info);
91         FREE(history_list);
92
93         history_list = new_list;
94         history_size = num;
95
96         return TRUE;
97 }
98
99
100 /*
101  * Return the number of history entries.
102  */
103 size_t history_get_num(void)
104 {
105         return history_ctr;
106 }
107
108
109 /*
110  * Mark artifact number `id` as known.
111  */
112 static bool history_know_artifact(byte a_idx)
113 {
114         size_t i = history_ctr;
115
116         while (i--)
117         {
118                 if (history_list[i].a_idx == a_idx)
119                 {
120                         history_list[i].type = HISTORY_ARTIFACT_KNOWN;
121                         return TRUE;
122                 }
123         }
124
125         return FALSE;
126 }
127
128
129 /*
130  * Mark artifact number `id` as lost forever, either due to leaving it on a
131  * level, or due to a store purging its inventory after the player sold it.
132  */
133 bool history_lose_artifact(byte a_idx)
134 {
135         size_t i = history_ctr;
136
137         while (i--)
138         {
139                 if (history_list[i].a_idx == a_idx)
140                 {
141                         history_list[i].type |= HISTORY_ARTIFACT_LOST;
142                         return TRUE;
143                 }
144         }
145
146         return FALSE;
147 }
148
149
150 /*
151  * Add an entry with text `event` to the history list, with type `type`
152  * ("HISTORY_xxx" in defines.h), and artifact number `id` (0 for everything
153  * else).
154  *
155  * Returne TRUE on success.
156  */
157 bool history_add_full(u16b type, byte a_idx, s16b dlev, s16b clev, s32b turn, const char *text)
158 {
159         /* Allocate the history list if needed */
160         if (!history_list)
161                 history_init(HISTORY_BIRTH_SIZE);
162
163         /* Expand the history list if appropriate */
164         else if ((history_ctr == history_size) && !history_set_num(history_size + 10))
165                 return FALSE;
166
167         /* History list exists and is not full.  Add an entry at the current counter location. */
168         history_list[history_ctr].type = type;
169         history_list[history_ctr].dlev = dlev;
170         history_list[history_ctr].clev = clev;
171         history_list[history_ctr].a_idx = a_idx;
172         history_list[history_ctr].turn = turn;
173         my_strcpy(history_list[history_ctr].event,
174                   text, sizeof(history_list[history_ctr].event));
175
176         history_ctr++;
177
178         return TRUE;
179 }
180
181
182 /*
183  * Add an entry with text `event` to the history list, with type `type`
184  * ("HISTORY_xxx" in defines.h), and artifact number `id` (0 for everything
185  * else).
186  *
187  * Returne TRUE on success.
188  */
189 bool history_add(const char *event, u16b type, byte a_idx)
190 {
191         return history_add_full(type, a_idx, p_ptr->depth, p_ptr->lev, turn, event);
192 }
193
194
195 /*
196  * Returns TRUE if the artifact denoted by a_idx is an active entry in
197  * the history log (i.e. is not marked HISTORY_ARTIFACT_LOST).  This permits
198  * proper handling of the case where the player loses an artifact but (in
199  * preserve mode) finds it again later.
200  */
201 static bool history_is_artifact_logged(byte a_idx)
202 {
203         size_t i = history_ctr;
204
205         while (i--)
206         {
207                 /* Don't count ARTIFACT_LOST entries; then we can handle
208                  * re-finding previously lost artifacts in preserve mode  */
209                 if (history_list[i].type & HISTORY_ARTIFACT_LOST)
210                         continue;
211
212                 if (history_list[i].a_idx == a_idx)
213                         return TRUE;
214         }
215
216         return FALSE;
217 }
218
219
220 /*
221  * Adding artifacts to the history list is trickier than other operations.
222  * This is a wrapper function that gets some of the logic out of places
223  * where it really doesn't belong.  Call this to add an artifact to the history
224  * list or make the history entry visible--history_add_artifact will make that
225  * determination depending on what object_known_p returns for the artifact.
226  */
227 bool history_add_artifact(byte a_idx, bool known)
228 {
229         object_type object_type_body;
230         object_type *o_ptr = &object_type_body;
231
232         char o_name[80];
233         char buf[80];
234
235         /* Make fake artifact for description purposes */
236         object_wipe(o_ptr);
237         make_fake_artifact(o_ptr, a_idx);
238         object_desc_spoil(o_name, sizeof(o_name), o_ptr, TRUE, ODESC_BASE);
239         strnfmt(buf, sizeof(buf), "Found %s", o_name);
240
241         /* Known objects gets different treatment */
242         if (known)
243         {
244                 /* Try revealing any existing artifact, otherwise log it */
245                 if (history_is_artifact_logged(a_idx))
246                         history_know_artifact(a_idx);
247                 else
248                         history_add(buf, HISTORY_ARTIFACT_KNOWN, a_idx);
249         }
250         else
251         {
252                 if (!history_is_artifact_logged(a_idx))
253                         history_add(buf, HISTORY_ARTIFACT_UNKNOWN, a_idx);
254                 else
255                         return FALSE;
256         }
257
258         return TRUE;
259 }
260
261
262 /*
263  * Convert all ARTIFACT_UNKNOWN history items to HISTORY_ARTIFACT_KNOWN.
264  * Use only after player retirement/death for the final character dump.
265  */
266 void history_unmask_unknown(void)
267 {
268         size_t i = history_ctr;
269
270         while (i--)
271         {
272                 if (history_list[i].type & HISTORY_ARTIFACT_UNKNOWN)
273                 {
274                         history_list[i].type &= ~(HISTORY_ARTIFACT_UNKNOWN);
275                         history_list[i].type |= HISTORY_ARTIFACT_KNOWN;
276                 }
277         }
278 }
279
280
281 /*
282  * Used to determine whether the history entry is visible in the listing or not.
283  * Returns TRUE if the item is masked -- that is, if it is invisible
284  */
285 static bool history_masked(size_t i)
286 {
287         if (history_list[i].type & HISTORY_ARTIFACT_UNKNOWN)
288                 return TRUE;
289
290         return FALSE;
291 }
292
293 /*
294  * Finds the index of the last printable (non-masked) item in the history list.
295  */
296 static int last_printable_item(void)
297 {
298         size_t i = history_ctr;
299
300         while (i--)
301         {
302                 if (!history_masked(i))
303                         break;
304         }
305
306         return i;
307 }
308
309 static void print_history_header(void)
310 {
311         char buf[80];
312
313         /* Print the header (character name and title) */
314         strnfmt(buf, sizeof(buf), "%s the %s %s",
315                 op_ptr->full_name,
316                 p_name + rp_ptr->name,
317                 c_name + cp_ptr->name);
318
319         c_put_str(TERM_WHITE, buf, 0, 0);
320         c_put_str(TERM_WHITE, "============================================================", 1, 0);
321         c_put_str(TERM_WHITE, "                   CHAR.  ", 2, 0);
322         c_put_str(TERM_WHITE, "|   TURN  | DEPTH |LEVEL| EVENT", 3, 0);
323         c_put_str(TERM_WHITE, "============================================================", 4, 0);
324 }
325
326
327 /* Handles all of the display functionality for the history list. */
328 void history_display(void)
329 {
330         int row, wid, hgt, page_size;
331         char buf[90];
332         static int first_item = 0;
333         int max_item = last_printable_item();
334         size_t i;
335
336         Term_get_size(&wid, &hgt);
337
338         /* Six lines provide space for the header and footer */
339         page_size = hgt - 6;
340
341         screen_save();
342
343         while (1)
344         {
345                 char ch;
346
347                 Term_clear();
348
349                 /* Print everything to screen */
350                 print_history_header();
351
352                 row = 0;
353                 for (i = first_item; row <= page_size && i < history_ctr; i++)
354                 {
355                         /* Skip messages about artifacts not yet IDed. */
356                         if (history_masked(i))
357                                 continue;
358
359                         strnfmt(buf, sizeof(buf), "%10d%7d\'%5d   %s",
360                                 history_list[i].turn,
361                                 history_list[i].dlev * 50,
362                                 history_list[i].clev,
363                                 history_list[i].event);
364
365                         if (history_list[i].type & HISTORY_ARTIFACT_LOST)
366                                 my_strcat(buf, " (LOST)", sizeof(buf));
367
368                         /* Size of header = 5 lines */
369                         prt(buf, row + 5, 0);
370                         row++;
371                 }
372                 prt("[Arrow keys scroll, p for previous page, n for next page, ESC to exit.]", hgt - 1, 0);
373
374                 ch = inkey();
375
376                 if (ch == 'n')
377                 {
378                         first_item += page_size;
379
380                         while (history_masked(first_item) && first_item < history_ctr - 1)
381                                 first_item++;
382
383                         LIMITHI(first_item, max_item);
384                 }
385                 else if (ch == 'p')
386                 {
387                         first_item -= page_size;
388
389                         while (history_masked(first_item) && first_item > 0)
390                                 first_item--;
391
392                         LIMITLOW(first_item, 0);
393                 }
394                 else if (ch == ARROW_DOWN)
395                 {
396                         first_item++;
397
398                         while (history_masked(first_item) && first_item < history_ctr - 1)
399                                 first_item++;
400
401                         LIMITHI(first_item, max_item);
402                 }
403                 else if (ch == ARROW_UP)
404                 {
405                         first_item--;
406
407                         while (history_masked(first_item) && first_item > 0)
408                                 first_item--;
409
410                         LIMITLOW(first_item, 0);
411                 }
412                 else if (ch == ESCAPE)
413                         break;
414         }
415
416         screen_load();
417
418         return;
419 }
Note: See TracBrowser for help on using the browser.