Blindfold removal fix
[slashemextended.git] / src / livelog.c
blob0fa19c5db5ca59193264b36b1580dacac407aa5b
1 /* Write live game progress changes to a log file
2 * Needs xlog-v3 patch. */
4 #include "hack.h"
6 #ifdef LIVELOGFILE
8 /* Encodes the current xlog "achieve" status to an integer */
9 long
10 encodeachieve(void)
12 /* Achievement bitfield:
13 * bit meaning
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
25 * 11 killed medusa
26 * 12 killed Nightmare
27 * 13 killed Vecna
28 * 14 killed Beholder
29 * 15 killed Ruggo
30 * 16 killed Kroo
31 * 17 killed Grund
32 * 18 killed The Largest Giant
33 * 19 killed Shelob
34 * 20 killed Girtab
35 * 21 killed Aphrodite
36 * 22 killed Frankenstein
37 * 23 killed Croesus
38 * 24 killed Dagon
39 * 25 killed Hydra
40 * 26 imbued the Bell of Opening
41 * 27 imbued the Amulet of Yendor
44 long r;
46 r = 0;
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;
77 return r;
80 /* Encodes the current xlog "achieveX" status to an integer */
81 long
82 encodeachieveX(void)
84 /* Achievement bitfield:
85 * bit meaning
86 * 0 killed an elder priest
87 * 1 killed the Motherfucker Glass Golem
88 * 2 killed Tiksrvzllat
89 * 3 killed the BOFH
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
96 * 10 killed Kalwina
97 * 11 killed Stahngnir
98 * 12 killed Ariane
99 * 13 completed the Rival Quest
100 * 14 completed Minus World
101 * 15 killed Vera
102 * 16 killed Elaine
105 long r;
107 r = 0;
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;
127 return r;
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();
145 return TRUE;
148 /* Locks the live log file and writes 'buffer' */
149 void livelog_write_string(char* buffer) {
150 FILE* livelogfile;
152 #ifdef FILE_AREAS
153 if (lock_file_area(LOGAREA, LIVELOGFILE, 10)) {
154 #else
155 if (lock_file(LIVELOGFILE, SCOREPREFIX, 10)) {
156 #endif
157 if(!(livelogfile = fopen_datafile_area(LOGAREA, LIVELOGFILE, "a", SCOREPREFIX))) {
158 pline("Cannot open live log file!");
159 } else {
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) {
182 return;
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,
192 hybrid_strcode(),
193 moves,
194 achieve_int,
195 achieve_diff,
196 achieveX_int,
197 achieveX_diff);
198 livelog_write_string(strbuf);
200 last_achieve_int = achieve_int;
201 last_achieveX_int = achieveX_int;
205 /* Reports wishes */
206 void
207 livelog_wish(item)
208 char *item;
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,
217 hybrid_strcode(),
218 moves,
219 item);
220 livelog_write_string(strbuf);
223 /* Reports achievements */
224 void
225 livelog_report_trophy(string)
226 char *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,
235 hybrid_strcode(),
236 moves,
237 string);
238 livelog_write_string(strbuf);
241 /* Reports lifesaving */
242 void
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,
252 hybrid_strcode(),
253 moves,
254 "averted death");
255 livelog_write_string(strbuf);
258 /* Shout */
259 #ifdef LIVELOG_SHOUT
261 int
262 doshout()
264 char buf[BUFSZ], qbuf[QBUFSZ];
265 char* p;
267 sprintf(qbuf,"Shout what?");
268 getlin(qbuf, buf);
270 You("shout into the void: %s", buf);
272 /* filter livelog delimiter */
273 for (p = buf; *p != 0; p++)
274 if( *p == ':' )
275 *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,
284 hybrid_strcode(),
285 moves,
286 buf);
287 livelog_write_string(strbuf);
289 return 0;
292 #endif /* LIVELOG_SHOUT */
294 #ifdef LIVELOG_BONES_KILLER
295 void
296 livelog_bones_killed(mtmp)
297 struct monst *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,
312 hybrid_strcode(),
313 moves,
314 depth(&u.uz),
315 name,
316 mtmp->former_rank,
317 mtmp->data->mname);
318 livelog_write_string(strbuf);
319 } else if ((mtmp->data->geno & G_UNIQ)
320 || (mtmp->data == &mons[PM_BLACK_MARKETEER])
321 ) {
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,
331 hybrid_strcode(),
332 moves,
333 n);
334 livelog_write_string(strbuf);
337 #endif /* LIVELOG_BONES_KILLER */
339 #endif /* LIVELOGFILE */