From 2fc277fdb6115c2cbf4afed0c720a6e449ca8506 Mon Sep 17 00:00:00 2001 From: Seizerkiller Date: Thu, 28 May 2009 19:35:52 +0400 Subject: [PATCH 1/7] [7904] Change creature damage calculation formula. * Add new creature_template field `dmg_multiplier` * Make attackpower include in creature damage not dependent from attack speed. NOTE: included in sql update recalculation for creature damage related fields only make temporary possible usable values. Real values need revisited by DB devs for correctness. Signed-off-by: VladimirMangos --- sql/mangos.sql | 3 ++- sql/updates/7904_01_mangos_creature_template.sql | 9 +++++++++ sql/updates/Makefile.am | 2 ++ src/game/Creature.h | 1 + src/game/StatSystem.cpp | 9 ++++----- src/shared/Database/SQLStorage.cpp | 4 ++-- src/shared/revision_nr.h | 2 +- 7 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 sql/updates/7904_01_mangos_creature_template.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index e5b43254d..633bdb683 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_7902_02_mangos_pool_gameobject` bit(1) default NULL + `required_7904_01_mangos_creature_template` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -813,6 +813,7 @@ CREATE TABLE `creature_template` ( `maxdmg` float NOT NULL default '0', `dmgschool` tinyint(4) NOT NULL default '0', `attackpower` int(10) unsigned NOT NULL default '0', + `dmg_multiplier` float NOT NULL default '1', `baseattacktime` int(10) unsigned NOT NULL default '0', `rangeattacktime` int(10) unsigned NOT NULL default '0', `unit_flags` int(10) unsigned NOT NULL default '0', diff --git a/sql/updates/7904_01_mangos_creature_template.sql b/sql/updates/7904_01_mangos_creature_template.sql new file mode 100644 index 000000000..0f984b74e --- /dev/null +++ b/sql/updates/7904_01_mangos_creature_template.sql @@ -0,0 +1,9 @@ +ALTER TABLE db_version CHANGE COLUMN required_7902_02_mangos_pool_gameobject required_7904_01_mangos_creature_template bit; + +ALTER TABLE creature_template + ADD COLUMN dmg_multiplier float NOT NULL default '1' AFTER attackpower; + +UPDATE creature_template SET mindmg = round(mindmg + attackpower / 14); +UPDATE creature_template SET maxdmg = round(maxdmg + attackpower / 14); +UPDATE creature_template SET attackpower = round((maxdmg + mindmg) * 0.3); +UPDATE creature_template SET mindmg = round(mindmg * 0.7), maxdmg = round(maxdmg * 0.7); diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 6e18e6493..62aab9912 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -204,6 +204,7 @@ pkgdata_DATA = \ 7902_01_mangos_pool_creature.sql \ 7902_02_mangos_pool_gameobject.sql \ 7903_01_characters_character_pet.sql \ + 7904_01_mangos_creature_template.sql \ README ## Additional files to include when running 'make dist' @@ -388,4 +389,5 @@ EXTRA_DIST = \ 7902_01_mangos_pool_creature.sql \ 7902_02_mangos_pool_gameobject.sql \ 7903_01_characters_character_pet.sql \ + 7904_01_mangos_creature_template.sql \ README diff --git a/src/game/Creature.h b/src/game/Creature.h index 70b1d771c..0d15dfe01 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -181,6 +181,7 @@ struct CreatureInfo float maxdmg; uint32 dmgschool; uint32 attackpower; + float dmg_multiplier; uint32 baseattacktime; uint32 rangeattacktime; uint32 unit_flags; // enum UnitFlags mask values diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp index 849f90575..8ca0ee1a8 100644 --- a/src/game/StatSystem.cpp +++ b/src/game/StatSystem.cpp @@ -796,18 +796,17 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType) UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; - float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; - - float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; + float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType); float base_pct = GetModifierValue(unitMod, BASE_PCT); float total_value = GetModifierValue(unitMod, TOTAL_VALUE); float total_pct = GetModifierValue(unitMod, TOTAL_PCT); + float dmg_multiplier = GetCreatureInfo()->dmg_multiplier; float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); - float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ; - float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ; + float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct * dmg_multiplier; + float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct * dmg_multiplier; SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 9cb1dbbaf..768abcee5 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -25,8 +25,8 @@ extern DatabasePostgre WorldDatabase; extern DatabaseMysql WorldDatabase; #endif -const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiis"; -const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiii"; +const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiis"; +const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiii"; const char CreatureDataAddonInfofmt[]="iiiiiiis"; const char CreatureModelfmt[]="iffbi"; const char CreatureInfoAddonInfofmt[]="iiiiiiis"; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index de1b34343..de10281b6 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7903" + #define REVISION_NR "7904" #endif // __REVISION_NR_H__ From b83f32fc19fc087c3c3985451ebcb4bb53abd69e Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 29 May 2009 01:00:29 +0400 Subject: [PATCH 2/7] [7905] Implement ACTION_T_SET_SHEATH for creature event ai make possibility set ranged fire state. Also related cleanup code in field cases and player Player::SetSheath. --- src/game/CombatHandler.cpp | 8 +++++++- src/game/Creature.cpp | 2 +- src/game/CreatureEventAI.cpp | 5 +++++ src/game/CreatureEventAI.h | 7 ++++++- src/game/CreatureEventAIMgr.cpp | 7 +++++++ src/game/Pet.cpp | 6 +++--- src/game/Player.cpp | 4 ++-- src/game/Player.h | 2 +- src/game/Unit.h | 5 +++++ src/shared/revision_nr.h | 2 +- 10 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/game/CombatHandler.cpp b/src/game/CombatHandler.cpp index 12fedd89a..ddc6748e2 100644 --- a/src/game/CombatHandler.cpp +++ b/src/game/CombatHandler.cpp @@ -81,7 +81,13 @@ void WorldSession::HandleSetSheathedOpcode( WorldPacket & recv_data ) //sLog.outDebug( "WORLD: Recvd CMSG_SETSHEATHED Message guidlow:%u value1:%u", GetPlayer()->GetGUIDLow(), sheathed ); - GetPlayer()->SetSheath(sheathed); + if(sheathed >= MAX_SHEATH_STATE) + { + sLog.outError("Unknown sheath state %u ??",sheathed); + return; + } + + GetPlayer()->SetSheath(SheathState(sheathed)); } void WorldSession::SendAttackStop(Unit const* enemy) diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 7c6cbdb6c..4ac9c77ad 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -256,7 +256,7 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data ) m_regenHealth = GetCreatureInfo()->RegenHealth; // creatures always have melee weapon ready if any - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); + SetSheath(SHEATH_STATE_MELEE); SelectLevel(GetCreatureInfo()); if (team == HORDE) diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 5a1cf5716..b98ad6a2b 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -783,6 +783,11 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32 cell_lock->Visit(cell_lock, grid_creature_searcher, *m_creature->GetMap()); break; } + case ACTION_T_SET_SHEATH: + { + m_creature->SetSheath(SheathState(action.set_sheath.sheath)); + break; + } } } diff --git a/src/game/CreatureEventAI.h b/src/game/CreatureEventAI.h index 5f967c51d..0fd9b06b2 100644 --- a/src/game/CreatureEventAI.h +++ b/src/game/CreatureEventAI.h @@ -102,7 +102,7 @@ enum EventAI_ActionType ACTION_T_DIE = 37, // No Params ACTION_T_ZONE_COMBAT_PULSE = 38, // No Params ACTION_T_CALL_FOR_HELP = 39, // Radius - + ACTION_T_SET_SHEATH = 40, // Sheath (0-passive,1-melee,2-ranged) ACTION_T_END, }; @@ -364,6 +364,11 @@ struct CreatureEventAI_Action { uint32 radius; } call_for_help; + // ACTION_T_SET_SHEATH = 40 + struct + { + uint32 sheath; + } set_sheath; // RAW struct { diff --git a/src/game/CreatureEventAIMgr.cpp b/src/game/CreatureEventAIMgr.cpp index b3678dad6..5caaa2311 100644 --- a/src/game/CreatureEventAIMgr.cpp +++ b/src/game/CreatureEventAIMgr.cpp @@ -641,6 +641,13 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts() if (!sCreatureStorage.LookupEntry(action.update_template.creatureId)) sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, action.update_template.creatureId); break; + case ACTION_T_SET_SHEATH: + if (action.set_sheath.sheath >= MAX_SHEATH_STATE) + { + sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses wrong sheath state %u.", i, j+1, action.set_sheath.sheath); + action.set_sheath.sheath = SHEATH_STATE_UNARMED; + } + break; case ACTION_T_EVADE: //No Params case ACTION_T_FLEE_FOR_ASSIST: //No Params case ACTION_T_DIE: //No Params diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 60b7c06b4..078c9c843 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -197,7 +197,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool break; case HUNTER_PET: SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); + SetSheath(SHEATH_STATE_MELEE); SetByteValue(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_RENAME_NOT_ALLOWED : UNIT_RENAME_ALLOWED); SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); @@ -783,7 +783,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) if(cinfo->type == CREATURE_TYPE_BEAST) { SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE ); + SetSheath(SHEATH_STATE_MELEE); SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_ALLOWED); SetUInt32Value(UNIT_MOD_CAST_SPEED, creature->GetUInt32Value(UNIT_MOD_CAST_SPEED)); } @@ -1756,7 +1756,7 @@ bool Pet::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint3 if(!InitEntry(Entry)) return false; - SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); + SetSheath(SHEATH_STATE_MELEE); if(getPetType() == MINI_PET) // always non-attackable SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index b5c0ebc8a..93a84ae9d 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -7913,7 +7913,7 @@ void Player::SetVirtualItemSlot( uint8 i, Item* item) } } -void Player::SetSheath( uint32 sheathed ) +void Player::SetSheath( SheathState sheathed ) { switch (sheathed) { @@ -7939,7 +7939,7 @@ void Player::SetSheath( uint32 sheathed ) SetVirtualItemSlot(2,NULL); break; } - SetByteValue(UNIT_FIELD_BYTES_2, 0, sheathed); // this must visualize Sheath changing for other players... + Unit::SetSheath(sheathed); // this must visualize Sheath changing for other players... } uint8 Player::FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const diff --git a/src/game/Player.h b/src/game/Player.h index 5c4dd2dc5..1b29a685b 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -963,7 +963,7 @@ class MANGOS_DLL_SPEC Player : public Unit /*********************************************************/ void SetVirtualItemSlot( uint8 i, Item* item); - void SetSheath( uint32 sheathed ); + void SetSheath( SheathState sheathed ); // overwrite Unit version uint8 FindEquipSlot( ItemPrototype const* proto, uint32 slot, bool swap ) const; uint32 GetItemCount( uint32 item, bool inBankAlso = false, Item* skipItem = NULL ) const; Item* GetItemByGuid( uint64 guid ) const; diff --git a/src/game/Unit.h b/src/game/Unit.h index ccefb8c86..301116756 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -191,6 +191,8 @@ enum SheathState SHEATH_STATE_RANGED = 2 // prepared ranged weapon }; +#define MAX_SHEATH_STATE 3 + // byte (1 from 0..3) of UNIT_FIELD_BYTES_2 enum UnitBytes2_Flags { @@ -918,6 +920,9 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void ApplyAttackTimePercentMod(WeaponAttackType att,float val, bool apply); void ApplyCastTimePercentMod(float val, bool apply); + SheathState GetSheath() const { return SheathState(GetByteValue(UNIT_FIELD_BYTES_2, 0)); } + virtual void SetSheath( SheathState sheathed ) { SetByteValue(UNIT_FIELD_BYTES_2, 0, sheathed); } + // faction template id uint32 getFaction() const { return GetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE); } void setFaction(uint32 faction) { SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, faction ); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index de10281b6..f5a326b91 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7904" + #define REVISION_NR "7905" #endif // __REVISION_NR_H__ From 661ddea7a77625f87d004a9378822efd473f223c Mon Sep 17 00:00:00 2001 From: ApoC Date: Thu, 28 May 2009 23:13:37 +0200 Subject: [PATCH 3/7] [7906] Inserted newline to make gcc happy. Signed-off-by: ApoC --- src/game/Pet.h | 2 +- src/shared/revision_nr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/Pet.h b/src/game/Pet.h index 223675a88..0ddc8fc56 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -250,4 +250,4 @@ class Pet : public Creature assert(false); } }; -#endif \ No newline at end of file +#endif diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f5a326b91..942de26c6 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7905" + #define REVISION_NR "7906" #endif // __REVISION_NR_H__ From 39637858aabaa6a5421e8968308c5ea6285d591c Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 29 May 2009 01:21:52 +0400 Subject: [PATCH 4/7] [7907] Also add documentation for ACTION_T_SET_SHEATH. --- doc/EventAI.txt | 20 ++++++++++++++++++++ src/shared/revision_nr.h | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/doc/EventAI.txt b/doc/EventAI.txt index 2390bb02c..5137c26dd 100644 --- a/doc/EventAI.txt +++ b/doc/EventAI.txt @@ -129,6 +129,7 @@ Params are always read from Param1, then Param2, then Param3. 37 ACTION_T_DIE No Params Kills the creature 38 ACTION_T_ZONE_COMBAT_PULSE No Params Places all players within the instance into combat with the creature. Only works in combat and only works inside of instances. 39 ACTION_T_CALL_FOR_HELP Radius Call any friendly creatures (if its not in combat/etc) in radius attack creature target. +40 ACTION_T_SET_SHEATH Sheath Let set sheath state for creature (0-no weapon show (not used mostly by creatures), 1-melee weapon show, 2-ranged weapon show) * = Use -1 to specify that if this param is picked to do nothing. Random is constant between actions within an event. So if you have a random Yell and a random Sound they will match up (ex: param2 with param2) @@ -684,6 +685,25 @@ This is commonly used if you need to Instakill the creature for one reason or an -------------------------------- Places all players within the instance into combat with the creature. Only works in combat and only works inside of instances. +---------------------------- +39 = ACTION_T_CALL_FOR_HELP: +---------------------------- +Parameter 1: Radius - All friendly (not only same faction) creatures will go to help + +Call any friendly creatures (if its not in combat/etc) in radius attack creature target. +Mostly used when call to help more wide that normal aggro radius or auto-used call for assistance, and need apply at some event. + +------------------------- +40 ACTION_T_SET_SHEATH: +------------------------- +Parameter 1: Sheath state +0 SHEATH_STATE_UNARMED not prepared weapon show (not used mostly by creatures) +1 SHEATH_STATE_MELEE melee weapon prepared show +2 SHEATH_STATE_RANGED ranged weapon prepared show + +Let set sheath state for creature. +Note: SHEATH_STATE_RANGED case work in combat state only if combat not start as melee commands. +This possible setup by set ar event AI start (single used EVENT_T_TIMER_OOC set ACTION_T_COMBAT_MOVEMENT 0 for creature that prefered ranged attack) ========================================= Target Types diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 942de26c6..175952f59 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7906" + #define REVISION_NR "7907" #endif // __REVISION_NR_H__ From 84464e5f3fec2b29045c564bd5b80e762c830154 Mon Sep 17 00:00:00 2001 From: NoFantasy Date: Fri, 29 May 2009 05:43:08 +0400 Subject: [PATCH 5/7] [7908] Extract class data from creature_*_addon bytes0 fields, drop its, amd add unit_class field to creature_template. Signed-off-by: VladimirMangos --- sql/mangos.sql | 7 +++---- .../7908_01_mangos_creature_template.sql | 17 +++++++++++++++++ sql/updates/7908_02_mangos_creature_addon.sql | 4 ++++ .../7908_03_mangos_creature_template_addon.sql | 4 ++++ sql/updates/Makefile.am | 6 ++++++ src/game/Creature.cpp | 11 ++++++++--- src/game/Creature.h | 2 +- src/game/ObjectMgr.cpp | 9 +++++++++ src/game/SharedDefines.h | 2 ++ src/game/SpellAuras.cpp | 9 ++++++--- src/shared/Database/SQLStorage.cpp | 8 ++++---- src/shared/revision_nr.h | 2 +- 12 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 sql/updates/7908_01_mangos_creature_template.sql create mode 100644 sql/updates/7908_02_mangos_creature_addon.sql create mode 100644 sql/updates/7908_03_mangos_creature_template_addon.sql diff --git a/sql/mangos.sql b/sql/mangos.sql index 633bdb683..61f7971aa 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_7904_01_mangos_creature_template` bit(1) default NULL + `required_7908_03_mangos_creature_template_addon` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -564,7 +564,6 @@ DROP TABLE IF EXISTS `creature_addon`; CREATE TABLE `creature_addon` ( `guid` int(11) NOT NULL default '0', `mount` mediumint(8) unsigned NOT NULL default '0', - `bytes0` int(10) unsigned NOT NULL default '0', `bytes1` int(10) unsigned NOT NULL default '0', `bytes2` int(10) unsigned NOT NULL default '0', `emote` int(10) unsigned NOT NULL default '0', @@ -816,6 +815,7 @@ CREATE TABLE `creature_template` ( `dmg_multiplier` float NOT NULL default '1', `baseattacktime` int(10) unsigned NOT NULL default '0', `rangeattacktime` int(10) unsigned NOT NULL default '0', + `unit_class` tinyint(3) unsigned NOT NULL default '0', `unit_flags` int(10) unsigned NOT NULL default '0', `dynamicflags` int(10) unsigned NOT NULL default '0', `family` tinyint(4) NOT NULL default '0', @@ -865,7 +865,7 @@ CREATE TABLE `creature_template` ( LOCK TABLES `creature_template` WRITE; /*!40000 ALTER TABLE `creature_template` DISABLE KEYS */; INSERT INTO `creature_template` VALUES -(1,0,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,2000,2200,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,1,0,0,0x82,''); +(1,0,10045,0,10045,0,'Waypoint(Only GM can see it)','Visual',NULL,1,1,64,64,0,0,0,35,35,0,0.91,1,0,14,15,0,100,1,2000,2200,8,4096,0,0,0,0,0,0,1.76,2.42,100,8,5242886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'',0,3,1.0,1.0,0,1,0,0,0x82,''); /*!40000 ALTER TABLE `creature_template` ENABLE KEYS */; UNLOCK TABLES; @@ -877,7 +877,6 @@ DROP TABLE IF EXISTS `creature_template_addon`; CREATE TABLE `creature_template_addon` ( `entry` mediumint(8) unsigned NOT NULL default '0', `mount` mediumint(8) unsigned NOT NULL default '0', - `bytes0` int(10) unsigned NOT NULL default '0', `bytes1` int(10) unsigned NOT NULL default '0', `bytes2` int(10) unsigned NOT NULL default '0', `emote` mediumint(8) unsigned NOT NULL default '0', diff --git a/sql/updates/7908_01_mangos_creature_template.sql b/sql/updates/7908_01_mangos_creature_template.sql new file mode 100644 index 000000000..ced41e185 --- /dev/null +++ b/sql/updates/7908_01_mangos_creature_template.sql @@ -0,0 +1,17 @@ +ALTER TABLE db_version CHANGE COLUMN required_7904_01_mangos_creature_template required_7908_01_mangos_creature_template bit; + +ALTER TABLE creature_template ADD COLUMN unit_class tinyint(3) unsigned NOT NULL default '0' AFTER rangeattacktime; + +UPDATE creature_template ct +JOIN creature c ON ct.entry=c.id +JOIN creature_addon ad ON c.guid=ad.guid +SET ct.unit_class=(ad.bytes0 & 0x0000FF00) >> 8 +WHERE ct.entry=c.id AND ct.unit_class=0; + +UPDATE creature_template ct +JOIN creature_template_addon ad ON ct.entry=ad.entry +SET ct.unit_class=(ad.bytes0 & 0x0000FF00) >> 8 +WHERE ct.entry=ad.entry AND ct.unit_class=0; + +UPDATE creature_template a1, creature_template a2 SET a1.unit_class=a2.unit_class WHERE a1.unit_class=0 AND a2.unit_class!=0 AND a1.entry=a2.heroic_entry; +UPDATE creature_template a1, creature_template a2 SET a1.unit_class=a2.unit_class WHERE a1.unit_class=0 AND a2.unit_class!=0 AND a2.entry=a1.heroic_entry; diff --git a/sql/updates/7908_02_mangos_creature_addon.sql b/sql/updates/7908_02_mangos_creature_addon.sql new file mode 100644 index 000000000..f72630957 --- /dev/null +++ b/sql/updates/7908_02_mangos_creature_addon.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7908_01_mangos_creature_template required_7908_02_mangos_creature_addon bit; + +ALTER TABLE creature_addon + DROP COLUMN bytes0; diff --git a/sql/updates/7908_03_mangos_creature_template_addon.sql b/sql/updates/7908_03_mangos_creature_template_addon.sql new file mode 100644 index 000000000..7dcea58fe --- /dev/null +++ b/sql/updates/7908_03_mangos_creature_template_addon.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_7908_02_mangos_creature_addon required_7908_03_mangos_creature_template_addon bit; + +ALTER TABLE creature_template_addon + DROP COLUMN bytes0; diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 62aab9912..acd664849 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -205,6 +205,9 @@ pkgdata_DATA = \ 7902_02_mangos_pool_gameobject.sql \ 7903_01_characters_character_pet.sql \ 7904_01_mangos_creature_template.sql \ + 7908_01_mangos_creature_template.sql \ + 7908_02_mangos_creature_addon.sql \ + 7908_03_mangos_creature_template_addon.sql \ README ## Additional files to include when running 'make dist' @@ -390,4 +393,7 @@ EXTRA_DIST = \ 7902_02_mangos_pool_gameobject.sql \ 7903_01_characters_character_pet.sql \ 7904_01_mangos_creature_template.sql \ + 7908_01_mangos_creature_template.sql \ + 7908_02_mangos_creature_addon.sql \ + 7908_03_mangos_creature_template_addon.sql \ README diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 4ac9c77ad..47ad3e2ae 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -197,6 +197,12 @@ bool Creature::InitEntry(uint32 Entry, uint32 team, const CreatureData *data ) SetEntry(Entry); // normal entry always m_creatureInfo = cinfo; // map mode related always + // equal to player Race field, but creature does not have race + SetByteValue(UNIT_FIELD_BYTES_0, 0, 0); + + // known valid are: CLASS_WARRIOR,CLASS_PALADIN,CLASS_ROGUE,CLASS_MAGE + SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class)); + if (cinfo->DisplayID_A == 0 || cinfo->DisplayID_H == 0) // Cancel load if no model defined { sLog.outErrorDb("Creature (Entry: %u) has no model defined for Horde or Alliance in table `creature_template`, can't load. ",Entry); @@ -1204,6 +1210,8 @@ void Creature::SelectLevel(const CreatureInfo *cinfo) SetMaxPower(POWER_MANA, mana); //MAX Mana SetPower(POWER_MANA, mana); + // TODO: set UNIT_FIELD_POWER*, for some creature class case (energy, etc) + SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, health); SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, mana); @@ -1860,9 +1868,6 @@ bool Creature::LoadCreaturesAddon(bool reload) if (cainfo->mount != 0) Mount(cainfo->mount); - if (cainfo->bytes0 != 0) - SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0); - if (cainfo->bytes1 != 0) SetUInt32Value(UNIT_FIELD_BYTES_1, cainfo->bytes1); diff --git a/src/game/Creature.h b/src/game/Creature.h index 0d15dfe01..15c90874b 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -184,6 +184,7 @@ struct CreatureInfo float dmg_multiplier; uint32 baseattacktime; uint32 rangeattacktime; + uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures. uint32 unit_flags; // enum UnitFlags mask values uint32 dynamicflags; uint32 family; // enum CreatureFamily values (optional) @@ -296,7 +297,6 @@ struct CreatureDataAddon { uint32 guidOrEntry; uint32 mount; - uint32 bytes0; uint32 bytes1; uint32 bytes2; uint32 emote; diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 2c0662fe6..20304eb6c 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -490,6 +490,12 @@ void ObjectMgr::LoadCreatureTemplates() continue; } + if(cInfo->unit_class != heroicInfo->unit_class) + { + sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in heroic mode (Entry: %u, class %u).",i, cInfo->unit_class, cInfo->HeroicEntry, heroicInfo->unit_class); + continue; + } + if(cInfo->npcflag != heroicInfo->npcflag) { sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in heroic mode (Entry: %u).",i,cInfo->HeroicEntry); @@ -551,6 +557,9 @@ void ObjectMgr::LoadCreatureTemplates() if (!minfo) sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u)", cInfo->Entry, cInfo->DisplayID_H); + if (cInfo->unit_class && ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) + sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); + if(cInfo->dmgschool >= MAX_SPELL_SCHOOL) { sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool); diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index f8a92c386..893a6ad2a 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -89,6 +89,8 @@ enum Classes (1<<(CLASS_MAGE-1)) |(1<<(CLASS_WARLOCK-1))|(1<<(CLASS_DRUID-1)) | \ (1<<(CLASS_DEATH_KNIGHT-1)) ) +#define CLASSMASK_ALL_CREATURES ((1<<(CLASS_WARRIOR-1)) | (1<<(CLASS_PALADIN-1)) | (1<<(CLASS_ROGUE-1)) | (1<<(CLASS_MAGE-1)) ) + #define CLASSMASK_WAND_USERS ((1<<(CLASS_PRIEST-1))|(1<<(CLASS_MAGE-1))|(1<<(CLASS_WARLOCK-1))) #define PLAYER_MAX_BATTLEGROUND_QUEUES 3 diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 1a9c6107e..9e8f4e075 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3217,8 +3217,9 @@ void Aura::HandleModCharm(bool apply, bool Real) CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo(); if(cinfo && cinfo->type == CREATURE_TYPE_DEMON) { + //does not appear to have relevance. Why code added initially? See note below at !apply //to prevent client crash - m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048); + //m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048); //just to enable stat window charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true); //if charmed two demons the same session, the 2nd gets the 1st one's name @@ -3256,11 +3257,13 @@ void Aura::HandleModCharm(bool apply, bool Real) // restore UNIT_FIELD_BYTES_0 if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON) { - CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon(); + //does not appear to have relevance. Why code added initially? Class, gender, powertype should be same. + //db field removed and replaced with better way to set class, restore using this if problems + /*CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon(); if(cainfo && cainfo->bytes0 != 0) m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0); else - m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048); + m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);*/ if(m_target->GetCharmInfo()) m_target->GetCharmInfo()->SetPetNumber(0, true); diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp index 768abcee5..61b7a5a37 100644 --- a/src/shared/Database/SQLStorage.cpp +++ b/src/shared/Database/SQLStorage.cpp @@ -25,11 +25,11 @@ extern DatabasePostgre WorldDatabase; extern DatabaseMysql WorldDatabase; #endif -const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiis"; -const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiii"; -const char CreatureDataAddonInfofmt[]="iiiiiiis"; +const char CreatureInfosrcfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiis"; +const char CreatureInfodstfmt[]="iiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiisiifflliiii"; +const char CreatureDataAddonInfofmt[]="iiiiiis"; const char CreatureModelfmt[]="iffbi"; -const char CreatureInfoAddonInfofmt[]="iiiiiiis"; +const char CreatureInfoAddonInfofmt[]="iiiiiis"; const char EquipmentInfofmt[]="iiii"; const char GameObjectInfosrcfmt[]="iiisssiifiiiiiiiiiiiiiiiiiiiiiiiis"; const char GameObjectInfodstfmt[]="iiisssiifiiiiiiiiiiiiiiiiiiiiiiiii"; diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 175952f59..649859178 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7907" + #define REVISION_NR "7908" #endif // __REVISION_NR_H__ From f84fdc6757fa355540b76b2cfa69bf857d9f3fcd Mon Sep 17 00:00:00 2001 From: tomrus88 Date: Thu, 28 May 2009 18:44:51 +0400 Subject: [PATCH 6/7] [7909] Applied coding style. (cherry picked from commit ed7e72975f4d4f95f5c429f1af6a2c021adfd5a1) Signed-off-by: VladimirMangos --- .../vmap_extractor_v2/vmapextract/adtfile.cpp | 303 +++--- .../vmap_extractor_v2/vmapextract/adtfile.h | 189 ++-- .../vmap_extractor_v2/vmapextract/dbcfile.cpp | 86 +- .../vmap_extractor_v2/vmapextract/dbcfile.h | 228 ++--- .../vmap_extractor_v2/vmapextract/model.cpp | 50 +- contrib/vmap_extractor_v2/vmapextract/model.h | 49 +- .../vmapextract/modelheaders.h | 125 ++- contrib/vmap_extractor_v2/vmapextract/mpq.cpp | 139 ++- contrib/vmap_extractor_v2/vmapextract/mpq.h | 67 +- contrib/vmap_extractor_v2/vmapextract/vec3d.h | 320 +++--- .../vmapextract/vmapexport.cpp | 132 +-- .../vmap_extractor_v2/vmapextract/wdtfile.cpp | 153 ++- .../vmap_extractor_v2/vmapextract/wdtfile.h | 24 +- contrib/vmap_extractor_v2/vmapextract/wmo.cpp | 920 +++++++++--------- contrib/vmap_extractor_v2/vmapextract/wmo.h | 113 ++- src/shared/revision_nr.h | 2 +- 16 files changed, 1433 insertions(+), 1467 deletions(-) diff --git a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp index b798263ca..2de3aa751 100644 --- a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp @@ -1,6 +1,5 @@ #include "adtfile.h" - char * GetPlainName(char * FileName) { char * szTemp; @@ -12,159 +11,149 @@ char * GetPlainName(char * FileName) void fixnamen(char *name, size_t len) { - for (size_t i=0; i0 && name[i]>='A' && name[i]<='Z' && isalpha(name[i-1])) - { - name[i] |= 0x20; - } else if ((i==0 || !isalpha(name[i-1])) && name[i]>='a' && name[i]<='z') - { - name[i] &= ~0x20; - } - } + for (size_t i=0; i0 && name[i]>='A' && name[i]<='Z' && isalpha(name[i-1])) + { + name[i] |= 0x20; + } else if ((i==0 || !isalpha(name[i-1])) && name[i]>='a' && name[i]<='z') + { + name[i] &= ~0x20; + } + } } void fixname2(char *name, size_t len) { - for (size_t i=0; iopen()) - { - m2->ConvertToVMAPModel((char*)szLocalFile); - } - delete m2; - - } - else - fclose(output); - } - - delete[] buf; - } - - } - else if (!strcmp(fourcc,"MWMO")) - { - if (size) - { - - char *buf = new char[size]; - ADT.read(buf, size); - char *p=buf; - int q = 0; - WmoInstansName = new string[size]; - while (popen()) + { + m2->ConvertToVMAPModel((char*)szLocalFile); + } + delete m2; + } + else + fclose(output); + } + delete[] buf; + } + } + else if (!strcmp(fourcc,"MWMO")) + { + if (size) + { + char *buf = new char[size]; + ADT.read(buf, size); + char *p=buf; + int q = 0; + WmoInstansName = new string[size]; + while (p= recordSize); - f.read(&na,4); // Number of records - f.read(&nb,4); // Number of fields - f.read(&es,4); // Size of a record - f.read(&ss,4); // String size - - recordSize = es; - recordCount = na; - fieldCount = nb; - stringSize = ss; - //assert(fieldCount*4 == recordSize); - assert(fieldCount*4 >= recordSize); - - data = new unsigned char[recordSize*recordCount+stringSize]; - stringTable = data + recordSize*recordCount; - f.read(data,recordSize*recordCount+stringSize); - f.close(); - return true; + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; + f.read(data,recordSize*recordCount+stringSize); + f.close(); + return true; } DBCFile::~DBCFile() { - delete [] data; + delete [] data; } DBCFile::Record DBCFile::getRecord(size_t id) { - assert(data); - return Record(*this, data + id*recordSize); + assert(data); + return Record(*this, data + id*recordSize); } DBCFile::Iterator DBCFile::begin() { - assert(data); - return Iterator(*this, data); -} -DBCFile::Iterator DBCFile::end() -{ - assert(data); - return Iterator(*this, stringTable); + assert(data); + return Iterator(*this, data); } +DBCFile::Iterator DBCFile::end() +{ + assert(data); + return Iterator(*this, stringTable); +} diff --git a/contrib/vmap_extractor_v2/vmapextract/dbcfile.h b/contrib/vmap_extractor_v2/vmapextract/dbcfile.h index bf6b8635a..63081bca4 100644 --- a/contrib/vmap_extractor_v2/vmapextract/dbcfile.h +++ b/contrib/vmap_extractor_v2/vmapextract/dbcfile.h @@ -9,131 +9,131 @@ class DBCFile { public: - DBCFile(const std::string &filename); - ~DBCFile(); + DBCFile(const std::string &filename); + ~DBCFile(); - // Open database. It must be openened before it can be used. - bool open(); + // Open database. It must be openened before it can be used. + bool open(); - // TODO: Add a close function? + // TODO: Add a close function? - // Database exceptions - class Exception - { - public: - Exception(const std::string &message): message(message) - { } - virtual ~Exception() - { } - const std::string &getMessage() {return message;} - private: - std::string message; - }; + // Database exceptions + class Exception + { + public: + Exception(const std::string &message): message(message) + { } + virtual ~Exception() + { } + const std::string &getMessage() {return message;} + private: + std::string message; + }; - // - class NotFound: public Exception - { - public: - NotFound(): Exception("Key was not found") - { } - }; + // + class NotFound: public Exception + { + public: + NotFound(): Exception("Key was not found") + { } + }; - // Iteration over database - class Iterator; - class Record - { - public: - Record& operator= (const Record& r) - { + // Iteration over database + class Iterator; + class Record + { + public: + Record& operator= (const Record& r) + { file = r.file; - offset = r.offset; - return *this; - } - float getFloat(size_t field) const - { - assert(field < file.fieldCount); - return *reinterpret_cast(offset+field*4); - } - unsigned int getUInt(size_t field) const - { - assert(field < file.fieldCount); - return *reinterpret_cast(offset+(field*4)); - } - int getInt(size_t field) const - { - assert(field < file.fieldCount); - return *reinterpret_cast(offset+field*4); - } - unsigned char getByte(size_t ofs) const - { - assert(ofs < file.recordSize); - return *reinterpret_cast(offset+ofs); - } - const char *getString(size_t field) const - { - assert(field < file.fieldCount); - size_t stringOffset = getUInt(field); - assert(stringOffset < file.stringSize); - //char * tmp = (char*)file.stringTable + stringOffset; - //unsigned char * tmp2 = file.stringTable + stringOffset; - return reinterpret_cast(file.stringTable + stringOffset); - } - private: - Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {} - unsigned char *offset; - DBCFile &file; + offset = r.offset; + return *this; + } + float getFloat(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+field*4); + } + unsigned int getUInt(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+(field*4)); + } + int getInt(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast(offset+field*4); + } + unsigned char getByte(size_t ofs) const + { + assert(ofs < file.recordSize); + return *reinterpret_cast(offset+ofs); + } + const char *getString(size_t field) const + { + assert(field < file.fieldCount); + size_t stringOffset = getUInt(field); + assert(stringOffset < file.stringSize); + //char * tmp = (char*)file.stringTable + stringOffset; + //unsigned char * tmp2 = file.stringTable + stringOffset; + return reinterpret_cast(file.stringTable + stringOffset); + } + private: + Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {} + unsigned char *offset; + DBCFile &file; - friend class DBCFile; - friend class Iterator; - }; + friend class DBCFile; + friend class Iterator; + }; - /* Iterator that iterates over records */ - class Iterator - { - public: - Iterator(DBCFile &file, unsigned char *offset): - record(file, offset) {} - /// Advance (prefix only) - Iterator & operator++() { - record.offset += record.file.recordSize; - return *this; - } - /// Return address of current instance - Record const & operator*() const { return record; } - const Record* operator->() const { - return &record; - } - /// Comparison - bool operator==(const Iterator &b) const - { - return record.offset == b.record.offset; - } - bool operator!=(const Iterator &b) const - { - return record.offset != b.record.offset; - } - private: - Record record; - }; + /* Iterator that iterates over records */ + class Iterator + { + public: + Iterator(DBCFile &file, unsigned char *offset): + record(file, offset) {} + /// Advance (prefix only) + Iterator & operator++() { + record.offset += record.file.recordSize; + return *this; + } + /// Return address of current instance + Record const & operator*() const { return record; } + const Record* operator->() const { + return &record; + } + /// Comparison + bool operator==(const Iterator &b) const + { + return record.offset == b.record.offset; + } + bool operator!=(const Iterator &b) const + { + return record.offset != b.record.offset; + } + private: + Record record; + }; - // Get record by id - Record getRecord(size_t id); - /// Get begin iterator over records - Iterator begin(); - /// Get begin iterator over records - Iterator end(); - /// Trivial - size_t getRecordCount() const { return recordCount;} - size_t getFieldCount() const { return fieldCount; } + // Get record by id + Record getRecord(size_t id); + /// Get begin iterator over records + Iterator begin(); + /// Get begin iterator over records + Iterator end(); + /// Trivial + size_t getRecordCount() const { return recordCount;} + size_t getFieldCount() const { return fieldCount; } private: - std::string filename; - size_t recordSize; - size_t recordCount; - size_t fieldCount; - size_t stringSize; - unsigned char *data; - unsigned char *stringTable; + std::string filename; + size_t recordSize; + size_t recordCount; + size_t fieldCount; + size_t stringSize; + unsigned char *data; + unsigned char *stringTable; }; #endif diff --git a/contrib/vmap_extractor_v2/vmapextract/model.cpp b/contrib/vmap_extractor_v2/vmapextract/model.cpp index 1d0c17d52..9605e3320 100644 --- a/contrib/vmap_extractor_v2/vmapextract/model.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/model.cpp @@ -12,7 +12,7 @@ bool Model::open() ok = !f.isEof(); - if (!ok) + if (!ok) { f.close(); printf("Error loading model %s\n", filename.c_str()); @@ -20,20 +20,20 @@ bool Model::open() } memcpy(&header, f.getBuffer(), sizeof(ModelHeader)); - if(header.nBoundingTriangles > 0) + if(header.nBoundingTriangles > 0) { f.seek(0); - f.seekRelative(header.ofsBoundingVertices); - vertices = new Vec3D[header.nBoundingVertices]; - f.read(vertices,header.nBoundingVertices*12); + f.seekRelative(header.ofsBoundingVertices); + vertices = new Vec3D[header.nBoundingVertices]; + f.read(vertices,header.nBoundingVertices*12); for (uint32 i=0; i0) + if(nIndexes >0) { fwrite(indices, sizeof(unsigned short), nIndexes, output); } @@ -84,7 +82,7 @@ bool Model::ConvertToVMAPModel(char * outfilename) wsize = sizeof(int) + sizeof(float) * 3 * nVertices; fwrite(&wsize, sizeof(int), 1, output); fwrite(&nVertices, sizeof(int), 1, output); - if(nVertices >0) + if(nVertices >0) { for(uint32 vpos=0; vpos ArchiveSet; ArchiveSet gOpenArchives; -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + MPQArchive::MPQArchive(const char* filename) { - BOOL succ = SFileOpenArchive(filename, 0, 0,&hMPQ); - if (succ) - { - MPQArchive*ar = (MPQArchive*)(hMPQ); - printf("Opening %s\n", filename); - gOpenArchives.push_back(ar); + BOOL succ = SFileOpenArchive(filename, 0, 0,&hMPQ); + if (succ) + { + MPQArchive*ar = (MPQArchive*)(hMPQ); + printf("Opening %s\n", filename); + gOpenArchives.push_back(ar); succ = true; - - } - else - { - printf("Error!!!Not open archive %s\n", filename); - } + } + else + { + printf("Error!!!Not open archive %s\n", filename); + } } void MPQArchive::close() { - SFileCloseArchive(hMPQ); + SFileCloseArchive(hMPQ); } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx MPQFile::MPQFile(const char* filename): - eof(false), - buffer(0), - pointer(0), - size(0) + eof(false), + buffer(0), + pointer(0), + size(0) { - for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i) - { - - HANDLE hFile = ""; - MPQArchive*(hMPQ) = *i; - BOOL succ = SFileOpenFileEx(hMPQ,filename,0, &hFile); - if (succ) - { - DWORD s = SFileGetFileSize(hFile, 0); - if (!s) - { - eof = true; - buffer = 0; - return; - } - size = (size_t)s; - buffer = new char[s]; - SFileReadFile(hFile, buffer, s, 0, 0); - SFileCloseFile(hFile); - - eof = false; - return; - } - } - - eof = true; - buffer = 0; - + for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i) + { + HANDLE hFile = ""; + MPQArchive*(hMPQ) = *i; + BOOL succ = SFileOpenFileEx(hMPQ,filename,0, &hFile); + if (succ) + { + DWORD s = SFileGetFileSize(hFile, 0); + if (!s) + { + eof = true; + buffer = 0; + return; + } + size = (size_t)s; + buffer = new char[s]; + SFileReadFile(hFile, buffer, s, 0, 0); + SFileCloseFile(hFile); + + eof = false; + return; + } + } + + eof = true; + buffer = 0; } MPQFile::~MPQFile() { - close(); + close(); } size_t MPQFile::read(void* dest, size_t bytes) { - if (eof) - return 0; + if (eof) + return 0; - size_t rpos = pointer + bytes; - if (rpos > size) - { - bytes = size - pointer; - eof = true; - } + size_t rpos = pointer + bytes; + if (rpos > size) + { + bytes = size - pointer; + eof = true; + } - memcpy(dest, &(buffer[pointer]), bytes); + memcpy(dest, &(buffer[pointer]), bytes); - pointer = rpos; + pointer = rpos; - return bytes; + return bytes; } bool MPQFile::isEof() @@ -96,41 +92,40 @@ bool MPQFile::isEof() void MPQFile::seek(int offset) { - pointer = offset; - eof = (pointer >= size); + pointer = offset; + eof = (pointer >= size); } void MPQFile::seekRelative(int offset) { - pointer += offset; - eof = (pointer >= size); + pointer += offset; + eof = (pointer >= size); } void MPQFile::close() { - if (buffer) - delete[] buffer; - buffer = 0; - eof = true; + if (buffer) + delete[] buffer; + buffer = 0; + eof = true; } size_t MPQFile::getSize() { - return size; + return size; } size_t MPQFile::getPos() { - return pointer; + return pointer; } char* MPQFile::getBuffer() { - return buffer; + return buffer; } char* MPQFile::getPointer() { - return buffer + pointer; + return buffer + pointer; } - diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq.h b/contrib/vmap_extractor_v2/vmapextract/mpq.h index 79f30afc7..8fc885667 100644 --- a/contrib/vmap_extractor_v2/vmapextract/mpq.h +++ b/contrib/vmap_extractor_v2/vmapextract/mpq.h @@ -3,7 +3,7 @@ #ifndef MPQ_H #define MPQ_H -#define __STORMLIB_SELF__ +#define __STORMLIB_SELF__ #include #include @@ -15,55 +15,50 @@ using namespace std; typedef unsigned int uint32; - class MPQArchive { - public: - HANDLE hMPQ; - MPQArchive(const char* filename); - void close(); + HANDLE hMPQ; + MPQArchive(const char* filename); + void close(); }; - + class MPQFile { - HANDLE hFile; + HANDLE hFile; HANDLE hMPQ; - bool eof; - char *buffer; - size_t pointer, - size; + bool eof; + char *buffer; + size_t pointer, + size; - // disable copying - //MPQFile(const MPQFile &f) {} - //void operator=(const MPQFile &f) {} + // disable copying + //MPQFile(const MPQFile &f) {} + //void operator=(const MPQFile &f) {} public: - MPQFile(const char* filename); - ~MPQFile(); - size_t read(void* dest, size_t bytes); - size_t getSize(); - size_t getPos(); - char* getBuffer(); - char* getPointer(); - bool isEof(); - void seek(int offset); - void seekRelative(int offset); - void close(); + MPQFile(const char* filename); + ~MPQFile(); + size_t read(void* dest, size_t bytes); + size_t getSize(); + size_t getPos(); + char* getBuffer(); + char* getPointer(); + bool isEof(); + void seek(int offset); + void seekRelative(int offset); + void close(); }; inline void flipcc(char *fcc) { - char t; - t=fcc[0]; - fcc[0]=fcc[3]; - fcc[3]=t; - t=fcc[1]; - fcc[1]=fcc[2]; - fcc[2]=t; + char t; + t=fcc[0]; + fcc[0]=fcc[3]; + fcc[3]=t; + t=fcc[1]; + fcc[1]=fcc[2]; + fcc[2]=t; } - - #endif - diff --git a/contrib/vmap_extractor_v2/vmapextract/vec3d.h b/contrib/vmap_extractor_v2/vmapextract/vec3d.h index 88b8e1c4f..fd966138d 100644 --- a/contrib/vmap_extractor_v2/vmapextract/vec3d.h +++ b/contrib/vmap_extractor_v2/vmapextract/vec3d.h @@ -4,227 +4,221 @@ #include #include - - -class Vec3D { +class Vec3D +{ public: - float x,y,z; + float x,y,z; - Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {} + Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {} - Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {} + Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {} - Vec3D& operator= (const Vec3D &v) { + Vec3D& operator= (const Vec3D &v) { x = v.x; - y = v.y; - z = v.z; - return *this; - } + y = v.y; + z = v.z; + return *this; + } - Vec3D operator+ (const Vec3D &v) const - { - Vec3D r(x+v.x,y+v.y,z+v.z); + Vec3D operator+ (const Vec3D &v) const + { + Vec3D r(x+v.x,y+v.y,z+v.z); return r; - } + } - Vec3D operator- (const Vec3D &v) const - { - Vec3D r(x-v.x,y-v.y,z-v.z); - return r; - } + Vec3D operator- (const Vec3D &v) const + { + Vec3D r(x-v.x,y-v.y,z-v.z); + return r; + } - float operator* (const Vec3D &v) const - { + float operator* (const Vec3D &v) const + { return x*v.x + y*v.y + z*v.z; - } + } - Vec3D operator* (float d) const - { - Vec3D r(x*d,y*d,z*d); + Vec3D operator* (float d) const + { + Vec3D r(x*d,y*d,z*d); return r; - } + } - friend Vec3D operator* (float d, const Vec3D& v) - { - return v * d; - } + friend Vec3D operator* (float d, const Vec3D& v) + { + return v * d; + } - Vec3D operator% (const Vec3D &v) const - { + Vec3D operator% (const Vec3D &v) const + { Vec3D r(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x); - return r; - } + return r; + } - Vec3D& operator+= (const Vec3D &v) - { - x += v.x; - y += v.y; - z += v.z; - return *this; - } + Vec3D& operator+= (const Vec3D &v) + { + x += v.x; + y += v.y; + z += v.z; + return *this; + } - Vec3D& operator-= (const Vec3D &v) - { - x -= v.x; - y -= v.y; - z -= v.z; - return *this; - } + Vec3D& operator-= (const Vec3D &v) + { + x -= v.x; + y -= v.y; + z -= v.z; + return *this; + } - Vec3D& operator*= (float d) - { - x *= d; - y *= d; - z *= d; - return *this; - } + Vec3D& operator*= (float d) + { + x *= d; + y *= d; + z *= d; + return *this; + } - float lengthSquared() const - { - return x*x+y*y+z*z; - } + float lengthSquared() const + { + return x*x+y*y+z*z; + } - float length() const - { + float length() const + { return sqrt(x*x+y*y+z*z); - } + } - Vec3D& normalize() - { - this->operator*= (1.0f/length()); - return *this; - } + Vec3D& normalize() + { + this->operator*= (1.0f/length()); + return *this; + } - Vec3D operator~ () const - { - Vec3D r(*this); + Vec3D operator~ () const + { + Vec3D r(*this); r.normalize(); - return r; - } + return r; + } - friend std::istream& operator>>(std::istream& in, Vec3D& v) - { - in >> v.x >> v.y >> v.z; - return in; - } - - operator float*() - { - return (float*)this; - } + friend std::istream& operator>>(std::istream& in, Vec3D& v) + { + in >> v.x >> v.y >> v.z; + return in; + } + operator float*() + { + return (float*)this; + } }; -class Vec2D { +class Vec2D +{ public: - float x,y; - - Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {} + float x,y; + + Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {} - Vec2D(const Vec2D& v) : x(v.x), y(v.y) {} + Vec2D(const Vec2D& v) : x(v.x), y(v.y) {} - Vec2D& operator= (const Vec2D &v) { + Vec2D& operator= (const Vec2D &v) { x = v.x; - y = v.y; - return *this; - } + y = v.y; + return *this; + } - Vec2D operator+ (const Vec2D &v) const - { - Vec2D r(x+v.x,y+v.y); + Vec2D operator+ (const Vec2D &v) const + { + Vec2D r(x+v.x,y+v.y); return r; - } + } - Vec2D operator- (const Vec2D &v) const - { - Vec2D r(x-v.x,y-v.y); - return r; - } + Vec2D operator- (const Vec2D &v) const + { + Vec2D r(x-v.x,y-v.y); + return r; + } - float operator* (const Vec2D &v) const - { + float operator* (const Vec2D &v) const + { return x*v.x + y*v.y; - } + } - Vec2D operator* (float d) const - { - Vec2D r(x*d,y*d); + Vec2D operator* (float d) const + { + Vec2D r(x*d,y*d); return r; - } + } - friend Vec2D operator* (float d, const Vec2D& v) - { - return v * d; - } + friend Vec2D operator* (float d, const Vec2D& v) + { + return v * d; + } - Vec2D& operator+= (const Vec2D &v) - { - x += v.x; - y += v.y; - return *this; - } + Vec2D& operator+= (const Vec2D &v) + { + x += v.x; + y += v.y; + return *this; + } - Vec2D& operator-= (const Vec2D &v) - { - x -= v.x; - y -= v.y; - return *this; - } + Vec2D& operator-= (const Vec2D &v) + { + x -= v.x; + y -= v.y; + return *this; + } - Vec2D& operator*= (float d) - { - x *= d; - y *= d; - return *this; - } + Vec2D& operator*= (float d) + { + x *= d; + y *= d; + return *this; + } - float lengthSquared() const - { - return x*x+y*y; - } + float lengthSquared() const + { + return x*x+y*y; + } - float length() const - { + float length() const + { return sqrt(x*x+y*y); - } + } - Vec2D& normalize() - { - this->operator*= (1.0f/length()); - return *this; - } + Vec2D& normalize() + { + this->operator*= (1.0f/length()); + return *this; + } - Vec2D operator~ () const - { - Vec2D r(*this); + Vec2D operator~ () const + { + Vec2D r(*this); r.normalize(); - return r; - } + return r; + } - friend std::istream& operator>>(std::istream& in, Vec2D& v) - { + friend std::istream& operator>>(std::istream& in, Vec2D& v) + { in >> v.x >> v.y; - return in; - } - - operator float*() - { - return (float*)this; - } + return in; + } + operator float*() + { + return (float*)this; + } }; - inline void rotate(float x0, float y0, float *x, float *y, float angle) { - float xa = *x - x0, ya = *y - y0; - *x = xa*cosf(angle) - ya*sinf(angle) + x0; - *y = xa*sinf(angle) + ya*cosf(angle) + y0; + float xa = *x - x0, ya = *y - y0; + *x = xa*cosf(angle) - ya*sinf(angle) + x0; + *y = xa*sinf(angle) + ya*cosf(angle) + y0; } - - #endif - diff --git a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp index 0d2b39f8d..32ff7970c 100644 --- a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp @@ -58,7 +58,7 @@ char input_path[1024]="."; bool hasInputPathParam = false; char tmp[512]; bool preciseVectorData = false; -//char gamepath[1024]; +//char gamepath[1024]; //Convert function //bool ConvertADT(char*,char*); @@ -86,7 +86,7 @@ static const char * GetPlainName(const char * szFileName) szFileName = szTemp + 1; return szFileName; } -//------------------------------------------------------------------------------ + static void ShowProcessedFile(const char * szFileName) { char szLine[80]; @@ -101,14 +101,11 @@ static void ShowProcessedFile(const char * szFileName) printf("\r%s\n", szLine); } - -//---------------------------------------------------------------------------------------------------------------------------------------------------------------------- int ExtractWmo(const std::vector& pArchiveNames) { - - char* szListFile = ""; + char* szListFile = ""; char szLocalFile[MAX_PATH] = ""; - HANDLE hMpq = ""; + HANDLE hMpq = ""; BOOL bResult = FALSE; //const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"}; @@ -118,9 +115,8 @@ int ExtractWmo(const std::vector& pArchiveNames) szListFile = NULL; //char tmp[1024]; //for (size_t i=0; i<4; i++) - for (size_t i=0; i& pArchiveNames) // Copy files from archive if(nError == ERROR_SUCCESS) - { + { SFILE_FIND_DATA wf; HANDLE hFind = SFileFindFirstFile(hMpq,"*.wmo*", &wf, szListFile); bResult = TRUE; @@ -149,11 +145,11 @@ int ExtractWmo(const std::vector& pArchiveNames) { char cpy[4]; strncpy((char*)cpy,rchr,4); - for (int i=0;i<4;i++) + for (int i=0;i<4; ++i) { int m = cpy[i]; if(isdigit(m)) - p++; + p++; } } if(p != 3) @@ -167,12 +163,12 @@ int ExtractWmo(const std::vector& pArchiveNames) bResult = SFileFindNextFile(hFind, &wf); continue; } - FILE *output=fopen(szLocalFile,"wb"); + FILE *output=fopen(szLocalFile,"wb"); froot->ConvertToVMAPRootWmo(output); int Wmo_nVertices = 0; if(froot->nGroups !=0) { - for (int i=0; inGroups; i++) + for (int i=0; inGroups; ++i) { char temp[512]; strcpy(temp, wf.cFileName); @@ -189,14 +185,16 @@ int ExtractWmo(const std::vector& pArchiveNames) bResult = SFileFindNextFile(hFind, &wf); break; } - Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, preciseVectorData); + Wmo_nVertices += fgroup->ConvertToVMAPGroupWmo(output, preciseVectorData); } } fseek(output, 8, SEEK_SET); // store the correct no of vertices fwrite(&Wmo_nVertices,sizeof(int),1,output); - fclose(output); + fclose(output); } - } else { + } + else + { fclose(n); } wf.dwFileFlags &= ~MPQ_FILE_HAS_EXTRA; @@ -220,29 +218,27 @@ int ExtractWmo(const std::vector& pArchiveNames) printf("\nExtract wmo complete (No errors)\n"); return nError; - } void ExtractMapsFromMpq() { - } -//----------------------------------------------------------------------------- + void ParsMapFiles() { char fn[512]; char id_filename[64]; char id[10]; - for (unsigned int i=0; iinit(id_filename); delete ADT; } - } } } @@ -259,31 +254,28 @@ void ParsMapFiles() #if 0 void ParsMapFiles() { - char fn[512]; - for (unsigned int i=0; iinit(); delete ADT; } - } } } } } #endif -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx void getGamePath() { @@ -297,18 +289,16 @@ void getGamePath() //l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Blizzard Entertainment\\Burning Crusade Closed Beta",0,KEY_QUERY_VALUE,&key); l = RegQueryValueEx(key,"InstallPath",0,&t,(LPBYTE)input_path,&s); RegCloseKey(key); - if (strlen(input_path) > 0) - { - if (input_path[strlen(input_path) - 1] != '\\') strcat(input_path, "\\"); - } + if (strlen(input_path) > 0) + { + if (input_path[strlen(input_path) - 1] != '\\') strcat(input_path, "\\"); + } strcat(input_path,"Data\\"); #else strcpy(input_path,"data/"); #endif } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - bool scan_patches(char* scanmatch, std::vector& pArchiveNames) { int i; @@ -338,7 +328,7 @@ bool scan_patches(char* scanmatch, std::vector& pArchiveNames) } matches.reverse(); - for (std::list::iterator i = matches.begin(); i != matches.end(); i++) + for (std::list::iterator i = matches.begin(); i != matches.end(); ++i) { pArchiveNames.push_back(i->c_str()); } @@ -348,11 +338,8 @@ bool scan_patches(char* scanmatch, std::vector& pArchiveNames) return(true); } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - -bool fillArchiveNameVector(std::vector& pArchiveNames) { - //srand((unsigned int)time(0)); - +bool fillArchiveNameVector(std::vector& pArchiveNames) +{ if(!hasInputPathParam) getGamePath(); @@ -408,11 +395,12 @@ bool fillArchiveNameVector(std::vector& pArchiveNames) { // now, scan for the patch levels in the core dir printf("Loading patch levels from data directory.\n"); sprintf(path, "%spatch", input_path); - if (!scan_patches(path, pArchiveNames)) return(false); + if (!scan_patches(path, pArchiveNames)) + return(false); // now, scan for the patch levels in locale dirs printf("Loading patch levels from locale directories.\n"); - for (std::vector::iterator i = locales.begin(); i != locales.end(); i++) + for (std::vector::iterator i = locales.begin(); i != locales.end(); ++i) { printf("Locale: %s\n", i->c_str()); sprintf(path, "%s%s\\patch-%s", input_path, i->c_str(), i->c_str()); @@ -433,7 +421,7 @@ bool fillArchiveNameVector(std::vector& pArchiveNames) { // open locale expansion and common files printf("Opening data files from locale directories.\n"); - for (std::vector::iterator i = locales.begin(); i != locales.end(); i++) + for (std::vector::iterator i = locales.begin(); i != locales.end(); ++i) { printf("Locale: %s\n", i->c_str()); sprintf(path, "%s%s\\lichking-locale-%s.mpq", input_path, i->c_str(), i->c_str()); @@ -446,8 +434,6 @@ bool fillArchiveNameVector(std::vector& pArchiveNames) { } return true; } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -// return false it normal processing can not proceed bool processArgv(int argc, char ** argv, char*versionString) { @@ -455,29 +441,43 @@ bool processArgv(int argc, char ** argv, char*versionString) hasInputPathParam = false; bool preciseVectorData = false; - for(int i=1; i< argc; ++i) { - if(strcmp("-s",argv[i]) == 0) { - preciseVectorData = false; - } else if(strcmp("-d",argv[i]) == 0) { - if((i+1)]\n", argv[0]); printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n"); @@ -512,9 +512,9 @@ int main(int argc, char ** argv) char *versionString = "V2.4 2007_07_12"; // Use command line arguments, when some - if(!processArgv(argc, argv, versionString)) + if(!processArgv(argc, argv, versionString)) return 1; - + printf("Extract %s. Beginning work ....\n",versionString); // Set the lowest priority to allow running in the background SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); @@ -528,7 +528,7 @@ int main(int argc, char ** argv) nError = GetLastError(); if(nError == ERROR_ALREADY_EXISTS) nError = ERROR_SUCCESS; - } + } //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx // patch goes first -> fake priority handling std::vector archives; @@ -537,7 +537,8 @@ int main(int argc, char ** argv) std::vector archiveNames; fillArchiveNameVector(archiveNames); - for (size_t i=0; iopen(); map_count=dbc->getRecordCount (); map_ids=new map_id[map_count]; - for(unsigned int x=0;xgetRecord (x).getUInt(0); strcpy(map_ids[x].name,dbc->getRecord(x).getString(1)); - printf("Map - %s\n",map_ids[x].name); + printf("Map - %s\n",map_ids[x].name); } delete dbc; @@ -564,7 +565,8 @@ int main(int argc, char ** argv) } clreol(); - if(nError != ERROR_SUCCESS) { + if(nError != ERROR_SUCCESS) + { printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n",versionString, preciseVectorData); _getch(); } diff --git a/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp b/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp index 831cdaae7..8d3fb6358 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/wdtfile.cpp @@ -1,9 +1,8 @@ -#define __STORMLIB_SELF__ +#define __STORMLIB_SELF__ #include "wdtfile.h" #include "adtfile.h" - char * wdtGetPlainName(char * FileName) { char * szTemp; @@ -15,106 +14,102 @@ char * wdtGetPlainName(char * FileName) WDTFile::WDTFile(char* file_name, char* file_name1):WDT(file_name) { - filename.append(file_name1,strlen(file_name1)); + filename.append(file_name1,strlen(file_name1)); } bool WDTFile::init(char *map_id) { + if (WDT.isEof()) + { + //printf("Can't find WDT file.\n"); + return false; + } - if (WDT.isEof()) - { - //printf("Can't find WDT file.\n"); - return false; - } - - char fourcc[5]; - size_t size; - + char fourcc[5]; + size_t size; - const char dirname[] = "buildings\\dir"; - FILE *dirfile; + const char dirname[] = "buildings\\dir"; + FILE *dirfile; dirfile = fopen(dirname, "ab"); - if(!dirfile) - { - printf("Can't open dirfile!'%s'\n"); - return false; - } + if(!dirfile) + { + printf("Can't open dirfile!'%s'\n"); + return false; + } + while (!WDT.isEof()) + { + WDT.read(fourcc,4); + WDT.read(&size, 4); - while (!WDT.isEof()) - { - WDT.read(fourcc,4); - WDT.read(&size, 4); + flipcc(fourcc); + fourcc[4] = 0; - flipcc(fourcc); - fourcc[4] = 0; + size_t nextpos = WDT.getPos() + size; - size_t nextpos = WDT.getPos() + size; - - if (!strcmp(fourcc,"MAIN")) - { - } - if (!strcmp(fourcc,"MWMO")) - { - // global map objects - if (size) - { - char *buf = new char[size]; - WDT.read(buf, size); - char *p=buf; - int q = 0; - gWmoInstansName = new string[size]; - while (p=0 && z >= 0 && x<64 && z<64)) return NULL; - - char name[512]; + if(!(x>=0 && z >= 0 && x<64 && z<64)) return NULL; - sprintf(name,"World\\Maps\\%s\\%s_%d_%d.adt", filename.c_str(), filename.c_str(), x, z); - return new ADTFile(name); + char name[512]; + + sprintf(name,"World\\Maps\\%s\\%s_%d_%d.adt", filename.c_str(), filename.c_str(), x, z); + return new ADTFile(name); } diff --git a/contrib/vmap_extractor_v2/vmapextract/wdtfile.h b/contrib/vmap_extractor_v2/vmapextract/wdtfile.h index 7a7002a2e..0baef22f1 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wdtfile.h +++ b/contrib/vmap_extractor_v2/vmapextract/wdtfile.h @@ -1,7 +1,7 @@ #ifndef WDTFILE_H #define WDTFILE_H -#define __STORMLIB_SELF__ +#define __STORMLIB_SELF__ #include "mpq.h" #include "adtfile.h" @@ -12,19 +12,19 @@ class WDTFile { public: - WDTFile(char* file_name, char* file_name1); - ~WDTFile(void); - bool init(char *map_id); - - string* gWmoInstansName; - int gnWMO, nMaps; - - ADTFile* GetMap(int x, int z); + WDTFile(char* file_name, char* file_name1); + ~WDTFile(void); + bool init(char *map_id); + + string* gWmoInstansName; + int gnWMO, nMaps; + + ADTFile* GetMap(int x, int z); private: - MPQFile WDT; - bool maps[64][64]; - string filename; + MPQFile WDT; + bool maps[64][64]; + string filename; }; #endif diff --git a/contrib/vmap_extractor_v2/vmapextract/wmo.cpp b/contrib/vmap_extractor_v2/vmapextract/wmo.cpp index a0deab1eb..b56a79477 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wmo.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/wmo.cpp @@ -6,444 +6,457 @@ using namespace std; - WMORoot::WMORoot(std::string &filename) : filename(filename) { } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx bool WMORoot::open() { + MPQFile f(filename.c_str()); + if(f.isEof ()) + { + printf("No such file.\n"); + return false; + } - MPQFile f(filename.c_str()); - if(f.isEof ()) - { - printf("No such file.\n"); - return false; - } + size_t size; + char fourcc[5]; + bbcorn1[3] = 0; + bbcorn2[3]= 0; - size_t size; - char fourcc[5]; - bbcorn1[3] = 0; - bbcorn2[3]= 0; + while (!f.isEof()) + { + f.read(fourcc,4); + f.read(&size, 4); - while (!f.isEof ()) - { - f.read(fourcc,4); - f.read(&size, 4); + flipcc(fourcc); + fourcc[4] = 0; - flipcc(fourcc); - fourcc[4] = 0; + size_t nextpos = f.getPos() + size; - size_t nextpos = f.getPos() + size; - - if (!strcmp(fourcc,"MOHD"))//header - { - - f.read(&nTextures, 4); - f.read(&nGroups, 4); - f.read(&nP, 4); - f.read(&nLights, 4); - f.read(&nModels, 4); - f.read(&nDoodads, 4); - f.read(&nDoodadSets, 4); - f.read(&col, 4); - f.read(&RootID, 4); - f.read(bbcorn1,12); - f.read(bbcorn2,12); - break; - } - /* - else if (!strcmp(fourcc,"MOTX")) - { - - } - else if (!strcmp(fourcc,"MOMT")) - { - - } - else if (!strcmp(fourcc,"MOGN")) - { - - } - else if (!strcmp(fourcc,"MOGI")) - { - - } - else if (!strcmp(fourcc,"MOLT")) - { - - } - else if (!strcmp(fourcc,"MODN")) - { - - } - else if (!strcmp(fourcc,"MODS")) - { - - } - else if (!strcmp(fourcc,"MODD")) - { - - } - else if (!strcmp(fourcc,"MOSB")) - { - - } - else if (!strcmp(fourcc,"MOPV")) - { - - } - else if (!strcmp(fourcc,"MOPT")) - { - - } - else if (!strcmp(fourcc,"MOPR")) - { - - } - else if (!strcmp(fourcc,"MFOG")) - { - - } - */ - f.seek((int)nextpos); - } - f.close (); - return true; + if (!strcmp(fourcc,"MOHD"))//header + { + f.read(&nTextures, 4); + f.read(&nGroups, 4); + f.read(&nP, 4); + f.read(&nLights, 4); + f.read(&nModels, 4); + f.read(&nDoodads, 4); + f.read(&nDoodadSets, 4); + f.read(&col, 4); + f.read(&RootID, 4); + f.read(bbcorn1,12); + f.read(bbcorn2,12); + break; + } + /* + else if (!strcmp(fourcc,"MOTX")) + { + } + else if (!strcmp(fourcc,"MOMT")) + { + } + else if (!strcmp(fourcc,"MOGN")) + { + } + else if (!strcmp(fourcc,"MOGI")) + { + } + else if (!strcmp(fourcc,"MOLT")) + { + } + else if (!strcmp(fourcc,"MODN")) + { + } + else if (!strcmp(fourcc,"MODS")) + { + } + else if (!strcmp(fourcc,"MODD")) + { + } + else if (!strcmp(fourcc,"MOSB")) + { + } + else if (!strcmp(fourcc,"MOPV")) + { + } + else if (!strcmp(fourcc,"MOPT")) + { + } + else if (!strcmp(fourcc,"MOPR")) + { + } + else if (!strcmp(fourcc,"MFOG")) + { + } + */ + f.seek((int)nextpos); + } + f.close (); + return true; } -//--------------------------------------------------------------------------- bool WMORoot::ConvertToVMAPRootWmo(FILE *pOutfile) { - //printf("Convert RootWmo...\n"); + //printf("Convert RootWmo...\n"); - fwrite("VMAP002",1,8,pOutfile); - unsigned int nVectors = 0; - fwrite(&nVectors,sizeof(nVectors),1,pOutfile); // will be filled later - fwrite(&nGroups,4,1,pOutfile); - return true; + fwrite("VMAP002",1,8,pOutfile); + unsigned int nVectors = 0; + fwrite(&nVectors,sizeof(nVectors),1,pOutfile); // will be filled later + fwrite(&nGroups,4,1,pOutfile); + return true; } -//---------------------------------------------------------------------------- WMORoot::~WMORoot() { } -//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx WMOGroup::WMOGroup(std::string &filename) : filename(filename) { } -//--------------------------------------------------------------------------- + bool WMOGroup::open() { - MPQFile f(filename.c_str()); - if(f.isEof ()) - { - printf("No such file.\n"); - return false; - } - size_t size; - char fourcc[5]; - bbcorn1[3] = 0; - bbcorn2[3] = 0; - while (!f.isEof ()) - { - f.read(fourcc,4); - f.read(&size, 4); - flipcc(fourcc); - if (!strcmp(fourcc,"MOGP"))//Fix sizeoff = Data size. - { - size = 68; - } - fourcc[4] = 0; - size_t nextpos = f.getPos() + size; - LiquEx_size = 0; - liquflags = 0; + MPQFile f(filename.c_str()); + if(f.isEof ()) + { + printf("No such file.\n"); + return false; + } + size_t size; + char fourcc[5]; + bbcorn1[3] = 0; + bbcorn2[3] = 0; + while (!f.isEof()) + { + f.read(fourcc,4); + f.read(&size, 4); + flipcc(fourcc); + if (!strcmp(fourcc,"MOGP"))//Fix sizeoff = Data size. + { + size = 68; + } + fourcc[4] = 0; + size_t nextpos = f.getPos() + size; + LiquEx_size = 0; + liquflags = 0; - if (!strcmp(fourcc,"MOGP"))//header - { - f.seekRelative(-4); - f.read(&offsize, 4); - f.read(&flag, 4); - f.read(&flag1, 4); - f.read(&Xid, 4); - f.read(bbcorn1, 12); - f.read(bbcorn2, 12); - f.read(&Xid2, 4); - f.read(&Xid3, 4); - f.read(&zero1, 4); - f.read(&Xflag, 4); - f.read(&nTexture,4); - f.read(&GroupID,4); - } - else if (!strcmp(fourcc,"MOPY")) - { - MOPY = new char[size]; - mopy_size = size; - nTriangles = (int)size / 2; - f.read(MOPY, size); - } - else if (!strcmp(fourcc,"MOVI")) - { - MOVI = new uint16[size/2]; - f.read(MOVI, size); + if (!strcmp(fourcc,"MOGP"))//header + { + f.seekRelative(-4); + f.read(&offsize, 4); + f.read(&flag, 4); + f.read(&flag1, 4); + f.read(&Xid, 4); + f.read(bbcorn1, 12); + f.read(bbcorn2, 12); + f.read(&Xid2, 4); + f.read(&Xid3, 4); + f.read(&zero1, 4); + f.read(&Xflag, 4); + f.read(&nTexture,4); + f.read(&GroupID,4); + } + else if (!strcmp(fourcc,"MOPY")) + { + MOPY = new char[size]; + mopy_size = size; + nTriangles = (int)size / 2; + f.read(MOPY, size); + } + else if (!strcmp(fourcc,"MOVI")) + { + MOVI = new uint16[size/2]; + f.read(MOVI, size); + } + else if (!strcmp(fourcc,"MOVT")) + { + MOVT = new float[size/4]; + f.read(MOVT, size); + nVertices = (int)size / 12; + } + else if (!strcmp(fourcc,"MONR")) + { + } + else if (!strcmp(fourcc,"MOTV")) + { + } + else if (!strcmp(fourcc,"MOBA")) + { + MOBA = new uint16[size/2]; + moba_size = size/2; + f.read(MOBA, size); + } + else if (!strcmp(fourcc,"MLIQ")) + { + liquflags |= 1; + WMOLiquidHeader hlq; + f.read(&hlq, 0x1E); + float ydir = -1.0f; + hlq_xverts = hlq.xverts; + hlq_yverts = hlq.yverts; + int noVer = hlq.xverts * hlq.yverts; + float tilesize = CHUNKSIZE / 8.0f; + LiquEx_size = sizeof(float) * 3 * noVer; + LiquEx = new float[sizeof(float) * 3 * noVer]; + int p = 0; - } - else if (!strcmp(fourcc,"MOVT")) - { - MOVT = new float[size/4]; - f.read(MOVT, size); - nVertices = (int)size / 12; - } - else if (!strcmp(fourcc,"MONR")) - { - } - else if (!strcmp(fourcc,"MOTV")) - { - } - else if (!strcmp(fourcc,"MOBA")) - { - MOBA = new uint16[size/2]; - moba_size = size/2; - f.read(MOBA, size); - } - else if (!strcmp(fourcc,"MLIQ")) - { - liquflags |= 1; - WMOLiquidHeader hlq; - f.read(&hlq, 0x1E); - float ydir = -1.0f; - hlq_xverts = hlq.xverts; - hlq_yverts = hlq.yverts; - int noVer = hlq.xverts * hlq.yverts; - float tilesize = CHUNKSIZE / 8.0f; - LiquEx_size = sizeof(float) * 3 * noVer; - LiquEx = new float[sizeof(float) * 3 * noVer]; - int p = 0; - - for (int j=0; j0) { - if(fwrite(MOVI, sizeof(unsigned short), nIdexes, output) != nIdexes) { printf("Error while writing file indexarray"); exit(0); } - } + if(fwrite("INDX",4, 1, output) != 1) + { + printf("Error while writing file nbraches ID"); + exit(0); + } + int wsize = sizeof(uint32) + sizeof(unsigned short) * nIdexes; + if(fwrite(&wsize, sizeof(int), 1, output) != 1) + { + printf("Error while writing file wsize"); + // no need to exit? + } + if(fwrite(&nIdexes, sizeof(uint32), 1, output) != 1) + { + printf("Error while writing file nIndexes"); + exit(0); + } + if(nIdexes >0) + { + if(fwrite(MOVI, sizeof(unsigned short), nIdexes, output) != nIdexes) + { + printf("Error while writing file indexarray"); + exit(0); + } + } - if(fwrite("VERT",4, 1, output) != 1) { printf("Error while writing file nbraches ID"); exit(0); } - wsize = sizeof(int) + sizeof(float) * 3 * nVertices; - if(fwrite(&wsize, sizeof(int), 1, output) != 1) { printf("Error while writing file wsize"); } - if(fwrite(&nVertices, sizeof(int), 1, output) != 1) { printf("Error while writing file nVertices"); exit(0); } - if(nVertices >0) { - if(fwrite(MOVT, sizeof(float)*3, nVertices, output) != nVertices) { printf("Error while writing file vectors"); exit(0); } - } + if(fwrite("VERT",4, 1, output) != 1) + { + printf("Error while writing file nbraches ID"); + exit(0); + } + wsize = sizeof(int) + sizeof(float) * 3 * nVertices; + if(fwrite(&wsize, sizeof(int), 1, output) != 1) + { + printf("Error while writing file wsize"); + // no need to exit? + } + if(fwrite(&nVertices, sizeof(int), 1, output) != 1) + { + printf("Error while writing file nVertices"); + exit(0); + } + if(nVertices >0) + { + if(fwrite(MOVT, sizeof(float)*3, nVertices, output) != nVertices) + { + printf("Error while writing file vectors"); + exit(0); + } + } - if(LiquEx_size != 0) - { - int LIQU_h[] = {0x5551494C,LiquEx_size+8,hlq_xverts,hlq_yverts};// "LIQU" - fwrite(LIQU_h,4,4,output); - fwrite(LiquEx,4,LiquEx_size/4,output); - delete [] LiquEx; - } + if(LiquEx_size != 0) + { + int LIQU_h[] = {0x5551494C,LiquEx_size+8,hlq_xverts,hlq_yverts};// "LIQU" + fwrite(LIQU_h,4,4,output); + fwrite(LiquEx,4,LiquEx_size/4,output); + delete [] LiquEx; + } - return nTriangles; - } else { - //printf("Convert GroupWmo...\n"); - //-------GRP ------------------------------------- - fwrite(&liquflags,sizeof(uint32),1,output); - char GRP[] = "GRP "; - fwrite(GRP,1,4,output); - int k = 0; - int moba_batch = moba_size/12; - MobaEx = new int[moba_batch*4]; - for(int i=8; i MoviExSort[i+1]) - { - hold = MoviExSort[i]; - MoviExSort[i] = MoviExSort[i+1]; - MoviExSort[i+1] = hold; - } - //double = 65535 - else - if (MoviExSort[i] == MoviExSort[i+1]) - MoviExSort[i+1] = 65535; - } - } - // double delet - uint16 s = 0; - for (int i=0; i < IndexExTr_size*3; i++) - { - if (MoviExSort[i]!=65535) - { - MoviExSort[s] = MoviExSort[i]; - s++; - } - } - MovtExSort = new uint16[s]; - for (int i=0; i < s; i++) - { - MovtExSort[i] = MoviExSort[i]; - } + uint16 hold; + for (int pass = 1; pass < IndexExTr_size*3; ++pass) + { + for (int i=0; i < IndexExTr_size*3-1; ++i) + { + if (MoviExSort[i] > MoviExSort[i+1]) + { + hold = MoviExSort[i]; + MoviExSort[i] = MoviExSort[i+1]; + MoviExSort[i+1] = hold; + } + //double = 65535 + else + if (MoviExSort[i] == MoviExSort[i+1]) + MoviExSort[i+1] = 65535; + } + } + // double delet + uint16 s = 0; + for (int i=0; i < IndexExTr_size*3; ++i) + { + if (MoviExSort[i]!=65535) + { + MoviExSort[s] = MoviExSort[i]; + s++; + } + } + MovtExSort = new uint16[s]; + for (int i=0; i < s; ++i) + { + MovtExSort[i] = MoviExSort[i]; + } - for (int i=0; i < IndexExTr_size*3; i++) - { - uint16 b = MoviEx[i]; - for (uint16 x = 0; x < s; x++) - { - if(MoviExSort[x] == b) - { + for (int i=0; i < IndexExTr_size*3; ++i) + { + uint16 b = MoviEx[i]; + for (uint16 x = 0; x < s; ++x) + { + if(MoviExSort[x] == b) + { + MoviEx[i] = x; + break; + } + } + } + int INDX[] = {0x58444E49,IndexExTr_size*6+4,IndexExTr_size*3}; + fwrite(INDX,4,3,output); + fwrite(MoviEx,2,IndexExTr_size*3,output); - MoviEx[i] = x; - break; - } - } + delete [] MoviEx; + delete [] MoviExSort; + delete [] IndexExTr; - } - int INDX[] = {0x58444E49,IndexExTr_size*6+4,IndexExTr_size*3}; - fwrite(INDX,4,3,output); - fwrite(MoviEx,2,IndexExTr_size*3,output); + //----------VERT--------- + //-----MOVT---------- + int d = 0; + MovtEx = new float[s*3]; + for (uint16 i=0; i> 16; + doodadset = (d2 & 0xFFFF0000) >> 16; - int realx1 = (int) ((float) pos2.x / 533.333333f); - int realy1 = (int) ((float) pos2.z / 533.333333f); - int realx2 = (int) ((float) pos3.x / 533.333333f); - int realy2 = (int) ((float) pos3.z / 533.333333f); + int realx1 = (int) ((float) pos2.x / 533.333333f); + int realy1 = (int) ((float) pos2.z / 533.333333f); + int realx2 = (int) ((float) pos3.x / 533.333333f); + int realy2 = (int) ((float) pos3.z / 533.333333f); - if(realx1 < 0) - { - realx1 +=20; realx2+=20; - } - if(realy1 < 0) - { - realy1 +=20; realy2+=20; - } // hack to prevent neg. values + if(realx1 < 0) + { + realx1 +=20; realx2+=20; + } + if(realy1 < 0) + { + realy1 +=20; realy2+=20; + } // hack to prevent neg. values - //-----------add_in _dir_file---------------- + //-----------add_in _dir_file---------------- - char tempname[512]; - // const char dirname[] = "buildings\\dir"; + char tempname[512]; + // const char dirname[] = "buildings\\dir"; - sprintf(tempname, "buildings\\%s", WmoInstName); - FILE *input; - input = fopen(tempname, "r+b"); - if(!input) - { - return; - } - fseek(input, 8, SEEK_SET); // get the correct no of vertices - int nVertices; - fread(&nVertices, sizeof (int), 1, input); - fclose(input); - if(nVertices == 0) - { - return; - } + sprintf(tempname, "buildings\\%s", WmoInstName); + FILE *input; + input = fopen(tempname, "r+b"); - /* FILE *dirfile; - dirfile = fopen(dirname, "ab"); - if(!dirfile) - { - printf("Can't open dirfile!'%s'\n"); - return; - } - */ - float x,z; - x = pos.x; - z = pos.z; - if(x==0 && z == 0) - { x = 533.33333f*32; z = 533.33333f*32; } - fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", - MapName, - WmoInstName, - (float) x, (float) pos.y, (float) z, - (float) rot.x, (float) rot.y, (float) rot.z, - nVertices, - realx1, realy1, - realx2, realy2 - ); + if(!input) + return; - // fclose(dirfile); -} + fseek(input, 8, SEEK_SET); // get the correct no of vertices + int nVertices; + fread(&nVertices, sizeof (int), 1, input); + fclose(input); + if(nVertices == 0) + return; + /* FILE *dirfile; + dirfile = fopen(dirname, "ab"); + if(!dirfile) + { + printf("Can't open dirfile!'%s'\n"); + return; + } + */ + float x,z; + x = pos.x; + z = pos.z; + if(x==0 && z == 0) + { + x = 533.33333f*32; + z = 533.33333f*32; + } + fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", + MapName, + WmoInstName, + (float) x, (float) pos.y, (float) z, + (float) rot.x, (float) rot.y, (float) rot.z, + nVertices, + realx1, realy1, + realx2, realy2 + ); + // fclose(dirfile); +} diff --git a/contrib/vmap_extractor_v2/vmapextract/wmo.h b/contrib/vmap_extractor_v2/vmapextract/wmo.h index 589e9113a..d57340855 100644 --- a/contrib/vmap_extractor_v2/vmapextract/wmo.h +++ b/contrib/vmap_extractor_v2/vmapextract/wmo.h @@ -30,86 +30,83 @@ typedef unsigned int uint32; class WMORoot { public: - int nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootID; - unsigned int col; - int bbcorn1[3]; - int bbcorn2[3]; + int nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootID; + unsigned int col; + int bbcorn1[3]; + int bbcorn2[3]; - WMORoot(std::string &filename); - ~WMORoot(); - - bool open(); - bool ConvertToVMAPRootWmo(FILE *output); + WMORoot(std::string &filename); + ~WMORoot(); + + bool open(); + bool ConvertToVMAPRootWmo(FILE *output); private: - std::string filename; - char outfilename; - + std::string filename; + char outfilename; }; class WMOGroup { public: - - int offsize,flag,flag1,Xid,Xid2,Xid3,zero1,Xflag,nTexture,GroupID; - int mopy_size,moba_size,hlq_xverts,hlq_yverts; - int MopyEx_size,IndexExTr_size,LiquEx_size; - unsigned int nVertices; // number when loaded - int nTriangles; // number when loaded - int bbcorn1[3]; - int bbcorn2[3]; - int * IndexExTr; - char* MOPY; - char* MopyEx; - uint16* MOVI; - uint16* MoviEx; - uint16* MoviExSort; - float* MOVT; - float* MovtEx; - uint16* MovtExSort; - float* MONR; - float* MonrEx; - uint16* MOBA; - int* MobaEx; - float* LiquEx; - uint32 liquflags; - - WMOGroup(std::string &filename); - ~WMOGroup(); + int offsize,flag,flag1,Xid,Xid2,Xid3,zero1,Xflag,nTexture,GroupID; + int mopy_size,moba_size,hlq_xverts,hlq_yverts; + int MopyEx_size,IndexExTr_size,LiquEx_size; + unsigned int nVertices; // number when loaded + int nTriangles; // number when loaded + int bbcorn1[3]; + int bbcorn2[3]; + int * IndexExTr; + char* MOPY; + char* MopyEx; + uint16* MOVI; + uint16* MoviEx; + uint16* MoviExSort; + float* MOVT; + float* MovtEx; + uint16* MovtExSort; + float* MONR; + float* MonrEx; + uint16* MOBA; + int* MobaEx; + float* LiquEx; + uint32 liquflags; - bool open(); - int ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData); + WMOGroup(std::string &filename); + ~WMOGroup(); + + bool open(); + int ConvertToVMAPGroupWmo(FILE *output, bool pPreciseVectorData); private: - std::string filename; - char outfilename; - + std::string filename; + char outfilename; }; struct WMOLiquidHeader { - int xverts, yverts, xtiles, ytiles; - float pos_x; - float pos_y; - float pos_z; - short type; + int xverts, yverts, xtiles, ytiles; + float pos_x; + float pos_y; + float pos_z; + short type; }; class WMOInstance { - static std::set ids; + static std::set ids; public: string MapName; int currx; - int curry; - WMOGroup *wmo; - Vec3D pos; - Vec3D pos2, pos3, rot; - int indx,id, d2, d3; - int doodadset; + int curry; + WMOGroup *wmo; + Vec3D pos; + Vec3D pos2, pos3, rot; + int indx,id, d2, d3; + int doodadset; - WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, FILE *pDirfile); + WMOInstance(MPQFile &f,const char* WmoInstName,const char*MapName, FILE *pDirfile); - static void reset(); + static void reset(); }; -#endif \ No newline at end of file +#endif diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 649859178..71cf82c94 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "7908" + #define REVISION_NR "7909" #endif // __REVISION_NR_H__ From ec1d6a3b56f58efeb798253893e47f460920708e Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Fri, 29 May 2009 06:17:28 +0400 Subject: [PATCH 7/7] [7910] Resolve problems with vmaps extractor support 3.1.2 archives. Binary in contrib/vmap_extract_assembler_bin also updated. --- .../vmapextract_v2.exe | Bin 217088 -> 223232 bytes .../stormlib/StormPortMac.cpp | 2 +- .../vmap_extractor_v2/vmapextract/adtfile.cpp | 33 +++++++--- .../vmap_extractor_v2/vmapextract/adtfile.h | 8 +-- contrib/vmap_extractor_v2/vmapextract/mpq.cpp | 38 ++++++++---- contrib/vmap_extractor_v2/vmapextract/mpq.h | 24 ++++++-- .../vmapextract/vmapexport.cpp | 58 +++++++++--------- src/shared/revision_nr.h | 2 +- 8 files changed, 105 insertions(+), 60 deletions(-) diff --git a/contrib/vmap_extract_assembler_bin/vmapextract_v2.exe b/contrib/vmap_extract_assembler_bin/vmapextract_v2.exe index a1e982f0cba4c1f9e03853f24860d40430df3679..213705f6cdf5f8ee860b6cd573b1297588e5b12d 100644 GIT binary patch delta 55878 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 WL80zOxmUb8SdtEx&zz$^D*ZoB#XCFz delta 50429 zcmagH4M5Y?_dmY-X5iG}rVgBniaHeq6$2H-2UI{T#EplciJ@@{UQ(&v^%YheXDXE*=?avo5`AeT1AW!E zzEu?gDwSHLTKZjpCxP{8cOfu9HIiU92B@|(&vI!*=+@sPLU8*JD0A7)H zNBKAFftfmc-t!ad-tO7yNK(If_nN0q5-NSx zFhr%=6^`WYDOC6f6~44R8ik2ec+{X^m_o$|Vg~?&CdBh`>+wTuE~auG*47-ypV^Wj zMCt8(c8*Qe0S(?h8mv+ksIuiI5$~!@Zqr{QwOj6)-(hoyF5^`<50#a-+5o(BWka&Q ztEW%L^vurVReQj9)u-Ra{9O8pJ=rtIMi2b)7v&I`--aC=uQ0^}2Jye8Za2x$>`$uQF-g zc-mjJ(m{a-c00WbzyzAK;nLuAnk#Dj=o>!xGu|bu21A9x7y3*quyjZ&MuIKvT z=cTH5J?o>VOIzNpyc(Sw0LZM^U-3*D`Usxeht8B@D?OctrJ?ccVOgNGvT{#c6w?oa zD5RO9Tv?_t+2F1l&~-3+Tw!XfQpF+VS`mR%?TTnT(*}E<%pJ@od3NMJAbl~cvgh;+DJ}`9<~sMS zS=0u&3LntzSUcWV@~p2UPPe0M+#N76fEl~9@{Rn)fL0s#fnDLdJX>ddCp|vcw69)6h4(ZU_6@Dvwsf;(7%^V8q+>%X_ZAbFt{NM!cF!K+nY+9@8&O%hymt_$ z=)WtY^{1(A`*wbW7qy=Hl~;WfwF&kYe&4q8QrQ$NmDZJaubRa4Tc}B98-MMf)|LN} zt0Yqql{#DbOY?$|IBbwto1(FD^7E$092XA-dgL|rG0}$rxQOa$xRyWyG&+k-Ce`#M zL!5s}#i6z)rH5vaL4ltCJY|=rX*}K5c9YtwJtNneq_BX>`_}fAFc{Y}BN!XudA_`x z=Nr#16g*$PTaALO=Ze{A&&SW*uRLQs^PZ1IYSZ)g;i-Nh1J9fnjsULvhC(zd-|!M) ziFxUDRGfe5WjvR@{G9R}?wP!C8d7g;d{W69J$G-Kf+m|cos_H>Fd9V=$-*2zZWTXy zy|~*He^RNIA2vd^eFQr%PT90}lIOMm_G^EM&~>}$Z`kyc%5(m|k^JrX>z7gK|IYbK-#hCG-yIrROoiK<3!gfx zQcZwCPPkEAXDgzr=bEeRXDes!9xv&0sWjz(ek?t|^laa|MxRE7Tfg)dI?s4A_I zQy)!*Y62(bef^QA@o+v^XMO+sApHia+jh)fx9Vu+J;&cuOT~vaOCRg>y7I)gb%D~vH$2eY@Sz%?f_`NZui}$`gNiW~UB2q2VrpF{O?6 zAz)6pCEF?n-tfG0xr_A84$q0pg%Jfi6wZ}a74~&cRLLKTYd5^!giH2#fQRW0SiR|% zj2w})!&C6va6N2_#wuUViO(}E3=|7Cd3yeyCgtw%Jo5W+L*2{cRI@jc5;8k4YBQ}l zBz1d!&xz^^gwDenSF)xdLQdAW=3H_mi^Kwz`AG70N!+;Z^`Z&@y9Rp`J)^Ef7-F{* zNqVQls9&I!C#x-@*G|u4SH??U?eHA95+>cf({t|1U6Q=RqyHnOOX$l?ReDzU%7&*DyOK`59Fvv-!u*e$;wYqUl3BMQiDDVc{$dONq$3c2_feNYl zNacg?)2AKMs(jtQ{v!Eh#)R61UF8&mnc)BDiMg61Io|QCz8WWudeL*_swwj84L<7M z0QD`1KZ;^s>mJRmn>-;+bEKy#JjG2<8}_}>Tpuo54H<;}qNnGz6zP?1o(HbgM85bu z(EhA@a-|>b4IfcYqPQ8Yzu68?&Yv05jJG{+{29?P^)`!~7sE5HG=)F>nIg^q)ARLT zT|B9OwU;U?JYV1F*@Z+JJpH!@&;DhXyxR!MGw}M8!=Jp36VgXgFhYVZcXd*iyN_V z^7r5>F>OFDvt^$prtK*5cUxjQjEsEEov)WabQPP7t|XI5jDQDJQl%@s3;U>DI*=Fh zGcYx2R4Uh-rYrb5QewJ*FUsyidk1Q(e6{<0wQo{wfx1AQ?Oq&VoADuBv6E z``zm`W3~=o@p@}ZOj`g;odDTJU+cBhTAnbnAjnzurx{B<)}k~&isq77g0)oO%{IGN zo7Vf_9aIq@-oJ`PR%}YrqbDLuS`ZAcF*-xkze$TpUBEC~xuC`0QfvVsC{(p9#MbD< zZ~sy(#10fk-k6+|Nb?rk+`ahqy4L}Eu$F=LqK_b=M=gf^3q5J3Xp6YlM~}Qu8Sp>I zYUd;C4q9a)t}6Xg_gSXcjOH;sie=|$?tc62?gPax?63aLjwDmGS)9W{13Tcc&}_-` zOh!3*q+G7dY-F{&xV;p4D90%znxo!COE@~C`L-xMi~K*aaa(Po&Mankxv9i~>B<1p zPh;3Y;xeiW!ihQkzt2>LFSMZE#g*5U zk-D}krI0n+2h!gWRFf2wm}ui6Giaeq%^_b4xx{o7gkVu7p_fE|lW4+!4&@75xqSd; zTN32SA*6S(=Hf`qLt^O}JQ7c=iZ_AZRc_jfueowaA_~!va<*us&92p^T~q}SqC{9; z#(cn5>CtgGb|j?-(6h||P_eN>8H%5P1$xXLQD_nEUspM3I%CfI7_(iW(6zyI2GwO7 z6ezT!RfbmOCR$t>;@p3mIYSkIrlkjHss(fvz5tB@AYm47--4zJK$GAAnrZ>5t3l%6xG8xUtJ%QY+64QEAu3Bw+ zfxgO3&*Q7C#Fr~EJx4h#e0<3tmX-VR{Yn%l%qQVhi7UVZ$J7vT1nMkpx7Nq@^{shz zTQ(rHWONYXDC*`ym8u~CR-exZU;_+Pa~=K(W{J8`b`;bqad>cFTRZ) znjmCGaNeBbo}`EJG>LS`APNogCH`U>>+Z+{7yv*;gkRW#ORMZ%Y?r)=D%&YMtZtjS zAS~MzEl$1#LZq0Vp|K1QMWb8YsaZZ<4`>sbbk2itXJgL#H#u^x+ssyJ5=)L1UW+_r z&JkTN!WplH3jrxNfOJ|U4y5(O5&Qv}ijwYBri^!$KC$Ezw5Yy@8ZN?Y{SB{E}`{5nO&}kbA}kSMVStT8}QZxjwW2w ztq7x?DWYN-;`mlSubtrQ?$ft;-M%d|hlVSvC(XS?ZyJ*&kNX zX8z6Ae0?yB?7056tLwZNrTEhP^I+DugI)`+VtdzYuZ4rRYsWgVPP}hBHev{wZA>=_ z1)w4X`5DUe8_2K3X|JWKwcSNTjm z>*6>{nOD{TU}YU(t(oZ6RG_v%Uqp#jC`U<_X=H&q!oL{WqgixrfpHgM)U4rQ z?U`}pFK$06an!yJIV^xg=i%tmszn{GW_e{27IA@O7Vo19UXnsn1!36k=JVUL?)q{c z2J9HnnRwF8Uuw^Cdq?=dWj+$^GsJ$#oe!5;yo0n=c%I_jI(Kbi6wQ~pu)$4V!Y%o->ilmgU$U8h z(~%{Qy$&XsMZZ#FTdus?G!otnZPuq@eZ`i5p6{n0(kn3_@~xx^xTdq;l1f!*a; z2J~1s?1a%d5&t)4*G*E2%0RBf7wP#lL4m(SpwMTUq$dwk3gBv1KEXpsC-2 zqUGcmD%AxrqNPHds{zZdvuBTJR8JenthpL+-D@=&q zt%X?N$m4Qp)l#h`!(tWLiW$*^xSHb#b=3yVz|=XHnv?*M-Yf!v4h)H@s!cH|_9P{| zEJZJ$%&WJq3JqTkRT9jGoY&U zXS*grsjvr%02Czrt}B5pS3x-RR}lp-{kbqz{PYrJwJKr0enFr(k2L1PC~8`54$`2-F1gSFRpphRo zMAlc|kbuibiu@j|_DnfXFV{p?L;iMS5sryGn(z@~#81O#b8F)g>UGYQ7?J$`$6}9C zeJbIzg@jBB5U3nikCS;}`U@jWcW9v`OZA`KYi=veGCzE?^eIz*6wxXX{Y78QVgzieI99hLJlP1@~29h zgfHaw?x_7V`>rg9DSY8QZf%4mle!zHVAsn>BWYs_DypwZ8Iji%Ql3OKjyDS{g&|AKA20UlH*vGjRT!r3TCD5x~Z8kf#lt9C8b=jUO9 zuwD{ALSsgaY2O}%>45<^5Yw(;j+&ub4C1(zR*+V{Y^4>MBZ6nb&SSRv%R#oSkZ6dz zL42s_H*yZOmffUggu@DnQM8sCcSgvPZuPcAOPZJgQJrNFXOV(Hj8?8Uewy?iVgy=mnPtJ9lDFMBFl%~ zt%l=CQQ26avB9`6^M+^~69*P1Ne5H(V}2rtDgd?&)U zHl6mk=9*hY%Xa+=*j#(}oP*S8vU|2kwQ2&J05_%yAv+V$&vkXm4_6wdHX}@B6nSZq zgTts^4hcWOV|ugRY!=Vy&3b6op2VIW8)zlq)V3rHxAay{im#to3)>F&@;3`Qh^1Zhg`L6N~5DeS$mM0o(QRF|-;G_DouEa^*lQ$uWn`R&> zr$r=M+~uZR#NurGKs)09aGaI8fcMQ5W8OtoTTo>YCsBoq6=>%?9OhOJpz5utrcGeD z7|{nJU2d9!f|#@98HQmiyq!p@Kn)^B`7z!c2f6#kt>;s3MB^GZ2Y9rz<73dQRz$-eN z&Hbpw%K+8~J5xg>yWjD`!_e-x zSmYlA5Po|b;qr?mh*~vk_7c-Frv;hr79R>uwcQgjVQvV!WWSr z@u3otM{&7=rSnncw2Yeh!`91+6mU>bIvO1pBr|1yR8gc>`=0bu4v zW{5w)J#aXtQFkCIHr6bp%Ex&8K-SY?2dn3U$@9u`O}S+7l&CF?TQe0&rXrHn8KUeX z#MpBwl81Q~H&zhB=7WiiC}QZ)0LUp81j+Xf$H*^X)rK_$0ehJIJGN^$Bci4bM6zI` z(rwWnjdS1{30MGyL=kGxYRB&7>$`y)Wa;Hg&|K7pG?#L~mTM7t{+?UVT|Wb^5;(h- zSVVEH43VU`0vcIlLpiSLtq4-MoT8>#!?C|A#*5UNryWSTx0}i#Y0h70hab_A zsYJw7HE8_ydhMz-wY_Y$ngEG42IRM;XG`F&}Zo&P~ejpvyg}&HXWDf6Gwci9Ip^sfYK}^iNKRkL{)%B zRFoz{5{s5M&qN%`h+6@e2|b`k(oD=AMl*5ixPs~>(PN-ud?xE0J3=0X>B=B3?d^q0 zL^Ker&(ixROF0KkG>eOhOsS!V!X_jKE!`Vm|3977NfwYYy`A$T20}+74wl5nuRo6B67a| zPU%Q8<(fs3pU`=xXyBah=c^*!4cPyaiG!eFWgC`nF_kdr0f^QUV3r*>o*zslUe$M^ z-3peuS-egK&_zCV;)Ilj?ehFhr%Zr`1_+(d+>NbCe6Go454N45;SYLJ=?&%)r%qse zvkLczr2UC+Q{y%1%S`)@-L#2M1F5ws;mRQL!mMR^S~1MQ`wU?{2k5ul zvVhKu8s9}BY*pVkyOXc@G%~IT!T7d!@cBd7VD=E-h-U59FIAAz&Ovl?@Q;SDC|%EE z*e@LkOSoG2Gqy}Md_)%(#h&H-E;g{Y5vK%DOk~NA`z+4HmL12Eef#k)HY@lpC@EZ^ z!EGcaj_{lq*26aUk7m4=W6ow~iUUi~_Yy%dph>4K!bDk2#SwYZmD`M&CQrH;b3)kX zg7M!^_xmAmLPQa5wr~eXTr5UaJ416eS6WWZ5T^y^(L0o-G_J z4zy_UZYiHVlx4JE)^hZ;>*2LSS)p|5H$Hk8i)0;n!7#?#o~3h2B4XQPTsxeN4Swu4 z*DpTC?;Xw}rJYCk%Hix$Dd|uC=WsThK;-1DX7{A+LUn|Xj$;%0?7T+IH&W5+YGC{q zJ}sTeUyoxcA*K~*j>Xwxm)d>>4~%CcLq3ImkcZ_!#OYFi9s@LpT5gSJYrCh=$=G2d zPFh|0*pN=2hII;`AfW+U(hkeHdITHX_v70mUVgC**5;L_s*_6uYss3Vv+_i;}SP#vhdy$sM;9S*EKLSbtj_r@WYnS^UR~n)B zk>UW^@-&m#B8C7J^hhEdc}x+#?R@=6*2giOmU1~5bK8Z6S2gR^TdQ^X#npE(ky!dS zuZrFU@vY%yqvk_9tKd-3ODS+YqA{ef?_mOHLuae{7)nN^P)A$+Sh3uJkg#nlilG|c zL=*ZGUqiNhTi(?s3Y*(D0>C29`n(9J*W3))81g~Dd723vE_l6#-E20(zsV=O3jTL7 z4Y-uiM+2IMMgy{P(03A|k%rboZ^*I}xB6T2Q9z+|RIrkVKW(bx!{ zLiJIq-iMT!jp{r2wjHGwF$1oJGVvh3f|w@ah_=H#Sd!#R@i<4oBKr}G0RoqXsBcihJd-09y67~O6`RZ?(jQ}-h~f4U2T@3JN?WW- zr1z2w>|U&n&o?e;EeAEUq9AUae8g-kqQ2koc|T~{MU=E?T7P=@%YT!IbLIw7|iE=0rvahh_5hzsgONlJR zLBdL04HI?yz*V~`8vPhDlp7f&FOm?jTnd+(BMe^2J#kx9-hAxlwDMd z94$W5f&?EDn^s}!A5bjlo!AUY{*?g7t>}{(kjlzcnDNk5r z)bX4%*B-Wi9N3&o>PJOa*83BD6Hv|>=@JmOK_zOOg zvYov(Lv}?<6%px*4Kt)vS;YldEzJYTLppx30pl3nyo#?Xlqa_UibvYX>&7#KLa2Y) zu2pRCD5%V4LI*io3Q!2B^a&8miJ!_=qR0P1r6NaT=G~@p4c2Zml`D|`S1KQ90W^J) zik}~kD?G$ZpUm5e6(O97Gp1%5yYr?*KQn!ce)KLsGfC9^WNJhzZ1dkugd%D49#ly5 zDgDoY*vHk*;%%(i+oLrfKHb0R)T_@tsCw%APtN_1gp1G4k!{jq!`;c9Lbptc zZadrL@XfDL+Sul!q1dbFMNI*$r?El_iyQDIhfwUo>d5eh=#fPLFvMqFF<8T>o#?iZ zw$8NqPZB|2DiRchE3?Z`BO1>jkARjL(^P^2Cayr5Ku2OE{HZ&3Qy)~<_rT1={2cIs zuH+BE#+*gW@5}=j9d0|Q9Z-c~z_JWAQo>F9Bp?|HO%WG)@(whIe1RUZptbk}E0Q3b z#WA=F(@wU>sI9n&@f~Pv(7XM)&nQPROuLDQB=ig;3&SanI_8sx)|lxjk)K!p>5$N2 zmV7PpX0=yJ_;X=f7sHvQ3uO%^`C7tdXsTJ%AEW@B2(#cMhc1sJoh35B1tJ$?j{66( z$pMGpg2yx_2;GWccrIvxOCK+PM-!)x2V-@mb6^Y{1+n6!4ITI|BZS4A^^+T**vo|9 z?IR09Y*R3iz%U!!Du!!XRF-S9iH`39EjfCMWukdd!=Q!%t4jQct(z?9N*~-fBZKF- z48>Gs?}_DPr_FkjX@=P$BGEfY0%kif&p(1vm3%_f9sz>n@R(zp=fPXulZ2Kn?oZ70 zsri`3%@ib$??y0-7RGoLOKOE^M3{kN7U9sy?Um3s9SDV6W*34TSbz7IceR?OhioD3A#6};1xe!O9HKJ}OM$Kg8v#gv(1`6YJz9z_P2IuQO=RJN*ngZ` ziiQNj=UO1VQzzc}GE5Q<{BbrfcJuPP*(fRUT~GHLod#1VL*Yu`e_C+G2zkHF6$5h3 zJKN6pu>Ou!$Gu*t&{=Ybaz{Uy?&xn)uIQI5s|fe-3Bz1DSh=EKuH=*}`WdbgQv_83 zBnsc+=oHLyQ_Rm06jEpjHwq2D3;LaX1_S%6!-ygxAQz%^sw>^B=GFJGj=HTM!l9-O zg^>>QpXcA*!%{kS1Q0ZrL2e4T34F#q=RV*g(^#T0j`SuhG^9zslwoz>qlM%|hlAY9B6*JgB6*y!*?4^#%Ng|M+c;9f%*TOh{I3!ZzNTm-xryS$EiZKE zi21MahbOTZ%ROj=ySAiYC^{F5cC;5$_Gdf-wAIR8Zm7JGz#1U(-%>;*!ne8lxPrf!&N_DqsvsJ* z%IiI8rd&WL0yTOBZ=3^4Q5N zM>>$t-ILjv_QWF#U9Ek7Hr@4$oXx+Q%sNTg`Mhy58zyzj=Y!0wXD>H&3+81JzG(Y1 z3!6ghiJ~0gu<%FCI11{S%DI{K8AO*VQbRbo(?cqkH8Cp3CjF9A@pS%^nRUhKO^}6kj~|p#zCvjHp4R6%Cb!J zgg%|?vv4prcs5^Y!A*p5_bGbD=!>nIaLEbs1`cGPMU+@J$rp7+umSXlN0F7+lmj3; zhpt4A%gu0j_MgqurIMvz2>;_xWr=%WdDf~v*vD9Hj zE39p51_#2O)f%sPndvtOM4-}6Pwj$jQ>dNU*N$Kz_e8)qX@p6EG1y`WCh8XM0faiq zguCmD2FTX=+2#T%Lsa-0B%mDB=sz8SCVzqjSQsFuDO(vXs8{ZRmbApKQ2x;^&=cAG zdIru+l5fNKsa)%W0hI-qtUkBv4YrG9jOO3M@i4lRTY7VBb>>}$PpHM8E$;W50aZ{G(E36A6PG^}S?huM-aS%r` zzWGw_mR2C!QYbc3-Y*n!geWD#9OI2SE54k;zsh1=r2RAawJet1c2^!M)8|>lwmg0! z8x><`@WO0nl@k2<6ZyP8o7GF-=JC^3wr%p)6A0VLY_}m%PO)du-QD90HnMTGOgFx;fsgCisa78Xm=bz-Tmpfce0oaqvP)#yz7T=_B=M*+n zdObzqsbdY*`+3@TnxCh|xIBimyoTCYL_10=KMRr}Bub}@1jlDX_kj1{`%7b*`QFkT z`rh}vZFrm)Bbu!atW~qg$()Kv;^`_cI0&gXz%5A<$p=WS*!$SFlE@FhKp`Sj3yqOP zI#zT%s08PVq3_&}L@N!at6cdbMH{85t~3QTGFcGi?L!KlY~1g+DAB%s)mr3NVd1aJ zGV!ZZS+7pL(Nw+^fKBP1jp!Fhqv?JNzdRijQWrRC3bTqOXh%6Q8wpZ=xge}0KvgirjydLM9&A6SV7hKcQdU?YHYFo0M6(BVGl zXZ_G&bXXQ9R#H~$ti?OAlr2)S*-CmI(h9`^e$sET@fjXDjfF)$GKx4HTSNX+QOgN4 z-=46v<_TLkjSX_V0bVH+7KRC%C&JLf?FnP|Hcwa>dYY$9*iV3fwT}wKgn>R+-V|5f zY;gf06tJ-L8pKzbt6Un4Nfe{pZ~c}0JmfJ~Q!rQ4R;8Kl<>9$3L{gpR!*khq;~~`2 z#T{7${OZa}biK3zld%W2mOM6)AI!yeI$A+UzP3qh*`px0DpO<<>wMW1Wr|GVNnbWy znIe-|Oj)hlnnp}F37apQf_Oe!8zhu4&OhW_0qmbFckmUbLmqW>>%Db zk9F!;E@rIC z=20_P4{a6j!7+;aDsb1QJZA=5?ogu%m=q=&cKB9RtH1mO1N=3&L}@n)ly^vG-}aah zX7HJSXNQyQ<=zS~;2_U=p$c;S#%;M?evvN9HH&tMDOyssQu&S*dEQL6Mz5uK)bsvjLtKF^$6BIHa_aO6SO6*sG^s0ewXZn5T zuDQ}}c(b4yk&iD^MxMEh7pC7+(uqi)5&uQ{%+gf&5hn3s7H6|q|4wnIXQ2GTYciKQ@{#o`v(D*wcLXEH*`>Q7{z` z<(+4<-qPc-eDrM0!AtA-{Ml?s#|PJ8)!e>O?;KUKm~WrWCg6sYc@FE%d(2@$?EV(% z2Pxe*=n>rhstVvYXS1-dwx7G6E?S6!YW4DKDlB5%icVPW`L%(BYz~VEj-CqYJ_@)R z6I)vJ2zSk8v1}nfFqc_E&`ka?a*|5^c=@+pELb^qUC}~rx}U`XV*34T09(w z0&Ipc5KNd2R4(MRZEPM-e1L@!`~z%q@O<)!P6phJ8ChC1i|>AbWd`e86y47|7qIcc zRpe**p&s-V&2Lfk$j;pbY$a<)_qR1UxS^IHj|!{c-5+8WR>9{##G-lhVrIx22rTX7 zr)`k(3}K>NkX$woIZPJiLgf{+kwg4lse{ww+(q$I6>WAO?5k)Z4ny~@QK#T_ZPAG0S8-qdGuo_xeF!J zA7fqGLi$O`8HM&HU-1~OME!MxS3bu22K*l2<>ww_U7I2FV)YF!J&7PLOfEBi{;LnQgQnnv9mv91~v>j8`{7aQ+1#iZK2en`NZYS9Dz*nf50PCg0Snr z)~Fm@F*zBoj332DxXrlP}pHRx;@wL2^b-~w$Qd}3P;73c@LRPVJ zPW>WP~QX0gG(l#ul`P*=~_+;Pn@Pg!~_Bwt*#ZcOc4@@76*Kw zVXo!0R!No0E6hll#g-mCNoJFQyIjWPSMWVD8`JxD+zMke%8Y!jn_UlUgBQp#kGMUgZmA8dBrtsG8kWJMpJJUs)!k3AFhgBe&_SV5=%+zB zcvnT74&{$Og}W>j{69~z0RyS)cJkN=hy~QmuueX86Dp63^_7_XC6J8Ho%qeCSW{~Z z$c!KEas0@=YuN$G)tMiB8tTDj;6FUg7EAR;p8pIK%1izD+GkhM5O%{iyvsVaBxGBNG8kGV5XO!L8ihq~u44&Z2?dm& zypEJAj$=vh(s5`5eNzK*wL@EC&SM;4GnSyN=jHxl&?9U`IZFJu{7??$Y&F$7(5LWbY`a#Aeg0 zpJ=fyS`<0TO5yPiig|r|E|Zn>DY#UxE`)W1^;tByDVMS@SmS!|C2&A z{MhsC!S+7J7!!^x)ED$s2AlkXvb-EGurxF}{(`c~etd!5gIvr8wi{nRZ-B`^b((j0 zk!__(+V>)ho^c$a*O2P`GpMjVg55?|*al9O{wS5+6>}^;_&T(V9ajP4*EUhA<5;)) z1T2=yxr=I4g+Dg5l?^8-4J}MBrRe3!Bh41uE?}^V^`@O^FEKUa8()TCpKr_eyv%w? zH9`FB%WR|+a)x)_$nKHuYRl(tWZNWj5bv}JypIUtV>Yp#9Tj^EagI{1T0<_|{>Gh~ z*-(Umc5h}wV&|a`Y;|Fjtri?cE&Rpn#q@W$bvOgtqbu!2YZ@`!%xt_ZbLkrIzJ=Kz z-qQqGY8&v8D?Mx%2?h*8nEbhGsnNC6AeLMwJd66G6}^u`b2s7!$*`sctjJNI7XJ?# z+Grz6a)bd;whKzKH6>3g$(z@oeU&{p%n5GULvyUoA9c(>nC z|J%wk9e9VXQ2M>5zG^Te!;9U3#X09Xe5B;-W->H|8Zmr`PnY5+&kBw4$=B^2#aT=f z^kf_H2@>+8>n;r( zJ5*SR0^IAN3qHVuoGWOmkU;^Fvy8}zAI;mp&O$qcqOw*M3glM$6FYnG_}5vwW(D4u z3EXYWJ{)(sXCM>ft$7rgO>7Yci4itI6%n@IV;ojF-i19H55Ne2-X;@!VYj&*%+iNz}d3e+tth3EC9-Di! z@F0*ob?W9bU>Jthy+Cbs4Xr~R0=_LP0t>oK$*YO^WH%vc2;4;QF0JIO4tE~HF2iVs zC-hUn%{)MC1w@XFcXI<}b?L?x{H-@w@1E(XKbap>l~*GIf)F|$b(l;w?o6yjH{PLV zoc!_|%y2iFCR|$3Yx&Kl$>UXvyT~Uak5*p`bXMyvA{r90JYB0=2C^F3IFE$G3TJ`; zdDCkY5yEfMIhzbiLY-B3y*FS8pZq2>b|HY<^$PI`)eCxzYMRWKzsW*$bzt+<={3%( za5(x?D)_5!vT(;ccNP+cU0be?Rc)Sv`Kb-e#Z&%$EK)O&8l$9UBUPlNY)F0c8-V8_ zQ5!fP&oH#D4YVV50~NJ_MM&iqhfPOLv z^}a5xK;pbvr(3xRFqt{>sN9NieN@g-B=4$1qi`Z&9nxC zRg54oaVC=A|2B*2@H*;p=+7tm;-0Sj)wkJRY2GY;-!{CQ_4>Wsy^W={svZ|>C8kOg#qmxRtVkMlAAh=n%}sjeK6G~V%+#(`blMKVDKOaT2vr<7 z7UOj-x!_uIu7HUlQGjzTxgOK#Dy&OTmV?gi#PA{ZJmDSqBu<|94ok<^Tko)bZFUbM z#xn8z0Dc~|@uMQ{9L9OYuQRl*X&Bd-qIKfUW-$ah$BI}(?JOt;@e&rOS^RPzkAIg% zP1JZn()pnn1y(x_SPM0HSKz8{T@^NR-Nc@L&BIkVC8qh1JCAxBw7{Nd*SeN!X}Z4| z%HMvMrLYzJk9XO7b3EAHDk{j&+gRu%Xq1A`DGhDp;Ek9#mquYq^J=oh| zZ##>-`>w_4Cq*Nt&U3YsQ*EwvwcIWtIPqS{W(PSqcPdm}>ioi1;>1G01<^YhfitF{ zGE_#RTlE?-b{-%79?O;t6pb7leJ}syJ$R!(6mjDYHpo}ip}8t^ z2eUe6L-$}Mctd6&vAk9UK!15>{G?JX#(vFyKHsmG#4-exXvLhEOqwtpnp8C6dX%!> zyr(d7KcG$f84xPi&_2X=9li~;mJQgE52UV6`9TR?H(aXlPE`n)2aw|h8WD0foxm*+$>uW)W(Esg2Txil&OO(9X7H@8Bg?8y;d4p#)6fINRHOk$)V{ z_pV&j)T&Lh31AigoTE-dDXFH~yV@urUi0JC;?BPWV;VxGF;x(oT%#?OtCA~{|ZhVYN;=x3#=!K`PX9a>Y&p$$o zz_dBs%s<)<%{eaIr*eGDE=PQ)+Znuv1v2TSW!$ir^^#6c;&FRfnzXw+e{wHW>6-5R zoxN;uD;rI~tSJ8DUKSNLpnLPe^*Jja22(G%Tqb5j@xlAp*7kF|VX8v&T+u$|qY36> zAAahiQ#T&5pPd~!BJ7Upb8xEAUOv*$KYoecUKgLNUD!^95KynF@ZT;sd_jwvc=bqo zKIQ=HG%5l@?z2sq@^lT}G{08cipuC`YV3W@;et5)ZeBS}qZJ5$*yat+}v`QYY&an>xXg{-vBos{(a>Se1t^h>}p)h(Esmwbn zhc^V%sJ5nJ#(`a@WPV0>$oz1urZMmwM425pg=b-BXRwmPIsIm=AKQto=qnton`(7W zx*`@QqfB}8IQa^kO~~7EMMXP#dKF%MPWy~ct71bm^RdW};gFTHL(JUa=+3d&Yb(xl z6ZPFe@L7l0Bo@oxImCK*Irt+2yqYRkunWe`7ei9SdYNn*k4T2x>!tA zVtoaP_?$DU+T?RXP>v8i?_b02mGlL?w1!QSDu3YL*08axnwt(Y8+($w53{7fV;=^W zk33jq2uQw;cWsaPID;1`$>(qdiC1i>U$!2&F#)3d+4q@&Ie5tXtY0tuQxA%FQ$e+b z?ZpJjr>k9Ml!v_$!+75NtlMz@kgq&d-SCNzB^Qm#0fKXmP`M|Gm}+?vez5owI&~#q zk&_LHwaFLz?c(pg&wBL>T#3d<*+E*JcBY?8GHF(@3S#IR?h>( z9MQb!-@!sgl(0Z++e$#w`P3sUfz9RXjv(N|vJS~)=ZozZ&^CNpKn;GPKpezHQY?YO z>*7Te2h`Z`OPLrP^r<^pOFIjVC{-%VLJRc_qbooV0P%Z`Jxzqw*vyn>H?yWEydg0e zP~=vlj}MeSYJ4+ulp&@OShtwJbPT^$65EmQKE}H0zbnNJpJc6bjvhiU!t42kV=Vff z2QGp*v#2V;0FS{C()&5nCoT8z<_GuGHVJX zaRy_XYU`v{Re3{-Q3Z%1d|`VVb7Gnp@wM0M7fbI@>QbD`2Rw90z;tgNnmkO-}OUC91Y`;h9tB(pnqy?84RaGS~Ml3=`yoGZvlKYd%SRFLHbbEcAa?O*a% zTnP#ne_+Q!mhK^dVICC>n+Y1b`@jNYXKXEX-*Rud2 zGFYQ{>#$)_CVmaG$$}{_rz!8Y7EcN`5Qz6vdFbj29`q4@_m8rlV{)pUcmcYw=@vk3 z{xrltbUW}5awM|N)L}y%ltQYCKl%}yDBbr1-}ez)A)PMaiKp;B{^%0^^eHwRO7_?( zmVv!X*vAMJU#ay4xHPp&tVn&-7vL&GcC8VQBz$bOz5o|sl>pZjs{B6#TvUsIQ3Jlt z;ByL}qxe+evkRXJe74s50$cNnX(#XFlltTHI({N2@HS!auS)bv1APQIranrBc zljKQF&YAOXG$df@=yt$vUBYGEyO&|XVxw_Mx1*J>Bn~CK|7Wa!HwS!%cxd~=9wIyl zZXx~oZB6wb{E^SFu)~-0HJ{;7Z!v%SGiD54hnMoEBF+J;W>fJ`KV!1vzaV(3H)K6z zZgUk@qUZ@#vRROh$#qhoZ3%g-PJ$AjqHCp~wOBv}(CPgNBlJ)!v&g5SO>d&*<_bK_ z-l1FY{cfOqX&oZWwSi`UGW@rRDjl2E z$kqlnVRWsbwrc~gBSl`BV&7b)XV7L-IX14Y(sM|9L&y+pPDLZI?SdT&l=eVm6KoY{ zXhTO9!8wWmR4@rlR1u7gaNl7P{C1!Xq$K88g8D>}nWvw{g-kOqILmq&EQsylYF>?) zVxh?@4BB43KO9(X?hL(#LX0RC7Wo? ziD^6-jw3+-#mIdcttm zswpVup@r)4s%T=R8!Din7>5YJM3=(%HWM) z(55ZUou8d&P~Ba(c(@uKpPpc*Mgj2A$t|rgg~Nhk=pr?#()7~<-dssAU0FE zYZQ$JZ}K0j*;Ij)6$8Up4x(6>3S$wU#ioF?1eG<@@h0d%cnd$s*iht*45VgyU$e~w z_h6$TKxtq*JQg$8LNfWo-!kKXt!VB_p_>jJu#vfil}6X_f-_y?b&Yl{ReJ+BI(fyn zY?idOVrR&A?1g|};Km+-b}4~doP7Te>@Mh;OFyta_zL|I2YOC!{*fgy=gxIMvQJn9 zhF91D-dTb&V}-4peQ3nwuemhtacafuIc{6_HGire2ji3YoAo%VoW#{Xv7Q~q;yxvQ ze-A;XfRAFdabidnAN~`2w8MdezH+NlK0>^Gknj14_3BksN70#Z8-0u4Q^;b_PF07W zWG-MhKdq|cH-Ey<15e_i4XjUx$iJcKdXP_QP<{#ap$66^xePzDU>2tkb0AO8UMy-s zjhY42w%=CQ=aS?s$9y;it1NE-XrkjYm z9d&-wL%vjfGqC!bpaAWAI5VjF88fhg|L`-*8$w#rS*MF>Y*5EE##HGJlvJNWQ9-Nf zCiPTTX*rf>LbYz?TiAc#%{f5dG=1%B^*`aj@ZG=%q9iRC*b<}NlNGtRBGdh*v$xM^PiqgtF-YV+& z>pX-Nl_@DQ?|1EI21eg=KEL<<KC@=+z4qE`-*0R0{X7G)!;%lr)@`J_i~*5* z-BFG6{||2S@2En|4=q7sXh#jR6^B9FWBSjs5P%vBQXH6og5sojQztEkwJPM+DQHR} zuAsZcaQHsWG@v0aP%o<5*c=l_n^PO-T5g^Efr(ux_2~&ZOro%H2F-f3mqC63ClPa~ zcByU2*UD|arJ;h);(|}H=#lp{<_L-{vWNWmVK9?ge_V%Z+^AX{$HWlebsY1Q+q4bS zzO>an#p?*HzvCe2))P6!zY52%;mDuqz{#e#qx`!L)&9T@l<@R+QZ;C)H-JvU2NMZ{ z+#{b?-&Ji1x{YW-qyA0tNZEj9QQ*HwOx&uX<=>k4q)ydegTgN1y~|nh-AQ6@7;y!y z)I(9At3Tlyn<`DUnHy}F!Kd>|8&rA&^7$bfHuVcW;iqjX0~`0yZXFxL1|Hl!l_j$$ z-r2pA1+$GG?|zHD&*mNDm`eS?zJG}4GB%q%@er?NEQQ^CmA5lCg7tfdhp1T+`y-F9 zP_qzrHjh6^`1L&gjvCSi{f&3v3zDo~BlmY{CYU8nqSbcL9FLOeo_PZb3Wu(G%SXV z%jLQrY&C1%$18iVdNk4mR~9GV7A&LkX;yudaim=*(Lm(VB-|4_m>{XEfvr+eLqV%pWnoGv}WoRdJ z?fpy*3X{=WufhjDAZf1rSgtgW645%g;D*gl^d}c%zA=U1SeR)bPV^+VLpyMn1VY7r zB@&rru#L;G`Gp`cVnjsVeT;A@GfjT5yhj#fGvuJXfsf9T`zq#6)1WNb17_?xXJMqG?o+<|I+EKw zFy~}*54CGfs|Ne)e25#%W7}WnkGrwL{)N?Gpb^mIF6Rj|jebzvy2~>S+}oY4)7b58PNWo$X)blEyuAe!*1$Et)&qWvPRN2 zc%}zSA8u86T9UvZ1p3gH2&Q9Dr?g=!6#H6a+&zPT?7?E$u3E13WCK`JEf4i%tJpg! zoO`lRW?aBedZN`#Ucmp`lRd!B)N-8{3&jbe1TU5i^sE<>Icpy8@M0qwPUa8yW}P61 z`mk?-w7pp)`T4vz3lC75g}eHlFsSKbzA=B&s+{!G^HXZF>G)1xwuq&w_^-ZfLVxDrM_A#cwS6P4;6^?&p-I;3m!;Zu4V{Xk7DSv2F^zm!OaGX91um z`?F!psKQ&zSwuL66D+qh;EQz8@>w7yIAzD82&cg*xcj2IkuCoVHw3VLtWw1b16Z&- zh8ZvGSwxdYhi3vw#eEnxdvynu?J2^AS^DmV%&kMRBqqRe+ghgGeNF$@f6Nt zY?^AU_QKeJ^VxcAUkpIaN7Wb3#eHZ9dh}^!2!gku9<700<5VWnNny{^v8*9T(>h#u zMebt2{9&M#vI)U^o&2Fkd90_cI7+mnuXJoMJC74a)eJt%`m#B_$!9;z%9;mKcA6U) z2?bhXym0@**=Nt-y zI&7M2>#-F<^J_kQAdB=g`r#I^4Z{Sg8v2rz1KD)1^_X8Ag%rt>q?Idk`00UcG+Vo! zE-~hkqK3lK*}z|0x)C=e@DK_aOFq)L$PL4c*ak9D;LdXt%v;iqR4!48_;LdbO5M9n8WqUPEiB>c1buL3w9q@qk7R87U`h zelnzy#w^*PF^etlyj$GcndKT-TCd<+%vhvh-zVOM9Qm2SVy1F^FdL`J=7U36MA&r^ zGp~x-5N%DC4VV>Qw38x0GOCE46og&H!mWHu2ut=IvK4ha{ThbBl^=zpT3X*M$>vw^ zZCi+J4`EY);)k%6dPLW2Yc>?}G`UU3))y)AU#$@NiOZjie=>xvi?HX6k0r$zr{s-6 zUIM0^s)fc3OWak&#rBVzDMid{D^3hZH#NCA{NbUjUjoFVPVB1}*nQtIV7&VS6Ww;r zM(<^o=}F$ps@#(gfE?c{3zs-b%SMmw({(|WmDyRmX($UEHJ99fu!#cbDyKf8V7lUS zu$+$ojSzP0q=c7gj zOxR0d7h~DbJR5avyqpBKoE+;WLu0ZQgS52S+@6;MP9KXaV(5k#LghJtm?kWm*n#sT zQ}9Ml2i=wE<&EC9bZv1XMug3kH|%Z z_BMII$`_Ad{Z;e0c?26Z2M1s*QEgPUu$^EEt}%c>3#9;PV=`g3U9g>lgVs{kjw;hS z?D%!+;2cLzirup0mK}%=Saim#a8hQ`xQ;ON|3Y-fe-OR8OSBgHjxN!@W}Dv)L>X@d zgl5qmPd`coy{Wo5&=w`5uFFeNr*g2xQ?wgrA~#!b}AhbZ}D z>2HKc+m}__C_|0fWlZKK3`+S77h6@2R(yDP;YLV_xaqjVLTN@m$!4TdWRSK1mx{K7 zhg>kGl`vj4iUltBA%FN*E+UHxtyXN2itUe5;TEgd{-xOB7274nHd(QKqS#Uu+k1*F zH;(dx#2zZ;ZlhUW->z}Mru22V&``>wN3$_KkusC-X1t<<7mda^G^~{G9F0ZUy%i66 z?O8=pYNyXsEJRjXq9|jH(Fg}`+%tv|-ggbf3yWS@s8+zD6PD}3QXWSf@Jp3rA5{jE ze|a1+N+vAnh)FWJU|AAkuAvIHkDO|#QZ#DFr#=`;Mic|oo#a`mm;3A$$g6_7A*D7N z#7h7x-UUI9MyXuKYI3}{vn|ydUro~NL`Rs5O!K@+t@o=oflhXK^ za2BaO@JFI_9DjVo1FWArDouSYQSe8U<9(~q*Fckrov<1tggystf6FUZjb$&f6O6w+ z7Mg?j>HM>?Y=B2Ibxj-#0bA4!Gyiie8}2bG6qBuzTZrR6kj6wXJ*u}Mf|XE2an^Jm zKO4bx!qOj>pCi~CG<@#spg*Y$e=hj5_ny!$TRigT@%JLxXfKfEkvAduRDs?osrl_l zmeK>hYTC^_C5lZL{s!jgG|fMJoaEHdU#tId5?n)nt-X$u=o*(Yejo~Ybi9Ip9>tQq z5wEKBt2hHl5%kNR$A^w%RdL|#j>JCQz1ARMh2~1HMx+j-QPU}0W#WggKD^1Vk7Hx7 zkO~^l=8oTjrO7ZkU_a(KI{EHCyP8B8M>C$%ePzX!*&z3lqa zd~!6K#s-A*r=nR6WJXM2b@wcX{+Pffu}4SqsEKSHB}OvI+xvJO`Pl1tm2n=gpUCF0 z>QUS)h7AaHM>m4AF{tj5j)Uw=um;X4PrnXb|BV^u-GuZ zE|yIZw^(AKu!&dmKV!v;a8w*tg#T?-^51!xl^e(2V}4d1IEj79^3=R-5*s)ax%YQH z{?L!2cKb}w7Kd3S>G~Ke2YWI2^T#xg49YW{0HrrHa+PXZgDI?lrrSU4u$ixb$y z!LuQyY8_599-!ko3$&KvYx4WJN7gO$O@2Iq#RaVcG2)|ys!De#d@U!%2(L9BAo-8- zfJ8QY;K!6i`}KsX*B~z9M0Bz{4*8tIStL1$FG^$+UFqYJvbv2|C$fT>mvEn2o*9RJ zXWow#m%kRa9l~}_J_}n_ExE}J{I5xDi0TRcc@n0_oB7X4 ztYplZSC9Z(a&zlzmW}QhGA+qhtEP0=iZ9ALP&_%ZjN4auEpt_+5OJCBp3D*lc#;$9 zg&USrS@Mv(6cL&SrBd{s=YQa?VxJi?%97fv;x_~i1!`Oj&q-!ceR^~`98?_sn8<6A zp)ZK#N1@U5IyzDDXj%+UhbHnLli9#wtr#mw)ipuh>~J0qXOqJcWZR&Vmrdm1DJ)>r ztEe7b8`sxbJ+W^hiY5_s9GYB%22NwHkz(7Qn^M@U$mGZHt~Z?(FE$`SJE#MPwrssF zLmmkiM`{1~vM6mu+Up!&gdf9N9_1sZuo&E{UN(gd==USkHRbhXNSS1MP`(PARoLWG z{^Aric#H?c;pJJ_V%%y0k7c8--0Uvl7)l@1J41iNTzL*}o5J>E2D&?y zrNsT^8p)=DfL`+*R8M&`C>Bw=RnSkZBU>4je1R&fD%o4E9Is?0#9!dLsi?b$P#xq@ zAxEi%rE)*=C90(C#q*}JVUsWgm$Np|s|AWZQp!(x$BZxir>ud`0u`yj@^MEjC&zdW z&DxrNULKDQ-&ldXv?iZ7$RBOsA5LYnac^0d#{P&{{5`_UrN6oOvsc9FFqUr&fnwgf zs*<9cRg81e?yYKDafti{kDtb7PWtvcN~@!x82&|{JaU{?r1Nj+Y8II8>uN;*l7X}6 zFY`~Qv45(X`0LZzP&Oxwe?Fb*S4M~^hnp)~m+_;s zSq5}99vLi}t=hq-WUz^_ZpmOT#61W7t-(;B#?OcVP8gd}5p904G&Q6%TK77~8|7~2x5>GN{;}qZga=w;P|=uh ze>g0>cN-okk=x0fmS>mQY+Y1W2ekrJQLDujhuM_%*Vk|9=&d9)0WUjFdF*1_&1nM#!l8Snyt%@U-R&Vf zoymsx9y^MZWI7zxMS$lmQNC|-K9hy_)u7wAbi~{-eck9P0%#NgT%5<7XEHrIHit6< ziwxL|R);Ts6ypZA?$$SfHwPEDqhEW3ryE$`>As?%CoH&O>PbO+XCV&I5FsG<3CTK| z>D-+|q|?@=&1nBn+~6Ak&w*q=c2j{cGXWnd3_V$UgqZs6g( zv3xL(CpD@Dxx9MWX5-(TRr&IbjjE}^ftVDFP50j0lX2*?GP$F2!QIozow&&6C$HEF z-bLqBgFUirMZTnqlBVAO}&z-|wFdME=Q=mzYv1U5e$qHmH zGz1Rii$?wx8d+35I?si37g#9ksM%Gc8pp<&R8z9#b3Y(XR#Okv_8#bce=Kmpd3ZC% zE84uRilft9*ew1;k&w}vm?ggi50;BbWs~A^%%%qlR2lf(D9z;CV6*Cys311e!cniYGAjE=ZlKiA==ywq-#F*6<-zO;5GvmbWu}7~&MvSAP08`LKCxP+Y=GqHwUm>JF7m z5ExsMQLk_y6ywn8G?Ddo2k~*M?utuVPc9vY<)$aLKCKrRR^u&Z4QED8_3&)Aqd8^Yuc3}pp_x@5n&iYMl>Oxo<)n~U94 zY-AnD#mpTCT65V4QIZC=>^aQ%(C_0wHuh263F(S9j&Dm97x3XuY|5Dgt3i^`HC9_PUeSwFl1j$Sq} z7JhLy5}es)p1zO`8u=L2-CWUEUW;io=`BeesWGSV)$P-U4BQ2fUm$+%%5Gz z!j=gSbbQLv-r5^cMp7_-ZAU)fj_1Z}(3os}AF-m7dr6WhEK7d+bvV(q@QY5GqG7mQ${)ALC(*SfDayDq-P(N0$A*XJnQgyn-Z z{i=LBlb>J2HVtn`b?T(=^We-sn?IJv%&H)MCy({_@q0wn!K!d&6SB_8hcAX6;Oi1T zdojy$%SQ)`Mw=zKuHtVkW?$l*!{ZOJxx?STMCBQR^6cv3K3u9)U#R-4*10dVoFaX{ zcb)4J=B84;!u#a2aX#0IDYUKwAKRAlc_5n~_z+&PDl3nRN8f=XmR?(*Kz1AJzoS0g zg<7c4c#WXSsA#+n!AbeXLkjIi&NE>21hYctgf@&x@I6}GaXLrQ0#17$Ziz1)$-BbMRQa0Xa80OmIf|*h< zA1&bl%h)*9ypGRY#^QZmTz8Li{1RThjICfH>$ux;HgpJj_SVpvHtOI#=)W~kZov>_ z?~G`gC~tp=XDw$#y#7J&X+3Mhkt^IVdSxx&zMKUO6YZ`Yq&`aLj>zLpEgT|pTF*Mo zx<3W8tDbs~v@+hdocZ>O1rJTQgV%CTBkO0MaQ6lk6YlnhsUgrrS(&9ivsl!b)-(6+ zm-~hl50yU$FTB*<=OtV5QvR{c@A(Ik~_CrrfXjTtK+wSoniC!_8`Gqk)sj@Vf7)_>9<&(Ex252(K6w^u-Kxx0mrDPZ9=CtX~?q8MMp_Y#Kv zYyn&1lZg(1s+;|+RPh3yw35XJp2V>9_Rjj~_K~CA?woVRrDbsf?ZY8Dw4^EFj59K4rNoBPTQD{Z#T z(bSon(s4-V=U31T-$wsW#fO(}jH_JGAx~=LFR#Ywl5eioHLYgjRqV=#TvNn$YOm2m zPkwp@f1!v4_HVl^BqPVXDo)(Rr#+H8S!+T@2E=}KnSWJ;ZRCa;e!B?T-Yq=vVHOM& z_b}vb;l&S&Ln<#m%!2ZfKFahiS0!{dwjC&-bHR<7B{V9 zA-#9sM<16}cW@p1yGmu`ON-g~-cRM<>u+o(T@wiiT7~P8?kMfXlY~*|R3n6O2T?Kwm#D77_&gaq zMv<^;GX5%z`^or&FdiV|6&TAK!uV5p{czBHpa9-%fc|P}b8sO9Ta% z28n`GL|r;EoEq7LPr%1$4%z*zRit>wXlm`0JcWXf2ET2m%up!07)?DWF%)>LLJEq} z9J4cxP$>Es%?Ue2Cn)PfVxk%ZB}?v6msiSGsm3^3#7#{zTvS=Oy59@m{Y6~mL+^+^ zIBkKyd>F!P^la2Cw%bsGxw4CA@rf#s!)qe zOS50$5%bFsGm8dVU}k~L@Fss0*k|)_r`jG#%&(f+c(02TO1g}jgBL9QF$`Wev$5>w zV_aW`E!5R#d3+hVhfuzz45y=da9+m7`p~e9F*2`eL38VTOMk3~E|;-^>_Q2@Q-&UT zD(}CU=|)VWg$|B#SeMfMO+^Xv=`g1_IFul(`J&CNaJVW0%{$o}Jr-8UjV4wVj&C@I z$IjhjU7Hz7r%uiso23RzO|f{Xt5$Gb~UEXGhPq2jE$;enSp|$784-@(AC!q42 zyrVAiNp_a$AgsJ4uPXUa%m-c-Ezr1c^tg5LX!xSKz^7TFI`L>9DukW>+i>pza02i< zAo}q{sR&R3_!jUnU}|NeGzst%%yvDYiE7SEyV)gk=x zcJcOzIMKpy?O{>Kno%4FvKH0N;w;2fRa3YAMRtv;%IoIWFb$iNi4g!3No5U;INQ%+#`|G8g8do4RB+w87`TU*QYUEk=fM__^^(`&Ioj6I{LPCh{h%R4#k&`@?-SLoaBtN*2=XMn zfcQ1mV*aAM6MLa1ltkBFC|O$4HsckpU3;NKlE;JO*b7Y!pysaZo)%25?|2RF3o&9F zOQ}rLFUo1l@d8;aP_4-q@mfJB7o0)o%!`Y(8Y4ml6D>}HNP z+~mmQCQI5Gu+1Vinb;=z^WeX-KIzfKlH6pF9}!_HMPldnC+?tjaI1w-6kUtti#Ukl zZnvb}fXH9(f+>}lzVYLmA+rBD^nv#j?MY&3B9_Ani@AQIBVu+bPZ3Kyv1~$4be9uM zM^hK$hW<8(52hqIk359@2@mP_d9YgZe?sogIqb-`Tv#pJv+-$0Cwk0B1}2U?1dE=%%WgM8jwbPHts z$Zp(K-i-T9G{lxK-PMWCzoj<&%}J(Lo~Kv5OELw|mPwk05U8ZJSSqc;hGz&vBHVy&K<2 z{=)CV-^Q+>l`^yYFTThB+%EsK!DY% zBcr=8(g@a~5=PW;Tgy!x@wW4}!l)F=MYveDpT|E!{03r0J@KZV^mEwiD=GZr-u$~- z*2i35;z;8eOIib1Y8)Pje;4szBYw(RYx<#<$}awDr9waK%%4yE-kso|1%8Y5dE|ae za<(I8J4BIGDn$}a9?d7vo~ZL4Nj_uAr;dCoZAKaEyveCujehbjrdU)dZp?K=8om#~ z_fNOLvI`@7%Vn@AMS_2P+hP05U0*j-RF4e?daZl@KGZS1dekfzVm3za^>K+gY0@@I z)F0Dfhkax)?!-&5sys4btn$bf|GD^=_xGi_Cw-94#qpg9%uexPi5g)lwzkAb_5~ zyQ-zn0N(>{0(yYn8!!M64mb$f4B%WqA>diqD*=;WE(JaVd>(Ke;L=kqc>_WKVSq`1 z>41fR0>Gx8YP0k-42JkO7?l zPdBwR2rw2f36KR?4JZLr0QLa(18M=s-OPwF4Br5L2Kc)prhsTbDj*xM7O)+#A8;IS z5g-FP0Xh%06bhIGm;uNGtOZm69FHC)?RfsINs#__GC{iV8D8WPlqmhv2ix0@XGuz; zbnxZ6J@2rweS5WGrg`pmyySU=fAJX`Tjze3<*EFOe#hcSkC)5d zR@ZP2(|WHNGc)yTik7Yp4i452S=Xy>`Iqch=07Qr%_SF|NcrGO$pJ|G(~9S{$Q2803hfLk9RgjTo#q5(QU$B)2p z^9EeR0e*L2Ex-jJ0Xlw3l-dE;0W!dNK2f>`+zhx1xcEz=Svn8HIY1NO44?sU0&oma z4|p3;3pfNg0N4+x20Rbg3)ltN3D^Os1XKXZ0HuHufC*p(+}1?&VA0j2}O0q%h7KOs_p1Ax7NU4R{cQb0Dq0GJGj1n2LBArg8Ho$N|8v_{@IK8<&z-Sb>aNs?Sp5giYM z!54NtAl6PN9@5X!gHgstI36JU;k&nv$Js60NhbL<8=V9?JP;0rfC?vOioh<|tDX3X z=if!Z*&oSD1>ZR*S=5G`VQ>2#)xudIF;YPEILF%Avv35Tb4rL7jhoex$Xv%m5t|JA zbUTgQ9Z$DxvviLqVyJ+syVOY#MQ8`?djXEDC!T+oa%X=e%NHZZ87Enk@{6#`0FiLB zJzI$J-=*ByGYK39jr;?+;aB!8Zdv;=sc99HnqOj)e>Ia*0owozYnZeb@Fk!f5c)Ec zvH{xx?*df&Km%k0lAglf_W!oD7Lk2LVdM7ZYmLk*K9npXjpwn~4?oPtp+q)9t)#l_cUZIyAWiC9tlesJ}!q7=i zDOSyt%{zb(035Y|+BQA*5|ctx9r8=UA(3O(G$yptXYSJFb6N*PDE9jj?adMSNn@awQs z0Z={#VJS-xSlAuRB*&QM3uvfzM15GYgvia$xph2t2N+V8<41V`NTI50)41a!i+ z_UOE8$ESfQBofwsM`Q%GJ6^3)yQs4}x{7?J^h%-->So9Ob{uTSVRk&;juY)T-Hx+? z9Z72Fmiu6}-TeSCrKHx5-vy>fownNvQv#${6*(f$6*<(q_=8N(G`lmUU4OSL`T=Ej zcZ-vIrs6L88OrHH-TV)p03QYSnH^sOCYjfODO$e(Q|8~cyT?QQO39;WT@`Yuck^_j zYCF4P<5lfMk5uTQ@z<->I@gz~6Cea{OLbBAb#1|9yvy=1X1)#!8}J&x?4s^R9i;U7 z0pUPKsrUe22)gUO*PWQ3{40OfMLodv_cxq~6W$UM+)CcX3xxrAM4+tmUEWUv?&f3N zMAw(zbFzGT+{x1SgKi6Z;6p{|+NK0)8^A8q&n*GVi3I>hD6X@<=(e!H^L%0tb-x~S z+Y+StZ6bK~&tDb1wiln*Lp_kWCGtRxy1)9EyJB!1>?sOeL|XlzcOrkzMcv;^(_5(u z6jFjuqT<@3OXOFOp?DD;X7O0n;89$L>Cp(0Hy(o$B`6KV%&%k+$NI9L=g5$5+V~Kn z`Mcd2hA$Xm`9T8Cx~l!$(qWn9L>Tr0EHw(DOX3N;WJd_Uj}&R>>slU`C_NjdBnZc0 zHoK|^s=tp^?4IFRq0sZ&IIIiCiSYd|f%ZKhUbrZKC!+a?p6WsV4NwzMEo2~{hgk)D zP0a^%V(C@VQ?2uApP&dd0zW)Kj=0ef`5xqj_aJWNc@*n^?^-75 zooIgtO{!&({r|h#A^ZQ8+M(`(yBZ(E>hw@wb9-7n+f+Db^@bIz^Z9q4>J4@IUh3)0 z?Nye#ba7F}ibt19{0$#9(|2NSZOKv=Z6uyD%oNvei>c&ht&P)PdrQRft`4dELvi)SFl=eRaY4 z>CV4IL8dY=JyNuE(Tdf}*2Kq){B`j2aP)uNJ4>ytE6r5zVxDI%qT~V8L6r6S%Vsvw z{L8#V>Hh>ME35HVE?P*Kfay?aDsV60+OMG@0j>b{0nP-bF*+O=Z-kdzfOWu4R}-ba z!25yw0T*6P%##9Phy)=B*d3Uv?)58)(m>!!U_Gz_I2btlGG-jW^_QTs0p1V%2=Ff8 zM}aGVJAli8sdp~Al!!zwdhOYHYE|8y9Q7v*w`Cv7Ro`Sy*Z8~z>g5S|-G%c*uiS8c z{%1R93)O>%<79^8IrBXuAkF;Th!Xaiga$bf5rX23kPR^W2#rcA4CEmm5Df?igaCp7-T)VX1n6i%!~jQ{CCOVtr7Rdrq3GW8MF{{n$f B;j{n% diff --git a/contrib/vmap_extractor_v2/stormlib/StormPortMac.cpp b/contrib/vmap_extractor_v2/stormlib/StormPortMac.cpp index 26f67872a..2477333ae 100644 --- a/contrib/vmap_extractor_v2/stormlib/StormPortMac.cpp +++ b/contrib/vmap_extractor_v2/stormlib/StormPortMac.cpp @@ -15,7 +15,7 @@ * ********************************************************************/ -#ifndef _WIN32 || _WIN64 +#ifndef _WIN32 #include "StormPort.h" #include "StormLib.h" diff --git a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp index 2de3aa751..1445a321e 100644 --- a/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/adtfile.cpp @@ -1,5 +1,7 @@ #include "adtfile.h" +#include + char * GetPlainName(char * FileName) { char * szTemp; @@ -67,6 +69,7 @@ bool ADTFile::init(char *map_id) return false; } + while (!ADT.isEof()) { char fourcc[5]; @@ -79,6 +82,7 @@ bool ADTFile::init(char *map_id) if (!strcmp(fourcc,"MCIN")) { + } else if (!strcmp(fourcc,"MTEX")) { @@ -92,7 +96,7 @@ bool ADTFile::init(char *map_id) char *p=buf; int t=0; ModelInstansName = new string[size]; - while (p= 4 ? path.substr(path.size()-4,4) : ""; + std::transform( ext3.begin(), ext3.end(), ext3.begin(), ::tolower ); + if(ext3 == ".mdx") + { + // replace .mdx -> .m2 + path.erase(path.length()-2,2); + path.append("2"); + } + // >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file + // nothing do + + char szLocalFile[MAX_PATH]; + sprintf(szLocalFile, ".\\buildings\\%s", s); + FILE * output = fopen(szLocalFile,"rb"); if(!output) { Model * m2 = new Model(path); if(m2->open()) - { - m2->ConvertToVMAPModel((char*)szLocalFile); - } + m2->ConvertToVMAPModel(szLocalFile); delete m2; } else fclose(output); } + delete[] buf; } + } else if (!strcmp(fourcc,"MWMO")) { diff --git a/contrib/vmap_extractor_v2/vmapextract/adtfile.h b/contrib/vmap_extractor_v2/vmapextract/adtfile.h index 4ce58d3c4..0ce5851ab 100644 --- a/contrib/vmap_extractor_v2/vmapextract/adtfile.h +++ b/contrib/vmap_extractor_v2/vmapextract/adtfile.h @@ -24,17 +24,17 @@ typedef struct float z; }svec; -typedef struct +struct vec { double x; double y; double z; -}vec; +}; -typedef struc +struct triangle { vec v[3]; -}triangle; +}; typedef struct { diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq.cpp b/contrib/vmap_extractor_v2/vmapextract/mpq.cpp index 333bb2f50..df2ad9364 100644 --- a/contrib/vmap_extractor_v2/vmapextract/mpq.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/mpq.cpp @@ -3,23 +3,16 @@ #include "Stormlib.h" #define __STORMLIB_SELF__ -typedef std::vector ArchiveSet; -ArchiveSet gOpenArchives; +MPQArchiveSet gOpenArchives; +//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx MPQArchive::MPQArchive(const char* filename) { BOOL succ = SFileOpenArchive(filename, 0, 0,&hMPQ); if (succ) - { - MPQArchive*ar = (MPQArchive*)(hMPQ); printf("Opening %s\n", filename); - gOpenArchives.push_back(ar); - succ = true; - } else - { printf("Error!!!Not open archive %s\n", filename); - } } void MPQArchive::close() @@ -27,16 +20,36 @@ void MPQArchive::close() SFileCloseArchive(hMPQ); } +bool MPQArchiveSet::Open( std::vector const& archiveNames ) +{ + for (size_t i=0; i < archiveNames.size(); ++i) + { + MPQArchive mpqarch(archiveNames[i].c_str()); + if(mpqarch.isOpen()) + archives.push_back(mpqarch); + } + + return !archives.empty(); +} + +MPQArchiveSet::~MPQArchiveSet() +{ + // close archives + for (ArchiveSet::iterator ar_itr = archives.begin(); ar_itr != archives.end(); ++ar_itr) + ar_itr->close(); +} + +//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx MPQFile::MPQFile(const char* filename): eof(false), buffer(0), pointer(0), size(0) { - for(ArchiveSet::iterator i=gOpenArchives.begin(); i!=gOpenArchives.end();++i) + for(ArchiveSet::const_iterator i=gOpenArchives.archives.begin(); i!=gOpenArchives.archives.end();++i) { HANDLE hFile = ""; - MPQArchive*(hMPQ) = *i; + hMPQ = i->hMPQ; BOOL succ = SFileOpenFileEx(hMPQ,filename,0, &hFile); if (succ) { @@ -54,11 +67,12 @@ MPQFile::MPQFile(const char* filename): eof = false; return; - } + } } eof = true; buffer = 0; + } MPQFile::~MPQFile() diff --git a/contrib/vmap_extractor_v2/vmapextract/mpq.h b/contrib/vmap_extractor_v2/vmapextract/mpq.h index 8fc885667..c1b04c2b3 100644 --- a/contrib/vmap_extractor_v2/vmapextract/mpq.h +++ b/contrib/vmap_extractor_v2/vmapextract/mpq.h @@ -17,12 +17,28 @@ typedef unsigned int uint32; class MPQArchive { -public: - HANDLE hMPQ; - MPQArchive(const char* filename); - void close(); + public: + HANDLE hMPQ; + MPQArchive(const char* filename); + void close(); + bool isOpen() const { return hMPQ != 0; } }; +typedef std::vector ArchiveSet; + +class MPQArchiveSet +{ + public: + MPQArchiveSet() {} + ~MPQArchiveSet(); + + bool Open(std::vector const& archiveNames); + + ArchiveSet archives; +}; + +extern MPQArchiveSet gOpenArchives; + class MPQFile { HANDLE hFile; diff --git a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp index 32ff7970c..6a8c6420c 100644 --- a/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp +++ b/contrib/vmap_extractor_v2/vmapextract/vmapexport.cpp @@ -89,6 +89,7 @@ static const char * GetPlainName(const char * szFileName) static void ShowProcessedFile(const char * szFileName) { +/* not truncate file names in output char szLine[80]; size_t nLength = strlen(szFileName); @@ -99,13 +100,15 @@ static void ShowProcessedFile(const char * szFileName) nLength = sizeof(szLine)-1; memcpy(szLine, szFileName, nLength); printf("\r%s\n", szLine); +*/ + printf("\r%s\n", szFileName); } -int ExtractWmo(const std::vector& pArchiveNames) +//---------------------------------------------------------------------------------------------------------------------------------------------------------------------- +int ExtractWmo() { char* szListFile = ""; char szLocalFile[MAX_PATH] = ""; - HANDLE hMpq = ""; BOOL bResult = FALSE; //const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"}; @@ -113,20 +116,14 @@ int ExtractWmo(const std::vector& pArchiveNames) int nError = ERROR_SUCCESS; if(szListFile == NULL || *szListFile == 0) szListFile = NULL; - //char tmp[1024]; - //for (size_t i=0; i<4; i++) - for (size_t i=0; ihMPQ,"*.wmo*", &wf, szListFile); bResult = TRUE; while(hFind != NULL && bResult == TRUE) @@ -170,10 +167,10 @@ int ExtractWmo(const std::vector& pArchiveNames) { for (int i=0; inGroups; ++i) { - char temp[512]; + char temp[MAX_PATH]; strcpy(temp, wf.cFileName); temp[strlen(wf.cFileName)-4] = 0; - char groupFileName[512]; + char groupFileName[MAX_PATH]; sprintf(groupFileName,"%s_%03d.wmo",temp, i); printf("%s\n",groupFileName); //printf("GroupWmo!\n"); @@ -211,11 +208,9 @@ int ExtractWmo(const std::vector& pArchiveNames) } } - // Close both archives - if(hMpq != NULL) - //SFileCloseArchive(hMpq); - if(nError == ERROR_SUCCESS) - printf("\nExtract wmo complete (No errors)\n"); + + if(nError == ERROR_SUCCESS) + printf("\nExtract wmo complete (No errors)\n"); return nError; } @@ -528,27 +523,31 @@ int main(int argc, char ** argv) nError = GetLastError(); if(nError == ERROR_ALREADY_EXISTS) nError = ERROR_SUCCESS; - } - //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - // patch goes first -> fake priority handling - std::vector archives; + } - //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + // prepare archive name list std::vector archiveNames; - fillArchiveNameVector(archiveNames); - for (size_t i=0; iopen(); + if(!dbc->open()) + { + delete dbc; + printf("FATAL ERROR: Map.dbc not found in data file.\n"); + return 1; + } map_count=dbc->getRecordCount (); map_ids=new map_id[map_count]; for(unsigned int x=0;x