-
Posts
12 -
Joined
-
Last visited
ValkyrieCK's Achievements
-
Original Post:
[UPDATED Charm Tutorial]
To add an item which can apply an item bonus effect while in inventory.
Step 1: Create new itemtype @ mmo.hpp
enum item_types { IT_HEALING = 0, IT_UNKNOWN, //1 IT_USABLE, //2 IT_ETC, //3 IT_ARMOR, //4 IT_WEAPON, //5 IT_CARD, //6 IT_PETEGG, //7 IT_PETARMOR,//8 IT_UNKNOWN2,//9 IT_AMMO, //10 IT_DELAYCONSUME,//11 IT_SHADOWGEAR, //12 IT_CHARM, //13 <<------------- new itemtype. In this case, we are going to use "integer 13" to represent this itemtype IT_CASH = 18, IT_MAX };
Step 2: Placement for "Charm" item, we are going to place this item at your inventory -> etc. @ clif.cpp
static inline int itemtype(unsigned short nameid) { struct item_data* id = itemdb_search(nameid); int type = id->type; if( type == IT_SHADOWGEAR ) { if( id->equip&EQP_SHADOW_WEAPON ) return IT_WEAPON; else return IT_ARMOR; } // =============================================================== // If the itemtype is IT_CHARM, we will place the item to ETC tab. // =============================================================== return ( type == IT_PETEGG ) ? IT_ARMOR : (type == IT_CHARM) ? IT_ETC : type; }
Step 3: Handle the stackable or not, you can customize your code here btw. @ itemdb.cpp
bool itemdb_isstackable2(struct item_data *id) { nullpo_ret(id); switch(id->type) { case IT_WEAPON: case IT_ARMOR: case IT_PETEGG: case IT_PETARMOR: case IT_SHADOWGEAR: case IT_CHARM: // <<--------- If you don't want it stackable place the itemtype here. return false; default: // <<--------------- By default, it will stackable if you don't add itemtype above. return true; } }
(Optional Step): Able to equip this item or not. @ itemdb.cpp
bool itemdb_isequip2(struct item_data *id) { nullpo_ret(id); switch (id->type) { case IT_WEAPON: case IT_ARMOR: case IT_AMMO: case IT_SHADOWGEAR: case IT_CHARM: // <<------------------ If you want to able to equip, place an itemtype here. return true; default: // <<------------------------ By default, it will not able to equip. return false; } }
Step 4: Add itemdb type name for "Charm" item. @ itemdb.cpp
const char* itemdb_typename(enum item_types type) { switch(type) { case IT_HEALING: return "Potion/Food"; case IT_USABLE: return "Usable"; case IT_ETC: return "Etc."; case IT_WEAPON: return "Weapon"; case IT_ARMOR: return "Armor"; case IT_CARD: return "Card"; case IT_PETEGG: return "Pet Egg"; case IT_PETARMOR: return "Pet Accessory"; case IT_AMMO: return "Arrow/Ammunition"; case IT_DELAYCONSUME: return "Delay-Consume Usable"; case IT_SHADOWGEAR: return "Shadow Equipment"; case IT_CASH: return "Cash Usable"; case IT_CHARM: return "Charms"; // <<--------------------- Add itemdb type name here. } return "Unknown Type"; }
Step 5: Accept the "IT_CHARM" itemtype go through the itemdb parse function @ itemdb.cpp
static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) { // many codes.... id->type = atoi(str[3]); // ================================================================================================================ // Exclude the IT_CHARM from the exception // It depends on which ID you set in the mmo.hpp. In this case, we use ID = 13, which is less than IT_CASH (18). // Therefore, from 14 to 17 are invalid value from itemdb. And it will cause an error when doing parse from itemdb. // ================================================================================================================ if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_CHARM && id->type < IT_CASH ) || id->type >= IT_MAX ) { // catch invalid item types ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %hu. IT_ETC will be used.\n", id->type, nameid); id->type = IT_ETC; } // many codes.... }
Step 6: Set "CHARM" item to auto equip. @ pc.cpp
char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_pick_type log_type) { // [many codes...] clif_updatestatus(sd,SP_WEIGHT); //Auto-equip if(id->flag.autoequip) pc_equipitem(sd, i, id->equip); // ========================================================================================== // If the itemtype is CHARM, then we will call the status_calc_pc for updating player status. // ========================================================================================== if (id->type == IT_CHARM) status_calc_pc(sd, SCO_NONE); // [many codes...] }
Step 7: Handle drop item @ pc.cpp
char pc_delitem(struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type) { // ===================================== // add tempoary int for storing itemtype // ===================================== int mem = -1; nullpo_retr(1, sd); if(n < 0 || sd->inventory.u.items_inventory[n].nameid == 0 || amount <= 0 || sd->inventory.u.items_inventory[n].amount<amount || sd->inventory_data[n] == NULL) return 1; log_pick_pc(sd, log_type, -amount, &sd->inventory.u.items_inventory[n]); sd->inventory.u.items_inventory[n].amount -= amount; sd->weight -= sd->inventory_data[n]->weight*amount ; if( sd->inventory.u.items_inventory[n].amount <= 0 ){ if(sd->inventory.u.items_inventory[n].equip) pc_unequipitem(sd,n,2|(!(type&4) ? 1 : 0)); memset(&sd->inventory.u.items_inventory[n],0,sizeof(sd->inventory.u.items_inventory[0])); // =========================== // store the itemtype to `mem` // =========================== mem = sd->inventory_data[n]->type; sd->inventory_data[n] = NULL; } if(!(type&1)) clif_delitem(sd,n,amount,reason); if(!(type&2)) clif_updatestatus(sd,SP_WEIGHT); // =============================================== // If is CHARM item, then update the player status // =============================================== if (mem == IT_CHARM) status_calc_pc(sd, SCO_NONE); return 0; }
Step 8: Handle the status calc function @ status.cpp
int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { // [many codes...] // Autobonus pc_delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),true); pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus2),true); pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true); // ================================ // Calculate CHARM item effect here // ================================ // Loop the whole inventory for ( i=0; i < MAX_INVENTORY; i++ ) { // If the item is not IT_CHARM, then skip it. if ( !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_CHARM ) continue; // Check the CHARM item level limitation and job limitation (you can customize the condition here) if ( sd->inventory_data[i]->script && sd->inventory_data[i]->elv <= sd->status.base_level && sd->inventory_data[i]->class_upper ) { // If player match the condition, then run the item bonus script. run_script( sd->inventory_data[i]->script, 0, sd->bl.id, 0 ); if ( !calculating ) //Abort, run_script retriggered this. [Skotlex] return 1; } } // [many codes...] }
Step 9: Recompile your server
Step 10: Add CHARM item to itemdb.txt. For example:
// all + 100 charm item 701,Ora_Ora,Ora Ora,13,10,,100,,10,,0,0xFFFFFFFF,63,2,16,,0,1,0,{ bonus bAllStats,100; },{},{}
Have fun!!!!