diff --git a/zone/client.h b/zone/client.h index 03748849d..3375d7066 100644 --- a/zone/client.h +++ b/zone/client.h @@ -314,7 +314,7 @@ public: /* New PP Save Functions */ bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); } bool SaveAA(); - + inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); } @@ -664,7 +664,7 @@ public: void IncreaseLanguageSkill(int skill_id, int value = 1); virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; } uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; } - bool HasSkill(SkillUseTypes skill_id) const; + bool HasSkill(SkillUseTypes skill_id) const; bool CanHaveSkill(SkillUseTypes skill_id) const; void SetSkill(SkillUseTypes skill_num, uint16 value); void AddSkill(SkillUseTypes skillid, uint16 value); @@ -681,7 +681,7 @@ public: inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); } uint8 SkillTrainLevel(SkillUseTypes skillid, uint16 class_); - void TradeskillSearchResults(const char *query, unsigned long qlen, unsigned long objtype, unsigned long someid); + void TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid); void SendTradeskillDetails(uint32 recipe_id); bool TradeskillExecute(DBTradeskillRecipe_Struct *spec); void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, SkillUseTypes tradeskill); @@ -1452,7 +1452,7 @@ private: unsigned int RestRegenHP; unsigned int RestRegenMana; unsigned int RestRegenEndurance; - + bool EngagedRaidTarget; uint32 SavedRaidRestTimer; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 74399274a..6da4a265f 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -523,7 +523,7 @@ void Client::CompleteConnect() switch (rank) { case 0: { rank = 5; break; } // GUILD_MEMBER 0 case 1: { rank = 3; break; } // GUILD_OFFICER 1 - case 2: { rank = 1; break; } // GUILD_LEADER 2 + case 2: { rank = 1; break; } // GUILD_LEADER 2 default: { break; } // GUILD_NONE } } @@ -848,7 +848,7 @@ void Client::CompleteConnect() void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z) { //ToDo: Break warp down for special zones. Some zones have special teleportation pads or bad .map files which can trigger the detector without a legit zone request. - + switch (CheatType) { case MQWarp: //Some zones may still have issues. Database updates will eliminate most if not all problems. @@ -1304,7 +1304,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if(strlen(cze->char_name) > 63) return; - conn_state = ReceivedZoneEntry; + conn_state = ReceivedZoneEntry; ClientVersion = Connection()->ClientVersion(); if (ClientVersion != EQClientUnknown) @@ -1329,7 +1329,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) client_state = CLIENT_KICKED; return; } - + strcpy(name, cze->char_name); /* Check for Client Spoofing */ if (client != 0) { @@ -1342,7 +1342,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) client->Disconnect(); } - uint32 pplen = 0; + uint32 pplen = 0; EQApplicationPacket* outapp = 0; MYSQL_RES* result = 0; bool loaditems = 0; @@ -1366,8 +1366,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) if (lsaccountid && atoi(row[2]) > 0){ lsaccountid = atoi(row[2]); } else{ lsaccountid = 0; } gmspeed = atoi(row[3]); - revoked = atoi(row[4]); - gmhideme = atoi(row[5]); + revoked = atoi(row[4]); + gmhideme = atoi(row[5]); if (account_creation){ account_creation = atoul(row[6]); } } @@ -1375,17 +1375,17 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) query = StringFormat("SELECT `lfp`, `lfg`, `xtargets`, `firstlogon`, `guild_id`, `rank` FROM `character_data` LEFT JOIN `guild_members` ON `id` = `char_id` WHERE `id` = %i", cid); results = database.QueryDatabase(query); for (auto row = results.begin(); row != results.end(); ++row) { - if (row[4] && atoi(row[4]) > 0){ - guild_id = atoi(row[4]); + if (row[4] && atoi(row[4]) > 0){ + guild_id = atoi(row[4]); if (row[5] != nullptr){ guildrank = atoi(row[5]); } else{ guildrank = GUILD_RANK_NONE; } } - + if (LFP){ LFP = atoi(row[0]); } if (LFG){ LFG = atoi(row[1]); } if (firstlogon){ firstlogon = atoi(row[3]); } } - + if (RuleB(Character, SharedBankPlat)) m_pp.platinum_shared = database.GetSharedPlatinum(this->AccountID()); @@ -1417,7 +1417,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Set Con State for Reporting */ conn_state = PlayerProfileLoaded; - m_pp.zone_id = zone->GetZoneID(); + m_pp.zone_id = zone->GetZoneID(); m_pp.zoneInstance = zone->GetInstanceID(); /* Set Total Seconds Played */ @@ -1426,7 +1426,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) max_AAXP = RuleI(AA, ExpPerPoint); /* If we can maintain intoxication across zones, check for it */ if (!RuleB(Character, MaintainIntoxicationAcrossZones)) - m_pp.intoxication = 0; + m_pp.intoxication = 0; strcpy(name, m_pp.name); strcpy(lastname, m_pp.last_name); @@ -1435,14 +1435,14 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) m_pp.x = zone->safe_x(); m_pp.y = zone->safe_y(); m_pp.z = zone->safe_z(); - } + } /* If too far below ground, then fix */ // float ground_z = GetGroundZ(m_pp.x, m_pp.y, m_pp.z); // if (m_pp.z < (ground_z - 500)) // m_pp.z = ground_z; /* Set Mob variables for spawn */ - class_ = m_pp.class_; + class_ = m_pp.class_; level = m_pp.level; x_pos = m_pp.x; y_pos = m_pp.y; @@ -1471,7 +1471,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Load Guild */ if (!IsInAGuild()) { m_pp.guild_id = GUILD_NONE; } else { - m_pp.guild_id = GuildID(); + m_pp.guild_id = GuildID(); if (zone->GetZoneID() == RuleI(World, GuildBankZoneID)) GuildBanker = (guild_mgr.IsGuildLeader(GuildID(), CharacterID()) || guild_mgr.GetBankerFlag(CharacterID())); } @@ -1711,12 +1711,12 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) #endif /* Reset to max so they dont drown on zone in if its underwater */ - m_pp.air_remaining = 60; + m_pp.air_remaining = 60; /* Check for PVP Zone status*/ if (zone->IsPVPZone()) m_pp.pvp = 1; /* Time entitled on Account: Move to account */ - m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; + m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; /* Reset rest timer if the durations have been lowered in the database */ if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate))) m_pp.RestTimer = 0; @@ -1836,7 +1836,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) QueuePacket(outapp); safe_delete(outapp); - SetAttackTimer(); + SetAttackTimer(); conn_state = ZoneInfoSent; return; @@ -11311,56 +11311,46 @@ void Client::Handle_OP_RecipesFavorite(const EQApplicationPacket *app) // some_id = 0 if world combiner, item number otherwise // make where clause segment for container(s) - char containers[30]; - if (tsf->some_id == 0) { - // world combiner so no item number - snprintf(containers, 29, "= %u", tsf->object_type); - } - else { - // container in inventory - snprintf(containers, 29, "in (%u,%u)", tsf->object_type, tsf->some_id); - } - - char *query = 0; - char buf[5500]; //gotta be big enough for 500 IDs + std::string containers; + if (tsf->some_id == 0) + containers += StringFormat(" = %u ", tsf->object_type); // world combiner so no item number + else + containers += StringFormat(" in (%u, %u) ", tsf->object_type, tsf->some_id); // container in inventory + std::string favoriteIDs; //gotta be big enough for 500 IDs bool first = true; - uint16 r; - char *pos = buf; - //Assumes item IDs are <10 characters long - for (r = 0; r < 500; r++) { - if (tsf->favorite_recipes[r] == 0) + for (uint16 favoriteIndex = 0; favoriteIndex < 500; ++favoriteIndex) { + if (tsf->favorite_recipes[favoriteIndex] == 0) continue; if (first) { - pos += snprintf(pos, 10, "%u", tsf->favorite_recipes[r]); + favoriteIDs += StringFormat("%u", tsf->favorite_recipes[favoriteIndex]); first = false; } - else { - pos += snprintf(pos, 10, ",%u", tsf->favorite_recipes[r]); - } + else + favoriteIDs += StringFormat(",%u", tsf->favorite_recipes[favoriteIndex]); } if (first) //no favorites.... return; - //To be a good kid, I should move this SQL somewhere else... - //but im lazy right now, so it stays here - uint32 qlen = 0; - qlen = MakeAnyLenString(&query, "SELECT tr.id,tr.name,tr.trivial,SUM(tre.componentcount),crl.madecount,tr.tradeskill " - " FROM tradeskill_recipe AS tr " - " 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 tr.enabled <> 0 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 " - " LIMIT 100 ", CharacterID(), buf, containers); + const std::string query = StringFormat("SELECT tr.id, tr.name, tr.trivial, " + "SUM(tre.componentcount), crl.madecount,tr.tradeskill " + "FROM tradeskill_recipe AS tr " + "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 tr.enabled <> 0 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 " + "LIMIT 100 ", CharacterID(), favoriteIDs.c_str(), containers.c_str()); - TradeskillSearchResults(query, qlen, tsf->object_type, tsf->some_id); - - safe_delete_array(query); + TradeskillSearchResults(query, tsf->object_type, tsf->some_id); return; } @@ -11389,36 +11379,33 @@ void Client::Handle_OP_RecipesSearch(const EQApplicationPacket *app) snprintf(containers, 29, "in (%u,%u)", rss->object_type, rss->some_id); } - char *query = 0; - char searchclause[140]; //2X rss->query + SQL crap + std::string searchClause; //omit the rlike clause if query is empty if (rss->query[0] != 0) { char buf[120]; //larger than 2X rss->query database.DoEscapeString(buf, rss->query, strlen(rss->query)); - - snprintf(searchclause, 139, "name rlike '%s' AND", buf); + searchClause = StringFormat("name rlike '%s' AND", buf); } - else { - searchclause[0] = '\0'; - } - uint32 qlen = 0; //arbitrary limit of 200 recipes, makes sense to me. - qlen = MakeAnyLenString(&query, "SELECT tr.id,tr.name,tr.trivial,SUM(tre.componentcount),crl.madecount,tr.tradeskill " - " FROM tradeskill_recipe AS tr " - " 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 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 " - " LIMIT 200 " - , CharacterID(), searchclause, rss->mintrivial, rss->maxtrivial, containers); - - TradeskillSearchResults(query, qlen, rss->object_type, rss->some_id); - - safe_delete_array(query); + const std::string query = StringFormat("SELECT tr.id, tr.name, tr.trivial, " + "SUM(tre.componentcount), crl.madecount,tr.tradeskill " + "FROM tradeskill_recipe AS tr " + "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 " + "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 " + "LIMIT 200 ", + CharacterID(), searchClause.c_str(), + rss->mintrivial, rss->maxtrivial, containers); + TradeskillSearchResults(query, rss->object_type, rss->some_id); return; } diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 91cb458a0..0fd130f89 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -142,7 +142,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme // Adding augment if (in_augment->augment_slot == -1) { - if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) && + if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) && (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots))) { tobe_auged->PutAugment(slot, *auged_with); @@ -424,38 +424,28 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac return; } - - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - char *query = 0; - - uint32 qlen = 0; - uint8 qcount = 0; - - //pull the list of components - qlen = MakeAnyLenString(&query, "SELECT tre.item_id,tre.componentcount " - " FROM tradeskill_recipe_entries AS tre " - " WHERE tre.componentcount > 0 AND tre.recipe_id=%u", rac->recipe_id); - - if (!database.RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine query '%s': %s", query, errbuf); - safe_delete_array(query); + //pull the list of components + std::string query = StringFormat("SELECT tre.item_id, tre.componentcount " + "FROM tradeskill_recipe_entries AS tre " + "WHERE tre.componentcount > 0 AND tre.recipe_id = %u", + rac->recipe_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); user->QueuePacket(outapp); safe_delete(outapp); return; } - safe_delete_array(query); - qcount = mysql_num_rows(result); - if(qcount < 1) { + if(results.RowCount() < 1) { LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: no components returned"); user->QueuePacket(outapp); safe_delete(outapp); return; } - if(qcount > 10) { - LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: too many components returned (%u)", qcount); + + if(results.RowCount() > 10) { + LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: too many components returned (%u)", results.RowCount()); user->QueuePacket(outapp); safe_delete(outapp); return; @@ -466,17 +456,15 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac uint8 counts[10]; memset(counts, 0, sizeof(counts)); - //search for all the items in their inventory Inventory& user_inv = user->GetInv(); uint8 count = 0; uint8 needcount = 0; - uint8 r,k; std::list MissingItems; - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + uint8 needItemIndex = 0; + for (auto row = results.begin(); row != results.end(); ++row, ++needItemIndex) { uint32 item = (uint32)atoi(row[0]); uint8 num = (uint8) atoi(row[1]); @@ -491,10 +479,9 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac MissingItems.push_back(item); //dont start deleting anything until we have found it all. - items[r] = item; - counts[r] = num; + items[needItemIndex] = item; + counts[needItemIndex] = num; } - mysql_free_result(result); //make sure we found it all... if(count != needcount) @@ -520,12 +507,12 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac //remove all the items from the players inventory, with updates... int16 slot; - for(r = 0; r < qcount; r++) { + for(uint8 r = 0; r < results.RowCount(); r++) { if(items[r] == 0 || counts[r] == 0) continue; //skip empties, could prolly break here //we have to loop here to delete 1 at a time in case its in multiple stacks. - for(k = 0; k < counts[r]; k++) { + for(uint8 k = 0; k < counts[r]; k++) { slot = user_inv.HasItem(items[r], 1, invWherePersonal); if (slot == INVALID_INDEX) { //WTF... I just checked this above, but just to be sure... @@ -539,19 +526,14 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac const ItemInst* inst = user_inv.GetItem(slot); if (inst && !inst->IsStackable()) - { user->DeleteItemInInventory(slot, 0, true); - } else - { user->DeleteItemInInventory(slot, 1, true); - } } } //otherwise, we found it all... outp->reply_code = 0x00000000; //success for finding it... - user->QueuePacket(outapp); safe_delete(outapp); @@ -654,34 +636,26 @@ SkillUseTypes Object::TypeToSkill(uint32 type) return TradeskillUnknown; } -void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsigned long objtype, unsigned long someid) { +void Client::TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid) { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - - if (!database.RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': %s", query, errbuf); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return; } - uint8 qcount = 0; + if(results.RowCount() < 1) + return; //search gave no results... not an error - qcount = mysql_num_rows(result); - if(qcount < 1) { - //search gave no results... not an error - return; - } - if(mysql_num_fields(result) != 6) { - LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': Invalid column count in result", query); + if(results.ColumnCount() != 6) { + LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': Invalid column count in result", query.c_str()); return; } - uint8 r; - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + for(auto row = results.begin(); row != results.end(); ++row) { if(row == nullptr || row[0] == nullptr || row[1] == nullptr || row[2] == nullptr || row[3] == nullptr || row[5] == nullptr) continue; + uint32 recipe = (uint32)atoi(row[0]); const char *name = row[1]; uint32 trivial = (uint32) atoi(row[2]); @@ -691,14 +665,10 @@ void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsi // Skip the recipes that exceed the threshold in skill difference // Recipes that have either been made before or were // explicitly learned are excempt from that limit - if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff)) { - if (((int32)trivial - (int32)GetSkill((SkillUseTypes)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff) - && row[4] == nullptr) - { + if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff) + && ((int32)trivial - (int32)GetSkill((SkillUseTypes)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff) + && row[4] == nullptr) continue; - } - } - EQApplicationPacket* outapp = new EQApplicationPacket(OP_RecipeReply, sizeof(RecipeReply_Struct)); RecipeReply_Struct *reply = (RecipeReply_Struct *) outapp->pBuffer; @@ -711,39 +681,30 @@ void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsi strn0cpy(reply->recipe_name, name, sizeof(reply->recipe_name)); FastQueuePacket(&outapp); } - mysql_free_result(result); + } void Client::SendTradeskillDetails(uint32 recipe_id) { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - char *query = 0; - - uint32 qlen = 0; - uint8 qcount = 0; - - //pull the list of components - qlen = MakeAnyLenString(&query, "SELECT tre.item_id,tre.componentcount,i.icon,i.Name " - " FROM tradeskill_recipe_entries AS tre " - " LEFT JOIN items AS i ON tre.item_id = i.id " - " WHERE tre.componentcount > 0 AND tre.recipe_id=%u", recipe_id); - - if (!database.RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails query '%s': %s", query, errbuf); - safe_delete_array(query); + //pull the list of components + std::string query = StringFormat("SELECT tre.item_id,tre.componentcount,i.icon,i.Name " + "FROM tradeskill_recipe_entries AS tre " + "LEFT JOIN items AS i ON tre.item_id = i.id " + "WHERE tre.componentcount > 0 AND tre.recipe_id = %u", + recipe_id); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return; } - safe_delete_array(query); - qcount = mysql_num_rows(result); - if(qcount < 1) { + if(results.RowCount() < 1) { LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: no components returned"); return; } - if(qcount > 10) { - LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: too many components returned (%u)", qcount); + + if(results.RowCount() > 10) { + LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: too many components returned (%u)", results.RowCount()); return; } @@ -773,20 +734,18 @@ void Client::SendTradeskillDetails(uint32 recipe_id) { uint32 len; uint32 datalen = 0; uint8 count = 0; - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + + for(auto row = results.begin(); row != results.end(); ++row) { //watch for references to items which are not in the //items table, which the left join will make nullptr... - if(row[2] == nullptr || row[3] == nullptr) { + if(row[2] == nullptr || row[3] == nullptr) continue; - } uint32 item = (uint32)atoi(row[0]); uint8 num = (uint8) atoi(row[1]); - - uint32 icon = (uint32) atoi(row[2]); + const char *name = row[3]; len = strlen(name); if(len > 63) @@ -816,7 +775,6 @@ void Client::SendTradeskillDetails(uint32 recipe_id) { } } - mysql_free_result(result); //now move the item data over top of the FFFFs uint8 dist = sizeof(uint32) * (10 - count); @@ -1094,7 +1052,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) { ++itr; } return(true); - } + } /* Tradeskill Fail */ else { success_modifier = 2; // Halves the chance @@ -1172,7 +1130,7 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float chance_stage2 = 12.5 - (.08 * (current_raw_skill - 175)); } } - + chance_stage2 = mod_tradeskill_skillup(chance_stage2); if (chance_stage2 > MakeRandomFloat(0, 99)) { @@ -1191,249 +1149,212 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec) { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - char *query = 0; - char buf2[4096]; - uint32 sum = 0; - uint32 count = 0; - uint32 qcount = 0; - uint32 qlen = 0; - - // make where clause segment for container(s) - char containers[30]; - if (some_id == 0) { - // world combiner so no item number - snprintf(containers,29, "= %u", c_type); - } else { - // container in inventory - snprintf(containers,29, "in (%u,%u)", c_type, some_id); - } - - buf2[0] = '\0'; + std::string containers;// make where clause segment for container(s) + if (some_id == 0) + containers = StringFormat("= %u", c_type); // world combiner so no item number + else + containers = StringFormat("IN (%u,%u)", c_type, some_id); // container in inventory //Could prolly watch for stacks in this loop and handle them properly... //just increment sum and count accordingly bool first = true; - uint8 i; - char *pos = buf2; - for (i = 0; i < 10; i++) { // TODO: need to determine if this is bound to world/item container size + std::string buf2; + uint32 count = 0; + uint32 sum = 0; + for (uint8 i = 0; i < 10; i++) { // TODO: need to determine if this is bound to world/item container size const ItemInst* inst = container->GetItem(i); - if (inst) { - const Item_Struct* item = GetItem(inst->GetItem()->ID); - if (item) { - if(first) { - pos += snprintf(pos, 19, "%d", item->ID); - first = false; - } else { - pos += snprintf(pos, 19, ",%d", item->ID); - } - sum += item->ID; - count++; - } - } - } - *pos = '\0'; + if (!inst) + continue; - if(count < 1) { - return(false); //no items == no recipe + const Item_Struct* item = GetItem(inst->GetItem()->ID); + if (!item) + continue; + + if(first) { + buf2 += StringFormat("%d", item->ID); + first = false; + } else + buf2 += StringFormat(",%d", item->ID); + + sum += item->ID; + count++; } - qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id " - " FROM tradeskill_recipe_entries AS tre" - " INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) " - " WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount>0 )" - " OR ( tre.item_id %s AND tre.iscontainer=1 ))" - " GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u" - " AND sum(tre.item_id * tre.componentcount) = %u", buf2, containers, count, sum); + if(count == 0) + return false; //no items == no recipe - if (!RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query); - safe_delete_array(query); - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", errbuf); - return(false); - } - safe_delete_array(query); - - qcount = mysql_num_rows(result); - if(qcount > 1) { - //multiple recipes, partial match... do an extra query to get it exact. - //this happens when combining components for a smaller recipe - //which is completely contained within another recipe - - first = true; - pos = buf2; - for (i = 0; i < qcount; i++) { - row = mysql_fetch_row(result); - uint32 recipeid = (uint32)atoi(row[0]); - if(first) { - pos += snprintf(pos, 19, "%u", recipeid); - first = false; - } else { - pos += snprintf(pos, 19, ",%u", recipeid); - } - //length limit on buf2 - if(i == 214) { //Maximum number of recipe matches (19 * 215 = 4096) - LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", i + 1, qcount); - break; - } - } - - qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id" - " FROM tradeskill_recipe_entries AS tre" - " WHERE tre.recipe_id IN (%s)" - " GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u" - " AND sum(tre.item_id * tre.componentcount) = %u", buf2, count, sum); - - if (!RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query); - safe_delete_array(query); - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf); - return(false); - } - safe_delete_array(query); - - qcount = mysql_num_rows(result); + std::string query = StringFormat("SELECT tre.recipe_id " + "FROM tradeskill_recipe_entries AS tre " + "INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) " + "WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount > 0) " + "OR ( tre.item_id %s AND tre.iscontainer=1 ))" + "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " + "AND sum(tre.item_id * tre.componentcount) = %u", + buf2.c_str(), containers.c_str(), count, sum); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query.c_str()); + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", results.ErrorMessage().c_str()); + return false; } - if(qcount < 1) - return(false); + if (results.RowCount() > 1) { + //multiple recipes, partial match... do an extra query to get it exact. + //this happens when combining components for a smaller recipe + //which is completely contained within another recipe + first = true; + uint32 index = 0; + buf2 = ""; + for (auto row = results.begin(); row != results.end(); ++row, ++index) { + uint32 recipeid = (uint32)atoi(row[0]); + if(first) { + buf2 += StringFormat("%u", recipeid); + first = false; + } else + buf2 += StringFormat(",%u", recipeid); - if(qcount > 1) - { + //length limit on buf2 + if(index == 214) { //Maximum number of recipe matches (19 * 215 = 4096) + LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", index + 1, results.RowCount()); + break; + } + } + + query = StringFormat("SELECT tre.recipe_id " + "FROM tradeskill_recipe_entries AS tre " + "WHERE tre.recipe_id IN (%s) " + "GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u " + "AND sum(tre.item_id * tre.componentcount) = %u", buf2.c_str(), count, sum); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str()); + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str()); + return false; + } + } + + if (results.RowCount() < 1) + return false; + + if(results.RowCount() > 1) { //The recipe is not unique, so we need to compare the container were using. - uint32 containerId = 0; - if(some_id) { //Standard container + if(some_id) //Standard container containerId = some_id; - } - else if(c_type) { //World container + else if(c_type)//World container containerId = c_type; - } - else { //Invalid container - return(false); + else //Invalid container + return false; + + query = StringFormat("SELECT tre.recipe_id " + "FROM tradeskill_recipe_entries AS tre " + "WHERE tre.recipe_id IN (%s) " + "AND tre.item_id = %u;", buf2.c_str(), containerId); + results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str()); + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str()); + return false; } - qlen = MakeAnyLenString(&query,"SELECT tre.recipe_id FROM tradeskill_recipe_entries as tre WHERE tre.recipe_id IN (%s)" - " AND tre.item_id = %u;",buf2,containerId); - - if (!RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query); - safe_delete_array(query); - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf); - return(false); - } - safe_delete_array(query); - - uint32 resultRowTotal = mysql_num_rows(result); - - if(resultRowTotal == 0) { //Recipe contents matched more than 1 recipe, but not in this container + if(results.RowCount() == 0) { //Recipe contents matched more than 1 recipe, but not in this container LogFile->write(EQEMuLog::Error, "Combine error: Incorrect container is being used!"); - return(false); - } - if(resultRowTotal > 1) { //Recipe contents matched more than 1 recipe in this container - LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", resultRowTotal, containerId); + return false; } + + if (results.RowCount() > 1) //Recipe contents matched more than 1 recipe in this container + LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", results.RowCount(), containerId); + } - row = mysql_fetch_row(result); + auto row = results.begin(); uint32 recipe_id = (uint32)atoi(row[0]); - mysql_free_result(result); //Right here we verify that we actually have ALL of the tradeskill components.. //instead of part which is possible with experimentation. //This is here because something's up with the query above.. it needs to be rethought out bool has_components = true; - char TSerrbuf[MYSQL_ERRMSG_SIZE]; - char *TSquery = 0; - MYSQL_RES *TSresult; - MYSQL_ROW TSrow; - if (RunQuery(TSquery, MakeAnyLenString(&TSquery, "SELECT item_id, componentcount from tradeskill_recipe_entries where recipe_id=%i AND componentcount > 0", recipe_id), TSerrbuf, &TSresult)) { - while((TSrow = mysql_fetch_row(TSresult))!=nullptr) { - int ccnt = 0; - for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) { - const ItemInst* inst = container->GetItem(x); - if(inst){ - const Item_Struct* item = GetItem(inst->GetItem()->ID); - if (item) { - if(item->ID == atoi(TSrow[0])){ - ccnt++; - } - } - } - } - if(ccnt != atoi(TSrow[1])) - has_components = false; - } - mysql_free_result(TSresult); - } else { - LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", TSquery, TSerrbuf); - } - safe_delete_array(TSquery); - if(has_components == false){ + query = StringFormat("SELECT item_id, componentcount " + "FROM tradeskill_recipe_entries " + "WHERE recipe_id = %i AND componentcount > 0", + recipe_id); + results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); + } - return false; - } + if (results.RowCount() == 0) + return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); - return(GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec)); + for (auto row = results.begin(); row != results.end(); ++row) { + int ccnt = 0; + + for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) { + const ItemInst* inst = container->GetItem(x); + if(!inst) + continue; + + const Item_Struct* item = GetItem(inst->GetItem()->ID); + if (!item) + continue; + + if(item->ID == atoi(row[0])) + ccnt++; + } + + if(ccnt != atoi(row[1])) + return false; + } + + return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec); } bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec) { - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - char *query = 0; - - uint32 qcount = 0; - uint32 qlen; // make where clause segment for container(s) - char containers[30]; - if (some_id == 0) { - // world combiner so no item number - snprintf(containers,29, "= %u", c_type); - } else { - // container in inventory - snprintf(containers,29, "in (%u,%u)", c_type, some_id); + std::string containers; + if (some_id == 0) + containers = StringFormat("= %u", c_type); // world combiner so no item number + else + containers = StringFormat("IN (%u,%u)", c_type, some_id); // container in inventory + + std::string query = StringFormat("SELECT tr.id, tr.tradeskill, tr.skillneeded, " + "tr.trivial, tr.nofail, tr.replace_container, " + "tr.name, tr.must_learn, tr.quest, crl.madecount " + "FROM tradeskill_recipe AS tr " + "INNER 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 tr.id = %lu AND tre.item_id %s AND tr.enabled " + "GROUP BY tr.id", + char_id, (unsigned long)recipe_id, containers.c_str()); + auto results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, query: %s", query.c_str()); + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str()); + return false; } - qlen = MakeAnyLenString(&query, "SELECT tr.id, tr.tradeskill, tr.skillneeded," - " tr.trivial, tr.nofail, tr.replace_container, tr.name, tr.must_learn, tr.quest, crl.madecount" - " FROM tradeskill_recipe AS tr inner 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 tr.id = %lu AND tre.item_id %s AND tr.enabled " - " GROUP BY tr.id", char_id, (unsigned long)recipe_id, containers); + if(results.RowCount() != 1) + return false;//just not found i guess.. - if (!RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, query: %s", query); - safe_delete_array(query); - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf); - return(false); - } - safe_delete_array(query); - - qcount = mysql_num_rows(result); - if(qcount != 1) { - //just not found i guess.. - return(false); - } - - row = mysql_fetch_row(result); - spec->tradeskill = (SkillUseTypes)atoi(row[1]); - spec->skill_needed = (int16)atoi(row[2]); - spec->trivial = (uint16)atoi(row[3]); - spec->nofail = atoi(row[4]) ? true : false; + auto row = results.begin(); + spec->tradeskill = (SkillUseTypes)atoi(row[1]); + spec->skill_needed = (int16)atoi(row[2]); + spec->trivial = (uint16)atoi(row[3]); + spec->nofail = atoi(row[4]) ? true : false; spec->replace_container = atoi(row[5]) ? true : false; spec->name = row[6]; spec->must_learn = (uint8)atoi(row[7]); spec->quest = atoi(row[8]) ? true : false; + if (row[9] == nullptr) { spec->has_learnt = false; spec->madecount = 0; @@ -1442,141 +1363,109 @@ bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id spec->madecount = (uint32)atoul(row[9]); } spec->recipe_id = recipe_id; - mysql_free_result(result); //Pull the on-success items... - qlen = MakeAnyLenString(&query, "SELECT item_id,successcount FROM tradeskill_recipe_entries" - " WHERE successcount>0 AND recipe_id=%u", recipe_id); - - if (!RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success query '%s': %s", query, errbuf); - safe_delete_array(query); - return(false); + query = StringFormat("SELECT item_id,successcount FROM tradeskill_recipe_entries " + "WHERE successcount > 0 AND recipe_id = %u", recipe_id); + results = QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); + return false; } - safe_delete_array(query); - qcount = mysql_num_rows(result); - if(qcount < 1) { + if(results.RowCount() < 1) { LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success: no success items returned"); - return(false); + return false; } - uint8 r; + spec->onsuccess.clear(); - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + for(auto row = results.begin(); row != results.end(); ++row) { uint32 item = (uint32)atoi(row[0]); uint8 num = (uint8) atoi(row[1]); spec->onsuccess.push_back(std::pair(item, num)); } - mysql_free_result(result); + spec->onfail.clear(); //Pull the on-fail items... - qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries" - " WHERE failcount>0 AND recipe_id=%u", recipe_id); - - spec->onfail.clear(); - if (RunQuery(query, qlen, errbuf, &result)) { - - qcount = mysql_num_rows(result); - uint8 r; - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + query = StringFormat("SELECT item_id, failcount FROM tradeskill_recipe_entries " + "WHERE failcount > 0 AND recipe_id = %u", recipe_id); + results = QueryDatabase(query); + if (results.Success()) + for(auto row = results.begin(); row != results.end(); ++row) { uint32 item = (uint32)atoi(row[0]); uint8 num = (uint8) atoi(row[1]); spec->onfail.push_back(std::pair(item, num)); } - mysql_free_result(result); - } + + spec->salvage.clear(); + + // Don't bother with the query if TS is nofail + if (spec->nofail) + return true; // Pull the salvage list - qlen = MakeAnyLenString(&query, "SELECT item_id,salvagecount FROM tradeskill_recipe_entries WHERE salvagecount>0 AND recipe_id=%u", recipe_id); - - spec->salvage.clear(); - // Don't bother with the query if TS is nofail - if (!spec->nofail && RunQuery(query, qlen, errbuf, &result)) { - qcount = mysql_num_rows(result); - uint8 r; - for(r = 0; r < qcount; r++) { - row = mysql_fetch_row(result); + query = StringFormat("SELECT item_id, salvagecount " + "FROM tradeskill_recipe_entries " + "WHERE salvagecount > 0 AND recipe_id = %u", recipe_id); + results = QueryDatabase(query); + if (results.Success()) + for(auto row = results.begin(); row != results.begin(); ++row) { uint32 item = (uint32)atoi(row[0]); uint8 num = (uint8)atoi(row[1]); spec->salvage.push_back(std::pair(item, num)); } - mysql_free_result(result); - } - safe_delete_array(query); - - return(true); + return true; } -void ZoneDatabase::UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madecount) +void ZoneDatabase::UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madeCount) { - char *query = 0; - uint32 qlen; - char errbuf[MYSQL_ERRMSG_SIZE]; - - qlen = MakeAnyLenString(&query, "INSERT INTO char_recipe_list " - " SET recipe_id = %u, char_id = %u, madecount = %u " - " ON DUPLICATE KEY UPDATE madecount = %u;" - , recipe_id, char_id, madecount, madecount); - - if (!RunQuery(query, qlen, errbuf)) { - LogFile->write(EQEMuLog::Error, "Error in UpdateRecipeMadecount query '%s': %s", query, errbuf); - } - safe_delete_array(query); + std::string query = StringFormat("INSERT INTO char_recipe_list " + "SET recipe_id = %u, char_id = %u, madecount = %u " + "ON DUPLICATE KEY UPDATE madecount = %u;", + recipe_id, char_id, madeCount, madeCount); + auto results = QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Error in UpdateRecipeMadecount query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); } void Client::LearnRecipe(uint32 recipeID) { - char *query = 0; - uint32 qlen; - uint32 qcount = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; - MYSQL_RES *result; - MYSQL_ROW row; - - qlen = MakeAnyLenString(&query, "SELECT tr.name, crl.madecount " - " FROM tradeskill_recipe as tr " - " 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 = %u ;", CharacterID(), recipeID); - - if (!database.RunQuery(query, qlen, errbuf, &result)) { - LogFile->write(EQEMuLog::Error, "Error in Client::LearnRecipe query '%s': %s", query, errbuf); - safe_delete_array(query); + std::string query = StringFormat("SELECT tr.name, crl.madecount " + "FROM tradeskill_recipe AS tr " + "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 = %u ;", CharacterID(), recipeID); + auto results = database.QueryDatabase(query); + if (!results.Success()) { + LogFile->write(EQEMuLog::Error, "Error in Client::LearnRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); return; } - qcount = mysql_num_rows(result); - if (qcount != 1) { - LogFile->write(EQEMuLog::Normal, "Client::LearnRecipe - RecipeID: %d had %d occurences.", recipeID, qcount); - mysql_free_result(result); - safe_delete_array(query); + if (results.RowCount() != 1) { + LogFile->write(EQEMuLog::Normal, "Client::LearnRecipe - RecipeID: %d had %d occurences.", recipeID, results.RowCount()); return; } - safe_delete_array(query); - row = mysql_fetch_row(result); + auto row = results.begin(); - if (row != nullptr && row[0] != nullptr) { - // Only give Learn message if character doesn't know the recipe - if (row[1] == nullptr) { - Message_StringID(4, TRADESKILL_LEARN_RECIPE, row[0]); - // Actually learn the recipe now - qlen = MakeAnyLenString(&query, "INSERT INTO char_recipe_list " - " SET recipe_id = %u, char_id = %u, madecount = 0 " - " ON DUPLICATE KEY UPDATE madecount = madecount;" - , recipeID, CharacterID()); + if (row[0] == nullptr) + return; - if (!database.RunQuery(query, qlen, errbuf)) { - LogFile->write(EQEMuLog::Error, "Error in LearnRecipe query '%s': %s", query, errbuf); - } - safe_delete_array(query); - } - } + // Only give Learn message if character doesn't know the recipe + if (row[1] != nullptr) + return; - mysql_free_result(result); + Message_StringID(4, TRADESKILL_LEARN_RECIPE, row[0]); + // Actually learn the recipe now + query = StringFormat("INSERT INTO char_recipe_list " + "SET recipe_id = %u, char_id = %u, madecount = 0 " + "ON DUPLICATE KEY UPDATE madecount = madecount;", + recipeID, CharacterID()); + results = database.QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Error in LearnRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); } @@ -1622,33 +1511,22 @@ bool Client::CanIncreaseTradeskill(SkillUseTypes tradeskill) { bool ZoneDatabase::EnableRecipe(uint32 recipe_id) { - char *query = 0; - uint32 qlen; - char errbuf[MYSQL_ERRMSG_SIZE]; - uint32 affected_rows = 0; + std::string query = StringFormat("UPDATE tradeskill_recipe SET enabled = 1 " + "WHERE id = %u;", recipe_id); + auto results = QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Error in EnableRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); - qlen = MakeAnyLenString(&query, "UPDATE tradeskill_recipe SET enabled = 1 WHERE id = %u;", recipe_id); - - if (!RunQuery(query, qlen, errbuf, 0, &affected_rows)) { - LogFile->write(EQEMuLog::Error, "Error in EnableRecipe query '%s': %s", query, errbuf); - } - safe_delete_array(query); - - return (affected_rows > 0); + return results.RowsAffected() > 0; } bool ZoneDatabase::DisableRecipe(uint32 recipe_id) { - char *query = 0; - uint32 qlen; - char errbuf[MYSQL_ERRMSG_SIZE]; - uint32 affected_rows = 0; + std::string query = StringFormat("UPDATE tradeskill_recipe SET enabled = 0 " + "WHERE id = %u;", recipe_id); + auto results = QueryDatabase(query); + if (!results.Success()) + LogFile->write(EQEMuLog::Error, "Error in DisableRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str()); - qlen = MakeAnyLenString(&query, "UPDATE tradeskill_recipe SET enabled = 0 WHERE id = %u;", recipe_id); - - if (!RunQuery(query, qlen, errbuf, 0, &affected_rows)) { - LogFile->write(EQEMuLog::Error, "Error in DisableRecipe query '%s': %s", query, errbuf); - } - safe_delete_array(query); - return (affected_rows > 0); + return results.RowsAffected() > 0; }