Jump to content
Rebel

Costume NPC and @costumeitem

Recommended Posts

Hi all,

I've taken the time to update this script and tested it on my server running latest version of rAthena (version at the time of writing Git Hash: f8d5d45).

Additional Changes

  • NPC name can now be easily customised by replacing 2nd argument in the function call at the bottom of npc/custom/etc/costume.txt
  • NPC checks whether the user already has the same item being restored equipped or in inventory and will prevent restoring.
  • Fixed/tweaked some typos and grammar for the NPC dialogue and atcommand messages.
  • costume.txt has been included inside the diff

Screenshot

screenChocobotRO010.thumb.jpg.a0ff6db06ffca4f21dbed55d3e6b69b9.jpg

Costume_System_v2.diff

Edit: I actually just discovered that the wonderful secretdataz had already updated the diff to work with newer versions of rAthena here (https://github.com/secretdataz/rathena/pull/8/files). The main differences to my edit is secret's also handles costuming garments and there is atcommand documentation. The diff I have uploaded comes with an updated NPC script.

Edited by latios
Found existing diff by secretdataz
  • Upvote 1
Link to comment
Share on other sites

@latios

Thx for the update, but to be able to equip the costume you must have the requirements of the normal headgear

example :

a costume apple of archer require lvl 30 and can't equip by a novice

 

Link to comment
Share on other sites

@Captain

Yes, that's correct. Although a way around this is to "costume" the item on another character who can wear it and then put it in storage to transfer back to your other character to wear.

I don't believe the item permissions (storage/trade/drop/etc ...) are modified, so if you could trade it before you can still trade it after "costuming" the item.

Link to comment
Share on other sites

@latios

The problem is you can't equip the costume headgear if you not have the requirement of not costume headgear

example on novice with costume apple of archer :

549625262_bugcostume.PNG.89dea0c64e32b9088cd9663782015a7d.PNG

 

Link to comment
Share on other sites

On 3/23/2020 at 1:12 AM, latios said:

Hi all,

I've taken the time to update this script and tested it on my server running latest version of rAthena (version at the time of writing Git Hash: f8d5d45).

Additional Changes

  • NPC name can now be easily customised by replacing 2nd argument in the function call at the bottom of npc/custom/etc/costume.txt
  • NPC checks whether the user already has the same item being restored equipped or in inventory and will prevent restoring.
  • Fixed/tweaked some typos and grammar for the NPC dialogue and atcommand messages.
  • costume.txt has been included inside the diff

Screenshot

screenChocobotRO010.thumb.jpg.a0ff6db06ffca4f21dbed55d3e6b69b9.jpg

Costume_System_v2.diff 14.63 kB · 27 downloads

Edit: I actually just discovered that the wonderful secretdataz had already updated the diff to work with newer versions of rAthena here (https://github.com/secretdataz/rathena/pull/8/files). The main differences to my edit is secret's also handles costuming garments and there is atcommand documentation. The diff I have uploaded comes with an updated NPC script.

Hi latios,

I failed to upload the "Costume System v2.diff", would you please guide me the step??

Thanks!

Link to comment
Share on other sites

@ahloi007 Ah apologies, I think I've made a mistake in the uploaded diff. I'll post a fixed version soon, one that works when you run: git apply "Costume System v2.diff"

Edited by latios
Link to comment
Share on other sites

1 minute ago, latios said:

@ahloi007 There is this StackOverflow answer but I believe there is also nice short video example here: 

But I recommend learning about what a "diff" is and how they work:

Yes...!! thats just awesome! thanks 

Link to comment
Share on other sites

Apologies, I may not be able to fix it such that it works with "git apply" for some time. It will have to be a manual process for now. /sry

Link to comment
Share on other sites

14 hours ago, Jholz27 said:

whats wrong with this one?

image.png.6a149e7c1dc86670f55e3e5bfc56a00b.png

You need to apply the diff, to make it work. It basically says that costume is not a command or is not present in your files.

Link to comment
Share on other sites

@latios  , I've got this error what should I do? 

Quote

pc.cpp: In function 'void pc_delautobonus(map_session_data*, std::vector<s_autobonus>&, bool)':
pc.cpp:2705:10: error: 'j' was not declared in this scope
      for(j = 0; j < EQI_MAX_BONUS; j++) {
          ^
pc.cpp:2705:21: error: 'EQI_MAX_BONUS' was not declared in this scope
      for(j = 0; j < EQI_MAX_BONUS; j++) {
                     ^
make[1]: *** [obj/pc.o] Error 1
 

 

Link to comment
Share on other sites

@ahloi007 The first issue is saying that "j" hasn't been defined on line 2705 in file pc.cpp. You'll want to look around the code there and try to figure out why the definition (e.g. "int j;") is missing. For example, in this part of the diff there is an "int j;" at the top, but isn't there for some reason in your code.

@@ -2627,7 +2638,7 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector<s_autobonus> *bonu
 		int j;
 		unsigned int equip_pos_idx = 0;
 		//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-		for(j = 0; j < EQI_MAX; j++) {
+		for(j = 0; j < EQI_MAX_BONUS; j++) {
 			if(sd->equip_index[j] >= 0)
 				equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
 		}

The second issue is saying that the constant "EQI_MAX_BONUS" isn't found anywhere in the pc.cpp or pc.hpp files. In the diff, there is a section which indicates it should be added to pc.hpp. You'll want to check if it's there and if it is, figure out why it might not be found in pc.cpp. Here is the part of the diff where it gets added:

diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index b52784b..23d1a85 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -84,7 +84,8 @@ enum equip_index {
 	EQI_SHADOW_SHOES,
 	EQI_SHADOW_ACC_R,
 	EQI_SHADOW_ACC_L,
-	EQI_MAX
+	EQI_MAX,
+	EQI_MAX_BONUS = 10
 };

 

Link to comment
Share on other sites

26 minutes ago, latios said:

@ahloi007 The first issue is saying that "j" hasn't been defined on line 2705 in file pc.cpp. You'll want to look around the code there and try to figure out why the definition (e.g. "int j;") is missing. For example, in this part of the diff there is an "int j;" at the top, but isn't there for some reason in your code.

@@ -2627,7 +2638,7 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector<s_autobonus> *bonu
 		int j;
 		unsigned int equip_pos_idx = 0;
 		//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-		for(j = 0; j < EQI_MAX; j++) {
+		for(j = 0; j < EQI_MAX_BONUS; j++) {
 			if(sd->equip_index[j] >= 0)
 				equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
 		}

The second issue is saying that the constant "EQI_MAX_BONUS" isn't found anywhere in the pc.cpp or pc.hpp files. In the diff, there is a section which indicates it should be added to pc.hpp. You'll want to check if it's there and if it is, figure out why it might not be found in pc.cpp. Here is the part of the diff where it gets added:

diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index b52784b..23d1a85 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -84,7 +84,8 @@ enum equip_index {
 	EQI_SHADOW_SHOES,
 	EQI_SHADOW_ACC_R,
 	EQI_SHADOW_ACC_L,
-	EQI_MAX
+	EQI_MAX,
+	EQI_MAX_BONUS = 10
 };

 

Okay thanks ! its working!

Link to comment
Share on other sites

On 9/3/2020 at 9:40 AM, Jaodegwapo said:

image.png.086ace4a78191cb829a7ada721afad57.png

 

 

 

can you help me with this error sir?

 

On 11/11/2020 at 5:22 AM, jawbreaker said:

is it possible to deduct headgear weight when it becomes costume?

Better use this version.

 

Link to comment
Share on other sites

Hey im trying to apply the diff. But i get this error

 

~/rAthena$ git apply Costume_System_v2.diff
Costume_System_v2.diff:152: new blank line at EOF.
+
error: patch failed: npc/scripts_custom.conf:115
error: npc/scripts_custom.conf: patch does not apply
Costume_System_v2.diff:225: new blank line at EOF.
+
error: patch failed: src/map/status.cpp:3805
error: src/map/status.cpp: patch does not apply

 

Using the v2

Link to comment
Share on other sites

On 3/23/2020 at 1:12 AM, latios said:

Hi all,

I've taken the time to update this script and tested it on my server running latest version of rAthena (version at the time of writing Git Hash: f8d5d45).

Additional Changes

  • NPC name can now be easily customised by replacing 2nd argument in the function call at the bottom of npc/custom/etc/costume.txt
  • NPC checks whether the user already has the same item being restored equipped or in inventory and will prevent restoring.
  • Fixed/tweaked some typos and grammar for the NPC dialogue and atcommand messages.
  • costume.txt has been included inside the diff

Screenshot

screenChocobotRO010.thumb.jpg.a0ff6db06ffca4f21dbed55d3e6b69b9.jpg

Costume_System_v2.diff 14.63 kB · 148 downloads

Edit: I actually just discovered that the wonderful secretdataz had already updated the diff to work with newer versions of rAthena here (https://github.com/secretdataz/rathena/pull/8/files). The main differences to my edit is secret's also handles costuming garments and there is atcommand documentation. The diff I have uploaded comes with an updated NPC script.

 

when converting an item with item_combo_db script the effect will remain

Link to comment
Share on other sites

Updated for latest git.
 


diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf
index 93fe9db..0e741ad 100644
--- a/conf/battle/battle.conf
+++ b/conf/battle/battle.conf
@@ -167,3 +167,6 @@ warg_can_falcon: no
 // Should the target be able of dodging damage by snapping away to the edge of the screen?
 // Official behavior is "no"
 snap_dodge: no
+
+// Reserved Char ID for costume converted items.
+reserved_costume_id: 999998
diff --git a/npc/custom/etc/costume.txt b/npc/custom/etc/costume.txt
new file mode 100644
index 0000000..bf3772c
--- /dev/null
+++ b/npc/custom/etc/costume.txt
@@ -0,0 +1,135 @@
+// -------------------------------------------------------------------------------
+//     Script Name : Headgear to Costume converter >> Costume to Headgear converter
+// -------------------------------------------------------------------------------
+// Description :
+// - Allows a user to convert the equipped headgear (on Top, Mid or Low) into a
+//   costume item. It will remove any card and refine of the Item.
+// - Allows a user to restore the equipped costume headgear (on Top, Mid or Low)
+//   into its original form. It will not return any card or refine of the item.
+// -------------------------------------------------------------------------------
+function    script    costume    {
+    [email protected]_name$ = getarg(0);
+    disable_items;
+    mes "["+ [email protected]_name$ +"]";
+    mes "Here you can convert your headgears into a Costume Headgear or restore to its Original form.";
+    next;
+
+    switch(select("I want to convert.:I want to restore.:No thanks.")) {
+    case 1:
+        setarray [email protected][1], EQI_HEAD_TOP, EQI_HEAD_MID, EQI_HEAD_LOW;
+        for ([email protected] = 1; [email protected]<=3; [email protected]) {
+            if (getequipisequiped([email protected][[email protected]])) {
+                [email protected]$ = [email protected]$ + F_getpositionname([email protected][[email protected]]) + "-[" + getequipname([email protected][[email protected]]) + "]";
+                [email protected] = 1;
+            }
+            [email protected]$ = [email protected]$ + ":";
+        }
+
+        if ([email protected] == 0) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You need to wear headgears that I can costume...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Please select what to convert.";
+        mes "Remember, cards and refine will be removed.";
+        next;
+
+        [email protected] = [email protected][ select([email protected]$) ];
+        if (!getequipisequiped([email protected])) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're not wearing anything there...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "You want to Costume your " + getitemname(getequipid([email protected])) + "?";
+        next;
+
+        if (select("Yes, proceed:No, sorry.") == 2) {
+            mes "["+ [email protected]_name$ + "]";
+            mes "Need some time to think about it, huh?";
+            mes "Alright, I can understand.";
+            close;
+        }
+
+        costume [email protected]; // Convert the Headgear
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Done, enjoy your costume headgear.";
+        close;
+    case 2:
+        setarray [email protected][1], EQI_COSTUME_HEAD_TOP, EQI_COSTUME_HEAD_MID, EQI_COSTUME_HEAD_LOW;
+        for ([email protected] = 1; [email protected]<=3; [email protected]) {
+            if (getequipisequiped([email protected][[email protected]])) {
+                [email protected]$ = [email protected]$ + F_getpositionname([email protected]$[[email protected]]) + "-[" + getequipname([email protected][[email protected]]) + "]";
+                [email protected] = 1;
+            }
+            [email protected]$ = [email protected]$ + ":";
+        }
+
+        if ([email protected] == 0) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You need to wear costumed headgears that I can restore...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Please select what to restore.";
+        mes "Remember, I will only restore it back without refine and cards.";
+        next;
+
+        [email protected] = [email protected][ select([email protected]$) ];
+        if (!getequipisequiped([email protected])) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're not wearing anything there...";
+            close;
+        }
+
+        if (isequippedcnt(getequipid([email protected])) > 1) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're wearing too many of the same headgear!";
+            mes "How am I supposed to know which one to restore?";
+            mes "See me when you have one equipped.";
+            close;
+        }
+
+        if (countitem(getequipid([email protected])) > 1) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You have another " + getitemname(getequipid([email protected])) + " with you.";
+            mes "Put it away before restoring.";
+            close;
+        }
+
+        mes "[" + [email protected]_name$ + "]";
+        mes "You want to restore your " + getitemname(getequipid([email protected])) + "?";
+        next;
+
+        if (select("Yes, proceed:No, sorry.") == 2) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "Need some time to think about it, huh?";
+            mes "Alright, I can understand.";
+            close;
+        }
+
+        // Restore headgear by recreating
+        a = getequipid([email protected]);
+        delitem a,1;
+        getitem a,1;
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Done, enjoy your restored headgear.";
+        close;
+    case 3:
+        mes "["+ [email protected]_name$ +"]";
+        mes "Very well. Return at once if you seek my services.";
+        close;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// Add more lines to put your npc on different cities (adjust name if desired)
+// ---------------------------------------------------------------------------
+prontera,144,230,6    script    Costume Clown#1    715,{ callfunc "costume","Costume Clown",0; end; }
+
diff --git a/npc/scripts_custom.conf b/npc/scripts_custom.conf
index 1adf1f3..d4e5706 100644
--- a/npc/scripts_custom.conf
+++ b/npc/scripts_custom.conf
@@ -115,6 +115,8 @@ npc: npc/custom/etc/quest_warper.txt
 // -- Custom quests from official Umbalian Quests
 //npc: npc/custom/quests/sphinx_mask.txt
 //npc: npc/custom/quests/umbalian_language.txt
+// -- Costume NPC script (from rAthena)
+npc: npc/custom/etc/costume.txt
 
 // --------------------- ChocobotRO Scripts --------------------
 // -- Peak NPC script (from FluxCP)
diff --git a/src/custom/atcommand_def.inc b/src/custom/atcommand_def.inc
index 54d9e74..d9b8b2d 100644
--- a/src/custom/atcommand_def.inc
+++ b/src/custom/atcommand_def.inc
@@ -9,3 +9,6 @@
  **/
 
 //ACMD_DEF(newcommand),
+
+// @costumeitem <item>
+ACMD_DEF2("costumeitem", item),
diff --git a/src/custom/script.inc b/src/custom/script.inc
index 839b990..776120e 100644
--- a/src/custom/script.inc
+++ b/src/custom/script.inc
@@ -17,3 +17,44 @@
 //    script_pushint(st,1);
 //    return 0;
 //}
+
+/*==========================================
+ * Costume Items
+ *------------------------------------------*/
+BUILDIN_FUNC(costume)
+{
+    int i = -1, num, ep;
+    TBL_PC *sd;
+    item* item;
+    num = script_getnum(st, 2); // Equip Slot
+    if (!script_rid2sd(sd))
+        return 0;
+    if (equip_index_check(num))
+        i = pc_checkequip(sd, equip_bitmask[num]);
+    if (i < 0)
+        return 0;
+    item = &sd->inventory.u.items_inventory[i];
+    ep = item->equip;
+    if (!(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP))
+        return 0;
+    log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, item);
+    pc_unequipitem(sd, i, 2);
+    clif_delitem(sd, i, 1, 3);
+    // --------------------------------------------------------------------
+    item->refine = 0;
+    item->attribute = 0;
+    item->card[0] = CARD0_CREATE;
+    item->card[1] = 0;
+    item->card[2] = GetWord(battle_config.reserved_costume_id, 0);
+    item->card[3] = GetWord(battle_config.reserved_costume_id, 1);
+    if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
+    if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
+    if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
+    // --------------------------------------------------------------------
+    log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, item);
+    clif_additem(sd, i, 1, 0);
+    pc_equipitem(sd, i, ep);
+    clif_misceffect(&sd->bl, 3);
+    return 0;
+}
+
diff --git a/src/custom/script_def.inc b/src/custom/script_def.inc
index 8863992..917ffea 100644
--- a/src/custom/script_def.inc
+++ b/src/custom/script_def.inc
@@ -9,3 +9,6 @@
  **/
 
 //BUILDIN_DEF(example,""),
+
+// Costume System
+BUILDIN_DEF(costume,"i"),
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index 266f375..8e9f8af 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -1343,7 +1343,7 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
 ACMD_FUNC(item)
 {
     char item_name[100];
-    int number = 0, bound = BOUND_NONE;
+    int number = 0, bound = BOUND_NONE, costume = 0;
     char flag = 0;
     struct item item_tmp;
     struct item_data *item_data[10];
@@ -1382,6 +1382,26 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
             clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
             return -1;
         }
+
+        // Start costume conversion logic (1)
+        if(!strcmpi(command+1, "costumeitem")) {
+            if(!battle_config.reserved_costume_id) {
+                clif_displaymessage(fd, "Costume conversion is disabled. Set a value for reserved_costume_id in your battle.conf file.");
+                return -1;
+            }
+            if(!(item.get()->equip&EQP_HEAD_LOW) &&
+                !(item.get()->equip&EQP_HEAD_MID) &&
+                !(item.get()->equip&EQP_HEAD_TOP) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_LOW) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_MID) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_TOP)) {
+                clif_displaymessage(fd, "You cannot costume this item. Costumes only work for headgears.");
+                return -1;
+            }
+            costume = 1;
+
+        }
+        // End costume conversion logic (1)
+
         itemlist = strtok(NULL, ":"); //next itemline
         j++;
     }
@@ -1403,6 +1423,15 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
                 item_tmp.nameid = item_id;
                 item_tmp.identify = 1;
                 item_tmp.bound = bound;
+
+                // Start costume conversion logic (2)
+                if(costume == 1) {
+                    item_tmp.card[0] = CARD0_CREATE;
+                    item_tmp.card[2] = GetWord(battle_config.reserved_costume_id, 0);
+                    item_tmp.card[3] = GetWord(battle_config.reserved_costume_id, 1);
+                }
+                // End costume conversion logic (2)
+
                 if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
                     clif_additem(sd, 0, 0, flag);
             }
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index 684c833..88a691b 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -8635,6 +8635,7 @@ bool battle_check_range(struct block_list *src, struct block_list *bl, int range
     { "item_enabled_npc",                   &battle_config.item_enabled_npc,                1,      0,      1,              },
     { "item_flooritem_check",               &battle_config.item_onfloor,                    1,      0,      1,              },
     { "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
+    { "reserved_costume_id",                &battle_config.reserved_costume_id,             999998, 0,      INT_MAX,        },
     { "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
     { "feature.auction",                    &battle_config.feature_auction,                 0,      0,      2,              },
     { "feature.banking",                    &battle_config.feature_banking,                 1,      0,      1,              },
diff --git a/src/map/battle.hpp b/src/map/battle.hpp
index c26efe3..58ffded 100644
--- a/src/map/battle.hpp
+++ b/src/map/battle.hpp
@@ -544,6 +544,7 @@ struct Battle_Config
     int item_enabled_npc;
     int item_onfloor; // Whether to drop an undroppable item on the map or destroy it if inventory is full.
     int bowling_bash_area;
+    int reserved_costume_id; // Costume System
     int drop_rateincrease;
     int feature_auction;
     int feature_banking;
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 0aee3ce..1cb4df2 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -1950,6 +1950,14 @@ void map_reqnickdb(struct map_session_data * sd, int charid)
 
     nullpo_retv(sd);
 
+    // Start costume conversion logic (3)
+    if( battle_config.reserved_costume_id && battle_config.reserved_costume_id == charid )
+    {
+        clif_solved_charname(sd->fd, charid, "Costume");
+        return;
+    }
+    // End costume conversion logic (3)
+
     tsd = map_charid2sd(charid);
     if( tsd )
     {
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 658984b..2b2a8cf 100755
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -870,7 +870,18 @@ int pc_equippoint_sub(struct map_session_data *sd,struct item_data* id){
 int pc_equippoint(struct map_session_data *sd,int n){
     nullpo_ret(sd);
 
-    return pc_equippoint_sub(sd,sd->inventory_data[n]);
+    // Start costume conversion logic (4)
+    int ep = pc_equippoint_sub(sd,sd->inventory_data[n]);
+    int char_id = 0;
+    if (battle_config.reserved_costume_id &&
+        sd->inventory.u.items_inventory[n].card[0] == CARD0_CREATE &&
+        (char_id = MakeDWord(sd->inventory.u.items_inventory[n].card[2],sd->inventory.u.items_inventory[n].card[3])) == battle_config.reserved_costume_id) {
+        if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
+        if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
+        if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
+    }
+    return ep;
+    // End costume conversion logic (4)
 }
 
 /**
@@ -2582,7 +2593,7 @@ void pc_delautobonus(struct map_session_data* sd, std::vector<s_autobonus> &bonu
                     unsigned int equip_pos_idx = 0;
 
                     // Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-                    for (uint8 j = 0; j < EQI_MAX; j++) {
+                    for (uint8 j = 0; j < EQI_MAX_BONUS; j++) {
                         if (sd->equip_index[j] >= 0)
                             equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
                     }
@@ -2627,7 +2638,7 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector<s_autobonus> *bonu
         int j;
         unsigned int equip_pos_idx = 0;
         //Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-        for(j = 0; j < EQI_MAX; j++) {
+        for(j = 0; j < EQI_MAX_BONUS; j++) {
             if(sd->equip_index[j] >= 0)
                 equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
         }
@@ -10126,7 +10137,7 @@ int pc_load_combo(struct map_session_data *sd) {
  *------------------------------------------*/
 bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswitch)
 {
-    int i, pos, flag = 0, iflag;
+    int i, pos, flag = 0, iflag, char_id = 0;
     struct item_data *id;
     uint8 res = ITEM_EQUIP_ACK_OK;
     short* equip_index;
diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index b52784b..23d1a85 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -84,7 +84,8 @@ enum equip_index {
     EQI_SHADOW_SHOES,
     EQI_SHADOW_ACC_R,
     EQI_SHADOW_ACC_L,
-    EQI_MAX
+    EQI_MAX,
+    EQI_MAX_BONUS = 10
 };
 
 enum prevent_logout_trigger {
diff --git a/src/map/status.cpp b/src/map/status.cpp
index 09317fd..bd3699b 100644
--- a/src/map/status.cpp
+++ b/src/map/status.cpp
@@ -3805,7 +3805,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)
     running_npc_stat_calc_event = false;
 
     // Parse equipment
-    for (i = 0; i < EQI_MAX; i++) {
+    for (i = 0; i < EQI_MAX_BONUS; i++) {
         current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
         current_equip_combo_pos = 0;
         if (index < 0)

 

Link to comment
Share on other sites

23 hours ago, mhielo12 said:

Updated for latest git.
 


diff --git a/conf/battle/battle.conf b/conf/battle/battle.conf
index 93fe9db..0e741ad 100644
--- a/conf/battle/battle.conf
+++ b/conf/battle/battle.conf
@@ -167,3 +167,6 @@ warg_can_falcon: no
 // Should the target be able of dodging damage by snapping away to the edge of the screen?
 // Official behavior is "no"
 snap_dodge: no
+
+// Reserved Char ID for costume converted items.
+reserved_costume_id: 999998
diff --git a/npc/custom/etc/costume.txt b/npc/custom/etc/costume.txt
new file mode 100644
index 0000000..bf3772c
--- /dev/null
+++ b/npc/custom/etc/costume.txt
@@ -0,0 +1,135 @@
+// -------------------------------------------------------------------------------
+//     Script Name : Headgear to Costume converter >> Costume to Headgear converter
+// -------------------------------------------------------------------------------
+// Description :
+// - Allows a user to convert the equipped headgear (on Top, Mid or Low) into a
+//   costume item. It will remove any card and refine of the Item.
+// - Allows a user to restore the equipped costume headgear (on Top, Mid or Low)
+//   into its original form. It will not return any card or refine of the item.
+// -------------------------------------------------------------------------------
+function    script    costume    {
+    [email protected]_name$ = getarg(0);
+    disable_items;
+    mes "["+ [email protected]_name$ +"]";
+    mes "Here you can convert your headgears into a Costume Headgear or restore to its Original form.";
+    next;
+
+    switch(select("I want to convert.:I want to restore.:No thanks.")) {
+    case 1:
+        setarray [email protected][1], EQI_HEAD_TOP, EQI_HEAD_MID, EQI_HEAD_LOW;
+        for ([email protected] = 1; [email protected]<=3; [email protected]) {
+            if (getequipisequiped([email protected][[email protected]])) {
+                [email protected]$ = [email protected]$ + F_getpositionname([email protected][[email protected]]) + "-[" + getequipname([email protected][[email protected]]) + "]";
+                [email protected] = 1;
+            }
+            [email protected]$ = [email protected]$ + ":";
+        }
+
+        if ([email protected] == 0) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You need to wear headgears that I can costume...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Please select what to convert.";
+        mes "Remember, cards and refine will be removed.";
+        next;
+
+        [email protected] = [email protected][ select([email protected]$) ];
+        if (!getequipisequiped([email protected])) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're not wearing anything there...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "You want to Costume your " + getitemname(getequipid([email protected])) + "?";
+        next;
+
+        if (select("Yes, proceed:No, sorry.") == 2) {
+            mes "["+ [email protected]_name$ + "]";
+            mes "Need some time to think about it, huh?";
+            mes "Alright, I can understand.";
+            close;
+        }
+
+        costume [email protected]; // Convert the Headgear
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Done, enjoy your costume headgear.";
+        close;
+    case 2:
+        setarray [email protected][1], EQI_COSTUME_HEAD_TOP, EQI_COSTUME_HEAD_MID, EQI_COSTUME_HEAD_LOW;
+        for ([email protected] = 1; [email protected]<=3; [email protected]) {
+            if (getequipisequiped([email protected][[email protected]])) {
+                [email protected]$ = [email protected]$ + F_getpositionname([email protected]$[[email protected]]) + "-[" + getequipname([email protected][[email protected]]) + "]";
+                [email protected] = 1;
+            }
+            [email protected]$ = [email protected]$ + ":";
+        }
+
+        if ([email protected] == 0) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You need to wear costumed headgears that I can restore...";
+            close;
+        }
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Please select what to restore.";
+        mes "Remember, I will only restore it back without refine and cards.";
+        next;
+
+        [email protected] = [email protected][ select([email protected]$) ];
+        if (!getequipisequiped([email protected])) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're not wearing anything there...";
+            close;
+        }
+
+        if (isequippedcnt(getequipid([email protected])) > 1) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You're wearing too many of the same headgear!";
+            mes "How am I supposed to know which one to restore?";
+            mes "See me when you have one equipped.";
+            close;
+        }
+
+        if (countitem(getequipid([email protected])) > 1) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "You have another " + getitemname(getequipid([email protected])) + " with you.";
+            mes "Put it away before restoring.";
+            close;
+        }
+
+        mes "[" + [email protected]_name$ + "]";
+        mes "You want to restore your " + getitemname(getequipid([email protected])) + "?";
+        next;
+
+        if (select("Yes, proceed:No, sorry.") == 2) {
+            mes "["+ [email protected]_name$ +"]";
+            mes "Need some time to think about it, huh?";
+            mes "Alright, I can understand.";
+            close;
+        }
+
+        // Restore headgear by recreating
+        a = getequipid([email protected]);
+        delitem a,1;
+        getitem a,1;
+
+        mes "["+ [email protected]_name$ +"]";
+        mes "Done, enjoy your restored headgear.";
+        close;
+    case 3:
+        mes "["+ [email protected]_name$ +"]";
+        mes "Very well. Return at once if you seek my services.";
+        close;
+    }
+}
+
+// ---------------------------------------------------------------------------
+// Add more lines to put your npc on different cities (adjust name if desired)
+// ---------------------------------------------------------------------------
+prontera,144,230,6    script    Costume Clown#1    715,{ callfunc "costume","Costume Clown",0; end; }
+
diff --git a/npc/scripts_custom.conf b/npc/scripts_custom.conf
index 1adf1f3..d4e5706 100644
--- a/npc/scripts_custom.conf
+++ b/npc/scripts_custom.conf
@@ -115,6 +115,8 @@ npc: npc/custom/etc/quest_warper.txt
 // -- Custom quests from official Umbalian Quests
 //npc: npc/custom/quests/sphinx_mask.txt
 //npc: npc/custom/quests/umbalian_language.txt
+// -- Costume NPC script (from rAthena)
+npc: npc/custom/etc/costume.txt
 
 // --------------------- ChocobotRO Scripts --------------------
 // -- Peak NPC script (from FluxCP)
diff --git a/src/custom/atcommand_def.inc b/src/custom/atcommand_def.inc
index 54d9e74..d9b8b2d 100644
--- a/src/custom/atcommand_def.inc
+++ b/src/custom/atcommand_def.inc
@@ -9,3 +9,6 @@
  **/
 
 //ACMD_DEF(newcommand),
+
+// @costumeitem <item>
+ACMD_DEF2("costumeitem", item),
diff --git a/src/custom/script.inc b/src/custom/script.inc
index 839b990..776120e 100644
--- a/src/custom/script.inc
+++ b/src/custom/script.inc
@@ -17,3 +17,44 @@
 //    script_pushint(st,1);
 //    return 0;
 //}
+
+/*==========================================
+ * Costume Items
+ *------------------------------------------*/
+BUILDIN_FUNC(costume)
+{
+    int i = -1, num, ep;
+    TBL_PC *sd;
+    item* item;
+    num = script_getnum(st, 2); // Equip Slot
+    if (!script_rid2sd(sd))
+        return 0;
+    if (equip_index_check(num))
+        i = pc_checkequip(sd, equip_bitmask[num]);
+    if (i < 0)
+        return 0;
+    item = &sd->inventory.u.items_inventory[i];
+    ep = item->equip;
+    if (!(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP))
+        return 0;
+    log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, item);
+    pc_unequipitem(sd, i, 2);
+    clif_delitem(sd, i, 1, 3);
+    // --------------------------------------------------------------------
+    item->refine = 0;
+    item->attribute = 0;
+    item->card[0] = CARD0_CREATE;
+    item->card[1] = 0;
+    item->card[2] = GetWord(battle_config.reserved_costume_id, 0);
+    item->card[3] = GetWord(battle_config.reserved_costume_id, 1);
+    if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
+    if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
+    if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
+    // --------------------------------------------------------------------
+    log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, item);
+    clif_additem(sd, i, 1, 0);
+    pc_equipitem(sd, i, ep);
+    clif_misceffect(&sd->bl, 3);
+    return 0;
+}
+
diff --git a/src/custom/script_def.inc b/src/custom/script_def.inc
index 8863992..917ffea 100644
--- a/src/custom/script_def.inc
+++ b/src/custom/script_def.inc
@@ -9,3 +9,6 @@
  **/
 
 //BUILDIN_DEF(example,""),
+
+// Costume System
+BUILDIN_DEF(costume,"i"),
diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp
index 266f375..8e9f8af 100644
--- a/src/map/atcommand.cpp
+++ b/src/map/atcommand.cpp
@@ -1343,7 +1343,7 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
 ACMD_FUNC(item)
 {
     char item_name[100];
-    int number = 0, bound = BOUND_NONE;
+    int number = 0, bound = BOUND_NONE, costume = 0;
     char flag = 0;
     struct item item_tmp;
     struct item_data *item_data[10];
@@ -1382,6 +1382,26 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
             clif_displaymessage(fd, msg_txt(sd,19)); // Invalid item ID or name.
             return -1;
         }
+
+        // Start costume conversion logic (1)
+        if(!strcmpi(command+1, "costumeitem")) {
+            if(!battle_config.reserved_costume_id) {
+                clif_displaymessage(fd, "Costume conversion is disabled. Set a value for reserved_costume_id in your battle.conf file.");
+                return -1;
+            }
+            if(!(item.get()->equip&EQP_HEAD_LOW) &&
+                !(item.get()->equip&EQP_HEAD_MID) &&
+                !(item.get()->equip&EQP_HEAD_TOP) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_LOW) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_MID) &&
+                !(item.get()->equip&EQP_COSTUME_HEAD_TOP)) {
+                clif_displaymessage(fd, "You cannot costume this item. Costumes only work for headgears.");
+                return -1;
+            }
+            costume = 1;
+
+        }
+        // End costume conversion logic (1)
+
         itemlist = strtok(NULL, ":"); //next itemline
         j++;
     }
@@ -1403,6 +1423,15 @@ static void warp_get_suggestions(struct map_session_data* sd, const char *name)
                 item_tmp.nameid = item_id;
                 item_tmp.identify = 1;
                 item_tmp.bound = bound;
+
+                // Start costume conversion logic (2)
+                if(costume == 1) {
+                    item_tmp.card[0] = CARD0_CREATE;
+                    item_tmp.card[2] = GetWord(battle_config.reserved_costume_id, 0);
+                    item_tmp.card[3] = GetWord(battle_config.reserved_costume_id, 1);
+                }
+                // End costume conversion logic (2)
+
                 if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
                     clif_additem(sd, 0, 0, flag);
             }
diff --git a/src/map/battle.cpp b/src/map/battle.cpp
index 684c833..88a691b 100644
--- a/src/map/battle.cpp
+++ b/src/map/battle.cpp
@@ -8635,6 +8635,7 @@ bool battle_check_range(struct block_list *src, struct block_list *bl, int range
     { "item_enabled_npc",                   &battle_config.item_enabled_npc,                1,      0,      1,              },
     { "item_flooritem_check",               &battle_config.item_onfloor,                    1,      0,      1,              },
     { "bowling_bash_area",                  &battle_config.bowling_bash_area,               0,      0,      20,             },
+    { "reserved_costume_id",                &battle_config.reserved_costume_id,             999998, 0,      INT_MAX,        },
     { "drop_rateincrease",                  &battle_config.drop_rateincrease,               0,      0,      1,              },
     { "feature.auction",                    &battle_config.feature_auction,                 0,      0,      2,              },
     { "feature.banking",                    &battle_config.feature_banking,                 1,      0,      1,              },
diff --git a/src/map/battle.hpp b/src/map/battle.hpp
index c26efe3..58ffded 100644
--- a/src/map/battle.hpp
+++ b/src/map/battle.hpp
@@ -544,6 +544,7 @@ struct Battle_Config
     int item_enabled_npc;
     int item_onfloor; // Whether to drop an undroppable item on the map or destroy it if inventory is full.
     int bowling_bash_area;
+    int reserved_costume_id; // Costume System
     int drop_rateincrease;
     int feature_auction;
     int feature_banking;
diff --git a/src/map/map.cpp b/src/map/map.cpp
index 0aee3ce..1cb4df2 100644
--- a/src/map/map.cpp
+++ b/src/map/map.cpp
@@ -1950,6 +1950,14 @@ void map_reqnickdb(struct map_session_data * sd, int charid)
 
     nullpo_retv(sd);
 
+    // Start costume conversion logic (3)
+    if( battle_config.reserved_costume_id && battle_config.reserved_costume_id == charid )
+    {
+        clif_solved_charname(sd->fd, charid, "Costume");
+        return;
+    }
+    // End costume conversion logic (3)
+
     tsd = map_charid2sd(charid);
     if( tsd )
     {
diff --git a/src/map/pc.cpp b/src/map/pc.cpp
index 658984b..2b2a8cf 100755
--- a/src/map/pc.cpp
+++ b/src/map/pc.cpp
@@ -870,7 +870,18 @@ int pc_equippoint_sub(struct map_session_data *sd,struct item_data* id){
 int pc_equippoint(struct map_session_data *sd,int n){
     nullpo_ret(sd);
 
-    return pc_equippoint_sub(sd,sd->inventory_data[n]);
+    // Start costume conversion logic (4)
+    int ep = pc_equippoint_sub(sd,sd->inventory_data[n]);
+    int char_id = 0;
+    if (battle_config.reserved_costume_id &&
+        sd->inventory.u.items_inventory[n].card[0] == CARD0_CREATE &&
+        (char_id = MakeDWord(sd->inventory.u.items_inventory[n].card[2],sd->inventory.u.items_inventory[n].card[3])) == battle_config.reserved_costume_id) {
+        if (ep&EQP_HEAD_TOP) { ep &= ~EQP_HEAD_TOP; ep |= EQP_COSTUME_HEAD_TOP; }
+        if (ep&EQP_HEAD_LOW) { ep &= ~EQP_HEAD_LOW; ep |= EQP_COSTUME_HEAD_LOW; }
+        if (ep&EQP_HEAD_MID) { ep &= ~EQP_HEAD_MID; ep |= EQP_COSTUME_HEAD_MID; }
+    }
+    return ep;
+    // End costume conversion logic (4)
 }
 
 /**
@@ -2582,7 +2593,7 @@ void pc_delautobonus(struct map_session_data* sd, std::vector<s_autobonus> &bonu
                     unsigned int equip_pos_idx = 0;
 
                     // Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-                    for (uint8 j = 0; j < EQI_MAX; j++) {
+                    for (uint8 j = 0; j < EQI_MAX_BONUS; j++) {
                         if (sd->equip_index[j] >= 0)
                             equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
                     }
@@ -2627,7 +2638,7 @@ void pc_exeautobonus(struct map_session_data *sd, std::vector<s_autobonus> *bonu
         int j;
         unsigned int equip_pos_idx = 0;
         //Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
-        for(j = 0; j < EQI_MAX; j++) {
+        for(j = 0; j < EQI_MAX_BONUS; j++) {
             if(sd->equip_index[j] >= 0)
                 equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
         }
@@ -10126,7 +10137,7 @@ int pc_load_combo(struct map_session_data *sd) {
  *------------------------------------------*/
 bool pc_equipitem(struct map_session_data *sd,short n,int req_pos,bool equipswitch)
 {
-    int i, pos, flag = 0, iflag;
+    int i, pos, flag = 0, iflag, char_id = 0;
     struct item_data *id;
     uint8 res = ITEM_EQUIP_ACK_OK;
     short* equip_index;
diff --git a/src/map/pc.hpp b/src/map/pc.hpp
index b52784b..23d1a85 100644
--- a/src/map/pc.hpp
+++ b/src/map/pc.hpp
@@ -84,7 +84,8 @@ enum equip_index {
     EQI_SHADOW_SHOES,
     EQI_SHADOW_ACC_R,
     EQI_SHADOW_ACC_L,
-    EQI_MAX
+    EQI_MAX,
+    EQI_MAX_BONUS = 10
 };
 
 enum prevent_logout_trigger {
diff --git a/src/map/status.cpp b/src/map/status.cpp
index 09317fd..bd3699b 100644
--- a/src/map/status.cpp
+++ b/src/map/status.cpp
@@ -3805,7 +3805,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)
     running_npc_stat_calc_event = false;
 
     // Parse equipment
-    for (i = 0; i < EQI_MAX; i++) {
+    for (i = 0; i < EQI_MAX_BONUS; i++) {
         current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
         current_equip_combo_pos = 0;
         if (index < 0)

 

I can see a problem in the code without testing it

not sure if there is more , will leave it for you to test

Edited by sader1992
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use and Privacy Policy.