From aac73c65582e60d44966a30208d3600fc0279efd Mon Sep 17 00:00:00 2001 From: Xackery Xtal Date: Tue, 22 Jan 2019 15:01:02 -0800 Subject: [PATCH] Added expansions support --- common/database.cpp | 10 +++++---- common/database.h | 4 ++-- common/shareddb.cpp | 16 +++++++------- utils/deprecated/apathing/load_db.cpp | 2 +- .../required/2019_01_22_peq_expansions.sql | 18 ++++++++++++++++ world/adventure_manager.cpp | 8 +++++-- world/worlddb.cpp | 8 +++---- zone/client_packet.cpp | 18 ++++++++-------- zone/command.cpp | 21 ++++++++++--------- zone/forage.cpp | 8 +++---- zone/loottables.cpp | 2 +- zone/object.cpp | 4 ++-- zone/spawn2.cpp | 2 +- zone/spawngroup.cpp | 2 +- zone/titles.cpp | 4 ++-- zone/tradeskills.cpp | 4 ++-- zone/trap.cpp | 6 +++--- zone/tribute.cpp | 2 +- zone/zone.cpp | 12 +++++------ zone/zoning.cpp | 13 +++++++++--- 20 files changed, 98 insertions(+), 66 deletions(-) create mode 100644 utils/sql/git/required/2019_01_22_peq_expansions.sql diff --git a/common/database.cpp b/common/database.cpp index 0af9169e5..268bf3a28 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -934,9 +934,9 @@ uint32 Database::GetMiniLoginAccount(char* ip) } // Get zone starting points from DB -bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe_x, float* safe_y, float* safe_z, int16* minstatus, uint8* minlevel, char *flag_needed) { +bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe_x, float* safe_y, float* safe_z, int16* minstatus, uint8* minlevel, uint32* expansions, char *flag_needed) { - std::string query = StringFormat("SELECT safe_x, safe_y, safe_z, min_status, min_level, flag_needed FROM zone " + std::string query = StringFormat("SELECT safe_x, safe_y, safe_z, min_status, min_level, flag_needed, expansions FROM zone " " WHERE short_name='%s' AND (version=%i OR version=0) ORDER BY version DESC", short_name, version); auto results = QueryDatabase(query); @@ -960,13 +960,15 @@ bool Database::GetSafePoints(const char* short_name, uint32 version, float* safe *minlevel = atoi(row[4]); if (flag_needed != nullptr) strcpy(flag_needed, row[5]); + if (expansions != nullptr) + *expansions = atoi(row[6]); return true; } bool Database::GetZoneLongName(const char* short_name, char** long_name, char* file_name, float* safe_x, float* safe_y, float* safe_z, uint32* graveyard_id, uint32* maxclients) { - std::string query = StringFormat("SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s' AND version=0", short_name); + std::string query = StringFormat("SELECT long_name, file_name, safe_x, safe_y, safe_z, graveyard_id, maxclients FROM zone WHERE short_name='%s' AND version=0 AND %i & expansions = expansions", short_name, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { @@ -1091,7 +1093,7 @@ const char* Database::GetZoneName(uint32 zoneID, bool ErrorUnknown) { uint8 Database::GetPEQZone(uint32 zoneID, uint32 version){ - std::string query = StringFormat("SELECT peqzone from zone where zoneidnumber='%i' AND (version=%i OR version=0) ORDER BY version DESC", zoneID, version); + std::string query = StringFormat("SELECT peqzone from zone where zoneidnumber='%i' AND (version=%i OR version=0) AND %i & expansions = expansions ORDER BY version DESC", zoneID, version, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { diff --git a/common/database.h b/common/database.h index 307390edf..9080f150f 100644 --- a/common/database.h +++ b/common/database.h @@ -237,8 +237,8 @@ public: /* General Queries */ - bool GetSafePoints(const char* short_name, uint32 version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr); - bool GetSafePoints(uint32 zoneID, uint32 version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int16* minstatus = 0, uint8* minlevel = 0, char *flag_needed = nullptr) { return GetSafePoints(GetZoneName(zoneID), version, safe_x, safe_y, safe_z, minstatus, minlevel, flag_needed); } + bool GetSafePoints(const char* short_name, uint32 version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int16* minstatus = 0, uint8* minlevel = 0, uint32* expansions = 0, char *flag_needed = nullptr); + bool GetSafePoints(uint32 zoneID, uint32 version, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, int16* minstatus = 0, uint8* minlevel = 0, uint32* expansions = 0, char *flag_needed = nullptr) { return GetSafePoints(GetZoneName(zoneID), version, safe_x, safe_y, safe_z, minstatus, minlevel, expansions, flag_needed); } bool GetZoneGraveyard(const uint32 graveyard_id, uint32* graveyard_zoneid = 0, float* graveyard_x = 0, float* graveyard_y = 0, float* graveyard_z = 0, float* graveyard_heading = 0); bool GetZoneLongName(const char* short_name, char** long_name, char* file_name = 0, float* safe_x = 0, float* safe_y = 0, float* safe_z = 0, uint32* graveyard_id = 0, uint32* maxclients = 0); bool LoadPTimers(uint32 charid, PTimerList &into); diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 46e3a7512..9ae238f38 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -417,8 +417,8 @@ bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, EQEmu::Inventory std::string query = StringFormat("SELECT itemid, item_charges, slot FROM starting_items " "WHERE (race = %i or race = 0) AND (class = %i or class = 0) AND " "(deityid = %i or deityid = 0) AND (zoneid = %i or zoneid = 0) AND " - "gm <= %i ORDER BY id", - si_race, si_class, si_deity, si_current_zone, admin_level); + "gm <= %i AND %i & expansions = expansions ORDER BY id", + si_race, si_class, si_deity, si_current_zone, admin_level, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) return false; @@ -1937,7 +1937,7 @@ void SharedDatabase::GetLootTableInfo(uint32 &loot_table_count, uint32 &max_loot loot_table_count = 0; max_loot_table = 0; loot_table_entries = 0; - const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable"; + const std::string query = StringFormat("SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM loottable_entries) FROM loottable WHERE %d & expansions = expansions", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return; @@ -1958,7 +1958,7 @@ void SharedDatabase::GetLootDropInfo(uint32 &loot_drop_count, uint32 &max_loot_d max_loot_drop = 0; loot_drop_entries = 0; - const std::string query = "SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop"; + const std::string query = StringFormat("SELECT COUNT(*), MAX(id), (SELECT COUNT(*) FROM lootdrop_entries) FROM lootdrop WHERE %d & expansions = expansions", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return; @@ -1980,10 +1980,10 @@ void SharedDatabase::LoadLootTables(void *data, uint32 size) { uint8 loot_table[sizeof(LootTable_Struct) + (sizeof(LootTableEntries_Struct) * 128)]; LootTable_Struct *lt = reinterpret_cast(loot_table); - const std::string query = "SELECT loottable.id, loottable.mincash, loottable.maxcash, loottable.avgcoin, " + const std::string query = StringFormat("SELECT loottable.id, loottable.mincash, loottable.maxcash, loottable.avgcoin, " "loottable_entries.lootdrop_id, loottable_entries.multiplier, loottable_entries.droplimit, " "loottable_entries.mindrop, loottable_entries.probability FROM loottable LEFT JOIN loottable_entries " - "ON loottable.id = loottable_entries.loottable_id ORDER BY id"; + "ON loottable.id = loottable_entries.loottable_id WHERE %d & loottable.expansions = loottable.expansions ORDER BY id", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return; @@ -2033,10 +2033,10 @@ void SharedDatabase::LoadLootDrops(void *data, uint32 size) { uint8 loot_drop[sizeof(LootDrop_Struct) + (sizeof(LootDropEntries_Struct) * 1260)]; LootDrop_Struct *ld = reinterpret_cast(loot_drop); - const std::string query = "SELECT lootdrop.id, lootdrop_entries.item_id, lootdrop_entries.item_charges, " + const std::string query = StringFormat("SELECT lootdrop.id, lootdrop_entries.item_id, lootdrop_entries.item_charges, " "lootdrop_entries.equip_item, lootdrop_entries.chance, lootdrop_entries.minlevel, " "lootdrop_entries.maxlevel, lootdrop_entries.multiplier FROM lootdrop JOIN lootdrop_entries " - "ON lootdrop.id = lootdrop_entries.lootdrop_id ORDER BY lootdrop_id"; + "ON lootdrop.id = lootdrop_entries.lootdrop_id WHERE %d & expansions = expansions ORDER BY lootdrop_id", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return; diff --git a/utils/deprecated/apathing/load_db.cpp b/utils/deprecated/apathing/load_db.cpp index 44a5f7b80..160a5833e 100644 --- a/utils/deprecated/apathing/load_db.cpp +++ b/utils/deprecated/apathing/load_db.cpp @@ -148,7 +148,7 @@ bool load_doors_from_db(MYSQL *m, const char *zone, list &db_spawns) sprintf(query, "SELECT pos_x,pos_y,pos_z FROM doors " - "WHERE zone='%s'", zone); + "WHERE zone='%s' AND %d & expansions = expansions", zone, RuleI(World, ExpansionSettings)); if(mysql_query(m, query) != 0) { printf("Unable to query: %s\n", mysql_error(m)); return(false); diff --git a/utils/sql/git/required/2019_01_22_peq_expansions.sql b/utils/sql/git/required/2019_01_22_peq_expansions.sql new file mode 100644 index 000000000..684e90e72 --- /dev/null +++ b/utils/sql/git/required/2019_01_22_peq_expansions.sql @@ -0,0 +1,18 @@ +ALTER TABLE `adventure_template` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `graveyard_radius`; +ALTER TABLE `doors` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `is_ldon_door`; +ALTER TABLE `fishing` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `npc_chance`; +ALTER TABLE `forage` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `chance`; +ALTER TABLE `global_loot` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `zone`; +ALTER TABLE `ground_spawns` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `respawn_timer`; +ALTER TABLE `loottable` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `done`; +ALTER TABLE `lootdrop` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `name`; +ALTER TABLE `merchantlist` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `probability`; +ALTER TABLE `object` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `display_name`; +ALTER TABLE `spawn2` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `animation`; +ALTER TABLE `starting_items` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `slot`; +ALTER TABLE `start_zones` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `select_rank`; +ALTER TABLE `titles` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `title_set`; +ALTER TABLE `tradeskill_recipe` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '4' AFTER `enabled`; +ALTER TABLE `traps` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `undetectable`; +ALTER TABLE `tributes` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `isguild`; +ALTER TABLE `zone` ADD `expansions` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' AFTER `npc_max_aggro_dist`; diff --git a/world/adventure_manager.cpp b/world/adventure_manager.cpp index 65e264a19..b98da1816 100644 --- a/world/adventure_manager.cpp +++ b/world/adventure_manager.cpp @@ -637,13 +637,17 @@ bool AdventureManager::LoadAdventureTemplates() "assa_y, assa_z, assa_h, text, duration, zone_in_time, win_points, lose_points, " "theme, zone_in_zone_id, zone_in_x, zone_in_y, zone_in_object_id, dest_x, dest_y, " "dest_z, dest_h, graveyard_zone_id, graveyard_x, graveyard_y, graveyard_z, " - "graveyard_radius FROM adventure_template"; + "graveyard_radius, expansions FROM adventure_template"; auto results = database.QueryDatabase(query); if (!results.Success()) { return false; } for (auto row = results.begin(); row != results.end(); ++row) { + int32 expansions = atoi(row[32]); + if (RuleI(World, ExpansionSettings) & expansions != expansions) { + continue; + } auto aTemplate = new AdventureTemplate; aTemplate->id = atoi(row[0]); strcpy(aTemplate->zone, row[1]); @@ -678,7 +682,7 @@ bool AdventureManager::LoadAdventureTemplates() aTemplate->graveyard_z = atof(row[30]); aTemplate->graveyard_radius = atof(row[31]); adventure_templates[aTemplate->id] = aTemplate; - } + } return true; } diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 4daa7fa77..42da1cd94 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -182,8 +182,8 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou } if (has_home == 0 || has_bind == 0) { - cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i", - cse->Class, cse->Deity, cse->Race); + cquery = StringFormat("SELECT `zone_id`, `bind_id`, `x`, `y`, `z` FROM `start_zones` WHERE `player_class` = %i AND `player_deity` = %i AND `player_race` = %i AND %i & expansions = expansions", + cse->Class, cse->Deity, cse->Race, RuleI(World, ExpansionSettings)); auto results_bind = database.QueryDatabase(cquery); for (auto row_d = results_bind.begin(); row_d != results_bind.end(); ++row_d) { /* If a bind_id is specified, make them start there */ @@ -358,8 +358,8 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = in_pp->binds[0].instance_id = 0; // see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids std::string query = StringFormat("SELECT x, y, z, heading, start_zone, bind_id, bind_x, bind_y, bind_z FROM start_zones WHERE zone_id = %i " - "AND player_class = %i AND player_deity = %i AND player_race = %i", - in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race); + "AND player_class = %i AND player_deity = %i AND player_race = %i AND %i & expansions = expansions", + in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if(!results.Success()) { return false; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7485d7451..98105f155 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11763,13 +11763,13 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app) "LEFT JOIN (SELECT recipe_id, madecount " "FROM char_recipe_list " "WHERE char_id = %u) AS crl ON tr.id=crl.recipe_id " - "WHERE tr.enabled <> 0 AND tr.id IN (%s) " + "WHERE tr.enabled <> 0 AND %i & tr.expansions = tr.expansions AND tr.id IN (%s) " "AND tr.must_learn & 0x20 <> 0x20 AND " "((tr.must_learn & 0x3 <> 0 AND crl.madecount IS NOT NULL) " "OR (tr.must_learn & 0x3 = 0)) " "GROUP BY tr.id " "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 AND SUM(tre.componentcount) <= %u " - "LIMIT 100 ", CharacterID(), favoriteIDs.c_str(), containers.c_str(), combineObjectSlots); + "LIMIT 100 ", CharacterID(), RuleI(World, ExpansionSettings), favoriteIDs.c_str(), containers.c_str(), combineObjectSlots); TradeskillSearchResults(query, tsf->object_type, tsf->some_id); return; @@ -11828,15 +11828,15 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app) "LEFT JOIN tradeskill_recipe_entries AS tre ON tr.id = tre.recipe_id " "LEFT JOIN (SELECT recipe_id, madecount " "FROM char_recipe_list WHERE char_id = %u) AS crl ON tr.id=crl.recipe_id " - "WHERE %s tr.trivial >= %u AND tr.trivial <= %u AND tr.enabled <> 0 " - "AND tr.must_learn & 0x20 <> 0x20 " + "WHERE %s tr.trivial >= %u AND tr.trivial <= %u AND tr.enabled <> 0" + "AND %i & tr.expansions = tr.expansions AND tr.must_learn & 0x20 <> 0x20 " "AND ((tr.must_learn & 0x3 <> 0 " "AND crl.madecount IS NOT NULL) " "OR (tr.must_learn & 0x3 = 0)) " "GROUP BY tr.id " "HAVING sum(if(tre.item_id %s AND tre.iscontainer > 0,1,0)) > 0 AND SUM(tre.componentcount) <= %u " "LIMIT 200 ", - CharacterID(), searchClause.c_str(), + CharacterID(), RuleI(World, ExpansionSettings), searchClause.c_str(), rss->mintrivial, rss->maxtrivial, containers, combineObjectSlots); TradeskillSearchResults(query, rss->object_type, rss->some_id); return; @@ -12306,8 +12306,8 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) uint32 startCity = (uint32)strtol((const char*)app->pBuffer, nullptr, 10); std::string query = StringFormat("SELECT zone_id, bind_id, x, y, z FROM start_zones " - "WHERE player_class=%i AND player_deity=%i AND player_race=%i", - m_pp.class_, m_pp.deity, m_pp.race); + "WHERE player_class=%i AND player_deity=%i AND player_race=%i AND %i & expansions = expansions", + m_pp.class_, m_pp.deity, m_pp.race, RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { Log(Logs::General, Logs::Error, "No valid start zones found for /setstartcity"); @@ -12337,8 +12337,8 @@ void Client::Handle_OP_SetStartCity(const EQApplicationPacket *app) } query = StringFormat("SELECT zone_id, bind_id FROM start_zones " - "WHERE player_class=%i AND player_deity=%i AND player_race=%i", - m_pp.class_, m_pp.deity, m_pp.race); + "WHERE player_class=%i AND player_deity=%i AND player_race=%i AND %i & expansions = expansions", + m_pp.class_, m_pp.deity, m_pp.race, RuleI(World, ExpansionSettings)); results = database.QueryDatabase(query); if (!results.Success()) return; diff --git a/zone/command.cpp b/zone/command.cpp index 8c64c44a4..100588c13 100755 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -3712,13 +3712,13 @@ void command_findzone(Client *c, const Seperator *sep) database.DoEscapeString(escName, sep->arg[1], strlen(sep->arg[1])); query = StringFormat("SELECT zoneidnumber, short_name, long_name FROM zone " - "WHERE long_name RLIKE '%s' AND version = 0", - escName); + "WHERE long_name RLIKE '%s' AND version = 0 AND %i & expansions = expansions", + escName, RuleI(World, ExpansionSettings)); safe_delete_array(escName); } else // Otherwise, look for just that zoneidnumber. query = StringFormat("SELECT zoneidnumber, short_name, long_name FROM zone " - "WHERE zoneidnumber = %i AND version = 0", id); + "WHERE zoneidnumber = %i AND version = 0 AND %i & expansions = expansions", id, RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -9512,17 +9512,18 @@ void command_object(Client *c, const Seperator *sep) "AND (xpos BETWEEN %.1f AND %.1f) " "AND (ypos BETWEEN %.1f AND %.1f) " "AND (zpos BETWEEN %.1f AND %.1f) " + "AND %d & expansions = expansions" "ORDER BY id", zone->GetZoneID(), zone->GetInstanceVersion(), c->GetX() - radius, // Yes, we're actually using a bounding box instead of a radius. c->GetX() + radius, // Much less processing power used this way. - c->GetY() - radius, c->GetY() + radius, c->GetZ() - radius, c->GetZ() + radius); + c->GetY() - radius, c->GetY() + radius, c->GetZ() - radius, c->GetZ() + radius, RuleI(World, ExpansionSettings)); else query = StringFormat("SELECT id, xpos, ypos, zpos, heading, itemid, " "objectname, type, icon, unknown08, unknown10, unknown20 " - "FROM object WHERE zoneid = %u AND version = %u " + "FROM object WHERE zoneid = %u AND version = %u AND %d & expansions = expansions" "ORDER BY id", - zone->GetZoneID(), zone->GetInstanceVersion()); + zone->GetZoneID(), zone->GetInstanceVersion(), RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { @@ -10376,9 +10377,9 @@ void command_object(Client *c, const Seperator *sep) std::string query = StringFormat("INSERT INTO object " "(zoneid, version, xpos, ypos, zpos, heading, itemid, " - "objectname, type, icon, unknown08, unknown10, unknown20) " + "objectname, type, icon, unknown08, unknown10, unknown20, expansions) " "SELECT zoneid, %u, xpos, ypos, zpos, heading, itemid, " - "objectname, type, icon, unknown08, unknown10, unknown20 " + "objectname, type, icon, unknown08, unknown10, unknown20, expansions " "FROM object WHERE zoneid = %u) AND version = %u", od.zone_instance, zone->GetZoneID(), zone->GetInstanceVersion()); auto results = database.QueryDatabase(query); @@ -10396,9 +10397,9 @@ void command_object(Client *c, const Seperator *sep) std::string query = StringFormat("INSERT INTO object " "(zoneid, version, xpos, ypos, zpos, heading, itemid, " - "objectname, type, icon, unknown08, unknown10, unknown20) " + "objectname, type, icon, unknown08, unknown10, unknown20, expansions) " "SELECT zoneid, %u, xpos, ypos, zpos, heading, itemid, " - "objectname, type, icon, unknown08, unknown10, unknown20 " + "objectname, type, icon, unknown08, unknown10, unknown20, expansions " "FROM object WHERE id = %u AND zoneid = %u AND version = %u", od.zone_instance, id, zone->GetZoneID(), zone->GetInstanceVersion()); auto results = database.QueryDatabase(query); diff --git a/zone/forage.cpp b/zone/forage.cpp index 77361ce33..8aa604cb3 100644 --- a/zone/forage.cpp +++ b/zone/forage.cpp @@ -55,8 +55,8 @@ uint32 ZoneDatabase::GetZoneForage(uint32 ZoneID, uint8 skill) { uint32 chancepool = 0; std::string query = StringFormat("SELECT itemid, chance FROM " - "forage WHERE zoneid = '%i' and level <= '%i' " - "LIMIT %i", ZoneID, skill, FORAGE_ITEM_LIMIT); + "forage WHERE zoneid = '%i' AND level <= '%i' AND %d & expansions = expansions " + "LIMIT %i", ZoneID, skill, RuleI(World, ExpansionSettings), FORAGE_ITEM_LIMIT); auto results = QueryDatabase(query); if (!results.Success()) { return 0; @@ -110,8 +110,8 @@ uint32 ZoneDatabase::GetZoneFishing(uint32 ZoneID, uint8 skill, uint32 &npc_id, } std::string query = StringFormat("SELECT itemid, chance, npc_id, npc_chance " - "FROM fishing WHERE (zoneid = '%i' || zoneid = 0) AND skill_level <= '%i'", - ZoneID, skill); + "FROM fishing WHERE (zoneid = '%i' || zoneid = 0) AND skill_level <= '%i' AND %d & expansions = expansions", + ZoneID, skill, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return 0; diff --git a/zone/loottables.cpp b/zone/loottables.cpp index e7c9624f1..c4bebc15b 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -464,7 +464,7 @@ void NPC::CheckGlobalLootTables() void ZoneDatabase::LoadGlobalLoot() { auto query = StringFormat("SELECT id, loottable_id, description, min_level, max_level, rare, raid, race, " - "class, bodytype, zone FROM global_loot WHERE enabled = 1"); + "class, bodytype, zone FROM global_loot WHERE enabled = 1 AND %d & expansions = expansions", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success() || results.RowCount() == 0) diff --git a/zone/object.cpp b/zone/object.cpp index 4306c6642..103014cb6 100644 --- a/zone/object.cpp +++ b/zone/object.cpp @@ -699,8 +699,8 @@ Ground_Spawns* ZoneDatabase::LoadGroundSpawns(uint32 zone_id, int16 version, Gro "min_x, min_y, heading, name, " "item, max_allowed, respawn_timer " "FROM ground_spawns " - "WHERE zoneid = %i AND (version = %u OR version = -1) " - "LIMIT 50", zone_id, version); + "WHERE zoneid = %i AND (version = %u OR version = -1) AND %d & expansions = expansions" + "LIMIT 50", zone_id, version, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return gs; diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index e004faa4a..e79955bdb 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -642,7 +642,7 @@ Spawn2* ZoneDatabase::LoadSpawn2(LinkedList &spawn2_list, uint32 spawn2 std::string query = StringFormat("SELECT id, spawngroupID, x, y, z, heading, " "respawntime, variance, pathgrid, _condition, " "cond_value, enabled, animation FROM spawn2 " - "WHERE id = %i", spawn2id); + "WHERE id = %i AND %d & expansions = expansions", spawn2id, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return nullptr; diff --git a/zone/spawngroup.cpp b/zone/spawngroup.cpp index 7cb5cd803..03e1a5671 100644 --- a/zone/spawngroup.cpp +++ b/zone/spawngroup.cpp @@ -146,7 +146,7 @@ bool ZoneDatabase::LoadSpawnGroups(const char *zone_name, uint16 version, SpawnG "spawngroup.max_y, spawngroup.min_y, spawngroup.delay, " "spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay " "FROM spawn2, spawngroup WHERE spawn2.spawngroupID = spawngroup.ID " - "AND spawn2.version = %u and zone = '%s'", + "AND spawn2.version = %u and zone = '%s' AND %d & spawn2.expansions = spawn2.expansions", version, zone_name); auto results = QueryDatabase(query); if (!results.Success()) { diff --git a/zone/titles.cpp b/zone/titles.cpp index 033edd144..c05be6422 100644 --- a/zone/titles.cpp +++ b/zone/titles.cpp @@ -36,9 +36,9 @@ bool TitleManager::LoadTitles() { Titles.clear(); - std::string query = "SELECT `id`, `skill_id`, `min_skill_value`, `max_skill_value`, " + std::string query = StringFormat("SELECT `id`, `skill_id`, `min_skill_value`, `max_skill_value`, " "`min_aa_points`, `max_aa_points`, `class`, `gender`, `char_id`, " - "`status`, `item_id`, `prefix`, `suffix`, `title_set` FROM titles"; + "`status`, `item_id`, `prefix`, `suffix`, `title_set` FROM titles WHERE %i & expansions = expansions", RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { return false; diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 72cb51795..1f20141a7 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -1283,9 +1283,9 @@ bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id "LEFT JOIN (SELECT recipe_id, madecount " "FROM char_recipe_list WHERE char_id = %u) AS crl " "ON tr.id = crl.recipe_id " - "WHERE tr.id = %lu AND tre.item_id %s AND tr.enabled " + "WHERE tr.id = %lu AND tre.item_id %s AND tr.enabled AND %i & tr.expansions = tr.expansions " "GROUP BY tr.id", - char_id, (unsigned long)recipe_id, containers.c_str()); + char_id, (unsigned long)recipe_id, containers.c_str(), RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { Log(Logs::General, Logs::Error, "Error in GetTradeRecipe, query: %s", query.c_str()); diff --git a/zone/trap.cpp b/zone/trap.cpp index 29314f568..d4d742b4e 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -401,7 +401,7 @@ bool ZoneDatabase::LoadTraps(const char* zonename, int16 version) { std::string query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, " "maxzdiff, radius, chance, message, respawn_time, respawn_var, level, " - "`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u", zonename, version); + "`group`, triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND version=%u AND %i & expansions = expansions", zonename, version, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { @@ -485,14 +485,14 @@ bool ZoneDatabase::SetTrapData(Trap* trap, bool repopnow) { { query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, " "maxzdiff, radius, chance, message, respawn_time, respawn_var, level, " - "triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND `group`=%d AND id != %d ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid); + "triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND `group`=%d AND id != %d AND %i & expansions = expansions ORDER BY RAND() LIMIT 1", zone->GetShortName(), trap->group, dbid, RuleI(World, ExpansionSettings)); } else { // We could just use the existing data here, but querying the DB is not expensive, and allows content developers to change traps without rebooting. query = StringFormat("SELECT id, x, y, z, effect, effectvalue, effectvalue2, skill, " "maxzdiff, radius, chance, message, respawn_time, respawn_var, level, " - "triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND id = %d", zone->GetShortName(), dbid); + "triggered_number, despawn_when_triggered, undetectable FROM traps WHERE zone='%s' AND id = %d AND %i & expansions = expansions", zone->GetShortName(), dbid, RuleI(World, ExpansionSettings)); } auto results = QueryDatabase(query); diff --git a/zone/tribute.cpp b/zone/tribute.cpp index ce1eb5f6d..99d04cac6 100644 --- a/zone/tribute.cpp +++ b/zone/tribute.cpp @@ -387,7 +387,7 @@ bool ZoneDatabase::LoadTributes() { tribute_list.clear(); - const std::string query = "SELECT id, name, descr, unknown, isguild FROM tributes"; + const std::string query = StringFormat("SELECT id, name, descr, unknown, isguild FROM tributes WHERE %i & expansions = expansions", RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return false; diff --git a/zone/zone.cpp b/zone/zone.cpp index 923e37a39..7ef733093 100755 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -171,8 +171,8 @@ bool Zone::LoadZoneObjects() std::string query = StringFormat("SELECT id, zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, type, icon, " "unknown08, unknown10, unknown20, unknown24, unknown76, size, tilt_x, tilt_y, display_name " - "FROM object WHERE zoneid = %i AND (version = %u OR version = -1)", - zoneid, instanceversion); + "FROM object WHERE zoneid = %i AND (version = %u OR version = -1) AND %d & expansions = expansions", + zoneid, instanceversion, RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { Log(Logs::General, Logs::Error, "Error Loading Objects from DB: %s", @@ -465,7 +465,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) { std::list merlist; std::string query = StringFormat("SELECT item, slot, faction_required, level_required, alt_currency_cost, " - "classes_required, probability FROM merchantlist WHERE merchantid=%d ORDER BY slot", merchantid); + "classes_required, probability FROM merchantlist WHERE merchantid=%d AND %d & expansions = expansions ORDER BY slot", merchantid, RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) { return; @@ -1706,9 +1706,9 @@ bool ZoneDatabase::LoadStaticZonePoints(LinkedList* zone_point_list, std::string query = StringFormat("SELECT x, y, z, target_x, target_y, " "target_z, target_zone_id, heading, target_heading, " "number, target_instance, client_version_mask " - "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) " + "FROM zone_points WHERE zone='%s' AND (version=%i OR version=-1) AND %d & expansions = expansions " "ORDER BY number", - zonename, version); + zonename, version, RuleI(World, ExpansionSettings)); auto results = QueryDatabase(query); if (!results.Success()) { return false; @@ -2344,7 +2344,7 @@ uint32 Zone::GetSpawnKillCount(uint32 in_spawnid) { void Zone::UpdateHotzone() { - std::string query = StringFormat("SELECT hotzone FROM zone WHERE short_name = '%s'", GetShortName()); + std::string query = StringFormat("SELECT hotzone FROM zone WHERE short_name = '%s' AND %d & expansions = expansions", GetShortName(), RuleI(World, ExpansionSettings)); auto results = database.QueryDatabase(query); if (!results.Success()) return; diff --git a/zone/zoning.cpp b/zone/zoning.cpp index dbe9346b7..4b199b3a6 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -169,8 +169,9 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) { float safe_x, safe_y, safe_z; int16 minstatus = 0; uint8 minlevel = 0; + uint32 expansions = 0; char flag_needed[128]; - if(!database.GetSafePoints(target_zone_name, database.GetInstanceVersion(target_instance_id), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) { + if(!database.GetSafePoints(target_zone_name, database.GetInstanceVersion(target_instance_id), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, &expansions, flag_needed)) { //invalid zone... Message(13, "Invalid target zone while getting safe points."); Log(Logs::General, Logs::Error, "Zoning %s: Unable to get safe coordinates for zone '%s'.", GetName(), target_zone_name); @@ -838,8 +839,9 @@ void Client::SendZoneFlagInfo(Client *to) const { float safe_x, safe_y, safe_z; int16 minstatus = 0; uint8 minlevel = 0; + uint32 expansions = 0; char flag_name[128]; - if(!database.GetSafePoints(short_name, 0, &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_name)) { + if(!database.GetSafePoints(short_name, 0, &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, &expansions, flag_name)) { strcpy(flag_name, "(ERROR GETTING NAME)"); } @@ -860,8 +862,9 @@ bool Client::CanBeInZone() { float safe_x, safe_y, safe_z; int16 minstatus = 0; uint8 minlevel = 0; + uint32 expansions = 0; char flag_needed[128]; - if(!database.GetSafePoints(zone->GetShortName(), zone->GetInstanceVersion(), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, flag_needed)) { + if(!database.GetSafePoints(zone->GetShortName(), zone->GetInstanceVersion(), &safe_x, &safe_y, &safe_z, &minstatus, &minlevel, &expansions, flag_needed)) { //this should not happen... Log(Logs::Detail, Logs::None, "[CLIENT] Unable to query zone info for ourself '%s'", zone->GetShortName()); return(false); @@ -875,6 +878,10 @@ bool Client::CanBeInZone() { Log(Logs::Detail, Logs::None, "[CLIENT] Character does not meet min status requirement (%d < %d)!", Admin(), minstatus); return(false); } + if(Admin() < 150 && RuleI(World, ExpansionSettings) & expansions != expansions) { + Log(Logs::Detail, Logs::None, "[CLIENT] Character does not have expansion", Admin(), expansions); + return(false); + } if(flag_needed[0] != '\0') { //the flag needed string is not empty, meaning a flag is required.