Someone on my server asked for this, and I saw that many people had been using an old script that doesn't work anymore, so I made a new one.
If playing PRE-RE, you need to pull RE's costume headgears into your PRE-RE item database first. Open re's item-db and search for 19500, and copy all the items from there until 20499 into pre-re's item database, under costume system.
This script also requires code changes to a few files, but they are purely additions, nothing needs to be changed.
In script.cpp
Near all of the other defs, you need this line:
BUILDIN_DEF(getcostumeid,"i?"),
You also need to add this function, anywhere in the class:
/*==========================================
* Returns the costume id associated with an equip slot, if one exists
* return costume id number or -1
* getcostumeid(<equipment slot>{,<char_id>})
*------------------------------------------*/
BUILDIN_FUNC(getcostumeid)
{
int i, num;
TBL_PC* sd;
struct item_data* item;
unsigned short returnid;
if (!script_charid2sd(3, sd)) {
script_pushint(st, -1);
return SCRIPT_CMD_FAILURE;
}
num = script_getnum(st, 2);
if (!equip_index_check(num))
{
script_pushint(st, -1);
return SCRIPT_CMD_SUCCESS;
}
// get inventory position of item
i = pc_checkequip(sd, equip_bitmask[num]);
if (i < 0)
{
script_pushint(st, -1);
return SCRIPT_CMD_SUCCESS;
}
item = sd->inventory_data[i];
if (item != 0) {
// search item db for an item with the same view id
returnid = itemdb_findmatchinglook(item);
script_pushint(st, returnid);
}
else
script_pushint(st, -1);
return SCRIPT_CMD_SUCCESS;
}
In itemdb.hpp:
Add this near all the other method declarations:
int itemdb_findmatchinglook(struct item_data* data);
In itemdb.cpp:
The solution you need here differs depending on the version of Rathena you have
If you have newest Rathena, add this in the class somewhere:
int itemdb_findmatchinglook(struct item_data* data) {
for (auto &tmp_item : item_db) {
std::shared_ptr<item_data> item = tmp_item.second;
if (item->look == data->look && item->nameid > 19432 && item->nameid < 20500 && item->nameid != data->nameid) {
return (int)item->nameid;
}
}
return -1;
}
If you have an older version, add this somewhere in the class instead.
static int itemdb_searchlook(DBKey key, DBData* data, va_list ap)
{
struct item_data* item = (struct item_data*)db_data2ptr(data), * tomatch, ** dst;
tomatch = va_arg(ap, struct item_data*);
dst = va_arg(ap, struct item_data**);
//We want items that have the same look but not the same id
if (dst != NULL && item->look == tomatch->look && item->nameid > 19432 && item->nameid < 20500 && item->nameid != tomatch->nameid)
*dst = item;
return 0;
}
int itemdb_findmatchinglook(struct item_data* data) {
struct item_data* item = NULL;
itemdb->foreach(itemdb, itemdb_searchlook, data, &item, NULL);
if (item) {
return (int)item->nameid;
}
else {
return -1;
}
}
Then just recompile and add the script to your npc folder and to script_athena.conf or any similar file.
//===== rAthena Script =======================================
//= Costume Trader NPC
//===== By: ==================================================
//= Tero
//===== Current Version: =====================================
//= 1.0
//===== Compatible With: =====================================
//= rAthena Project
//===== Description: =========================================
//= Can trade headgears for costumes.
//===== Additional Comments: =================================
//=
//============================================================
prontera,145,211,4 script Costume Trader#prt 612,{
mes "[Costume Trader]";
mes "I'm the costume trader.";
mes "I can trade your headgear for costume versions.";
mes "These items don't affect your stats, so you can wear other headgear with them.";
mes "Do you want to trade for a costume?";
next;
switch(select("Trade for a costume:Cancel")) {
case 1:
setarray .@indices[1], EQI_HEAD_TOP, EQI_HEAD_MID, EQI_HEAD_LOW;
for(.@i = 1; .@i<getarraysize(.@indices); ++.@i) {
if(getequipisequiped(.@indices[.@i])) {
.@menu$ = .@menu$ + F_getpositionname(.@indices[.@i]) + "-[" + getequipname(.@indices[.@i]) + "]";
.@equipped = 1;
}
.@menu$ = .@menu$ + ":";
}
if (.@equipped == 0) {
mes "[Costume Trader]";
mes "It doesn't seem you have anything you can trade.";
close;
}
mes "[Costume Trader]";
mes "Here's what you're wearing right now.";
next;
.@part = .@indices[select(.@menu$)];
.@baseitemid = getequipid(.@part);
.@costumeid = getcostumeid(.@part);
if (.@costumeid < 19433 || .@costumeid > 20499 ) {
mes "[Costume Trader]";
mes "Unfortunately, it doesn't seem like a costume exists for this item.";
mes "I guess you'll just have to keep wearing it.";
mes "I think it looks good on you at least.";
close;
}
mes "[Costume Trader]";
mes "A costume is available for that item.";
mes "If you trade, the costume will have no stats,";
mes "and any cards in it will be lost";
mes "Are you sure you want to trade?";
next;
switch(select("Do the trade!:Cancel")) {
case 1:
// anti-hack
if (callfunc("F_IsEquipIDHack", .@part, .@baseitemid)) {
mes "[Costume Trader]";
emotion ET_FRET;
mes "Wait a second...";
mes "Do you think I'm stupid?!";
mes "You switched the item while I wasn't looking! Get out of here!";
close;
}
delequip .@part;
getitem .@costumeid, 1;
mes "[Costume Trader]";
mes "Tada!";
mes "It's a shiny new costume item!";
mes "Aren't I amazing?";
mes "Come back again!";
close;
case 2:
mes "[Costume Trader]";
mes "That's too bad.";
mes "But I understand you might be attached to it.";
mes "Come back again.";
close;
}
case 2:
mes "[Costume Trader]";
mes "That's too bad.";
mes "Collect more cute headgear and come back.";
close;
}
}
Enjoy costumes!