I saw some people asking to make the costume converter compatible with 3ceam.
So i look upon it and just so happen to caught my interest even though i'm not fond
of costume system.
so without further ado!
Here's a patch i made for you guys.
EDIT:
V2 Fixed missing script.c dependencies
V3 Removed the relocation of ammo as informed by 15peaces that rytech moved it to the last for ammo-fix.
sorry, i was not aware about it.
3CEAM_COSTUME_CONVERTER_V3.patch
Index: conf/battle/battle.conf
===================================================================
--- conf/battle/battle.conf (revision 801)
+++ conf/battle/battle.conf (working copy)
@@ -171,3 +171,9 @@
// range. For example, Sonic Blow requires a 2 cell distance before autocasting is allowed.
// This setting also affects autospellwhenhit.
autospell_check_range: no
+
+// ****************************************
+// Reserved Costume ID's
+// ****************************************
+// Reserved Char ID for costume converted items.
+reserved_costume_id: 999998
\ No newline at end of file
Index: npc/custom/costume.txt
===================================================================
--- npc/custom/costume.txt (nonexistent)
+++ npc/custom/costume.txt (working copy)
@@ -0,0 +1,146 @@
+//===== Hercules Script ======================================
+//= Headgear to Costume converter >> Costume to Headgear converter
+//===== By: ==================================================
+//= Rebel, Zephyrus [rAthena]
+//= Mhalicot [Hercules]
+//===== Current Version: =====================================
+//= 1.1
+//===== Compatible With: =====================================
+//= Hercules
+//===== 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.
+//===== Additional Comments: =================================
+//= 1.0 Initial script [All of this script are credit to
+// Rebel, Zephyrus of [rAthena] and revised by [Mhalicot]
+// to make it compatible in Hercules.]
+//= 1.1 Denied if Headgear is rental, has refine,
+// or has card[Mhalicot]
+// Note: You must apply the patch in order to use this script
+//============================================================
+- script Costume Clown -1,{
+ mes "[Clown]";
+ mes "Here you can convert your headgears into a Costume Headgear or restore to its Original form.";
+ switch(select("I want to convert.:I want to restore.:No thanks.")) {
+ case 1:
+ next;
+ mes "[Clown]";
+ mes "Please, select what to convert.";
+ mes "Remember, cards and refine will be removed.";
+ next;
+ setarray .@Position$[1],"Top","Mid","Low";
+ setarray .@Position[1], 1, 9, 10;
+ set .@Menu$,"";
+ for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
+ {
+ if( getequipisequiped(.@Position[.@i]) )
+ set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
+ set .@Menu$, .@Menu$ + ":";
+ }
+ set .@Part, .@Position[ select(.@Menu$) ];
+ set .@id, getequipid(.@Part);
+ set .@ref, getequiprefinerycnt(.@Part);
+ if( !getequipisequiped(.@Part) )
+ {
+ mes "[Clown]";
+ mes "Your not wearing anything there...";
+ close;
+ }
+ mes "[Clown]";
+ mes "You want to Costume your " + getitemname(getequipid(.@Part)) + "?";
+ next;
+ if( select("Yes, proceed:No, I am sorry.") == 2 )
+ {
+ mes "[Clown]";
+ mes "Need some time to think about it, huh?";
+ mes "Alright, I can understand.";
+ close;
+ }
+ for(set .@i,0; .@i<4; set .@i,.@i+1)
+ set .@slot[.@i], getequipcardid(.@Part,.@i);
+ if (.@slot[0]>4000 && .@slot[0]<5000) { // If it has card don't convert
+ mes "[Clown]";
+ mes "A card? Here?!";
+ mes "As I said before, I don't convert headgear with cards.";
+ emotion e_hmm;
+ close;
+ }
+ getinventorylist;
+ for(set .@i,0; .@i<@inventorylist_count; set .@i,.@i+1)
+ if (@inventorylist_expire[.@i] != 0 && @inventorylist_equip[.@i] != 0) { // If rental don't convert
+ mes "[Clown]";
+ mes "Sorry, I don't convert a rental headgear!";
+ emotion e_hmm;
+ close;
+ }
+ if (.@ref > 0) { // If refine don't convert
+ mes "[Clown]";
+ mes "Sorry please keep in mind.";
+ mes "I don't convert headgear with refine.";
+ emotion e_hmm;
+ close;
+ }
+ if (!countitem(.@id)) {
+ mes "[Clown]";
+ mes "Where is "+getitemname(@id)+"...?";
+ npctalk "You're a snoozy cheater!";
+ logmes "CHEATER: Tried to sign an item not having it: "+getitemname(@id);
+ emotion e_wah;
+ close;
+ }
+ costume .@Part; // Convert the Headgear
+ mes "[Clown]";
+ mes "Done, enjoy your costume headgear.";
+ close;
+ case 2:
+ next;
+ mes "Please, select what to restore.";
+ mes "Remember, I will only restore it back without refine and cards.";
+ next;
+ setarray .@Position$[1],"Top","Mid","Low";
+ setarray .@Position[1], 13, 12, 11;
+ set .@Menu$,"";
+ for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
+ {
+ if( getequipisequiped(.@Position[.@i]) )
+ set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
+ set .@Menu$, .@Menu$ + ":";
+ }
+ set .@Part, .@Position[ select(.@Menu$) ];
+ if( !getequipisequiped(.@Part) )
+ {
+ mes "[Clown]";
+ mes "Your not wearing anything there...";
+ close;
+ }
+ mes "[Clown]";
+ mes "You want to restore your " + getitemname(getequipid(.@Part)) + "?";
+ next;
+ if( select("Yes, proceed:No, I am sorry.") == 2 )
+ {
+ mes "[Clown]";
+ mes "Need some time to think about it, huh?";
+ mes "Alright, I can understand.";
+ close;
+ }
+ a = getequipid(.@Part);
+ delitem a,1;
+ getitem a,1;
+
+ mes "[Clown]";
+ mes "Done, enjoy your restored headgear.";
+ close;
+ case 3:
+ mes "[Clown]";
+ mes "Very well. Return at once if you seek my services.";
+ close;
+ }
+}
+// --------------------------------------------------------------------------
+// Use duplicates to put your npc on different cities
+// --------------------------------------------------------------------------
+prontera,155,181,4 duplicate(Costume Clown) Costume Clown#1 715
\ No newline at end of file
Index: npc/scripts_custom.conf
===================================================================
--- npc/scripts_custom.conf (revision 801)
+++ npc/scripts_custom.conf (working copy)
@@ -9,6 +9,7 @@
// Your scripts go here!!
// --------------------------------------------------------------
// ----------------------- Basic Scripts -----------------------
+npc: npc/custom/costume.txt
// -- Card Remover
//npc: npc/custom/card_remover.txt
// -- Write your name on your equipment/weapon (mini-quest)
Index: src/map/atcommand.c
===================================================================
--- src/map/atcommand.c (revision 801)
+++ src/map/atcommand.c (working copy)
@@ -1679,7 +1679,7 @@
ACMD_FUNC(item)
{
char item_name[100];
- int number = 0, item_id, flag;
+ int number = 0, item_id, flag = 0, costume = 0;
struct item item_tmp;
struct item_data *item_data;
int get_count, i;
@@ -1704,6 +1704,27 @@
clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
return -1;
}
+
+
+ if( !strcmpi(command+1,"costumeitem") )
+ {
+ if( !battle_config.reserved_costume_id )
+ {
+ clif_displaymessage(fd, "Costume convertion is disable. Set a value for reserved_cosutme_id on your battle.conf file.");
+ return -1;
+ }
+ if( !(item_data->equip&EQP_HEAD_LOW) &&
+ !(item_data->equip&EQP_HEAD_MID) &&
+ !(item_data->equip&EQP_HEAD_TOP) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_LOW) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_MID) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_TOP) )
+ {
+ clif_displaymessage(fd, "You cannot costume this item. Costume only work for headgears.");
+ return -1;
+ }
+ costume = 1;
+ }
item_id = item_data->nameid;
get_count = number;
@@ -1718,6 +1739,13 @@
item_tmp.nameid = item_id;
item_tmp.identify = 1;
+ if( costume == 1 )
+ { // Costume Item
+ 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);
+ }
+
if ((flag = pc_additem(sd, &item_tmp, get_count)))
clif_additem(sd, 0, 0, flag);
}
@@ -9218,6 +9246,7 @@
{ "kamic", 40,40, atcommand_kami },
{ "heal", 40,60, atcommand_heal },
{ "item", 60,60, atcommand_item },
+ { "costumeitem", 99,99, atcommand_item },
{ "item2", 60,60, atcommand_item2 },
{ "itemreset", 40,40, atcommand_itemreset },
{ "blvl", 60,60, atcommand_baselevelup },
Index: src/map/battle.c
===================================================================
--- src/map/battle.c (revision 801)
+++ src/map/battle.c (working copy)
@@ -5848,6 +5848,7 @@
{ "buyer_name", &battle_config.buyer_name, 1, 0, 1, },
{ "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, },
{ "cell_stack_limit", &battle_config.cell_stack_limit, 1, 1, 255, },
+ { "reserved_costume_id", &battle_config.reserved_costume_id, 999998, 0, INT_MAX, },
// eAthena additions
{ "item_logarithmic_drops", &battle_config.logarithmic_drops, 0, 0, 1, },
{ "item_drop_common_min", &battle_config.item_drop_common_min, 1, 1, 10000, },
Index: src/map/battle.h
===================================================================
--- src/map/battle.h (revision 801)
+++ src/map/battle.h (working copy)
@@ -540,6 +540,9 @@
int oktoberfest_ignorepalette;
int summer2_ignorepalette;
+ // Costume System
+ int reserved_costume_id;
+
// Homunculus Limits
int max_homunculus_hp;
int max_homunculus_sp;
Index: src/map/map.c
===================================================================
--- src/map/map.c (revision 801)
+++ src/map/map.c (working copy)
@@ -1677,6 +1677,12 @@
nullpo_retv(sd);
+ if( battle_config.reserved_costume_id && battle_config.reserved_costume_id == charid )
+ {
+ clif_solved_charname(sd->fd, charid, "Costume");
+ return;
+ }
+
tsd = map_charid2sd(charid);
if( tsd )
{
Index: src/map/pc.c
===================================================================
--- src/map/pc.c (revision 801)
+++ src/map/pc.c (working copy)
@@ -845,7 +845,7 @@
int pc_equippoint(struct map_session_data *sd,int n)
{
- int ep = 0;
+ int ep = 0, char_id = 0;
nullpo_ret(sd);
@@ -863,6 +863,15 @@
(sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech]
return EQP_ARMS;
}
+
+ if( battle_config.reserved_costume_id &&
+ sd->status.inventory[n].card[0] == CARD0_CREATE &&
+ (char_id = MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3])) == battle_config.reserved_costume_id )
+ { // Costume Item - Converted
+ 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;
}
@@ -2082,8 +2091,8 @@
if( autobonus.bonus_script )
{
int j;
- ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus.pos );
- if( j < EQI_MAX-1 )
+ ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus.pos );
+ if( j < EQI_MAX_BONUS )
script_run_autobonus(autobonus.bonus_script,sd->bl.id,sd->equip_index[j]);
}
continue;
@@ -2113,8 +2122,8 @@
if( autobonus->other_script )
{
int j;
- ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
- if( j < EQI_MAX-1 )
+ ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
+ if( j < EQI_MAX_BONUS )
script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
}
Index: src/map/pc.h
===================================================================
--- src/map/pc.h (revision 801)
+++ src/map/pc.h (working copy)
@@ -563,6 +563,8 @@
EQI_ARMOR,
EQI_HAND_L,
EQI_HAND_R,
+ EQI_MAX_BONUS = 10,
EQI_COSTUME_HEAD_LOW,
EQI_COSTUME_HEAD_MID,
EQI_COSTUME_HEAD_TOP,
@@ -574,7 +576,6 @@
EQI_SHADOW_SHOES,
EQI_SHADOW_ACC_R,
EQI_SHADOW_ACC_L,
EQI_AMMO,
EQI_MAX
};
Index: src/map/script.c
===================================================================
--- src/map/script.c (revision 801)
+++ src/map/script.c (working copy)
@@ -208,6 +208,12 @@
DBMap* script_get_label_db(){ return scriptlabel_db; }
DBMap* script_get_userfunc_db(){ return userfunc_db; }
+// important buildin function references for usage in scripts
+static int buildin_set_ref = 0;
+static int buildin_callsub_ref = 0;
+static int buildin_callfunc_ref = 0;
+static int buildin_getelementofarray_ref = 0;
+
// Caches compiled autoscript item code.
// Note: This is not cleared when reloading itemdb.
static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
@@ -903,7 +909,7 @@
/// The argument list can have parenthesis or not.
/// The number of arguments is checked.
static
-const char* parse_callfunc(const char* p, int require_paren)
+const char* parse_callfunc(const char* p, int require_paren, int is_custom)
{
const char* p2;
const char* arg=NULL;
@@ -917,17 +923,32 @@
arg = buildin_func[str_data[func].val].arg;
} else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
// script defined function
- int callsub = search_str("callsub");
- add_scriptl(callsub);
+ add_scriptl(buildin_callsub_ref);
add_scriptc(C_ARG);
add_scriptl(func);
- arg = buildin_func[str_data[callsub].val].arg;
+ arg = buildin_func[str_data[buildin_callsub_ref].val].arg;
if( *arg == 0 )
disp_error_message("parse_callfunc: callsub has no arguments, please review it's definition",p);
if( *arg != '*' )
++arg; // count func as argument
- } else
- disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+ } else {
+#ifdef SCRIPT_CALLFUNC_CHECK
+ const char* name = get_str(func);
+ if( !is_custom && strdb_get(userfunc_db, name) == NULL ) {
+#endif
+ disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+#ifdef SCRIPT_CALLFUNC_CHECK
+ } else {;
+ add_scriptl(buildin_callfunc_ref);
+ add_scriptc(C_ARG);
+ add_scriptc(C_STR);
+ while( *name ) add_scriptb(*name ++);
+ add_scriptb(0);
+ arg = buildin_func[str_data[buildin_callfunc_ref].val].arg;
+ if( *arg != '*' ) ++ arg;
+ }
+#endif
+ }
p = skip_word(p);
p = skip_space(p);
@@ -1002,6 +1023,157 @@
str_data[LABEL_NEXTLINE].label = -1;
}
+/// Parse a variable assignment using the direct equals operator
+/// @param p script position where the function should run from
+/// @return NULL if not a variable assignment, the new position otherwise
+const char* parse_variable(const char* p)
+{
+ int i, j, word;
+ c_op type = C_NOP;
+ const char *p2 = NULL;
+ const char *var = p;
+
+ // skip the variable where applicable
+ p = skip_word(p);
+ p = skip_space(p);
+
+ if( p == NULL )
+ {// end of the line or invalid buffer
+ return NULL;
+ }
+
+ if( *p == '[' )
+ {// array variable so process the array as appropriate
+ for( p2 = p, i = 0, j = 1; p; ++ i )
+ {
+ if( *p ++ == ']' && --(j) == 0 ) break;
+ if( *p == '[' ) ++ j;
+ }
+
+ if( !(p = skip_space(p)) )
+ {// end of line or invalid characters remaining
+ disp_error_message("Missing right expression or closing bracket for variable.", p);
+ }
+ }
+
+ if( type == C_NOP &&
+ !( ( p[0] == '=' && p[1] != '=' && (type = C_EQ) ) // =
+ || ( p[0] == '+' && p[1] == '=' && (type = C_ADD) ) // +=
+ || ( p[0] == '-' && p[1] == '=' && (type = C_SUB) ) // -=
+ || ( p[0] == '^' && p[1] == '=' && (type = C_XOR) ) // ^=
+ || ( p[0] == '|' && p[1] == '=' && (type = C_OR ) ) // |=
+ || ( p[0] == '&' && p[1] == '=' && (type = C_AND) ) // &=
+ || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *=
+ || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /=
+ || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %=
+ || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~=
+ || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++
+ || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // --
+ || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<=
+ || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>=
+ ) )
+ {// failed to find a matching operator combination so invalid
+ return NULL;
+ }
+
+ switch( type )
+ {
+ case C_EQ:
+ {// incremental modifier
+ p = skip_space( &p[1] );
+ }
+ break;
+
+ case C_L_SHIFT:
+ case C_R_SHIFT:
+ {// left or right shift modifier
+ p = skip_space( &p[3] );
+ }
+ break;
+
+ default:
+ {// normal incremental command
+ p = skip_space( &p[2] );
+ }
+ }
+
+ if( p == NULL )
+ {// end of line or invalid buffer
+ return NULL;
+ }
+
+ // push the set function onto the stack
+ add_scriptl(buildin_set_ref);
+ add_scriptc(C_ARG);
+
+ // always append parenthesis to avoid errors
+ syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
+ syntax.curly[syntax.curly_count].count = 0;
+ syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
+
+ // increment the total curly count for the position in the script
+ ++ syntax.curly_count;
+
+ // parse the variable currently being modified
+ word = add_word(var);
+
+ if( str_data[word].type == C_FUNC || str_data[word].type == C_USERFUNC || str_data[word].type == C_USERFUNC_POS )
+ {// cannot assign a variable which exists as a function or label
+ disp_error_message("Cannot modify a variable which has the same name as a function or label.", p);
+ }
+
+ if( p2 )
+ {// process the variable index
+ const char* p3 = NULL;
+
+ // push the getelementofarray method into the stack
+ add_scriptl(buildin_getelementofarray_ref);
+ add_scriptc(C_ARG);
+ add_scriptl(word);
+
+ // process the sub-expression for this assignment
+ p3 = parse_subexpr(p2 + 1, 1);
+ p3 = skip_space(p3);
+
+ if( *p3 != ']' )
+ {// closing parenthesis is required for this script
+ disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
+ }
+
+ // push the closing function stack operator onto the stack
+ add_scriptc(C_FUNC);
+ p3 ++;
+ }
+ else
+ {// simply push the variable or value onto the stack
+ add_scriptl(word);
+ }
+
+ if( type == C_ADD_PP || type == C_SUB_PP )
+ {// incremental operator for the method
+ add_scripti(1);
+ add_scriptc(type == C_ADD_PP ? C_ADD : C_SUB);
+ }
+ else
+ {// process the value as an expression
+ p = parse_subexpr(p, -1);
+
+ if( type != C_EQ )
+ {// push the type of modifier onto the stack
+ add_scriptc(type);
+ }
+ }
+
+ // decrement the curly count for the position within the script
+ -- syntax.curly_count;
+
+ // close the script by appending the function operator
+ add_scriptc(C_FUNC);
+
+ // push the buffer from the method
+ return p;
+}
+
/*==========================================
* €‚̉ðÍ
*------------------------------------------*/
@@ -1059,6 +1231,8 @@
p++; //'"'
} else {
int l;
+ const char* pv;
+
// label , register , function etc
if(skip_word(p)==p)
disp_error_message("parse_simpleexpr: unexpected character",p);
@@ -1065,12 +1239,25 @@
l=add_word(p);
if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
- return parse_callfunc(p,1);
+ return parse_callfunc(p,1,0);
+#ifdef SCRIPT_CALLFUNC_CHECK
+ else {
+ const char* name = get_str(l);
+ if( strdb_get(userfunc_db,name) != NULL ) {
+ return parse_callfunc(p,1,1);
+ }
+ }
+#endif
+ if( (pv = parse_variable(p)) )
+ {// successfully processed a variable assignment
+ return pv;
+ }
+
p=skip_word(p);
if( *p == '[' ){
// array(name => getelementofarray(name,i) )
- add_scriptl(search_str("getelementofarray"));
+ add_scriptl(buildin_getelementofarray_ref);
add_scriptc(C_ARG);
add_scriptl(l);
@@ -1196,7 +1383,15 @@
if(p2 != NULL)
return p2;
- p = parse_callfunc(p,0);
+ // attempt to process a variable assignment
+ p2 = parse_variable(p);
+
+ if( p2 != NULL )
+ {// variable assignment processed so leave the method
+ return parse_syntax_close(p2 + 1);
+ }
+
+ p = parse_callfunc(p,0,0);
p = skip_space(p);
if(parse_syntax_for_flag) {
@@ -1919,6 +2114,11 @@
str_data[n].type = C_FUNC;
str_data[n].val = i;
str_data[n].func = buildin_func.func;
+
+ if( !strcmp(buildin_func.name, "set") ) buildin_set_ref = n; else
+ if( !strcmp(buildin_func.name, "callsub") ) buildin_callsub_ref = n; else
+ if( !strcmp(buildin_func.name, "callfunc") ) buildin_callfunc_ref = n; else
+ if( !strcmp(buildin_func.name, "getelementofarray") ) buildin_getelementofarray_ref = n;
}
}
}
@@ -3442,7 +3642,7 @@
run_func(st);
if(st->state==GOTO){
st->state = RUN;
- if( gotocount>0 && (--gotocount)<=0 ){
+ if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){
ShowError("run_script: infinity loop !\n");
script_reportsrc(st);
st->state=END;
@@ -3490,7 +3690,7 @@
st->state=END;
break;
}
- if( cmdcount>0 && (--cmdcount)<=0 ){
+ if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){
ShowError("run_script: infinity loop !\n");
script_reportsrc(st);
st->state=END;
@@ -15073,6 +15273,134 @@
return 0;
}
+/**
+ * Retrieves quantity of arguments provided to callfunc/callsub.
+ * getargcount() -> amount of arguments received in a function
+ **/
+BUILDIN_FUNC(getargcount) {
+ struct script_retinfo* ri;
+
+ if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
+ ShowError("script:getargcount: used out of function or callsub label!\n");
+ st->state = END;
+ return 1;
+ }
+ ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
+
+ script_pushint(st, ri->nargs);
+
+ return 0;
+}
+
+/**
+ * is_function(<function name>
-> 1 if function exists, 0 otherwise
+ **/
+BUILDIN_FUNC(is_function) {
+ const char* str = script_getstr(st,2);
+
+ if( ((struct script_code*)strdb_get(userfunc_db, str)) != NULL )
+ script_pushint(st,1);
+ else
+ script_pushint(st,0);
+
+ return 0;
+}
+
+/**
+ * freeloop(<toggle>
-> toggles this script instance's looping-check ability
+ **/
+BUILDIN_FUNC(freeloop) {
+
+ if( script_getnum(st,2) )
+ st->freeloop = 1;
+ else
+ st->freeloop = 0;
+
+ script_pushint(st, st->freeloop);
+
+ return 0;
+}
+
+BUILDIN_FUNC(consumeitem)
+{
+ TBL_PC *sd;
+ struct script_data *data;
+ struct item_data *item_data;
+
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;
+
+ data = script_getdata( st, 2 );
+ get_val( st, data );
+
+ if( data_isstring( data ) ){
+ const char *name = conv_str( st, data );
+
+ if( ( item_data = itemdb_searchname( name ) ) == NULL ){
+ ShowError( "buildin_consumeitem: Nonexistant item %s requested.\n", name );
+ return 1;
+ }
+ }else if( data_isint( data ) ){
+ unsigned short nameid = conv_num( st, data );
+
+ if( ( item_data = itemdb_exists( nameid ) ) == NULL ){
+ ShowError("buildin_consumeitem: Nonexistant item %hu requested.\n", nameid );
+ return 1;
+ }
+ }else{
+ ShowError("buildin_consumeitem: invalid data type for argument #1 (%d).\n", data->type );
+ return 1;
+ }
+
+ run_script( item_data->script, 0, sd->bl.id, 0 );
+ return 0;
+}
+
+/*==========================================
+ * Costume Items
+ *------------------------------------------*/
+BUILDIN_FUNC(costume)
+{
+ int i = -1, num, ep;
+ TBL_PC *sd;
+
+ num = script_getnum(st,2); // Equip Slot
+ sd = script_rid2sd(st);
+
+ if( sd == NULL )
+ return 0;
+ if( num > 0 && num <= ARRAYLENGTH(equip) )
+ i = pc_checkequip(sd, equip[num - 1]);
+ if( i < 0 )
+ return 0;
+
+ ep = sd->status.inventory.equip;
+ if( !(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) )
+ return 0;
+
+ pc_unequipitem(sd,i,2);
+ clif_delitem(sd,i,1,3);
+ // --------------------------------------------------------------------
+ sd->status.inventory.refine = 0;
+ sd->status.inventory.attribute = 0;
+ sd->status.inventory.card[0] = CARD0_CREATE;
+ sd->status.inventory.card[1] = 0;
+ sd->status.inventory.card[2] = GetWord(battle_config.reserved_costume_id, 0);
+ sd->status.inventory.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; }
+ // --------------------------------------------------------------------
+
+ clif_additem(sd,i,1,0);
+ pc_equipitem(sd,i,ep);
+ clif_misceffect(&sd->bl,3);
+
+ return 0;
+}
+
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
BUILDIN_FUNC(defpattern);
@@ -15464,6 +15792,15 @@
BUILDIN_DEF(bg_getareausers,"isiiii"),
BUILDIN_DEF(bg_updatescore,"sii"),
+ /**
+ * rAthena and beyond!
+ **/
+ BUILDIN_DEF(getargcount,""),
+ BUILDIN_DEF(is_function,"s"),
+ BUILDIN_DEF(freeloop,"i"),
+ BUILDIN_DEF(consumeitem,"v?"),
+ BUILDIN_DEF(costume,"i"),
+
// Instancing
BUILDIN_DEF(instance_create,"si"),
BUILDIN_DEF(instance_destroy,"?"),
Index: src/map/script.h
===================================================================
--- src/map/script.h (revision 801)
+++ src/map/script.h (working copy)
@@ -68,7 +68,9 @@
C_LNOT, // ! a
C_NOT, // ~ a
C_R_SHIFT, // a >> b
- C_L_SHIFT // a << b
+ C_L_SHIFT, // a << b
+ C_ADD_PP, // ++a
+ C_SUB_PP, // --a
} c_op;
struct script_retinfo {
@@ -125,6 +127,7 @@
//For backing up purposes
struct script_state *bk_st;
int bk_npcid;
+ unsigned freeloop : 1;// used by buildin_freeloop
};
struct script_reg {
Index: src/map/status.c
===================================================================
--- src/map/status.c (revision 801)
+++ src/map/status.c (working copy)
@@ -2471,7 +2471,7 @@
pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true);
// Parse equipment.
- for( i = 0; i < EQI_MAX - 1; i++ )
+ for( i = 0; i < EQI_MAX_BONUS; i++ )
{
current_equip_item_index = index = sd->equip_index; //We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
if( index < 0 )
Kindly report for any missing dependencies.
i will fix it
3CEAM_COSTUME_CONVERTER.patch
3CEAM_COSTUME_CONVERTER_V2.patch
costume_v2.txt
So i look upon it and just so happen to caught my interest even though i'm not fond
of costume system.
so without further ado!
Here's a patch i made for you guys.
EDIT:
V2 Fixed missing script.c dependencies
V3 Removed the relocation of ammo as informed by 15peaces that rytech moved it to the last for ammo-fix.
sorry, i was not aware about it.
3CEAM_COSTUME_CONVERTER_V3.patch
Index: conf/battle/battle.conf
===================================================================
--- conf/battle/battle.conf (revision 801)
+++ conf/battle/battle.conf (working copy)
@@ -171,3 +171,9 @@
// range. For example, Sonic Blow requires a 2 cell distance before autocasting is allowed.
// This setting also affects autospellwhenhit.
autospell_check_range: no
+
+// ****************************************
+// Reserved Costume ID's
+// ****************************************
+// Reserved Char ID for costume converted items.
+reserved_costume_id: 999998
\ No newline at end of file
Index: npc/custom/costume.txt
===================================================================
--- npc/custom/costume.txt (nonexistent)
+++ npc/custom/costume.txt (working copy)
@@ -0,0 +1,146 @@
+//===== Hercules Script ======================================
+//= Headgear to Costume converter >> Costume to Headgear converter
+//===== By: ==================================================
+//= Rebel, Zephyrus [rAthena]
+//= Mhalicot [Hercules]
+//===== Current Version: =====================================
+//= 1.1
+//===== Compatible With: =====================================
+//= Hercules
+//===== 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.
+//===== Additional Comments: =================================
+//= 1.0 Initial script [All of this script are credit to
+// Rebel, Zephyrus of [rAthena] and revised by [Mhalicot]
+// to make it compatible in Hercules.]
+//= 1.1 Denied if Headgear is rental, has refine,
+// or has card[Mhalicot]
+// Note: You must apply the patch in order to use this script
+//============================================================
+- script Costume Clown -1,{
+ mes "[Clown]";
+ mes "Here you can convert your headgears into a Costume Headgear or restore to its Original form.";
+ switch(select("I want to convert.:I want to restore.:No thanks.")) {
+ case 1:
+ next;
+ mes "[Clown]";
+ mes "Please, select what to convert.";
+ mes "Remember, cards and refine will be removed.";
+ next;
+ setarray .@Position$[1],"Top","Mid","Low";
+ setarray .@Position[1], 1, 9, 10;
+ set .@Menu$,"";
+ for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
+ {
+ if( getequipisequiped(.@Position[.@i]) )
+ set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
+ set .@Menu$, .@Menu$ + ":";
+ }
+ set .@Part, .@Position[ select(.@Menu$) ];
+ set .@id, getequipid(.@Part);
+ set .@ref, getequiprefinerycnt(.@Part);
+ if( !getequipisequiped(.@Part) )
+ {
+ mes "[Clown]";
+ mes "Your not wearing anything there...";
+ close;
+ }
+ mes "[Clown]";
+ mes "You want to Costume your " + getitemname(getequipid(.@Part)) + "?";
+ next;
+ if( select("Yes, proceed:No, I am sorry.") == 2 )
+ {
+ mes "[Clown]";
+ mes "Need some time to think about it, huh?";
+ mes "Alright, I can understand.";
+ close;
+ }
+ for(set .@i,0; .@i<4; set .@i,.@i+1)
+ set .@slot[.@i], getequipcardid(.@Part,.@i);
+ if (.@slot[0]>4000 && .@slot[0]<5000) { // If it has card don't convert
+ mes "[Clown]";
+ mes "A card? Here?!";
+ mes "As I said before, I don't convert headgear with cards.";
+ emotion e_hmm;
+ close;
+ }
+ getinventorylist;
+ for(set .@i,0; .@i<@inventorylist_count; set .@i,.@i+1)
+ if (@inventorylist_expire[.@i] != 0 && @inventorylist_equip[.@i] != 0) { // If rental don't convert
+ mes "[Clown]";
+ mes "Sorry, I don't convert a rental headgear!";
+ emotion e_hmm;
+ close;
+ }
+ if (.@ref > 0) { // If refine don't convert
+ mes "[Clown]";
+ mes "Sorry please keep in mind.";
+ mes "I don't convert headgear with refine.";
+ emotion e_hmm;
+ close;
+ }
+ if (!countitem(.@id)) {
+ mes "[Clown]";
+ mes "Where is "+getitemname(@id)+"...?";
+ npctalk "You're a snoozy cheater!";
+ logmes "CHEATER: Tried to sign an item not having it: "+getitemname(@id);
+ emotion e_wah;
+ close;
+ }
+ costume .@Part; // Convert the Headgear
+ mes "[Clown]";
+ mes "Done, enjoy your costume headgear.";
+ close;
+ case 2:
+ next;
+ mes "Please, select what to restore.";
+ mes "Remember, I will only restore it back without refine and cards.";
+ next;
+ setarray .@Position$[1],"Top","Mid","Low";
+ setarray .@Position[1], 13, 12, 11;
+ set .@Menu$,"";
+ for( set .@i, 1; .@i < 5; set .@i, .@i + 1 )
+ {
+ if( getequipisequiped(.@Position[.@i]) )
+ set .@Menu$, .@Menu$ + .@Position$[.@i] + "-" + "[" + getequipname(.@Position[.@i]) + "]";
+ set .@Menu$, .@Menu$ + ":";
+ }
+ set .@Part, .@Position[ select(.@Menu$) ];
+ if( !getequipisequiped(.@Part) )
+ {
+ mes "[Clown]";
+ mes "Your not wearing anything there...";
+ close;
+ }
+ mes "[Clown]";
+ mes "You want to restore your " + getitemname(getequipid(.@Part)) + "?";
+ next;
+ if( select("Yes, proceed:No, I am sorry.") == 2 )
+ {
+ mes "[Clown]";
+ mes "Need some time to think about it, huh?";
+ mes "Alright, I can understand.";
+ close;
+ }
+ a = getequipid(.@Part);
+ delitem a,1;
+ getitem a,1;
+
+ mes "[Clown]";
+ mes "Done, enjoy your restored headgear.";
+ close;
+ case 3:
+ mes "[Clown]";
+ mes "Very well. Return at once if you seek my services.";
+ close;
+ }
+}
+// --------------------------------------------------------------------------
+// Use duplicates to put your npc on different cities
+// --------------------------------------------------------------------------
+prontera,155,181,4 duplicate(Costume Clown) Costume Clown#1 715
\ No newline at end of file
Index: npc/scripts_custom.conf
===================================================================
--- npc/scripts_custom.conf (revision 801)
+++ npc/scripts_custom.conf (working copy)
@@ -9,6 +9,7 @@
// Your scripts go here!!
// --------------------------------------------------------------
// ----------------------- Basic Scripts -----------------------
+npc: npc/custom/costume.txt
// -- Card Remover
//npc: npc/custom/card_remover.txt
// -- Write your name on your equipment/weapon (mini-quest)
Index: src/map/atcommand.c
===================================================================
--- src/map/atcommand.c (revision 801)
+++ src/map/atcommand.c (working copy)
@@ -1679,7 +1679,7 @@
ACMD_FUNC(item)
{
char item_name[100];
- int number = 0, item_id, flag;
+ int number = 0, item_id, flag = 0, costume = 0;
struct item item_tmp;
struct item_data *item_data;
int get_count, i;
@@ -1704,6 +1704,27 @@
clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
return -1;
}
+
+
+ if( !strcmpi(command+1,"costumeitem") )
+ {
+ if( !battle_config.reserved_costume_id )
+ {
+ clif_displaymessage(fd, "Costume convertion is disable. Set a value for reserved_cosutme_id on your battle.conf file.");
+ return -1;
+ }
+ if( !(item_data->equip&EQP_HEAD_LOW) &&
+ !(item_data->equip&EQP_HEAD_MID) &&
+ !(item_data->equip&EQP_HEAD_TOP) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_LOW) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_MID) &&
+ !(item_data->equip&EQP_COSTUME_HEAD_TOP) )
+ {
+ clif_displaymessage(fd, "You cannot costume this item. Costume only work for headgears.");
+ return -1;
+ }
+ costume = 1;
+ }
item_id = item_data->nameid;
get_count = number;
@@ -1718,6 +1739,13 @@
item_tmp.nameid = item_id;
item_tmp.identify = 1;
+ if( costume == 1 )
+ { // Costume Item
+ 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);
+ }
+
if ((flag = pc_additem(sd, &item_tmp, get_count)))
clif_additem(sd, 0, 0, flag);
}
@@ -9218,6 +9246,7 @@
{ "kamic", 40,40, atcommand_kami },
{ "heal", 40,60, atcommand_heal },
{ "item", 60,60, atcommand_item },
+ { "costumeitem", 99,99, atcommand_item },
{ "item2", 60,60, atcommand_item2 },
{ "itemreset", 40,40, atcommand_itemreset },
{ "blvl", 60,60, atcommand_baselevelup },
Index: src/map/battle.c
===================================================================
--- src/map/battle.c (revision 801)
+++ src/map/battle.c (working copy)
@@ -5848,6 +5848,7 @@
{ "buyer_name", &battle_config.buyer_name, 1, 0, 1, },
{ "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, },
{ "cell_stack_limit", &battle_config.cell_stack_limit, 1, 1, 255, },
+ { "reserved_costume_id", &battle_config.reserved_costume_id, 999998, 0, INT_MAX, },
// eAthena additions
{ "item_logarithmic_drops", &battle_config.logarithmic_drops, 0, 0, 1, },
{ "item_drop_common_min", &battle_config.item_drop_common_min, 1, 1, 10000, },
Index: src/map/battle.h
===================================================================
--- src/map/battle.h (revision 801)
+++ src/map/battle.h (working copy)
@@ -540,6 +540,9 @@
int oktoberfest_ignorepalette;
int summer2_ignorepalette;
+ // Costume System
+ int reserved_costume_id;
+
// Homunculus Limits
int max_homunculus_hp;
int max_homunculus_sp;
Index: src/map/map.c
===================================================================
--- src/map/map.c (revision 801)
+++ src/map/map.c (working copy)
@@ -1677,6 +1677,12 @@
nullpo_retv(sd);
+ if( battle_config.reserved_costume_id && battle_config.reserved_costume_id == charid )
+ {
+ clif_solved_charname(sd->fd, charid, "Costume");
+ return;
+ }
+
tsd = map_charid2sd(charid);
if( tsd )
{
Index: src/map/pc.c
===================================================================
--- src/map/pc.c (revision 801)
+++ src/map/pc.c (working copy)
@@ -845,7 +845,7 @@
int pc_equippoint(struct map_session_data *sd,int n)
{
- int ep = 0;
+ int ep = 0, char_id = 0;
nullpo_ret(sd);
@@ -863,6 +863,15 @@
(sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech]
return EQP_ARMS;
}
+
+ if( battle_config.reserved_costume_id &&
+ sd->status.inventory[n].card[0] == CARD0_CREATE &&
+ (char_id = MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3])) == battle_config.reserved_costume_id )
+ { // Costume Item - Converted
+ 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;
}
@@ -2082,8 +2091,8 @@
if( autobonus.bonus_script )
{
int j;
- ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus.pos );
- if( j < EQI_MAX-1 )
+ ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus.pos );
+ if( j < EQI_MAX_BONUS )
script_run_autobonus(autobonus.bonus_script,sd->bl.id,sd->equip_index[j]);
}
continue;
@@ -2113,8 +2122,8 @@
if( autobonus->other_script )
{
int j;
- ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
- if( j < EQI_MAX-1 )
+ ARR_FIND( 0, EQI_MAX_BONUS, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
+ if( j < EQI_MAX_BONUS )
script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
}
Index: src/map/pc.h
===================================================================
--- src/map/pc.h (revision 801)
+++ src/map/pc.h (working copy)
@@ -563,6 +563,8 @@
EQI_ARMOR,
EQI_HAND_L,
EQI_HAND_R,
+ EQI_MAX_BONUS = 10,
EQI_COSTUME_HEAD_LOW,
EQI_COSTUME_HEAD_MID,
EQI_COSTUME_HEAD_TOP,
@@ -574,7 +576,6 @@
EQI_SHADOW_SHOES,
EQI_SHADOW_ACC_R,
EQI_SHADOW_ACC_L,
EQI_AMMO,
EQI_MAX
};
Index: src/map/script.c
===================================================================
--- src/map/script.c (revision 801)
+++ src/map/script.c (working copy)
@@ -208,6 +208,12 @@
DBMap* script_get_label_db(){ return scriptlabel_db; }
DBMap* script_get_userfunc_db(){ return userfunc_db; }
+// important buildin function references for usage in scripts
+static int buildin_set_ref = 0;
+static int buildin_callsub_ref = 0;
+static int buildin_callfunc_ref = 0;
+static int buildin_getelementofarray_ref = 0;
+
// Caches compiled autoscript item code.
// Note: This is not cleared when reloading itemdb.
static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
@@ -903,7 +909,7 @@
/// The argument list can have parenthesis or not.
/// The number of arguments is checked.
static
-const char* parse_callfunc(const char* p, int require_paren)
+const char* parse_callfunc(const char* p, int require_paren, int is_custom)
{
const char* p2;
const char* arg=NULL;
@@ -917,17 +923,32 @@
arg = buildin_func[str_data[func].val].arg;
} else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
// script defined function
- int callsub = search_str("callsub");
- add_scriptl(callsub);
+ add_scriptl(buildin_callsub_ref);
add_scriptc(C_ARG);
add_scriptl(func);
- arg = buildin_func[str_data[callsub].val].arg;
+ arg = buildin_func[str_data[buildin_callsub_ref].val].arg;
if( *arg == 0 )
disp_error_message("parse_callfunc: callsub has no arguments, please review it's definition",p);
if( *arg != '*' )
++arg; // count func as argument
- } else
- disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+ } else {
+#ifdef SCRIPT_CALLFUNC_CHECK
+ const char* name = get_str(func);
+ if( !is_custom && strdb_get(userfunc_db, name) == NULL ) {
+#endif
+ disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p);
+#ifdef SCRIPT_CALLFUNC_CHECK
+ } else {;
+ add_scriptl(buildin_callfunc_ref);
+ add_scriptc(C_ARG);
+ add_scriptc(C_STR);
+ while( *name ) add_scriptb(*name ++);
+ add_scriptb(0);
+ arg = buildin_func[str_data[buildin_callfunc_ref].val].arg;
+ if( *arg != '*' ) ++ arg;
+ }
+#endif
+ }
p = skip_word(p);
p = skip_space(p);
@@ -1002,6 +1023,157 @@
str_data[LABEL_NEXTLINE].label = -1;
}
+/// Parse a variable assignment using the direct equals operator
+/// @param p script position where the function should run from
+/// @return NULL if not a variable assignment, the new position otherwise
+const char* parse_variable(const char* p)
+{
+ int i, j, word;
+ c_op type = C_NOP;
+ const char *p2 = NULL;
+ const char *var = p;
+
+ // skip the variable where applicable
+ p = skip_word(p);
+ p = skip_space(p);
+
+ if( p == NULL )
+ {// end of the line or invalid buffer
+ return NULL;
+ }
+
+ if( *p == '[' )
+ {// array variable so process the array as appropriate
+ for( p2 = p, i = 0, j = 1; p; ++ i )
+ {
+ if( *p ++ == ']' && --(j) == 0 ) break;
+ if( *p == '[' ) ++ j;
+ }
+
+ if( !(p = skip_space(p)) )
+ {// end of line or invalid characters remaining
+ disp_error_message("Missing right expression or closing bracket for variable.", p);
+ }
+ }
+
+ if( type == C_NOP &&
+ !( ( p[0] == '=' && p[1] != '=' && (type = C_EQ) ) // =
+ || ( p[0] == '+' && p[1] == '=' && (type = C_ADD) ) // +=
+ || ( p[0] == '-' && p[1] == '=' && (type = C_SUB) ) // -=
+ || ( p[0] == '^' && p[1] == '=' && (type = C_XOR) ) // ^=
+ || ( p[0] == '|' && p[1] == '=' && (type = C_OR ) ) // |=
+ || ( p[0] == '&' && p[1] == '=' && (type = C_AND) ) // &=
+ || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *=
+ || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /=
+ || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %=
+ || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~=
+ || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++
+ || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // --
+ || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<=
+ || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>=
+ ) )
+ {// failed to find a matching operator combination so invalid
+ return NULL;
+ }
+
+ switch( type )
+ {
+ case C_EQ:
+ {// incremental modifier
+ p = skip_space( &p[1] );
+ }
+ break;
+
+ case C_L_SHIFT:
+ case C_R_SHIFT:
+ {// left or right shift modifier
+ p = skip_space( &p[3] );
+ }
+ break;
+
+ default:
+ {// normal incremental command
+ p = skip_space( &p[2] );
+ }
+ }
+
+ if( p == NULL )
+ {// end of line or invalid buffer
+ return NULL;
+ }
+
+ // push the set function onto the stack
+ add_scriptl(buildin_set_ref);
+ add_scriptc(C_ARG);
+
+ // always append parenthesis to avoid errors
+ syntax.curly[syntax.curly_count].type = TYPE_ARGLIST;
+ syntax.curly[syntax.curly_count].count = 0;
+ syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN;
+
+ // increment the total curly count for the position in the script
+ ++ syntax.curly_count;
+
+ // parse the variable currently being modified
+ word = add_word(var);
+
+ if( str_data[word].type == C_FUNC || str_data[word].type == C_USERFUNC || str_data[word].type == C_USERFUNC_POS )
+ {// cannot assign a variable which exists as a function or label
+ disp_error_message("Cannot modify a variable which has the same name as a function or label.", p);
+ }
+
+ if( p2 )
+ {// process the variable index
+ const char* p3 = NULL;
+
+ // push the getelementofarray method into the stack
+ add_scriptl(buildin_getelementofarray_ref);
+ add_scriptc(C_ARG);
+ add_scriptl(word);
+
+ // process the sub-expression for this assignment
+ p3 = parse_subexpr(p2 + 1, 1);
+ p3 = skip_space(p3);
+
+ if( *p3 != ']' )
+ {// closing parenthesis is required for this script
+ disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3);
+ }
+
+ // push the closing function stack operator onto the stack
+ add_scriptc(C_FUNC);
+ p3 ++;
+ }
+ else
+ {// simply push the variable or value onto the stack
+ add_scriptl(word);
+ }
+
+ if( type == C_ADD_PP || type == C_SUB_PP )
+ {// incremental operator for the method
+ add_scripti(1);
+ add_scriptc(type == C_ADD_PP ? C_ADD : C_SUB);
+ }
+ else
+ {// process the value as an expression
+ p = parse_subexpr(p, -1);
+
+ if( type != C_EQ )
+ {// push the type of modifier onto the stack
+ add_scriptc(type);
+ }
+ }
+
+ // decrement the curly count for the position within the script
+ -- syntax.curly_count;
+
+ // close the script by appending the function operator
+ add_scriptc(C_FUNC);
+
+ // push the buffer from the method
+ return p;
+}
+
/*==========================================
* €‚̉ðÍ
*------------------------------------------*/
@@ -1059,6 +1231,8 @@
p++; //'"'
} else {
int l;
+ const char* pv;
+
// label , register , function etc
if(skip_word(p)==p)
disp_error_message("parse_simpleexpr: unexpected character",p);
@@ -1065,12 +1239,25 @@
l=add_word(p);
if( str_data[l].type == C_FUNC || str_data[l].type == C_USERFUNC || str_data[l].type == C_USERFUNC_POS)
- return parse_callfunc(p,1);
+ return parse_callfunc(p,1,0);
+#ifdef SCRIPT_CALLFUNC_CHECK
+ else {
+ const char* name = get_str(l);
+ if( strdb_get(userfunc_db,name) != NULL ) {
+ return parse_callfunc(p,1,1);
+ }
+ }
+#endif
+ if( (pv = parse_variable(p)) )
+ {// successfully processed a variable assignment
+ return pv;
+ }
+
p=skip_word(p);
if( *p == '[' ){
// array(name => getelementofarray(name,i) )
- add_scriptl(search_str("getelementofarray"));
+ add_scriptl(buildin_getelementofarray_ref);
add_scriptc(C_ARG);
add_scriptl(l);
@@ -1196,7 +1383,15 @@
if(p2 != NULL)
return p2;
- p = parse_callfunc(p,0);
+ // attempt to process a variable assignment
+ p2 = parse_variable(p);
+
+ if( p2 != NULL )
+ {// variable assignment processed so leave the method
+ return parse_syntax_close(p2 + 1);
+ }
+
+ p = parse_callfunc(p,0,0);
p = skip_space(p);
if(parse_syntax_for_flag) {
@@ -1919,6 +2114,11 @@
str_data[n].type = C_FUNC;
str_data[n].val = i;
str_data[n].func = buildin_func.func;
+
+ if( !strcmp(buildin_func.name, "set") ) buildin_set_ref = n; else
+ if( !strcmp(buildin_func.name, "callsub") ) buildin_callsub_ref = n; else
+ if( !strcmp(buildin_func.name, "callfunc") ) buildin_callfunc_ref = n; else
+ if( !strcmp(buildin_func.name, "getelementofarray") ) buildin_getelementofarray_ref = n;
}
}
}
@@ -3442,7 +3642,7 @@
run_func(st);
if(st->state==GOTO){
st->state = RUN;
- if( gotocount>0 && (--gotocount)<=0 ){
+ if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){
ShowError("run_script: infinity loop !\n");
script_reportsrc(st);
st->state=END;
@@ -3490,7 +3690,7 @@
st->state=END;
break;
}
- if( cmdcount>0 && (--cmdcount)<=0 ){
+ if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){
ShowError("run_script: infinity loop !\n");
script_reportsrc(st);
st->state=END;
@@ -15073,6 +15273,134 @@
return 0;
}
+/**
+ * Retrieves quantity of arguments provided to callfunc/callsub.
+ * getargcount() -> amount of arguments received in a function
+ **/
+BUILDIN_FUNC(getargcount) {
+ struct script_retinfo* ri;
+
+ if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) {
+ ShowError("script:getargcount: used out of function or callsub label!\n");
+ st->state = END;
+ return 1;
+ }
+ ri = st->stack->stack_data[st->stack->defsp - 1].u.ri;
+
+ script_pushint(st, ri->nargs);
+
+ return 0;
+}
+
+/**
+ * is_function(<function name>
+ **/
+BUILDIN_FUNC(is_function) {
+ const char* str = script_getstr(st,2);
+
+ if( ((struct script_code*)strdb_get(userfunc_db, str)) != NULL )
+ script_pushint(st,1);
+ else
+ script_pushint(st,0);
+
+ return 0;
+}
+
+/**
+ * freeloop(<toggle>
+ **/
+BUILDIN_FUNC(freeloop) {
+
+ if( script_getnum(st,2) )
+ st->freeloop = 1;
+ else
+ st->freeloop = 0;
+
+ script_pushint(st, st->freeloop);
+
+ return 0;
+}
+
+BUILDIN_FUNC(consumeitem)
+{
+ TBL_PC *sd;
+ struct script_data *data;
+ struct item_data *item_data;
+
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;
+
+ data = script_getdata( st, 2 );
+ get_val( st, data );
+
+ if( data_isstring( data ) ){
+ const char *name = conv_str( st, data );
+
+ if( ( item_data = itemdb_searchname( name ) ) == NULL ){
+ ShowError( "buildin_consumeitem: Nonexistant item %s requested.\n", name );
+ return 1;
+ }
+ }else if( data_isint( data ) ){
+ unsigned short nameid = conv_num( st, data );
+
+ if( ( item_data = itemdb_exists( nameid ) ) == NULL ){
+ ShowError("buildin_consumeitem: Nonexistant item %hu requested.\n", nameid );
+ return 1;
+ }
+ }else{
+ ShowError("buildin_consumeitem: invalid data type for argument #1 (%d).\n", data->type );
+ return 1;
+ }
+
+ run_script( item_data->script, 0, sd->bl.id, 0 );
+ return 0;
+}
+
+/*==========================================
+ * Costume Items
+ *------------------------------------------*/
+BUILDIN_FUNC(costume)
+{
+ int i = -1, num, ep;
+ TBL_PC *sd;
+
+ num = script_getnum(st,2); // Equip Slot
+ sd = script_rid2sd(st);
+
+ if( sd == NULL )
+ return 0;
+ if( num > 0 && num <= ARRAYLENGTH(equip) )
+ i = pc_checkequip(sd, equip[num - 1]);
+ if( i < 0 )
+ return 0;
+
+ ep = sd->status.inventory.equip;
+ if( !(ep&EQP_HEAD_LOW) && !(ep&EQP_HEAD_MID) && !(ep&EQP_HEAD_TOP) )
+ return 0;
+
+ pc_unequipitem(sd,i,2);
+ clif_delitem(sd,i,1,3);
+ // --------------------------------------------------------------------
+ sd->status.inventory.refine = 0;
+ sd->status.inventory.attribute = 0;
+ sd->status.inventory.card[0] = CARD0_CREATE;
+ sd->status.inventory.card[1] = 0;
+ sd->status.inventory.card[2] = GetWord(battle_config.reserved_costume_id, 0);
+ sd->status.inventory.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; }
+ // --------------------------------------------------------------------
+
+ clif_additem(sd,i,1,0);
+ pc_equipitem(sd,i,ep);
+ clif_misceffect(&sd->bl,3);
+
+ return 0;
+}
+
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
BUILDIN_FUNC(defpattern);
@@ -15464,6 +15792,15 @@
BUILDIN_DEF(bg_getareausers,"isiiii"),
BUILDIN_DEF(bg_updatescore,"sii"),
+ /**
+ * rAthena and beyond!
+ **/
+ BUILDIN_DEF(getargcount,""),
+ BUILDIN_DEF(is_function,"s"),
+ BUILDIN_DEF(freeloop,"i"),
+ BUILDIN_DEF(consumeitem,"v?"),
+ BUILDIN_DEF(costume,"i"),
+
// Instancing
BUILDIN_DEF(instance_create,"si"),
BUILDIN_DEF(instance_destroy,"?"),
Index: src/map/script.h
===================================================================
--- src/map/script.h (revision 801)
+++ src/map/script.h (working copy)
@@ -68,7 +68,9 @@
C_LNOT, // ! a
C_NOT, // ~ a
C_R_SHIFT, // a >> b
- C_L_SHIFT // a << b
+ C_L_SHIFT, // a << b
+ C_ADD_PP, // ++a
+ C_SUB_PP, // --a
} c_op;
struct script_retinfo {
@@ -125,6 +127,7 @@
//For backing up purposes
struct script_state *bk_st;
int bk_npcid;
+ unsigned freeloop : 1;// used by buildin_freeloop
};
struct script_reg {
Index: src/map/status.c
===================================================================
--- src/map/status.c (revision 801)
+++ src/map/status.c (working copy)
@@ -2471,7 +2471,7 @@
pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true);
// Parse equipment.
- for( i = 0; i < EQI_MAX - 1; i++ )
+ for( i = 0; i < EQI_MAX_BONUS; i++ )
{
current_equip_item_index = index = sd->equip_index; //We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
if( index < 0 )
Kindly report for any missing dependencies.
i will fix it
3CEAM_COSTUME_CONVERTER.patch
3CEAM_COSTUME_CONVERTER_V2.patch
costume_v2.txt
Attachments
Last edited by a moderator:
