From 0e00165195525c84effe8614d1eb7ffe68a84814 Mon Sep 17 00:00:00 2001 From: Emagi Date: Sun, 24 Jul 2022 22:19:45 -0400 Subject: [PATCH] - Fix #453 PlayFlavor re-design PlayFlavorID(NPC, type, id, index, Player, language) Set Player to 'nil' to send to all clients, specifying a Player will make it send ONLY to that player New command /reload voiceovers added - versioning updated to 0.9.4-aquarii - Fix #454 Support for SendShowBook to have language, items field 'book_language' added - Some debug log cleanup --- DB/updates/jul22_items_book_language.sql | 1 + DB/updates/voiceovers_table_july23_2022.sql | 13 ++ EQ2/source/WorldServer/Bots/BotCommands.cpp | 4 +- EQ2/source/WorldServer/Commands/Commands.cpp | 14 +- EQ2/source/WorldServer/Commands/Commands.h | 2 + EQ2/source/WorldServer/Items/Items.cpp | 3 + EQ2/source/WorldServer/Items/Items.h | 1 + EQ2/source/WorldServer/Items/ItemsDB.cpp | 1 + EQ2/source/WorldServer/LuaFunctions.cpp | 27 +++ EQ2/source/WorldServer/LuaFunctions.h | 1 + EQ2/source/WorldServer/LuaInterface.cpp | 1 + EQ2/source/WorldServer/World.cpp | 156 ++++++++++++++++++ EQ2/source/WorldServer/World.h | 22 ++- EQ2/source/WorldServer/WorldDatabase.cpp | 36 ++++ EQ2/source/WorldServer/WorldDatabase.h | 1 + EQ2/source/WorldServer/Zone/region_map_v1.cpp | 1 - EQ2/source/WorldServer/client.cpp | 29 +++- EQ2/source/WorldServer/client.h | 7 +- EQ2/source/WorldServer/zoneserver.cpp | 23 +++ EQ2/source/WorldServer/zoneserver.h | 1 + EQ2/source/common/version.h | 6 +- server/WorldStructs.xml | 6 +- 22 files changed, 338 insertions(+), 18 deletions(-) create mode 100644 DB/updates/jul22_items_book_language.sql create mode 100644 DB/updates/voiceovers_table_july23_2022.sql diff --git a/DB/updates/jul22_items_book_language.sql b/DB/updates/jul22_items_book_language.sql new file mode 100644 index 000000000..d7195c32a --- /dev/null +++ b/DB/updates/jul22_items_book_language.sql @@ -0,0 +1 @@ +alter table items add column book_language tinyint(3) unsigned default 0; diff --git a/DB/updates/voiceovers_table_july23_2022.sql b/DB/updates/voiceovers_table_july23_2022.sql new file mode 100644 index 000000000..4594540fb --- /dev/null +++ b/DB/updates/voiceovers_table_july23_2022.sql @@ -0,0 +1,13 @@ +insert into commands set type=1,command='reload',subcommand='voiceovers',required_status=100,handler=532; +CREATE TABLE `voiceovers` ( + `type_id` tinyint(3) unsigned NOT NULL default 0, + `id` int(10) unsigned NOT NULL default 0, + `indexed` smallint(5) unsigned NOT NULL default 0, + `mp3_string` text not null default '', + `text_string` text not null default '', + `emote_string` text not null default '', + `key1` int(10) unsigned NOT NULL default 0, + `key2` int(10) unsigned NOT NULL default 0, + `garbled` tinyint(3) unsigned NOT NULL default 0, + `garble_link_id` tinyint(3) unsigned NOT NULL default 0 +) ENGINE=InnoDB DEFAULT CHARSET=latin1; \ No newline at end of file diff --git a/EQ2/source/WorldServer/Bots/BotCommands.cpp b/EQ2/source/WorldServer/Bots/BotCommands.cpp index 83ae9b45d..14f265ec3 100644 --- a/EQ2/source/WorldServer/Bots/BotCommands.cpp +++ b/EQ2/source/WorldServer/Bots/BotCommands.cpp @@ -756,7 +756,7 @@ void Commands::Command_Bot_Help(Client* client, Seperator* sep) { details += "18\tSarnak\n"; details += "19\tVampire\n"; details += "20\tAerakyn\n"; - client->SendShowBook(client->GetPlayer(), title, 1, details); + client->SendShowBook(client->GetPlayer(), title, 0, 1, details); return; } else if (strncasecmp("class", sep->arg[0], 5) == 0) { @@ -811,7 +811,7 @@ void Commands::Command_Bot_Help(Client* client, Seperator* sep) { details3 += "43\tSHAPER\n"; details3 += "44\tCHANNELER\n"; - client->SendShowBook(client->GetPlayer(), title, 3, details, details2, details3); + client->SendShowBook(client->GetPlayer(), title, 0, 3, details, details2, details3); return; } } diff --git a/EQ2/source/WorldServer/Commands/Commands.cpp b/EQ2/source/WorldServer/Commands/Commands.cpp index 8ce22dc23..13b5d8128 100644 --- a/EQ2/source/WorldServer/Commands/Commands.cpp +++ b/EQ2/source/WorldServer/Commands/Commands.cpp @@ -1833,6 +1833,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/reload rules"); client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/reload transporters"); client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/reload startabilities"); + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "/reload voiceovers"); break; } case COMMAND_RELOADSTRUCTS: { @@ -1946,6 +1947,13 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Done!"); break; } + case COMMAND_RELOAD_VOICEOVERS: { + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Reloading Voiceovers..."); + world.PurgeVoiceOvers(); + world.LoadVoiceOvers(); + client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Done!"); + break; + } case COMMAND_READ: { if (sep && sep->arg[1][0] && sep->IsNumber(1)) { if (strcmp(sep->arg[0], "read") == 0) { @@ -1953,7 +1961,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie Item* item = client->GetPlayer()->item_list.GetItemFromIndex(item_index); if (item) { Spawn* spawn = cmdTarget; - client->SendShowBook(client->GetPlayer(), item->name, item->book_pages); + client->SendShowBook(client->GetPlayer(), item->name, item->book_language, item->book_pages); break; } } @@ -3867,7 +3875,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false); client->Message(CHANNEL_COLOR_RED, "Adding spawn group tag \"%s\" with tag icon %u.", (value == 1) ? "on" : "off", tag_icon); } - else if(strncasecmp(sep->arg[1], "race", 5) == 0){ + else if(strncasecmp(sep->arg[1], "race", 4 == 0)){ if(!value) { client->SimpleMessage(CHANNEL_COLOR_RED, "Need to supply a valid race id."); break; @@ -4742,7 +4750,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie } string title = string(spawn->GetName()) + "(" + to_string(spawn->GetDatabaseID()) + ")"; - client->SendShowBook(client->GetPlayer(), title, 4, details, details2, details3, details4); + client->SendShowBook(client->GetPlayer(), title, 0, 4, details, details2, details3, details4); } else { client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Syntax: /spawn details (radius)"); diff --git a/EQ2/source/WorldServer/Commands/Commands.h b/EQ2/source/WorldServer/Commands/Commands.h index 4db7ece43..623b7a058 100644 --- a/EQ2/source/WorldServer/Commands/Commands.h +++ b/EQ2/source/WorldServer/Commands/Commands.h @@ -932,6 +932,8 @@ private: #define COMMAND_CANCEL_EFFECT 530 #define COMMAND_CUREPLAYER 531 +#define COMMAND_RELOAD_VOICEOVERS 532 + #define GET_AA_XML 750 #define ADD_AA 751 diff --git a/EQ2/source/WorldServer/Items/Items.cpp b/EQ2/source/WorldServer/Items/Items.cpp index 4a94a4fad..b2cea55fc 100644 --- a/EQ2/source/WorldServer/Items/Items.cpp +++ b/EQ2/source/WorldServer/Items/Items.cpp @@ -897,6 +897,7 @@ Item::Item(){ no_sale = false; created = std::time(nullptr); effect_type = NO_EFFECT_TYPE; + book_language = 0; } Item::Item(Item* in_item){ @@ -917,6 +918,7 @@ Item::Item(Item* in_item){ created = in_item->created; grouped_char_ids.insert(in_item->grouped_char_ids.begin(), in_item->grouped_char_ids.end()); effect_type = in_item->effect_type; + book_language = in_item->book_language; } Item::~Item(){ @@ -1140,6 +1142,7 @@ void Item::SetItem(Item* old_item){ slot_data = old_item->slot_data; spell_id = old_item->spell_id; spell_tier = old_item->spell_tier; + book_language = old_item->book_language; } bool Item::CheckArchetypeAdvSubclass(int8 adventure_class, map* adv_class_levels) { diff --git a/EQ2/source/WorldServer/Items/Items.h b/EQ2/source/WorldServer/Items/Items.h index 9a461c509..c04bc7a0c 100644 --- a/EQ2/source/WorldServer/Items/Items.h +++ b/EQ2/source/WorldServer/Items/Items.h @@ -951,6 +951,7 @@ public: ItemEffectType effect_type; bool crafted; bool tinkered; + int8 book_language; void AddEffect(string effect, int8 percentage, int8 subbulletflag); void AddBookPage(int8 page, string page_text,int8 valign, int8 halign); diff --git a/EQ2/source/WorldServer/Items/ItemsDB.cpp b/EQ2/source/WorldServer/Items/ItemsDB.cpp index e93bac08a..b1ad03f06 100644 --- a/EQ2/source/WorldServer/Items/ItemsDB.cpp +++ b/EQ2/source/WorldServer/Items/ItemsDB.cpp @@ -224,6 +224,7 @@ void WorldDatabase::LoadDataFromRow(DatabaseResult* result, Item* item) item->crafted = result->GetInt8Str("crafted"); item->tinkered = result->GetInt8Str("tinkered"); + item->book_language = result->GetInt8Str("book_language"); } diff --git a/EQ2/source/WorldServer/LuaFunctions.cpp b/EQ2/source/WorldServer/LuaFunctions.cpp index 66c29e522..e5a2326fc 100755 --- a/EQ2/source/WorldServer/LuaFunctions.cpp +++ b/EQ2/source/WorldServer/LuaFunctions.cpp @@ -188,6 +188,33 @@ int EQ2Emu_lua_PlayFlavor(lua_State* state) { return 0; } +int EQ2Emu_lua_PlayFlavorID(lua_State* state) { + if (!lua_interface) + return 0; + Spawn* spawn = lua_interface->GetSpawn(state); + + int8 type = lua_interface->GetInt8Value(state, 2); + int32 id = lua_interface->GetInt32Value(state, 3); + int16 index = lua_interface->GetInt16Value(state, 4); + Spawn* player = lua_interface->GetSpawn(state, 5); + int8 language = lua_interface->GetInt8Value(state, 6); + lua_interface->ResetFunctionStack(state); + if (spawn) { + Client* client = 0; + if (player && player->IsPlayer()) + client = spawn->GetZone()->GetClientBySpawn(player); + if (client) { + VoiceOverStruct non_garble, garble; + bool garble_success = false; + bool success = world.FindVoiceOver(type, id, index, &non_garble, &garble_success, &garble); + client->SendPlayFlavor(spawn, language, &non_garble, &garble, success, garble_success); + } + else + spawn->GetZone()->PlayFlavorID(spawn, type, id, index, language); + } + return 0; +} + int EQ2Emu_lua_PlaySound(lua_State* state) { if (!lua_interface) return 0; diff --git a/EQ2/source/WorldServer/LuaFunctions.h b/EQ2/source/WorldServer/LuaFunctions.h index e427933c4..2be15393e 100755 --- a/EQ2/source/WorldServer/LuaFunctions.h +++ b/EQ2/source/WorldServer/LuaFunctions.h @@ -194,6 +194,7 @@ int EQ2Emu_lua_GetCharacterID(lua_State* state); int EQ2Emu_lua_MovementLoopAdd(lua_State* state); int EQ2Emu_lua_GetCurrentZoneSafeLocation(lua_State* state); int EQ2Emu_lua_PlayFlavor(lua_State* state); +int EQ2Emu_lua_PlayFlavorID(lua_State* state); int EQ2Emu_lua_PlaySound(lua_State* state); int EQ2Emu_lua_PlayVoice(lua_State* state); int EQ2Emu_lua_PlayAnimation(lua_State* state); diff --git a/EQ2/source/WorldServer/LuaInterface.cpp b/EQ2/source/WorldServer/LuaInterface.cpp index 893d028b1..1e8486cdd 100755 --- a/EQ2/source/WorldServer/LuaInterface.cpp +++ b/EQ2/source/WorldServer/LuaInterface.cpp @@ -1057,6 +1057,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state, "GetSpawnByGroupID", EQ2Emu_lua_GetSpawnByGroupID); lua_register(state, "GetSpawnByLocationID", EQ2Emu_lua_GetSpawnByLocationID); lua_register(state, "PlayFlavor", EQ2Emu_lua_PlayFlavor); + lua_register(state, "PlayFlavorID", EQ2Emu_lua_PlayFlavorID); lua_register(state, "PlaySound", EQ2Emu_lua_PlaySound); lua_register(state, "PlayVoice", EQ2Emu_lua_PlayVoice); lua_register(state, "PlayAnimation", EQ2Emu_lua_PlayAnimation); diff --git a/EQ2/source/WorldServer/World.cpp b/EQ2/source/WorldServer/World.cpp index cba6faba7..886191e51 100644 --- a/EQ2/source/WorldServer/World.cpp +++ b/EQ2/source/WorldServer/World.cpp @@ -132,6 +132,7 @@ World::~World(){ tov_itemstat_conversion.clear(); PurgeStartingLists(); + PurgeVoiceOvers(); map::iterator itr3; for (itr3 = region_maps.begin(); itr3 != region_maps.end(); itr3++) @@ -170,6 +171,7 @@ void World::init(){ LogWrite(WORLD__DEBUG, 1, "World", "-Load `visual states` complete!"); LoadStartingLists(); + LoadVoiceOvers(); LogWrite(WORLD__DEBUG, 1, "World", "-Setting system parameters..."); Variable* var = variables.FindVariable("gametime"); @@ -2411,7 +2413,18 @@ void World::PurgeStartingLists() safe_delete(tmpMap); } starting_spells.clear(); + + for(int type=0;type<3;type++) { + multimap*>::iterator vos_itr; + + for (vos_itr = voiceover_map[type].begin(); vos_itr != voiceover_map[type].end(); vos_itr++) + { + multimap* tmpMap = vos_itr->second; + safe_delete(tmpMap); + } + voiceover_map[type].clear(); + } MStartingLists.releasewritelock(); } @@ -2611,3 +2624,146 @@ void World::SendTimeUpdate() { zone_list.SendTimeUpdate(); } + +void World::LoadVoiceOvers() +{ + LogWrite(WORLD__DEBUG, 1, "World", "-Loading `voiceovers`..."); + database.LoadVoiceOvers(this); +} + + +void World::PurgeVoiceOvers() +{ + MVoiceOvers.writelock(); + for(int type=0;type*>::iterator vos_itr; + + for (vos_itr = voiceover_map[type].begin(); vos_itr != voiceover_map[type].end(); vos_itr++) + { + multimap* tmpMap = vos_itr->second; + safe_delete(tmpMap); + } + voiceover_map[type].clear(); + } + MVoiceOvers.releasewritelock(); +} + + +bool World::FindVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_, bool* find_garbled, VoiceOverStruct* garble_struct_) { + // if we complete both requirements, based on struct_ and garble_struct_ being passed when required by ptr not being null + bool succeed = false; + if(type > MAX_VOICEOVER_TYPE) { + LogWrite(WORLD__ERROR, 0, "World", "Voice over %u out of range, max voiceover type is %u...", type, MAX_VOICEOVER_TYPE); + return succeed; + } + + MVoiceOvers.readlock(); + multimap*>::iterator itr = voiceover_map[type].find(id); + if(itr != voiceover_map[type].end()) { + std::pair result = itr->second->equal_range(index); + int count = std::distance(result.first, result.second); + bool tries_attempt = true; // abort out the while loop + bool non_garble_found = false; + int rand = 0; // use to randomize the voiceover selection + int pos = 0; + int tries = 0; + bool has_ungarbled = false; + bool has_garbled = false; + int8 garble_link_id = 0; // used to match ungarbled to garbled when the link id is set in the DB + while(tries_attempt) { + pos = 0; + rand = MakeRandomInt(0, count); + if ( tries == 3 || non_garble_found || (find_garbled && (*find_garbled))) + rand = 0; // override, too many tries, or we otherwise found one garbled/ungarbled lets try to link it + for (VOMapIterator it = result.first; it != result.second; it++) { + if(!it->second.is_garbled) { + has_ungarbled = true; + } + else { + has_garbled = true; + } + pos++; + + // if there is only 1 entry in the voiceover list we aren't going to bother skipping + if(count > 1 && pos < rand) { + continue; + } + if(!it->second.is_garbled && (garble_link_id == 0 || it->second.garble_link_id == garble_link_id)) { + garble_link_id = it->second.garble_link_id; + non_garble_found = true; + if(struct_) { + CopyVoiceOver(struct_, &it->second); + } + + if(!find_garbled || ((*find_garbled))) { + if(find_garbled) + *find_garbled = true; + tries_attempt = false; + succeed = true; + break; + } + } + else if(find_garbled && !(*find_garbled) && it->second.is_garbled && (garble_link_id == 0 || it->second.garble_link_id == garble_link_id)) { + *find_garbled = true; + garble_link_id = it->second.garble_link_id; + if(garble_struct_) { + CopyVoiceOver(garble_struct_, &it->second); + if(!struct_ || non_garble_found) { + tries_attempt = false; + succeed = true; + break; + } + } + } + } + tries++; + if(!tries_attempt || (tries > 0 && !has_ungarbled && (!find_garbled || *find_garbled == true || !has_garbled)) || tries > 3) + break; + } + } + MVoiceOvers.releasereadlock(); + + return succeed; +} + +void World::AddVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_) { + if(type > MAX_VOICEOVER_TYPE) { + LogWrite(WORLD__ERROR, 0, "World", "Voice over %u out of range, max voiceover type is %u...", type, MAX_VOICEOVER_TYPE); + return; + } + + VoiceOverStruct tmpStruct; + tmpStruct.mp3_string = std::string(struct_->mp3_string); + tmpStruct.text_string = std::string(struct_->text_string); + tmpStruct.emote_string = std::string(struct_->emote_string); + tmpStruct.key1 = struct_->key1; + tmpStruct.key2 = struct_->key2; + tmpStruct.is_garbled = struct_->is_garbled; + + MVoiceOvers.writelock(); + if(!voiceover_map[type].count(id)) + { + multimap* vo_struct = new multimap(); + vo_struct->insert(make_pair(index, tmpStruct)); + voiceover_map[type].insert(make_pair(id, vo_struct)); + } + else + { + multimap*>::const_iterator itr = voiceover_map[type].find(id); + itr->second->insert(make_pair(index, tmpStruct)); + } + MVoiceOvers.releasewritelock(); +} + +void World::CopyVoiceOver(VoiceOverStruct* struct1, VoiceOverStruct* struct2) { + if(!struct1 || !struct2) + return; + + struct1->mp3_string = std::string(struct2->mp3_string); + struct1->text_string = std::string(struct2->text_string); + struct1->emote_string = std::string(struct2->emote_string); + struct1->key1 = struct2->key1; + struct1->key2 = struct2->key2; + struct1->is_garbled = struct2->is_garbled; + struct1->garble_link_id = struct2->garble_link_id; +} diff --git a/EQ2/source/WorldServer/World.h b/EQ2/source/WorldServer/World.h index abe0015ab..2d41aea2c 100644 --- a/EQ2/source/WorldServer/World.h +++ b/EQ2/source/WorldServer/World.h @@ -398,6 +398,17 @@ struct StartingSpell int32 knowledge_slot; }; +#define MAX_VOICEOVER_TYPE 2 +struct VoiceOverStruct{ + string mp3_string; + string text_string; + string emote_string; + int32 key1; + int32 key2; + bool is_garbled; + int8 garble_link_id; +}; + class ZoneList { public: ZoneList(); @@ -642,10 +653,17 @@ public: // just in case we roll over a time as to not send bad times to clients (days before hours, hours before minutes as examples) Mutex MWorldTime; - - + void LoadVoiceOvers(); + void PurgeVoiceOvers(); + typedef std::multimap::iterator VOMapIterator; + bool FindVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_ = nullptr, bool* find_garbled = nullptr, VoiceOverStruct* garble_struct_ = nullptr); + void AddVoiceOver(int8 type, int32 id, int16 index, VoiceOverStruct* struct_); + void CopyVoiceOver(VoiceOverStruct* struct1, VoiceOverStruct* struct2); + Mutex MVoiceOvers; + static sint64 newValue; private: + multimap*> voiceover_map[3]; int32 suppressed_warning = 0; map reloading_subsystems; //void RemovePlayerFromGroup(PlayerGroup* group, GroupMemberInfo* info, bool erase = true); diff --git a/EQ2/source/WorldServer/WorldDatabase.cpp b/EQ2/source/WorldServer/WorldDatabase.cpp index 9dc6fed97..101bffc63 100644 --- a/EQ2/source/WorldServer/WorldDatabase.cpp +++ b/EQ2/source/WorldServer/WorldDatabase.cpp @@ -7416,6 +7416,42 @@ void WorldDatabase::LoadStartingSkills(World* world) } +void WorldDatabase::LoadVoiceOvers(World* world) +{ + int32 total = 0; + Query query; + MYSQL_ROW row; + MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT type_id, id, indexed, mp3_string, text_string, emote_string, key1, key2, garbled, garble_link_id FROM voiceovers"); + + if (result) + { + if (mysql_num_rows(result) > 0) + { + Skill* skill = 0; + + while (result && (row = mysql_fetch_row(result))) + { + + VoiceOverStruct vos; + vos.mp3_string = std::string(row[3]); + vos.text_string = std::string(row[4]); + vos.emote_string = std::string(row[5]); + vos.key1 = atoul(row[6]); + vos.key2 = atoul(row[7]); + vos.is_garbled = atoul(row[8]); + vos.garble_link_id = atoul(row[9]); + int8 type = atoul(row[0]); + int32 id = atoul(row[1]); + int16 index = atoul(row[2]); + world->AddVoiceOver(type, id, index, &vos); + total++; + } + } + } + LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u Voiceover(s)", total); +} + + void WorldDatabase::LoadStartingSpells(World* world) { world->MStartingLists.writelock(); diff --git a/EQ2/source/WorldServer/WorldDatabase.h b/EQ2/source/WorldServer/WorldDatabase.h index 313b940f3..35bfb1300 100644 --- a/EQ2/source/WorldServer/WorldDatabase.h +++ b/EQ2/source/WorldServer/WorldDatabase.h @@ -604,6 +604,7 @@ public: void LoadStartingSkills(World* world); void LoadStartingSpells(World* world); + void LoadVoiceOvers(World* world); int32 CreateSpiritShard(const char* name, int32 level, int8 race, int8 gender, int8 adventure_class, int16 model_type, int16 soga_model_type, int16 hair_type, int16 hair_face_type, int16 wing_type, diff --git a/EQ2/source/WorldServer/Zone/region_map_v1.cpp b/EQ2/source/WorldServer/Zone/region_map_v1.cpp index d150cca5f..c62c03347 100644 --- a/EQ2/source/WorldServer/Zone/region_map_v1.cpp +++ b/EQ2/source/WorldServer/Zone/region_map_v1.cpp @@ -64,7 +64,6 @@ std::string RegionMapV1::TestFile(std::string testFile) string tmpScript("RegionScripts/"); tmpScript.append(mZoneNameLower); tmpScript.append("/" + tmpStr + ".lua"); - printf("File to test : %s\n",tmpScript.c_str()); std::ifstream f(tmpScript.c_str()); return f.good() ? tmpScript : string(""); } diff --git a/EQ2/source/WorldServer/client.cpp b/EQ2/source/WorldServer/client.cpp index b7ad97976..1a2f047f5 100755 --- a/EQ2/source/WorldServer/client.cpp +++ b/EQ2/source/WorldServer/client.cpp @@ -10530,7 +10530,7 @@ void Client::SendFlightAutoMount(int32 path_id, int16 mount_id, int8 mount_red_c ((Entity*)GetPlayer())->SetMount(mount_id, mount_red_color, mount_green_color, mount_blue_color); } -void Client::SendShowBook(Spawn* sender, string title, int8 num_pages, ...) +void Client::SendShowBook(Spawn* sender, string title, int8 language, int8 num_pages, ...) { if (!sender) { @@ -10547,7 +10547,9 @@ void Client::SendShowBook(Spawn* sender, string title, int8 num_pages, ...) packet->setDataByName("book_title", title.c_str()); packet->setDataByName("book_type", "simple"); packet->setDataByName("unknown2", 1); - + if(language > 0 && !GetPlayer()->HasLanguage(language)) + packet->setDataByName("language", language); + if (GetVersion() > 546) packet->setDataByName("unknown5", 1, 4); @@ -10596,7 +10598,7 @@ void Client::SendShowBook(Spawn* sender, string title, int8 num_pages, ...) safe_delete(packet); } -void Client::SendShowBook(Spawn* sender, string title, vector pages) +void Client::SendShowBook(Spawn* sender, string title, int8 language, vector pages) { if (!sender) { @@ -10613,6 +10615,9 @@ void Client::SendShowBook(Spawn* sender, string title, vector p packet->setDataByName("book_title", title.c_str()); packet->setDataByName("book_type", "simple"); packet->setDataByName("unknown2", 1); + + if(language > 0 && !GetPlayer()->HasLanguage(language)) + packet->setDataByName("language", language); if (GetVersion() > 546) packet->setDataByName("unknown5", 1, 4); @@ -11018,4 +11023,22 @@ bool Client::UseItem(Item* item, Spawn* target) { } } return false; +} + +void Client::SendPlayFlavor(Spawn* spawn, int8 language, VoiceOverStruct* non_garble, + VoiceOverStruct* garble, bool success, bool garble_success) { + VoiceOverStruct* resStruct = nullptr; + + if(language == 0 || GetPlayer()->HasLanguage(language)) { + if(success) { + resStruct = non_garble; + } + } + else if(garble_success) { + resStruct = garble; + } + + if(resStruct) { + GetPlayer()->GetZone()->PlayFlavor(this, spawn, resStruct->mp3_string.c_str(), resStruct->text_string.c_str(), resStruct->emote_string.c_str(), resStruct->key1, resStruct->key2, language); + } } \ No newline at end of file diff --git a/EQ2/source/WorldServer/client.h b/EQ2/source/WorldServer/client.h index b0edf1c3c..d94d669de 100644 --- a/EQ2/source/WorldServer/client.h +++ b/EQ2/source/WorldServer/client.h @@ -32,6 +32,7 @@ using namespace std; #define CLIENT_TIMEOUT 60000 struct TransportDestination; struct ConversationOption; +struct VoiceOverStruct; #define MAIL_SEND_RESULT_SUCCESS 0 #define MAIL_SEND_RESULT_UNKNOWN_PLAYER 1 @@ -446,8 +447,8 @@ public: void SendFlightAutoMount(int32 path_id, int16 mount_id = 0, int8 mount_red_color = 0xFF, int8 mount_green_color = 0xFF, int8 mount_blue_color=0xFF); - void SendShowBook(Spawn* sender, string title, int8 num_pages, ...); - void SendShowBook(Spawn* sender, string title, vector pages); + void SendShowBook(Spawn* sender, string title, int8 language, int8 num_pages, ...); + void SendShowBook(Spawn* sender, string title, int8 language, vector pages); void SetTemporaryTransportID(int32 id) { temporary_transport_id = id; } int32 GetTemporaryTransportID() { return temporary_transport_id; } @@ -540,6 +541,8 @@ public: } bool UseItem(Item* item, Spawn* target = nullptr); + + void SendPlayFlavor(Spawn* spawn, int8 language, VoiceOverStruct* non_garble, VoiceOverStruct* garble, bool success = false, bool garble_success = false); private: void SavePlayerImages(); void SkillChanged(Skill* skill, int16 previous_value, int16 new_value); diff --git a/EQ2/source/WorldServer/zoneserver.cpp b/EQ2/source/WorldServer/zoneserver.cpp index 0f74af194..a8c9aa328 100644 --- a/EQ2/source/WorldServer/zoneserver.cpp +++ b/EQ2/source/WorldServer/zoneserver.cpp @@ -3654,6 +3654,29 @@ void ZoneServer::PlayFlavor(Spawn* spawn, const char* mp3, const char* text, con MClientList.releasereadlock(__FUNCTION__, __LINE__); } +void ZoneServer::PlayFlavorID(Spawn* spawn, int8 type, int32 id, int16 index, int8 language){ + if(!spawn) + return; + + Client* client = 0; + vector::iterator client_itr; + + VoiceOverStruct non_garble, garble; + bool garble_success = false; + bool success = world.FindVoiceOver(type, id, index, &non_garble, &garble_success, &garble); + + VoiceOverStruct* resStruct = nullptr; + MClientList.readlock(__FUNCTION__, __LINE__); + for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) { + client = *client_itr; + if(!client || !client->IsReadyForUpdates() || !client->GetPlayer()->WasSentSpawn(spawn->GetID()) || client->GetPlayer()->GetDistance(spawn) > 30) + continue; + + client->SendPlayFlavor(spawn, language, &non_garble, &garble, success, garble_success); + } + MClientList.releasereadlock(__FUNCTION__, __LINE__); +} + void ZoneServer::PlayVoice(Spawn* spawn, const char* mp3, int32 key1, int32 key2){ if(!spawn || !mp3) return; diff --git a/EQ2/source/WorldServer/zoneserver.h b/EQ2/source/WorldServer/zoneserver.h index 8e08789b4..9559f1ab7 100644 --- a/EQ2/source/WorldServer/zoneserver.h +++ b/EQ2/source/WorldServer/zoneserver.h @@ -450,6 +450,7 @@ public: void PlayFlavor(Client* client, Spawn* spawn, const char* mp3, const char* text, const char* emote, int32 key1, int32 key2, int8 language); void PlayVoice(Client* client, Spawn* spawn, const char* mp3, int32 key1, int32 key2); void PlayFlavor(Spawn* spawn, const char* mp3, const char* text, const char* emote, int32 key1, int32 key2, int8 language); + void PlayFlavorID(Spawn* spawn, int8 type, int32 id, int16 index, int8 language); void PlayVoice(Spawn* spawn, const char* mp3, int32 key1, int32 key2); void SendThreatPacket(Spawn* caster, Spawn* target, int32 threat_amt, const char* spell_name); void KillSpawnByDistance(Spawn* spawn, float max_distance, bool include_players = false, bool send_packet = false); diff --git a/EQ2/source/common/version.h b/EQ2/source/common/version.h index fe7a21bc6..bba38c572 100644 --- a/EQ2/source/common/version.h +++ b/EQ2/source/common/version.h @@ -38,11 +38,11 @@ #endif #if defined(LOGIN) -#define CURRENT_VERSION "0.9.4-geminorum" +#define CURRENT_VERSION "0.9.4-aquarii" #elif defined(WORLD) -#define CURRENT_VERSION "0.9.4-geminorum" +#define CURRENT_VERSION "0.9.4-aquarii" #else -#define CURRENT_VERSION "0.9.4-geminorum" +#define CURRENT_VERSION "0.9.4-aquarii" #endif #define COMPILE_DATE __DATE__ diff --git a/server/WorldStructs.xml b/server/WorldStructs.xml index f3371d7cd..927c5d882 100644 --- a/server/WorldStructs.xml +++ b/server/WorldStructs.xml @@ -9876,7 +9876,8 @@ to zero and treated like placeholders." /> - + + @@ -9891,7 +9892,8 @@ to zero and treated like placeholders." /> - + +