From d3819ec13575875895a27d624e1fab8afde2ea85 Mon Sep 17 00:00:00 2001 From: Emagi <image.emagi@gmail.com> Date: Fri, 15 Jul 2022 07:57:21 -0400 Subject: [PATCH] - Fix #412 - "placed" function now called on ItemScript placement in homes. The placed spawn will be the target field (after player). - Fixed some additional lacking group member checks and bad returns inside mutex locks - Fix #432 - set languages on sign/conversation, we can now set language in spawn_signs, language setting only garbles description, not title of spawn_signs * StartDialogConversation has a 9th parameter (after key2) for language (int8), 10th parameter is can_close (defaults to 1) * StartConversation has an 8th parameter (after key2) for language (int8), 9th prameter is can_close (defaults to 1) * spawn_signs table now supports the language parameter, db update: alter table spawn_signs add column language tinyint(3) unsigned default 0; - Fixed AoM skill display for general skills, languages now display too, but we need to discover how to omit skill values - /spawn details now includes sign language on the third page if the spawn is a sign. --- EQ2/source/WorldServer/Bots/Bot.cpp | 7 ++- EQ2/source/WorldServer/Bots/BotCommands.cpp | 5 +- EQ2/source/WorldServer/Combat.cpp | 3 +- EQ2/source/WorldServer/Commands/Commands.cpp | 4 ++ EQ2/source/WorldServer/LuaFunctions.cpp | 48 +++++++---------- EQ2/source/WorldServer/Player.cpp | 4 ++ EQ2/source/WorldServer/Sign.cpp | 2 + EQ2/source/WorldServer/Sign.h | 5 +- EQ2/source/WorldServer/Skills.cpp | 32 ++++++++--- EQ2/source/WorldServer/Spawn.cpp | 6 ++- EQ2/source/WorldServer/SpellProcess.cpp | 6 +-- EQ2/source/WorldServer/WorldDatabase.cpp | 13 +++-- EQ2/source/WorldServer/client.cpp | 57 +++++++++++++------- EQ2/source/WorldServer/client.h | 8 +-- 14 files changed, 121 insertions(+), 79 deletions(-) diff --git a/EQ2/source/WorldServer/Bots/Bot.cpp b/EQ2/source/WorldServer/Bots/Bot.cpp index a64f4e0d1..7bd9114d3 100644 --- a/EQ2/source/WorldServer/Bots/Bot.cpp +++ b/EQ2/source/WorldServer/Bots/Bot.cpp @@ -415,10 +415,13 @@ Spell* Bot::GetHoTWardSpell() { { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return 0; + for (int8 i = 0; i < members->size(); i++) { Entity* member = members->at(i)->member; + + if(!member) + continue; + int8 percent = 0; if (member->GetHP() > 0) percent = (int8)(((float)member->GetHP() / member->GetTotalHP()) * 100); diff --git a/EQ2/source/WorldServer/Bots/BotCommands.cpp b/EQ2/source/WorldServer/Bots/BotCommands.cpp index 39beb5471..83ae9b45d 100644 --- a/EQ2/source/WorldServer/Bots/BotCommands.cpp +++ b/EQ2/source/WorldServer/Bots/BotCommands.cpp @@ -114,11 +114,10 @@ void Commands::Command_Bot(Client* client, Seperator* sep) { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return; - for (int8 i = 0; i < members->size(); i++) { GroupMemberInfo* gmi2 = members->at(i); + if(!gmi2 || !gmi2->member) + continue; if (gmi2->member->IsBot() && ((Bot*)gmi2->member)->GetOwner() == client->GetPlayer()) { ((Bot*)gmi2->member)->SetMainTank(target); client->Message(CHANNEL_COMMAND_TEXT, "Setting main tank for %s to %s", gmi2->member->GetName(), target->GetName()); diff --git a/EQ2/source/WorldServer/Combat.cpp b/EQ2/source/WorldServer/Combat.cpp index 1731ddcfa..5365923c5 100644 --- a/EQ2/source/WorldServer/Combat.cpp +++ b/EQ2/source/WorldServer/Combat.cpp @@ -1247,8 +1247,7 @@ void Entity::HandleDeathExperienceDebt(Spawn* killer) { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return; + int32 size = members->size(); float xpDebtPerMember = ruleDebt/(float)size; deque<GroupMemberInfo*>::iterator itr; diff --git a/EQ2/source/WorldServer/Commands/Commands.cpp b/EQ2/source/WorldServer/Commands/Commands.cpp index 3ae8548be..7d361fe98 100644 --- a/EQ2/source/WorldServer/Commands/Commands.cpp +++ b/EQ2/source/WorldServer/Commands/Commands.cpp @@ -4709,6 +4709,10 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie details3 += "Speed: " + to_string(spawn->GetSpeed()) + "\n"; details3 += "BaseSpeed: " + to_string(spawn->GetBaseSpeed()) + "\n"; + if(spawn->IsSign()) { + details3 += "Sign Language: " + to_string(((Sign*)spawn)->GetLanguage()) + "\n"; + } + if(spawn->IsEntity()) { Entity* ent = (Entity*)spawn; diff --git a/EQ2/source/WorldServer/LuaFunctions.cpp b/EQ2/source/WorldServer/LuaFunctions.cpp index 3feba37fa..e13675520 100755 --- a/EQ2/source/WorldServer/LuaFunctions.cpp +++ b/EQ2/source/WorldServer/LuaFunctions.cpp @@ -1019,6 +1019,12 @@ int EQ2Emu_lua_StartDialogConversation(lua_State* state) { string mp3 = lua_interface->GetStringValue(state, 6); int32 key1 = lua_interface->GetInt32Value(state, 7); int32 key2 = lua_interface->GetInt32Value(state, 8); + int8 language = lua_interface->GetInt8Value(state, 9); + + int numargs = lua_interface->GetNumberOfArgs(state); + int8 can_close = 1; + if(numargs > 9) + can_close = lua_interface->GetInt32Value(state, 10); lua_interface->ResetFunctionStack(state); if (conversation && text.length() > 0 && (spawn || item) && player && player->IsPlayer()) { @@ -1030,15 +1036,15 @@ int EQ2Emu_lua_StartDialogConversation(lua_State* state) { type++; if (mp3.length() > 0) - client->DisplayConversation((Entity*)spawn, type, conversation, const_cast<char*>(text.c_str()), mp3.c_str(), key1, key2); + client->DisplayConversation((Entity*)spawn, type, conversation, const_cast<char*>(text.c_str()), mp3.c_str(), key1, key2, language, can_close); else - client->DisplayConversation((Entity*)spawn, type, conversation, const_cast<char*>(text.c_str())); + client->DisplayConversation((Entity*)spawn, type, conversation, const_cast<char*>(text.c_str()), nullptr, 0, 0, language, can_close); } else { if (mp3.length() > 0) - client->DisplayConversation(item, conversation, const_cast<char*>(text.c_str()), type, mp3.c_str(), key1, key2); + client->DisplayConversation(item, conversation, const_cast<char*>(text.c_str()), type, mp3.c_str(), key1, key2, language, can_close); else - client->DisplayConversation(item, conversation, const_cast<char*>(text.c_str()), type); + client->DisplayConversation(item, conversation, const_cast<char*>(text.c_str()), type, nullptr, 0, 0, language, can_close); } } } @@ -1047,29 +1053,6 @@ int EQ2Emu_lua_StartDialogConversation(lua_State* state) { return 0; } -/*int EQ2Emu_lua_StartItemConversation(lua_State* state){ - if(!lua_interface) - return 0; - vector<ConversationOption>* conversation = lua_interface->GetConversation(state); - Item* item = lua_interface->GetItem(state, 2); - Spawn* player = lua_interface->GetSpawn(state, 3); - string text = lua_interface->GetStringValue(state, 4); - string mp3 = lua_interface->GetStringValue(state, 5); - int32 key1 = lua_interface->GetInt32Value(state, 6); - int32 key2 = lua_interface->GetInt32Value(state, 7); - if(conversation && text.length() > 0 && item && player && player->IsPlayer()){ - Client* client = player->GetZone()->GetClientBySpawn(player); - if(client){ - if(mp3.length() > 0) - client->DisplayConversation(item, conversation, (char*)text.c_str(), mp3.c_str(), key1, key2); - else - client->DisplayConversation(item, conversation, (char*)text.c_str()); - } - safe_delete(conversation); - } - return 0; -}*/ - int EQ2Emu_lua_StartConversation(lua_State* state) { if (!lua_interface) return 0; @@ -1080,13 +1063,20 @@ int EQ2Emu_lua_StartConversation(lua_State* state) { string mp3 = lua_interface->GetStringValue(state, 5); int32 key1 = lua_interface->GetInt32Value(state, 6); int32 key2 = lua_interface->GetInt32Value(state, 7); + int8 language = lua_interface->GetInt32Value(state, 8); + + int numargs = lua_interface->GetNumberOfArgs(state); + int8 can_close = 1; + if(numargs > 8) + can_close = lua_interface->GetInt32Value(state, 9); + lua_interface->ResetFunctionStack(state); if (conversation && conversation->size() > 0 && text.length() > 0 && source && player && player->IsPlayer()) { Client* client = source->GetZone()->GetClientBySpawn(player); if (mp3.length() > 0) - client->DisplayConversation(source, 1, conversation, text.c_str(), mp3.c_str(), key1, key2); + client->DisplayConversation(source, 1, conversation, text.c_str(), mp3.c_str(), key1, key2, language, can_close); else - client->DisplayConversation(source, 1, conversation, text.c_str()); + client->DisplayConversation(source, 1, conversation, text.c_str(), nullptr, 0, 0, language, can_close); safe_delete(conversation); lua_interface->SetConversationValue(state, NULL); } diff --git a/EQ2/source/WorldServer/Player.cpp b/EQ2/source/WorldServer/Player.cpp index 4c872e178..f7cdcca40 100644 --- a/EQ2/source/WorldServer/Player.cpp +++ b/EQ2/source/WorldServer/Player.cpp @@ -6100,6 +6100,10 @@ void Player::AddAAEntry(int16 template_id, int8 tab_id, int32 aa_id, int16 order } void Player::AddLanguage(int32 id, const char *name, bool save_needed){ + Skill* skill = master_skill_list.GetSkillByName(name); + if(skill && !GetSkills()->HasSkill(skill->skill_id)) { + AddSkill(skill->skill_id, 1, skill->max_val, true); + } // Check to see if the player already has the language if (HasLanguage(id)) return; diff --git a/EQ2/source/WorldServer/Sign.cpp b/EQ2/source/WorldServer/Sign.cpp index 3d58f873c..07a1f00eb 100644 --- a/EQ2/source/WorldServer/Sign.cpp +++ b/EQ2/source/WorldServer/Sign.cpp @@ -48,6 +48,7 @@ Sign::Sign(){ include_location = false; include_heading = false; zone_id = 0; + language = 0; } Sign::~Sign(){ @@ -150,6 +151,7 @@ Sign* Sign::Copy(){ new_spawn->SetOmittedByDBFlag(IsOmittedByDBFlag()); new_spawn->SetLootTier(GetLootTier()); new_spawn->SetLootDropType(GetLootDropType()); + new_spawn->SetLanguage(GetLanguage()); return new_spawn; } diff --git a/EQ2/source/WorldServer/Sign.h b/EQ2/source/WorldServer/Sign.h index 85b7f0fbd..d202bf5c0 100644 --- a/EQ2/source/WorldServer/Sign.h +++ b/EQ2/source/WorldServer/Sign.h @@ -66,7 +66,9 @@ public: bool GetIncludeLocation(); void SetIncludeHeading(bool val); bool GetIncludeHeading(); - + void SetLanguage(int8 in_language) { language = in_language; } + int8 GetLanguage() { return language; } + private: string description; string title; @@ -83,6 +85,7 @@ private: float sign_distance; bool include_location; bool include_heading; + int8 language; }; #endif diff --git a/EQ2/source/WorldServer/Skills.cpp b/EQ2/source/WorldServer/Skills.cpp index f9fecf216..ee2e7c586 100644 --- a/EQ2/source/WorldServer/Skills.cpp +++ b/EQ2/source/WorldServer/Skills.cpp @@ -370,15 +370,31 @@ EQ2Packet* PlayerSkillList::GetSkillPacket(int16 version){ if (version <= 546 && skill->skill_type >= SKILL_TYPE_GENERAL) { //covert it to DOF types packet->setArrayDataByName("type", skill->skill_type-2, i); } - else + else if(version >= 60085 && skill->skill_type >= 12) { + packet->setArrayDataByName("type", skill->skill_type-1, i); + } + else { packet->setArrayDataByName("type", skill->skill_type, i); - packet->setArrayDataByName("current_val", skill->current_val, i); - packet->setArrayDataByName("base_val", skill->current_val, i);// skill-> - packet->setArrayDataByName("skill_delta", 0, i);// skill_with_bonuses- skill->current_val - packet->setArrayDataByName("skill_delta2", skill_max_with_bonuses - skill->max_val, i);// skill_max_with_bonuses - skill->max_val, i); - packet->setArrayDataByName("max_val", skill->max_val, i); - packet->setArrayDataByName("display_minval", skill->display, i); - packet->setArrayDataByName("display_maxval", skill->display, i); + } + + int16 current_val = skill->current_val; + + if(skill->skill_type == SKILL_TYPE_LANGUAGE) { // 13 is language in the DB?? 14 is the skill type though + packet->setArrayDataByName("language_unknown", skill->skill_id, i); + packet->setArrayDataByName("display_maxval", 1, i); + packet->setArrayDataByName("max_val", 1, i); + } + else { + packet->setArrayDataByName("max_val", skill->max_val, i); + packet->setArrayDataByName("display_minval", skill->display, i); + packet->setArrayDataByName("display_maxval", skill->display, i); + packet->setArrayDataByName("skill_delta", 0, i);// skill_with_bonuses- skill->current_val + packet->setArrayDataByName("skill_delta2", skill_max_with_bonuses - skill->max_val, i);// skill_max_with_bonuses - skill->max_val, i); + } + + packet->setArrayDataByName("current_val", current_val, i); + packet->setArrayDataByName("base_val", current_val, i); + i++; } } diff --git a/EQ2/source/WorldServer/Spawn.cpp b/EQ2/source/WorldServer/Spawn.cpp index fe5cda14a..80f2fbda1 100644 --- a/EQ2/source/WorldServer/Spawn.cpp +++ b/EQ2/source/WorldServer/Spawn.cpp @@ -403,7 +403,6 @@ void Spawn::InitializeFooterPacketData(Player* player, PacketStruct* footer) { footer->setDataByName("widget_z", widget->GetWidgetZ()); } footer->setDataByName("widget_id", widget->GetWidgetID()); - footer->setDataByName("unknown3c", 6); } else if (IsSign()){ Sign* sign = (Sign*)this; @@ -411,13 +410,16 @@ void Spawn::InitializeFooterPacketData(Player* player, PacketStruct* footer) { footer->setDataByName("widget_x", sign->GetWidgetX()); footer->setDataByName("widget_y", sign->GetWidgetY()); footer->setDataByName("widget_z", sign->GetWidgetZ()); - footer->setDataByName("unknown2b", 6); if (sign->GetSignTitle()) footer->setMediumStringByName("title", sign->GetSignTitle()); if (sign->GetSignDescription()) footer->setMediumStringByName("description", sign->GetSignDescription()); footer->setDataByName("sign_distance", sign->GetSignDistance()); footer->setDataByName("show", 1); + // in live we see that the language is set when the player does not have it, otherwise its left as 00's. + if(!player->HasLanguage(sign->GetLanguage())) { + footer->setDataByName("language", sign->GetLanguage()); + } } if ( IsPlayer()) diff --git a/EQ2/source/WorldServer/SpellProcess.cpp b/EQ2/source/WorldServer/SpellProcess.cpp index 59ddaeae4..3ae6d964b 100644 --- a/EQ2/source/WorldServer/SpellProcess.cpp +++ b/EQ2/source/WorldServer/SpellProcess.cpp @@ -2386,8 +2386,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell) { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return; + // iterate through players group members for (itr = members->begin(); itr != members->end(); itr++) { @@ -2436,8 +2435,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell) { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return; + Entity* group_member = 0; for (itr = members->begin(); itr != members->end(); itr++) { group_member = (*itr)->member; diff --git a/EQ2/source/WorldServer/WorldDatabase.cpp b/EQ2/source/WorldServer/WorldDatabase.cpp index b81032efe..621581e9d 100644 --- a/EQ2/source/WorldServer/WorldDatabase.cpp +++ b/EQ2/source/WorldServer/WorldDatabase.cpp @@ -1216,7 +1216,7 @@ void WorldDatabase::LoadSigns(ZoneServer* zone){ Sign* sign = 0; int32 id = 0; int32 total = 0; - MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state, s.expansion_flag, s.holiday_flag, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type\n" + MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state, s.expansion_flag, s.holiday_flag, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type, ss.language\n" "FROM spawn s\n" "INNER JOIN spawn_signs ss\n" "ON s.id = ss.spawn_id\n" @@ -1295,6 +1295,8 @@ void WorldDatabase::LoadSigns(ZoneServer* zone){ sign->SetLootDropType(atoul(row[35])); + sign->SetLanguage(atoul(row[36])); + zone->AddSign(id, sign); total++; @@ -3425,14 +3427,14 @@ bool WorldDatabase::SaveSpawnInfo(Spawn* spawn){ } else if(spawn->IsSign()){ Sign* sign = (Sign*)spawn; - query.RunQuery2(Q_UPDATE, "update spawn_signs, spawn set name='%s', race=%i, model_type=%i, show_name=%i, attackable=%i, show_level=%i, show_command_icon=%i, display_hand_icon=%i, size=%i, hp=%u, power=%u, collision_radius=%i, command_primary=%u, command_secondary=%u, visual_state=%i, faction_id=%u, suffix ='%s', prefix='%s', last_name='%s', type='%s', zone_id = %u, widget_id = %u, title='%s', widget_x = %f, widget_y = %f, widget_z = %f, icon = %u, description='%s', sign_distance = %f, zone_x = %f, zone_y = %f, zone_z = %f, zone_heading = %f, include_heading = %u, include_location = %u, merchant_min_level = %u, merchant_max_level = %u where spawn_signs.spawn_id = spawn.id and spawn.id = %u", + query.RunQuery2(Q_UPDATE, "update spawn_signs, spawn set name='%s', race=%i, model_type=%i, show_name=%i, attackable=%i, show_level=%i, show_command_icon=%i, display_hand_icon=%i, size=%i, hp=%u, power=%u, collision_radius=%i, command_primary=%u, command_secondary=%u, visual_state=%i, faction_id=%u, suffix ='%s', prefix='%s', last_name='%s', type='%s', zone_id = %u, widget_id = %u, title='%s', widget_x = %f, widget_y = %f, widget_z = %f, icon = %u, description='%s', sign_distance = %f, zone_x = %f, zone_y = %f, zone_z = %f, zone_heading = %f, include_heading = %u, include_location = %u, merchant_min_level = %u, merchant_max_level = %u, language = %u where spawn_signs.spawn_id = spawn.id and spawn.id = %u", name.c_str(), spawn->GetRace(), spawn->GetModelType(), spawn->appearance.display_name, spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon, spawn->GetSize(), spawn->GetTotalHP(), spawn->GetTotalPower(), spawn->GetCollisionRadius(), spawn->GetPrimaryCommandListID(), spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->GetFactionID(), suffix.c_str(), prefix.c_str(), last_name.c_str(), sign->GetSignType(), sign->GetSignZoneID(), sign->GetWidgetID(), sign->GetSignTitle(), sign->GetWidgetX(), sign->GetWidgetY(), sign->GetWidgetZ(), sign->GetIconValue(), sign->GetSignDescription(), sign->GetSignDistance(), sign->GetSignZoneX(), sign->GetSignZoneY(), sign->GetSignZoneZ(), sign->GetSignZoneHeading(), sign->GetIncludeHeading(), - sign->GetIncludeLocation(), spawn->GetMerchantMinLevel(), spawn->GetMerchantMaxLevel(), spawn->GetDatabaseID()); + sign->GetIncludeLocation(), spawn->GetMerchantMinLevel(), spawn->GetMerchantMaxLevel(), sign->GetLanguage(), spawn->GetDatabaseID()); } } if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){ @@ -6391,7 +6393,7 @@ bool WorldDatabase::LoadSign(ZoneServer* zone, int32 spawn_id) { Sign* sign = 0; int32 id = 0; DatabaseResult result; - database_new.Select(&result, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type\n" + database_new.Select(&result, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state, s.disable_sounds, s.merchant_min_level, s.merchant_max_level, s.aaxp_rewards, s.loot_tier, s.loot_drop_type, ss.language\n" "FROM spawn s\n" "INNER JOIN spawn_signs ss\n" "ON ss.spawn_id = s.id\n" @@ -6452,6 +6454,9 @@ bool WorldDatabase::LoadSign(ZoneServer* zone, int32 spawn_id) { sign->SetLootTier(result.GetInt32(32)); sign->SetLootDropType(result.GetInt32(33)); + + sign->SetLanguage(result.GetInt8(34)); + zone->AddSign(id, sign); diff --git a/EQ2/source/WorldServer/client.cpp b/EQ2/source/WorldServer/client.cpp index 23f38dd89..bb655983d 100755 --- a/EQ2/source/WorldServer/client.cpp +++ b/EQ2/source/WorldServer/client.cpp @@ -1303,7 +1303,12 @@ bool Client::HandlePacket(EQApplicationPacket* app) { int32 response_index = packet->getType_int32_ByName("response"); if (GetCurrentZone()) { MConversation.readlock(); - Spawn* spawn = conversation_spawns[conversation_id]; + int32 spawn_id = conversation_spawns[conversation_id]; + Spawn* spawn = nullptr; + if(spawn_id) { + spawn = GetCurrentZone()->GetSpawnByID(spawn_id); + } + Item* item = conversation_items[conversation_id]; MConversation.releasereadlock(); if (conversation_map.count(conversation_id) > 0 && conversation_map[conversation_id].count(response_index) > 0) { @@ -2549,6 +2554,8 @@ bool Client::HandleLootItem(Spawn* entity, Item* item) { if(members) { for (int8 i = 0; i < members->size(); i++) { Entity* member = members->at(i)->member; + if(!member) + continue; if ((member->GetZone() != this->GetPlayer()->GetZone())) continue; @@ -5194,11 +5201,12 @@ void Client::CastGroupOrSelf(Entity* source, uint32 spellID, uint32 spellTier, f { group->MGroupMembers.readlock(__FUNCTION__, __LINE__); deque<GroupMemberInfo*>* members = group->GetMembers(); - if(!members) - return; + for (int8 i = 0; i < members->size(); i++) { Entity* member = members->at(i)->member; - + if(!member) + continue; + if (!member->Alive() || (member->GetZone() != source->GetZone())) continue; // if we have a radius provided then check if the group member is outside the radius or not @@ -6323,12 +6331,13 @@ void Client::GiveQuestReward(Quest* quest) { RemovePlayerQuest(quest->GetQuestID(), true, false); } -void Client::DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2) { +void Client::DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language, int8 can_close) { PacketStruct* packet = configReader.getStruct("WS_DialogOpen", GetVersion()); if (packet) { packet->setDataByName("conversation_id", conversation_id); packet->setDataByName("text", text); - packet->setDataByName("unknown2", 1); + packet->setDataByName("language", language); // default 0 + packet->setDataByName("can_close", can_close); // default 1 conversation_map[conversation_id].clear(); if (conversations) { packet->setArrayLengthByName("num_responses", conversations->size()); @@ -6350,7 +6359,7 @@ void Client::DisplayConversation(int32 conversation_id, int32 spawn_id, vector<C } -void Client::DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3, int32 key1, int32 key2) { +void Client::DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3, int32 key1, int32 key2, int8 language, int8 can_close) { if (!item || !text || !conversations || conversations->size() == 0) { return; } @@ -6363,13 +6372,13 @@ void Client::DisplayConversation(Item* item, vector<ConversationOption>* convers conversation_items[conversation_id] = item; MConversation.releasewritelock(); if (type == 4) - DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2); + DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2, language, can_close); else - DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2); + DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2, language, can_close); } -void Client::DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2) { +void Client::DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language, int8 can_close) { if (!src || !(type == 1 || type == 2 || type == 3) || !text /*|| !conversations || conversations->size() == 0*/) { return; } @@ -6379,18 +6388,18 @@ void Client::DisplayConversation(Spawn* src, int8 type, vector<ConversationOptio conversation_id = next_conversation_id; } MConversation.writelock(); - conversation_spawns[conversation_id] = src; + conversation_spawns[conversation_id] = src->GetID(); MConversation.releasewritelock(); /* Spawns can start two different types of conversations. * Type 1: The chat type with bubbles. * Type 2: The dialog type with the blue box. */ if (type == 1) - DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(src), conversations, text, mp3, key1, key2); + DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(src), conversations, text, mp3, key1, key2, language, can_close); else if (type == 2) - DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2); + DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2, language, can_close); else //if (type == 3) - DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2); + DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2, language, can_close); } @@ -6409,7 +6418,7 @@ void Client::CloseDialog(int32 conversation_id) { conversation_items.erase(itr); } - std::map<int32, Spawn*>::iterator itr2 = conversation_spawns.find(conversation_id); + std::map<int32, int32>::iterator itr2 = conversation_spawns.find(conversation_id); while((itr2 = conversation_spawns.find(conversation_id)) != conversation_spawns.end()) { @@ -6423,9 +6432,9 @@ int32 Client::GetConversationID(Spawn* spawn, Item* item) { int32 conversation_id = 0; MConversation.readlock(); if (spawn) { - map<int32, Spawn*>::iterator itr; + map<int32, int32>::iterator itr; for (itr = conversation_spawns.begin(); itr != conversation_spawns.end(); itr++) { - if (itr->second == spawn) { + if (itr->second == spawn->GetID()) { conversation_id = itr->first; break; } @@ -10461,9 +10470,17 @@ bool Client::PopulateHouseSpawnFinalize() query.RunQuery2(Q_INSERT, "insert into spawn_instance_data set spawn_id = %u, spawn_location_id = %u, pickup_item_id = %u, pickup_unique_item_id = %u", tmp->GetDatabaseID(), tmp->GetSpawnLocationID(), tmp->GetPickupItemID(), uniqueID); } - database.DeleteItem(GetCharacterID(), uniqueItem, 0); - GetPlayer()->item_list.RemoveItem(uniqueItem, true); - QueuePacket(GetPlayer()->SendInventoryUpdate(GetVersion())); + if(lua_interface->RunItemScript(uniqueItem->GetItemScript(), "placed", uniqueItem, GetPlayer(), tmp)) + { + uniqueItem = GetPlayer()->item_list.GetItemFromUniqueID(uniqueID); + } + + if(uniqueItem) { + database.DeleteItem(GetCharacterID(), uniqueItem, 0); + GetPlayer()->item_list.RemoveItem(uniqueItem, true); + QueuePacket(GetPlayer()->SendInventoryUpdate(GetVersion())); + } + SetPlacementUniqueItemID(0); } return true; diff --git a/EQ2/source/WorldServer/client.h b/EQ2/source/WorldServer/client.h index 72c6f38ed..5f7a51e46 100644 --- a/EQ2/source/WorldServer/client.h +++ b/EQ2/source/WorldServer/client.h @@ -285,9 +285,9 @@ public: void AcceptQuestReward(Quest* quest, int32 item_id); Quest* GetPendingQuestAcceptance(int32 item_id); Quest* GetActiveQuest(int32 quest_id); - void DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2); - void DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0); - void DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0); + void DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2, int8 language = 0, int8 can_close = 1); + void DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1); + void DisplayConversation(Spawn* src, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3 = 0, int32 key1 = 0, int32 key2 = 0, int8 language = 0, int8 can_close = 1); void CloseDialog(int32 conversation_id); int32 GetConversationID(Spawn* spawn, Item* item); void CombineSpawns(float radius, Spawn* spawn); @@ -568,7 +568,7 @@ private: Spawn* combine_spawn; int8 num_active_failures; int32 next_conversation_id; - map<int32, Spawn*> conversation_spawns; + map<int32, int32> conversation_spawns; map<int32, Item*> conversation_items; Mutex MConversation; map<int32, map<int8, string> > conversation_map;