Jump to content

ValkyrieCK

Members
  • Posts

    12
  • Joined

  • Last visited

1 Follower

About ValkyrieCK

  • Birthday 01/01/1980

Profile Information

  • Gender
    Male
  • Location
    Hong Kong
  • Server
    __RO
  • Github: __RO
  • Discord: ValkyrieCK#7983
  • Interests
    Innovation & Design

Contact Methods

Recent Profile Visitors

3640 profile views

ValkyrieCK's Achievements

Poring

Poring (1/15)

  • Reacting Well
  • Dedicated
  • Week One Done
  • One Month Later
  • One Year In

Recent Badges

6

Reputation

1

Community Answers

Single Status Update

See all updates by ValkyrieCK

  1. 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!!!!

×
×
  • Create New...