Ticket #10: 002-notes.2

File 002-notes.2, 22.1 KB (added by takkaria, 12 years ago)

Updated patch vs r632

Line 
1Index: src/birth.c
2===================================================================
3--- src/birth.c (revision 632)
4+++ src/birth.c (working copy)
5@@ -1937,6 +1937,11 @@
6                player_birth_aux();
7        }
8 
9+
10+       /* Init the history (to clear old messages) */
11+       history_init(HISTORY_BIRTH_SIZE);
12+       history_add("Began the quest to destroy Morgoth.", HISTORY_PLAYER_BIRTH, 0);
13+
14        /* Note player birth in the message recall */
15        message_add(" ", MSG_GENERIC);
16        message_add("  ", MSG_GENERIC);
17Index: src/load.c
18===================================================================
19--- src/load.c  (revision 632)
20+++ src/load.c  (working copy)
21@@ -2049,6 +2049,7 @@
22        u32b n_x_check, n_v_check;
23        u32b o_x_check, o_v_check;
24 
25+       char buf[80];
26 
27        /* Mention the savefile version */
28        note(format("Loading a %d.%d.%d savefile...",
29@@ -2257,7 +2258,38 @@
30                rd_ghost();
31        }
32 
33+       /* Read in the history list if the savefile is new enough */
34+       if (!older_than(3, 0, 11))
35+       {
36+               /* Read and set the current history counter */
37+               rd_u32b(&tmp32u);
38+               history_init(tmp32u);
39 
40+               for (history_ctr = 0; history_ctr < tmp32u; history_ctr++)
41+               {
42+                       rd_u16b(&history_list[history_ctr].type);
43+                       rd_s32b(&history_list[history_ctr].turns);
44+                       rd_s16b(&history_list[history_ctr].cur_dun);
45+                       rd_s16b(&history_list[history_ctr].cur_lev);
46+                       rd_byte(&history_list[history_ctr].id);
47+
48+                       rd_string(history_list[history_ctr].event,
49+                                 sizeof(history_list[history_ctr].event));
50+               }
51+       }
52+
53+       /*
54+        * Savefile is from an older version:
55+        * Still have to initialize the variables correctly.
56+        * Then the game should correctly log future history entries.
57+        */
58+       else
59+       {
60+               strnfmt(buf, sizeof(buf), "Imported an Angband %d.%d.%d savefile",
61+                       sf_major, sf_minor, sf_patch);
62+               history_add(buf, HISTORY_SAVEFILE_IMPORT, 0);
63+       }
64+
65        /* Save the checksum */
66        n_v_check = v_check;
67 
68Index: src/defines.h
69===================================================================
70--- src/defines.h       (revision 632)
71+++ src/defines.h       (working copy)
72@@ -214,6 +214,27 @@
73 
74 
75 /*
76+ * Number of slots available at birth in the player history list.  Defaults to
77+ * 10 and will expand automatically as new history entries are added, up the
78+ * the maximum defined value.
79+ */
80+#define HISTORY_BIRTH_SIZE  10
81+#define HISTORY_MAX 5000
82+
83+/* History message types */
84+#define HISTORY_PLAYER_BIRTH     0x0001        /* Player was born */
85+#define HISTORY_ARTIFACT_UNKNOWN 0x0002        /* Player found but not IDd an artifact */
86+#define HISTORY_ARTIFACT_KNOWN   0x0004        /* Player has IDed an artifact */
87+#define HISTORY_ARTIFACT_LOST    0x0008        /* Player had an artifact and lost it */
88+#define HISTORY_PLAYER_DEATH     0x0010        /* Player has been slain */
89+#define HISTORY_SLAY_UNIQUE      0x0020        /* Player has slain a unique monster */
90+#define HISTORY_USER_INPUT       0x0040        /* User-added note */
91+#define HISTORY_SAVEFILE_IMPORT  0x0080        /* Added when an older version savefile is imported */
92+#define HISTORY_GAIN_LEVEL       0x0100        /* Player gained a level */
93+#define HISTORY_GENERIC          0x0200        /* Anything else not covered here (unused) */
94+
95+
96+/*
97  * Store constants
98  *
99  * STORE_MAX_KEEP must be < STORE_INVEN_MAX.
100Index: src/Makefile.src
101===================================================================
102--- src/Makefile.src    (revision 632)
103+++ src/Makefile.src    (working copy)
104@@ -68,6 +68,7 @@
105        game-cmd.o \
106        game-event.o \
107        generate.o \
108+       history.o \
109        init1.o \
110        init2.o \
111        load.o \
112Index: src/death.c
113===================================================================
114--- src/death.c (revision 632)
115+++ src/death.c (working copy)
116@@ -373,6 +373,18 @@
117 
118 
119 /*
120+ * Menu command: view character history.
121+ */
122+static void death_history(void *unused, const char *title)
123+{
124+       (void)unused;
125+       (void)title;
126+
127+       history_display();
128+}
129+
130+
131+/*
132  * Menu structures for the death menu.
133  */
134 static menu_type death_menu;
135@@ -383,6 +395,7 @@
136        { 'f', "File dump",     death_file,     NULL },
137        { 'v', "View scores",   death_scores,   NULL },
138        { 'x', "Examine items", death_examine,  NULL },
139+       { 'h', "History",       death_history,  NULL },
140        { 'q', "Quit",          death_examine,  NULL },
141 };
142 
143@@ -421,7 +434,7 @@
144 {
145        menu_type *menu;
146        const char cmd_keys[] = { ARROW_LEFT, ARROW_RIGHT, '\0' };
147-       const region area = { 51, 2, 0, 6 };
148+       const region area = { 51, 2, 0, 7 };
149 
150        int cursor = 0;
151        ui_event_data c = EVENT_EMPTY;
152@@ -472,7 +485,7 @@
153        {
154                c = menu_select(&death_menu, &cursor, 0);
155 
156-               if (c.key == ESCAPE || cursor == 5)
157+               if (c.key == ESCAPE || cursor == 6)
158                {
159                        if (get_check("Do you want to quit? "))
160                                break;
161Index: src/externs.h
162===================================================================
163--- src/externs.h       (revision 632)
164+++ src/externs.h       (working copy)
165@@ -245,6 +245,10 @@
166 extern autoinscription *inscriptions;
167 extern u16b inscriptions_count;
168 
169+/* history.c */
170+extern history_info *history_list;
171+extern size_t history_ctr;
172+
173 /* squelch.c */
174 extern byte squelch_level[SQUELCH_BYTES];
175 
176@@ -341,6 +345,15 @@
177 /* generate.c */
178 extern void generate_cave(void);
179 
180+/* history.c */
181+void history_init(size_t entries);
182+void history_unmask_unknown(void);
183+bool history_add(const char *event, u16b message_type, byte id);
184+bool history_add_artifact(const object_type *o_ptr);
185+bool history_artifact_lost(byte id);
186+void history_display(void);
187+
188+
189 /* init2.c */
190 extern void init_file_paths(const char *path);
191 extern void create_user_dirs(void);
192Index: src/history.c
193===================================================================
194--- src/history.c       (revision 0)
195+++ src/history.c       (revision 0)
196@@ -0,0 +1,404 @@
197+/*
198+ * File: notes.c
199+ * Purpose: Character auto-history creation, management, and display
200+ *
201+ * Copyright (c) 2007 J.D. White
202+ *
203+ * This work is free software; you can redistribute it and/or modify it
204+ * under the terms of either:
205+ *
206+ * a) the GNU General Public License as published by the Free Software
207+ *    Foundation, version 2, or
208+ *
209+ * b) the "Angband licence":
210+ *    This software may be copied and distributed for educational, research,
211+ *    and not for profit purposes provided that this copyright and statement
212+ *    are included in all such copies.  Other copyrights may also apply.
213+ */
214+#include "angband.h"
215+
216+
217+/* The historical list for the character */
218+history_info *history_list;
219+
220+/* Index of first writable entry */
221+size_t history_ctr;
222+
223+/* Current size of history list */
224+static size_t history_size;
225+
226+
227+#define LIMITLOW(a, b) if (a < b) a = b;
228+#define LIMITHI(a, b) if (a > b) a = b;
229+
230+
231+/*
232+ * Convert all ARTIFACT_UNKNOWN history items to HISTORY_ARTIFACT_KNOWN.
233+ * Use only after player retirement/death for the final character dump.
234+ */
235+void history_unmask_unknown(void)
236+{
237+       size_t i = history_ctr;
238+
239+       while (i--)
240+       {
241+               if (history_list[i].type & HISTORY_ARTIFACT_UNKNOWN)
242+                       history_list[i].type = HISTORY_ARTIFACT_KNOWN;
243+       }
244+}
245+
246+
247+/*
248+ * Returns the status of the artifact (either HISTORY_ARTIFACT_KNOWN or
249+ * HISTORY_ARTIFACT_UNKNOWN).
250+ *
251+ * Allows us to preserve this status while adding the HISTORY_ARTIFACT_LOST
252+ * flag if necessary.
253+ */
254+static u16b history_get_artifact_status(byte artifact_id)
255+{
256+       size_t i = history_ctr;
257+
258+       while (i--)
259+       {
260+               /* Skip any artifacts marked as lost */
261+               if (history_list[i].type & HISTORY_ARTIFACT_LOST)
262+                       continue;
263+
264+               if (history_list[i].id == artifact_id)
265+                       return history_list[i].type;
266+       }
267+
268+       return HISTORY_ARTIFACT_KNOWN;
269+}
270+
271+/*
272+ * Sets the status of the history entry that contains the selected artifact.
273+ * Ignores any HISTORY_ARTIFACT_LOST entries.
274+ */
275+static bool history_set_artifact_status(byte artifact_id, u16b message_type)
276+{
277+       size_t i = history_ctr;
278+
279+       while (i--)
280+       {
281+               /* Skip any artifacts marked as LOST */
282+               if (history_list[i].type & HISTORY_ARTIFACT_LOST)
283+                       continue;
284+
285+               if (history_list[i].id == artifact_id)
286+               {
287+                       history_list[i].type = message_type;
288+                       return TRUE;
289+               }
290+       }
291+
292+       return FALSE;
293+}
294+
295+/*
296+ * Returns TRUE if the artifact denoted by artifact_id is an active entry in the history log--that is,
297+ * NOT marked as HISTORY_ARTIFACT_LOST.  This permits proper handling of the case where the player loses
298+ * an artifact but (in preserve mode) finds it again later.
299+ */
300+static bool history_artifact_logged(const byte artifact_id)
301+{
302+       size_t i = history_ctr;
303+
304+       while (i--)
305+       {
306+               /* Don't count ARTIFACT_LOST entries; then we can handle
307+                * re-finding previously lost artifacts in preserve mode  */
308+               if (history_list[i].type & HISTORY_ARTIFACT_LOST)
309+                       continue;
310+
311+               if (history_list[i].id == artifact_id)
312+                       return TRUE;
313+       }
314+
315+       return FALSE;
316+}
317+
318+/*
319+ * Initialise an empty history list.
320+ */
321+void history_init(size_t entries)
322+{
323+       if (history_list)
324+               FREE(history_list);
325+
326+       history_ctr = 0;
327+       history_size = entries;
328+       history_list = C_ZNEW(history_size, history_info);
329+}
330+
331+/*
332+ * History list is full, expand it by another ten entries
333+ */
334+static bool history_expand(int increment)
335+{
336+       history_info *new_history_list;
337+       size_t newsize;
338+
339+       /* Create array of history_size+10 OR maximum size, whichever is smaller */
340+       if (history_size >= HISTORY_MAX)
341+               return FALSE;
342+       else if (history_size + increment >= HISTORY_MAX)
343+               newsize = HISTORY_MAX;
344+       else
345+               newsize = history_size + increment;
346+
347+       /* Allocate new memory, copy across */
348+       /* XXX Should use mem_realloc() */
349+       new_history_list = C_ZNEW(newsize, history_info);
350+       C_COPY(new_history_list, history_list, history_ctr, history_info);
351+       FREE(history_list);
352+
353+       history_list = new_history_list;
354+       history_size = newsize;
355+
356+       return TRUE;
357+}
358+
359+/*
360+ * Add an entry with text `event` to the history list, with type `message_type`
361+ * ("HISTORY_xxx" in defines.h), and artifact number `id` (0 for everything
362+ * else).
363+ *
364+ * Returne TRUE on success.
365+ */
366+bool history_add(const char *event, u16b message_type, byte id)
367+{
368+       /* History list head ptr is history_list
369+        * Currently writable location is history_list[history_ctr]
370+        * Last writable entry in list is
371+        *    history_list[history_size - 1]
372+        */
373+
374+       /* Something is very wrong if this is true. Bail out. */
375+       if (!p_ptr) return FALSE;
376+
377+       /* Allocate the history list if needed */
378+       if (!history_list)
379+               history_init(HISTORY_BIRTH_SIZE);
380+
381+       /* Expand the history list if appropriate */
382+       else if ((history_ctr == history_size) && !history_expand(10))
383+               return FALSE;
384+
385+       /* History list exists and is not full.  Add an entry at the current counter location. */
386+       history_list[history_ctr].type = message_type;
387+       history_list[history_ctr].cur_dun = p_ptr->depth;
388+       history_list[history_ctr].cur_lev = p_ptr->lev;
389+       history_list[history_ctr].id = id;
390+       history_list[history_ctr].turns = turn;
391+       my_strcpy(history_list[history_ctr].event,
392+                 event, sizeof(history_list[history_ctr].event));
393+
394+       history_ctr++;
395+
396+       return TRUE;
397+}
398+
399+
400+/*
401+ * Adding artifacts to the history list is trickier than other operations.
402+ * This is a wrapper function that gets some of the logic out of places
403+ * where it really doesn't belong.  Call this to add an artifact to the history
404+ * list or make the history entry visible--history_add_artifact will make that
405+ * determination depending on what object_known_p returns for the artifact.
406+ */
407+bool history_add_artifact(const object_type *o_ptr)
408+{
409+       char o_name[80];
410+       char buf[80];
411+
412+       /* Paranoia */
413+       if (!artifact_p(o_ptr))
414+               return FALSE;
415+
416+       /* Use object_desc_spoil, otherwise item must be known to get name from object_desc */
417+       object_desc_spoil(o_name, sizeof(o_name), o_ptr, TRUE, 0);
418+       strnfmt(buf, sizeof(buf), "Found %s", o_name);
419+
420+       /* If object_known_p returns TRUE, we have an identified artifact.
421+        * Check to be sure that the item is not in the history list,
422+        * and add it if there is not an existing entry.
423+        */
424+       if (object_known_p(o_ptr))
425+       {
426+               /* First see if there is an existing "UNKNOWN" entry we can convert to a known artifact */
427+               if (history_set_artifact_status(o_ptr->name1, HISTORY_ARTIFACT_KNOWN))
428+               {
429+                       return TRUE;
430+               }
431+               /* Next see if a line exists in the log. If not, add it. */
432+               else if (!history_artifact_logged(o_ptr->name1))
433+               {
434+                       history_add(buf, HISTORY_ARTIFACT_KNOWN, o_ptr->name1);
435+                       return TRUE;
436+               }
437+       }
438+
439+       /* If object_known_p returns FALSE, we have an artifact but
440+        * the player does not know it as an artifact.  Add as an UNKNOWN.
441+        */
442+       else
443+       {
444+               if (!history_artifact_logged(o_ptr->name1))
445+               {
446+                       history_add(buf, HISTORY_ARTIFACT_UNKNOWN, o_ptr->name1);
447+                       return TRUE;
448+               }
449+       }
450+
451+       return FALSE;
452+}
453+
454+/*
455+ * Mark artifact number `id` as lost forever, either due to leaving it on a
456+ * level, or due to a store purging its inventory after the player sold it.
457+ */
458+bool history_artifact_lost(byte id)
459+{
460+       return history_set_artifact_status(id,
461+              history_get_artifact_status(id) | HISTORY_ARTIFACT_LOST);
462+}
463+
464+/*
465+ * Used to determine whether the history entry is visible in the listing or not.
466+ * Returns TRUE if the item is masked -- that is, if it is invisible
467+ */
468+static bool history_masked(size_t i)
469+{
470+       if (history_list[i].type & HISTORY_ARTIFACT_UNKNOWN)
471+               return TRUE;
472+
473+       return FALSE;
474+}
475+
476+/* Finds the index of the last printable (non-masked) item in the history list. */
477+static int last_printable_item(void)
478+{
479+       size_t i = history_ctr;
480+
481+       while (i--)
482+       {
483+               if (!history_masked(i))
484+                       break;
485+       }
486+
487+       return i;
488+}
489+
490+static void print_history_header(void)
491+{
492+       char buf[80];
493+
494+       /* Print the header (character name and title) */
495+       strnfmt(buf, sizeof(buf), "%s the %s %s",
496+               op_ptr->full_name,
497+               p_name + rp_ptr->name,
498+               c_name + cp_ptr->name);
499+
500+       c_put_str(TERM_WHITE, buf, 0, 0);
501+       c_put_str(TERM_WHITE, "============================================================", 1, 0);
502+       c_put_str(TERM_WHITE, "                   CHAR.  ", 2, 0);
503+       c_put_str(TERM_WHITE, "|   TURN  | DEPTH |LEVEL| EVENT", 3, 0);
504+       c_put_str(TERM_WHITE, "============================================================", 4, 0);
505+}
506+
507+
508+/* Handles all of the display functionality for the history list. */
509+void history_display(void)
510+{
511+       int row, wid, hgt, page_size;
512+       char buf[90];
513+       static int first_item = 0;
514+       int max_item = last_printable_item();
515+       size_t i;
516+
517+       Term_get_size(&wid, &hgt);
518+
519+       /* Six lines provide space for the header and footer */
520+       page_size = hgt - 6;
521+
522+       screen_save();
523+
524+       while (1)
525+       {
526+               char ch;
527+
528+               Term_clear();
529+
530+               /* Print everything to screen */
531+               print_history_header();
532+
533+               row = 0;
534+               for (i = first_item; row <= page_size && i < history_ctr; i++)
535+               {
536+                       /* Skip messages about artifacts not yet IDed. */
537+                       if (history_masked(i))
538+                               continue;
539+
540+                       strnfmt(buf, sizeof(buf), "%10d%7d\'%5d   %s",
541+                               history_list[i].turns,
542+                               history_list[i].cur_dun * 50,
543+                               history_list[i].cur_lev,
544+                               history_list[i].event);
545+
546+                       if (history_list[i].type & HISTORY_ARTIFACT_LOST)
547+                               strncat(buf, " (LOST)", sizeof(buf));
548+
549+                       /* Size of header = 5 lines */
550+                       prt(buf, row + 5, 0);
551+                       row++;
552+               }
553+               prt("[Arrow keys scroll, p for previous page, n for next page, ESC to exit.]", hgt - 1, 0);
554+
555+               ch = inkey();
556+
557+               if (ch == 'n')
558+               {
559+                       first_item += page_size;
560+
561+                       while (history_masked(first_item) && first_item < history_ctr - 1)
562+                               first_item++;
563+
564+                       LIMITHI(first_item, max_item);
565+               }
566+               else if (ch == 'p')
567+               {
568+                       first_item -= page_size;
569+
570+                       while (history_masked(first_item) && first_item > 0)
571+                               first_item--;
572+
573+                       LIMITLOW(first_item, 0);
574+               }
575+               else if (ch == ARROW_DOWN)
576+               {
577+                       first_item++;
578+
579+                       while (history_masked(first_item) && first_item < history_ctr - 1)
580+                               first_item++;
581+
582+                       LIMITHI(first_item, max_item);
583+               }
584+               else if (ch == ARROW_UP)
585+               {
586+                       first_item--;
587+
588+                       while (history_masked(first_item) && first_item > 0)
589+                               first_item--;
590+
591+                       LIMITLOW(first_item, 0);
592+               }
593+               else if (ch == ESCAPE)
594+                       break;
595+       }
596+
597+       screen_load();
598+
599+       return;
600+}
601Index: src/cmd4.c
602===================================================================
603--- src/cmd4.c  (revision 632)
604+++ src/cmd4.c  (working copy)
605@@ -19,6 +19,7 @@
606 #include "angband.h"
607 #include "option.h"
608 #include "ui.h"
609+#include "externs.h"
610 #include "ui-menu.h"
611 
612 
613@@ -4062,6 +4063,12 @@
614        show_scores();
615 }
616 
617+static void do_cmd_knowledge_history(void *obj, const char *name)
618+{
619+       history_display();     
620+}
621+
622+
623 /*
624  * Definition of the "player knowledge" menu.
625  */
626@@ -4074,6 +4081,7 @@
627        {{0, "Display feature knowledge", do_cmd_knowledge_features, 0}, 'e'},
628        {{0, "Display self-knowledge", do_cmd_self_knowledge, 0}, 'f'},
629        {{0, "Display hall of fame", do_cmd_knowledge_scores, 0}, 'g'},
630+       {{0, "Display character history", do_cmd_knowledge_history, 0}, 'h'},
631 };
632 
633 static menu_type knowledge_menu;
634@@ -4253,6 +4261,9 @@
635 
636        /* Add the note to the message recall */
637        msg_format("Note: %s", tmp);
638+
639+       /* Add a history entry */
640+       history_add(tmp, HISTORY_USER_INPUT, 0);
641 }
642 
643 
644Index: src/xtra2.c
645===================================================================
646--- src/xtra2.c (revision 632)
647+++ src/xtra2.c (working copy)
648@@ -991,12 +991,22 @@
649               (p_ptr->exp >= (player_exp[p_ptr->lev-1] *
650                               p_ptr->expfact / 100L)))
651        {
652+               char buf[80];
653+               
654                /* Gain a level */
655                p_ptr->lev++;
656 
657                /* Save the highest level */
658-               if (p_ptr->lev > p_ptr->max_lev) p_ptr->max_lev = p_ptr->lev;
659+               if (p_ptr->lev > p_ptr->max_lev)
660+               {
661+                       p_ptr->max_lev = p_ptr->lev;
662 
663+                       /* Log level updates (TODO: perhaps only every other level or every 5) */
664+                       strnfmt(buf, sizeof(buf), "Reached level %d", p_ptr->lev);
665+                       history_add(buf, HISTORY_GAIN_LEVEL, 0);
666+                       
667+               }
668+                       
669                /* Message */
670                message_format(MSG_LEVEL, p_ptr->lev, "Welcome to level %d.", p_ptr->lev);
671 
672@@ -1408,6 +1418,7 @@
673        if (m_ptr->hp < 0)
674        {
675                char m_name[80];
676+               char buf[80];
677 
678                /* Assume normal death sound */
679                int soundfx = MSG_KILL;
680@@ -1473,6 +1484,20 @@
681                        p_ptr->exp_frac = (u16b)new_exp_frac;
682                }
683 
684+               /* When the player kills a Unique, it stays dead */
685+               if (r_ptr->flags1 & (RF1_UNIQUE))
686+               {
687+                       char unique_name[80];
688+                       r_ptr->max_num = 0;
689+                       
690+                       /* This gets the correct name if we slay an invisible unique and don't have See Invisible. */
691+                       monster_desc(unique_name, sizeof(unique_name), m_ptr, 0x88);
692+
693+                       /* Log the slaying of a unique */
694+                       strnfmt(buf, sizeof(buf), "Killed %s", unique_name);
695+                       history_add(buf, HISTORY_SLAY_UNIQUE, 0);
696+               }
697+                       
698                /* Gain experience */
699                gain_exp(new_exp);
700 
701Index: src/store.c
702===================================================================
703--- src/store.c (revision 632)
704+++ src/store.c (working copy)
705@@ -1077,6 +1077,10 @@
706 
707        }
708 
709+       /* Is the item an artifact? Mark it as lost if the player has it in history list */
710+       if (artifact_p(o_ptr))
711+               history_artifact_lost(o_ptr->name1);
712+
713        /* Delete the item */
714        store_item_increase(st, what, -num);
715        store_item_optimize(st, what);
716@@ -2224,6 +2228,10 @@
717                object_aware(o_ptr);
718                object_known(o_ptr);
719 
720+               /* Update the auto-history if selling an artifact that was previously un-IDed. (Ouch!) */
721+               if (artifact_p(o_ptr))
722+                       history_add_artifact(o_ptr);
723+
724                /* Combine / Reorder the pack (later) */
725                p_ptr->notice |= (PN_COMBINE | PN_REORDER);
726 
727Index: src/types.h
728===================================================================
729--- src/types.h (revision 632)
730+++ src/types.h (working copy)
731@@ -90,6 +90,7 @@
732 typedef struct player_type player_type;
733 typedef struct start_item start_item;
734 typedef struct autoinscription autoinscription;
735+typedef struct history_info history_info;
736 
737 
738 /**** Available structs ****/
739@@ -1034,7 +1035,7 @@
740 
741        s16b pspeed;            /* Current speed */
742 
743-    /* Generation fields (for quick start) */
744+       /* Generation fields (for quick start) */
745        s32b au_birth;          /* Birth gold */
746        s16b stat_birth[A_MAX]; /* Birth "natural" stat values */
747        s16b ht_birth;          /* Birth Height */
748@@ -1115,6 +1116,16 @@
749 };
750 
751 
752+struct history_info
753+{
754+       u16b type;                              /* Kind of history item */
755+       s16b cur_dun;                   /* Dungeon level when this item was recorded */
756+       s16b cur_lev;                   /* Character level when this item was recorded */
757+       byte id;                                        /* Artifact this item relates to */
758+       s32b turns;                             /* Turn this item was recorded on */
759+       char event[80];         /* The text of the item */
760+};
761+
762 enum grid_light_level
763 {
764        LIGHT_TORCH,
765Index: src/cmd1.c
766===================================================================
767--- src/cmd1.c  (revision 632)
768+++ src/cmd1.c  (working copy)
769@@ -284,6 +284,12 @@
770                msg_format("You have %s (%c).", o_name, index_to_label(slot));
771        }
772 
773+       /* Log if picking up an artifact. */
774+       if (artifact_p(o_ptr))
775+       {
776+               history_add_artifact(o_ptr);
777+       }
778+
779        /* Delete the object */
780        delete_object_idx(o_idx);
781 }
782Index: src/object2.c
783===================================================================
784--- src/object2.c       (revision 632)
785+++ src/object2.c       (working copy)
786@@ -464,6 +464,10 @@
787                                a_info[o_ptr->name1].cur_num = 0;
788                }
789 
790+               /* Mark artifacts as lost in logs */
791+               if (artifact_p(o_ptr))
792+                       history_artifact_lost(o_ptr->name1);
793+
794                /* Monster */
795                if (o_ptr->held_m_idx)
796                {
797Index: src/save.c
798===================================================================
799--- src/save.c  (revision 632)
800+++ src/save.c  (working copy)
801@@ -813,8 +813,8 @@
802        u32b now;
803 
804        u16b tmp16u;
805+       u32b tmp32u;
806 
807-
808        /* Guess at the current time */
809        now = time((time_t *)0);
810 
811@@ -995,7 +995,23 @@
812                wr_ghost();
813        }
814 
815+       /* NEW (jdw): dumping history entries */
816+       /* Dump the number of history entries */
817+       tmp32u = history_ctr;
818+       wr_u32b(tmp32u);
819 
820+       /* Dump the history entries one-by-one */
821+       for (i = 0; i < tmp32u; i++)
822+       {
823+               wr_u16b(history_list[i].type);
824+               wr_s32b(history_list[i].turns);
825+               wr_s16b(history_list[i].cur_dun);
826+               wr_s16b(history_list[i].cur_lev);
827+               wr_byte(history_list[i].id);
828+               wr_string(history_list[i].event);
829+       }
830+
831+
832        /* Write the "value check-sum" */
833        wr_u32b(v_stamp);
834 
835Index: src/spells2.c
836===================================================================
837--- src/spells2.c       (revision 632)
838+++ src/spells2.c       (working copy)
839@@ -3689,6 +3689,18 @@
840                sound(MSG_IDENT_EGO);
841        }
842 
843+       /* Log artifacts to the history list.
844+        * Can't do this in the 'else if' above, because it only catches 'good'
845+        * artifacts--thus doesn't log cursed or dubious artifacts (pval < 0)
846+        */
847+       if (artifact_p(o_ptr))
848+       {
849+               /* Update artifact history entry to mark as known or add a new item
850+                * as appropriate. Logic to do this properly is in history_add_artifact.
851+                */
852+               history_add_artifact(o_ptr);   
853+       }
854+       
855        /* Describe */
856        if (item >= INVEN_WIELD)
857        {