1 /* Write live game progress changes to a log file
2 * Needs xlog-v3 patch. */
8 /* Encodes the current xlog "achieve" status to an integer */
12 /* Achievement bitfield:
14 * 0 obtained the Bell of Opening
15 * 1 entered gehennom (by any means)
16 * 2 obtained the Candelabrum of Invocation
17 * 3 obtained the Book of the Dead
18 * 4 performed the invocation ritual
19 * 5 obtained the amulet
20 * 6 entered elemental planes
21 * 7 entered astral plane
22 * 8 ascended (not "escaped in celestial disgrace!")
23 * 9 obtained the luckstone from the Mines
24 * 10 obtained the sokoban prize
32 * 18 killed The Largest Giant
36 * 22 killed Frankenstein
40 * 26 imbued the Bell of Opening
41 * 27 imbued the Amulet of Yendor
48 if(achieve
.get_bell
) r
|= 1L << 0;
49 if(achieve
.enter_gehennom
) r
|= 1L << 1;
50 if(achieve
.get_candelabrum
) r
|= 1L << 2;
51 if(achieve
.get_book
) r
|= 1L << 3;
52 if(achieve
.perform_invocation
) r
|= 1L << 4;
53 if(achieve
.get_amulet
) r
|= 1L << 5;
54 if(In_endgame(&u
.uz
)) r
|= 1L << 6;
55 if(Is_astralevel(&u
.uz
)) r
|= 1L << 7;
56 if(achieve
.ascended
) r
|= 1L << 8;
57 if(achieve
.get_luckstone
) r
|= 1L << 9;
58 if(achieve
.finish_sokoban
) r
|= 1L << 10;
59 if(achieve
.killed_medusa
) r
|= 1L << 11;
60 if(achieve
.killed_nightmare
) r
|= 1L << 12;
61 if(achieve
.killed_vecna
) r
|= 1L << 13;
62 if(achieve
.killed_beholder
) r
|= 1L << 14;
63 if(achieve
.killed_ruggo
) r
|= 1L << 15;
64 if(achieve
.killed_kroo
) r
|= 1L << 16;
65 if(achieve
.killed_grund
) r
|= 1L << 17;
66 if(achieve
.killed_largestgiant
) r
|= 1L << 18;
67 if(achieve
.killed_shelob
) r
|= 1L << 19;
68 if(achieve
.killed_girtab
) r
|= 1L << 20;
69 if(achieve
.killed_aphrodite
) r
|= 1L << 21;
70 if(achieve
.killed_frankenstein
) r
|= 1L << 22;
71 if(achieve
.killed_croesus
) r
|= 1L << 23;
72 if(achieve
.killed_dagon
) r
|= 1L << 24;
73 if(achieve
.killed_hydra
) r
|= 1L << 25;
74 if(achieve
.imbued_bell
) r
|= 1L << 26;
75 if(achieve
.imbued_amulet
) r
|= 1L << 27;
80 /* Encodes the current xlog "achieveX" status to an integer */
84 /* Achievement bitfield:
86 * 0 killed an elder priest
87 * 1 killed the Motherfucker Glass Golem
88 * 2 killed Tiksrvzllat
90 * 4 reached the bottom of the Swimming Pools
91 * 5 killed Erogenous Katia
92 * 6 killed the Witch King of Angmar
93 * 7 obtained the stone of magic resistance from the Deep Mines
94 * 8 completed all the DevNull dungeons
95 * 9 killed the Minotaur of the Maze
99 * 13 completed the Rival Quest
100 * 14 completed Minus World
109 if(achieveX
.killed_elderpriest
) r
|= 1L << 0;
110 if(achieveX
.killed_glassgolem
) r
|= 1L << 1;
111 if(achieveX
.killed_tiksrvzllat
) r
|= 1L << 2;
112 if(achieveX
.killed_bofh
) r
|= 1L << 3;
113 if(achieveX
.swimmingpool_cleared
) r
|= 1L << 4;
114 if(achieveX
.killed_katia
) r
|= 1L << 5;
115 if(achieveX
.killed_witchking
) r
|= 1L << 6;
116 if(achieveX
.get_magresstone
) r
|= 1L << 7;
117 if(achieveX
.devnull_complete
) r
|= 1L << 8;
118 if(achieveX
.killed_minotaur
) r
|= 1L << 9;
119 if(achieveX
.killed_kalwina
) r
|= 1L << 10;
120 if(achieveX
.killed_stahngnir
) r
|= 1L << 11;
121 if(achieveX
.killed_ariane
) r
|= 1L << 12;
122 if(achieveX
.completed_rivalquest
) r
|= 1L << 13;
123 if(achieveX
.completed_minusworld
) r
|= 1L << 14;
124 if(achieveX
.killed_vera
) r
|= 1L << 15;
125 if(achieveX
.killed_elaine
) r
|= 1L << 16;
130 /* Keep the last xlog "achieve" value to be able to compare */
131 long last_achieve_int
;
132 long last_achieveX_int
;
134 /* Generic buffer for snprintf */
135 #define STRBUF_LEN (4096)
136 char strbuf
[STRBUF_LEN
];
138 /* Open the live log file */
139 boolean
livelog_start() {
142 last_achieve_int
= encodeachieve();
143 last_achieveX_int
= encodeachieveX();
148 /* Locks the live log file and writes 'buffer' */
149 void livelog_write_string(char* buffer
) {
153 if (lock_file_area(LOGAREA
, LIVELOGFILE
, 10)) {
155 if (lock_file(LIVELOGFILE
, SCOREPREFIX
, 10)) {
157 if(!(livelogfile
= fopen_datafile_area(LOGAREA
, LIVELOGFILE
, "a", SCOREPREFIX
))) {
158 pline("Cannot open live log file!");
160 fprintf(livelogfile
,"%s", buffer
);
161 (void) fclose(livelogfile
);
163 unlock_file_area(LOGAREA
, LIVELOGFILE
);
167 /* Writes changes in the achieve structure to the live log.
168 * Called from various places in the NetHack source,
169 * usually where xlog's achieve is set. */
170 void livelog_achieve_update() {
171 long achieve_int
, achieve_diff
, achieveX_int
, achieveX_diff
;
173 achieve_int
= encodeachieve();
174 achieve_diff
= last_achieve_int
^ achieve_int
;
176 achieveX_int
= encodeachieveX();
177 achieveX_diff
= last_achieveX_int
^ achieveX_int
;
179 /* livelog_achieve_update is sometimes called when there's
180 * no actual change. */
181 if(achieve_diff
== 0 && achieveX_diff
== 0) {
185 snprintf(strbuf
, STRBUF_LEN
,
186 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:achieve=0x%lx:achieve_diff=0x%lx:achieveX=0x%lx:achieveX_diff=0x%lx\n",
187 plalias
[0] ? plalias
: plname
,
188 plalias
[0] ? " (" : "",
189 plalias
[0] ? plname
: "",
190 plalias
[0] ? ")" : "",
191 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
198 livelog_write_string(strbuf
);
200 last_achieve_int
= achieve_int
;
201 last_achieveX_int
= achieveX_int
;
210 snprintf(strbuf
, STRBUF_LEN
,
211 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:wish=%s\n",
212 plalias
[0] ? plalias
: plname
,
213 plalias
[0] ? " (" : "",
214 plalias
[0] ? plname
: "",
215 plalias
[0] ? ")" : "",
216 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
220 livelog_write_string(strbuf
);
223 /* Reports achievements */
225 livelog_report_trophy(string
)
228 snprintf(strbuf
, STRBUF_LEN
,
229 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:message=%s\n",
230 plalias
[0] ? plalias
: plname
,
231 plalias
[0] ? " (" : "",
232 plalias
[0] ? plname
: "",
233 plalias
[0] ? ")" : "",
234 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
238 livelog_write_string(strbuf
);
241 /* Reports lifesaving */
243 livelog_avert_death()
245 snprintf(strbuf
, STRBUF_LEN
,
246 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:message=%s\n",
247 plalias
[0] ? plalias
: plname
,
248 plalias
[0] ? " (" : "",
249 plalias
[0] ? plname
: "",
250 plalias
[0] ? ")" : "",
251 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
255 livelog_write_string(strbuf
);
264 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
267 sprintf(qbuf
,"Shout what?");
270 You("shout into the void: %s", buf
);
272 /* filter livelog delimiter */
273 for (p
= buf
; *p
!= 0; p
++)
277 snprintf(strbuf
, STRBUF_LEN
,
278 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:shout=%s\n",
279 plalias
[0] ? plalias
: plname
,
280 plalias
[0] ? " (" : "",
281 plalias
[0] ? plname
: "",
282 plalias
[0] ? ")" : "",
283 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
287 livelog_write_string(strbuf
);
292 #endif /* LIVELOG_SHOUT */
294 #ifdef LIVELOG_BONES_KILLER
296 livelog_bones_killed(mtmp
)
299 char *name
= NAME(mtmp
);
301 if (name
&& mtmp
->former_rank
&& mtmp
->former_rank
[0]) {
302 /* $player killed the $bones_monst of $bones_killed the former
303 * $bones_rank on $turns on dungeon level $dlev! */
304 snprintf(strbuf
, STRBUF_LEN
,
305 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:dlev=%d:"
306 "bones_killed=%s:bones_rank=%s:bones_monst=%s\n",
307 plalias
[0] ? plalias
: plname
,
308 plalias
[0] ? " (" : "",
309 plalias
[0] ? plname
: "",
310 plalias
[0] ? ")" : "",
311 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
318 livelog_write_string(strbuf
);
319 } else if ((mtmp
->data
->geno
& G_UNIQ
)
320 || (mtmp
->data
== &mons
[PM_BLACK_MARKETEER
])
322 char *n
= noit_mon_nam(mtmp
);
323 /* $player killed a uniq monster */
324 snprintf(strbuf
, STRBUF_LEN
,
325 "player=%s%s%s%s:role=%s:race=%s:gender=%s:align=%s:hybrid=%s:turns=%ld:killed_uniq=%s\n",
326 plalias
[0] ? plalias
: plname
,
327 plalias
[0] ? " (" : "",
328 plalias
[0] ? plname
: "",
329 plalias
[0] ? ")" : "",
330 urole
.filecode
, urace
.filecode
, genders
[flags
.female
].filecode
, aligns
[1-u
.ualign
.type
].filecode
,
334 livelog_write_string(strbuf
);
337 #endif /* LIVELOG_BONES_KILLER */
339 #endif /* LIVELOGFILE */