diff --git a/changelog.txt b/changelog.txt index 0a85c5259..60a1e4b9d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/24/2014 == +Trevius: (RoF+) Added herosforgemodel field to the npc_types table. Not fully functional yet for NPCs (currently only displays helm correctly). +Trevius: (RoF2) Updated item links from #npcstat command output. + == 12/23/2014 == Uleat: Tidied up some ItemInst* declarations and added some nullptr checks. Trevius: (RoF+) Added support for Hero's Forge Robe Models. Set herosforgemodel field in items table to exact model such as 11607, 11707, etc. diff --git a/common/version.h b/common/version.h index dc6e0d720..f1218e73f 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9063 +#define CURRENT_BINARY_DATABASE_VERSION 9064 #define COMPILE_DATE __DATE__ #define COMPILE_TIME __TIME__ #ifndef WIN32 diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index ad6de4298..61ab5e3d9 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -317,6 +317,7 @@ 9061|2014_12_13_inventory_table_update.sql|SHOW COLUMNS FROM `inventory` LIKE 'ornament_hero_model'|empty| 9062|2014_12_15_multiple_table_updates.sql|SHOW COLUMNS FROM `items` LIKE 'augslot6type'|empty| 9063|2014_12_24_npc_types_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'd_melee_texture1'|empty| +9064|2014_12_24_npc_types_table_update.sql|SHOW COLUMNS FROM `npc_types` LIKE 'herosforgemodel'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2014_12_24_npc_types_table_update.sql b/utils/sql/git/required/2014_12_24_npc_types_table_update.sql new file mode 100644 index 000000000..c65749b36 --- /dev/null +++ b/utils/sql/git/required/2014_12_24_npc_types_table_update.sql @@ -0,0 +1 @@ +ALTER TABLE `npc_types` ADD `herosforgemodel` int( 11 ) NOT NULL DEFAULT '0' AFTER `helmtexture`; \ No newline at end of file diff --git a/zone/mob.cpp b/zone/mob.cpp index 2f66cf51d..455a1c4ef 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -978,7 +978,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName)); - for (i = 0; i < _MaterialCount; i++) + //for (i = 0; i < _MaterialCount; i++) + for (i = 0; i < 9; i++) { // Only Player Races Wear Armor if (Mob::IsPlayerRace(race) || i > 6) @@ -2733,7 +2734,6 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const int32 Mob::GetHerosForgeModel(uint8 material_slot) const { - uint32 HeroModel = 0; if (material_slot >= 0 && material_slot < MaterialPrimary) { @@ -2744,7 +2744,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const if (item != 0 && invslot != INVALID_INDEX) { - if (this->IsClient()) + if (IsClient()) { const ItemInst* inst = CastToClient()->m_inv[invslot]; if (inst) @@ -2766,6 +2766,16 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const HeroModel = item->HerosForgeModel; } } + + if (IsNPC()) + { + HeroModel = CastToNPC()->GetHeroForgeModel(); + // Robes require full model number, and should only be sent to chest slot + if (HeroModel > 1000 && material_slot != 1) + { + HeroModel = 0; + } + } } // Auto-Convert Hero Model to match the slot diff --git a/zone/npc.cpp b/zone/npc.cpp index e57f70208..d52365f72 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -263,6 +263,8 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float d_melee_texture1 = d->d_melee_texture1; d_melee_texture2 = d->d_melee_texture2; + herosforgemodel = d->herosforgemodel; + ammo_idfile = d->ammo_idfile; memset(equipment, 0, sizeof(equipment)); prim_melee_type = d->prim_melee_type; @@ -508,7 +510,11 @@ void NPC::QueryLoot(Client* to) { for(; cur != end; ++cur) { const Item_Struct* item = database.GetItem((*cur)->item_id); if (item) - if (to->GetClientVersion() >= EQClientRoF) + if (to->GetClientVersion() >= EQClientRoF2) + { + to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X00000000000000000000000000000000000000000000000000%s%c", (*cur)->min_level, (*cur)->max_level, (int)item->ID, 0x12, item->ID, item->Name, 0x12); + } + else if (to->GetClientVersion() >= EQClientRoF) { to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12); } diff --git a/zone/npc.h b/zone/npc.h index b8a948800..72395622b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -403,6 +403,9 @@ public: void mod_npc_killed(Mob* oos); void AISpellsList(Client *c); + uint32 GetHeroForgeModel() const { return herosforgemodel; } + void SetHeroForgeModel(uint32 model) { herosforgemodel = model; } + bool IsRaidTarget() const { return raid_target; }; protected: @@ -492,6 +495,8 @@ protected: uint16 skills[HIGHEST_SKILL+1]; uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs + + uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203) uint16 d_melee_texture1; //this is an item Material value uint16 d_melee_texture2; //this is an item Material value (offhand) const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile') diff --git a/zone/pets.cpp b/zone/pets.cpp index 5c1f4e0cd..6bd92cdca 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -393,6 +393,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, npc_type->gender = monster->gender; npc_type->luclinface = monster->luclinface; npc_type->helmtexture = monster->helmtexture; + npc_type->herosforgemodel = monster->herosforgemodel; } else LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid); diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index bf2f5841b..8d5bc1dd0 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -1740,7 +1740,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { // according to spawn2. std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, " "npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, " - "npc_types.texture, npc_types.helmtexture, npc_types.size, " + "npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, " "npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, " "npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, " "npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, " @@ -1790,82 +1790,83 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { tmpNPCType->gender = atoi(row[7]); tmpNPCType->texture = atoi(row[8]); tmpNPCType->helmtexture = atoi(row[9]); - tmpNPCType->size = atof(row[10]); - tmpNPCType->loottable_id = atoi(row[11]); - tmpNPCType->merchanttype = atoi(row[12]); - tmpNPCType->alt_currency_type = atoi(row[13]); - tmpNPCType->adventure_template = atoi(row[14]); - tmpNPCType->trap_template = atoi(row[15]); - tmpNPCType->attack_speed = atof(row[16]); - tmpNPCType->STR = atoi(row[17]); - tmpNPCType->STA = atoi(row[18]); - tmpNPCType->DEX = atoi(row[19]); - tmpNPCType->AGI = atoi(row[20]); - tmpNPCType->INT = atoi(row[21]); - tmpNPCType->WIS = atoi(row[22]); - tmpNPCType->CHA = atoi(row[23]); - tmpNPCType->MR = atoi(row[24]); - tmpNPCType->CR = atoi(row[25]); - tmpNPCType->DR = atoi(row[26]); - tmpNPCType->FR = atoi(row[27]); - tmpNPCType->PR = atoi(row[28]); - tmpNPCType->Corrup = atoi(row[29]); - tmpNPCType->PhR = atoi(row[30]); - tmpNPCType->min_dmg = atoi(row[31]); - tmpNPCType->max_dmg = atoi(row[32]); - tmpNPCType->attack_count = atoi(row[33]); + tmpNPCType->herosforgemodel = atoi(row[10]); + tmpNPCType->size = atof(row[11]); + tmpNPCType->loottable_id = atoi(row[12]); + tmpNPCType->merchanttype = atoi(row[13]); + tmpNPCType->alt_currency_type = atoi(row[14]); + tmpNPCType->adventure_template = atoi(row[15]); + tmpNPCType->trap_template = atoi(row[16]); + tmpNPCType->attack_speed = atof(row[17]); + tmpNPCType->STR = atoi(row[18]); + tmpNPCType->STA = atoi(row[19]); + tmpNPCType->DEX = atoi(row[20]); + tmpNPCType->AGI = atoi(row[21]); + tmpNPCType->INT = atoi(row[22]); + tmpNPCType->WIS = atoi(row[23]); + tmpNPCType->CHA = atoi(row[24]); + tmpNPCType->MR = atoi(row[25]); + tmpNPCType->CR = atoi(row[26]); + tmpNPCType->DR = atoi(row[27]); + tmpNPCType->FR = atoi(row[28]); + tmpNPCType->PR = atoi(row[29]); + tmpNPCType->Corrup = atoi(row[30]); + tmpNPCType->PhR = atoi(row[31]); + tmpNPCType->min_dmg = atoi(row[32]); + tmpNPCType->max_dmg = atoi(row[33]); + tmpNPCType->attack_count = atoi(row[34]); if (row[34] != nullptr) - strn0cpy(tmpNPCType->special_abilities, row[34], 512); + strn0cpy(tmpNPCType->special_abilities, row[35], 512); else tmpNPCType->special_abilities[0] = '\0'; - tmpNPCType->npc_spells_id = atoi(row[35]); - tmpNPCType->npc_spells_effects_id = atoi(row[36]); - tmpNPCType->d_melee_texture1 = atoi(row[37]); - tmpNPCType->d_melee_texture2 = atoi(row[38]); - strn0cpy(tmpNPCType->ammo_idfile, row[39], 30); - tmpNPCType->prim_melee_type = atoi(row[40]); - tmpNPCType->sec_melee_type = atoi(row[41]); - tmpNPCType->ranged_type = atoi(row[42]); - tmpNPCType->runspeed= atof(row[43]); - tmpNPCType->findable = atoi(row[44]) == 0? false : true; - tmpNPCType->trackable = atoi(row[45]) == 0? false : true; - tmpNPCType->hp_regen = atoi(row[46]); - tmpNPCType->mana_regen = atoi(row[47]); + tmpNPCType->npc_spells_id = atoi(row[36]); + tmpNPCType->npc_spells_effects_id = atoi(row[37]); + tmpNPCType->d_melee_texture1 = atoi(row[38]); + tmpNPCType->d_melee_texture2 = atoi(row[39]); + strn0cpy(tmpNPCType->ammo_idfile, row[40], 30); + tmpNPCType->prim_melee_type = atoi(row[41]); + tmpNPCType->sec_melee_type = atoi(row[42]); + tmpNPCType->ranged_type = atoi(row[43]); + tmpNPCType->runspeed= atof(row[44]); + tmpNPCType->findable = atoi(row[45]) == 0? false : true; + tmpNPCType->trackable = atoi(row[46]) == 0? false : true; + tmpNPCType->hp_regen = atoi(row[47]); + tmpNPCType->mana_regen = atoi(row[48]); // set defaultvalue for aggroradius - tmpNPCType->aggroradius = (int32)atoi(row[48]); + tmpNPCType->aggroradius = (int32)atoi(row[49]); if (tmpNPCType->aggroradius <= 0) tmpNPCType->aggroradius = 70; - tmpNPCType->assistradius = (int32)atoi(row[49]); + tmpNPCType->assistradius = (int32)atoi(row[50]); if (tmpNPCType->assistradius <= 0) tmpNPCType->assistradius = tmpNPCType->aggroradius; if (row[50] && strlen(row[50])) - tmpNPCType->bodytype = (uint8)atoi(row[50]); + tmpNPCType->bodytype = (uint8)atoi(row[51]); else tmpNPCType->bodytype = 0; - tmpNPCType->npc_faction_id = atoi(row[51]); + tmpNPCType->npc_faction_id = atoi(row[52]); - tmpNPCType->luclinface = atoi(row[52]); - tmpNPCType->hairstyle = atoi(row[53]); - tmpNPCType->haircolor = atoi(row[54]); - tmpNPCType->eyecolor1 = atoi(row[55]); - tmpNPCType->eyecolor2 = atoi(row[56]); - tmpNPCType->beardcolor = atoi(row[57]); - tmpNPCType->beard = atoi(row[58]); - tmpNPCType->drakkin_heritage = atoi(row[59]); - tmpNPCType->drakkin_tattoo = atoi(row[60]); - tmpNPCType->drakkin_details = atoi(row[61]); + tmpNPCType->luclinface = atoi(row[53]); + tmpNPCType->hairstyle = atoi(row[54]); + tmpNPCType->haircolor = atoi(row[55]); + tmpNPCType->eyecolor1 = atoi(row[56]); + tmpNPCType->eyecolor2 = atoi(row[57]); + tmpNPCType->beardcolor = atoi(row[58]); + tmpNPCType->beard = atoi(row[59]); + tmpNPCType->drakkin_heritage = atoi(row[60]); + tmpNPCType->drakkin_tattoo = atoi(row[61]); + tmpNPCType->drakkin_details = atoi(row[62]); - uint32 armor_tint_id = atoi(row[62]); + uint32 armor_tint_id = atoi(row[63]); - tmpNPCType->armor_tint[0] = (atoi(row[63]) & 0xFF) << 16; - tmpNPCType->armor_tint[0] |= (atoi(row[64]) & 0xFF) << 8; - tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF); + tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16; + tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8; + tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF); tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0; if (armor_tint_id == 0) @@ -1900,32 +1901,32 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) { } else armor_tint_id = 0; - tmpNPCType->see_invis = atoi(row[66]); - tmpNPCType->see_invis_undead = atoi(row[67]) == 0? false: true; // Set see_invis_undead flag + tmpNPCType->see_invis = atoi(row[67]); + tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag if (row[68] != nullptr) - strn0cpy(tmpNPCType->lastname, row[68], 32); + strn0cpy(tmpNPCType->lastname, row[69], 32); - tmpNPCType->qglobal = atoi(row[69]) == 0? false: true; // qglobal - tmpNPCType->AC = atoi(row[70]); - tmpNPCType->npc_aggro = atoi(row[71]) == 0? false: true; - tmpNPCType->spawn_limit = atoi(row[72]); - tmpNPCType->see_hide = atoi(row[73]) == 0? false: true; - tmpNPCType->see_improved_hide = atoi(row[74]) == 0? false: true; - tmpNPCType->ATK = atoi(row[75]); - tmpNPCType->accuracy_rating = atoi(row[76]); - tmpNPCType->avoidance_rating = atoi(row[77]); - tmpNPCType->slow_mitigation = atoi(row[78]); - tmpNPCType->maxlevel = atoi(row[79]); - tmpNPCType->scalerate = atoi(row[80]); - tmpNPCType->private_corpse = atoi(row[81]) == 1 ? true: false; - tmpNPCType->unique_spawn_by_name = atoi(row[82]) == 1 ? true: false; - tmpNPCType->underwater = atoi(row[83]) == 1 ? true: false; - tmpNPCType->emoteid = atoi(row[84]); - tmpNPCType->spellscale = atoi(row[85]); - tmpNPCType->healscale = atoi(row[86]); - tmpNPCType->no_target_hotkey = atoi(row[87]) == 1 ? true: false; - tmpNPCType->raid_target = atoi(row[88]) == 0 ? false: true; - tmpNPCType->attack_delay = atoi(row[89]); + tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal + tmpNPCType->AC = atoi(row[71]); + tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true; + tmpNPCType->spawn_limit = atoi(row[73]); + tmpNPCType->see_hide = atoi(row[74]) == 0? false: true; + tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true; + tmpNPCType->ATK = atoi(row[76]); + tmpNPCType->accuracy_rating = atoi(row[77]); + tmpNPCType->avoidance_rating = atoi(row[78]); + tmpNPCType->slow_mitigation = atoi(row[79]); + tmpNPCType->maxlevel = atoi(row[80]); + tmpNPCType->scalerate = atoi(row[81]); + tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false; + tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false; + tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false; + tmpNPCType->emoteid = atoi(row[85]); + tmpNPCType->spellscale = atoi(row[86]); + tmpNPCType->healscale = atoi(row[87]); + tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false; + tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true; + tmpNPCType->attack_delay = atoi(row[90]); // If NPC with duplicate NPC id already in table, // free item we attempted to add. diff --git a/zone/zonedump.h b/zone/zonedump.h index 36a53df9c..3dd6d4569 100644 --- a/zone/zonedump.h +++ b/zone/zonedump.h @@ -49,6 +49,7 @@ struct NPCType uint32 npc_id; uint8 texture; uint8 helmtexture; + uint32 herosforgemodel; uint32 loottable_id; uint32 npc_spells_id; uint32 npc_spells_effects_id;