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