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