Tradeskills.cpp
Code:
<!bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint8 tradeskill,
!>bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id,
DBTradeskillRecipe_Struct *spec)
{
char errbuf[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
char *query = 0;
char buf2[2048];
uint32 sum = 0;
uint32 count = 0;
uint32 qcount = 0;
uint32 qlen = 0;
<! //use the world item type as type if we have a world item
<! //otherwise use the item's ID... this make the assumption that
<! //no tradeskill containers will have an item ID which is
<! //below the highest ID of objects, which is currently 0x30
<! uint32 type = c_type;
<!
<! //dunno why I have to cast this up to call GetItem
<! const Item_Struct *istruct = ((const ItemInst *) container)->GetItem();
<! if(c_type == 0 && istruct) {
<! type = istruct->ID;
<! }
<!
!> // 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';
//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++) {
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(count < 1) {
return(false); //no items == no recipe
}
qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id "
" FROM tradeskill_recipe_entries AS tre"
" WHERE ( tre.item_id IN(%s) AND tre.componentcount>0 )"
<! " OR ( tre.item_id=%u AND tre.iscontainer=1 )"
!> " 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, type, count, sum);
!> " AND sum(tre.item_id * tre.componentcount) = %u", buf2, containers, count, sum);
if (!RunQuery(query, qlen, errbuf, &result)) {
<! LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept search, query: %s", query);
!> LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query);
safe_delete_array(query);
<! LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept search, error: %s", errbuf);
!> 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 sanity check on buf2
if(pos > (buf2 + 2020))
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 GetTradeRecept, re-query: %s", query);
!> LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query);
safe_delete_array(query);
<! LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept, error: %s", errbuf);
!> LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf);
return(false);
}
safe_delete_array(query);
qcount = mysql_num_rows(result);
}
if (qcount != 1) {
if(qcount > 1) {
LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique!");
}
//else, just not found i guess..
return(false);
}
row = mysql_fetch_row(result);
uint32 recipe_id = (uint32)atoi(row[0]);
mysql_free_result(result);
<! return(GetTradeRecipe(recipe_id, c_type, tradeskill, spec));
!> return(GetTradeRecipe(recipe_id, c_type, some_id, spec));
}
Changed signature to use some_id instead of tradeskill
Changed error logging to use actual function name
Changed query to use containers (type and some_id) instead of just one or the other - this helps simplify recipes
Code:
<!bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint8 tradeskill,
!>bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id,
DBTradeskillRecipe_Struct *spec)
{
char errbuf[MYSQL_ERRMSG_SIZE];
MYSQL_RES *result;
MYSQL_ROW row;
char *query = 0;
uint32 qcount = 0;
uint32 qlen;
<! qlen = MakeAnyLenString(&query, "SELECT tr.skillneeded, tr.trivial, tr.nofail, tr.replace_container"
<! " FROM tradeskill_recipe AS tr"
<! " WHERE tr.id = %lu AND tr.tradeskill = %u", recipe_id, tradeskill);
!> // 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);
!> }
!>
!> qlen = MakeAnyLenString(&query, "SELECT tr.id, tr.tradeskill, tr.skillneeded,"
!> " tr.trivial, tr.nofail, tr.replace_container"
!> " FROM tradeskill_recipe AS tr inner join tradeskill_recipe_entries as tre"
!> " ON tr.id = tre.recipe_id"
!> " WHERE tr.id = %lu AND tre.item_id %s"
!> " GROUP BY tr.id", recipe_id, containers);
if (!RunQuery(query, qlen, errbuf, &result)) {
<! LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept, query: %s", query);
!> LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, query: %s", query);
safe_delete_array(query);
<! LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept, error: %s", errbuf);
!> 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->skill_needed = (sint16)atoi(row[0]);
<! spec->trivial = (uint16)atoi(row[1]);
<! spec->nofail = atoi(row[2]) ? true : false;
<! spec->replace_container = atoi(row[3]) ? true : false;
!> spec->tradeskill = (SkillType)atoi(row[1]);
!> spec->skill_needed = (sint16)atoi(row[2]);
!> spec->trivial = (uint16)atoi(row[3]);
!> spec->nofail = atoi(row[4]) ? true : false;
!> spec->replace_container = atoi(row[5]) ? true : false;
mysql_free_result(result);
//Pull the on-success items...
qlen = MakeAnyLenString(&query, "SELECT item_id,successcount FROM tradeskill_recipe_entries"
" WHERE successcount>0 AND componentcount=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);
}
safe_delete_array(query);
qcount = mysql_num_rows(result);
if(qcount < 1) {
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success: no success items returned");
return(false);
}
uint8 r;
spec->onsuccess.clear();
for(r = 0; r < qcount; r++) {
row = mysql_fetch_row(result);
/*if(r == 0) {
*product1_id = (uint32)atoi(row[0]);
*productcount = (uint32)atoi(row[1]);
} else if(r == 1) {
*product2_id = (uint32)atoi(row[0]);
} else {
LogFile->write(EQEMuLog::Warning, "Warning: recipe returned more than 2 products, not yet supported.");
}*/
uint32 item = (uint32)atoi(row[0]);
uint8 num = (uint8) atoi(row[1]);
spec->onsuccess.push_back(pair<uint32,uint8>::pair(item, num));
}
mysql_free_result(result);
//Pull the on-fail items...
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
" WHERE failcount>0 AND componentcount=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);
/*if(r == 0) {
*failproduct_id = (uint32)atoi(row[0]);
} else {
LogFile->write(EQEMuLog::Warning, "Warning: recipe returned more than 1 fail product, not yet supported.");
}*/
uint32 item = (uint32)atoi(row[0]);
uint8 num = (uint8) atoi(row[1]);
spec->onfail.push_back(pair<uint32,uint8>::pair(item, num));
}
mysql_free_result(result);
}
safe_delete_array(query);
return(true);
}
Changed signature from using tradeskill to using some_id
Changed query to use containers instead of tradeskill
Changed error message posting to use actual name of function
Changed fetch results to include tradeskill from recipe in spec
|