/** ** Shapeinf.cc: Info. about shapes read from various 'static' data files. ** ** Written: 4/29/99 - JSF **/ /* Copyright (C) 1998 Jeffrey S. Freedman Copyright (C) 1999-2013 The Exult Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H # include #endif #include "shapeinf.h" #include "ammoinf.h" #include "aniinf.h" #include "armorinf.h" #include "bodyinf.h" #include "continf.h" #include "effhpinf.h" #include "expinf.h" #include "frnameinf.h" #include "frflags.h" #include "frusefun.h" #include "lightinf.h" #include "monstinf.h" #include "npcdollinf.h" #include "objdollinf.h" #include "sfxinf.h" #include "warminf.h" #include "weaponinf.h" #include "ready.h" #include "data_utils.h" #include "ignore_unused_variable_warning.h" #include "utils.h" #include #include #include using std::vector; using std::cerr; using std::endl; Shape_info::Shape_info() = default; /* * Not supported: */ Shape_info::Shape_info(const Shape_info &other) { copy(other); } Shape_info &Shape_info::operator = (const Shape_info &other) { if (this != &other) copy(other); return *this; } /* * Clean up. */ Shape_info::~Shape_info() { delete weapon; delete ammo; delete armor; delete [] weapon_offsets; delete monstinf; delete npcpaperdoll; delete sfxinf; delete aniinf; delete explosion; delete body; clear_paperdoll_info(); clear_effective_hp_info(); clear_frame_name_info(); clear_light_info(); clear_warmth_info(); } /* * Copy. */ void Shape_info::copy( const Shape_info &inf2, bool skip_dolls ) { for (int i = 0; i < 3; ++i) { tfa[i] = inf2.tfa[i]; dims[i] = inf2.dims[i]; } weight = inf2.weight; volume = inf2.volume; shpdims[0] = inf2.shpdims[0]; shpdims[1] = inf2.shpdims[1]; ready_type = inf2.ready_type; alt_ready1 = inf2.alt_ready1; alt_ready2 = inf2.alt_ready2; spell_flag = inf2.spell_flag; occludes_flag = inf2.occludes_flag; if (!skip_dolls || gump_shape < 0) { gump_shape = inf2.gump_shape; gump_font = inf2.gump_font; } monster_food = inf2.monster_food; mountain_top = inf2.mountain_top; barge_type = inf2.barge_type; actor_flags = inf2.actor_flags; shape_flags = inf2.shape_flags; field_type = inf2.field_type; modified_flags = inf2.modified_flags; frompatch_flags = inf2.frompatch_flags; have_static_flags = inf2.have_static_flags; // Allocated fields. delete [] weapon_offsets; if (inf2.weapon_offsets) { weapon_offsets = new unsigned char[64]; memcpy(weapon_offsets, inf2.weapon_offsets, 64); } else weapon_offsets = nullptr; delete armor; armor = inf2.armor ? new Armor_info(*inf2.armor) : nullptr; delete ammo; ammo = inf2.ammo ? new Ammo_info(*inf2.ammo) : nullptr; delete weapon; weapon = inf2.weapon ? new Weapon_info(*inf2.weapon) : nullptr; delete monstinf; monstinf = inf2.monstinf ? new Monster_info(*inf2.monstinf) : nullptr; if (!skip_dolls || !npcpaperdoll) { delete npcpaperdoll; npcpaperdoll = inf2.npcpaperdoll ? new Paperdoll_npc(*inf2.npcpaperdoll) : nullptr; } if (!skip_dolls || objpaperdoll.empty()) copy_vector_info(inf2.objpaperdoll, objpaperdoll); copy_vector_info(inf2.hpinf, hpinf); copy_vector_info(inf2.frflagsinf, frflagsinf); copy_vector_info(inf2.cntrules, cntrules); copy_vector_info(inf2.nameinf, nameinf); copy_vector_info(inf2.frucinf, frucinf); copy_vector_info(inf2.lightinf, lightinf); copy_vector_info(inf2.warminf, warminf); delete sfxinf; sfxinf = inf2.sfxinf ? new SFX_info(*inf2.sfxinf) : nullptr; delete explosion; explosion = inf2.explosion ? new Explosion_info(*inf2.explosion) : nullptr; delete aniinf; aniinf = inf2.aniinf ? new Animation_info(*inf2.aniinf) : nullptr; delete body; body = inf2.body ? new Body_info(*inf2.body) : nullptr; } /* * Get (safely) a specified information set. */ // Get armor protection. int Shape_info::get_armor() const { return armor ? armor->prot : 0; } // Get armor-granted immunities. int Shape_info::get_armor_immunity() const { return armor ? armor->immune : 0; } // Get sprite of explosion. int Shape_info::get_explosion_sprite() const { return explosion ? explosion->sprite : 5; } // Get sfx of explosion. int Shape_info::get_explosion_sfx() const { return explosion ? explosion->sfxnum : -1; } int Shape_info::get_body_shape() const { return body ? body->bshape : 400; } int Shape_info::get_body_frame() const { return body ? body->bframe : 3; } const Weapon_info *Shape_info::get_weapon_info_safe() const { return weapon ? weapon : Weapon_info::get_default(); } const Ammo_info *Shape_info::get_ammo_info_safe() const { return ammo ? ammo : Ammo_info::get_default(); } const Monster_info *Shape_info::get_monster_info_safe() const { return monstinf ? monstinf : Monster_info::get_default(); } const Animation_info *Shape_info::get_animation_info_safe( int shnum, int nframes ) { ignore_unused_variable_warning(shnum); if (!aniinf) aniinf = Animation_info::create_from_tfa(0, nframes); return aniinf; } bool Shape_info::has_paperdoll_info() const { return !objpaperdoll.empty(); } std::vector &Shape_info::set_paperdoll_info(bool tf) { return set_vector_info(tf, objpaperdoll); } void Shape_info::clean_invalid_paperdolls() { clean_vector(objpaperdoll); } void Shape_info::clear_paperdoll_info() { objpaperdoll.clear(); } void Shape_info::add_paperdoll_info(Paperdoll_item &add) { add_vector_info(add, objpaperdoll); } bool Shape_info::has_content_rules() const { return !cntrules.empty(); } std::vector &Shape_info::set_content_rules(bool tf) { return set_vector_info(tf, cntrules); } void Shape_info::clean_invalid_content_rules() { clean_vector(cntrules); } void Shape_info::clear_content_rules() { cntrules.clear(); } void Shape_info::add_content_rule(Content_rules &add) { add_vector_info(add, cntrules); } bool Shape_info::has_effective_hp_info() const { return !hpinf.empty(); } std::vector &Shape_info::set_effective_hp_info(bool tf) { return set_vector_info(tf, hpinf); } void Shape_info::clean_invalid_hp_info() { clean_vector(hpinf); } void Shape_info::clear_effective_hp_info() { hpinf.clear(); } void Shape_info::add_effective_hp_info(Effective_hp_info &add) { add_vector_info(add, hpinf); } bool Shape_info::has_frame_name_info() const { return !nameinf.empty(); } std::vector &Shape_info::set_frame_name_info(bool tf) { return set_vector_info(tf, nameinf); } void Shape_info::clean_invalid_name_info() { clean_vector(nameinf); } void Shape_info::clear_frame_name_info() { nameinf.clear(); } void Shape_info::add_frame_name_info(Frame_name_info &add) { add_vector_info(add, nameinf); } bool Shape_info::has_frame_usecode_info() const { return !frucinf.empty(); } std::vector &Shape_info::set_frame_usecode_info(bool tf) { return set_vector_info(tf, frucinf); } void Shape_info::clean_invalid_usecode_info() { clean_vector(frucinf); } void Shape_info::clear_frame_usecode_info() { frucinf.clear(); } void Shape_info::add_frame_usecode_info(Frame_usecode_info &add) { add_vector_info(add, frucinf); } bool Shape_info::has_frame_flags() const { return !frflagsinf.empty(); } std::vector &Shape_info::set_frame_flags(bool tf) { return set_vector_info(tf, frflagsinf); } void Shape_info::clean_invalid_frame_flags() { clean_vector(frflagsinf); } void Shape_info::clear_frame_flags() { frflagsinf.clear(); } void Shape_info::add_frame_flags(Frame_flags_info &add) { add_vector_info(add, frflagsinf); } bool Shape_info::has_light_info() const { return !lightinf.empty(); } std::vector &Shape_info::set_light_info(bool tf) { return set_vector_info(tf, lightinf); } void Shape_info::clean_invalid_light_info() { clean_vector(lightinf); } void Shape_info::clear_light_info() { lightinf.clear(); } void Shape_info::add_light_info(Light_info &add) { add_vector_info(add, lightinf); } bool Shape_info::has_warmth_info() const { return !warminf.empty(); } std::vector &Shape_info::set_warmth_info(bool tf) { return set_vector_info(tf, warminf); } void Shape_info::clean_invalid_warmth_info() { clean_vector(warminf); } void Shape_info::clear_warmth_info() { warminf.clear(); } void Shape_info::add_warmth_info(Warmth_info &add) { add_vector_info(add, warminf); } const Frame_name_info *Shape_info::get_frame_name(int frame, int quality) const { return Search_vector_data_double_wildcards(nameinf, frame, quality, &Frame_name_info::frame, &Frame_name_info::quality); } const Frame_usecode_info *Shape_info::get_frame_usecode(int frame, int quality) const { return Search_vector_data_double_wildcards(frucinf, frame, quality, &Frame_usecode_info::frame, &Frame_usecode_info::quality); } int Shape_info::get_effective_hps(int frame, int quality) const { const Effective_hp_info *inf = Search_vector_data_double_wildcards(hpinf, frame, quality, &Effective_hp_info::frame, &Effective_hp_info::quality); return inf ? inf->hps : 0; // Default to indestructible. } int Shape_info::get_object_flags(int frame, int qual) const { const Frame_flags_info *inf = Search_vector_data_double_wildcards(frflagsinf, frame, qual, &Frame_flags_info::frame, &Frame_flags_info::quality); return inf ? inf->m_flags : 0; // Default to no flagss. } const Paperdoll_item *Shape_info::get_item_paperdoll(int frame, int spot) const { if (objpaperdoll.empty()) return nullptr; // No paperdoll. Paperdoll_item inf; inf.world_frame = frame; if (spot == both_hands) spot = lhand; else if (spot == lrgloves) spot = lfinger; else if (spot == neck) spot = amulet; else if (spot == scabbard) spot = belt; inf.spot = spot; // Try finding exact match first. auto it = std::lower_bound(objpaperdoll.begin(), objpaperdoll.end(), inf); if (it == objpaperdoll.end()) // Nowhere to be found. return nullptr; else if (*it == inf && !it->is_invalid()) // Have it already. return &*it; // Time for wildcard world frame. inf.world_frame = -1; it = std::lower_bound(it, objpaperdoll.end(), inf); if (it == objpaperdoll.end() || *it != inf // It just isn't there... || it->is_invalid()) // ... or it is invalid. return nullptr; else // At last! return &*it; } bool Shape_info::is_shape_accepted(int shape) const { const Content_rules *inf = Search_vector_data_single_wildcard(cntrules, shape, &Content_rules::shape); #ifdef DEBUG if (inf && !inf->accept) cerr << "Shape '" << shape << "' was REJECTED" << endl; #endif return inf ? inf->accept : true; // Default to true. } int Shape_info::get_object_light(int frame) const { if (!is_light_source()) { // Don't bother checking if not a light source. return 0; } const Light_info *inf = Search_vector_data_single_wildcard(lightinf, (frame & 31), &Light_info::frame); return inf ? inf->light : 1; // Default to candle-strength. } int Shape_info::get_object_warmth(int frame) const { const Warmth_info *inf = Search_vector_data_single_wildcard(warminf, (frame & 31), &Warmth_info::frame); return inf ? inf->warmth : 0; // Default to no warmth. } /* * Set 3D dimensions. */ void Shape_info::set_3d( int xt, int yt, int zt // In tiles. ) { xt = (xt - 1) & 7; // Force legal values. yt = (yt - 1) & 7; zt &= 7; tfa[2] = (tfa[2]&~63) | xt | (yt << 3); tfa[0] = (tfa[0]&~(7 << 5)) | (zt << 5); dims[0] = xt + 1; dims[1] = yt + 1; dims[2] = zt; } /* * Set weapon offsets for given frame. */ void Shape_info::set_weapon_offset( int frame, // 0-31. unsigned char x, unsigned char y// 255 means "dont' draw". ) { if (frame < 0 || frame > 31) return; if (x == 255 && y == 255) { if (weapon_offsets) // +++Could delete if all 255's now. weapon_offsets[frame * 2] = weapon_offsets[frame * 2 + 1] = 255; return; } if (!weapon_offsets) { weapon_offsets = new unsigned char[64]; std::memset(weapon_offsets, 255, 64); } weapon_offsets[frame * 2] = x; weapon_offsets[frame * 2 + 1] = y; } /* * Get rotated frame (algorithmically). */ int Shape_info::get_rotated_frame( int curframe, int quads // 1=90, 2=180, 3=270. ) const { // Seat is a special case. if (barge_type == barge_seat) { int dir = curframe % 4; // Current dir (0-3). return (curframe - dir) + (dir + quads) % 4; } else if (is_barge_part()) // Piece of a barge? switch (quads) { case 1: return (curframe ^ 32) ^ ((curframe & 32) ? 3 : 1); case 2: return curframe ^ 2; case 3: return (curframe ^ 32) ^ ((curframe & 32) ? 1 : 3); default: return curframe; } else // Reflect. Bit 32==horizontal. return curframe ^ ((quads % 2) << 5); }