//------------------------------------------------ //Guild bound items pull for offline characters [Akinari] //Revised by [Mhalicot] //------------------------------------------------ int mapif_parse_ItemBoundRetrieve_sub(int fd) { #ifdef GP_BOUND_ITEMS StringBuf buf; struct SqlStmt *stmt; struct item item; int j, i=0, s=0, bound_qt=0; struct item items[MAX_INVENTORY]; unsigned int bound_item[MAX_INVENTORY] = {0}; int char_id = RFIFOL(fd,2); int aid = RFIFOL(fd,6); int guild_id = RFIFOW(fd,10); StrBuf->Init(&buf); StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`"); for( j = 0; j < MAX_SLOTS; ++j ) StrBuf->Printf(&buf, ", `card%d`", j); StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = '%d'",inventory_db,char_id,IBT_GUILD); stmt = SQL->StmtMalloc(inter->sql_handle); if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtExecute(stmt) ) { Sql_ShowDebug(inter->sql_handle); SQL->StmtFree(stmt); StrBuf->Destroy(&buf); return 1; } memset(&item, 0, sizeof(item)); SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL); for( j = 0; j < MAX_SLOTS; ++j ) SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); while( SQL_SUCCESS == SQL->StmtNextRow(stmt)) { Assert_retb(i < MAX_INVENTORY); memcpy(&items[i],&item,sizeof(struct item)); i++; } SQL->FreeResult(inter->sql_handle); if(!i) { //No items found - No need to continue StrBuf->Destroy(&buf); SQL->StmtFree(stmt); return 0; } //First we delete the character's items StrBuf->Clear(&buf); StrBuf->Printf(&buf, "DELETE FROM `%s` WHERE",inventory_db); for(j=0; j<i; j++) { if( j ) StrBuf->AppendStr(&buf, " OR"); StrBuf->Printf(&buf, " `id`=%d",items[j].id); if( items[j].bound && items[j].equip ) { // Only the items that are also stored in `char` `equip` if( items[j].equip&EQP_HAND_R || items[j].equip&EQP_HAND_L || items[j].equip&EQP_HEAD_TOP || items[j].equip&EQP_HEAD_MID || items[j].equip&EQP_HEAD_LOW || items[j].equip&EQP_GARMENT ) { bound_item[bound_qt] = items[j].equip; bound_qt++; } } } if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtExecute(stmt) ) { Sql_ShowDebug(inter->sql_handle); SQL->StmtFree(stmt); StrBuf->Destroy(&buf); return 1; } // Removes any view id that was set by an item that was removed if( bound_qt ) { #define CHECK_REMOVE(var,mask,token) do { /* Verifies equip bitmasks (see item.equip) and handles the sql statement */ \ if ((var)&(mask)) { \ if ((var) != (mask) && s) StrBuf->AppendStr(&buf, ","); \ StrBuf->AppendStr(&buf,"`"#token"`='0'"); \ (var) &= ~(mask); \ s++; \ } \ } while(0) StrBuf->Clear(&buf); StrBuf->Printf(&buf, "UPDATE `%s` SET ", char_db); for( j = 0; j < bound_qt; j++ ) { // Equips can be at more than one slot at the same time CHECK_REMOVE(bound_item[j],EQP_HAND_R,weapon); CHECK_REMOVE(bound_item[j],EQP_HAND_L,shield); CHECK_REMOVE(bound_item[j],EQP_HEAD_TOP,head_top); CHECK_REMOVE(bound_item[j],EQP_HEAD_MID,head_mid); CHECK_REMOVE(bound_item[j],EQP_HEAD_LOW,head_bottom); CHECK_REMOVE(bound_item[j],EQP_GARMENT,robe); } StrBuf->Printf(&buf, " WHERE `char_id`='%d'", char_id); if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtExecute(stmt) ) { Sql_ShowDebug(inter->sql_handle); SQL->StmtFree(stmt); StrBuf->Destroy(&buf); return 1; } #undef CHECK_REMOVE } //Now let's update the guild storage with those deleted items /// TODO/FIXME: /// This approach is basically the same as the one from chr->memitemdata_to_sql, but /// the latter compares current database values and this is not needed in this case /// maybe sometime separate chr->memitemdata_to_sql into different methods in order to use /// call that function here as well [Panikon] StrBuf->Clear(&buf); StrBuf->Printf(&buf,"INSERT INTO `%s` (`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`," "`attribute`,`expire_time`,`bound`,`unique_id`", guild_storage_db); for( s = 0; s < MAX_SLOTS; ++s ) StrBuf->Printf(&buf, ", `card%d`", s); StrBuf->AppendStr(&buf," ) VALUES "); for( j = 0; j < i; ++j ) { if( j ) StrBuf->AppendStr(&buf, ","); StrBuf->Printf(&buf, "('%d', '%d', '%d', '%u', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'", guild_id, items[j].nameid, items[j].amount, items[j].equip, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound, items[j].unique_id); for( s = 0; s < MAX_SLOTS; ++s ) StrBuf->Printf(&buf, ", '%d'", items[j].card[s]); StrBuf->AppendStr(&buf, ")"); } if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf)) || SQL_ERROR == SQL->StmtExecute(stmt) ) { Sql_ShowDebug(inter->sql_handle); SQL->StmtFree(stmt); StrBuf->Destroy(&buf); return 1; } StrBuf->Destroy(&buf); SQL->StmtFree(stmt); //Finally reload storage and tell map we're done mapif->load_guild_storage(fd,aid,guild_id,0); // If character is logged in char, disconnect chr->disconnect_player(aid); #endif return 0; }
/** * Loads console commands list **/ void console_load_defaults(void) { /** * Defines a main category. * * Categories can't be used as commands! * E.G. * - sql update skip * 'sql' is the main category * CP_DEF_C(category) **/ #define CP_DEF_C(x) { #x , CPET_CATEGORY, NULL , NULL, NULL } /** * Defines a sub-category. * * Sub-categories can't be used as commands! * E.G. * - sql update skip * 'update' is a sub-category * CP_DEF_C2(command, category) **/ #define CP_DEF_C2(x,y) { #x , CPET_CATEGORY, NULL , #y, NULL } /** * Defines a command that is inside a category or sub-category * CP_DEF_S(command, category/sub-category) **/ #define CP_DEF_S(x,y) { #x, CPET_FUNCTION, CPCMD_C_A(x,y), #y, NULL } /** * Defines a command that is _not_ inside any category * CP_DEF_S(command) **/ #define CP_DEF(x) { #x , CPET_FUNCTION, CPCMD_A(x), NULL, NULL } struct { char *name; int type; CParseFunc func; char *connect; struct CParseEntry *self; } default_list[] = { CP_DEF(help), /** * Server related commands **/ CP_DEF_C(server), CP_DEF_S(ers_report,server), CP_DEF_S(mem_report,server), CP_DEF_S(malloc_usage,server), CP_DEF_S(exit,server), /** * Sql related commands **/ CP_DEF_C(sql), CP_DEF_C2(update,sql), CP_DEF_S(skip,update), }; int len = ARRAYLENGTH(default_list); struct CParseEntry *cmd; int i; VECTOR_ENSURE(console->input->commands, len, 1); for(i = 0; i < len; i++) { CREATE(cmd, struct CParseEntry, 1); safestrncpy(cmd->cmd, default_list[i].name, CP_CMD_LENGTH); cmd->type = default_list[i].type; switch (cmd->type) { case CPET_FUNCTION: cmd->u.func = default_list[i].func; break; case CPET_CATEGORY: VECTOR_INIT(cmd->u.children); break; case CPET_UNKNOWN: break; } VECTOR_PUSH(console->input->commands, cmd); default_list[i].self = cmd; if (!default_list[i].connect) { VECTOR_ENSURE(console->input->command_list, 1, 1); VECTOR_PUSH(console->input->command_list, cmd); } } for (i = 0; i < len; i++) { int k; if (!default_list[i].connect) continue; ARR_FIND(0, VECTOR_LENGTH(console->input->commands), k, strcmpi(default_list[i].connect, VECTOR_INDEX(console->input->commands, k)->cmd) == 0); if (k != VECTOR_LENGTH(console->input->commands)) { struct CParseEntry *parent = VECTOR_INDEX(console->input->commands, k); Assert_retb(parent->type == CPET_CATEGORY); cmd = default_list[i].self; VECTOR_ENSURE(parent->u.children, 1, 1); VECTOR_PUSH(parent->u.children, cmd); } } #undef CP_DEF_C #undef CP_DEF_C2 #undef CP_DEF_S #undef CP_DEF }