1 /* $Id$ */
2 /* File: save.c */
3 
4 /* Purpose: interact with savefiles */
5 
6 #define SERVER
7 
8 #include "angband.h"
9 #include "party.h"
10 
11 static void new_wr_wild();
12 static void new_wr_floors();
13 void wr_towns();
14 void wr_byte(byte v);
15 void wr_u16b(u16b v);
16 void wr_s16b(s16b v);
17 void wr_u32b(u32b v);
18 void wr_s32b(s32b v);
19 void wr_string(cptr str);
20 static void write_buffer();
21 
22 
23 
24 /*
25  * Some "local" parameters, used to help write savefiles
26  */
27 
28 static FILE	*fff;		/* Current save "file" */
29 
30 static char	*fff_buf;	/* Savefile buffer */
31 static int	fff_buf_pos;	/* Buffer position */
32 
33 #define MAX_BUF_SIZE	4096
34 
35 static byte	xor_byte;	/* Simple encryption */
36 
37 static u32b	v_stamp = 0L;	/* A simple "checksum" on the actual values */
38 static u32b	x_stamp = 0L;	/* A simple "checksum" on the encoded bytes */
39 
40 
41 
42 /*
43  * These functions place information into a savefile a byte at a time
44  */
45 
sf_put(byte v)46 static void sf_put(byte v)
47 {
48 	/* Encode the value, write a character */
49 	xor_byte ^= v;
50 #if 0
51 	(void)putc((int)xor_byte, fff);
52 #else
53 	/* Buffered output */
54 	fff_buf[fff_buf_pos++] = xor_byte;
55 
56 	if (fff_buf_pos == MAX_BUF_SIZE) {
57 		if (fwrite(fff_buf, 1, MAX_BUF_SIZE, fff) < MAX_BUF_SIZE) {
58 			s_printf("Writing to savefile failed: %s\n", feof(fff) ? "EOF" : strerror(ferror(fff)));
59 		}
60 		fff_buf_pos = 0;
61 	}
62 #endif
63 
64 	/* Maintain the checksum info */
65 	v_stamp += v;
66 	x_stamp += xor_byte;
67 }
68 
wr_byte(byte v)69 void wr_byte(byte v)
70 {
71 	sf_put(v);
72 }
73 
wr_u16b(u16b v)74 void wr_u16b(u16b v)
75 {
76 	sf_put(v & 0xFF);
77 	sf_put((v >> 8) & 0xFF);
78 }
79 
wr_s16b(s16b v)80 void wr_s16b(s16b v)
81 {
82 	wr_u16b((u16b)v);
83 }
84 
wr_u32b(u32b v)85 void wr_u32b(u32b v)
86 {
87 	sf_put(v & 0xFF);
88 	sf_put((v >> 8) & 0xFF);
89 	sf_put((v >> 16) & 0xFF);
90 	sf_put((v >> 24) & 0xFF);
91 }
92 
wr_s32b(s32b v)93 void wr_s32b(s32b v)
94 {
95 	wr_u32b((u32b)v);
96 }
97 
wr_string(cptr str)98 void wr_string(cptr str)
99 {
100 	while (*str)
101 	{
102 		wr_byte(*str);
103 		str++;
104 	}
105 	wr_byte(*str);
106 }
107 
write_buffer()108 static void write_buffer()
109 {
110 	if (fff_buf_pos > 0) {
111 		if (fwrite(fff_buf, 1, fff_buf_pos, fff) < fff_buf_pos) {
112 			s_printf("Writing to savefile failed: %s\n", feof(fff) ? "EOF" : strerror(ferror(fff)));
113 		}
114 		fff_buf_pos = 0;
115 	}
116 }
117 
118 
119 /*
120  * These functions write info in larger logical records
121  */
122 
123 
124 /*
125  * Write an "item" record
126  */
wr_item(object_type * o_ptr)127 static void wr_item(object_type *o_ptr)
128 {
129 	wr_s32b(o_ptr->owner);
130 	wr_s16b(o_ptr->level);
131 	wr_byte(o_ptr->mode);
132 
133 	wr_s16b(o_ptr->k_idx);
134 
135 	wr_byte(o_ptr->iy);
136 	wr_byte(o_ptr->ix);
137 
138 	wr_s16b(o_ptr->wpos.wx);
139 	wr_s16b(o_ptr->wpos.wy);
140 	wr_s16b(o_ptr->wpos.wz);
141 
142 	wr_byte(o_ptr->tval);
143 	wr_byte(o_ptr->sval);
144 	wr_byte(o_ptr->tval2);
145 	wr_byte(o_ptr->sval2);
146 	wr_s32b(o_ptr->bpval);
147 	wr_s32b(o_ptr->pval);
148 	wr_s32b(o_ptr->pval2);
149 	wr_s32b(o_ptr->pval3);
150 	wr_s32b(o_ptr->sigil);
151 	wr_s32b(o_ptr->sseed);
152 
153 	wr_byte(o_ptr->discount);
154 	wr_byte(o_ptr->number);
155 	wr_s16b(o_ptr->weight);
156 
157 	wr_u16b(o_ptr->name1);
158 	wr_u16b(o_ptr->name2);
159 	wr_s32b(o_ptr->name3);
160 	wr_s32b(o_ptr->timeout);
161 
162 	wr_s16b(o_ptr->to_h);
163 	wr_s16b(o_ptr->to_d);
164 	wr_s16b(o_ptr->to_a);
165 
166 /* DEBUGGING PURPOSES - the_sandman */
167 #if 0
168         if (o_ptr->tval == 46)
169          {
170           s_printf("TRAP_DEBUG: Trap with s_val:%d,to_h:%d,to_d:%d,to_a:%d written\n",
171                                 o_ptr->sval, o_ptr->to_h, o_ptr->to_d, o_ptr->to_a);
172          }
173 #endif
174 	wr_s16b(o_ptr->ac);
175 	wr_byte(o_ptr->dd);
176 	wr_byte(o_ptr->ds);
177 
178 	wr_u16b(o_ptr->ident);
179 
180 	wr_u16b(o_ptr->name2b);
181 
182 	wr_byte(o_ptr->xtra1);
183 	wr_byte(o_ptr->xtra2);
184 	/* more info, originally for self-made spellbook feature */
185 	wr_byte(o_ptr->xtra3);
186 	wr_byte(o_ptr->xtra4);
187 	wr_byte(o_ptr->xtra5);
188 	wr_byte(o_ptr->xtra6);
189 	wr_byte(o_ptr->xtra7);
190 	wr_byte(o_ptr->xtra8);
191 	wr_byte(o_ptr->xtra9);
192 
193 	wr_s32b(o_ptr->marked);
194 	wr_byte(o_ptr->marked2);
195 
196 	wr_byte(o_ptr->questor);
197 	wr_s16b(o_ptr->questor_idx);
198 	wr_s16b(o_ptr->quest);
199 	wr_s16b(o_ptr->quest_stage);
200 	wr_byte(o_ptr->questor_invincible);
201 
202 	/* Save the inscription (if any) */
203 	if (o_ptr->note) {
204 		wr_string(quark_str(o_ptr->note));
205 	} else {
206 		wr_string("");
207 	}
208 	wr_byte(o_ptr->note_utag);
209 
210 	wr_u16b(o_ptr->next_o_idx);
211 	wr_byte(o_ptr->stack_pos);
212 	wr_u16b(o_ptr->held_m_idx);
213 }
214 
215 /*
216  * Write a "monster" record
217  */
wr_monster_race(monster_race * r_ptr)218 static void wr_monster_race(monster_race *r_ptr) {
219 	int i;
220 
221 	wr_u16b(r_ptr->name);
222 	wr_u16b(r_ptr->text);
223 	wr_byte(r_ptr->hdice);
224 	wr_byte(r_ptr->hside);
225 	wr_s16b(r_ptr->ac);
226 	wr_s16b(r_ptr->sleep);
227 	wr_byte(r_ptr->aaf);
228 	wr_byte(r_ptr->speed);
229 	wr_s32b(r_ptr->mexp);
230 	wr_s16b(r_ptr->extra);
231 	wr_byte(r_ptr->freq_innate);
232 	wr_byte(r_ptr->freq_spell);
233 	wr_u32b(r_ptr->flags1);
234 	wr_u32b(r_ptr->flags2);
235 	wr_u32b(r_ptr->flags3);
236 	wr_u32b(r_ptr->flags4);
237 	wr_u32b(r_ptr->flags5);
238 	wr_u32b(r_ptr->flags6);
239 	wr_u32b(r_ptr->flags7);
240 	wr_u32b(r_ptr->flags8);
241 	wr_u32b(r_ptr->flags9);
242 	wr_u32b(r_ptr->flags0);
243 	wr_s16b(r_ptr->level);
244 	wr_byte(r_ptr->rarity);
245 	wr_byte(r_ptr->d_attr);
246 	wr_byte(r_ptr->d_char);
247 	wr_byte(r_ptr->x_attr);
248 	wr_byte(r_ptr->x_char);
249 	for (i = 0; i < 4; i++) {
250 		wr_byte(r_ptr->blow[i].method);
251 		wr_byte(r_ptr->blow[i].effect);
252 		wr_byte(r_ptr->blow[i].d_dice);
253 		wr_byte(r_ptr->blow[i].d_side);
254 	}
255 }
256 
257 /*
258  * Write a "monster" record
259  */
wr_monster(monster_type * m_ptr)260 static void wr_monster(monster_type *m_ptr) {
261 	int i;
262 	wr_byte(m_ptr->pet);
263 	wr_byte(m_ptr->special);
264 	wr_byte(m_ptr->questor);
265 	wr_s16b(m_ptr->questor_idx);
266 	wr_s16b(m_ptr->quest);
267 	wr_byte(m_ptr->questor_invincible);
268 	wr_byte(m_ptr->questor_hostile);
269 	wr_byte(m_ptr->questor_target);
270 
271 	wr_s32b(m_ptr->owner);
272 	wr_s16b(m_ptr->r_idx);
273 	wr_byte(m_ptr->fy);
274 	wr_byte(m_ptr->fx);
275 
276 	wr_s16b(m_ptr->wpos.wx);
277 	wr_s16b(m_ptr->wpos.wy);
278 	wr_s16b(m_ptr->wpos.wz);
279 
280 	wr_s16b(m_ptr->ac);
281 	wr_byte(m_ptr->speed);
282 	wr_s32b(m_ptr->exp);
283 	wr_s16b(m_ptr->level);
284 	for (i = 0; i < 4; i++) {
285 		wr_byte(m_ptr->blow[i].method);
286 		wr_byte(m_ptr->blow[i].effect);
287 		wr_byte(m_ptr->blow[i].d_dice);
288 		wr_byte(m_ptr->blow[i].d_side);
289 	}
290 	wr_s32b(m_ptr->hp);
291 	wr_s32b(m_ptr->maxhp);
292 	wr_s16b(m_ptr->csleep);
293 	wr_byte(m_ptr->mspeed);
294 //	wr_byte(m_ptr->energy);
295 	wr_s16b(m_ptr->energy);
296 	wr_byte(m_ptr->stunned);
297 	wr_byte(m_ptr->confused);
298 	wr_byte(m_ptr->monfear);
299 	wr_byte(m_ptr->paralyzed);
300 	wr_byte(m_ptr->bleeding);
301 	wr_byte(m_ptr->poisoned);
302 	wr_byte(m_ptr->blinded);
303 	wr_byte(m_ptr->silenced);
304 	wr_u16b(m_ptr->hold_o_idx);
305 	wr_u16b(m_ptr->clone);
306 	wr_s16b(m_ptr->mind);
307 
308 	if (m_ptr->special || m_ptr->questor) wr_monster_race(m_ptr->r_ptr);
309 
310 	wr_u16b(m_ptr->ego);
311 	wr_s32b(m_ptr->name3);
312 
313 	wr_s16b(m_ptr->status);
314 	wr_s16b(m_ptr->target);
315 	wr_s16b(m_ptr->possessor);
316 	wr_s16b(m_ptr->destx);
317 	wr_s16b(m_ptr->desty);
318 	wr_s16b(m_ptr->determination);
319 	wr_s16b(m_ptr->limit_hp);
320 }
321 
322 /*
323  * Write a "lore" record
324  */
wr_global_lore(int r_idx)325 static void wr_global_lore(int r_idx)
326 {
327 	monster_race *r_ptr = &r_info[r_idx];
328 
329 	/* Count sights/deaths/kills */
330 	wr_s32b(r_ptr->r_sights);
331 	wr_s32b(r_ptr->r_deaths);
332 	wr_s32b(r_ptr->r_tkills);
333 
334 	/* Global monster limit */
335 	wr_s32b(r_ptr->max_num);
336 
337 	/* Global monster population */
338 	wr_s32b(r_ptr->cur_num);
339 }
340 
341 /*
342  * Write an "xtra" record
343  */
wr_xtra(int Ind,int k_idx)344 static void wr_xtra(int Ind, int k_idx)
345 {
346 	player_type *p_ptr = Players[Ind];
347 	byte tmp8u = 0;
348 
349 	if (p_ptr->obj_aware[k_idx]) tmp8u |= 0x01;
350 	if (p_ptr->obj_tried[k_idx]) tmp8u |= 0x02;
351 	if (p_ptr->obj_felt[k_idx]) tmp8u |= 0x04;
352 	if (p_ptr->obj_felt_heavy[k_idx]) tmp8u |= 0x08;
353 
354 	wr_byte(tmp8u);
355 }
356 
357 /*
358  * Write a "trap memory" record
359  *
360  * Of course, we should be able to compress this into 1/8..	- Jir -
361  */
wr_trap_memory(int Ind,int t_idx)362 static void wr_trap_memory(int Ind, int t_idx)
363 {
364 	player_type *p_ptr = Players[Ind];
365 	byte tmp8u = 0;
366 
367 	if (p_ptr->trap_ident[t_idx]) tmp8u |= 0x01;
368 
369 	wr_byte(tmp8u);
370 }
371 
372 
373 /*
374  * Write a "store" record
375  */
wr_store(store_type * st_ptr)376 static void wr_store(store_type *st_ptr)
377 {
378 	int j;
379 
380 	/* Save the "open" counter */
381 	wr_u32b(st_ptr->store_open);
382 
383 	/* Save the "insults" */
384 	wr_s16b(st_ptr->insult_cur);
385 
386 	/* Save the current owner */
387 	wr_u16b(st_ptr->owner);
388 //	wr_byte(st_ptr->owner);
389 
390 	/* Save the stock size */
391 	wr_byte(st_ptr->stock_num);
392 
393 	/* Save the "haggle" info */
394 	wr_s16b(st_ptr->good_buy);
395 	wr_s16b(st_ptr->bad_buy);
396 
397 	/* Last visit */
398 	wr_s32b(st_ptr->last_visit);
399 
400 	/* Save the stock */
401 	for (j = 0; j < st_ptr->stock_num; j++) {
402 		/* Save each item in stock */
403 		wr_item(&st_ptr->stock[j]);
404 	}
405 }
406 
wr_bbs()407 static void wr_bbs() {
408 	int i, j;
409 
410 	wr_s16b(BBS_LINES);
411 
412 	for (i = 0; i < BBS_LINES; i++)
413 		wr_string(bbs_line[i]);
414 
415 	/* also write complete party-BBS and guild-BBS (tripling the server file size oO) - C. Blue */
416 
417 	wr_s16b(MAX_PARTIES);
418 	for (j = 0; j < MAX_PARTIES; j++)
419 		for (i = 0; i < BBS_LINES; i++)
420 			wr_string(pbbs_line[j][i]);
421 
422 	wr_s16b(MAX_GUILDS);
423 	for (j = 0; j < MAX_GUILDS; j++)
424 		for (i = 0; i < BBS_LINES; i++)
425 			wr_string(gbbs_line[j][i]);
426 }
427 
wr_notes()428 static void wr_notes() {
429 	int i;
430 
431 	wr_s16b(MAX_NOTES);
432 	for (i = 0; i < MAX_NOTES; i++) {
433 		wr_string(priv_note[i]);
434 		wr_string(priv_note_sender[i]);
435 		wr_string(priv_note_target[i]);
436 	}
437 
438 	wr_s16b(MAX_PARTYNOTES);
439 	for (i = 0; i < MAX_PARTYNOTES; i++) {
440 		wr_string(party_note[i]);
441 		wr_string(party_note_target[i]);
442 	}
443 
444 	wr_s16b(MAX_GUILDNOTES);
445 	for (i = 0; i < MAX_GUILDNOTES; i++) {
446 		wr_string(guild_note[i]);
447 		wr_string(guild_note_target[i]);
448 	}
449 	//omitted (use custom.lua instead): admin_note[MAX_ADMINNOTES]
450 }
451 
wr_xorders()452 static void wr_xorders() {
453 	int i;
454 	wr_s16b(questid);
455 	for (i = 0; i < MAX_XORDERS; i++) {
456 		wr_s16b(xorders[i].active);
457 		wr_s16b(xorders[i].id);
458 		wr_s16b(xorders[i].type);
459 		wr_u16b(xorders[i].flags);
460 		wr_s32b(xorders[i].creator);
461 		wr_s32b(xorders[i].turn);
462 	}
463 }
464 
465 #if 0 /* need to use separate function save_quests() now */
466 static void wr_quests() {
467 	int i, j, k;
468 
469 	wr_s16b(max_q_idx);
470 	wr_s16b(QI_QUESTORS);
471 	wr_byte(QI_FLAGS);
472 
473 	for (i = 0; i < max_q_idx; i++) {
474 		wr_byte(q_info[i].active);
475 #if 0 /* actually don't write this, it's more comfortable to use q_info '-2 repeatable' entry instead */
476 		wr_byte(q_info[i].disabled);
477 #else
478 		wr_byte(0);
479 #endif
480 		wr_s16b(q_info[i].cur_cooldown);
481 		wr_s16b(q_info[i].cur_stage);
482 		wr_s32b(q_info[i].turn_activated);
483 		wr_s32b(q_info[i].turn_acquired);
484 
485 		for (j = 0; j < QI_QUESTORS; j++) {
486 #if 0//restructure
487 			wr_byte(q_info[i].current_wpos[j].wx);
488 			wr_byte(q_info[i].current_wpos[j].wy);
489 			wr_byte(q_info[i].current_wpos[j].wz);
490 			wr_byte(q_info[i].current_x[j]);
491 			wr_byte(q_info[i].current_y[j]);
492 
493 			wr_s16b(q_info[i].questor_m_idx[j]);
494 #else
495 			wr_byte(0);wr_byte(0);wr_byte(0);wr_byte(0);wr_byte(0);wr_byte(0);wr_byte(0);
496 #endif
497 		}
498 
499 		wr_u16b(q_info[i].flags);
500 
501 		for (k = 0; k < QI_STAGES; k++) {
502 			for (j = 0; j < QI_GOALS; j++) {
503 #if 0//restructure
504 				wr_byte(q_info[i].goals[k][j]);
505 				wr_s16b(q_info[i].kill_number_left[k][j]);
506 #else
507 				wr_byte(0);wr_byte(0);wr_byte(0);
508 #endif
509 			}
510 			for (j = 0; j < QI_OPTIONAL; j++) {
511 #if 0//restructure
512 				wr_byte(q_info[i].goalsopt[k][j]);
513 				wr_s16b(q_info[i].killopt_number_left[k][j]);
514 #else
515 				wr_byte(0);wr_byte(0);wr_byte(0);
516 #endif
517 			}
518 		}
519 	}
520 }
521 #endif
522 
wr_guilds()523 static void wr_guilds() {
524 	int i, j;
525 	u16b tmp16u;
526 
527 	tmp16u = MAX_GUILDS;
528 	wr_u16b(tmp16u);
529 
530 	/* Dump the guilds */
531 	for (i = 0; i < tmp16u; i++){
532 		wr_u32b(guilds[i].dna);
533 		wr_string(guilds[i].name);
534 		wr_s32b(guilds[i].master);
535 		wr_s32b(guilds[i].members);
536 		wr_byte(guilds[i].cmode);
537 		wr_u32b(guilds[i].flags);
538 		wr_s16b(guilds[i].minlev);
539 		for (j = 0; j < 5; j++)
540 			wr_string(guilds[i].adder[j]);
541 		wr_s16b(guilds[i].h_idx);
542 	}
543 }
544 
wr_party(party_type * party_ptr)545 static void wr_party(party_type *party_ptr) {
546 	/* Save the party name */
547 	wr_string(party_ptr->name);
548 
549 	/* Save the owner's name */
550 	wr_string(party_ptr->owner);
551 
552 	/* Save the number of people and creation time */
553 	wr_s32b(party_ptr->members);
554 	wr_s32b(party_ptr->created);
555 
556 	/* Save the modus and members */
557 	wr_byte(party_ptr->mode);
558 
559 	/* Save the creator's character mode */
560 	wr_byte(party_ptr->cmode);
561 
562 	/* New - party flags, maybe */
563 	wr_u32b(party_ptr->flags);
564 
565 }
566 
wr_wild(wilderness_type * w_ptr)567 static void wr_wild(wilderness_type *w_ptr)
568 {
569 	/* Reserved for future use */
570 	wr_u32b(0);
571 	/* level flags */
572 	wr_u16b(w_ptr->type);
573 	wr_u16b(w_ptr->bled);
574 	wr_u32b(w_ptr->flags);
575 
576 	wr_s32b(w_ptr->own);
577 
578 	/* ondepth is not saved? */
579 }
580 
581 
582 /*
583  * Write the information about a house
584  */
wr_house(house_type * house)585 static void wr_house(house_type *house)
586 {
587 	int i;
588 
589 	wr_byte(house->x);
590 	wr_byte(house->y);
591 	wr_byte(house->dx);
592 	wr_byte(house->dy);
593 	wr_u32b(house->dna->creator);
594 	wr_byte(house->dna->mode);
595 	wr_s32b(house->dna->owner);
596 	wr_byte(house->dna->owner_type);
597 	wr_byte(house->dna->a_flags);
598 	wr_u16b(house->dna->min_level);
599 	wr_u32b(house->dna->price);
600 	wr_u16b(house->flags);
601 
602 	wr_s16b(house->wpos.wx);
603 	wr_s16b(house->wpos.wy);
604 	wr_s16b(house->wpos.wz);
605 
606 	if(house->flags & HF_RECT){
607 		wr_byte(house->coords.rect.width);
608 		wr_byte(house->coords.rect.height);
609 	} else {
610 		i = -2;
611 		do {
612 			i += 2;
613 			wr_byte(house->coords.poly[i]);
614 			wr_byte(house->coords.poly[i+1]);
615 		} while (house->coords.poly[i] || house->coords.poly[i+1]);
616 	}
617 
618 	wr_byte(house->colour);
619 	wr_byte(house->xtra);
620 
621 #ifndef USE_MANG_HOUSE_ONLY
622 	wr_s16b(house->stock_num);
623 	wr_s16b(house->stock_size);
624 	for (i = 0; i < house->stock_num; i++)
625 		wr_item(&house->stock[i]);
626 #endif	// USE_MANG_HOUSE
627 }
628 
629 
630 /*
631  * Write some "extra" info
632  */
wr_extra(int Ind)633 static void wr_extra(int Ind) {
634 	player_type *p_ptr = Players[Ind];
635 
636 	int i, j;
637 	u16b tmp16u = 0;
638 	byte tmp8u = 0;
639 
640 	dungeon_type *d_ptr;
641 
642 
643 	wr_string(p_ptr->name);
644 
645 	wr_string(p_ptr->died_from);
646 	wr_string(p_ptr->died_from_list);
647 	wr_s16b(p_ptr->died_from_depth);
648 
649 	for (i = 0; i < 4; i++)
650 		wr_string(p_ptr->history[i]);
651 
652 	wr_byte(p_ptr->has_pet); //pet pet
653 
654 	/* Race/Class/Gender/Party */
655 	wr_byte(p_ptr->prace);
656 	wr_byte(p_ptr->pclass);
657 	wr_byte(p_ptr->ptrait);
658 	wr_byte(p_ptr->male);
659 	wr_u16b(p_ptr->party); /* changed to u16b to allow more parties - mikaelh */
660 	wr_byte(p_ptr->mode);
661 
662 	wr_byte(p_ptr->hitdie);
663 	wr_s16b(p_ptr->expfact);
664 
665 	wr_s16b(p_ptr->age);
666 	wr_s16b(p_ptr->ht);
667 	wr_s16b(p_ptr->wt);
668 	wr_u16b(p_ptr->align_good);
669 	wr_u16b(p_ptr->align_law);
670 
671 	/* Dump the stats (maximum and current) */
672 	for (i = 0; i < 6; ++i) wr_s16b(p_ptr->stat_max[i]);
673 	for (i = 0; i < 6; ++i) wr_s16b(p_ptr->stat_cur[i]);
674 
675 	/* Dump the stats (maximum and current) */
676 	for (i = 0; i < 6; ++i) wr_s16b(p_ptr->stat_cnt[i]);
677 	for (i = 0; i < 6; ++i) wr_s16b(p_ptr->stat_los[i]);
678 
679         /* Dump the skills */
680         wr_u16b(MAX_SKILLS);
681         for (i = 0; i < MAX_SKILLS; ++i) {
682                 wr_s32b(p_ptr->s_info[i].value);
683                 wr_u16b(p_ptr->s_info[i].mod);
684                 wr_byte(p_ptr->s_info[i].dev);
685 #if 0 //SMOOTHSKILLS
686                 wr_byte(p_ptr->s_info[i].hidden);
687                 wr_byte(p_ptr->s_info[i].dummy);
688 #else
689 		wr_byte(p_ptr->s_info[i].flags1);
690 		wr_s32b(p_ptr->s_info[i].base_value);
691 #endif
692         }
693 	wr_s16b(p_ptr->skill_points);
694 //	wr_s16b(p_ptr->skill_last_level);
695 
696 	/* /undoskills - mikaelh */
697 	for (i = 0; i < MAX_SKILLS; ++i) {
698                 wr_s32b(p_ptr->s_info_old[i].value);
699                 wr_u16b(p_ptr->s_info_old[i].mod);
700                 wr_byte(p_ptr->s_info_old[i].dev);
701 #if 0 //SMOOTHSKILLS
702                 wr_byte(p_ptr->s_info_old[i].hidden);
703                 wr_byte(p_ptr->s_info_old[i].dummy);
704 #else
705 		wr_byte(p_ptr->s_info_old[i].flags1);
706 		wr_s32b(p_ptr->s_info_old[i].base_value);
707 #endif
708 	}
709 	wr_s16b(p_ptr->skill_points_old);
710 	wr_byte(p_ptr->reskill_possible);
711 
712 	wr_s32b(p_ptr->id);
713 	wr_u32b(p_ptr->dna);
714 	wr_s32b(p_ptr->turn);
715 	wr_s32b(p_ptr->turns_online);
716 	wr_s32b(p_ptr->turns_afk);
717 	wr_s32b(p_ptr->turns_idle);
718 	wr_s32b(p_ptr->turns_active);
719 
720 	/* Ignore the transient stats */
721 	for (i = 0; i < 10; ++i) wr_s16b(0);
722 
723 	wr_u32b(p_ptr->au);
724 
725 	wr_u32b(p_ptr->max_exp);
726 	wr_u32b(p_ptr->exp);
727 	wr_u16b(p_ptr->exp_frac);
728 	wr_s16b(p_ptr->lev);
729 
730 	wr_s16b(p_ptr->mhp);
731 	wr_s16b(p_ptr->chp);
732 	wr_u16b(p_ptr->chp_frac);
733 
734 	wr_s16b(p_ptr->mst);
735 	wr_s16b(p_ptr->cst);
736 	wr_s16b(p_ptr->cst_frac);
737 
738 	wr_s16b(p_ptr->msp);
739 	wr_s16b(p_ptr->csp);
740 	wr_u16b(p_ptr->csp_frac);
741 
742 	/* Max Player and Dungeon Levels */
743 	wr_s16b(p_ptr->max_plv);
744 	wr_s16b(p_ptr->max_dlv);
745 	for (i = 0; i < MAX_D_IDX * 2; i++) {
746 		d_ptr = NULL;
747 		/* hack: don't save max depth for quest dungeons! (they get removed when quest (stage) ends) */
748 		if (p_ptr->max_depth_wx[i] || p_ptr->max_depth_wy[i]) {
749 			if (p_ptr->max_depth_tower[i])
750 				d_ptr = wild_info[p_ptr->max_depth_wy[i]][p_ptr->max_depth_wx[i]].tower;
751 			else
752 				d_ptr = wild_info[p_ptr->max_depth_wy[i]][p_ptr->max_depth_wx[i]].dungeon;
753 		}
754 		if (d_ptr && d_ptr->quest) {
755 			wr_byte(0);
756 			wr_byte(0);
757 			wr_byte(0);
758 			wr_byte(0);
759 		} else {
760 			wr_byte(p_ptr->max_depth[i]);
761 			wr_byte(p_ptr->max_depth_wx[i]);
762 			wr_byte(p_ptr->max_depth_wy[i]);
763 			wr_byte(p_ptr->max_depth_tower[i] ? 1 : 0);
764 		}
765 	}
766 
767 	/* Player location */
768 	wr_s16b(p_ptr->py);
769 	wr_s16b(p_ptr->px);
770 
771 	wr_s16b(p_ptr->wpos.wx);
772 	wr_s16b(p_ptr->wpos.wy);
773 	wr_s16b(p_ptr->wpos.wz);
774 
775 	wr_u16b(p_ptr->town_x);
776 	wr_u16b(p_ptr->town_y);
777 
778 	/* More info */
779 	wr_s16b(p_ptr->ghost);
780 	wr_s16b(p_ptr->sc);
781 	wr_s16b(p_ptr->fruit_bat);
782 
783 	wr_byte(p_ptr->lives);		/* old "rest" */
784 	wr_byte(p_ptr->houses_owned);
785 
786 	wr_byte(0);			/* unused */
787 	wr_s16b(p_ptr->blind);
788 	wr_s16b(p_ptr->paralyzed);
789 	wr_s16b(p_ptr->confused);
790 	wr_s16b(p_ptr->food);
791 	wr_s16b(0);	/* old "food_digested" */
792 	wr_s16b(0);	/* old "protection" */
793 	wr_s16b(p_ptr->energy);
794 	wr_s16b(p_ptr->fast);
795 	wr_s16b(p_ptr->fast_mod);
796 	wr_s16b(p_ptr->slow);
797 	wr_s16b(p_ptr->afraid);
798 	wr_s16b(p_ptr->cut);
799 	wr_s16b(p_ptr->stun);
800 	wr_s16b(p_ptr->poisoned);
801 	wr_s16b(p_ptr->image);
802 	wr_s16b(p_ptr->protevil);
803 	wr_s16b(p_ptr->invuln);
804 	wr_s16b(p_ptr->hero);
805 	wr_s16b(p_ptr->shero);
806 	wr_s16b(p_ptr->berserk);
807         wr_s16b(p_ptr->shield);
808         wr_s16b(p_ptr->shield_power);
809         wr_s16b(p_ptr->shield_opt);
810         wr_s16b(p_ptr->shield_power_opt);
811         wr_s16b(p_ptr->shield_power_opt2);
812         wr_s16b(p_ptr->tim_thunder);
813         wr_s16b(p_ptr->tim_thunder_p1);
814         wr_s16b(p_ptr->tim_thunder_p2);
815         wr_s16b(p_ptr->tim_lev);
816         wr_s16b(p_ptr->tim_ffall);
817         wr_s16b(p_ptr->tim_regen);
818         wr_s16b(p_ptr->tim_regen_pow);
819 	wr_s16b(p_ptr->blessed);
820 	wr_s16b(p_ptr->tim_invis);
821 	wr_s16b(p_ptr->word_recall);
822 	wr_s16b(p_ptr->see_infra);
823 	wr_s16b(p_ptr->tim_infra);
824 	wr_s16b(p_ptr->oppose_fire);
825 	wr_s16b(p_ptr->oppose_cold);
826 	wr_s16b(p_ptr->oppose_acid);
827 	wr_s16b(p_ptr->oppose_elec);
828 	wr_s16b(p_ptr->oppose_pois);
829 	wr_s16b(p_ptr->prob_travel);
830 	wr_s16b(p_ptr->st_anchor);
831 	wr_s16b(p_ptr->tim_esp);
832 	wr_s16b(p_ptr->adrenaline);
833 	wr_s16b(p_ptr->biofeedback);
834 	wr_byte(p_ptr->confusing);
835 	wr_u16b(p_ptr->tim_jail);
836 	wr_u16b(p_ptr->tim_susp);
837 	wr_u16b(p_ptr->pkill);
838 	wr_u16b(p_ptr->tim_pkill);
839 	wr_s16b(p_ptr->tim_wraith);
840 	wr_byte(p_ptr->wraith_in_wall);
841 	wr_byte(p_ptr->searching);
842 	wr_byte(p_ptr->maximize);
843 	wr_byte(p_ptr->preserve);
844 	wr_byte(p_ptr->stunning);
845 
846 	wr_s16b(p_ptr->body_monster);
847 	wr_s16b(p_ptr->auto_tunnel);
848 
849 	wr_s16b(p_ptr->tim_meditation);
850 
851 	wr_s16b(p_ptr->tim_invisibility);
852 	wr_s16b(p_ptr->tim_invis_power);
853 	wr_s16b(p_ptr->tim_invis_power2);
854 
855 	wr_s16b(p_ptr->fury);
856 
857 	wr_s16b(p_ptr->tim_manashield);
858 
859 	wr_s16b(p_ptr->tim_traps);
860 	wr_s16b(p_ptr->tim_mimic);
861 	wr_s16b(p_ptr->tim_mimic_what);
862 
863 	/* Dump the monster lore */
864 	tmp16u = MAX_R_IDX;
865 	wr_u16b(tmp16u);
866 	for (i = 0; i < tmp16u; i++) wr_s16b(p_ptr->r_killed[i]);
867 
868 	wr_u32b(p_ptr->gold_picked_up);
869 	wr_byte(p_ptr->insta_res);
870 	wr_byte(p_ptr->castles_owned);
871 	wr_s16b(p_ptr->flash_self);
872 	wr_byte(p_ptr->fluent_artifact_reset); /* for automatic artifact resets */
873 	wr_byte(p_ptr->sanity_bar);
874 	wr_byte(p_ptr->IDDC_found_rndtown);
875 	wr_byte(p_ptr->IDDC_logscum);
876 	wr_byte(p_ptr->IDDC_flags);
877 
878 	wr_s16b(p_ptr->word_recall);
879 	wr_s16b(p_ptr->recall_pos.wx);
880 	wr_s16b(p_ptr->recall_pos.wy);
881 	wr_s16b(p_ptr->recall_pos.wz);
882 
883 	/* Future use */
884 	for (i = 0; i < 22; i++) wr_byte(0);
885 
886         /* Toggle for possible automatic save-game updates
887            (done via script login-hook, eg custom.lua) - C. Blue */
888 	wr_byte(p_ptr->updated_savegame);
889 
890 	/* for automatic artifact resets */
891 	wr_byte(p_ptr->artifact_reset);
892 
893 	/* Ignore some flags */
894 	wr_u32b(0L);	/* oops */
895 	wr_u32b(0L);	/* oops */
896 	wr_u32b(0L);	/* oops */
897 
898 
899 	/* Write the "object seeds" */
900 	/*wr_u32b(seed_flavor);*/
901 	/*wr_u32b(seed_town);*/
902 	wr_s32b(p_ptr->mimic_seed);
903 	wr_byte(p_ptr->mimic_immunity);
904 	wr_u16b(p_ptr->autoret);
905 	wr_s16b(p_ptr->martyr_timeout);
906 
907 	/* Special stuff */
908 	wr_u16b(panic_save);
909 	wr_u16b(p_ptr->total_winner);
910 	wr_u16b(p_ptr->once_winner);
911 	wr_byte(p_ptr->iron_winner);
912 	wr_byte(p_ptr->iron_winner_ded);
913 
914 	wr_s16b(p_ptr->own1.wx);
915 	wr_s16b(p_ptr->own1.wy);
916 	wr_s16b(p_ptr->own1.wz);
917 	wr_s16b(p_ptr->own2.wx);
918 	wr_s16b(p_ptr->own2.wy);
919 	wr_s16b(p_ptr->own2.wz);
920 
921 	wr_u16b(p_ptr->retire_timer);
922 	wr_u16b(p_ptr->noscore);
923 
924 	/* Write death */
925 	wr_byte(p_ptr->death);
926 
927 	wr_byte(p_ptr->black_breath);
928 
929 	wr_s16b(p_ptr->msane);
930 	wr_s16b(p_ptr->csane);
931 	wr_u16b(p_ptr->csane_frac);
932 
933 	wr_s32b(p_ptr->balance);
934 	wr_s32b(p_ptr->tim_blacklist);
935 	wr_s32b(p_ptr->tim_watchlist);
936 	wr_s32b(p_ptr->pstealing);
937 
938         for (i = 0; i < MAX_GLOBAL_EVENTS; i++) {
939                 wr_s16b(p_ptr->global_event_type[i]);
940                 wr_s32b(p_ptr->global_event_signup[i]);
941                 wr_s32b(p_ptr->global_event_started[i]);
942                 for (j = 0; j < 4; j++) wr_u32b(p_ptr->global_event_progress[i][j]);
943         }
944 
945 	for (i = 0; i < MAX_GLOBAL_EVENT_TYPES; i++)
946 		wr_s16b(p_ptr->global_event_participated[i]);
947 
948         wr_s16b(p_ptr->combat_stance);
949         wr_s16b(p_ptr->combat_stance_power);
950 	wr_byte(p_ptr->cloaked);
951 	wr_byte(p_ptr->shadow_running);
952 	wr_byte(p_ptr->shoot_till_kill);
953 	wr_byte(p_ptr->dual_mode);
954 
955         wr_s16b(p_ptr->kills);
956         wr_s16b(p_ptr->kills_own);
957         wr_s16b(p_ptr->kills_lower);
958         wr_s16b(p_ptr->kills_higher);
959         wr_s16b(p_ptr->kills_equal);
960         wr_s16b(p_ptr->free_mimic);
961 
962 	if (p_ptr->aura[0]) tmp8u |= 0x1;
963 	if (p_ptr->aura[1]) tmp8u |= 0x2;
964 	if (p_ptr->aura[2]) tmp8u |= 0x4;
965 	wr_byte(tmp8u); /* aura states (on/off) */
966 
967 	wr_u16b(p_ptr->deaths);
968 	wr_u16b(p_ptr->soft_deaths);
969 
970 	/* array of 'warnings' and hints aimed at newbies */
971 	tmp16u = 0x00;
972 	if (p_ptr->warning_technique_melee == 1) tmp16u |= 0x01;
973 	if (p_ptr->warning_technique_ranged == 1) tmp16u |= 0x02;
974 	wr_u16b(tmp16u);
975 
976 	wr_string(p_ptr->info_msg);
977 
978 	/* for ENABLE_GO_GAME */
979 	wr_byte(p_ptr->go_level);
980 	wr_byte(p_ptr->go_sublevel);
981 
982 	/* For things like 'Officer' status to add others etc */
983 	wr_u32b(p_ptr->party_flags);
984 	wr_u32b(p_ptr->guild_flags);
985 
986 	/* Runecraft buff */
987 	wr_u16b(p_ptr->tim_deflect);
988 
989 	/* for shuffling/dealing a deck of cards */
990 	wr_u16b(p_ptr->cards_diamonds);
991 	wr_u16b(p_ptr->cards_hearts);
992 	wr_u16b(p_ptr->cards_spades);
993 	wr_u16b(p_ptr->cards_clubs);
994 }
995 
996 /*
997  * Write the list of players a player is hostile toward
998  */
wr_hostilities(int Ind)999 static void wr_hostilities(int Ind)
1000 {
1001 	player_type *p_ptr = Players[Ind];
1002 	hostile_type *h_ptr;
1003 	int i;
1004 	u16b tmp16u = 0;
1005 
1006 	/* Count hostilities */
1007 	for (h_ptr = p_ptr->hostile; h_ptr; h_ptr = h_ptr->next)
1008 	{
1009 		/* One more */
1010 		tmp16u++;
1011 	}
1012 
1013 	/* Save number */
1014 	wr_u16b(tmp16u);
1015 
1016 	/* Start at beginning */
1017 	h_ptr = p_ptr->hostile;
1018 
1019 	/* Save each record */
1020 	for (i = 0; i < tmp16u; i++)
1021 	{
1022 		/* Write ID */
1023 		wr_s32b(h_ptr->id);
1024 
1025 		/* Advance pointer */
1026 		h_ptr = h_ptr->next;
1027 	}
1028 }
1029 
1030 
1031 
1032 
1033 /*
1034  * Write a specified depth
1035  *
1036  * Each row is broken down into a series of run-length encoded runs.
1037  * Each run has a constant feature type, and flags.
1038  *
1039  * Note that a cave_type's monster index and object indecies are not stored
1040  * here.  They should be assigned automatically when the objects
1041  * and monsters are loaded later.
1042  *
1043  * This could probably be made more efficient by allowing runs to encompass
1044  * more than one row.
1045  *
1046  * We could also probably get a large efficiency increase by splitting the features
1047  * and flags into two seperate run-length encoded blocks.
1048  *
1049  * -APD
1050  */
1051 
wr_floor(struct worldpos * wpos)1052 static void wr_floor(struct worldpos *wpos)
1053 {
1054 	int y, x, i;
1055 	byte prev_feature = 0xff, n;
1056 	u16b prev_info = 0xffff;
1057 	unsigned char runlength;
1058 	struct c_special *cs_ptr;
1059 
1060 	cave_type *c_ptr;
1061 	cave_type **zcave;
1062 	if (!(zcave = getcave(wpos))) return;
1063 #if DEBUG_LEVEL > 1
1064 //#if 1 > 0
1065 	s_printf("%d players on %s.\n", players_on_depth(wpos), wpos_format(0, wpos));
1066 #endif
1067 
1068 	/* Depth */
1069 	wr_s16b(wpos->wx);
1070 	wr_s16b(wpos->wy);
1071 	wr_s16b(wpos->wz);
1072 
1073 	/* Dungeon size */
1074 	wr_u16b(MAX_HGT);
1075 	wr_u16b(MAX_WID);
1076 
1077 	/* How many players are on this depth */
1078 	wr_s16b(players_on_depth(wpos));
1079 
1080 	/* The staircase locations on this depth */
1081 	/* Hack -- this information is currently not present for the wilderness
1082 	 * levels.
1083 	 */
1084 
1085 	wr_byte(level_up_y(wpos));
1086 	wr_byte(level_up_x(wpos));
1087 	wr_byte(level_down_y(wpos));
1088 	wr_byte(level_down_x(wpos));
1089 	wr_byte(level_rand_y(wpos));
1090 	wr_byte(level_rand_x(wpos));
1091 
1092 	{
1093 		dun_level *l_ptr = getfloor(wpos);
1094 		if (l_ptr) {
1095 			wr_u32b(l_ptr->id);
1096 			wr_u32b(l_ptr->flags1);
1097 			wr_u32b(l_ptr->flags2);
1098 			wr_byte(l_ptr->hgt);
1099 			wr_byte(l_ptr->wid);
1100 		}
1101 	}
1102 
1103 	/*** Simple "Run-Length-Encoding" of cave ***/
1104 	/* for each each row */
1105 	for (y = 0; y < MAX_HGT; y++) {
1106 		/* start a new run */
1107 		runlength = 0;
1108 
1109 		/* break the row down into runs */
1110 		for (x = 0; x < MAX_WID; x++) {
1111 			c_ptr = &zcave[y][x];
1112 
1113 			/* if we are starting a new run */
1114 			if ((!runlength) || (c_ptr->feat != prev_feature) || (c_ptr->info != prev_info)
1115 					|| (runlength > 254))
1116 			{
1117 				if (runlength) {
1118 					/* if we just finished a run, write it */
1119 					wr_byte(runlength);
1120 					wr_byte(prev_feature);
1121 					wr_u16b(prev_info);
1122 				}
1123 
1124 				/* start a new run */
1125 				prev_feature = c_ptr->feat;
1126 				prev_info = c_ptr->info;
1127 				runlength = 1;
1128 			}
1129 			/* otherwise continue our current run */
1130 			else runlength++;
1131 		}
1132 		/* hack -- write the final run of this row */
1133 		wr_byte(runlength);
1134 		wr_byte(prev_feature);
1135 		wr_u16b(prev_info);
1136 	}
1137 
1138 	/*** another scan for c_special ***/
1139 	/* for each each row */
1140 	for (y = 0; y < MAX_HGT; y++) {
1141 		/* break the row down into runs */
1142 		for (x = 0; x < MAX_WID; x++) {
1143 			n = 0;
1144 			c_ptr = &zcave[y][x];
1145 			cs_ptr = c_ptr->special;
1146 			/* count the number of cs_things */
1147 			while (cs_ptr) {
1148 				n++;
1149 				cs_ptr = cs_ptr->next;
1150 			}
1151 			/* write them */
1152 			if (n) {
1153 				wr_byte(x);
1154 				wr_byte(y);
1155 				wr_byte(n);
1156 				cs_ptr = c_ptr->special;
1157 				while (cs_ptr) {
1158 					i = cs_ptr->type;
1159 					wr_byte(i);
1160 					csfunc[i].save(cs_ptr);
1161 					cs_ptr = cs_ptr->next;
1162 				}
1163 			}
1164 #if 0
1165 		/* redesign needed - too much of hurry to sort now */
1166 			while (cs_ptr) {
1167 				i = cs_ptr->type;
1168 
1169 				/* nothing special */
1170 				if (i != CS_NONE){
1171 
1172 					/* TODO: implement CS_DNADOOR and CS_KEYDOOR saving
1173 			 		* currently, their x,y,i is saved in vain.	- Jir -
1174 			 		*/
1175 					wr_byte(x);
1176 					wr_byte(y);
1177 					wr_byte(i);
1178 
1179 					/* csfunc will take care of it :) */
1180 					csfunc[i].save(sc_is_pointer(i) ?
1181 					    cs_ptr->sc.ptr : &c_ptr->special);
1182 				}
1183 				cs_ptr = cs_ptr->next;
1184 			}
1185 #endif /* 0 */
1186 		}
1187 	}
1188 
1189 	/* hack -- terminate it */
1190 	wr_byte(255);
1191 	wr_byte(255);
1192 	wr_byte(255);
1193 }
1194 
1195 /* Write a players memory of a cave, simmilar to the above function. */
wr_cave_memory(int Ind)1196 static void wr_cave_memory(int Ind)
1197 {
1198 	player_type *p_ptr = Players[Ind];
1199 	int y,x;
1200 	char prev_flag = -1;	/* just for definedness. */
1201 	unsigned char runlength = 0;
1202 
1203 	/* Remember unique ID of the old floor */
1204 	wr_u32b(p_ptr->dlev_id);
1205 
1206 	/* write the number of flags */
1207 	wr_u16b(MAX_HGT);
1208 	wr_u16b(MAX_WID);
1209 
1210 	for (x = y = 0; y < MAX_HGT;) {
1211 		/* if we are starting a new run */
1212 		if (!runlength || (p_ptr->cave_flag[y][x] != prev_flag) || (runlength > 254) ) {
1213 			/* if we just finished a run, write it */
1214 			if (runlength) {
1215 				wr_byte(runlength);
1216 				wr_byte(prev_flag);
1217 			}
1218 			/* star the new run */
1219 			prev_flag = p_ptr->cave_flag[y][x];
1220 			runlength = 1;
1221 		}
1222 		/* else lengthen our previous run */
1223 		else runlength++;
1224 
1225 		/* update our current position */
1226 		x++;
1227 		if (x >= MAX_WID) {
1228 			x = 0; y++;
1229 			if (y >= MAX_HGT) {
1230 				/* hack -- write the final run */
1231 				wr_byte(runlength);
1232 				wr_byte(prev_flag);
1233 				break;
1234 			}
1235 		}
1236 	}
1237 }
1238 
1239 
1240 
1241 /*
1242  * Actually write a player save-file
1243  */
wr_savefile_new(int Ind)1244 static bool wr_savefile_new(int Ind) {
1245 	player_type *p_ptr = Players[Ind];
1246 	int        i, j;
1247 
1248 	u32b              now, tmp32u;
1249 	byte		tmp8u;
1250 	u16b		tmp16u;
1251 
1252 
1253 	/* Guess at the current time */
1254 	now = time((time_t *)0);
1255 
1256 
1257 	/* Note the operating system */
1258 	sf_xtra = 0L;
1259 
1260 	/* Note when the file was saved */
1261 	sf_when = now;
1262 
1263 	/* Note the number of saves */
1264 	sf_saves++;
1265 
1266 
1267 	/*** Actually write the file ***/
1268 
1269 	/* Dump the file header */
1270 	xor_byte = 0;
1271 	wr_byte(SF_VERSION_MAJOR);
1272 	xor_byte = 0;
1273 	wr_byte(SF_VERSION_MINOR);
1274 	xor_byte = 0;
1275 	wr_byte(SF_VERSION_PATCH);
1276 	xor_byte = 0;
1277 	tmp8u = rand_int(256);
1278 	wr_byte(tmp8u);
1279 
1280 
1281 	/* Reset the checksum */
1282 	v_stamp = 0L;
1283 	x_stamp = 0L;
1284 
1285 
1286 	/* Operating system */
1287 	wr_u32b(sf_xtra);
1288 
1289 
1290 	/* Time file last saved */
1291 	wr_u32b(sf_when);
1292 
1293 	/* Number of past lives */
1294 	wr_u16b(sf_lives);
1295 
1296 	/* Number of times saved */
1297 	wr_u16b(sf_saves);
1298 
1299 
1300 	/* Space */
1301 	wr_u32b(0L);
1302 	wr_u32b(0L);
1303 
1304 
1305 	/* Write the boolean "options" */
1306 	/*wr_options();*/
1307 
1308 
1309 #if 0
1310 	/* Dump the monster lore */
1311 	tmp16u = MAX_R_IDX;
1312 	wr_u16b(tmp16u);
1313 	for (i = 0; i < tmp16u; i++) wr_lore(i);
1314 #endif
1315 
1316 
1317 	/* Dump the object memory */
1318 	tmp16u = MAX_K_IDX;
1319 	wr_u16b(tmp16u);
1320 	for (i = 0; i < tmp16u; i++) wr_xtra(Ind, i);
1321 
1322 	/* Dump the trap memory (unefficient!) */
1323 	tmp16u = MAX_T_IDX;
1324 	wr_u16b(tmp16u);
1325 	for (i = 0; i < tmp16u; i++) wr_trap_memory(Ind, i);
1326 
1327 #if 0
1328 
1329 	/* Hack -- Dump the quests */
1330 	tmp16u = MAX_XO_IDX;
1331 	wr_u16b(tmp16u);
1332 	for (i = 0; i < tmp16u; i++)
1333 	{
1334 		wr_byte(xo_list[i].level);
1335 		wr_byte(0);
1336 		wr_byte(0);
1337 		wr_byte(0);
1338 	}
1339 
1340 	/* Hack -- Dump the artifacts */
1341 	tmp16u = MAX_A_IDX;
1342 	wr_u16b(tmp16u);
1343 	for (i = 0; i < tmp16u; i++)
1344 	{
1345 		artifact_type *a_ptr = &a_info[i];
1346 		wr_byte(a_ptr->cur_num);
1347 		wr_byte(0);
1348 		wr_byte(0);
1349 		wr_byte(0);
1350 	}
1351 
1352 #endif
1353 
1354 
1355 	/* Write the "extra" information */
1356 	wr_extra(Ind);
1357 
1358 
1359 	/* Dump the "player hp" entries */
1360 	tmp16u = PY_MAX_LEVEL;
1361 	wr_u16b(tmp16u);
1362 	for (i = 0; i < tmp16u; i++)
1363 	{
1364 		wr_s16b(p_ptr->player_hp[i]);
1365 	}
1366 
1367 	/* Write the inventory */
1368 	for (i = 0; i < INVEN_TOTAL; i++)
1369 	{
1370 		if (p_ptr->inventory[i].k_idx)
1371 		{
1372 			wr_u16b(i);
1373 			wr_item(&p_ptr->inventory[i]);
1374 		}
1375 	}
1376 
1377 	/* Add a sentinel */
1378 	wr_u16b(0xFFFF);
1379 
1380 	/* Write the list of hostilities */
1381 	wr_hostilities(Ind);
1382 
1383 	/* write the cave flags (our memory of our current level) */
1384 	wr_cave_memory(Ind);
1385 	/* write the wilderness map */
1386 	tmp32u = MAX_WILD_8;
1387 	wr_u32b(tmp32u);
1388 	for (i = 0; i < MAX_WILD_8; i++)
1389 		wr_byte(p_ptr->wild_map[i]);
1390 
1391 	wr_byte(p_ptr->guild);
1392 	wr_u32b(p_ptr->guild_dna);
1393 
1394 	wr_s16b(p_ptr->xorder_id);
1395 	wr_s16b(p_ptr->xorder_num);
1396 
1397 
1398 	/* Quest information */
1399 	wr_byte(p_ptr->quest_any_k);
1400 	wr_byte(p_ptr->quest_any_k_target);
1401 	wr_byte(p_ptr->quest_any_k_within_target);
1402 	wr_byte(p_ptr->quest_any_r);
1403 	wr_byte(p_ptr->quest_any_r_target);
1404 	wr_byte(p_ptr->quest_any_r_within_target);
1405 	wr_byte(p_ptr->quest_any_deliver_xy);
1406 	wr_byte(p_ptr->quest_any_deliver_xy_within_target);
1407 
1408 	for (i = 0; i < MAX_CONCURRENT_QUESTS; i++) {
1409 		wr_s16b(p_ptr->quest_idx[i]);
1410 		wr_string(p_ptr->quest_codename[i]);
1411 		wr_s16b(p_ptr->quest_stage[i]);
1412 		wr_s16b(p_ptr->quest_stage_timer[i]);
1413 		for (j = 0; j < QI_GOALS; j++) {
1414 			wr_byte(p_ptr->quest_goals[i][j]);
1415 			wr_s16b(p_ptr->quest_kill_number[i][j]);
1416 			wr_s16b(p_ptr->quest_retrieve_number[i][j]);
1417 			/* hack: added in 4, 5, 26 actually: */
1418 			wr_byte(p_ptr->quest_goals_nisi[i][j]);
1419 		}
1420 		for (j = 0; j < 5; j++) {
1421 			/* the 'missing' byte to strip is instead used for 'nisi' above */
1422 	// FREE SPACE:
1423 			wr_s16b(0);
1424 			wr_s16b(0);
1425 		}
1426 
1427 		/* helper info */
1428 		wr_byte(p_ptr->quest_kill[i]);
1429 		wr_byte(p_ptr->quest_retrieve[i]);
1430 
1431 		wr_byte(p_ptr->quest_deliver_pos[i]);
1432 		wr_byte(p_ptr->quest_deliver_xy[i]);
1433 
1434 		wr_s32b(p_ptr->quest_acquired[i]);
1435 		wr_s32b(p_ptr->quest_timed_stage_change[i]);
1436 
1437 		/* 'individual' quest type information */
1438 		wr_u16b(p_ptr->quest_flags[i]);
1439 	}
1440 
1441 	/* remember quests we completed */
1442 	for (i = 0; i < MAX_Q_IDX; i++) {
1443 		wr_s16b(p_ptr->quest_done[i]);
1444 		wr_s16b(p_ptr->quest_cooldown[i]);
1445 	}
1446 
1447 
1448         wr_byte(p_ptr->spell_project);
1449 
1450         /* Special powers */
1451         wr_s16b(p_ptr->power_num);
1452         for (i = 0; i < MAX_POWERS; i++)
1453         {
1454                 wr_s16b(p_ptr->powers[i]);
1455         }
1456 
1457 	/* Write the "value check-sum" */
1458 	wr_u32b(v_stamp);
1459 
1460 	/* Write the "encoded checksum" */
1461 	wr_u32b(x_stamp);
1462 
1463 	/* Write the remaining contents of the buffer */
1464 	write_buffer();
1465 
1466 	/* Error in save */
1467 	if (ferror(fff) || (fflush(fff) == EOF)) return FALSE;
1468 
1469 	/* Successful save */
1470 	return TRUE;
1471 }
1472 
1473 
1474 /*
1475  * Medium level player saver
1476  *
1477  * XXX XXX XXX Angband 2.8.0 will use "fd" instead of "fff" if possible
1478  */
save_player_aux(int Ind,char * name)1479 static bool save_player_aux(int Ind, char *name)
1480 {
1481 	bool	ok = FALSE;
1482 
1483 	int		fd = -1;
1484 
1485 	int		mode = 0644;
1486 
1487 
1488 	/* No file yet */
1489 	fff = NULL;
1490 
1491 
1492 	/* File type is "SAVE" */
1493 	FILE_TYPE(FILE_TYPE_SAVE);
1494 
1495 
1496 	/* Create the savefile */
1497 	fd = fd_make(name, mode);
1498 
1499 	/* File is okay */
1500 	if (fd >= 0)
1501 	{
1502 		/* Close the "fd" */
1503 		(void)fd_close(fd);
1504 
1505 		/* Open the savefile */
1506 		fff = my_fopen(name, "wb");
1507 
1508 		/* Successful open */
1509 		if (fff)
1510 		{
1511 			/* Allocate a buffer */
1512 			fff_buf = C_NEW(MAX_BUF_SIZE, char);
1513 			fff_buf_pos = 0;
1514 
1515 			/* Write the savefile */
1516 			if (wr_savefile_new(Ind)) ok = TRUE;
1517 
1518 			/* Attempt to close it */
1519 			if (my_fclose(fff)) ok = FALSE;
1520 
1521 			/* Free the buffer */
1522 			C_FREE(fff_buf, MAX_BUF_SIZE, char);
1523 		}
1524 
1525 		/* Remove "broken" files */
1526 		if (!ok) (void)fd_kill(name);
1527 	}
1528 
1529 
1530 	/* Failure */
1531 	if (!ok) return (FALSE);
1532 
1533 	/* Successful save */
1534 	/*server_saved = TRUE;*/
1535 
1536 	/* Success */
1537 	return (TRUE);
1538 }
1539 
1540 
1541 
1542 /*
1543  * Attempt to save the player in a savefile
1544  */
save_player(int Ind)1545 bool save_player(int Ind)
1546 {
1547 	player_type *p_ptr = Players[Ind];
1548 
1549 	int		result = FALSE;
1550 
1551 	char	safe[1024];
1552 
1553 
1554 #ifdef SET_UID
1555 
1556 # ifdef SECURE
1557 
1558 	/* Get "games" permissions */
1559 	beGames();
1560 
1561 # endif
1562 
1563 #endif
1564 
1565 
1566 	/* New savefile */
1567 	strcpy(safe, p_ptr->savefile);
1568 	strcat(safe, ".new");
1569 
1570 #ifdef VM
1571 	/* Hack -- support "flat directory" usage on VM/ESA */
1572 	strcpy(safe, p_ptr->savefile);
1573 	strcat(safe, "n");
1574 #endif /* VM */
1575 
1576 	/* Remove it */
1577 	fd_kill(safe);
1578 
1579 	/* Attempt to save the player */
1580 	if (save_player_aux(Ind, safe))
1581 	{
1582 		char temp[1024];
1583 
1584 		/* Old savefile */
1585 		strcpy(temp, p_ptr->savefile);
1586 		strcat(temp, ".old");
1587 
1588 #ifdef VM
1589 		/* Hack -- support "flat directory" usage on VM/ESA */
1590 		strcpy(temp, p_ptr->savefile);
1591 		strcat(temp, "o");
1592 #endif /* VM */
1593 
1594 		/* Remove it */
1595 		fd_kill(temp);
1596 
1597 		/* Preserve old savefile */
1598 		fd_move(p_ptr->savefile, temp);
1599 
1600 		/* Activate new savefile */
1601 		fd_move(safe, p_ptr->savefile);
1602 
1603 		/* Remove preserved savefile */
1604 		fd_kill(temp);
1605 
1606 		/* Hack -- Pretend the character was loaded */
1607 		/*character_loaded = TRUE;*/
1608 
1609 #ifdef VERIFY_SAVEFILE
1610 
1611 		/* Lock on savefile */
1612 		strcpy(temp, savefile);
1613 		strcat(temp, ".lok");
1614 
1615 		/* Remove lock file */
1616 		fd_kill(temp);
1617 
1618 #endif
1619 
1620 		/* Success */
1621 		result = TRUE;
1622 	}
1623 
1624 
1625 #ifdef SET_UID
1626 
1627 # ifdef SECURE
1628 
1629 	/* Drop "games" permissions */
1630 	bePlayer();
1631 
1632 # endif
1633 
1634 #endif
1635 
1636 
1637 	/* Return the result */
1638 	return (result);
1639 }
1640 
1641 
file_exist(char * buf)1642 static bool file_exist(char *buf)
1643 {
1644 	int fd;
1645 
1646 	fd = fd_open(buf, O_RDONLY);
1647 	if (fd >= 0)
1648 	{
1649 		fd_close(fd);
1650 		return (TRUE);
1651 	}
1652 	else return (FALSE);
1653 }
1654 
1655 
1656 /*
1657  * Attempt to Load a "savefile"
1658  *
1659  * Version 2.7.0 introduced a slightly different "savefile" format from
1660  * older versions, requiring a completely different parsing method.
1661  *
1662  * Note that savefiles from 2.7.0 - 2.7.2 are completely obsolete.
1663  *
1664  * Pre-2.8.0 savefiles lose some data, see "load2.c" for info.
1665  *
1666  * Pre-2.7.0 savefiles lose a lot of things, see "load1.c" for info.
1667  *
1668  * On multi-user systems, you may only "read" a savefile if you will be
1669  * allowed to "write" it later, this prevents painful situations in which
1670  * the player loads a savefile belonging to someone else, and then is not
1671  * allowed to save his game when he quits.
1672  *
1673  * We return "TRUE" if the savefile was usable, and we set the global
1674  * flag "character_loaded" if a real, living, character was loaded.
1675  *
1676  * Note that we always try to load the "current" savefile, even if
1677  * there is no such file, so we must check for "empty" savefile names.
1678  */
load_player(int Ind)1679 bool load_player(int Ind)
1680 {
1681 	player_type *p_ptr = Players[Ind];
1682 
1683 	int		fd = -1;
1684 
1685 	errr	err = 0;
1686 
1687 	byte	vvv[4];
1688 
1689 #ifdef VERIFY_TIMESTAMP
1690 	struct stat	statbuf;
1691 #endif
1692 
1693 	cptr	what = "generic";
1694 	bool	edit = (cfg.runlevel == 1024) ? TRUE : FALSE;
1695 
1696 
1697 	/* Paranoia */
1698 	/*turn = 0;*/
1699 
1700 	/* Paranoia */
1701 	p_ptr->death = FALSE;
1702 
1703 
1704 	/* Allow empty savefile name */
1705 	if (!p_ptr->savefile[0])
1706 	{
1707 		if (edit)
1708 		{
1709 			what = "Server is closed for login now";
1710 			err = 1;
1711 		}
1712 		else return (TRUE);
1713 	}
1714 
1715 
1716 	/* XXX XXX XXX Fix this */
1717 
1718 	/* Verify the existence of the savefile */
1719 	if (!err && !file_exist(p_ptr->savefile))
1720 	{
1721 		/* Give a message */
1722 		s_printf("Savefile does not exist for player %s.\n", p_ptr->name);
1723 		s_printf("(%s) %d\n", p_ptr->savefile, errno);
1724 
1725 		if (errno != ENOENT && errno != EIO) {	/* EMFILE for example */
1726 			if (cfg.runlevel > 1) {
1727 				s_printf("Automatic shutdown\n");
1728 				msg_broadcast(0, "\377r* SERVER EMERGENCY SHUTDOWN *");
1729 				set_runlevel(1);
1730 			}
1731 			return(FALSE);
1732 		}
1733 
1734 		/* Allow this */
1735 		if (edit)
1736 		{
1737 			what = "Server is closed for login now";
1738 			err = 1;
1739 		}
1740 		else return (TRUE);
1741 	}
1742 
1743 
1744 #ifdef VERIFY_SAVEFILE
1745 
1746 	/* Verify savefile usage */
1747 	if (!err)
1748 	{
1749 		FILE *fkk;
1750 
1751 		char temp[MAX_PATH_LENGTH];
1752 
1753 		/* Extract name of lock file */
1754 		strcpy(temp, p_ptr->savefile);
1755 		strcat(temp, ".lok");
1756 
1757 		/* Check for lock */
1758 		fkk = my_fopen(temp, "rb");
1759 
1760 		/* Oops, lock exists */
1761 		if (fkk)
1762 		{
1763 			/* Close the file */
1764 			my_fclose(fkk);
1765 
1766 			/* Message */
1767 			msg_print(Ind, "Savefile is currently in use.");
1768 			msg_print(Ind, NULL);
1769 
1770 			/* Oops */
1771 			return (FALSE);
1772 		}
1773 
1774 		/* Create a lock file */
1775 		fkk = my_fopen(temp, "wb");
1776 
1777 		/* Dump a line of info */
1778 		fprintf(fkk, "Lock file for savefile '%s'\n", p_ptr->savefile);
1779 
1780 		/* Close the lock file */
1781 		my_fclose(fkk);
1782 	}
1783 
1784 #endif
1785 
1786 
1787 	/* Okay */
1788 	if (!err)
1789 	{
1790 		/* Open the savefile */
1791 		fd = fd_open(p_ptr->savefile, O_RDONLY);
1792 
1793 		/* No file */
1794 		if (fd < 0) err = -1;
1795 
1796 		/* Message (below) */
1797 		if (err) what = "Cannot open savefile";
1798 	}
1799 
1800 	/* Process file */
1801 	if (!err)
1802 	{
1803 
1804 #ifdef VERIFY_TIMESTAMP
1805 		/* Get the timestamp */
1806 		(void)fstat(fd, &statbuf);
1807 #endif
1808 
1809 		/* Read the first four bytes */
1810 		if (fd_read(fd, (char*)(vvv), 4)) err = -1;
1811 
1812 		/* What */
1813 		if (err) what = "Cannot read savefile";
1814 
1815 		/* Close the file */
1816 		(void)fd_close(fd);
1817 	}
1818 
1819 	/* Process file */
1820 	if (!err)
1821 	{
1822 		/* Extract version */
1823 		sf_major = vvv[0];
1824 		sf_minor = vvv[1];
1825 		sf_patch = vvv[2];
1826 		sf_extra = vvv[3];
1827 
1828 		/* Attempt to load */
1829 		err = rd_savefile_new(Ind);
1830 
1831 		/* Message (below) */
1832 		/*
1833 		   if (err) {
1834 		   what = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
1835 		   (void)sprintf (what,"Cannot parse savefile error %d",err);
1836 		   };
1837 		   */
1838 		if (err) what = "Cannot parse savefile error";
1839 		if (err == 35) what = edit ? "Server is closed for login now" :
1840 			"Incorrect password";
1841 		if (err == 1) what = "Name already in use";
1842 	}
1843 
1844 	/* Paranoia */
1845 	if (!err)
1846 	{
1847 		/* Invalid turn */
1848 		/* if (!turn) err = -1; */
1849 
1850 		/* Message (below) */
1851 		if (err) what = "Broken savefile";
1852 	}
1853 
1854 #ifdef VERIFY_TIMESTAMP
1855 	/* Verify timestamp */
1856 	if (!err)
1857 	{
1858 		/* Hack -- Verify the timestamp */
1859 		if (sf_when > (statbuf.st_ctime + 100) ||
1860 				sf_when < (statbuf.st_ctime - 100))
1861 		{
1862 			/* Message */
1863 			what = "Invalid timestamp";
1864 
1865 			/* Oops */
1866 			err = -1;
1867 		}
1868 	}
1869 #endif
1870 
1871 
1872 	/* Okay */
1873 	if (!err)
1874 	{
1875 		/* Give a conversion warning */
1876 		if ((version_major != sf_major) ||
1877 				(version_minor != sf_minor) ||
1878 				(version_patch != sf_patch))
1879 		{
1880 			/* Message */
1881 			printf("Converted a %d.%d.%d savefile.\n",
1882 					sf_major, sf_minor, sf_patch);
1883 		}
1884 
1885 		/* Player is dead */
1886 		if (p_ptr->death)
1887 		{
1888 			/* Player is no longer "dead" */
1889 			p_ptr->death = FALSE;
1890 
1891 			/* Count lives */
1892 			sf_lives++;
1893 
1894 			/* Done */
1895 			return (TRUE);
1896 		}
1897 
1898 		/* A character was loaded */
1899 		character_loaded = TRUE;
1900 
1901 		/* Still alive */
1902 		if (p_ptr->chp >= 0)
1903 		{
1904 			/* Reset cause of death */
1905 			(void)strcpy(p_ptr->died_from, "(alive and well)");
1906 		}
1907 
1908 		p_ptr->body_changed = TRUE;
1909 
1910 		/* Success */
1911 		return (TRUE);
1912 	}
1913 
1914 
1915 #ifdef VERIFY_SAVEFILE
1916 
1917 	/* Verify savefile usage */
1918 	if (TRUE)
1919 	{
1920 		char temp[MAX_PATH_LENGTH];
1921 
1922 		/* Extract name of lock file */
1923 		strcpy(temp, p_ptr->savefile);
1924 		strcat(temp, ".lok");
1925 
1926 		/* Remove lock */
1927 		fd_kill(temp);
1928 	}
1929 
1930 #endif
1931 
1932 
1933 	/* Message */
1934 	Destroy_connection(p_ptr->conn, format("Error (%s) reading %d.%d.%d savefile.",
1935 				what, sf_major, sf_minor, sf_patch));
1936 
1937 	/* Oops */
1938 	return (FALSE);
1939 }
1940 
1941 /*
1942  * Write the player name hash table.
1943  * Much better to write it from here...
1944  */
wr_player_names(void)1945 static void wr_player_names(void) {
1946 	hash_entry *ptr;
1947 
1948 	/*int i, num, *id_list;*/
1949 	s32b *id_list;
1950 	u32b i, num;
1951 
1952 	/* Get the list of player ID's */
1953 	num = player_id_list(&id_list, 0L);
1954 
1955 	/* Store the number of entries */
1956 	wr_u32b(num);
1957 
1958 	/* Store each entry */
1959 	for (i = 0; i < num; i++) {
1960 		/* Store the ID */
1961 		ptr = lookup_player(id_list[i]);
1962 		if (ptr) {
1963 			wr_s32b(id_list[i]);
1964 			wr_u32b(ptr->account);
1965 			wr_s32b(ptr->laston);
1966 			/* 3.4.2 server */
1967 			wr_byte(ptr->race);
1968 			wr_byte(ptr->class);
1969 			wr_byte(ptr->mode);
1970 			wr_byte(ptr->level);
1971 			wr_u16b(ptr->party); /* changed to u16b to allow more parties */
1972 			wr_byte(ptr->guild);
1973 			wr_u32b(ptr->guild_flags);
1974 			wr_u16b(ptr->xorder);
1975 			wr_byte(ptr->admin);
1976 			wr_s16b(ptr->wpos.wx);
1977 			wr_s16b(ptr->wpos.wy);
1978 			wr_s16b(ptr->wpos.wz);
1979 			/* Store the player name */
1980 			wr_string(ptr->name);
1981 		}
1982 	}
1983 
1984 	/* Free the memory in the list */
1985 	if (num) C_KILL(id_list, num, int);
1986 }
1987 
wr_auctions()1988 static void wr_auctions()
1989 {
1990 	int i, j;
1991 	auction_type *auc_ptr;
1992 	bid_type *bid_ptr;
1993 
1994 	wr_u32b(auction_alloc);
1995 
1996 	for (i = 0; i < auction_alloc; i++)
1997 	{
1998 		auc_ptr = &auctions[i];
1999 		wr_byte(auc_ptr->status);
2000 		wr_byte(auc_ptr->flags);
2001 		wr_byte(auc_ptr->mode);
2002 		wr_s32b(auc_ptr->owner);
2003 		wr_item(&auc_ptr->item);
2004 		if (auc_ptr->desc)
2005 		{
2006 			wr_string(auc_ptr->desc);
2007 		}
2008 		else
2009 		{
2010 			wr_string("");
2011 		}
2012 		wr_s32b(auc_ptr->starting_price);
2013 		wr_s32b(auc_ptr->buyout_price);
2014 		wr_s32b(auc_ptr->bids_cnt);
2015 		for (j = 0; j < auc_ptr->bids_cnt; j++) {
2016 			bid_ptr = &auc_ptr->bids[j];
2017 			wr_s32b(bid_ptr->bid);
2018 			wr_s32b(bid_ptr->bidder);
2019 		}
2020 		wr_s32b(auc_ptr->winning_bid);
2021 
2022 		/* Write time_t's as s32b's for now */
2023 		wr_s32b((s32b) auc_ptr->start);
2024 		wr_s32b((s32b) auc_ptr->duration);
2025 	}
2026 }
2027 
wr_server_savefile()2028 static bool wr_server_savefile()
2029 {
2030         int        i;
2031 	u32b              now;
2032 
2033 	byte            tmp8u;
2034 	u16b            tmp16u;
2035 	u32b		tmp32u;
2036 
2037 
2038 	/* Guess at the current time */
2039 	now = time((time_t *)0);
2040 
2041 
2042 	/* Note the operating system */
2043 	sf_xtra = 0L;
2044 
2045 	/* Note when the file was saved */
2046 	sf_when = now;
2047 
2048 	/* Note the number of saves */
2049 	sf_saves++;
2050 
2051 
2052 	/*** Actually write the file ***/
2053 
2054 	/* Dump the file header */
2055 	xor_byte = 0;
2056 	wr_byte(SF_VERSION_MAJOR);
2057 	xor_byte = 0;
2058 	wr_byte(SF_VERSION_MINOR);
2059 	xor_byte = 0;
2060 	wr_byte(SF_VERSION_PATCH);
2061 	xor_byte = 0;
2062 	tmp8u = rand_int(256);
2063 	wr_byte(tmp8u);
2064 
2065 
2066 	/* Reset the checksum */
2067 	v_stamp = 0L;
2068 	x_stamp = 0L;
2069 
2070 
2071 	/* Operating system */
2072 	wr_u32b(sf_xtra);
2073 
2074 	/* Time file last saved */
2075 	wr_u32b(sf_when);
2076 
2077 	/* Number of past lives */
2078 	wr_u16b(sf_lives);
2079 
2080 	/* Number of times saved */
2081 	wr_u16b(sf_saves);
2082 
2083 	/* Is this a panic save? - C. Blue */
2084         if (panic_save) wr_byte(1); else wr_byte(0);
2085 
2086         /* save server state regarding updates (lua) */
2087 	wr_s16b(updated_server);
2088 	/* save artifact-reset state (lua) */
2089 	wr_s16b(artifact_reset);
2090 
2091 	/* Space */
2092 	wr_u32b(0L);
2093 	wr_u32b(0L);
2094 
2095 	/* Dump the monster (unique) race information */
2096 	tmp16u = MAX_R_IDX;
2097 	wr_u16b(tmp16u);
2098 	for (i = 0; i < tmp16u; i++) wr_global_lore(i);
2099 
2100 	/* Hack -- Dump the artifacts */
2101 	tmp16u = MAX_A_IDX;
2102 	wr_u16b(tmp16u);
2103 	for (i = 0; i < tmp16u; i++) {
2104 		artifact_type *a_ptr = &a_info[i];
2105 		wr_byte(a_ptr->cur_num);
2106 		wr_byte(a_ptr->known);
2107 		wr_s32b(a_ptr->carrier);
2108 		wr_s32b(a_ptr->timeout);
2109 		wr_byte((a_ptr->iddc ? 0x1 : 0) + (a_ptr->winner ? 0x2 : 0));
2110 	}
2111 
2112 
2113 	/* Note the parties */
2114 	tmp16u = MAX_PARTIES;
2115 	wr_u16b(tmp16u);
2116 
2117 	/* Dump the parties */
2118 	for (i = 0; i < tmp16u; i++) wr_party(&parties[i]);
2119 
2120 
2121 	wr_towns();		/* write town data */
2122 	new_wr_wild();		/* must alloc dungeons first on load! ;) */
2123 	new_wr_floors();	/* rename wr_floors(void) later */
2124 
2125 	/* Prepare to write the monsters */
2126 	compact_monsters(0, FALSE);
2127 	/* Note the number of monsters */
2128 	tmp32u = m_max;
2129 	wr_u32b(tmp32u);
2130 	/* Dump the monsters */
2131 	for (i = 0; i < m_max; i++) wr_monster(&m_list[i]);
2132 
2133 	/* Prepare to write the objects */
2134 	compact_objects(0, FALSE);
2135 	/* Note the number of objects */
2136 	tmp16u = o_max;
2137 	wr_u16b(tmp16u);
2138 	/* Dump the objects */
2139 	for (i = 0; i < tmp16u; i++) wr_item(&o_list[i]);
2140 
2141 	tmp32u = 0L;
2142 	for(i = 0; i < num_houses; i++)
2143 		if(!(houses[i].flags&HF_DELETED)) tmp32u++;
2144 
2145 	/* Note the number of houses */
2146 	wr_s32b(tmp32u);
2147 
2148 	/* Dump the houses */
2149 	for (i = 0; i < num_houses; i++){
2150 		if(!(houses[i].flags&HF_DELETED))
2151 			wr_house(&houses[i]);
2152 	}
2153 
2154 	/* Write the player name database */
2155 	wr_player_names();
2156 
2157 	wr_u32b(seed_flavor);
2158 	wr_u32b(seed_town);
2159 
2160 	wr_guilds();
2161 	wr_xorders();
2162 	//wr_quests();
2163 
2164 	wr_u32b(account_id);
2165 	wr_s32b(player_id);
2166 	wr_s32b(turn);
2167 
2168 	wr_notes();
2169 	wr_bbs();
2170 
2171 	wr_byte(season);
2172 	wr_byte(weather_frequency);
2173 
2174 	wr_auctions();
2175 
2176 	/* write Ironman Deep Dive Challenge records */
2177 	wr_byte(IDDC_HIGHSCORE_SIZE);
2178 	for (i = 0; i < IDDC_HIGHSCORE_SIZE; i++) {
2179 		wr_s16b(deep_dive_level[i]);
2180 		wr_string(deep_dive_name[i]);
2181 		wr_string(deep_dive_char[i]);
2182 		wr_string(deep_dive_account[i]);
2183 		wr_s16b(deep_dive_class[i]);
2184 	}
2185 
2186 	/* Write the remaining contents of the buffer */
2187 	write_buffer();
2188 
2189 	/* Error in save */
2190 	if (ferror(fff) || (fflush(fff) == EOF)) return FALSE;
2191 
2192 	/* Successful save */
2193 	return TRUE;
2194 }
2195 
2196 /* write the wilderness and dungeon structure */
new_wr_wild()2197 static void new_wr_wild(){
2198 	wilderness_type *w_ptr;
2199 	int x, y, i;
2200 	u32b temp;
2201 
2202 	temp = MAX_WILD_Y;
2203 	wr_u32b(temp);
2204 	temp = MAX_WILD_X;
2205 	wr_u32b(temp);
2206 
2207 	for (y = 0; y < MAX_WILD_Y; y++) {
2208 		for (x = 0; x < MAX_WILD_X; x++) {
2209 			w_ptr = &wild_info[y][x];
2210 			wr_wild(w_ptr);
2211 			if (w_ptr->flags & WILD_F_DOWN) {
2212 				wr_byte(w_ptr->up_x);
2213 				wr_byte(w_ptr->up_y);
2214 				wr_u16b(w_ptr->dungeon->id);
2215 				wr_u16b(w_ptr->dungeon->type);
2216 				wr_u16b(w_ptr->dungeon->baselevel);
2217 				wr_u32b(w_ptr->dungeon->flags1);
2218 				wr_u32b(w_ptr->dungeon->flags2);
2219 				wr_u32b(w_ptr->dungeon->flags3);
2220 				wr_byte(w_ptr->dungeon->maxdepth);
2221 				for(i = 0; i < 10; i++) {
2222 #if 0	/* unused - mikaelh */
2223 					wr_byte(w_ptr->dungeon->r_char[i]);
2224 					wr_byte(w_ptr->dungeon->nr_char[i]);
2225 #else
2226 					wr_byte(0);
2227 					wr_byte(0);
2228 #endif
2229 				}
2230 #ifdef DUNGEON_VISIT_BONUS
2231 				wr_u16b(dungeon_visit_frequency[w_ptr->dungeon->id]);
2232 #else
2233 				wr_u16b(VISIT_TIME_CAP);
2234 #endif
2235 
2236 				wr_byte(w_ptr->dungeon->theme);
2237 				wr_s16b(w_ptr->dungeon->quest);
2238 				wr_s16b(w_ptr->dungeon->quest_stage);
2239 			}
2240 			if (w_ptr->flags & WILD_F_UP) {
2241 				wr_byte(w_ptr->dn_x);
2242 				wr_byte(w_ptr->dn_y);
2243 				wr_u16b(w_ptr->tower->id);
2244 				wr_u16b(w_ptr->tower->type);
2245 				wr_u16b(w_ptr->tower->baselevel);
2246 				wr_u32b(w_ptr->tower->flags1);
2247 				wr_u32b(w_ptr->tower->flags2);
2248 				wr_u32b(w_ptr->tower->flags3);
2249 				wr_byte(w_ptr->tower->maxdepth);
2250 				for (i = 0; i < 10; i++){
2251 #if 0	/* unused - mikaelh */
2252 					wr_byte(w_ptr->tower->r_char[i]);
2253 					wr_byte(w_ptr->tower->nr_char[i]);
2254 #else
2255 					wr_byte(0);
2256 					wr_byte(0);
2257 #endif
2258 				}
2259 #ifdef DUNGEON_VISIT_BONUS
2260 				wr_u16b(dungeon_visit_frequency[w_ptr->tower->id]);
2261 #else
2262 				wr_u16b(VISIT_TIME_CAP);
2263 #endif
2264 				wr_byte(w_ptr->tower->theme);
2265 				wr_s16b(w_ptr->tower->quest);
2266 				wr_s16b(w_ptr->tower->quest_stage);
2267 			}
2268 		}
2269 	}
2270 }
2271 
2272 /* write the actual dungeons */
new_wr_floors()2273 static void new_wr_floors(){
2274 	struct worldpos cwpos;
2275 	wilderness_type *w_ptr;
2276 	int x, y, z;
2277 	cwpos.wz = 0;
2278 	for(y = 0; y < MAX_WILD_Y; y++) {
2279 		cwpos.wy = y;
2280 		for(x = 0; x < MAX_WILD_X; x++) {
2281 			cwpos.wx = x;
2282 			w_ptr = &wild_info[y][x];
2283 			save_guildhalls(&cwpos);
2284 			/*
2285 			 * One problem here; if a wilderness tower/dungeon exists, and
2286 			 * the surface is not static, stair/recall informations are lost
2287 			 * and cause crash/infinite-loop next time.		FIXME
2288 			 */
2289 			if (getcave(&cwpos) && players_on_depth(&cwpos)) wr_floor(&cwpos);
2290 			if (w_ptr->flags & WILD_F_DOWN) {
2291 				struct dungeon_type *d_ptr = w_ptr->dungeon;
2292 				for (z = 1; z <= d_ptr->maxdepth; z++) {
2293 					cwpos.wz = -z;
2294 					if(d_ptr->level[z - 1].ondepth && d_ptr->level[z - 1].cave)
2295 						wr_floor(&cwpos);
2296 				}
2297 			}
2298 			if (w_ptr->flags & WILD_F_UP) {
2299 				struct dungeon_type *d_ptr = w_ptr->tower;
2300 				for (z = 1; z <= d_ptr->maxdepth; z++) {
2301 					cwpos.wz = z;
2302 					if(d_ptr->level[z - 1].ondepth && d_ptr->level[z - 1].cave)
2303 						wr_floor(&cwpos);
2304 				}
2305 			}
2306 			cwpos.wz = 0;
2307 		}
2308 	}
2309 	wr_s16b(0x7fff);	/* this could fail if we had 32767^3 areas */
2310 	wr_s16b(0x7fff);	/* I cant see that happening for a while */
2311 	wr_s16b(0x7fff);
2312 }
2313 
save_server_aux(char * name)2314 static bool save_server_aux(char *name) {
2315 	bool	ok = FALSE;
2316 	int	fd = -1;
2317 	int	mode = 0644;
2318 
2319 
2320 	/* No file yet */
2321 	fff = NULL;
2322 
2323 	/* File type is "SAVE" */
2324 	FILE_TYPE(FILE_TYPE_SAVE);
2325 
2326 	/* Create the savefile */
2327 	fd = fd_make(name, mode);
2328 
2329 	/* File is okay */
2330 	if (fd >= 0) {
2331 		/* Close the "fd" */
2332 		(void)fd_close(fd);
2333 
2334 		/* Open the savefile */
2335 		fff = my_fopen(name, "wb");
2336 
2337 		/* Successful open */
2338 		if (fff) {
2339 			/* Allocate a buffer */
2340 			fff_buf = C_NEW(MAX_BUF_SIZE, char);
2341 			fff_buf_pos = 0;
2342 
2343 			/* Write the savefile */
2344 			if (wr_server_savefile()) ok = TRUE;
2345 
2346 			/* Attempt to close it */
2347 			if (my_fclose(fff)) ok = FALSE;
2348 
2349 			/* Free the buffer */
2350 			C_FREE(fff_buf, MAX_BUF_SIZE, char);
2351 		}
2352 
2353 		/* Remove "broken" files */
2354 		if (!ok) (void)fd_kill(name);
2355 	}
2356 
2357 
2358 	/* Failure */
2359 	if (!ok) return (FALSE);
2360 
2361 	/* Successful save */
2362 	/*server_saved = TRUE;*/
2363 
2364 	/* Success */
2365 	return (TRUE);
2366 }
2367 
2368 
2369 /*
2370  * Load the whole server info from one special savefile.
2371  */
load_server_info_classic(void)2372 static bool load_server_info_classic(void) {
2373 	int fd = -1;
2374 	byte vvv[4];
2375 	errr err = 0;
2376 	cptr what = "generic";
2377 	char buf[1024];
2378 
2379 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "server");
2380 
2381 	/* XXX XXX XXX Fix this */
2382 	if (!file_exist(buf)) {
2383 		/* Give message */
2384 		s_printf("Server savefile does not exist\n");
2385 
2386 		/* Allow this */
2387 		return (TRUE);
2388 	}
2389 
2390 	/* Okay */
2391 	if (!err) {
2392 		/* Open the savefile */
2393 		fd = fd_open(buf, O_RDONLY);
2394 
2395 		/* No file */
2396 		if (fd < 0) err = -1;
2397 
2398 		/* Message (below) */
2399 		if (err) what = "Cannot open savefile";
2400 	}
2401 
2402 	/* Process file */
2403 	if (!err) {
2404 		/* Read the first four bytes */
2405 		if (fd_read(fd, (char*)(vvv), 4)) err = -1;
2406 
2407 		/* What */
2408 		if (err) what = "Cannot read savefile";
2409 
2410 		/* Close the file */
2411 		(void)fd_close(fd);
2412 	}
2413 
2414 	/* Process file */
2415 	if (!err) {
2416 		/* Extract version */
2417 		sf_major = vvv[0];
2418 		sf_minor = vvv[1];
2419 		sf_patch = vvv[2];
2420 		sf_extra = vvv[3];
2421 
2422 		/* Parse "MAngband" savefiles */
2423 		/* If I ever catch the one that put that STUPID UGLY IDIOT
2424 		 * HACK there he will know what *WRATH* means ... -- DG
2425 		 */
2426 
2427 		/* Attempt to load */
2428 		err = rd_server_savefile();
2429 
2430 		/* Message (below) */
2431 		/*
2432 		   if (err) {
2433 		   what = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx";
2434 		   (void)sprintf (what,"Cannot parse savefile error %d",err);
2435 		   };
2436 		   */
2437 		if (err) what ="Cannot parse savefile error %d";
2438 	}
2439 
2440 	/* Okay */
2441 	if (!err) {
2442 		/* Give a conversion warning */
2443 		if ((version_major != sf_major) ||
2444 		    (version_minor != sf_minor) ||
2445 		    (version_patch != sf_patch)) {
2446 			/* Message */
2447 			printf("Converted a %d.%d.%d savefile.\n",
2448 					sf_major, sf_minor, sf_patch);
2449 		}
2450 
2451 		/* The server state was loaded */
2452 		server_state_loaded = TRUE;
2453 
2454 		/* Success */
2455 		return (TRUE);
2456 	}
2457 
2458 	/* Message */
2459 	s_printf("Error (%s) reading a %d.%d.%d server savefile.\n", what, sf_major, sf_minor, sf_patch);
2460 
2461 	return (FALSE);
2462 }
2463 
2464 /* Load the complete server info, either
2465  *   -from one giant 'server' save file (old way) or
2466  *   -from multiple partial 'server0'..'serverN' save files (new):
2467  *	server0		wilderness, dungeons, towns, houses
2468  *	server1		item flavours
2469  *	server2		parties, guilds, bbs
2470  */
load_server_info(void)2471 bool load_server_info(void) {
2472 	char buf[1024];
2473 
2474 	/* check for existence of old huge server save file */
2475 	path_build(buf, 1024, ANGBAND_DIR_SAVE, "server");
2476 	if (file_exist(buf)) {
2477 //		s_printf("Found classic 'server' savefile\n");
2478 		return load_server_info_classic();
2479 	}
2480 
2481 	/* check for existence of partial server save files */
2482 
2483 	//TODO
2484 
2485 
2486 	/* regenerate server savefile */
2487 	s_printf("Server savefile does not exist\n");
2488 
2489 	/* Allow this */
2490 	return (TRUE);
2491 }
2492 
2493 /*
2494  * Save the server state to a "server" savefile.
2495  */
save_server_info()2496 bool save_server_info() {
2497 	int result = FALSE;
2498 	char safe[MAX_PATH_LENGTH];
2499 
2500 #if DEBUG_LEVEL > 1
2501 	printf("saving server info...\n");
2502 #endif
2503 	/* New savefile */
2504 	path_build(safe, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "server.new");
2505 
2506 	/* Remove it */
2507 	fd_kill(safe);
2508 
2509 	/* Attempt to save the server state */
2510 	if (save_server_aux(safe)) {
2511 		char temp[MAX_PATH_LENGTH];
2512 		char prev[MAX_PATH_LENGTH];
2513 
2514 		/* Old savefile */
2515 		path_build(temp, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "server.old");
2516 
2517 		/* Remove it */
2518 		fd_kill(temp);
2519 
2520 		/* Name of previous savefile */
2521 		path_build(prev, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "server");
2522 
2523 		/* Preserve old savefile */
2524 		fd_move(prev, temp);
2525 
2526 		/* Activate new savefile */
2527 		fd_move(safe, prev);
2528 
2529 		/* Remove preserved savefile */
2530 		fd_kill(temp);
2531 
2532 		/* Success */
2533 		result = TRUE;
2534 	}
2535 
2536 	/* Return the result */
2537 	return (result);
2538 }
2539 
wr_towns()2540 void wr_towns() {
2541 	int i, j;
2542 	wr_u16b(numtowns);
2543 	for (i = 0; i < numtowns; i++){
2544 		wr_u16b(town[i].x);
2545 		wr_u16b(town[i].y);
2546 		wr_u16b(town[i].baselevel);
2547 		wr_u16b(town[i].flags);
2548 		wr_u16b(town[i].num_stores);
2549 		wr_u16b(town[i].type);
2550 
2551 		/* Dump the stores */
2552 		for (j = 0; j < town[i].num_stores; j++){
2553 			wr_store(&town[i].townstore[j]);
2554 		}
2555 	}
2556 }
2557 
save_banlist(void)2558 void save_banlist(void) {
2559 	char buf[1024];
2560 	FILE *fp;
2561 	struct combo_ban *ptr;
2562 
2563 	path_build(buf, 1024, ANGBAND_DIR_CONFIG, "banlist.txt");
2564 
2565 	fp = fopen(buf, "w");
2566 	if (!fp) return;
2567 
2568 	for (ptr = banlist; ptr != (struct combo_ban*)NULL; ptr = ptr->next)
2569 		fprintf(fp, "%s|%s|%s|%d|%s\n", ptr->acc[0] ? ptr->acc : " ", ptr->ip[0] ? ptr->ip : " ", ptr->hostname[0] ? ptr->hostname : " ", ptr->time, ptr->reason[0] ? ptr->reason : " "); /* omg fu scanf^^ */
2570 	fclose(fp);
2571 }
2572 
2573 /* ---------- Save dynamic quest data.  ---------- */
2574 /* This cannot be done in the server savefile, because it gets read before all
2575    ?_info.txt files are read from lib/data. So for example the remaining number
2576    of kills in a kill-quest cannot be stored anywhere, since the stage and
2577    stage goals are not yet initialised. Oops.
2578    However, saving this quest data of random/varying lenght is a mess anyway,
2579    so it's good that we keep it far away from the server savefile. */
save_quests_file(void)2580 static bool save_quests_file(void) {
2581 	int i, j, k;
2582 	u32b now;
2583 
2584 	byte tmp8u;
2585 
2586 
2587 	quest_info *q_ptr;
2588 
2589 	qi_questor *q_questor;
2590 	qi_goal *q_goal;
2591 	qi_stage *q_stage;
2592 
2593 
2594 	now = time((time_t *)0);
2595 	/* Note the operating system */
2596 	sf_xtra = 0L;
2597 	/* Note when the file was saved */
2598 	sf_when = now;
2599 
2600 	/* Dump the file header */
2601 	xor_byte = 0;
2602 	wr_byte(QUEST_SF_VERSION_MAJOR);
2603 	xor_byte = 0;
2604 	wr_byte(QUEST_SF_VERSION_MINOR);
2605 	xor_byte = 0;
2606 	wr_byte(QUEST_SF_VERSION_PATCH);
2607 	xor_byte = 0;
2608 	tmp8u = rand_int(256);
2609 	wr_byte(tmp8u);
2610 
2611 	/* Reset the checksum */
2612 	v_stamp = 0L;
2613 	x_stamp = 0L;
2614 
2615 	wr_u32b(sf_xtra);
2616 	wr_u32b(sf_when);
2617 
2618 	/* begin writing the actual quest data */
2619 
2620 	wr_s16b(max_q_idx);
2621 	for (i = 0; i < max_q_idx; i++) {
2622 		q_ptr = &q_info[i];
2623 
2624 		//to recognize the quest (ID)
2625 		wr_string(q_ptr->codename);
2626 		wr_string(q_ptr->creator);
2627 		wr_u16b(q_ptr->name);
2628 
2629 		//main quest data
2630 		wr_byte(q_ptr->active);
2631 #if 0 /* 0'ed for now, use 'x' disable feature from q_info.txt exclusively. */
2632 		wr_byte(q_ptr->disabled);
2633 #else
2634 		wr_byte(0);
2635 #endif
2636 
2637 		wr_s16b(q_ptr->cur_cooldown);
2638 		wr_s32b(q_ptr->turn_activated);
2639 		wr_s32b(q_ptr->turn_acquired);
2640 
2641 		wr_s16b(q_ptr->cur_stage);
2642 		wr_u16b(q_ptr->flags);
2643 		wr_byte(q_ptr->tainted);
2644 		wr_s16b(q_ptr->objects_registered);
2645 
2646 		wr_s16b(q_ptr->timed_countdown);
2647 		wr_s16b(q_ptr->timed_countdown_stage);
2648 		wr_byte(q_ptr->timed_countdown_quiet);
2649 
2650 		//dynamically generated random passwords
2651 		for (j = 0; j < QI_PASSWORDS; j++)
2652 			wr_string(q_ptr->password[j]);
2653 
2654 		//questors:
2655 		wr_byte(q_ptr->questors);
2656 		for (j = 0; j < q_ptr->questors; j++) {
2657 			q_questor = &q_ptr->questor[j];
2658 
2659 			wr_s16b(q_questor->current_wpos.wx);
2660 			wr_s16b(q_questor->current_wpos.wy);
2661 			wr_s16b(q_questor->current_wpos.wz);
2662 
2663 			wr_s16b(q_questor->current_x);
2664 			wr_s16b(q_questor->current_y);
2665 
2666 			wr_s16b(q_questor->mo_idx);
2667 			wr_s16b(q_questor->talk_focus);//not needed
2668 
2669 			wr_byte(q_questor->tainted);
2670 		}
2671 
2672 		//stages:
2673 		wr_byte(q_ptr->stages);
2674 		for (j = 0; j < q_ptr->stages; j++) {
2675 			q_stage = &q_ptr->stage[j];
2676 
2677 			//questor hostility timers:
2678 			for (k = 0; k < q_ptr->questors; k++) {
2679 				if (q_stage->questor_hostility[k])
2680 					wr_s16b(q_stage->questor_hostility[k]->hostile_revert_timed_countdown);
2681 				else
2682 					wr_s16b(9999);
2683 			}
2684 
2685 			//goals:
2686 			wr_byte(q_stage->goals);
2687 			for (k = 0; k < q_stage->goals; k++) {
2688 				q_goal = &q_stage->goal[k];
2689 
2690 				wr_byte(q_goal->cleared);
2691 				wr_byte(q_goal->nisi);
2692 
2693 				//kill goals:
2694 				if (q_goal->kill) wr_s16b(q_goal->kill->number_left);
2695 				else wr_s16b(-1); /* actually write a value for recognising, in case quest has been edited meanwhile */
2696 			}
2697 		}
2698 	}
2699 
2700 	/* finish up */
2701 
2702 	/* Write the remaining contents of the buffer */
2703 	write_buffer();
2704 	/* Error in save */
2705 	if (ferror(fff) || (fflush(fff) == EOF)) return FALSE;
2706 	/* Successful save */
2707 	return TRUE;
2708 }
save_quests_aux(char * name)2709 static bool save_quests_aux(char *name) {
2710 	bool	ok = FALSE;
2711 	int	fd = -1;
2712 	int	mode = 0644;
2713 
2714 	fff = NULL;
2715 	FILE_TYPE(FILE_TYPE_SAVE);
2716 	fd = fd_make(name, mode);
2717 	if (fd >= 0) {
2718 		(void)fd_close(fd);
2719 		fff = my_fopen(name, "wb");
2720 		if (fff) {
2721 			fff_buf = C_NEW(MAX_BUF_SIZE, char);
2722 			fff_buf_pos = 0;
2723 			if (save_quests_file()) ok = TRUE;
2724 			if (my_fclose(fff)) ok = FALSE;
2725 			C_FREE(fff_buf, MAX_BUF_SIZE, char);
2726 		}
2727 		if (!ok) (void)fd_kill(name);
2728 	}
2729 	if (!ok) return FALSE;
2730 	return TRUE;
2731 }
save_quests(void)2732 void save_quests(void) {
2733 	//int result = FALSE;
2734 	char safe[MAX_PATH_LENGTH];
2735 
2736 #if DEBUG_LEVEL > 1
2737 	printf("saving quest info...\n");
2738 #endif
2739 	path_build(safe, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "quests.new");
2740 	fd_kill(safe);
2741 
2742 	if (save_quests_aux(safe)) {
2743 		char temp[MAX_PATH_LENGTH];
2744 		char prev[MAX_PATH_LENGTH];
2745 
2746 		path_build(temp, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "quests.old");
2747 		fd_kill(temp);
2748 		path_build(prev, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "quests");
2749 		fd_move(prev, temp);
2750 		fd_move(safe, prev);
2751 		fd_kill(temp);
2752 		//result = TRUE;
2753 	}
2754 	return;// (result);
2755 }
2756