1 /*
2  *  shapevga.cc - Handle the 'shapes.vga' file and associated info.
3  *
4  *  Copyright (C) 1999  Jeffrey S. Freedman
5  *  Copyright (C) 2000-2013  The Exult Team
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25 
26 #include <iomanip>          /* For debugging only. */
27 #include <sstream>
28 #include "shapevga.h"
29 #include "ammoinf.h"
30 #include "aniinf.h"
31 #include "armorinf.h"
32 #include "bodyinf.h"
33 #include "continf.h"
34 #include "effhpinf.h"
35 #include "expinf.h"
36 #include "frnameinf.h"
37 #include "frflags.h"
38 #include "frusefun.h"
39 #include "lightinf.h"
40 #include "monstinf.h"
41 #include "npcdollinf.h"
42 #include "objdollinf.h"
43 #include "sfxinf.h"
44 #include "warminf.h"
45 #include "weaponinf.h"
46 #include "data/exult_bg_flx.h"
47 #include "data/exult_si_flx.h"
48 #include "utils.h"
49 #include "databuf.h"
50 #include "msgfile.h"
51 #include "U7file.h"
52 #include "exceptions.h"
53 #include "ready.h"
54 #include "data_utils.h"
55 #include "ignore_unused_variable_warning.h"
56 #include "array_size.h"
57 
58 using std::ifstream;
59 using std::ios;
60 using namespace std;
61 
62 // For convienience
63 #define patch_exists(p) (have_patch_path && U7exists(p))
64 #define patch_name(p) (patch_exists(p) ? (p) : nullptr)
65 
66 /*
67  *  Open, but don't quit if editing.  We first try the patch name if it's
68  *  given.
69  */
70 
U7open2(ifstream & in,const char * pname,const char * fname,bool editing)71 static bool U7open2(
72     ifstream &in,           // Stream to open.
73     const char *pname,      // Patch name, or null.
74     const char *fname,      // File name.
75     bool editing
76 ) {
77 	ignore_unused_variable_warning(editing);
78 	if (pname) {
79 		U7open(in, pname);
80 		return true;
81 	}
82 	try {
83 		U7open(in, fname);
84 	} catch (const file_exception & /*f*/) {
85 		return false;
86 	}
87 	return true;
88 }
89 
90 // Special case ID reader functors.
91 
92 extern int get_skinvar(const std::string& key);
93 
94 // Multiracial support in Exult.
95 class Paperdoll_npc_ID_reader {
96 public:
operator ()(std::istream & in,int index,int version,bool binary)97 	int operator()(std::istream &in, int index, int version, bool binary) {
98 		ignore_unused_variable_warning(index, version, binary);
99 		if (in.peek() == '%') {
100 			std::string key = ReadStr(in);
101 			// We need these for Exult, but not for ES.
102 			// For now, a compromise/hack in that ES defines
103 			// a version of this function which always returns
104 			// -1, while Exult has another which forwards to
105 			// Shapeinfo_lookup::get_skinvar
106 			int id = get_skinvar(key);
107 			return id < 0 ? -1 : id;
108 		} else
109 			return ReadInt(in);
110 	}
111 };
112 
113 // For backward compatibility.
114 class Body_ID_reader {
115 public:
operator ()(std::istream & in,int index,int version,bool binary)116 	int operator()(std::istream &in, int index, int version, bool binary) {
117 		ignore_unused_variable_warning(binary);
118 		return version == 1 ? index : ReadInt(in);
119 	}
120 };
121 
122 // Special case reader functor.
123 class Gump_reader_functor {
124 public:
operator ()(std::istream & in,int version,bool patch,Exult_Game game,Shape_info & info)125 	bool operator()(std::istream &in, int version, bool patch,
126 	                Exult_Game game, Shape_info &info) {
127 		ignore_unused_variable_warning(patch, game);
128 		info.gump_shape = Read2(in);
129 		if (version >= 2)
130 			info.gump_font = Read2(in);
131 		else
132 			info.gump_font = -1;
133 		return true;
134 	}
135 };
136 
137 // A few custom post-read functors.
138 class Ready_type_functor {
139 	Patch_flags_functor<ready_type_flag, Shape_info> setflags;
140 public:
operator ()(std::istream & in,int version,bool patch,Exult_Game game,Shape_info & info)141 	void operator()(std::istream &in, int version, bool patch,
142 	                Exult_Game game, Shape_info &info) {
143 		unsigned char ready = info.ready_type;
144 		info.spell_flag = ready & 1;
145 		ready >>= 3;
146 		unsigned char spot = game == BLACK_GATE ? Ready_spot_from_BG(ready)
147 		            : Ready_spot_from_SI(ready);
148 		info.ready_type = spot;
149 		// Init alternate spots.
150 		switch (spot) {
151 		case lfinger:
152 			info.alt_ready1 = rfinger;
153 			break;
154 		case lhand:
155 			info.alt_ready1 = rhand;
156 			info.alt_ready2 = belt;
157 			break;
158 		case both_hands:
159 			info.alt_ready1 = back_2h;
160 			break;
161 		}
162 		setflags(in, version, patch, game, info);
163 	}
164 };
165 
166 class Actor_flags_functor {
167 	Patch_flags_functor<actor_flags_flag, Shape_info> setflags;
168 public:
operator ()(std::istream & in,int version,bool patch,Exult_Game game,Shape_info & info)169 	void operator()(std::istream &in, int version, bool patch,
170 	                Exult_Game game, Shape_info &info) {
171 		setflags(in, version, patch, game, info);
172 	}
173 };
174 
175 class Paperdoll_npc_functor {
176 public:
operator ()(std::istream & in,int version,bool patch,Exult_Game game,Shape_info & info)177 	void operator()(std::istream &in, int version, bool patch,
178 	                Exult_Game game, Shape_info &info) {
179 		ignore_unused_variable_warning(patch, game);
180 		if (version < 3)
181 			// We need this for backward compatibility.
182 			// We use the setter methods so that the info
183 			// will get saved by ES if that is needed.
184 			info.set_gump_data(ReadInt(in, -1), -1);
185 	}
186 };
187 
Read_Shapeinf_text_data_file(bool editing,Exult_Game game_type)188 void Shapes_vga_file::Read_Shapeinf_text_data_file(
189     bool editing,
190     Exult_Game game_type
191 ) {
192 	const char *sections[] = {"explosions", "shape_sfx", "animation",
193 	                          "usecode_events", "mountain_tops", "monster_food", "actor_flags",
194 	                          "effective_hps", "lightweight_object", "light_data", "warmth_data",
195 	                          "quantity_frames", "locked_containers", "content_rules",
196 	                          "volatile_explosive", "framenames", "altready", "barge_type",
197 	                          "frame_powers", "is_jawbone", "is_mirror", "on_fire",
198 	                          "extradimensional_storage", "field_type",
199 	                          "frame_usecode"
200 	                         };
201 	Base_reader *readers[] = {
202 		// For explosions.
203 		new Functor_multidata_reader < Shape_info,
204 		Class_reader_functor < Explosion_info, Shape_info,
205 		&Shape_info::explosion > > (info),
206 		// For sound effects.
207 		new Functor_multidata_reader < Shape_info,
208 		Class_reader_functor < SFX_info, Shape_info,
209 		&Shape_info::sfxinf > > (info),
210 		// For animations.
211 		new Functor_multidata_reader < Shape_info,
212 		Class_reader_functor < Animation_info, Shape_info,
213 		&Shape_info::aniinf > > (info),
214 		// For usecode events.
215 		new Functor_multidata_reader < Shape_info,
216 		Bit_text_reader_functor < unsigned short, Shape_info,
217 		&Shape_info::shape_flags, Shape_info::usecode_events > ,
218 		Patch_flags_functor<usecode_events_flag, Shape_info> > (info),
219 		// For mountain tops.
220 		new Functor_multidata_reader < Shape_info,
221 		Text_reader_functor < unsigned char, Shape_info,
222 		&Shape_info::mountain_top > ,
223 		Patch_flags_functor<mountain_top_flag, Shape_info> > (info),
224 		// For monster food.
225 		new Functor_multidata_reader < Shape_info,
226 		Text_reader_functor < short, Shape_info,
227 		&Shape_info::monster_food > ,
228 		Patch_flags_functor<monster_food_flag, Shape_info> > (info),
229 		// For actor flags.
230 		new Functor_multidata_reader < Shape_info,
231 		Bit_field_text_reader_functor < unsigned char, Shape_info,
232 		&Shape_info::actor_flags > ,
233 		Actor_flags_functor > (info),
234 		// For effective HPs.
235 		new Functor_multidata_reader < Shape_info,
236 		Vector_reader_functor < Effective_hp_info, Shape_info,
237 		&Shape_info::hpinf > > (info),
238 		// For lightweight objects.
239 		new Functor_multidata_reader < Shape_info,
240 		Bit_text_reader_functor < unsigned short, Shape_info,
241 		&Shape_info::shape_flags, Shape_info::lightweight > ,
242 		Patch_flags_functor<lightweight_flag, Shape_info> > (info),
243 		// For light data.
244 		new Functor_multidata_reader < Shape_info,
245 		Vector_reader_functor < Light_info, Shape_info,
246 		&Shape_info::lightinf > > (info),
247 		// For warmth data.
248 		new Functor_multidata_reader < Shape_info,
249 		Vector_reader_functor < Warmth_info, Shape_info,
250 		&Shape_info::warminf > > (info),
251 		// For quantity frames.
252 		new Functor_multidata_reader < Shape_info,
253 		Bit_text_reader_functor < unsigned short, Shape_info,
254 		&Shape_info::shape_flags, Shape_info::quantity_frames > ,
255 		Patch_flags_functor<quantity_frames_flag, Shape_info> > (info),
256 		// For locked objects.
257 		new Functor_multidata_reader < Shape_info,
258 		Bit_text_reader_functor < unsigned short, Shape_info,
259 		&Shape_info::shape_flags, Shape_info::locked > ,
260 		Patch_flags_functor<locked_flag, Shape_info> > (info),
261 		// For content rules.
262 		new Functor_multidata_reader < Shape_info,
263 		Vector_reader_functor < Content_rules, Shape_info,
264 		&Shape_info::cntrules > > (info),
265 		// For highly explosive objects.
266 		new Functor_multidata_reader < Shape_info,
267 		Bit_text_reader_functor < unsigned short, Shape_info,
268 		&Shape_info::shape_flags, Shape_info::is_volatile > ,
269 		Patch_flags_functor<is_volatile_flag, Shape_info> > (info),
270 		// For frame names.
271 		new Functor_multidata_reader < Shape_info,
272 		Vector_reader_functor < Frame_name_info, Shape_info,
273 		&Shape_info::nameinf > > (info),
274 		// For alternate ready spots.
275 		new Functor_multidata_reader < Shape_info,
276 		Text_pair_reader_functor < unsigned char, Shape_info,
277 		&Shape_info::alt_ready1, &Shape_info::alt_ready2 > ,
278 		Patch_flags_functor<altready_type_flag, Shape_info> > (info),
279 		// For barge parts.
280 		new Functor_multidata_reader < Shape_info,
281 		Text_reader_functor < unsigned char, Shape_info,
282 		&Shape_info::barge_type > ,
283 		Patch_flags_functor<barge_type_flag, Shape_info> > (info),
284 		// For frame flags.
285 		new Functor_multidata_reader < Shape_info,
286 		Vector_reader_functor < Frame_flags_info, Shape_info,
287 		&Shape_info::frflagsinf > > (info),
288 		// For the jawbone.
289 		new Functor_multidata_reader < Shape_info,
290 		Bit_text_reader_functor < unsigned short, Shape_info,
291 		&Shape_info::shape_flags, Shape_info::jawbone > ,
292 		Patch_flags_functor<jawbone_flag, Shape_info> > (info),
293 		// Mirrors.
294 		new Functor_multidata_reader < Shape_info,
295 		Bit_text_reader_functor < unsigned short, Shape_info,
296 		&Shape_info::shape_flags, Shape_info::mirror > ,
297 		Patch_flags_functor<mirror_flag, Shape_info> > (info),
298 		// Objects on fire.
299 		new Functor_multidata_reader < Shape_info,
300 		Bit_text_reader_functor < unsigned short, Shape_info,
301 		&Shape_info::shape_flags, Shape_info::on_fire > ,
302 		Patch_flags_functor<on_fire_flag, Shape_info> > (info),
303 		// Containers with unlimited storage.
304 		new Functor_multidata_reader < Shape_info,
305 		Bit_text_reader_functor < unsigned short, Shape_info,
306 		&Shape_info::shape_flags, Shape_info::extradimensional_storage > ,
307 		Patch_flags_functor<extradimensional_storage_flag, Shape_info> > (info),
308 		// For field types.
309 		new Functor_multidata_reader < Shape_info,
310 		Text_reader_functor < signed char, Shape_info,
311 		&Shape_info::field_type > ,
312 		Patch_flags_functor<field_type_flag, Shape_info> > (info),
313 		// For frame usecode.
314 		new Functor_multidata_reader < Shape_info,
315 		Vector_reader_functor < Frame_usecode_info, Shape_info,
316 		&Shape_info::frucinf > > (info),
317 	};
318 	int numsections = array_size(sections);
319 	int numreaders = array_size(readers);
320 	assert(numsections == numreaders);
321 	int flxres = game_type == BLACK_GATE ?
322 	             EXULT_BG_FLX_SHAPE_INFO_TXT : EXULT_SI_FLX_SHAPE_INFO_TXT;
323 
324 	Read_text_data_file("shape_info", readers, sections,
325 	                    numsections, editing, game_type, flxres);
326 }
327 
Read_Bodies_text_data_file(bool editing,Exult_Game game_type)328 void Shapes_vga_file::Read_Bodies_text_data_file(
329     bool editing,
330     Exult_Game game_type
331 ) {
332 	const char *sections[] = {"bodyshapes", "bodylist"};
333 	Base_reader *readers[] = {
334 		new Functor_multidata_reader < Shape_info,
335 		Bit_text_reader_functor < unsigned short, Shape_info,
336 		&Shape_info::shape_flags, Shape_info::is_body > ,
337 		Patch_flags_functor<is_body_flag, Shape_info>,
338 		Body_ID_reader > (info),
339 		new Functor_multidata_reader < Shape_info,
340 		Class_reader_functor < Body_info, Shape_info,
341 		&Shape_info::body > > (info)
342 	};
343 	int numsections = array_size(sections);
344 	int numreaders = array_size(readers);
345 	assert(numsections == numreaders);
346 	int flxres = game_type == BLACK_GATE ?
347 	             EXULT_BG_FLX_BODIES_TXT : EXULT_SI_FLX_BODIES_TXT;
348 
349 	Read_text_data_file("bodies", readers, sections,
350 	                    numsections, editing, game_type, flxres);
351 }
352 
Read_Paperdoll_text_data_file(bool editing,Exult_Game game_type)353 void Shapes_vga_file::Read_Paperdoll_text_data_file(
354     bool editing,
355     Exult_Game game_type
356 ) {
357 	const char *sections[] = {"characters", "items"};
358 	Base_reader *readers[] = {
359 		new Functor_multidata_reader < Shape_info,
360 		Class_reader_functor < Paperdoll_npc, Shape_info,
361 		&Shape_info::npcpaperdoll > ,
362 		Paperdoll_npc_functor,
363 		Paperdoll_npc_ID_reader > (info),
364 		new Functor_multidata_reader < Shape_info,
365 		Vector_reader_functor < Paperdoll_item, Shape_info,
366 		&Shape_info::objpaperdoll > > (info),
367 	};
368 	int numsections = array_size(sections);
369 	int numreaders = array_size(readers);
370 	assert(numsections == numreaders);
371 	int flxres = game_type == BLACK_GATE ?
372 	             EXULT_BG_FLX_PAPERDOL_INFO_TXT : EXULT_SI_FLX_PAPERDOL_INFO_TXT;
373 
374 	Read_text_data_file("paperdol_info", readers, sections,
375 	                    numsections, editing, game_type, flxres);
376 }
377 
378 /*
379  *  Reload static data for weapons, ammo and mosters to
380  *  fix data that was lost by earlier versions of ES.
381  */
fix_old_shape_info(Exult_Game game)382 void Shapes_vga_file::fix_old_shape_info(
383     Exult_Game game     // Which game.
384 ) {
385 	if (!info_read) // Read info first.
386 		read_info(game, true);
387 	Functor_multidata_reader < Shape_info,
388 	                         Class_reader_functor < Weapon_info, Shape_info,
389 	                         &Shape_info::weapon > > weapon(info);
390 	weapon.read(WEAPONS, false, game);
391 	Functor_multidata_reader < Shape_info,
392 	                         Class_reader_functor < Ammo_info, Shape_info,
393 	                         &Shape_info::ammo > > ammo(info);
394 	ammo.read(AMMO, false, game);
395 	Functor_multidata_reader < Shape_info,
396 	                         Class_reader_functor < Monster_info, Shape_info,
397 	                         &Shape_info::monstinf > > monstinf(info);
398 	monstinf.read(MONSTERS, false, game);
399 }
400 
401 /*
402  *  Reload info.
403  */
404 
reload_info(Exult_Game game)405 void Shapes_vga_file::reload_info(
406     Exult_Game game     // Which game.
407 ) {
408 	info_read = false;
409 	info.clear();
410 	read_info(game);
411 }
412 
413 /*
414  *  Read in data files about shapes.
415  *
416  *  Output: 0 if error.
417  */
418 
read_info(Exult_Game game,bool editing)419 bool Shapes_vga_file::read_info(
420     Exult_Game game,        // Which game.
421     bool editing            // True to allow files to not exist.
422 ) {
423 	if (info_read)
424 		return false;
425 	info_read = true;
426 	bool have_patch_path = is_system_path_defined("<PATCH>");
427 
428 	// ShapeDims
429 
430 	// Starts at 0x96'th shape.
431 	ifstream shpdims;
432 	if (U7open2(shpdims, patch_name(PATCH_SHPDIMS), SHPDIMS, editing))
433 		for (size_t i = c_first_obj_shape;
434 		        i < shapes.size() && !shpdims.eof(); i++) {
435 			info[i].shpdims[0] = shpdims.get();
436 			info[i].shpdims[1] = shpdims.get();
437 		}
438 
439 	// WGTVOL
440 	ifstream wgtvol;
441 	if (U7open2(wgtvol, patch_name(PATCH_WGTVOL), WGTVOL, editing))
442 		for (size_t i = 0; i < shapes.size() && !wgtvol.eof(); i++) {
443 			info[i].weight = wgtvol.get();
444 			info[i].volume = wgtvol.get();
445 		}
446 
447 	// TFA
448 	ifstream tfa;
449 	if (U7open2(tfa, patch_name(PATCH_TFA), TFA, editing))
450 		for (size_t i = 0; i < shapes.size() && !tfa.eof(); i++) {
451 			tfa.read(reinterpret_cast<char *>(&info[i].tfa[0]), 3);
452 			info[i].set_tfa_data();
453 		}
454 
455 	if (game == BLACK_GATE || game == SERPENT_ISLE) {
456 		// Animation data at the end of BG and SI TFA.DAT
457 		ifstream stfa;
458 		// We *should* blow up if TFA not there.
459 		U7open(stfa, TFA);
460 		stfa.seekg(3 * 1024);
461 		unsigned char buf[512];
462 		stfa.read(reinterpret_cast<char *>(buf), 512);
463 		stfa.close();
464 		unsigned char *ptr = buf;
465 		for (int i = 0; i < 512; i++, ptr++) {
466 			int val = *ptr;
467 			int shape = 2 * i;
468 			while (val) {
469 				if (val & 0xf) {
470 					delete info[shape].aniinf;
471 					info[shape].aniinf = Animation_info::create_from_tfa(
472 					                         val & 0xf, get_num_frames(shape));
473 				}
474 				val >>= 4;
475 				shape++;
476 			}
477 		}
478 	}
479 
480 	// Load data about drawing the weapon in an actor's hand
481 	ifstream wihh;
482 	if (U7open2(wihh, patch_name(PATCH_WIHH), WIHH, editing)) {
483 		size_t cnt = shapes.size();
484 		unsigned short offsets[c_max_shapes];
485 		for (size_t i = 0; i < cnt; i++)
486 			offsets[i] = Read2(wihh);
487 		for (size_t i = 0; i < cnt; i++)
488 			// A zero offset means there is no record
489 			if (offsets[i] == 0)
490 				info[i].weapon_offsets = nullptr;
491 			else {
492 				wihh.seekg(offsets[i]);
493 				// There are two bytes per frame: 64 total
494 				info[i].weapon_offsets = new unsigned char[64];
495 				for (int j = 0; j < 32; j++) {
496 					unsigned char x = Read1(wihh);
497 					unsigned char y = Read1(wihh);
498 					// Set x/y to 255 if weapon is not to be drawn
499 					// In the file x/y are either 64 or 255:
500 					// I am assuming that they mean the same
501 					if (x > 63 || y > 63)
502 						x = y = 255;
503 					info[i].weapon_offsets[j * 2] = x;
504 					info[i].weapon_offsets[j * 2 + 1] = y;
505 				}
506 			}
507 		wihh.close();
508 	}
509 
510 	ifstream occ;          // Read flags from occlude.dat.
511 	if (U7open2(occ, patch_name(PATCH_OCCLUDE), OCCLUDE, editing)) {
512 		unsigned char occbits[c_occsize];   // c_max_shapes bit flags.
513 		// Ensure sensible defaults.
514 		memset(&occbits[0], 0, sizeof(occbits));
515 		occ.read(reinterpret_cast<char *>(occbits), sizeof(occbits));
516 		for (int i = 0; i < occ.gcount(); i++) {
517 			unsigned char bits = occbits[i];
518 			int shnum = i * 8;  // Check each bit.
519 			for (int b = 0; bits; b++, bits = bits >> 1)
520 				if (bits & 1)
521 					info[shnum + b].occludes_flag = true;
522 		}
523 	}
524 
525 	// Get 'equip.dat'.
526 	ifstream mfile;
527 	if (U7open2(mfile, patch_name(PATCH_EQUIP), EQUIP, editing)) {
528 		// Get # entries (with Exult extension).
529 		int num_recs = Read_count(mfile);
530 		Monster_info::reserve_equip(num_recs);
531 		for (int i = 0; i < num_recs; i++) {
532 			Equip_record equip;
533 			// 10 elements/record.
534 			for (int elem = 0; elem < 10; elem++) {
535 				int shnum = Read2(mfile);
536 				unsigned prob = Read1(mfile);
537 				unsigned quant = Read1(mfile);
538 				Read2(mfile);
539 				equip.set(elem, shnum, prob, quant);
540 			}
541 			Monster_info::add_equip(equip);
542 		}
543 		mfile.close();
544 	}
545 
546 	Functor_multidata_reader < Shape_info,
547 	                         Class_reader_functor < Armor_info, Shape_info,
548 	                         &Shape_info::armor > > armor(info);
549 	armor.read(ARMOR, false, game);
550 	armor.read(PATCH_ARMOR, true, game);
551 
552 	Functor_multidata_reader < Shape_info,
553 	                         Class_reader_functor < Weapon_info, Shape_info,
554 	                         &Shape_info::weapon > > weapon(info);
555 	weapon.read(WEAPONS, false, game);
556 	weapon.read(PATCH_WEAPONS, true, game);
557 
558 	Functor_multidata_reader < Shape_info,
559 	                         Class_reader_functor < Ammo_info, Shape_info,
560 	                         &Shape_info::ammo > > ammo(info);
561 	ammo.read(AMMO, false, game);
562 	ammo.read(PATCH_AMMO, true, game);
563 
564 	Functor_multidata_reader < Shape_info,
565 	                         Class_reader_functor < Monster_info, Shape_info,
566 	                         &Shape_info::monstinf > > monstinf(info);
567 	monstinf.read(MONSTERS, false, game);
568 	monstinf.read(PATCH_MONSTERS, true, game);
569 
570 	Functor_multidata_reader < Shape_info, Gump_reader_functor,
571 	                         Patch_flags_functor<gump_shape_flag, Shape_info> > gump(info, true);
572 	if (game == BLACK_GATE || game == SERPENT_ISLE)
573 		gump.read(game, game == BLACK_GATE ?
574 		          EXULT_BG_FLX_CONTAINER_DAT : EXULT_SI_FLX_CONTAINER_DAT);
575 	else
576 		gump.read(CONTAINER, false, game);
577 	gump.read(PATCH_CONTAINER, true, game);
578 
579 	Functor_multidata_reader < Shape_info,
580 	                         Binary_reader_functor < unsigned char, Shape_info,
581 	                         &Shape_info::ready_type, 6 > ,
582 	                         Ready_type_functor > ready(info);
583 	ready.read(READY, false, game);
584 	ready.read(PATCH_READY, true, game);
585 
586 	Read_Shapeinf_text_data_file(editing, game);
587 	Read_Bodies_text_data_file(editing, game);
588 	Read_Paperdoll_text_data_file(editing, game);
589 
590 	// Ensure valid ready spots for all shapes.
591 	unsigned char defready = game == BLACK_GATE ? backpack : rhand;
592 	zinfo.ready_type = defready;
593 	for (auto& it : info) {
594 		Shape_info &inf = it.second;
595 		if (inf.ready_type == invalid_spot)
596 			inf.ready_type = defready;
597 	}
598 	bool auto_modified = false;
599 	for (auto &it : info) {
600 		int shnum = it.first;
601 		Shape_info &inf = it.second;
602 		if (inf.has_monster_info()) {
603 			Monster_info *minf = inf.monstinf;
604 			if (minf->can_teleport()) {
605 				std::cerr << "Shape " << shnum << " is a monster that can teleport, teleport flag moved from Monster info ( monster.dat ) to Actor info ( shape_info.txt ) as NPC flags." << std::endl;
606 				inf.set_actor_flag(Shape_info::teleports);
607 				minf->set_can_teleport(false);
608 				auto_modified = true;
609 			}
610 			if (minf->can_summon()) {
611 				std::cerr << "Shape " << shnum << " is a monster that can summon, summon flag moved from Monster info ( monster.dat ) to Actor info ( shape_info.txt ) as NPC flags." << std::endl;
612 				inf.set_actor_flag(Shape_info::summons);
613 				minf->set_can_summon(false);
614 				auto_modified = true;
615 			}
616 			if (minf->can_be_invisible()) {
617 				std::cerr << "Shape " << shnum << " is a monster that can be invisible, invisible flag moved from Monster info ( monster.dat ) to Actor info ( shape_info.txt ) as NPC flags." << std::endl;
618 				inf.set_actor_flag(Shape_info::turns_invisible);
619 				minf->set_can_be_invisible(false);
620 				auto_modified = true;
621 			}
622 		}
623 	}
624 	return auto_modified;
625 }
626 
627 /*
628  *  Open/close file.
629  */
630 
Shapes_vga_file(const char * nm,int u7drag,const char * nm2)631 Shapes_vga_file::Shapes_vga_file(
632     const char *nm,         // Path to file.
633     int u7drag,         // # from u7drag.h, or -1.
634     const char *nm2         // Path to patch version, or 0.
635 ) : Vga_file(nm, u7drag, nm2) {
636 }
637 
init()638 void Shapes_vga_file::init() {
639 	if (is_system_path_defined("<PATCH>") && U7exists(PATCH_SHAPES))
640 		load(SHAPES_VGA, PATCH_SHAPES);
641 	else
642 		load(SHAPES_VGA);
643 	info_read = false;
644 }
645 
646 /*
647  *  Make a spot for a new shape, and delete frames in existing shape.
648  *
649  *  Output: ->shape, or 0 if invalid shapenum.
650  */
651 
new_shape(int shapenum)652 Shape *Shapes_vga_file::new_shape(
653     int shapenum
654 ) {
655 	Shape *newshape = Vga_file::new_shape(shapenum);
656 	return newshape;
657 }
658