1 /**
2 ** Shapeinf.cc: Info. about shapes read from various 'static' data files.
3 **
4 ** Written: 4/29/99 - JSF
5 **/
6
7 /*
8 Copyright (C) 1998 Jeffrey S. Freedman
9 Copyright (C) 1999-2013 The Exult Team
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 as published by the Free Software Foundation; either version 2
14 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include "shapeinf.h"
31 #include "ammoinf.h"
32 #include "aniinf.h"
33 #include "armorinf.h"
34 #include "bodyinf.h"
35 #include "continf.h"
36 #include "effhpinf.h"
37 #include "expinf.h"
38 #include "frnameinf.h"
39 #include "frflags.h"
40 #include "frusefun.h"
41 #include "lightinf.h"
42 #include "monstinf.h"
43 #include "npcdollinf.h"
44 #include "objdollinf.h"
45 #include "sfxinf.h"
46 #include "warminf.h"
47 #include "weaponinf.h"
48 #include "ready.h"
49 #include "data_utils.h"
50 #include "ignore_unused_variable_warning.h"
51
52 #include "utils.h"
53 #include <vector>
54 #include <map>
55 #include <string>
56
57 using std::vector;
58 using std::cerr;
59 using std::endl;
60
61 Shape_info::Shape_info() = default;
62
63 /*
64 * Not supported:
65 */
Shape_info(const Shape_info & other)66 Shape_info::Shape_info(const Shape_info &other) {
67 copy(other);
68 }
operator =(const Shape_info & other)69 Shape_info &Shape_info::operator = (const Shape_info &other) {
70 if (this != &other) copy(other);
71 return *this;
72 }
73 /*
74 * Clean up.
75 */
76
~Shape_info()77 Shape_info::~Shape_info() {
78 delete weapon;
79 delete ammo;
80 delete armor;
81 delete [] weapon_offsets;
82 delete monstinf;
83 delete npcpaperdoll;
84 delete sfxinf;
85 delete aniinf;
86 delete explosion;
87 delete body;
88 clear_paperdoll_info();
89 clear_effective_hp_info();
90 clear_frame_name_info();
91 clear_light_info();
92 clear_warmth_info();
93 }
94
95 /*
96 * Copy.
97 */
98
copy(const Shape_info & inf2,bool skip_dolls)99 void Shape_info::copy(
100 const Shape_info &inf2,
101 bool skip_dolls
102 ) {
103 for (int i = 0; i < 3; ++i) {
104 tfa[i] = inf2.tfa[i];
105 dims[i] = inf2.dims[i];
106 }
107 weight = inf2.weight;
108 volume = inf2.volume;
109 shpdims[0] = inf2.shpdims[0];
110 shpdims[1] = inf2.shpdims[1];
111 ready_type = inf2.ready_type;
112 alt_ready1 = inf2.alt_ready1;
113 alt_ready2 = inf2.alt_ready2;
114 spell_flag = inf2.spell_flag;
115 occludes_flag = inf2.occludes_flag;
116 if (!skip_dolls || gump_shape < 0) {
117 gump_shape = inf2.gump_shape;
118 gump_font = inf2.gump_font;
119 }
120 monster_food = inf2.monster_food;
121 mountain_top = inf2.mountain_top;
122 barge_type = inf2.barge_type;
123 actor_flags = inf2.actor_flags;
124 shape_flags = inf2.shape_flags;
125 field_type = inf2.field_type;
126 modified_flags = inf2.modified_flags;
127 frompatch_flags = inf2.frompatch_flags;
128 have_static_flags = inf2.have_static_flags;
129 // Allocated fields.
130 delete [] weapon_offsets;
131 if (inf2.weapon_offsets) {
132 weapon_offsets = new unsigned char[64];
133 memcpy(weapon_offsets, inf2.weapon_offsets, 64);
134 } else
135 weapon_offsets = nullptr;
136 delete armor;
137 armor = inf2.armor ? new Armor_info(*inf2.armor) : nullptr;
138 delete ammo;
139 ammo = inf2.ammo ? new Ammo_info(*inf2.ammo) : nullptr;
140 delete weapon;
141 weapon = inf2.weapon ? new Weapon_info(*inf2.weapon) : nullptr;
142 delete monstinf;
143 monstinf = inf2.monstinf ? new Monster_info(*inf2.monstinf) : nullptr;
144 if (!skip_dolls || !npcpaperdoll) {
145 delete npcpaperdoll;
146 npcpaperdoll = inf2.npcpaperdoll ?
147 new Paperdoll_npc(*inf2.npcpaperdoll) : nullptr;
148 }
149 if (!skip_dolls || objpaperdoll.empty())
150 copy_vector_info(inf2.objpaperdoll, objpaperdoll);
151 copy_vector_info(inf2.hpinf, hpinf);
152 copy_vector_info(inf2.frflagsinf, frflagsinf);
153 copy_vector_info(inf2.cntrules, cntrules);
154 copy_vector_info(inf2.nameinf, nameinf);
155 copy_vector_info(inf2.frucinf, frucinf);
156 copy_vector_info(inf2.lightinf, lightinf);
157 copy_vector_info(inf2.warminf, warminf);
158
159 delete sfxinf;
160 sfxinf = inf2.sfxinf ? new SFX_info(*inf2.sfxinf) : nullptr;
161 delete explosion;
162 explosion = inf2.explosion ? new Explosion_info(*inf2.explosion) : nullptr;
163 delete aniinf;
164 aniinf = inf2.aniinf ? new Animation_info(*inf2.aniinf) : nullptr;
165 delete body;
166 body = inf2.body ? new Body_info(*inf2.body) : nullptr;
167 }
168
169 /*
170 * Get (safely) a specified information set.
171 */
172 // Get armor protection.
get_armor() const173 int Shape_info::get_armor() const {
174 return armor ? armor->prot : 0;
175 }
176
177 // Get armor-granted immunities.
get_armor_immunity() const178 int Shape_info::get_armor_immunity() const {
179 return armor ? armor->immune : 0;
180 }
181
182 // Get sprite of explosion.
get_explosion_sprite() const183 int Shape_info::get_explosion_sprite() const {
184 return explosion ? explosion->sprite : 5;
185 }
186
187 // Get sfx of explosion.
get_explosion_sfx() const188 int Shape_info::get_explosion_sfx() const {
189 return explosion ? explosion->sfxnum : -1;
190 }
191
get_body_shape() const192 int Shape_info::get_body_shape() const {
193 return body ? body->bshape : 400;
194 }
195
get_body_frame() const196 int Shape_info::get_body_frame() const {
197 return body ? body->bframe : 3;
198 }
199
get_weapon_info_safe() const200 const Weapon_info *Shape_info::get_weapon_info_safe() const {
201 return weapon ? weapon : Weapon_info::get_default();
202 }
203
get_ammo_info_safe() const204 const Ammo_info *Shape_info::get_ammo_info_safe() const {
205 return ammo ? ammo : Ammo_info::get_default();
206 }
207
get_monster_info_safe() const208 const Monster_info *Shape_info::get_monster_info_safe() const {
209 return monstinf ? monstinf : Monster_info::get_default();
210 }
211
get_animation_info_safe(int shnum,int nframes)212 const Animation_info *Shape_info::get_animation_info_safe(
213 int shnum,
214 int nframes
215 ) {
216 ignore_unused_variable_warning(shnum);
217 if (!aniinf)
218 aniinf = Animation_info::create_from_tfa(0, nframes);
219 return aniinf;
220 }
221
has_paperdoll_info() const222 bool Shape_info::has_paperdoll_info() const {
223 return !objpaperdoll.empty();
224 }
225
set_paperdoll_info(bool tf)226 std::vector<Paperdoll_item> &Shape_info::set_paperdoll_info(bool tf) {
227 return set_vector_info(tf, objpaperdoll);
228 }
229
clean_invalid_paperdolls()230 void Shape_info::clean_invalid_paperdolls() {
231 clean_vector(objpaperdoll);
232 }
233
clear_paperdoll_info()234 void Shape_info::clear_paperdoll_info() {
235 objpaperdoll.clear();
236 }
237
add_paperdoll_info(Paperdoll_item & add)238 void Shape_info::add_paperdoll_info(Paperdoll_item &add) {
239 add_vector_info(add, objpaperdoll);
240 }
241
has_content_rules() const242 bool Shape_info::has_content_rules() const {
243 return !cntrules.empty();
244 }
245
set_content_rules(bool tf)246 std::vector<Content_rules> &Shape_info::set_content_rules(bool tf) {
247 return set_vector_info(tf, cntrules);
248 }
249
clean_invalid_content_rules()250 void Shape_info::clean_invalid_content_rules() {
251 clean_vector(cntrules);
252 }
253
clear_content_rules()254 void Shape_info::clear_content_rules() {
255 cntrules.clear();
256 }
257
add_content_rule(Content_rules & add)258 void Shape_info::add_content_rule(Content_rules &add) {
259 add_vector_info(add, cntrules);
260 }
261
has_effective_hp_info() const262 bool Shape_info::has_effective_hp_info() const {
263 return !hpinf.empty();
264 }
265
set_effective_hp_info(bool tf)266 std::vector<Effective_hp_info> &Shape_info::set_effective_hp_info(bool tf) {
267 return set_vector_info(tf, hpinf);
268 }
269
clean_invalid_hp_info()270 void Shape_info::clean_invalid_hp_info() {
271 clean_vector(hpinf);
272 }
273
clear_effective_hp_info()274 void Shape_info::clear_effective_hp_info() {
275 hpinf.clear();
276 }
277
add_effective_hp_info(Effective_hp_info & add)278 void Shape_info::add_effective_hp_info(Effective_hp_info &add) {
279 add_vector_info(add, hpinf);
280 }
281
has_frame_name_info() const282 bool Shape_info::has_frame_name_info() const {
283 return !nameinf.empty();
284 }
285
set_frame_name_info(bool tf)286 std::vector<Frame_name_info> &Shape_info::set_frame_name_info(bool tf) {
287 return set_vector_info(tf, nameinf);
288 }
289
clean_invalid_name_info()290 void Shape_info::clean_invalid_name_info() {
291 clean_vector(nameinf);
292 }
293
clear_frame_name_info()294 void Shape_info::clear_frame_name_info() {
295 nameinf.clear();
296 }
297
add_frame_name_info(Frame_name_info & add)298 void Shape_info::add_frame_name_info(Frame_name_info &add) {
299 add_vector_info(add, nameinf);
300 }
301
has_frame_usecode_info() const302 bool Shape_info::has_frame_usecode_info() const {
303 return !frucinf.empty();
304 }
305
set_frame_usecode_info(bool tf)306 std::vector<Frame_usecode_info> &Shape_info::set_frame_usecode_info(bool tf) {
307 return set_vector_info(tf, frucinf);
308 }
309
clean_invalid_usecode_info()310 void Shape_info::clean_invalid_usecode_info() {
311 clean_vector(frucinf);
312 }
313
clear_frame_usecode_info()314 void Shape_info::clear_frame_usecode_info() {
315 frucinf.clear();
316 }
317
add_frame_usecode_info(Frame_usecode_info & add)318 void Shape_info::add_frame_usecode_info(Frame_usecode_info &add) {
319 add_vector_info(add, frucinf);
320 }
321
has_frame_flags() const322 bool Shape_info::has_frame_flags() const {
323 return !frflagsinf.empty();
324 }
325
set_frame_flags(bool tf)326 std::vector<Frame_flags_info> &Shape_info::set_frame_flags(bool tf) {
327 return set_vector_info(tf, frflagsinf);
328 }
329
clean_invalid_frame_flags()330 void Shape_info::clean_invalid_frame_flags() {
331 clean_vector(frflagsinf);
332 }
333
clear_frame_flags()334 void Shape_info::clear_frame_flags() {
335 frflagsinf.clear();
336 }
337
add_frame_flags(Frame_flags_info & add)338 void Shape_info::add_frame_flags(Frame_flags_info &add) {
339 add_vector_info(add, frflagsinf);
340 }
341
has_light_info() const342 bool Shape_info::has_light_info() const {
343 return !lightinf.empty();
344 }
345
set_light_info(bool tf)346 std::vector<Light_info> &Shape_info::set_light_info(bool tf) {
347 return set_vector_info(tf, lightinf);
348 }
349
clean_invalid_light_info()350 void Shape_info::clean_invalid_light_info() {
351 clean_vector(lightinf);
352 }
353
clear_light_info()354 void Shape_info::clear_light_info() {
355 lightinf.clear();
356 }
357
add_light_info(Light_info & add)358 void Shape_info::add_light_info(Light_info &add) {
359 add_vector_info(add, lightinf);
360 }
361
has_warmth_info() const362 bool Shape_info::has_warmth_info() const {
363 return !warminf.empty();
364 }
365
set_warmth_info(bool tf)366 std::vector<Warmth_info> &Shape_info::set_warmth_info(bool tf) {
367 return set_vector_info(tf, warminf);
368 }
369
clean_invalid_warmth_info()370 void Shape_info::clean_invalid_warmth_info() {
371 clean_vector(warminf);
372 }
373
clear_warmth_info()374 void Shape_info::clear_warmth_info() {
375 warminf.clear();
376 }
377
add_warmth_info(Warmth_info & add)378 void Shape_info::add_warmth_info(Warmth_info &add) {
379 add_vector_info(add, warminf);
380 }
381
get_frame_name(int frame,int quality) const382 const Frame_name_info *Shape_info::get_frame_name(int frame, int quality) const {
383 return Search_vector_data_double_wildcards(nameinf,
384 frame, quality,
385 &Frame_name_info::frame, &Frame_name_info::quality);
386 }
387
get_frame_usecode(int frame,int quality) const388 const Frame_usecode_info *Shape_info::get_frame_usecode(int frame, int quality) const {
389 return Search_vector_data_double_wildcards(frucinf,
390 frame, quality,
391 &Frame_usecode_info::frame, &Frame_usecode_info::quality);
392 }
393
get_effective_hps(int frame,int quality) const394 int Shape_info::get_effective_hps(int frame, int quality) const {
395 const Effective_hp_info *inf = Search_vector_data_double_wildcards(hpinf,
396 frame, quality,
397 &Effective_hp_info::frame, &Effective_hp_info::quality);
398 return inf ? inf->hps : 0; // Default to indestructible.
399 }
400
get_object_flags(int frame,int qual) const401 int Shape_info::get_object_flags(int frame, int qual) const {
402 const Frame_flags_info *inf = Search_vector_data_double_wildcards(frflagsinf,
403 frame, qual,
404 &Frame_flags_info::frame, &Frame_flags_info::quality);
405 return inf ? inf->m_flags : 0; // Default to no flagss.
406 }
407
get_item_paperdoll(int frame,int spot) const408 const Paperdoll_item *Shape_info::get_item_paperdoll(int frame, int spot) const {
409 if (objpaperdoll.empty())
410 return nullptr; // No paperdoll.
411 Paperdoll_item inf;
412 inf.world_frame = frame;
413 if (spot == both_hands)
414 spot = lhand;
415 else if (spot == lrgloves)
416 spot = lfinger;
417 else if (spot == neck)
418 spot = amulet;
419 else if (spot == scabbard)
420 spot = belt;
421 inf.spot = spot;
422 // Try finding exact match first.
423 auto it = std::lower_bound(objpaperdoll.begin(), objpaperdoll.end(), inf);
424 if (it == objpaperdoll.end()) // Nowhere to be found.
425 return nullptr;
426 else if (*it == inf && !it->is_invalid()) // Have it already.
427 return &*it;
428 // Time for wildcard world frame.
429 inf.world_frame = -1;
430 it = std::lower_bound(it, objpaperdoll.end(), inf);
431 if (it == objpaperdoll.end() || *it != inf // It just isn't there...
432 || it->is_invalid()) // ... or it is invalid.
433 return nullptr;
434 else // At last!
435 return &*it;
436 }
437
is_shape_accepted(int shape) const438 bool Shape_info::is_shape_accepted(int shape) const {
439 const Content_rules *inf = Search_vector_data_single_wildcard(cntrules,
440 shape, &Content_rules::shape);
441 #ifdef DEBUG
442 if (inf && !inf->accept)
443 cerr << "Shape '" << shape << "' was REJECTED" << endl;
444 #endif
445 return inf ? inf->accept : true; // Default to true.
446 }
447
get_object_light(int frame) const448 int Shape_info::get_object_light(int frame) const {
449 if (!is_light_source()) {
450 // Don't bother checking if not a light source.
451 return 0;
452 }
453 const Light_info *inf = Search_vector_data_single_wildcard(lightinf,
454 (frame & 31), &Light_info::frame);
455 return inf ? inf->light : 1; // Default to candle-strength.
456 }
457
get_object_warmth(int frame) const458 int Shape_info::get_object_warmth(int frame) const {
459 const Warmth_info *inf = Search_vector_data_single_wildcard(warminf,
460 (frame & 31), &Warmth_info::frame);
461 return inf ? inf->warmth : 0; // Default to no warmth.
462 }
463
464 /*
465 * Set 3D dimensions.
466 */
467
set_3d(int xt,int yt,int zt)468 void Shape_info::set_3d(
469 int xt, int yt, int zt // In tiles.
470 ) {
471 xt = (xt - 1) & 7; // Force legal values.
472 yt = (yt - 1) & 7;
473 zt &= 7;
474 tfa[2] = (tfa[2]&~63) | xt | (yt << 3);
475 tfa[0] = (tfa[0]&~(7 << 5)) | (zt << 5);
476 dims[0] = xt + 1;
477 dims[1] = yt + 1;
478 dims[2] = zt;
479 }
480
481 /*
482 * Set weapon offsets for given frame.
483 */
484
set_weapon_offset(int frame,unsigned char x,unsigned char y)485 void Shape_info::set_weapon_offset(
486 int frame, // 0-31.
487 unsigned char x, unsigned char y// 255 means "dont' draw".
488 ) {
489 if (frame < 0 || frame > 31)
490 return;
491 if (x == 255 && y == 255) {
492 if (weapon_offsets) // +++Could delete if all 255's now.
493 weapon_offsets[frame * 2] =
494 weapon_offsets[frame * 2 + 1] = 255;
495 return;
496 }
497 if (!weapon_offsets) {
498 weapon_offsets = new unsigned char[64];
499 std::memset(weapon_offsets, 255, 64);
500 }
501 weapon_offsets[frame * 2] = x;
502 weapon_offsets[frame * 2 + 1] = y;
503 }
504
505 /*
506 * Get rotated frame (algorithmically).
507 */
508
get_rotated_frame(int curframe,int quads) const509 int Shape_info::get_rotated_frame(
510 int curframe,
511 int quads // 1=90, 2=180, 3=270.
512 ) const {
513 // Seat is a special case.
514 if (barge_type == barge_seat) {
515 int dir = curframe % 4; // Current dir (0-3).
516 return (curframe - dir) + (dir + quads) % 4;
517 } else if (is_barge_part()) // Piece of a barge?
518 switch (quads) {
519 case 1:
520 return (curframe ^ 32) ^ ((curframe & 32) ? 3 : 1);
521 case 2:
522 return curframe ^ 2;
523 case 3:
524 return (curframe ^ 32) ^ ((curframe & 32) ? 1 : 3);
525 default:
526 return curframe;
527 }
528 else
529 // Reflect. Bit 32==horizontal.
530 return curframe ^ ((quads % 2) << 5);
531 }
532