diff options
Diffstat (limited to 'src/map/script.c')
-rw-r--r-- | src/map/script.c | 7315 |
1 files changed, 5918 insertions, 1397 deletions
diff --git a/src/map/script.c b/src/map/script.c index 48c377d24..841e21169 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2016 Hercules Dev Team + * Copyright (C) 2012-2018 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -29,7 +29,9 @@ #include "map/channel.h" #include "map/chat.h" #include "map/chrif.h" +#include "map/clan.h" #include "map/clif.h" +#include "map/date.h" #include "map/elemental.h" #include "map/guild.h" #include "map/homunculus.h" @@ -41,6 +43,7 @@ #include "map/map.h" #include "map/mapreg.h" #include "map/mercenary.h" +#include "map/messages.h" #include "map/mob.h" #include "map/npc.h" #include "map/party.h" @@ -54,6 +57,7 @@ #include "map/status.h" #include "map/storage.h" #include "map/unit.h" +#include "map/achievement.h" #include "common/cbasetypes.h" #include "common/conf.h" #include "common/db.h" @@ -80,7 +84,7 @@ #include <sys/time.h> #endif -struct script_interface script_s; +static struct script_interface script_s; struct script_interface *script; static inline int GETVALUE(const struct script_buf *buf, int i) __attribute__((nonnull (1))); @@ -100,7 +104,8 @@ static inline void SETVALUE(struct script_buf *buf, int i, int n) VECTOR_INDEX(*buf, i+2) = GetByte(n, 2); } -const char* script_op2name(int op) { +const char *script_op2name(int op) +{ #define RETURN_OP_NAME(type) case type: return #type switch( op ) { RETURN_OP_NAME(C_NOP); @@ -136,6 +141,7 @@ const char* script_op2name(int op) { RETURN_OP_NAME(C_ADD); RETURN_OP_NAME(C_SUB); RETURN_OP_NAME(C_MUL); + RETURN_OP_NAME(C_POW); RETURN_OP_NAME(C_DIV); RETURN_OP_NAME(C_MOD); RETURN_OP_NAME(C_NEG); @@ -158,7 +164,7 @@ const char* script_op2name(int op) { } #ifdef SCRIPT_DEBUG_DUMP_STACK -static void script_dump_stack(struct script_state* st) +static void script_dump_stack(struct script_state *st) { int i; nullpo_retv(st); @@ -201,7 +207,8 @@ static void script_dump_stack(struct script_state* st) #endif /// Reports on the console the src of a script error. -void script_reportsrc(struct script_state *st) { +static void script_reportsrc(struct script_state *st) +{ struct block_list* bl; nullpo_retv(st); @@ -232,7 +239,7 @@ void script_reportsrc(struct script_state *st) { } /// Reports on the console information about the script data. -void script_reportdata(struct script_data* data) +static void script_reportdata(struct script_data *data) { if( data == NULL ) return; @@ -274,7 +281,7 @@ void script_reportdata(struct script_data* data) } /// Reports on the console information about the current built-in function. -void script_reportfunc(struct script_state* st) +static void script_reportfunc(struct script_state *st) { int params, id; struct script_data* data; @@ -309,8 +316,9 @@ void script_reportfunc(struct script_state* st) /*========================================== * Output error message *------------------------------------------*/ -static void disp_error_message2(const char *mes,const char *pos,int report) __attribute__((nonnull (1))) analyzer_noreturn; -static void disp_error_message2(const char *mes,const char *pos,int report) { +static void disp_error_message2(const char *mes, const char *pos, int report) __attribute__((nonnull (1))) analyzer_noreturn; +static void disp_error_message2(const char *mes, const char *pos, int report) +{ script->error_msg = aStrdup(mes); script->error_pos = pos; script->error_report = report; @@ -318,12 +326,13 @@ static void disp_error_message2(const char *mes,const char *pos,int report) { } #define disp_error_message(mes,pos) (disp_error_message2((mes),(pos),1)) -void disp_warning_message(const char *mes, const char *pos) { +static void disp_warning_message(const char *mes, const char *pos) +{ script->warning(script->parser_current_src,script->parser_current_file,script->parser_current_line,mes,pos); } /// Checks event parameter validity -void check_event(struct script_state *st, const char *evt) +static void check_event(struct script_state *st, const char *evt) { if( evt && evt[0] && !stristr(evt, "::On") ) { @@ -335,7 +344,8 @@ void check_event(struct script_state *st, const char *evt) /*========================================== * Hashes the input string *------------------------------------------*/ -unsigned int calc_hash(const char* p) { +static unsigned int calc_hash(const char *p) +{ unsigned int h; nullpo_ret(p); @@ -370,7 +380,8 @@ unsigned int calc_hash(const char* p) { /*========================================== * Hashes the input string in a case insensitive way *------------------------------------------*/ -unsigned int calc_hash_ci(const char* p) { +static unsigned int calc_hash_ci(const char *p) +{ unsigned int h = 0; #ifdef ENABLE_CASE_CHECK @@ -409,14 +420,14 @@ unsigned int calc_hash_ci(const char* p) { *------------------------------------------*/ /// Looks up string using the provided id. -const char* script_get_str(int id) +static const char *script_get_str(int id) { Assert_retr(NULL, id >= LABEL_START && id < script->str_size); return script->str_buf+script->str_data[id].str; } /// Returns the uid of the string, or -1. -int script_search_str(const char* p) +static int script_search_str(const char *p) { int i; @@ -429,7 +440,7 @@ int script_search_str(const char* p) return -1; } -void script_casecheck_clear_sub(struct casecheck_data *ccd) +static void script_casecheck_clear_sub(struct casecheck_data *ccd) { #ifdef ENABLE_CASE_CHECK nullpo_retv(ccd); @@ -449,15 +460,17 @@ void script_casecheck_clear_sub(struct casecheck_data *ccd) #endif // ENABLE_CASE_CHECK } -void script_global_casecheck_clear(void) { +static void script_global_casecheck_clear(void) +{ script_casecheck_clear_sub(&script->global_casecheck); } -void script_local_casecheck_clear(void) { +static void script_local_casecheck_clear(void) +{ script_casecheck_clear_sub(&script->local_casecheck); } -const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char *p) +static const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char *p) { #ifdef ENABLE_CASE_CHECK int len; @@ -514,17 +527,19 @@ const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char return NULL; } -const char *script_global_casecheck_add_str(const char *p) { +static const char *script_global_casecheck_add_str(const char *p) +{ return script_casecheck_add_str_sub(&script->global_casecheck, p); } -const char *script_local_casecheck_add_str(const char *p) { +static const char *script_local_casecheck_add_str(const char *p) +{ return script_casecheck_add_str_sub(&script->local_casecheck, p); } /// Stores a copy of the string and returns its id. /// If an identical string is already present, returns its id instead. -int script_add_str(const char* p) +static int script_add_str(const char *p) { int len, h = script->calc_hash(p); #ifdef ENABLE_CASE_CHECK @@ -598,12 +613,24 @@ int script_add_str(const char* p) return script->str_num++; } +static int script_add_variable(const char *varname) +{ + int key = script->search_str(varname); + + if (key < 0) { + key = script->add_str(varname); + script->str_data[key].type = C_NAME; + } + + return key; +} + /** * Appends 1 byte to the script buffer. * * @param a The byte to append. */ -void add_scriptb(int a) +static void add_scriptb(int a) { VECTOR_ENSURE(script->buf, 1, SCRIPT_BLOCK_SIZE); VECTOR_PUSH(script->buf, (uint8)a); @@ -618,7 +645,7 @@ void add_scriptb(int a) * * @param a The value to append. */ -void add_scriptc(int a) +static void add_scriptc(int a) { while( a >= 0x40 ) { @@ -638,7 +665,7 @@ void add_scriptc(int a) * * @param a The value to append. */ -void add_scripti(int a) +static void add_scripti(int a) { while( a >= 0x40 ) { @@ -653,7 +680,7 @@ void add_scripti(int a) * * @param l The id of the script->str_data entry (Maximum up to 16M) */ -void add_scriptl(int l) +static void add_scriptl(int l) { int backpatch = script->str_data[l].backpatch; @@ -691,7 +718,7 @@ void add_scriptl(int l) /*========================================== * Resolve the label *------------------------------------------*/ -void set_label(int l,int pos, const char* script_pos) +static void set_label(int l, int pos, const char *script_pos) { int i; @@ -715,7 +742,7 @@ void set_label(int l,int pos, const char* script_pos) } /// Skips spaces and/or comments. -const char* script_skip_space(const char* p) +static const char *script_skip_space(const char *p) { if( p == NULL ) return NULL; @@ -754,7 +781,7 @@ const char* script_skip_space(const char* p) /// Skips a word. /// A word consists of undercores and/or alphanumeric characters, /// and valid variable prefixes/postfixes. -const char* skip_word(const char* p) +static const char *skip_word(const char *p) { nullpo_retr(NULL, p); // prefix @@ -783,7 +810,8 @@ const char* skip_word(const char* p) /// Adds a word to script->str_data. /// @see skip_word /// @see script->add_str -int add_word(const char* p) { +static int add_word(const char *p) +{ size_t len; int i; @@ -809,8 +837,7 @@ int add_word(const char* p) { /// Parses a function call. /// 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, int is_custom) +static const char *parse_callfunc(const char *p, int require_paren, int is_custom) { const char *p2; char *arg = NULL; @@ -941,7 +968,7 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) /// Processes end of logical script line. /// @param first When true, only fix up scheduling data is initialized /// @param p Script position for error reporting in set_label -void parse_nextline(bool first, const char* p) +static void parse_nextline(bool first, const char *p) { if( !first ) { @@ -959,7 +986,7 @@ void parse_nextline(bool first, const char* p) * Pushes a variable into stack, processing its array index if needed. * @see parse_variable */ -void parse_variable_sub_push(int word, const char *p2) +static void parse_variable_sub_push(int word, const char *p2) { if( p2 ) { const char* p3 = NULL; @@ -990,7 +1017,7 @@ void parse_variable_sub_push(int word, const char *p2) /// 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) +static const char *parse_variable(const char *p) { int word; c_op type = C_NOP; @@ -1035,6 +1062,7 @@ const char* parse_variable(const char* p) || ( p[0] == '|' && p[1] == '=' && (type = C_OR, true) ) // |= || ( p[0] == '&' && p[1] == '=' && (type = C_AND, true) ) // &= || ( p[0] == '*' && p[1] == '=' && (type = C_MUL, true) ) // *= + || ( p[0] == '*' && p[1] == '*' && p[2] == '=' && (type = C_POW, true) ) // **= || ( p[0] == '/' && p[1] == '=' && (type = C_DIV, true) ) // /= || ( p[0] == '%' && p[1] == '=' && (type = C_MOD, true) ) // %= || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST, true) ) // post ++ @@ -1058,6 +1086,7 @@ const char* parse_variable(const char* p) case C_L_SHIFT: // <<= case C_R_SHIFT: // >>= + case C_POW: // **= p = script->skip_space( &p[3] ); break; @@ -1144,7 +1173,8 @@ const char* parse_variable(const char* p) * @param p Pointer to the string to check * @return Whether the string is a number literal */ -bool is_number(const char *p) { +static bool is_number(const char *p) +{ const char *np; if (!p) return false; @@ -1175,7 +1205,7 @@ bool is_number(const char *p) { * @param str The string to insert. * @return the string position in the script string list. */ -int script_string_dup(char *str) +static int script_string_dup(char *str) { int len; int pos = script->string_list_pos; @@ -1197,7 +1227,7 @@ int script_string_dup(char *str) /*========================================== * Analysis section *------------------------------------------*/ -const char *parse_simpleexpr(const char *p) +static const char *parse_simpleexpr(const char *p) { p=script->skip_space(p); @@ -1215,7 +1245,7 @@ const char *parse_simpleexpr(const char *p) } } -const char *parse_simpleexpr_paren(const char *p) +static const char *parse_simpleexpr_paren(const char *p) { int i = script->syntax.curly_count - 1; nullpo_retr(NULL, p); @@ -1242,7 +1272,7 @@ const char *parse_simpleexpr_paren(const char *p) return p + 1; } -const char *parse_simpleexpr_number(const char *p) +static const char *parse_simpleexpr_number(const char *p) { char *np = NULL; long long lli; @@ -1264,7 +1294,7 @@ const char *parse_simpleexpr_number(const char *p) return np; } -const char *parse_simpleexpr_string(const char *p) +static const char *parse_simpleexpr_string(const char *p) { const char *start_point = p; @@ -1305,7 +1335,7 @@ const char *parse_simpleexpr_string(const char *p) return p; } -const char *parse_simpleexpr_name(const char *p) +static const char *parse_simpleexpr_name(const char *p) { int l; const char *pv = NULL; @@ -1348,6 +1378,11 @@ const char *parse_simpleexpr_name(const char *p) disp_error_message("parse_simpleexpr: unmatched ']'", p); ++p; script->addc(C_FUNC); + } else if (script->str_data[l].type == C_INT) { + script->addc(C_NAME); + script->addb(l); + script->addb(l >> 8); + script->addb(l >> 16); } else { script->addl(l); } @@ -1355,7 +1390,7 @@ const char *parse_simpleexpr_name(const char *p) return p; } -void script_add_translatable_string(const struct script_string_buf *string, const char *start_point) +static void script_add_translatable_string(const struct script_string_buf *string, const char *start_point) { struct string_translation *st = NULL; @@ -1395,7 +1430,7 @@ void script_add_translatable_string(const struct script_string_buf *string, cons /*========================================== * Analysis of the expression *------------------------------------------*/ -const char* script_parse_subexpr(const char* p,int limit) +static const char *script_parse_subexpr(const char *p, int limit) { int op,opl,len; @@ -1422,8 +1457,9 @@ const char* script_parse_subexpr(const char* p,int limit) p=script->skip_space(p); while(( (op=C_OP3, opl=0, len=1,*p=='?') // ?: - || (op=C_ADD, opl=9, len=1,*p=='+') // + - || (op=C_SUB, opl=9, len=1,*p=='-') // - + || (op=C_ADD, opl=9, len=1,*p=='+' && p[1]!='+') // + + || (op=C_SUB, opl=9, len=1,*p=='-' && p[1]!='-') // - + || (op=C_POW, opl=11,len=2,*p=='*' && p[1]=='*') // ** || (op=C_MUL, opl=10,len=1,*p=='*') // * || (op=C_DIV, opl=10,len=1,*p=='/') // / || (op=C_MOD, opl=10,len=1,*p=='%') // % @@ -1463,7 +1499,7 @@ const char* script_parse_subexpr(const char* p,int limit) /*========================================== * Evaluation of the expression *------------------------------------------*/ -const char* parse_expr(const char *p) +static const char *parse_expr(const char *p) { nullpo_retr(NULL, p); switch(*p) { @@ -1478,7 +1514,7 @@ const char* parse_expr(const char *p) /*========================================== * Analysis of the line *------------------------------------------*/ -const char* parse_line(const char* p) +static const char *parse_line(const char *p) { const char* p2; @@ -1541,7 +1577,7 @@ const char* parse_line(const char* p) } // { ... } Closing process -const char* parse_curly_close(const char* p) +static const char *parse_curly_close(const char *p) { nullpo_retr(NULL, p); if(script->syntax.curly_count <= 0) { @@ -1600,7 +1636,7 @@ const char* parse_curly_close(const char* p) // Syntax-related processing // break, case, continue, default, do, for, function, // if, switch, while ? will handle this internally. -const char* parse_syntax(const char* p) +static const char *parse_syntax(const char *p) { const char *p2 = script->skip_word(p); @@ -2030,7 +2066,8 @@ const char* parse_syntax(const char* p) return NULL; } -const char* parse_syntax_close(const char *p) { +static const char *parse_syntax_close(const char *p) +{ // If (...) for (...) hoge (); as to make sure closed closed once again int flag; @@ -2044,7 +2081,7 @@ const char* parse_syntax_close(const char *p) { // Close judgment if, for, while, of do // flag == 1 : closed // flag == 0 : not closed -const char* parse_syntax_close_sub(const char* p,int* flag) +static const char *parse_syntax_close_sub(const char *p, int *flag) { char label[256]; int pos = script->syntax.curly_count - 1; @@ -2217,7 +2254,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) } /// Retrieves the value of a constant. -bool script_get_constant(const char* name, int* value) +static bool script_get_constant(const char *name, int *value) { int n = script->search_str(name); @@ -2235,11 +2272,11 @@ bool script_get_constant(const char* name, int* value) } /// Creates new constant or parameter with given value. -void script_set_constant(const char *name, int value, bool is_parameter, bool is_deprecated) +static void script_set_constant(const char *name, int value, bool is_parameter, bool is_deprecated) { int n = script->add_str(name); - if( script->str_data[n].type == C_NOP ) {// new + if (script->str_data[n].type == C_NOP) { script->str_data[n].type = is_parameter ? C_PARAM : C_INT; script->str_data[n].val = value; script->str_data[n].deprecated = is_deprecated ? 1 : 0; @@ -2250,7 +2287,7 @@ void script_set_constant(const char *name, int value, bool is_parameter, bool is } } /* adds data to a existent constant in the database, inserted normally via parse */ -void script_set_constant2(const char *name, int value, bool is_parameter, bool is_deprecated) +static void script_set_constant2(const char *name, int value, bool is_parameter, bool is_deprecated) { int n = script->add_str(name); @@ -2283,7 +2320,7 @@ void script_set_constant2(const char *name, int value, bool is_parameter, bool i /** * Loads the constants database from constants.conf */ -void read_constdb(void) +static void read_constdb(bool reload) { struct config_t constants_conf; char filepath[256]; @@ -2291,7 +2328,7 @@ void read_constdb(void) struct config_setting_t *t; int i = 0; - snprintf(filepath, 256, "%s/constants.conf", map->db_path); + safesnprintf(filepath, 256, "%s/constants.conf", map->db_path); if (!libconfig->load_file(&constants_conf, filepath)) return; @@ -2302,7 +2339,6 @@ void read_constdb(void) } while ((t = libconfig->setting_get_elem(cdb, i++))) { - bool is_parameter = false; bool is_deprecated = false; int value = 0; const char *name = config_setting_name(t); @@ -2333,10 +2369,6 @@ void read_constdb(void) continue; } value = i32; - if (libconfig->setting_lookup_bool(t, "Parameter", &i32)) { - if (i32 != 0) - is_parameter = true; - } if (libconfig->setting_lookup_bool(t, "Deprecated", &i32)) { if (i32 != 0) is_deprecated = true; @@ -2344,9 +2376,13 @@ void read_constdb(void) } else { value = libconfig->setting_get_int(t); } - if (is_parameter) - ShowWarning("read_constdb: Defining parameters in the constants configuration is deprecated and will no longer be possible in a future version. Parameters should be defined in source. (parameter = '%s')\n", name); - script->set_constant(name, value, is_parameter, is_deprecated); + + if (reload) { + int n = script->add_str(name); + script->str_data[n].type = C_NOP; // ensures it will be overwritten + } + + script->set_constant(name, value, false, is_deprecated); } script->constdb_comment(NULL); libconfig->destroy(&constants_conf); @@ -2359,12 +2395,12 @@ void read_constdb(void) * * @param comment The comment to set (NULL to unset) */ -void script_constdb_comment(const char *comment) +static void script_constdb_comment(const char *comment) { (void)comment; } -void script_load_parameters(void) +static void script_load_parameters(void) { int i = 0; struct { @@ -2384,6 +2420,7 @@ void script_load_parameters(void) {"SkillPoint", SP_SKILLPOINT}, {"Class", SP_CLASS}, {"Zeny", SP_ZENY}, + {"BankVault", SP_BANKVAULT}, {"Sex", SP_SEX}, {"NextBaseExp", SP_NEXTBASEEXP}, {"NextJobExp", SP_NEXTJOBEXP}, @@ -2418,7 +2455,7 @@ void script_load_parameters(void) /*========================================== * Display emplacement line of script *------------------------------------------*/ -const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line) +static const char *script_print_line(StringBuf *buf, const char *p, const char *mark, int line) { int i, mark_pos = 0, tabstop = TAB_SIZE; if( p == NULL || !p[0] ) return NULL; @@ -2457,7 +2494,8 @@ const char* script_print_line(StringBuf* buf, const char* p, const char* mark, i #undef update_tabstop #define CONTEXTLINES 3 -void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { +static void script_errorwarning_sub(StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos) +{ // Find the line where the error occurred int j; int line = start_line; @@ -2493,7 +2531,8 @@ void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, } #undef CONTEXTLINES -void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { +static void script_error(const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos) +{ StringBuf buf; StrBuf->Init(&buf); @@ -2505,7 +2544,8 @@ void script_error(const char* src, const char* file, int start_line, const char* StrBuf->Destroy(&buf); } -void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { +static void script_warning(const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos) +{ StringBuf buf; StrBuf->Init(&buf); @@ -2519,7 +2559,8 @@ void script_warning(const char* src, const char* file, int start_line, const cha /*========================================== * Analysis of the script *------------------------------------------*/ -struct script_code* parse_script(const char *src,const char *file,int line,int options, int *retval) { +static struct script_code *parse_script(const char *src, const char *file, int line, int options, int *retval) +{ const char *p,*tmpp; int i; struct script_code* code = NULL; @@ -2733,7 +2774,7 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o /// Returns the player attached to this script, identified by the rid. /// If there is no player attached, the script is terminated. -struct map_session_data *script_rid2sd(struct script_state *st) +static struct map_session_data *script_rid2sd(struct script_state *st) { struct map_session_data *sd; nullpo_retr(NULL, st); @@ -2746,7 +2787,7 @@ struct map_session_data *script_rid2sd(struct script_state *st) return sd; } -struct map_session_data *script_id2sd(struct script_state *st, int account_id) +static struct map_session_data *script_id2sd(struct script_state *st, int account_id) { struct map_session_data *sd; if ((sd = map->id2sd(account_id)) == NULL) { @@ -2757,7 +2798,7 @@ struct map_session_data *script_id2sd(struct script_state *st, int account_id) return sd; } -struct map_session_data *script_charid2sd(struct script_state *st, int char_id) +static struct map_session_data *script_charid2sd(struct script_state *st, int char_id) { struct map_session_data *sd; if ((sd = map->charid2sd(char_id)) == NULL) { @@ -2768,7 +2809,7 @@ struct map_session_data *script_charid2sd(struct script_state *st, int char_id) return sd; } -struct map_session_data *script_nick2sd(struct script_state *st, const char *name) +static struct map_session_data *script_nick2sd(struct script_state *st, const char *name) { struct map_session_data *sd; if ((sd = map->nick2sd(name)) == NULL) { @@ -2779,14 +2820,25 @@ struct map_session_data *script_nick2sd(struct script_state *st, const char *nam return sd; } -char *get_val_npcscope_str(struct script_state* st, struct reg_db *n, struct script_data* data) { +static char *get_val_npcscope_str(struct script_state *st, struct reg_db *n, struct script_data *data) +{ if (n) return (char*)i64db_get(n->vars, reference_getuid(data)); else return NULL; } -char *get_val_instance_str(struct script_state* st, const char* name, struct script_data* data) { +static char *get_val_pc_ref_str(struct script_state *st, struct reg_db *n, struct script_data *data) +{ + struct script_reg_str *p = NULL; + nullpo_retr(NULL, n); + + p = i64db_get(n->vars, reference_getuid(data)); + return p ? p->value : NULL; +} + +static char *get_val_instance_str(struct script_state *st, const char *name, struct script_data *data) +{ nullpo_retr(NULL, st); if (st->instance_id >= 0) { return (char*)i64db_get(instance->list[st->instance_id].regs.vars, reference_getuid(data)); @@ -2796,14 +2848,25 @@ char *get_val_instance_str(struct script_state* st, const char* name, struct scr } } -int get_val_npcscope_num(struct script_state* st, struct reg_db *n, struct script_data* data) { +static int get_val_npcscope_num(struct script_state *st, struct reg_db *n, struct script_data *data) +{ if (n) return (int)i64db_iget(n->vars, reference_getuid(data)); else return 0; } -int get_val_instance_num(struct script_state* st, const char* name, struct script_data* data) { +static int get_val_pc_ref_num(struct script_state *st, struct reg_db *n, struct script_data *data) +{ + struct script_reg_num *p = NULL; + nullpo_retr(0, n); + + p = i64db_get(n->vars, reference_getuid(data)); + return p ? p->value : 0; +} + +static int get_val_instance_num(struct script_state *st, const char *name, struct script_data *data) +{ if (st->instance_id >= 0) return (int)i64db_iget(instance->list[st->instance_id].regs.vars, reference_getuid(data)); else { @@ -2819,7 +2882,8 @@ int get_val_instance_num(struct script_state* st, const char* name, struct scrip * @param data[in,out] variable/constant. * @return pointer to data, for convenience. */ -struct script_data *get_val(struct script_state* st, struct script_data* data) { +static struct script_data *get_val(struct script_state *st, struct script_data *data) +{ const char* name; char prefix; char postfix; @@ -2839,8 +2903,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { return data; } - //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS] - if (!reference_toconstant(data) && not_server_variable(prefix) && reference_getref(data) == NULL) { + if (((reference_tovariable(data) && not_server_variable(prefix)) || reference_toparam(data)) && reference_getref(data) == NULL) { sd = script->rid2sd(st); if (sd == NULL) {// needs player attached if (postfix == '$') {// string variable @@ -2873,7 +2936,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; case '#': if (data->ref) { - str = script->get_val_ref_str(st, data->ref, data); + str = script->get_val_pc_ref_str(st, data->ref, data); } else if (name[1] == '#') { str = pc_readaccountreg2str(sd, data->u.num);// global } else { @@ -2894,7 +2957,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; default: if (data->ref) { - str = script->get_val_ref_str(st, data->ref, data); + str = script->get_val_pc_ref_str(st, data->ref, data); } else { str = pc_readglobalreg_str(sd, data->u.num); } @@ -2932,7 +2995,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; case '#': if (data->ref) { - data->u.num = script->get_val_ref_num(st, data->ref, data); + data->u.num = script->get_val_pc_ref_num(st, data->ref, data); } else if (name[1] == '#') { data->u.num = pc_readaccountreg2(sd, data->u.num);// global } else { @@ -2953,7 +3016,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { break; default: if (data->ref) { - data->u.num = script->get_val_ref_num(st, data->ref, data); + data->u.num = script->get_val_pc_ref_num(st, data->ref, data); } else { data->u.num = pc_readglobalreg(sd, data->u.num); } @@ -2976,7 +3039,7 @@ struct script_data *get_val(struct script_state* st, struct script_data* data) { * @param ref[in] the container to look up the reference into. * @return the retrieved value of the reference. */ -const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref) +static const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref) { struct script_data* data; nullpo_retr(NULL, st); @@ -2985,6 +3048,10 @@ const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref) script->get_val(st, data); if (data->type == C_INT) // u.num is int32 because it comes from script->get_val return (const void *)h64BPTRSIZE((int32)data->u.num); + else if (data_isreference(data) && reference_toconstant(data)) + return (const void *)h64BPTRSIZE((int32)reference_getconstant(data)); + else if (data_isreference(data) && reference_toparam(data)) + return (const void *)h64BPTRSIZE((int32)reference_getparamtype(data)); else return (const void *)h64BPTRSIZE(data->u.str); } @@ -2992,7 +3059,8 @@ const void *get_val2(struct script_state *st, int64 uid, struct reg_db *ref) * Because, currently, array members with key 0 are indifferenciable from normal variables, we should ensure its actually in * Will be gone as soon as undefined var feature is implemented **/ -void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref) { +static void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref) +{ const char *name = script->get_str(script_getvarid(uid)); struct reg_db *src = NULL; bool insert = false; @@ -3039,7 +3107,8 @@ void script_array_ensure_zero(struct script_state *st, struct map_session_data * /** * Returns array size by ID **/ -unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { +static unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) +{ struct script_array *sa = NULL; struct reg_db *src = script->array_src(st, sd, name, ref); @@ -3051,7 +3120,8 @@ unsigned int script_array_size(struct script_state *st, struct map_session_data /** * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size) **/ -unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { +static unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) +{ struct script_array *sa = NULL; struct reg_db *src = script->array_src(st, sd, name, ref); @@ -3072,7 +3142,7 @@ unsigned int script_array_highest_key(struct script_state *st, struct map_sessio } return 0; } -int script_free_array_db(union DBKey key, struct DBData *data, va_list ap) +static int script_free_array_db(union DBKey key, struct DBData *data, va_list ap) { struct script_array *sa = DB->data2ptr(data); aFree(sa->members); @@ -3082,7 +3152,8 @@ int script_free_array_db(union DBKey key, struct DBData *data, va_list ap) /** * Clears script_array and removes it from script->array_db **/ -void script_array_delete(struct reg_db *src, struct script_array *sa) { +static void script_array_delete(struct reg_db *src, struct script_array *sa) +{ nullpo_retv(src); nullpo_retv(sa); aFree(sa->members); @@ -3094,7 +3165,8 @@ void script_array_delete(struct reg_db *src, struct script_array *sa) { * * @param idx the index of the member in script_array struct list, not of the actual array member **/ -void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx) { +static void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx) +{ unsigned int i, cursor; nullpo_retv(sa); @@ -3121,7 +3193,8 @@ void script_array_remove_member(struct reg_db *src, struct script_array *sa, uns * * @param idx the index of the array member being inserted **/ -void script_array_add_member(struct script_array *sa, unsigned int idx) { +static void script_array_add_member(struct script_array *sa, unsigned int idx) +{ nullpo_retv(sa); RECREATE(sa->members, unsigned int, ++sa->size); sa->members[sa->size - 1] = idx; @@ -3130,7 +3203,8 @@ void script_array_add_member(struct script_array *sa, unsigned int idx) { * Obtains the source of the array database for this type and scenario * Initializes such database when not yet initialized. **/ -struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { +static struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) +{ struct reg_db *src = NULL; nullpo_retr(NULL, name); @@ -3181,7 +3255,8 @@ struct reg_db *script_array_src(struct script_state *st, struct map_session_data * @param num[in] Variable ID * @param empty[in] Whether the modified member is empty (needs to be removed) **/ -void script_array_update(struct reg_db *src, int64 num, bool empty) { +static void script_array_update(struct reg_db *src, int64 num, bool empty) +{ struct script_array *sa = NULL; int id = script_getvarid(num); unsigned int index = script_getvaridx(num); @@ -3222,7 +3297,7 @@ void script_array_update(struct reg_db *src, int64 num, bool empty) { } } -void set_reg_npcscope_str(struct script_state* st, struct reg_db *n, int64 num, const char* name, const char *str) +static void set_reg_npcscope_str(struct script_state *st, struct reg_db *n, int64 num, const char *name, const char *str) { if (n) { @@ -3239,7 +3314,33 @@ void set_reg_npcscope_str(struct script_state* st, struct reg_db *n, int64 num, } } -void set_reg_npcscope_num(struct script_state* st, struct reg_db *n, int64 num, const char* name, int val) +static void set_reg_pc_ref_str(struct script_state *st, struct reg_db *n, int64 num, const char *name, const char *str) +{ + struct DBIterator *iter = db_iterator(map->pc_db); + + for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) { + if (sd != NULL && n == &sd->regs) { + pc->setregistry_str(sd, num, str); + break; + } + } + dbi_destroy(iter); +} + +static void set_reg_pc_ref_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val) +{ + struct DBIterator *iter = db_iterator(map->pc_db); + + for (struct map_session_data *sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter)) { + if (sd != NULL && n == &sd->regs) { + pc->setregistry(sd, num, val); + break; + } + } + dbi_destroy(iter); +} + +static void set_reg_npcscope_num(struct script_state *st, struct reg_db *n, int64 num, const char *name, int val) { if (n) { if (val != 0) { @@ -3254,7 +3355,7 @@ void set_reg_npcscope_num(struct script_state* st, struct reg_db *n, int64 num, } } -void set_reg_instance_str(struct script_state* st, int64 num, const char* name, const char *str) +static void set_reg_instance_str(struct script_state *st, int64 num, const char *name, const char *str) { nullpo_retv(st); if (st->instance_id >= 0) { @@ -3273,7 +3374,7 @@ void set_reg_instance_str(struct script_state* st, int64 num, const char* name, } } -void set_reg_instance_num(struct script_state* st, int64 num, const char* name, int val) +static void set_reg_instance_num(struct script_state *st, int64 num, const char *name, int val) { nullpo_retv(st); if (st->instance_id >= 0) { @@ -3306,12 +3407,25 @@ void set_reg_instance_num(struct script_state* st, int64 num, const char* name, * * TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success. *------------------------------------------*/ -int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref) +static int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, const char *name, const void *value, struct reg_db *ref) { char prefix; nullpo_ret(name); prefix = name[0]; + if (script->str_data[script_getvarid(num)].type != C_NAME && script->str_data[script_getvarid(num)].type != C_PARAM) { + ShowError("script:set_reg: not a variable! '%s'\n", name); + + // to avoid this don't do script->add_str(") without setting its type. + // either use script->add_variable() or manually set the type + + if (st) { + script->reportsrc(st); + st->state = END; + } + return 0; + } + if (strlen(name) > SCRIPT_VARNAME_LENGTH) { ShowError("script:set_reg: variable name too long. '%s'\n", name); if (st) { @@ -3337,7 +3451,7 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con return 1; case '#': if (ref) { - script->set_reg_ref_str(st, ref, num, name, str); + script->set_reg_pc_ref_str(st, ref, num, name, str); } else if (name[1] == '#') { pc_setaccountreg2str(sd, num, str); } else { @@ -3358,7 +3472,7 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con return 1; default: if (ref) { - script->set_reg_ref_str(st, ref, num, name, str); + script->set_reg_pc_ref_str(st, ref, num, name, str); } else { pc_setglobalreg_str(sd, num, str); } @@ -3399,7 +3513,7 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con return 1; case '#': if (ref) { - script->set_reg_ref_num(st, ref, num, name, val); + script->set_reg_pc_ref_num(st, ref, num, name, val); } else if (name[1] == '#') { pc_setaccountreg2(sd, num, val); } else { @@ -3420,7 +3534,7 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con return 1; default: if (ref) { - script->set_reg_ref_num(st, ref, num, name, val); + script->set_reg_pc_ref_num(st, ref, num, name, val); } else { pc_setglobalreg(sd, num, val); } @@ -3429,18 +3543,32 @@ int set_reg(struct script_state *st, struct map_session_data *sd, int64 num, con } } -int set_var(struct map_session_data *sd, char *name, void *val) +static int set_var(struct map_session_data *sd, char *name, void *val) { - return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL); + int key = script->add_variable(name); + + if (script->str_data[key].type != C_NAME) { + ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", name); + return -1; + } + + return script->set_reg(NULL, sd, reference_uid(key, 0), name, val, NULL); } -void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref) +static void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, const void *value, struct reg_db *ref) { - script->set_reg(st, sd, reference_uid(script->add_str(varname),elem), varname, value, ref); + int key = script->add_variable(varname); + + if (script->str_data[key].type != C_NAME) { + ShowError("script:setd_sub: `%s` is already used by something that is not a variable.\n", varname); + return; + } + + script->set_reg(st, sd, reference_uid(key, elem), varname, value, ref); } /// Converts the data to a string -const char *conv_str(struct script_state *st, struct script_data* data) +static const char *conv_str(struct script_state *st, struct script_data *data) { script->get_val(st, data); if (data_isstring(data)) { @@ -3474,7 +3602,7 @@ const char *conv_str(struct script_state *st, struct script_data* data) } /// Converts the data to an int -int conv_num(struct script_state *st, struct script_data *data) +static int conv_num(struct script_state *st, struct script_data *data) { long num; @@ -3532,7 +3660,8 @@ int conv_num(struct script_state *st, struct script_data *data) // /// Increases the size of the stack -void stack_expand(struct script_stack* stack) { +static void stack_expand(struct script_stack *stack) +{ nullpo_retv(stack); stack->sp_max += 64; stack->stack_data = (struct script_data*)aRealloc(stack->stack_data, @@ -3542,7 +3671,8 @@ void stack_expand(struct script_stack* stack) { } /// Pushes a value into the stack (with reference) -struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref) { +static struct script_data *push_val(struct script_stack *stack, enum c_op type, int64 val, struct reg_db *ref) +{ nullpo_retr(NULL, stack); if( stack->sp >= stack->sp_max ) script->stack_expand(stack); @@ -3554,7 +3684,7 @@ struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 v } /// Pushes a string into the stack -struct script_data *push_str(struct script_stack *stack, char *str) +static struct script_data *push_str(struct script_stack *stack, char *str) { nullpo_retr(NULL, stack); if( stack->sp >= stack->sp_max ) @@ -3567,7 +3697,7 @@ struct script_data *push_str(struct script_stack *stack, char *str) } /// Pushes a constant string into the stack -struct script_data *push_conststr(struct script_stack *stack, const char *str) +static struct script_data *push_conststr(struct script_stack *stack, const char *str) { nullpo_retr(NULL, stack); if( stack->sp >= stack->sp_max ) @@ -3580,7 +3710,8 @@ struct script_data *push_conststr(struct script_stack *stack, const char *str) } /// Pushes a retinfo into the stack -struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, struct reg_db *ref) { +static struct script_data *push_retinfo(struct script_stack *stack, struct script_retinfo *ri, struct reg_db *ref) +{ nullpo_retr(NULL, stack); if( stack->sp >= stack->sp_max ) script->stack_expand(stack); @@ -3592,7 +3723,8 @@ struct script_data* push_retinfo(struct script_stack* stack, struct script_retin } /// Pushes a copy of the target position into the stack -struct script_data* push_copy(struct script_stack* stack, int pos) { +static struct script_data *push_copy(struct script_stack *stack, int pos) +{ nullpo_retr(NULL, stack); switch( stack->stack_data[pos].type ) { case C_CONSTSTR: @@ -3617,7 +3749,8 @@ struct script_data* push_copy(struct script_stack* stack, int pos) { /// Removes the values in indexes [start,end[ from the stack. /// Adjusts all stack pointers. -void pop_stack(struct script_state* st, int start, int end) { +static void pop_stack(struct script_state *st, int start, int end) +{ struct script_stack* stack; struct script_data* data; int i; @@ -3689,7 +3822,7 @@ void pop_stack(struct script_state* st, int start, int end) { /*========================================== * Release script dependent variable, dependent variable of function *------------------------------------------*/ -void script_free_vars(struct DBMap *var_storage) +static void script_free_vars(struct DBMap *var_storage) { if( var_storage ) { // destroy the storage construct containing the variables @@ -3697,7 +3830,7 @@ void script_free_vars(struct DBMap *var_storage) } } -void script_free_code(struct script_code* code) +static void script_free_code(struct script_code *code) { nullpo_retv(code); @@ -3717,7 +3850,8 @@ void script_free_code(struct script_code* code) /// @param rid Who is running the script (attached player) /// @param oid Where the code is being run (npc 'object') /// @return Script state -struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid) { +static struct script_state *script_alloc_state(struct script_code *rootscript, int pos, int rid, int oid) +{ struct script_state* st; st = ers_alloc(script->st_ers, struct script_state); @@ -3759,7 +3893,8 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, /// Frees a script state. /// /// @param st Script state -void script_free_state(struct script_state* st) { +static void script_free_state(struct script_state *st) +{ nullpo_retv(st); if( idb_exists(script->st_db,st->id) ) { struct map_session_data *sd = st->rid ? map->id2sd(st->rid) : NULL; @@ -3821,7 +3956,8 @@ void script_free_state(struct script_state* st) { * @param st[in] Script state. * @param ref[in] Reference to be added. */ -void script_add_pending_ref(struct script_state *st, struct reg_db *ref) { +static void script_add_pending_ref(struct script_state *st, struct reg_db *ref) +{ nullpo_retv(st); RECREATE(st->pending_refs, struct reg_db*, ++st->pending_ref_count); st->pending_refs[st->pending_ref_count-1] = ref; @@ -3833,7 +3969,7 @@ void script_add_pending_ref(struct script_state *st, struct reg_db *ref) { /*========================================== * Read command *------------------------------------------*/ -c_op get_com(const struct script_buf *scriptbuf, int *pos) +static c_op get_com(const struct script_buf *scriptbuf, int *pos) { int i = 0, j = 0; @@ -3850,7 +3986,7 @@ c_op get_com(const struct script_buf *scriptbuf, int *pos) /*========================================== * Income figures *------------------------------------------*/ -int get_num(const struct script_buf *scriptbuf, int *pos) +static int get_num(const struct script_buf *scriptbuf, int *pos) { int i,j; i=0; j=0; @@ -3863,7 +3999,7 @@ int get_num(const struct script_buf *scriptbuf, int *pos) /// Ternary operators /// test ? if_true : if_false -void op_3(struct script_state* st, int op) +static void op_3(struct script_state *st, int op) { struct script_data* data; int flag = 0; @@ -3900,7 +4036,7 @@ void op_3(struct script_state* st, int op) /// s1 RE_EQ s2 -> i /// s1 RE_NE s2 -> i /// s1 ADD s2 -> s -void op_2str(struct script_state* st, int op, const char* s1, const char* s2) +static void op_2str(struct script_state *st, int op, const char *s1, const char *s2) { int a = 0; @@ -3963,10 +4099,10 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) int i; for (i = 0; i < offsetcount; i++) { libpcre->get_substring(s1, offsets, offsetcount, i, &pcre_match); - mapreg->setregstr(reference_uid(script->add_str("$@regexmatch$"), i), pcre_match); + mapreg->setregstr(reference_uid(script->add_variable("$@regexmatch$"), i), pcre_match); libpcre->free_substring(pcre_match); } - mapreg->setreg(script->add_str("$@regexmatchcount"), i); + mapreg->setreg(script->add_variable("$@regexmatchcount"), i); a = offsetcount; } else { // C_RE_NE a = (offsetcount == 0); @@ -3997,7 +4133,7 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) /// Binary number operators /// i OP i -> i -void op_2num(struct script_state* st, int op, int i1, int i2) +static void op_2num(struct script_state *st, int op, int i1, int i2) { int ret; int64 ret64; @@ -4036,6 +4172,7 @@ void op_2num(struct script_state* st, int op, int i1, int i2) case C_ADD: ret = i1 + i2; ret64 = (int64)i1 + i2; break; case C_SUB: ret = i1 - i2; ret64 = (int64)i1 - i2; break; case C_MUL: ret = i1 * i2; ret64 = (int64)i1 * i2; break; + case C_POW: ret = (int)pow((double)i1, (double)i2); ret64 = (int64)pow((double)i1, (double)i2); break; default: ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script->op2name(op), i1, i2); script->reportsrc(st); @@ -4056,7 +4193,7 @@ void op_2num(struct script_state* st, int op, int i1, int i2) } /// Binary operators -void op_2(struct script_state *st, int op) +static void op_2(struct script_state *st, int op) { struct script_data* left, leftref; struct script_data* right; @@ -4130,7 +4267,7 @@ void op_2(struct script_state *st, int op) /// NEG i -> i /// NOT i -> i /// LNOT i -> i -void op_1(struct script_state* st, int op) +static void op_1(struct script_state *st, int op) { struct script_data* data; int i1; @@ -4168,7 +4305,7 @@ void op_1(struct script_state* st, int op) /// /// @param st Script state whose stack arguments should be inspected. /// @param func Built-in function for which the arguments are intended. -bool script_check_buildin_argtype(struct script_state* st, int func) +static bool script_check_buildin_argtype(struct script_state *st, int func) { int idx, invalid = 0; char* sf; @@ -4254,7 +4391,7 @@ bool script_check_buildin_argtype(struct script_state* st, int func) /// Executes a buildin command. /// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN> -int run_func(struct script_state *st) +static int run_func(struct script_state *st) { struct script_data* data; int i,start_sp,end_sp,func; @@ -4347,7 +4484,8 @@ int run_func(struct script_state *st) /*========================================== * script execution *------------------------------------------*/ -void run_script(struct script_code *rootscript, int pos, int rid, int oid) { +static void run_script(struct script_code *rootscript, int pos, int rid, int oid) +{ struct script_state *st; if( rootscript == NULL || pos < 0 ) @@ -4361,7 +4499,7 @@ void run_script(struct script_code *rootscript, int pos, int rid, int oid) { script->run_main(st); } -void script_stop_instances(struct script_code *code) +static void script_stop_instances(struct script_code *code) { struct DBIterator *iter; struct script_state* st; @@ -4383,7 +4521,8 @@ void script_stop_instances(struct script_code *code) /*========================================== * Timer function for sleep *------------------------------------------*/ -int run_script_timer(int tid, int64 tick, int id, intptr_t data) { +static int run_script_timer(int tid, int64 tick, int id, intptr_t data) +{ struct script_state *st = idb_get(script->st_db,(int)data); if( st ) { struct map_session_data *sd = map->id2sd(st->rid); @@ -4404,7 +4543,8 @@ int run_script_timer(int tid, int64 tick, int id, intptr_t data) { /// /// @param st Script state to detach. /// @param dequeue_event Whether to schedule any queued events, when there was no previous script. -void script_detach_state(struct script_state* st, bool dequeue_event) { +static void script_detach_state(struct script_state *st, bool dequeue_event) +{ struct map_session_data* sd; nullpo_retv(st); @@ -4438,7 +4578,8 @@ void script_detach_state(struct script_state* st, bool dequeue_event) { /// Attaches script state to possibly attached character and backups it's previous script, if any. /// /// @param st Script state to attach. -void script_attach_state(struct script_state* st) { +static void script_attach_state(struct script_state *st) +{ struct map_session_data* sd; nullpo_retv(st); @@ -4470,7 +4611,8 @@ void script_attach_state(struct script_state* st) { /*========================================== * The main part of the script execution *------------------------------------------*/ -void run_script_main(struct script_state *st) { +static void run_script_main(struct script_state *st) +{ int cmdcount = script->config.check_cmdcount; int gotocount = script->config.check_gotocount; struct map_session_data *sd; @@ -4573,6 +4715,7 @@ void run_script_main(struct script_state *st) { case C_ADD: case C_SUB: case C_MUL: + case C_POW: case C_DIV: case C_MOD: case C_EQ: @@ -4659,7 +4802,7 @@ void run_script_main(struct script_state *st) { * * @retval false in case of error. */ -bool script_config_read(const char *filename, bool imported) +static bool script_config_read(const char *filename, bool imported) { struct config_t config; struct config_setting_t * setting = NULL; @@ -4706,7 +4849,7 @@ bool script_config_read(const char *filename, bool imported) /** * @see DBApply */ -int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap) +static int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap) { struct script_code *code = DB->data2ptr(data); if (code) @@ -4714,7 +4857,7 @@ int db_script_free_code_sub(union DBKey key, struct DBData *data, va_list ap) return 0; } -void script_run_autobonus(const char *autobonus, int id, int pos) +static void script_run_autobonus(const char *autobonus, int id, int pos) { struct script_code *scriptroot = (struct script_code *)strdb_get(script->autobonus_db, autobonus); @@ -4724,7 +4867,7 @@ void script_run_autobonus(const char *autobonus, int id, int pos) } } -void script_add_autobonus(const char *autobonus) +static void script_add_autobonus(const char *autobonus) { if( strdb_get(script->autobonus_db, autobonus) == NULL ) { struct script_code *scriptroot = script->parse(autobonus, "autobonus", 0, 0, NULL); @@ -4735,13 +4878,19 @@ void script_add_autobonus(const char *autobonus) } /// resets a temporary character array variable to given value -void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) { +static void script_cleararray_pc(struct map_session_data *sd, const char *varname, void *value) +{ struct script_array *sa = NULL; struct reg_db *src = NULL; unsigned int i, *list = NULL, size = 0; int key; - key = script->add_str(varname); + key = script->add_variable(varname); + + if (script->str_data[key].type != C_NAME) { + ShowError("script:cleararray_pc: `%s` is already used by something that is not a variable.\n", varname); + return; + } if( !(src = script->array_src(NULL,sd,varname,NULL) ) ) return; @@ -4762,15 +4911,21 @@ void script_cleararray_pc(struct map_session_data* sd, const char* varname, void /// sets a temporary character array variable element idx to given value /// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set. -void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) { +static void script_setarray_pc(struct map_session_data *sd, const char *varname, uint32 idx, void *value, int *refcache) +{ int key; - if( idx >= SCRIPT_MAX_ARRAYSIZE ) { + if (idx > SCRIPT_MAX_ARRAYSIZE) { ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id); return; } - key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname); + key = ( refcache && refcache[0] ) ? refcache[0] : script->add_variable(varname); + + if (script->str_data[key].type != C_NAME) { + ShowError("script:setarray_pc: `%s` is already used by something that is not a variable.\n", varname); + return; + } script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL); @@ -4782,7 +4937,7 @@ void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 /** * Clears persistent variables from memory **/ -int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap) +static int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap) { struct script_reg_state *src; @@ -4807,7 +4962,8 @@ int script_reg_destroy(union DBKey key, struct DBData *data, va_list ap) /** * Clears a single persistent variable **/ -void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) { +static void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) +{ nullpo_retv(sd); nullpo_retv(data); i64db_remove(sd->regs.vars, reg); @@ -4823,21 +4979,23 @@ void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct sc ers_free(pc->num_reg_ers,(struct script_reg_num*)data); } } -unsigned int *script_array_cpy_list(struct script_array *sa) { +static unsigned int *script_array_cpy_list(struct script_array *sa) +{ nullpo_retr(NULL, sa); if( sa->size > script->generic_ui_array_size ) script->generic_ui_array_expand(sa->size); memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size); return script->generic_ui_array; } -void script_generic_ui_array_expand (unsigned int plus) { +static void script_generic_ui_array_expand(unsigned int plus) +{ script->generic_ui_array_size += plus + 100; RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size); } /*========================================== * Destructor *------------------------------------------*/ -void do_final_script(void) +static void do_final_script(void) { int i; struct DBIterator *iter; @@ -4917,6 +5075,8 @@ void do_final_script(void) aFree(script->str_buf); for( i = 0; i < atcommand->binding_count; i++ ) { + aFree(atcommand->binding[i]->at_groups); + aFree(atcommand->binding[i]->char_groups); aFree(atcommand->binding[i]); } @@ -4970,7 +5130,8 @@ void do_final_script(void) /** * **/ -uint8 script_add_language(const char *name) { +static uint8 script_add_language(const char *name) +{ uint8 lang_id = script->max_lang_id; nullpo_ret(name); @@ -4982,7 +5143,8 @@ uint8 script_add_language(const char *name) { /** * Goes thru db/translations.conf file **/ -void script_load_translations(void) { +static void script_load_translations(void) +{ struct config_t translations_conf; const char *config_filename = "db/translations.conf"; // FIXME hardcoded name struct config_setting_t *translations = NULL; @@ -5066,7 +5228,7 @@ void script_load_translations(void) { * @param file The filename. * @return The corresponding translation name. */ -const char *script_get_translation_file_name(const char *file) +static const char *script_get_translation_file_name(const char *file) { const char *basename = NULL, *last_dot = NULL; @@ -5110,7 +5272,7 @@ const char *script_get_translation_file_name(const char *file) * @return success state * @retval true if a new string was added. */ -bool script_load_translation_addstring(const char *file, uint8 lang_id, const char *msgctxt, const struct script_string_buf *msgid, const struct script_string_buf *msgstr) +static bool script_load_translation_addstring(const char *file, uint8 lang_id, const char *msgctxt, const struct script_string_buf *msgid, const struct script_string_buf *msgstr) { nullpo_retr(false, file); nullpo_retr(false, msgctxt); @@ -5178,7 +5340,7 @@ bool script_load_translation_addstring(const char *file, uint8 lang_id, const ch * @param lang_id The language identifier. * @return The amount of strings loaded. */ -int script_load_translation(const char *file, uint8 lang_id) +static int script_load_translation(const char *file, uint8 lang_id) { int translations = 0; char line[1024]; @@ -5318,7 +5480,8 @@ int script_load_translation(const char *file, uint8 lang_id) /** * **/ -void script_clear_translations(bool reload) { +static void script_clear_translations(bool reload) +{ uint32 i; if( script->string_list ) @@ -5352,7 +5515,7 @@ void script_clear_translations(bool reload) { /** * **/ -int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_list ap) +static int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_list ap) { struct DBMap *string_db = DB->data2ptr(data); @@ -5373,7 +5536,7 @@ int script_translation_db_destroyer(union DBKey key, struct DBData *data, va_lis /** * **/ -void script_parser_clean_leftovers(void) +static void script_parser_clean_leftovers(void) { VECTOR_CLEAR(script->buf); @@ -5388,7 +5551,8 @@ void script_parser_clean_leftovers(void) /** * Performs cleanup after all parsing is processed **/ -int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { +static int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) +{ script->parser_clean_leftovers(); script->parse_cleanup_timer_id = INVALID_TIMER; @@ -5399,7 +5563,8 @@ int script_parse_cleanup_timer(int tid, int64 tick, int id, intptr_t data) { /*========================================== * Initialization *------------------------------------------*/ -void do_init_script(bool minimal) { +static void do_init_script(bool minimal) +{ script->parse_cleanup_timer_id = INVALID_TIMER; VECTOR_INIT(script->parse_simpleexpr_strbuf); @@ -5418,7 +5583,7 @@ void do_init_script(bool minimal) { VECTOR_INIT(script->hqi); script->parse_builtin(); - script->read_constdb(); + script->read_constdb(false); script->load_parameters(); script->hardcoded_constants(); @@ -5429,7 +5594,7 @@ void do_init_script(bool minimal) { script->load_translations(); } -int script_reload(void) +static int script_reload(void) { int i; struct DBIterator *iter; @@ -5451,6 +5616,8 @@ int script_reload(void) script->label_count = 0; for( i = 0; i < atcommand->binding_count; i++ ) { + aFree(atcommand->binding[i]->at_groups); + aFree(atcommand->binding[i]->char_groups); aFree(atcommand->binding[i]); } @@ -5468,16 +5635,18 @@ int script_reload(void) script->parse_cleanup_timer_id = INVALID_TIMER; } - mapreg->reload(); - + script->read_constdb(true); itemdb->name_constants(); + clan->set_constants(); + mapreg->reload(); sysinfo->vcsrevision_reload(); return 0; } /* returns name of current function being run, from within the stack [Ind/Hercules] */ -const char *script_getfuncname(struct script_state *st) { +static const char *script_getfuncname(struct script_state *st) +{ struct script_data *data; nullpo_retr(NULL, st); @@ -5501,7 +5670,7 @@ const char *script_getfuncname(struct script_state *st) { * already initialized) * @retval false if an error occurs. */ -bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) +static bool script_sprintf_helper(struct script_state *st, int start, struct StringBuf *out) { const char *format = NULL; const char *p = NULL, *np = NULL; @@ -5554,7 +5723,7 @@ bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) } // placeholder = "%n" ; (ignored) if (*np == 'n') { - ShowWarning("script_sprintf: Format %%n not supported! Skipping...\n"); + ShowWarning("script_sprintf_helper: Format %%n not supported! Skipping...\n"); script->reportsrc(st); lastarg = nextarg; p = np + 1; @@ -5726,13 +5895,17 @@ bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) /// If a dialog doesn't exist yet, one is created. /// /// mes "<message>"; -BUILDIN(mes) +static BUILDIN(mes) { struct map_session_data *sd = script->rid2sd(st); + if (sd == NULL) return true; - clif->scriptmes(sd, st->oid, script_getstr(st, 2)); + if (script_hasdata(st, 2)) + clif->scriptmes(sd, st->oid, script_getstr(st, 2)); + else + clif->scriptmes(sd, st->oid, ""); return true; } @@ -5747,7 +5920,7 @@ BUILDIN(mes) * mes "<message>"; * @endcode */ -BUILDIN(mesf) +static BUILDIN(mesf) { struct map_session_data *sd = script->rid2sd(st); struct StringBuf buf; @@ -5757,7 +5930,7 @@ BUILDIN(mesf) StrBuf->Init(&buf); - if (!script_sprintf(st, 2, &buf)) { + if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); return false; } @@ -5772,7 +5945,7 @@ BUILDIN(mesf) /// The dialog text is cleared and the script continues when the button is pressed. /// /// next; -BUILDIN(next) +static BUILDIN(next) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -5789,7 +5962,7 @@ BUILDIN(next) /// The dialog is closed when the button is pressed. /// /// close; -BUILDIN(close) +static BUILDIN(close) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -5804,7 +5977,7 @@ BUILDIN(close) /// The dialog is closed and the script continues when the button is pressed. /// /// close2; -BUILDIN(close2) +static BUILDIN(close2) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -5824,7 +5997,7 @@ BUILDIN(close2) /// Counts the number of valid and total number of options in 'str' /// If max_count > 0 the counting stops when that valid option is reached /// total is incremented for each option (NULL is supported) -int menu_countoptions(const char* str, int max_count, int* total) +static int menu_countoptions(const char *str, int max_count, int *total) { int count = 0; int bogus_total; @@ -5874,7 +6047,7 @@ int menu_countoptions(const char* str, int max_count, int* total) /// NOTE: the client closes the npc dialog when cancel is pressed /// /// menu "<option_text>",<target_label>{,"<option_text>",<target_label>,...}; -BUILDIN(menu) +static BUILDIN(menu) { int i; const char* text; @@ -5926,11 +6099,11 @@ BUILDIN(menu) sd->state.menu_or_input = 1; /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { + if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) { struct npc_data * nd = map->id2nd(st->oid); char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); + CREATE(menu, char, MAX_MENU_LENGTH); + safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1); ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); clif->scriptmenu(sd, st->oid, menu); aFree(menu); @@ -5939,13 +6112,13 @@ BUILDIN(menu) StrBuf->Destroy(&buf); - if( sd->npc_menu >= 0xff ) + if( sd->npc_menu >= MAX_MENU_OPTIONS ) {// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow - ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu); + ShowWarning("buildin_menu: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1); script->reportsrc(st); } } - else if( sd->npc_menu == 0xff ) + else if( sd->npc_menu == MAX_MENU_OPTIONS ) {// Cancel was pressed sd->state.menu_or_input = 0; st->state = END; @@ -5983,7 +6156,7 @@ BUILDIN(menu) st->state = END; return false; } - pc->setreg(sd, script->add_str("@menu"), menu); + pc->setreg(sd, script->add_variable("@menu"), menu); st->pos = script_getnum(st, i + 1); st->state = GOTO; } @@ -5996,7 +6169,7 @@ BUILDIN(menu) /// select(<option_text>{,<option_text>,...}) -> <selected_option> /// /// @see menu -BUILDIN(select) +static BUILDIN(select) { int i; const char* text; @@ -6027,11 +6200,11 @@ BUILDIN(select) sd->state.menu_or_input = 1; /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { + if( StrBuf->Length(&buf) >= MAX_MENU_LENGTH - 1 ) { struct npc_data * nd = map->id2nd(st->oid); char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); + CREATE(menu, char, MAX_MENU_LENGTH); + safestrncpy(menu, StrBuf->Value(&buf), MAX_MENU_LENGTH - 1); ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); clif->scriptmenu(sd, st->oid, menu); aFree(menu); @@ -6039,107 +6212,31 @@ BUILDIN(select) clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); - if( sd->npc_menu >= 0xff ) { - ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu); + if( sd->npc_menu >= MAX_MENU_OPTIONS ) { + ShowWarning("buildin_select: Too many options specified (current=%d, max=%d).\n", sd->npc_menu, MAX_MENU_OPTIONS - 1); script->reportsrc(st); } - } else if( sd->npc_menu == 0xff ) {// Cancel was pressed + } else if(sd->npc_menu == MAX_MENU_OPTIONS) { // Cancel was pressed sd->state.menu_or_input = 0; - st->state = END; - } else {// return selected option - int menu = 0; - - sd->state.menu_or_input = 0; - for( i = 2; i <= script_lastdata(st); ++i ) { - text = script_getstr(st, i); - sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); - if( sd->npc_menu <= 0 ) - break;// entry found - } - pc->setreg(sd, script->add_str("@menu"), menu); - script_pushint(st, menu); - st->state = RUN; - } - return true; -} - -/// Displays a menu with options and returns the selected option. -/// Behaves like 'menu' without the target labels, except when cancel is -/// pressed. -/// When cancel is pressed, the script continues and 255 is returned. -/// -/// prompt(<option_text>{,<option_text>,...}) -> <selected_option> -/// -/// @see menu -BUILDIN(prompt) -{ - int i; - const char *text; - struct map_session_data *sd = script->rid2sd(st); - if (sd == NULL) - return true; -#ifdef SECURE_NPCTIMEOUT - sd->npc_idle_type = NPCT_MENU; -#endif - - if( sd->state.menu_or_input == 0 ) - { - struct StringBuf buf; - - StrBuf->Init(&buf); - sd->npc_menu = 0; - for( i = 2; i <= script_lastdata(st); ++i ) - { - text = script_getstr(st, i); - if( sd->npc_menu > 0 ) - StrBuf->AppendStr(&buf, ":"); - StrBuf->AppendStr(&buf, text); - sd->npc_menu += script->menu_countoptions(text, 0, NULL); - } - - st->state = RERUNLINE; - sd->state.menu_or_input = 1; - - /* menus beyond this length crash the client (see bugreport:6402) */ - if( StrBuf->Length(&buf) >= 2047 ) { - struct npc_data * nd = map->id2nd(st->oid); - char* menu; - CREATE(menu, char, 2048); - safestrncpy(menu, StrBuf->Value(&buf), 2047); - ShowWarning("NPC Menu too long! (source:%s / length:%d)\n",nd?nd->name:"Unknown",StrBuf->Length(&buf)); - clif->scriptmenu(sd, st->oid, menu); - aFree(menu); - } else - clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); - StrBuf->Destroy(&buf); - - if( sd->npc_menu >= 0xff ) - { - ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu); - script->reportsrc(st); + if (strncmp(get_buildin_name(st), "prompt", 6) == 0) { + pc->setreg(sd, script->add_variable("@menu"), MAX_MENU_OPTIONS); + script_pushint(st, MAX_MENU_OPTIONS); // XXX: we should really be pushing -1 instead + st->state = RUN; + } else { + st->state = END; } - } - else if( sd->npc_menu == 0xff ) - {// Cancel was pressed - sd->state.menu_or_input = 0; - pc->setreg(sd, script->add_str("@menu"), 0xff); - script_pushint(st, 0xff); - st->state = RUN; - } - else - {// return selected option + } else {// return selected option int menu = 0; sd->state.menu_or_input = 0; - for( i = 2; i <= script_lastdata(st); ++i ) - { + for( i = 2; i <= script_lastdata(st); ++i ) { text = script_getstr(st, i); sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); if( sd->npc_menu <= 0 ) break;// entry found } - pc->setreg(sd, script->add_str("@menu"), menu); + pc->setreg(sd, script->add_variable("@menu"), menu); // TODO: throw a deprecation warning for scripts using @menu script_pushint(st, menu); st->state = RUN; } @@ -6153,7 +6250,7 @@ BUILDIN(prompt) /// Jumps to the target script label. /// /// goto <label>; -BUILDIN(goto) +static BUILDIN(goto) { if( !data_islabel(script_getdata(st,2)) ) { @@ -6171,7 +6268,7 @@ BUILDIN(goto) /*========================================== * user-defined function call *------------------------------------------*/ -BUILDIN(callfunc) +static BUILDIN(callfunc) { int i, j; struct script_retinfo* ri; @@ -6231,7 +6328,7 @@ BUILDIN(callfunc) /*========================================== * subroutine call *------------------------------------------*/ -BUILDIN(callsub) +static BUILDIN(callsub) { int i,j; struct script_retinfo* ri; @@ -6284,7 +6381,7 @@ BUILDIN(callsub) /// If the argument doesn't exist /// /// getarg(<index>{,<default_value>}) -> <value> -BUILDIN(getarg) +static BUILDIN(getarg) { struct script_retinfo* ri; int idx; @@ -6318,7 +6415,8 @@ BUILDIN(getarg) /// /// return; /// return <value>; -BUILDIN(return) { +static BUILDIN(return) +{ st->state = RETFUNC; if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO ) { @@ -6368,7 +6466,7 @@ BUILDIN(return) { /// If <min> is greater than <max>, their numbers are switched. /// rand(<range>) -> <int> /// rand(<min>,<max>) -> <int> -BUILDIN(rand) +static BUILDIN(rand) { int range; int min; @@ -6397,7 +6495,7 @@ BUILDIN(rand) /*========================================== * Warp sd to str,x,y or Random or SavePoint/Save *------------------------------------------*/ -BUILDIN(warp) +static BUILDIN(warp) { int ret; int x,y; @@ -6433,7 +6531,7 @@ BUILDIN(warp) /*========================================== * Warp a specified area *------------------------------------------*/ -int buildin_areawarp_sub(struct block_list *bl, va_list ap) +static int buildin_areawarp_sub(struct block_list *bl, va_list ap) { int x2,y2,x3,y3; unsigned int index; @@ -6474,7 +6572,7 @@ int buildin_areawarp_sub(struct block_list *bl, va_list ap) } return 0; } -BUILDIN(areawarp) +static BUILDIN(areawarp) { int16 m, x0,y0,x1,y1, x2,y2,x3=0,y3=0; unsigned int index; @@ -6516,7 +6614,7 @@ BUILDIN(areawarp) /*========================================== * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp> *------------------------------------------*/ -int buildin_areapercentheal_sub(struct block_list *bl, va_list ap) +static int buildin_areapercentheal_sub(struct block_list *bl, va_list ap) { int hp = va_arg(ap, int); int sp = va_arg(ap, int); @@ -6530,7 +6628,8 @@ int buildin_areapercentheal_sub(struct block_list *bl, va_list ap) return 0; } -BUILDIN(areapercentheal) { +static BUILDIN(areapercentheal) +{ int hp,sp,m; const char *mapname; int x0,y0,x1,y1; @@ -6556,7 +6655,8 @@ BUILDIN(areapercentheal) { * another player npc-session. * Using: warpchar "mapname",x,y,Char_ID; *------------------------------------------*/ -BUILDIN(warpchar) { +static BUILDIN(warpchar) +{ int x,y,a; const char *str; struct map_session_data *sd; @@ -6581,11 +6681,12 @@ BUILDIN(warpchar) { return true; } /*========================================== - * Warpparty - [Fredzilla] [Paradox924X] - * Syntax: warpparty "to_mapname",x,y,Party_ID,{"from_mapname"}; + * Warpparty - [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir] + * Syntax: warpparty("<to_mapname>", <x>, <y>, <party_id>, "<from_mapname>", <include_leader>) * If 'from_mapname' is specified, only the party members on that map will be warped + * If 'include_leader' option is set to false, the leader will be warped too. *------------------------------------------*/ -BUILDIN(warpparty) +static BUILDIN(warpparty) { struct map_session_data *sd = NULL; struct map_session_data *pl_sd; @@ -6593,78 +6694,84 @@ BUILDIN(warpparty) int type; int map_index; int i; + bool include_leader = true; - const char* str = script_getstr(st,2); - int x = script_getnum(st,3); - int y = script_getnum(st,4); - int p_id = script_getnum(st,5); + const char* str = script_getstr(st, 2); + int x = script_getnum(st, 3); + int y = script_getnum(st, 4); + int p_id = script_getnum(st, 5); const char* str2 = NULL; - if ( script_hasdata(st,6) ) - str2 = script_getstr(st,6); + + if (script_hasdata(st, 6)) + str2 = script_getstr(st, 6); + if (script_hasdata(st, 7)) + include_leader = script_getnum(st, 7); p = party->search(p_id); - if(!p) + + if (p == NULL) return true; - type = ( strcmp(str,"Random")==0 ) ? 0 - : ( strcmp(str,"SavePointAll")==0 ) ? 1 - : ( strcmp(str,"SavePoint")==0 ) ? 2 - : ( strcmp(str,"Leader")==0 ) ? 3 + type = (strcmp(str, "Random") == 0) ? 0 + : (strcmp(str, "SavePointAll") == 0) ? 1 + : (strcmp(str, "SavePoint") == 0) ? 2 + : (strcmp(str, "Leader") == 0) ? 3 : 4; - switch (type) - { - case 3: - for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++); - if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online - return true; - pl_sd = p->data[i].sd; - map_index = pl_sd->mapindex; - x = pl_sd->bl.x; - y = pl_sd->bl.y; - break; - case 4: - map_index = script->mapindexname2id(st,str); - break; - case 2: - //"SavePoint" uses save point of the currently attached player - if (( sd = script->rid2sd(st) ) == NULL ) - return true; - /* Fall through */ - default: - map_index = 0; - break; + switch (type) { + case 3: + ARR_FIND(0, MAX_PARTY, i, p->party.member[i].leader); + if (i == MAX_PARTY || !p->data[i].sd) // Leader not found / not online + return true; + pl_sd = p->data[i].sd; + map_index = pl_sd->mapindex; + x = pl_sd->bl.x; + y = pl_sd->bl.y; + break; + case 4: + map_index = script->mapindexname2id(st, str); + break; + case 2: + // "SavePoint" uses save point of the currently attached player + if ((sd = script->rid2sd(st)) == NULL) + return true; + /* Fall through */ + default: + map_index = 0; + break; } for (i = 0; i < MAX_PARTY; i++) { - if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id ) + if (!(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id) continue; - if( str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0 ) + if (str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0) continue; - if( pc_isdead(pl_sd) ) + if (pc_isdead(pl_sd)) continue; - switch( type ) - { - case 0: // Random - if(!map->list[pl_sd->bl.m].flag.nowarp) - pc->randomwarp(pl_sd,CLR_TELEPORT); - break; - case 1: // SavePointAll - if(!map->list[pl_sd->bl.m].flag.noreturn) - pc->setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT); - break; - case 2: // SavePoint - if(!map->list[pl_sd->bl.m].flag.noreturn) - pc->setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); - break; - case 3: // Leader - case 4: // m,x,y - if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp) - pc->setpos(pl_sd,map_index,x,y,CLR_TELEPORT); - break; + if (include_leader == false && p->party.member[i].leader) + continue; + + switch( type ) { + case 0: // Random + if (!map->list[pl_sd->bl.m].flag.nowarp) + pc->randomwarp(pl_sd, CLR_TELEPORT); + break; + case 1: // SavePointAll + if (!map->list[pl_sd->bl.m].flag.noreturn) + pc->setpos(pl_sd, pl_sd->status.save_point.map, pl_sd->status.save_point.x, pl_sd->status.save_point.y, CLR_TELEPORT); + break; + case 2: // SavePoint + if (!map->list[pl_sd->bl.m].flag.noreturn) + pc->setpos(pl_sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); + break; + case 3: // Leader + case 4: // m,x,y + if (!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp) + pc->setpos(pl_sd, map_index, x, y, CLR_TELEPORT); + break; } } @@ -6674,7 +6781,7 @@ BUILDIN(warpparty) * Warpguild - [Fredzilla] * Syntax: warpguild "mapname",x,y,Guild_ID,{"from_mapname"}; *------------------------------------------*/ -BUILDIN(warpguild) +static BUILDIN(warpguild) { struct map_session_data *sd = NULL; struct guild* g; @@ -6739,7 +6846,7 @@ BUILDIN(warpguild) /*========================================== * Force Heal a player (hp and sp) *------------------------------------------*/ -BUILDIN(heal) +static BUILDIN(heal) { int hp,sp; struct map_session_data *sd = script->rid2sd(st); @@ -6748,13 +6855,13 @@ BUILDIN(heal) hp=script_getnum(st,2); sp=script_getnum(st,3); - status->heal(&sd->bl, hp, sp, 1); + status->heal(&sd->bl, hp, sp, STATUS_HEAL_FORCED); return true; } /*========================================== * Heal a player by item (get vit bonus etc) *------------------------------------------*/ -BUILDIN(itemheal) +static BUILDIN(itemheal) { struct map_session_data *sd; int hp,sp; @@ -6777,7 +6884,7 @@ BUILDIN(itemheal) /*========================================== * *------------------------------------------*/ -BUILDIN(percentheal) +static BUILDIN(percentheal) { int hp,sp; struct map_session_data *sd; @@ -6808,7 +6915,7 @@ BUILDIN(percentheal) /*========================================== * *------------------------------------------*/ -BUILDIN(jobchange) +static BUILDIN(jobchange) { int class, upper=-1; @@ -6830,7 +6937,7 @@ BUILDIN(jobchange) /*========================================== * *------------------------------------------*/ -BUILDIN(jobname) +static BUILDIN(jobname) { int class = script_getnum(st,2); script_pushconststr(st, pc->job_name(class)); @@ -6844,7 +6951,7 @@ BUILDIN(jobname) /// shorter than 'min' and 0 otherwise. /// /// input(<var>{,<min>{,<max>}}) -> <int> -BUILDIN(input) +static BUILDIN(input) { struct script_data* data; int64 uid; @@ -6897,13 +7004,13 @@ BUILDIN(input) } // declare the copyarray method here for future reference -BUILDIN(copyarray); +static BUILDIN(copyarray); /// Sets the value of a variable. /// The value is converted to the type of the variable. /// /// set(<variable>,<value>) -> <variable> -BUILDIN(__setr) +static BUILDIN(__setr) { struct map_session_data *sd = NULL; struct script_data* data; @@ -6911,6 +7018,7 @@ BUILDIN(__setr) int64 num; const char* name; char prefix; + struct reg_db *ref; data = script_getdata(st,2); //datavalue = script_getdata(st,3); @@ -6923,11 +7031,11 @@ BUILDIN(__setr) num = reference_getuid(data); name = reference_getname(data); + ref = reference_getref(data); prefix = *name; if (not_server_variable(prefix)) { - sd = script->rid2sd(st); - if (sd == NULL) { + if (ref == NULL && (sd = script->rid2sd(st)) == NULL) { ShowError("script:set: no player attached for player variable '%s'\n", name); return true; } @@ -6975,9 +7083,9 @@ BUILDIN(__setr) } if (is_string_variable(name)) - script->set_reg(st, sd, num, name, script_getstr(st, 3), script_getref(st, 2)); + script->set_reg(st, sd, num, name, script_getstr(st, 3), ref); else - script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), script_getref(st, 2)); + script->set_reg(st, sd, num, name, (const void *)h64BPTRSIZE(script_getnum(st, 3)), ref); return true; } @@ -6990,7 +7098,7 @@ BUILDIN(__setr) /// ex: setarray arr[1],1,2,3; /// /// setarray <array variable>,<value1>{,<value2>...}; -BUILDIN(setarray) +static BUILDIN(setarray) { struct script_data* data; const char* name; @@ -7040,7 +7148,7 @@ BUILDIN(setarray) /// ex: cleararray arr[0],0,1; /// /// cleararray <array variable>,<value>,<count>; -BUILDIN(cleararray) +static BUILDIN(cleararray) { struct script_data* data; const char* name; @@ -7088,7 +7196,7 @@ BUILDIN(cleararray) /// ex: copyarray arr[0],arr[2],2; /// /// copyarray <destination array variable>,<source array variable>,<count>; -BUILDIN(copyarray) +static BUILDIN(copyarray) { struct script_data* data1; struct script_data* data2; @@ -7175,7 +7283,7 @@ BUILDIN(copyarray) /// ex: getarraysize(arr[3]) /// /// getarraysize(<array variable>) -> <int> -BUILDIN(getarraysize) +static BUILDIN(getarraysize) { struct script_data* data; @@ -7192,17 +7300,33 @@ BUILDIN(getarraysize) script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data),reference_getref(data))); return true; } -int script_array_index_cmp(const void *a, const void *b) +static int script_array_index_cmp(const void *a, const void *b) { return (*(const unsigned int *)a - *(const unsigned int *)b); // FIXME: Is the unsigned difference really intended here? } +static BUILDIN(getarrayindex) +{ + struct script_data *data = script_getdata(st, 2); + + if (!data_isreference(data) || reference_toconstant(data)) + { + ShowError("script:getarrayindex: not a variable\n"); + script->reportdata(data); + st->state = END; + return false;// not a variable + } + + script_pushint(st, reference_getindex(data)); + return true; +} + /// Deletes count or all the elements in an array, from the starting index. /// ex: deletearray arr[4],2; /// /// deletearray <array variable>; /// deletearray <array variable>,<count>; -BUILDIN(deletearray) +static BUILDIN(deletearray) { struct script_data* data; const char* name; @@ -7316,7 +7440,7 @@ BUILDIN(deletearray) /// Equivalent to var[index]. /// /// getelementofarray(<array variable>,<index>) -> <variable reference> -BUILDIN(getelementofarray) +static BUILDIN(getelementofarray) { struct script_data* data; int32 id; @@ -7335,7 +7459,7 @@ BUILDIN(getelementofarray) id = reference_getid(data); i = script_getnum(st, 3); - if (i < 0 || i >= SCRIPT_MAX_ARRAYSIZE) { + if (i < 0 || i > SCRIPT_MAX_ARRAYSIZE) { ShowWarning("script:getelementofarray: index out of range (%"PRId64")\n", i); script->reportdata(data); script_pushnil(st); @@ -7354,7 +7478,7 @@ BUILDIN(getelementofarray) /*========================================== * *------------------------------------------*/ -BUILDIN(setlook) +static BUILDIN(setlook) { int type,val; struct map_session_data *sd; @@ -7371,7 +7495,7 @@ BUILDIN(setlook) return true; } -BUILDIN(changelook) +static BUILDIN(changelook) { // As setlook but only client side int type,val; struct map_session_data *sd; @@ -7391,7 +7515,7 @@ BUILDIN(changelook) /*========================================== * *------------------------------------------*/ -BUILDIN(cutin) +static BUILDIN(cutin) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -7404,7 +7528,7 @@ BUILDIN(cutin) /*========================================== * *------------------------------------------*/ -BUILDIN(viewpoint) +static BUILDIN(viewpoint) { int type,x,y,id,color; struct map_session_data *sd; @@ -7427,8 +7551,8 @@ BUILDIN(viewpoint) /*========================================== * *------------------------------------------*/ -BUILDIN(countitem) { - int nameid, i; +static BUILDIN(countitem) +{ int count = 0; struct item_data* id = NULL; @@ -7450,11 +7574,12 @@ BUILDIN(countitem) { return false; } - nameid = id->nameid; + int nameid = id->nameid; - for(i = 0; i < MAX_INVENTORY; i++) - if(sd->status.inventory[i].nameid == nameid) + for (int i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; + } script_pushint(st,count); return true; @@ -7464,10 +7589,10 @@ BUILDIN(countitem) { * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus] * returns number of items that meet the conditions *------------------------------------------*/ -BUILDIN(countitem2) { +static BUILDIN(countitem2) +{ int nameid, iden, ref, attr, c1, c2, c3, c4; int count = 0; - int i; struct item_data* id = NULL; struct map_session_data *sd = script->rid2sd(st); @@ -7492,12 +7617,12 @@ BUILDIN(countitem2) { iden = script_getnum(st,3); ref = script_getnum(st,4); attr = script_getnum(st,5); - c1 = (short)script_getnum(st,6); - c2 = (short)script_getnum(st,7); - c3 = (short)script_getnum(st,8); - c4 = (short)script_getnum(st,9); + c1 = script_getnum(st,6); + c2 = script_getnum(st,7); + c3 = script_getnum(st,8); + c4 = script_getnum(st,9); - for(i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < sd->status.inventorySize; i++) if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].identify == iden && sd->status.inventory[i].refine == ref && @@ -7518,7 +7643,7 @@ BUILDIN(countitem2) { * 0 : fail * 1 : success (npc side only) *------------------------------------------*/ -BUILDIN(checkweight) +static BUILDIN(checkweight) { int slots, amount2=0; unsigned int weight=0, i, nbargs; @@ -7600,7 +7725,7 @@ BUILDIN(checkweight) return true; } -BUILDIN(checkweight2) +static BUILDIN(checkweight2) { //variable sub checkweight int i=0, amount2=0, slots=0, weight=0; @@ -7704,7 +7829,8 @@ BUILDIN(checkweight2) * getitembound <item id>,<amount>,<type>{,<account ID>}; * getitembound "<item id>",<amount>,<type>{,<account ID>}; *------------------------------------------*/ -BUILDIN(getitem) { +static BUILDIN(getitem) +{ int nameid,amount,get_count,i,flag = 0, offset = 0; struct item it; struct map_session_data *sd; @@ -7778,7 +7904,7 @@ BUILDIN(getitem) { if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); if( pc->candrop(sd,&it) ) - map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); + map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } @@ -7789,7 +7915,7 @@ BUILDIN(getitem) { /*========================================== * *------------------------------------------*/ -BUILDIN(getitem2) +static BUILDIN(getitem2) { int nameid,amount,flag = 0, offset = 0; int iden,ref,attr,c1,c2,c3,c4, bound = 0; @@ -7827,10 +7953,10 @@ BUILDIN(getitem2) iden=script_getnum(st,4); ref=script_getnum(st,5); attr=script_getnum(st,6); - c1=(short)script_getnum(st,7); - c2=(short)script_getnum(st,8); - c3=(short)script_getnum(st,9); - c4=(short)script_getnum(st,10); + c1 = script_getnum(st,7); + c2 = script_getnum(st,8); + c3 = script_getnum(st,9); + c4 = script_getnum(st,10); if (bound && (itemdb_type(nameid) == IT_PETEGG || itemdb_type(nameid) == IT_PETARMOR)) { ShowError("script_getitembound2: can't bind a pet egg/armor! Type=%d\n",bound); @@ -7869,10 +7995,10 @@ BUILDIN(getitem2) item_tmp.refine=ref; item_tmp.attribute=attr; item_tmp.bound=(unsigned char)bound; - item_tmp.card[0]=(short)c1; - item_tmp.card[1]=(short)c2; - item_tmp.card[2]=(short)c3; - item_tmp.card[3]=(short)c4; + item_tmp.card[0] = c1; + item_tmp.card[1] = c2; + item_tmp.card[2] = c3; + item_tmp.card[3] = c4; //Check if it's stackable. if (!itemdb->isstackable(nameid)) @@ -7886,7 +8012,7 @@ BUILDIN(getitem2) if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); if( pc->candrop(sd,&item_tmp) ) - map->addflooritem(&sd->bl, &item_tmp, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); + map->addflooritem(&sd->bl, &item_tmp, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } @@ -7899,7 +8025,8 @@ BUILDIN(getitem2) * rentitem <item id>,<seconds> * rentitem "<item name>",<seconds> *------------------------------------------*/ -BUILDIN(rentitem) { +static BUILDIN(rentitem) +{ struct map_session_data *sd; struct item it; int seconds; @@ -7947,7 +8074,8 @@ BUILDIN(rentitem) { * Returned Qty is always 1, only works on equip-able * equipment *------------------------------------------*/ -BUILDIN(getnameditem) { +static BUILDIN(getnameditem) +{ int nameid; struct item item_tmp; struct map_session_data *sd, *tsd; @@ -8006,7 +8134,8 @@ BUILDIN(getnameditem) { * gets a random item ID from an item group [Skotlex] * groupranditem group_num *------------------------------------------*/ -BUILDIN(grouprandomitem) { +static BUILDIN(grouprandomitem) +{ struct item_data *data; int nameid; @@ -8036,7 +8165,7 @@ BUILDIN(grouprandomitem) { /*========================================== * *------------------------------------------*/ -BUILDIN(makeitem) +static BUILDIN(makeitem) { int nameid,amount; int x,y,m; @@ -8079,15 +8208,15 @@ BUILDIN(makeitem) item_tmp.nameid = nameid; item_tmp.identify=1; - map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0); + map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0, false); return true; } /*========================================== -* makeitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,{"<map name>",<X>,<Y>,<range>}; -*------------------------------------------*/ -BUILDIN(makeitem2) + * makeitem2 <item id>, <amount>, <identify>, <refine>, <attribute>, <card1>, <card2>, <card3>, <card4>, {"<map name>", <X>, <Y>, <range>}; + *------------------------------------------*/ +static BUILDIN(makeitem2) { struct map_session_data *sd = NULL; struct item_data *i_data; @@ -8136,7 +8265,7 @@ BUILDIN(makeitem2) map->search_freecell(NULL, m, &x, &y, -1, -1, 1); } else { range = (script_hasdata(st, 14) ? cap_value(script_getnum(st, 14), 1, battle_config.area_size) : 3); - map->search_freecell(&sd->bl, sd->bl.m, &x, &y, range, range, 0); // Locate spot next to player. + map->search_freecell(&sd->bl, sd->bl.m, &x, &y, range, range, 0); // Locate spot next to player. } } @@ -8158,12 +8287,12 @@ BUILDIN(makeitem2) item_tmp.identify = script_getnum(st, 4); item_tmp.refine = cap_value(script_getnum(st, 5), 0, MAX_REFINE); item_tmp.attribute = script_getnum(st, 6); - item_tmp.card[0] = (short)script_getnum(st, 7); - item_tmp.card[1] = (short)script_getnum(st, 8); - item_tmp.card[2] = (short)script_getnum(st, 9); - item_tmp.card[3] = (short)script_getnum(st, 10); + item_tmp.card[0] = script_getnum(st, 7); + item_tmp.card[1] = script_getnum(st, 8); + item_tmp.card[2] = script_getnum(st, 9); + item_tmp.card[3] = script_getnum(st, 10); - map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0); + map->addflooritem(NULL, &item_tmp, amount, m, x, y, 0, 0, 0, 0, false); return true; } @@ -8171,7 +8300,7 @@ BUILDIN(makeitem2) /// Counts / deletes the current item given by idx. /// Used by buildin_delitem_search /// Relies on all input data being already fully valid. -void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items) +static void buildin_delitem_delete(struct map_session_data *sd, int idx, int *amount, bool delete_items) { int delamount; struct item* inv; @@ -8199,7 +8328,7 @@ void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, b /// Relies on all input data being already fully valid. /// @param exact_match will also match item attributes and cards, not just name id /// @return true when all items could be deleted, false when there were not enough items to delete -bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match) +static bool buildin_delitem_search(struct map_session_data *sd, struct item *it, bool exact_match) { bool delete_items = false; int i, amount; @@ -8308,7 +8437,7 @@ bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool e /// /// delitem <item id>,<amount>{,<account id>} /// delitem "<item name>",<amount>{,<account id>} -BUILDIN(delitem) +static BUILDIN(delitem) { struct map_session_data *sd; struct item it; @@ -8365,7 +8494,7 @@ BUILDIN(delitem) /// /// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>} /// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>} -BUILDIN(delitem2) +static BUILDIN(delitem2) { struct map_session_data *sd; struct item it; @@ -8406,10 +8535,10 @@ BUILDIN(delitem2) it.identify=script_getnum(st,4); it.refine=script_getnum(st,5); it.attribute=script_getnum(st,6); - it.card[0]=(short)script_getnum(st,7); - it.card[1]=(short)script_getnum(st,8); - it.card[2]=(short)script_getnum(st,9); - it.card[3]=(short)script_getnum(st,10); + it.card[0] = script_getnum(st, 7); + it.card[1] = script_getnum(st, 8); + it.card[2] = script_getnum(st, 9); + it.card[3] = script_getnum(st, 10); if( it.amount <= 0 ) return true;// nothing to do @@ -8428,7 +8557,7 @@ BUILDIN(delitem2) /*========================================== * Enables/Disables use of items while in an NPC [Skotlex] *------------------------------------------*/ -BUILDIN(enableitemuse) +static BUILDIN(enableitemuse) { struct map_session_data *sd = script->rid2sd(st); if (sd != NULL) @@ -8436,7 +8565,7 @@ BUILDIN(enableitemuse) return true; } -BUILDIN(disableitemuse) +static BUILDIN(disableitemuse) { struct map_session_data *sd = script->rid2sd(st); if (sd != NULL) @@ -8448,23 +8577,71 @@ BUILDIN(disableitemuse) * return the basic stats of sd * chk pc->readparam for available type *------------------------------------------*/ -BUILDIN(readparam) { +static BUILDIN(readparam) +{ int type; struct map_session_data *sd; + struct script_data *data = script_getdata(st, 2); - type=script_getnum(st,2); - if (script_hasdata(st,3)) - sd = script->nick2sd(st, script_getstr(st,3)); - else - sd=script->rid2sd(st); + if (reference_toparam(data)) { + type = reference_getparamtype(data); + } else { + type = script->conv_num(st, data); + } + + if (script_hasdata(st, 3)) { + if (script_isstringtype(st, 3)) { + sd = script->nick2sd(st, script_getstr(st, 3)); + } else { + sd = script->id2sd(st, script_getnum(st, 3)); + } + } else { + sd = script->rid2sd(st); + } if (sd == NULL) { - script_pushint(st,-1); + script_pushint(st, -1); return true; } - script_pushint(st,pc->readparam(sd,type)); + script_pushint(st, pc->readparam(sd, type)); + return true; +} + +static BUILDIN(setparam) +{ + int type; + struct map_session_data *sd; + struct script_data *data = script_getdata(st, 2); + int val = script_getnum(st, 3); + + if (data_isreference(data) && reference_toparam(data)) { + type = reference_getparamtype(data); + } else { + type = script->conv_num(st, data); + } + + if (script_hasdata(st, 4)) { + if (script_isstringtype(st, 4)) { + sd = script->nick2sd(st, script_getstr(st, 4)); + } else { + sd = script->id2sd(st, script_getnum(st, 4)); + } + } else { + sd = script->rid2sd(st); + } + if (sd == NULL) { + script_pushint(st, 0); + return true; + } + + if (pc->setparam(sd, type, val) == 0) { + script_pushint(st, 0); + return false; + } + + script_pushint(st, 1); return true; } @@ -8476,62 +8653,67 @@ BUILDIN(readparam) { * 2 : guild_id * 3 : account_id * 4 : bg_id + * 5 : clan_id *------------------------------------------*/ -BUILDIN(getcharid) { - int num; +static BUILDIN(getcharid) +{ + int num = script_getnum(st, 2); struct map_session_data *sd; - num = script_getnum(st,2); - if( script_hasdata(st,3) ) - sd=map->nick2sd(script_getstr(st,3)); + if (script_hasdata(st, 3)) + sd = map->nick2sd(script_getstr(st, 3)); else - sd=script->rid2sd(st); + sd = script->rid2sd(st); - if(sd==NULL) { - script_pushint(st,0); //return 0, according docs + if (sd == NULL) { + script_pushint(st, 0); //return 0, according docs return true; } - switch( num ) { - case 0: script_pushint(st,sd->status.char_id); break; - case 1: script_pushint(st,sd->status.party_id); break; - case 2: script_pushint(st,sd->status.guild_id); break; - case 3: script_pushint(st,sd->status.account_id); break; - case 4: script_pushint(st,sd->bg_id); break; - default: - ShowError("buildin_getcharid: invalid parameter (%d).\n", num); - script_pushint(st,0); - break; + switch (num) { + case 0: + script_pushint(st, sd->status.char_id); + break; + case 1: + script_pushint(st, sd->status.party_id); + break; + case 2: + script_pushint(st, sd->status.guild_id); + break; + case 3: + script_pushint(st, sd->status.account_id); + break; + case 4: + script_pushint(st, sd->bg_id); + break; + case 5: + script_pushint(st, sd->status.clan_id); + break; + default: + ShowError("buildin_getcharid: invalid parameter (%d).\n", num); + script_pushint(st, 0); + break; } return true; } + /*========================================== * returns the GID of an NPC *------------------------------------------*/ -BUILDIN(getnpcid) +static BUILDIN(getnpcid) { - int num = script_getnum(st,2); - struct npc_data* nd = NULL; - - if( script_hasdata(st,3) ) - {// unique npc name - if( ( nd = npc->name2id(script_getstr(st,3)) ) == NULL ) - { - ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3)); - script_pushint(st,0); - return false; + if (script_hasdata(st, 2)) { + if (script_isinttype(st, 2)) { + // Deprecate old form - getnpcid(<type>{, <"npc name">}) + ShowWarning("buildin_getnpcid: Use of type is deprecated. Format - getnpcid({<\"npc name\">})\n"); + script_pushint(st, 0); + } else { + struct npc_data *nd = npc->name2id(script_getstr(st, 2)); + script_pushint(st, (nd != NULL) ? nd->bl.id : 0); } - } - - switch (num) { - case 0: - script_pushint(st,nd ? nd->bl.id : st->oid); - break; - default: - ShowError("buildin_getnpcid: invalid parameter (%d).\n", num); - script_pushint(st,0); - return false; + } else { + script_pushint(st, st->oid); } return true; @@ -8541,7 +8723,7 @@ BUILDIN(getnpcid) * Return the name of the party_id * null if not found *------------------------------------------*/ -BUILDIN(getpartyname) +static BUILDIN(getpartyname) { int party_id; struct party_data* p; @@ -8567,7 +8749,7 @@ BUILDIN(getpartyname) * 1 : char_id des membres * 2 : account_id des membres *------------------------------------------*/ -BUILDIN(getpartymember) +static BUILDIN(getpartymember) { struct party_data *p; int j=0,type=0; @@ -8583,19 +8765,19 @@ BUILDIN(getpartymember) if(p->party.member[i].account_id) { switch (type) { case 2: - mapreg->setreg(reference_uid(script->add_str("$@partymemberaid"), j),p->party.member[i].account_id); + mapreg->setreg(reference_uid(script->add_variable("$@partymemberaid"), j),p->party.member[i].account_id); break; case 1: - mapreg->setreg(reference_uid(script->add_str("$@partymembercid"), j),p->party.member[i].char_id); + mapreg->setreg(reference_uid(script->add_variable("$@partymembercid"), j),p->party.member[i].char_id); break; default: - mapreg->setregstr(reference_uid(script->add_str("$@partymembername$"), j),p->party.member[i].name); + mapreg->setregstr(reference_uid(script->add_variable("$@partymembername$"), j),p->party.member[i].name); } j++; } } } - mapreg->setreg(script->add_str("$@partymembercount"),j); + mapreg->setreg(script->add_variable("$@partymembercount"),j); return true; } @@ -8604,7 +8786,7 @@ BUILDIN(getpartymember) * Retrieves party leader. if flag is specified, * return some of the leader data. Otherwise, return name. *------------------------------------------*/ -BUILDIN(getpartyleader) +static BUILDIN(getpartyleader) { int party_id, type = 0, i=0; struct party_data *p; @@ -8641,7 +8823,7 @@ BUILDIN(getpartyleader) * Return the name of the @guild_id * null if not found *------------------------------------------*/ -BUILDIN(getguildname) +static BUILDIN(getguildname) { int guild_id; struct guild* g; @@ -8663,7 +8845,7 @@ BUILDIN(getguildname) * Return the name of the guild master of @guild_id * null if not found *------------------------------------------*/ -BUILDIN(getguildmaster) +static BUILDIN(getguildmaster) { int guild_id; struct guild* g; @@ -8681,7 +8863,7 @@ BUILDIN(getguildmaster) return true; } -BUILDIN(getguildmasterid) +static BUILDIN(getguildmasterid) { int guild_id; struct guild* g; @@ -8708,7 +8890,7 @@ BUILDIN(getguildmasterid) * 1 : character ID * 2 : account ID *------------------------------------------*/ -BUILDIN(getguildmember) +static BUILDIN(getguildmember) { struct guild *g = NULL; int j = 0; @@ -8725,20 +8907,20 @@ BUILDIN(getguildmember) if ( g->member[i].account_id ) { switch (type) { case 2: - mapreg->setreg(reference_uid(script->add_str("$@guildmemberaid"), j),g->member[i].account_id); + mapreg->setreg(reference_uid(script->add_variable("$@guildmemberaid"), j),g->member[i].account_id); break; case 1: - mapreg->setreg(reference_uid(script->add_str("$@guildmembercid"), j), g->member[i].char_id); + mapreg->setreg(reference_uid(script->add_variable("$@guildmembercid"), j), g->member[i].char_id); break; default: - mapreg->setregstr(reference_uid(script->add_str("$@guildmembername$"), j), g->member[i].name); + mapreg->setregstr(reference_uid(script->add_variable("$@guildmembername$"), j), g->member[i].name); break; } j++; } } } - mapreg->setreg(script->add_str("$@guildmembercount"), j); + mapreg->setreg(script->add_variable("$@guildmembercount"), j); return true; } @@ -8749,10 +8931,12 @@ BUILDIN(getguildmember) * 1 : party_name or "" * 2 : guild_name or "" * 3 : map_name + * 4 : clan_name or "" * - : "" *------------------------------------------*/ -BUILDIN(strcharinfo) +static BUILDIN(strcharinfo) { + struct clan *c; struct guild* g; struct party_data* p; struct map_session_data *sd; @@ -8792,6 +8976,13 @@ BUILDIN(strcharinfo) case 3: script_pushconststr(st, map->list[sd->bl.m].name); break; + case 4: + if ((c = sd->clan) != NULL) { + script_pushstrcopy(st, c->name); + } else { + script_pushconststr(st, ""); + } + break; default: ShowWarning("script:strcharinfo: unknown parameter.\n"); script_pushconststr(st, ""); @@ -8809,7 +9000,7 @@ BUILDIN(strcharinfo) * 3 : ::str * 4 : map name *------------------------------------------*/ -BUILDIN(strnpcinfo) +static BUILDIN(strnpcinfo) { char *buf,*name=NULL; struct npc_data *nd; @@ -8866,7 +9057,7 @@ BUILDIN(strnpcinfo) /** * charid2rid: Returns the RID associated to the given character ID */ -BUILDIN(charid2rid) +static BUILDIN(charid2rid) { int cid = script_getnum(st, 2); struct map_session_data *sd = map->charid2sd(cid); @@ -8883,7 +9074,7 @@ BUILDIN(charid2rid) /*========================================== * GetEquipID(Pos); Pos: 1-SCRIPT_EQUIP_TABLE_SIZE *------------------------------------------*/ -BUILDIN(getequipid) +static BUILDIN(getequipid) { int i, num; struct item_data* item; @@ -8919,7 +9110,7 @@ BUILDIN(getequipid) * Get the equipement name at pos * return item jname or "" *------------------------------------------*/ -BUILDIN(getequipname) +static BUILDIN(getequipname) { int i, num; struct item_data* item; @@ -8954,15 +9145,17 @@ BUILDIN(getequipname) /*========================================== * getbrokenid [Valaris] *------------------------------------------*/ -BUILDIN(getbrokenid) +static BUILDIN(getbrokenid) { - int i,num,id=0,brokencounter=0; + int num,id=0,brokencounter=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; num=script_getnum(st,2); - for(i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].card[0] == CARD0_PET) + continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { brokencounter++; if(num==brokencounter) { @@ -8980,14 +9173,16 @@ BUILDIN(getbrokenid) /*========================================== * getbrokencount *------------------------------------------*/ -BUILDIN(getbrokencount) +static BUILDIN(getbrokencount) { int i, counter = 0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - for (i = 0; i < MAX_INVENTORY; i++) { + for (i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].card[0] == CARD0_PET) + continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) counter++; } @@ -9000,22 +9195,23 @@ BUILDIN(getbrokencount) /*========================================== * repair [Valaris] *------------------------------------------*/ -BUILDIN(repair) +static BUILDIN(repair) { - int i,num; int repaircounter=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - num=script_getnum(st,2); - for(i=0; i<MAX_INVENTORY; i++) { + int num = script_getnum(st, 2); + for(int i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].card[0] == CARD0_PET) + continue; if ((sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { repaircounter++; if(num==repaircounter) { sd->status.inventory[i].attribute |= ATTR_BROKEN; sd->status.inventory[i].attribute ^= ATTR_BROKEN; - clif->equiplist(sd); + clif->equipList(sd); clif->produce_effect(sd, 0, sd->status.inventory[i].nameid); clif->misceffect(&sd->bl, 3); break; @@ -9029,15 +9225,17 @@ BUILDIN(repair) /*========================================== * repairall *------------------------------------------*/ -BUILDIN(repairall) +static BUILDIN(repairall) { - int i, repaircounter = 0; + int repaircounter = 0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - for(i = 0; i < MAX_INVENTORY; i++) + for (int i = 0; i < sd->status.inventorySize; i++) { + if (sd->status.inventory[i].card[0] == CARD0_PET) + continue; if (sd->status.inventory[i].nameid && (sd->status.inventory[i].attribute & ATTR_BROKEN) != 0) { sd->status.inventory[i].attribute |= ATTR_BROKEN; @@ -9050,7 +9248,7 @@ BUILDIN(repairall) if(repaircounter) { clif->misceffect(&sd->bl, 3); - clif->equiplist(sd); + clif->equipList(sd); } return true; @@ -9059,7 +9257,7 @@ BUILDIN(repairall) /*========================================== * Chk if player have something equiped at pos *------------------------------------------*/ -BUILDIN(getequipisequiped) +static BUILDIN(getequipisequiped) { int i = -1,num; struct map_session_data *sd; @@ -9086,7 +9284,7 @@ BUILDIN(getequipisequiped) * 1 : true * 0 : false *------------------------------------------*/ -BUILDIN(getequipisenableref) +static BUILDIN(getequipisenableref) { int i = -1,num; struct map_session_data *sd; @@ -9106,13 +9304,42 @@ BUILDIN(getequipisenableref) return true; } +/** + * Checks if the equipped item allows options. + * *getequipisenableopt(<equipment_index>); + * + * @param equipment_index as the inventory index of the equipment. + * @return 1 on enabled 0 on disabled. + */ +static BUILDIN(getequipisenableopt) +{ + int i = -1, index = script_getnum(st, 2); + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, -1); + ShowError("buildin_getequipisenableopt: player is not attached!"); + return false; + } + + if (index > 0 && index <= ARRAYLENGTH(script->equip)) + i = pc->checkequip(sd, script->equip[index - 1]); + + if (i >=0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_options && !sd->status.inventory[i].expire_time) + script_pushint(st, 1); + else + script_pushint(st, 0); + + return true; +} + /*========================================== * Chk if the item equiped at pos is identify (huh ?) * return (npc) * 1 : true * 0 : false *------------------------------------------*/ -BUILDIN(getequipisidentify) +static BUILDIN(getequipisidentify) { int i = -1,num; struct map_session_data *sd; @@ -9138,7 +9365,7 @@ BUILDIN(getequipisidentify) * x : refine amount * 0 : false (not refined) *------------------------------------------*/ -BUILDIN(getequiprefinerycnt) +static BUILDIN(getequiprefinerycnt) { int i = -1,num; struct map_session_data *sd; @@ -9165,7 +9392,7 @@ BUILDIN(getequiprefinerycnt) * x : weapon level * 0 : false *------------------------------------------*/ -BUILDIN(getequipweaponlv) +static BUILDIN(getequipweaponlv) { int i = -1,num; struct map_session_data *sd; @@ -9191,21 +9418,34 @@ BUILDIN(getequipweaponlv) * x : refine chance * 0 : false (max refine level or unequip..) *------------------------------------------*/ -BUILDIN(getequippercentrefinery) { - int i = -1,num; +static BUILDIN(getequippercentrefinery) +{ + int i = -1, num; struct map_session_data *sd; + int type = 0; + + num = script_getnum(st, 2); + type = (script_hasdata(st, 3)) ? script_getnum(st, 3) : REFINE_CHANCE_TYPE_NORMAL; - num = script_getnum(st,2); sd = script->rid2sd(st); - if( sd == NULL ) + if (sd == NULL) return true; + if (type < REFINE_CHANCE_TYPE_NORMAL || type >= REFINE_CHANCE_TYPE_MAX) { + ShowError("buildin_getequippercentrefinery: Invalid type (%d) provided!\n", type); + script_pushint(st, 0); + return false; + } + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) - i=pc->checkequip(sd,script->equip[num-1]); - if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE) - script_pushint(st,status->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int)sd->status.inventory[i].refine)); + i = pc->checkequip(sd, script->equip[num - 1]); + + if (i >= 0 && sd->status.inventory[i].nameid != 0 && sd->status.inventory[i].refine < MAX_REFINE) + script_pushint(st, + status->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int) sd->status.inventory[i].refine, (enum refine_chance_type) type)); else - script_pushint(st,0); + script_pushint(st, 0); return true; } @@ -9213,7 +9453,7 @@ BUILDIN(getequippercentrefinery) { /*========================================== * Refine +1 item at pos and log and display refine *------------------------------------------*/ -BUILDIN(successrefitem) +static BUILDIN(successrefitem) { int i = -1 , num, up = 1; struct map_session_data *sd; @@ -9250,6 +9490,11 @@ BUILDIN(successrefitem) clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); clif->misceffect(&sd->bl,3); + + achievement->validate_refine(sd, i, true); // Achievements [Smokexyz/Hercules] + + /* The following check is exclusive to characters (possibly only whitesmiths) + * that create equipments and refine them to level 10. */ if(sd->status.inventory[i].refine == 10 && sd->status.inventory[i].card[0] == CARD0_FORGE && sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3]) @@ -9274,7 +9519,7 @@ BUILDIN(successrefitem) /*========================================== * Show a failed Refine +1 attempt *------------------------------------------*/ -BUILDIN(failedrefitem) +static BUILDIN(failedrefitem) { int i=-1,num; struct map_session_data *sd; @@ -9287,6 +9532,9 @@ BUILDIN(failedrefitem) if (num > 0 && num <= ARRAYLENGTH(script->equip)) i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { + // Call before changing refine to 0. + achievement->validate_refine(sd, i, false); + sd->status.inventory[i].refine = 0; pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE); //recalculate bonus clif->refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure @@ -9302,7 +9550,7 @@ BUILDIN(failedrefitem) /*========================================== * Downgrades an Equipment Part by -1 . [Masao] *------------------------------------------*/ -BUILDIN(downrefitem) +static BUILDIN(downrefitem) { int i = -1, num, down = 1; struct map_session_data *sd; @@ -9334,6 +9582,9 @@ BUILDIN(downrefitem) clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); + + achievement->validate_refine(sd, i, false); // Achievements [Smokexyz/Hercules] + clif->misceffect(&sd->bl,2); } @@ -9343,7 +9594,7 @@ BUILDIN(downrefitem) /*========================================== * Delete the item equipped at pos. *------------------------------------------*/ -BUILDIN(delequip) +static BUILDIN(delequip) { int i=-1,num; struct map_session_data *sd; @@ -9371,7 +9622,8 @@ BUILDIN(delequip) /*========================================== * *------------------------------------------*/ -BUILDIN(statusup) { +static BUILDIN(statusup) +{ int type; struct map_session_data *sd; @@ -9387,7 +9639,7 @@ BUILDIN(statusup) { /*========================================== * *------------------------------------------*/ -BUILDIN(statusup2) +static BUILDIN(statusup2) { int type,val; struct map_session_data *sd; @@ -9403,6 +9655,25 @@ BUILDIN(statusup2) return true; } + +/*========================================== +* Returns the number of stat points needed to change the specified stat by val. +* needed_status_point(<type>,<val>{,<char id>}); [secretdataz] +*------------------------------------------*/ +static BUILDIN(needed_status_point) +{ + int type = script_getnum(st, 2); + int val = script_getnum(st, 3);; + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) + script_pushint(st, 0); + else + script_pushint(st, pc->need_status_point(sd, type, val)); + + return true; +} + /// See 'doc/item_bonus.txt' /// /// bonus <bonus type>,<val1>; @@ -9410,7 +9681,8 @@ BUILDIN(statusup2) /// bonus3 <bonus type>,<val1>,<val2>,<val3>; /// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>; /// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>; -BUILDIN(bonus) { +static BUILDIN(bonus) +{ int type; int val1; int val2 = 0; @@ -9492,7 +9764,7 @@ BUILDIN(bonus) { return true; } -BUILDIN(autobonus) +static BUILDIN(autobonus) { unsigned int dur; short rate; @@ -9527,7 +9799,7 @@ BUILDIN(autobonus) return true; } -BUILDIN(autobonus2) +static BUILDIN(autobonus2) { unsigned int dur; short rate; @@ -9562,7 +9834,7 @@ BUILDIN(autobonus2) return true; } -BUILDIN(autobonus3) +static BUILDIN(autobonus3) { unsigned int dur; short rate,atk_type; @@ -9605,7 +9877,8 @@ BUILDIN(autobonus3) /// skill <skill id>,<level> /// skill "<skill name>",<level>,<flag> /// skill "<skill name>",<level> -BUILDIN(skill) { +static BUILDIN(skill) +{ int id; int level; int flag = SKILL_GRANT_TEMPORARY; @@ -9631,7 +9904,8 @@ BUILDIN(skill) { /// addtoskill "<skill name>",<amount> /// /// @see skill -BUILDIN(addtoskill) { +static BUILDIN(addtoskill) +{ int id; int level; int flag = SKILL_GRANT_TEMPSTACK; @@ -9652,7 +9926,8 @@ BUILDIN(addtoskill) { /// /// guildskill <skill id>,<amount>; /// guildskill "<skill name>",<amount>; -BUILDIN(guildskill) { +static BUILDIN(guildskill) +{ int skill_id, id, max_points; int level; @@ -9691,7 +9966,7 @@ BUILDIN(guildskill) { /// /// getskilllv(<skill id>) -> <level> /// getskilllv("<skill name>") -> <level> -BUILDIN(getskilllv) +static BUILDIN(getskilllv) { int id; struct map_session_data *sd = script->rid2sd(st); @@ -9708,7 +9983,8 @@ BUILDIN(getskilllv) /// /// getgdskilllv(<guild id>,<skill id>) -> <level> /// getgdskilllv(<guild id>,"<skill name>") -> <level> -BUILDIN(getgdskilllv) { +static BUILDIN(getgdskilllv) +{ int guild_id; uint16 skill_id; struct guild* g; @@ -9729,7 +10005,7 @@ BUILDIN(getgdskilllv) { /// before allowing the basic actions. /// /// basicskillcheck() -> <bool> -BUILDIN(basicskillcheck) +static BUILDIN(basicskillcheck) { script_pushint(st, battle_config.basic_skill_check); return true; @@ -9738,7 +10014,7 @@ BUILDIN(basicskillcheck) /// Returns the GM level of the player. /// /// getgmlevel() -> <level> -BUILDIN(getgmlevel) +static BUILDIN(getgmlevel) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -9752,7 +10028,8 @@ BUILDIN(getgmlevel) /// set the group ID of the player. /// setgroupid(<new group id>{,"<character name>"|<account id>}) /// return 1 on success, 0 if failed. -BUILDIN(setgroupid) { +static BUILDIN(setgroupid) +{ struct map_session_data* sd = NULL; int new_group = script_getnum(st, 2); @@ -9775,21 +10052,31 @@ BUILDIN(setgroupid) { /// Returns the group ID of the player. /// -/// getgroupid() -> <int> -BUILDIN(getgroupid) +/// getgroupid({<account id>}) -> <int> +static BUILDIN(getgroupid) { - struct map_session_data *sd = script->rid2sd(st); - if (sd == NULL) + struct map_session_data *sd = NULL; + + if (script_hasdata(st, 2)) { + sd = map->id2sd(script_getnum(st, 2)); + } else { + sd = script->rid2sd(st); + } + + if (sd == NULL) { + script_pushint(st, -1); return true; // no player attached, report source - script_pushint(st, pc_get_group_id(sd)); + } + script_pushint(st, pc_get_group_id(sd)); return true; } /// Terminates the execution of this script instance. /// /// end -BUILDIN(end) { +static BUILDIN(end) +{ st->state = END; /* are we stopping inside a function? */ @@ -9809,10 +10096,16 @@ BUILDIN(end) { /// Checks if the player has that effect state (option). /// /// checkoption(<option>) -> <bool> -BUILDIN(checkoption) +static BUILDIN(checkoption) { int option; - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd; + + if (script_hasdata(st, 3)) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = script->rid2sd(st); + if (sd == NULL) return true;// no player attached, report source @@ -9828,10 +10121,16 @@ BUILDIN(checkoption) /// Checks if the player is in that body state (opt1). /// /// checkoption1(<opt1>) -> <bool> -BUILDIN(checkoption1) +static BUILDIN(checkoption1) { int opt1; - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd; + + if (script_hasdata(st, 3)) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = script->rid2sd(st); + if (sd == NULL) return true;// no player attached, report source @@ -9847,10 +10146,16 @@ BUILDIN(checkoption1) /// Checks if the player has that health state (opt2). /// /// checkoption2(<opt2>) -> <bool> -BUILDIN(checkoption2) +static BUILDIN(checkoption2) { int opt2; - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd; + + if (script_hasdata(st, 3)) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = script->rid2sd(st); + if (sd == NULL) return true;// no player attached, report source @@ -9870,11 +10175,17 @@ BUILDIN(checkoption2) /// /// setoption <option>,<flag>; /// setoption <option>; -BUILDIN(setoption) +static BUILDIN(setoption) { int option; int flag = 1; - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd; + + if (script_hasdata(st, 4)) + sd = map->id2sd(script_getnum(st, 4)); + else + sd = script->rid2sd(st); + if (sd == NULL) return true;// no player attached, report source @@ -9903,7 +10214,7 @@ BUILDIN(setoption) /// checkcart() -> <bool> /// /// @author Valaris -BUILDIN(checkcart) +static BUILDIN(checkcart) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -9928,7 +10239,7 @@ BUILDIN(checkcart) /// /// setcart <type>; /// setcart; -BUILDIN(setcart) +static BUILDIN(setcart) { int type = 1; struct map_session_data *sd = script->rid2sd(st); @@ -9947,7 +10258,7 @@ BUILDIN(setcart) /// checkfalcon() -> <bool> /// /// @author Valaris -BUILDIN(checkfalcon) +static BUILDIN(checkfalcon) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -9966,7 +10277,7 @@ BUILDIN(checkfalcon) /// /// setfalcon <flag>; /// setfalcon; -BUILDIN(setfalcon) +static BUILDIN(setfalcon) { bool flag = true; struct map_session_data *sd = script->rid2sd(st); @@ -10003,7 +10314,7 @@ enum setmount_type { * The exact returned values are the same used as flag in setmount, except for * dragons, where SETMOUNT_TYPE_DRAGON is returned, regardless of color. */ -BUILDIN(checkmount) +static BUILDIN(checkmount) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -10046,7 +10357,7 @@ BUILDIN(checkmount) * auto-detected. As a result of this, there is no need to specify a flag at * all, unless it is a dragon color other than green. */ -BUILDIN(setmount) +static BUILDIN(setmount) { int flag = SETMOUNT_TYPE_AUTODETECT; struct map_session_data *sd = script->rid2sd(st); @@ -10111,7 +10422,7 @@ BUILDIN(setmount) /// /// checkwug() -> <bool> /// -BUILDIN(checkwug) +static BUILDIN(checkwug) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -10129,7 +10440,8 @@ BUILDIN(checkwug) /// /// save "<map name>",<x>,<y> /// savepoint "<map name>",<x>,<y> -BUILDIN(savepoint) { +static BUILDIN(savepoint) +{ int x; int y; short mapid; @@ -10151,7 +10463,9 @@ BUILDIN(savepoint) { /*========================================== * GetTimeTick(0: System Tick, 1: Time Second Tick) *------------------------------------------*/ -BUILDIN(gettimetick) { /* Asgard Version */ +/* Asgard Version */ +static BUILDIN(gettimetick) +{ int type; time_t clock; struct tm *t; @@ -10184,7 +10498,9 @@ BUILDIN(gettimetick) { /* Asgard Version */ * 4: WeekDay 5: MonthDay 6: Month * 7: Year *------------------------------------------*/ -BUILDIN(gettime) { /* Asgard Version */ +/* Asgard Version */ +static BUILDIN(gettime) +{ int type; time_t clock; struct tm *t; @@ -10229,7 +10545,7 @@ BUILDIN(gettime) { /* Asgard Version */ /*========================================== * GetTimeStr("TimeFMT", Length); *------------------------------------------*/ -BUILDIN(gettimestr) +static BUILDIN(gettimestr) { char *tmpstr; const char *fmtstr; @@ -10250,17 +10566,25 @@ BUILDIN(gettimestr) /*========================================== * Open player storage *------------------------------------------*/ -BUILDIN(openstorage) +static BUILDIN(openstorage) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) - return true; + return false; + + if (sd->storage.received == false) { + script_pushint(st, 0); + ShowWarning("buildin_openstorage: Storage data for AID %d has not been loaded.\n", sd->bl.id); + return false; + } storage->open(sd); + + script_pushint(st, 1); // success flag. return true; } -BUILDIN(guildopenstorage) +static BUILDIN(guildopenstorage) { int ret; struct map_session_data *sd = script->rid2sd(st); @@ -10277,7 +10601,7 @@ BUILDIN(guildopenstorage) *------------------------------------------*/ /// itemskill <skill id>,<level>{,flag /// itemskill "<skill name>",<level>{,flag -BUILDIN(itemskill) +static BUILDIN(itemskill) { int id; int lv; @@ -10302,7 +10626,7 @@ BUILDIN(itemskill) /*========================================== * Attempt to create an item *------------------------------------------*/ -BUILDIN(produce) +static BUILDIN(produce) { int trigger; struct map_session_data *sd = script->rid2sd(st); @@ -10316,7 +10640,7 @@ BUILDIN(produce) /*========================================== * *------------------------------------------*/ -BUILDIN(cooking) +static BUILDIN(cooking) { int trigger; struct map_session_data *sd = script->rid2sd(st); @@ -10330,7 +10654,7 @@ BUILDIN(cooking) /*========================================== * Create a pet *------------------------------------------*/ -BUILDIN(makepet) +static BUILDIN(makepet) { struct map_session_data *sd; int id,pet_id; @@ -10348,7 +10672,7 @@ BUILDIN(makepet) sd->catch_target_class = pet->db[pet_id].class_; intif->create_pet(sd->status.account_id, sd->status.char_id, (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv, - (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, + pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, 100, 0, 1, pet->db[pet_id].jname); } @@ -10357,7 +10681,7 @@ BUILDIN(makepet) /*========================================== * Give player exp base,job * quest_exp_rate/100 *------------------------------------------*/ -BUILDIN(getexp) +static BUILDIN(getexp) { int base=0,job=0; struct map_session_data *sd = script->rid2sd(st); @@ -10381,7 +10705,7 @@ BUILDIN(getexp) /*========================================== * Gain guild exp [Celest] *------------------------------------------*/ -BUILDIN(guildgetexp) +static BUILDIN(guildgetexp) { int exp; struct map_session_data *sd = script->rid2sd(st); @@ -10400,7 +10724,7 @@ BUILDIN(guildgetexp) /*========================================== * Changes the guild master of a guild [Skotlex] *------------------------------------------*/ -BUILDIN(guildchangegm) +static BUILDIN(guildchangegm) { struct map_session_data *sd; int guild_id; @@ -10413,7 +10737,7 @@ BUILDIN(guildchangegm) if (sd == NULL) script_pushint(st,0); else - script_pushint(st,guild->gm_change(guild_id, sd)); + script_pushint(st, guild->gm_change(guild_id, sd->status.char_id)); return true; } @@ -10426,7 +10750,7 @@ BUILDIN(guildchangegm) * @amount : nb to spawn * @event : event to attach to mob *------------------------------------------*/ -BUILDIN(monster) +static BUILDIN(monster) { const char *mapn = script_getstr(st,2); int x = script_getnum(st,3); @@ -10498,7 +10822,7 @@ BUILDIN(monster) /*========================================== * Request List of Monster Drops *------------------------------------------*/ -BUILDIN(getmobdrops) +static BUILDIN(getmobdrops) { int class_ = script_getnum(st,2); int i, j = 0; @@ -10519,13 +10843,13 @@ BUILDIN(getmobdrops) if( itemdb->exists(monster->dropitem[i].nameid) == NULL ) continue; - mapreg->setreg(reference_uid(script->add_str("$@MobDrop_item"), j), monster->dropitem[i].nameid); - mapreg->setreg(reference_uid(script->add_str("$@MobDrop_rate"), j), monster->dropitem[i].p); + mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_item"), j), monster->dropitem[i].nameid); + mapreg->setreg(reference_uid(script->add_variable("$@MobDrop_rate"), j), monster->dropitem[i].p); j++; } - mapreg->setreg(script->add_str("$@MobDrop_count"), j); + mapreg->setreg(script->add_variable("$@MobDrop_count"), j); script_pushint(st, 1); return true; @@ -10533,7 +10857,8 @@ BUILDIN(getmobdrops) /*========================================== * Same as monster but randomize location in x0,x1,y0,y1 area *------------------------------------------*/ -BUILDIN(areamonster) { +static BUILDIN(areamonster) +{ const char *mapn = script_getstr(st,2); int x0 = script_getnum(st,3); int y0 = script_getnum(st,4); @@ -10596,7 +10921,7 @@ BUILDIN(areamonster) { /*========================================== * KillMonster subcheck, verify if mob to kill ain't got an even to handle, could be force kill by allflag *------------------------------------------*/ -int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap) +static int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap) { //same fix but with killmonster instead - stripping events from mobs. struct mob_data *md = NULL; @@ -10619,7 +10944,7 @@ int buildin_killmonster_sub_strip(struct block_list *bl, va_list ap) md->state.npc_killmonster = 0; return 0; } -int buildin_killmonster_sub(struct block_list *bl, va_list ap) +static int buildin_killmonster_sub(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; char *event = va_arg(ap,char *); @@ -10638,7 +10963,8 @@ int buildin_killmonster_sub(struct block_list *bl, va_list ap) } return 0; } -BUILDIN(killmonster) { +static BUILDIN(killmonster) +{ const char *mapname,*event; int16 m,allflag=0; mapname=script_getstr(st,2); @@ -10667,7 +10993,7 @@ BUILDIN(killmonster) { return true; } -int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap) +static int buildin_killmonsterall_sub_strip(struct block_list *bl, va_list ap) { //Strips the event from the mob if it's killed the old method. struct mob_data *md; @@ -10679,12 +11005,13 @@ int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap) status_kill(bl); return 0; } -int buildin_killmonsterall_sub(struct block_list *bl,va_list ap) +static int buildin_killmonsterall_sub(struct block_list *bl, va_list ap) { status_kill(bl); return 0; } -BUILDIN(killmonsterall) { +static BUILDIN(killmonsterall) +{ const char *mapname; int16 m; mapname=script_getstr(st,2); @@ -10710,7 +11037,8 @@ BUILDIN(killmonsterall) { * Creates a clone of a player. * clone map, x, y, event, char_id, master_id, mode, flag, duration *------------------------------------------*/ -BUILDIN(clone) { +static BUILDIN(clone) +{ struct map_session_data *sd, *msd = NULL; int char_id, master_id = 0, x, y, flag = 0, m; uint32 mode = 0; @@ -10758,7 +11086,7 @@ BUILDIN(clone) { } /*========================================== *------------------------------------------*/ -BUILDIN(doevent) +static BUILDIN(doevent) { const char* event = script_getstr(st,2); struct map_session_data* sd; @@ -10774,7 +11102,7 @@ BUILDIN(doevent) } /*========================================== *------------------------------------------*/ -BUILDIN(donpcevent) +static BUILDIN(donpcevent) { const char* event = script_getstr(st,2); script->check_event(st, event); @@ -10789,7 +11117,7 @@ BUILDIN(donpcevent) /*========================================== *------------------------------------------*/ -BUILDIN(addtimer) +static BUILDIN(addtimer) { int tick = script_getnum(st, 2); const char* event = script_getstr(st, 3); @@ -10818,7 +11146,7 @@ BUILDIN(addtimer) } /*========================================== *------------------------------------------*/ -BUILDIN(deltimer) +static BUILDIN(deltimer) { const char *event; struct map_session_data *sd; @@ -10839,7 +11167,7 @@ BUILDIN(deltimer) } /*========================================== *------------------------------------------*/ -BUILDIN(addtimercount) +static BUILDIN(addtimercount) { const char *event; int tick; @@ -10861,9 +11189,232 @@ BUILDIN(addtimercount) return true; } +enum gettimer_mode { + GETTIMER_COUNT = 0, + GETTIMER_TICK_NEXT = 1, + GETTIMER_TICK_LAST = 2, +}; + +static BUILDIN(gettimer) +{ + struct map_session_data *sd; + const struct TimerData *td; + int i; + int tick; + const char *event = NULL; + int val = 0; + bool first = true; + short mode = script_getnum(st, 2); + + if (script_hasdata(st, 3)) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = script->rid2sd(st); + + if (script_hasdata(st, 4)) { + event = script_getstr(st, 4); + script->check_event(st, event); + } + + if (sd == NULL) { + script_pushint(st, -1); + return true; + } + + switch (mode) { + case GETTIMER_COUNT: + // get number of timers + for (i = 0; i < MAX_EVENTTIMER; i++) { + if (sd->eventtimer[i] != INVALID_TIMER) { + if (event != NULL) { + td = timer->get(sd->eventtimer[i]); + Assert_retr(false, td != NULL); + + if (strcmp((char *)(td->data), event) == 0) { + val++; + } + } else { + val++; + } + } + } + break; + case GETTIMER_TICK_NEXT: + // get the number of tick before the next timer runs + for (i = 0; i < MAX_EVENTTIMER; i++) { + if (sd->eventtimer[i] != INVALID_TIMER) { + td = timer->get(sd->eventtimer[i]); + Assert_retr(false, td != NULL); + tick = max(0, DIFF_TICK32(td->tick, timer->gettick())); + + if (event != NULL) { + if ((first == true || tick < val) && strcmp((char *)(td->data), event) == 0) { + val = tick; + first = false; + } + } else if (first == true || tick < val) { + val = tick; + first = false; + } + } + } + break; + case GETTIMER_TICK_LAST: + // get the number of ticks before the last timer runs + for (i = MAX_EVENTTIMER - 1; i >= 0; i--) { + if (sd->eventtimer[i] != INVALID_TIMER) { + td = timer->get(sd->eventtimer[i]); + Assert_retr(false, td != NULL); + tick = max(0, DIFF_TICK32(td->tick, timer->gettick())); + + if (event != NULL) { + if (strcmp((char *)(td->data), event) == 0) { + val = max(val, tick); + } + } else { + val = max(val, tick); + } + } + } + break; + } + + script_pushint(st, val); + return true; +} + +static int buildin_getunits_sub(struct block_list *bl, va_list ap) +{ + struct script_state *st = va_arg(ap, struct script_state *); + struct map_session_data *sd = va_arg(ap, struct map_session_data *); + int32 id = va_arg(ap, int32); + uint32 start = va_arg(ap, uint32); + uint32 *count = va_arg(ap, uint32 *); + uint32 limit = va_arg(ap, uint32); + const char *name = va_arg(ap, const char *); + struct reg_db *ref = va_arg(ap, struct reg_db *); + enum bl_type type = va_arg(ap, enum bl_type); + uint32 index = start + *count; + + if ((bl->type & type) == 0) { + return 0; // type mismatch => skip + } + + if (index >= SCRIPT_MAX_ARRAYSIZE || *count >= limit) { + return -1; + } + + script->set_reg(st, sd, reference_uid(id, index), name, + (const void *)h64BPTRSIZE(bl->id), ref); + + (*count)++; + return 1; +} + +static int buildin_getunits_sub_pc(struct map_session_data *sd, va_list ap) +{ + return buildin_getunits_sub(&sd->bl, ap); +} + +static int buildin_getunits_sub_mob(struct mob_data *md, va_list ap) +{ + return buildin_getunits_sub(&md->bl, ap); +} + +static int buildin_getunits_sub_npc(struct npc_data *nd, va_list ap) +{ + return buildin_getunits_sub(&nd->bl, ap); +} + +static BUILDIN(getunits) +{ + const char *name; + int32 id; + uint32 start; + struct reg_db *ref; + enum bl_type type = script_getnum(st, 2); + struct script_data *data = script_getdata(st, 3); + uint32 count = 0; + uint32 limit = script_getnum(st, 4); + struct map_session_data *sd = NULL; + + if (!data_isreference(data) || reference_toconstant(data)) { + ShowError("script:getunits: second argument must be a variable\n"); + script->reportdata(data); + st->state = END; + return false; + } + + id = reference_getid(data); + start = reference_getindex(data); + name = reference_getname(data); + ref = reference_getref(data); + + if (not_server_variable(*name)) { + sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, 0); + return true; // player variable but no player attached + } + } + + if (is_string_variable(name)) { + ShowError("script:getunits: second argument must be an integer variable\n"); + script->reportdata(data); + st->state = END; + return false; + } + + if (limit < 1 || limit > SCRIPT_MAX_ARRAYSIZE) { + limit = SCRIPT_MAX_ARRAYSIZE; + } + + if (script_hasdata(st, 5)) { + const char *mapname = script_getstr(st, 5); + int16 m = map->mapname2mapid(mapname); + + if (script_hasdata(st, 9)) { + int16 x1 = script_getnum(st, 6); + int16 y1 = script_getnum(st, 7); + int16 x2 = script_getnum(st, 8); + int16 y2 = script_getnum(st, 9); + + map->forcountinarea(buildin_getunits_sub, m, x1, y1, x2, y2, limit, type, + st, sd, id, start, &count, limit, name, ref, type); + } else { + map->forcountinmap(buildin_getunits_sub, m, limit, type, + st, sd, id, start, &count, limit, name, ref, type); + } + } else { + // for faster lookup we try to reduce the scope of the search if possible + switch (type) { + case BL_PC: + map->foreachpc(buildin_getunits_sub_pc, + st, sd, id, start, &count, limit, name, ref, type); + break; + case BL_MOB: + map->foreachmob(buildin_getunits_sub_mob, + st, sd, id, start, &count, limit, name, ref, type); + break; + case BL_NPC: + map->foreachnpc(buildin_getunits_sub_npc, + st, sd, id, start, &count, limit, name, ref, type); + break; + default: + // fallback to global lookup (slowest option) + map->foreachiddb(buildin_getunits_sub, + st, sd, id, start, &count, limit, name, ref, type); + } + } + + script_pushint(st, count); + return true; +} + /*========================================== *------------------------------------------*/ -BUILDIN(initnpctimer) +static BUILDIN(initnpctimer) { struct npc_data *nd; int flag = 0; @@ -10908,7 +11459,7 @@ BUILDIN(initnpctimer) } /*========================================== *------------------------------------------*/ -BUILDIN(startnpctimer) +static BUILDIN(startnpctimer) { struct npc_data *nd; int flag = 0; @@ -10951,7 +11502,8 @@ BUILDIN(startnpctimer) } /*========================================== *------------------------------------------*/ -BUILDIN(stopnpctimer) { +static BUILDIN(stopnpctimer) +{ struct npc_data *nd; int flag = 0; @@ -10989,7 +11541,7 @@ BUILDIN(stopnpctimer) { } /*========================================== *------------------------------------------*/ -BUILDIN(getnpctimer) +static BUILDIN(getnpctimer) { struct npc_data *nd; struct map_session_data *sd; @@ -11027,7 +11579,7 @@ BUILDIN(getnpctimer) } /*========================================== *------------------------------------------*/ -BUILDIN(setnpctimer) +static BUILDIN(setnpctimer) { int tick; struct npc_data *nd; @@ -11052,7 +11604,7 @@ BUILDIN(setnpctimer) /*========================================== * attaches the player rid to the timer [Celest] *------------------------------------------*/ -BUILDIN(attachnpctimer) +static BUILDIN(attachnpctimer) { struct map_session_data *sd; struct npc_data *nd = map->id2nd(st->oid); @@ -11081,7 +11633,8 @@ BUILDIN(attachnpctimer) /*========================================== * detaches a player rid from the timer [Celest] *------------------------------------------*/ -BUILDIN(detachnpctimer) { +static BUILDIN(detachnpctimer) +{ struct npc_data *nd; if( script_hasdata(st,2) ) @@ -11105,7 +11658,8 @@ BUILDIN(detachnpctimer) { * it checks if there is a player attached to the current script. [Skotlex] * If no, returns 0, if yes, returns the account_id of the attached player. *------------------------------------------*/ -BUILDIN(playerattached) { +static BUILDIN(playerattached) +{ if(st->rid == 0 || map->id2sd(st->rid) == NULL) script_pushint(st,0); else @@ -11115,7 +11669,7 @@ BUILDIN(playerattached) { /*========================================== *------------------------------------------*/ -BUILDIN(announce) +static BUILDIN(announce) { const char *mes = script_getstr(st,2); int flag = script_getnum(st,3); @@ -11163,7 +11717,7 @@ BUILDIN(announce) } /*========================================== *------------------------------------------*/ -int buildin_announce_sub(struct block_list *bl, va_list ap) +static int buildin_announce_sub(struct block_list *bl, va_list ap) { const char *mes = va_arg(ap, const char *); int len = va_arg(ap, int); @@ -11182,7 +11736,7 @@ int buildin_announce_sub(struct block_list *bl, va_list ap) /* Runs item effect on attached character. * itemeffect <item id>; * itemeffect "<item name>"; */ -BUILDIN(itemeffect) +static BUILDIN(itemeffect) { struct npc_data *nd; struct item_data *item_data; @@ -11215,7 +11769,7 @@ BUILDIN(itemeffect) return true; } -BUILDIN(mapannounce) +static BUILDIN(mapannounce) { const char *mapname = script_getstr(st,2); const char *mes = script_getstr(st,3); @@ -11238,7 +11792,7 @@ BUILDIN(mapannounce) } /*========================================== *------------------------------------------*/ -BUILDIN(areaannounce) +static BUILDIN(areaannounce) { const char *mapname = script_getstr(st,2); int x0 = script_getnum(st,3); @@ -11266,7 +11820,8 @@ BUILDIN(areaannounce) /*========================================== *------------------------------------------*/ -BUILDIN(getusers) { +static BUILDIN(getusers) +{ int flag, val = 0; struct map_session_data* sd; struct block_list* bl = NULL; @@ -11302,7 +11857,7 @@ BUILDIN(getusers) { /*========================================== * Works like @WHO - displays all online users names in window *------------------------------------------*/ -BUILDIN(getusersname) +static BUILDIN(getusersname) { struct map_session_data *sd; const struct map_session_data *pl_sd; @@ -11331,7 +11886,7 @@ BUILDIN(getusersname) /*========================================== * getmapguildusers("mapname",guild ID) Returns the number guild members present on a map [Reddozen] *------------------------------------------*/ -BUILDIN(getmapguildusers) +static BUILDIN(getmapguildusers) { const char *str; int16 m; @@ -11359,7 +11914,8 @@ BUILDIN(getmapguildusers) } /*========================================== *------------------------------------------*/ -BUILDIN(getmapusers) { +static BUILDIN(getmapusers) +{ const char *str; int16 m; str=script_getstr(st,2); @@ -11372,7 +11928,7 @@ BUILDIN(getmapusers) { } /*========================================== *------------------------------------------*/ -int buildin_getareausers_sub(struct block_list *bl,va_list ap) +static int buildin_getareausers_sub(struct block_list *bl, va_list ap) { int *users=va_arg(ap,int *); nullpo_ret(users); @@ -11380,7 +11936,7 @@ int buildin_getareausers_sub(struct block_list *bl,va_list ap) return 0; } -BUILDIN(getareausers) +static BUILDIN(getareausers) { int16 m = -1, x0, y0, x1, y1; int users = 0; @@ -11440,7 +11996,7 @@ BUILDIN(getareausers) /*========================================== *------------------------------------------*/ -int buildin_getareadropitem_sub(struct block_list *bl, va_list ap) +static int buildin_getareadropitem_sub(struct block_list *bl, va_list ap) { int item = va_arg(ap, int); int *amount = va_arg(ap, int *); @@ -11456,7 +12012,8 @@ int buildin_getareadropitem_sub(struct block_list *bl, va_list ap) return 0; } -BUILDIN(getareadropitem) { +static BUILDIN(getareadropitem) +{ const char *str; int16 m,x0,y0,x1,y1; int item,amount=0; @@ -11488,7 +12045,7 @@ BUILDIN(getareadropitem) { } /*========================================== *------------------------------------------*/ -BUILDIN(enablenpc) +static BUILDIN(enablenpc) { const char *str; str=script_getstr(st,2); @@ -11497,7 +12054,7 @@ BUILDIN(enablenpc) } /*========================================== *------------------------------------------*/ -BUILDIN(disablenpc) +static BUILDIN(disablenpc) { const char *str; str=script_getstr(st,2); @@ -11507,7 +12064,7 @@ BUILDIN(disablenpc) /*========================================== *------------------------------------------*/ -BUILDIN(hideoffnpc) +static BUILDIN(hideoffnpc) { const char *str; str=script_getstr(st,2); @@ -11516,7 +12073,7 @@ BUILDIN(hideoffnpc) } /*========================================== *------------------------------------------*/ -BUILDIN(hideonnpc) +static BUILDIN(hideonnpc) { const char *str; str=script_getstr(st,2); @@ -11531,7 +12088,7 @@ BUILDIN(hideonnpc) * sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<rate,<flag>,{<unit_id>}}; * <flag>: @see enum scstart_flag */ -BUILDIN(sc_start) +static BUILDIN(sc_start) { struct npc_data *nd = map->id2nd(st->oid); struct block_list* bl; @@ -11599,7 +12156,8 @@ BUILDIN(sc_start) /// Ends one or all status effects on the target unit or on the attached player. /// /// sc_end <effect_id>{,<unit_id>}; -BUILDIN(sc_end) { +static BUILDIN(sc_end) +{ struct block_list* bl; int type; @@ -11634,7 +12192,9 @@ BUILDIN(sc_end) { } //This should help status_change_end force disabling the SC in case it has no limit. - sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0; + if (type != SC_BERSERK) + sce->val1 = 0; // SC_BERSERK requires skill_lv that's stored in sce->val1 when being removed [KirieZ] + sce->val2 = sce->val3 = sce->val4 = 0; status_change_end(bl, (sc_type)type, INVALID_TIMER); } else @@ -11646,7 +12206,8 @@ BUILDIN(sc_end) { /*========================================== * @FIXME atm will return reduced tick, 0 immune, 1 no tick *------------------------------------------*/ -BUILDIN(getscrate) { +static BUILDIN(getscrate) +{ struct block_list *bl; int type,rate; @@ -11667,7 +12228,7 @@ BUILDIN(getscrate) { /*========================================== * getstatus <type>{, <info>}; *------------------------------------------*/ -BUILDIN(getstatus) +static BUILDIN(getstatus) { int id, type; struct map_session_data* sd = script->rid2sd(st); @@ -11698,14 +12259,16 @@ BUILDIN(getstatus) case 3: script_pushint(st, sd->sc.data[id]->val3); break; case 4: script_pushint(st, sd->sc.data[id]->val4); break; case 5: - { - const struct TimerData *td = timer->get(sd->sc.data[id]->timer); + if (sd->sc.data[id]->infinite_duration) { + script_pushint(st, INFINITE_DURATION); + } else { + const struct TimerData *td = timer->get(sd->sc.data[id]->timer); - if (td != NULL) { - // return the amount of time remaining - script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values + if (td != NULL) { + // return the amount of time remaining + script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values + } } - } break; default: script_pushint(st, 1); break; } @@ -11716,17 +12279,26 @@ BUILDIN(getstatus) /*========================================== * *------------------------------------------*/ -BUILDIN(debugmes) +static BUILDIN(debugmes) { - const char *str; - str=script_getstr(st,2); - ShowDebug("script debug : %d %d : %s\n",st->rid,st->oid,str); + struct StringBuf buf; + StrBuf->Init(&buf); + + if (!script->sprintf_helper(st, 2, &buf)) { + StrBuf->Destroy(&buf); + script_pushint(st, 0); + return false; + } + + ShowDebug("script debug : %d %d : %s\n", st->rid, st->oid, StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); + script_pushint(st, 1); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(catchpet) +static BUILDIN(catchpet) { int pet_id; struct map_session_data *sd; @@ -11743,7 +12315,7 @@ BUILDIN(catchpet) /*========================================== * [orn] *------------------------------------------*/ -BUILDIN(homunculus_evolution) +static BUILDIN(homunculus_evolution) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11763,7 +12335,7 @@ BUILDIN(homunculus_evolution) * Checks for vaporized morph state * and deletes ITEMID_STRANGE_EMBRYO. *------------------------------------------*/ -BUILDIN(homunculus_mutate) +static BUILDIN(homunculus_mutate) { bool success = false; struct map_session_data *sd = script->rid2sd(st); @@ -11777,7 +12349,7 @@ BUILDIN(homunculus_mutate) if (script_hasdata(st,2)) homun_id = script_getnum(st,2); else - homun_id = 6048 + (rnd() % 4); + homun_id = HOMID_EIRA + (rnd() % 4); m_class = homun->class2type(sd->hd->homunculus.class_); m_id = homun->class2type(homun_id); @@ -11804,7 +12376,7 @@ BUILDIN(homunculus_mutate) * Puts homunculus into morph state * and gives ITEMID_STRANGE_EMBRYO. *------------------------------------------*/ -BUILDIN(homunculus_morphembryo) +static BUILDIN(homunculus_morphembryo) { bool success = false; struct map_session_data *sd = script->rid2sd(st); @@ -11847,7 +12419,7 @@ BUILDIN(homunculus_morphembryo) * 1 = Homunculus is vaporized (rest) * 2 = Homunculus is in morph state *------------------------------------------*/ -BUILDIN(homunculus_checkcall) +static BUILDIN(homunculus_checkcall) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || sd->hd == NULL) @@ -11859,7 +12431,7 @@ BUILDIN(homunculus_checkcall) } // [Zephyrus] -BUILDIN(homunculus_shuffle) +static BUILDIN(homunculus_shuffle) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11872,7 +12444,7 @@ BUILDIN(homunculus_shuffle) } //These two functions bring the eA MAPID_* class functionality to scripts. -BUILDIN(eaclass) +static BUILDIN(eaclass) { int class; if (script_hasdata(st,2)) { @@ -11887,7 +12459,7 @@ BUILDIN(eaclass) return true; } -BUILDIN(roclass) +static BUILDIN(roclass) { int job = script_getnum(st,2); int sex; @@ -11907,7 +12479,7 @@ BUILDIN(roclass) /*========================================== * Tells client to open a hatching window, used for pet incubator *------------------------------------------*/ -BUILDIN(birthpet) +static BUILDIN(birthpet) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11930,7 +12502,7 @@ BUILDIN(birthpet) * 3 : don't reset skill, blvl=1 * 4 : jlvl=0 *------------------------------------------*/ -BUILDIN(resetlvl) +static BUILDIN(resetlvl) { int type=script_getnum(st,2); struct map_session_data *sd = script->rid2sd(st); @@ -11943,7 +12515,7 @@ BUILDIN(resetlvl) /*========================================== * Reset a player status point *------------------------------------------*/ -BUILDIN(resetstatus) +static BUILDIN(resetstatus) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11955,7 +12527,7 @@ BUILDIN(resetstatus) /*========================================== * script command resetskill *------------------------------------------*/ -BUILDIN(resetskill) +static BUILDIN(resetskill) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11967,7 +12539,7 @@ BUILDIN(resetskill) /*========================================== * Counts total amount of skill points. *------------------------------------------*/ -BUILDIN(skillpointcount) +static BUILDIN(skillpointcount) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -11979,7 +12551,7 @@ BUILDIN(skillpointcount) /*========================================== * *------------------------------------------*/ -BUILDIN(changebase) +static BUILDIN(changebase) { struct map_session_data *sd = NULL; int vclass; @@ -12025,7 +12597,7 @@ static struct map_session_data *prepareChangeSex(struct script_state *st) /*========================================== * Unequip all item and request for a changesex to char-serv *------------------------------------------*/ -BUILDIN(changesex) +static BUILDIN(changesex) { struct map_session_data *sd = prepareChangeSex(st); if (sd == NULL) @@ -12037,7 +12609,7 @@ BUILDIN(changesex) /*========================================== * Unequip all items and change character sex [4144] *------------------------------------------*/ -BUILDIN(changecharsex) +static BUILDIN(changecharsex) { struct map_session_data *sd = prepareChangeSex(st); if (sd == NULL) @@ -12049,7 +12621,7 @@ BUILDIN(changecharsex) /*========================================== * Works like 'announce' but outputs in the common chat window *------------------------------------------*/ -BUILDIN(globalmes) +static BUILDIN(globalmes) { const char *name=NULL,*mes; @@ -12077,7 +12649,7 @@ BUILDIN(globalmes) /// Creates a waiting room (chat room) for this npc. /// /// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}}; -BUILDIN(waitingroom) +static BUILDIN(waitingroom) { struct npc_data* nd; const char* title = script_getstr(st, 2); @@ -12101,7 +12673,8 @@ BUILDIN(waitingroom) /// /// delwaitingroom "<npc_name>"; /// delwaitingroom; -BUILDIN(delwaitingroom) { +static BUILDIN(delwaitingroom) +{ struct npc_data* nd; if( script_hasdata(st,2) ) nd = npc->name2id(script_getstr(st, 2)); @@ -12116,7 +12689,8 @@ BUILDIN(delwaitingroom) { /// /// kickwaitingroomall "<npc_name>"; /// kickwaitingroomall; -BUILDIN(waitingroomkickall) { +static BUILDIN(waitingroomkickall) +{ struct npc_data* nd; struct chat_data* cd; @@ -12134,7 +12708,8 @@ BUILDIN(waitingroomkickall) { /// /// enablewaitingroomevent "<npc_name>"; /// enablewaitingroomevent; -BUILDIN(enablewaitingroomevent) { +static BUILDIN(enablewaitingroomevent) +{ struct npc_data* nd; struct chat_data* cd; @@ -12152,7 +12727,8 @@ BUILDIN(enablewaitingroomevent) { /// /// disablewaitingroomevent "<npc_name>"; /// disablewaitingroomevent; -BUILDIN(disablewaitingroomevent) { +static BUILDIN(disablewaitingroomevent) +{ struct npc_data *nd; struct chat_data *cd; @@ -12184,7 +12760,7 @@ BUILDIN(disablewaitingroomevent) { /// /// getwaitingroomstate(<type>,"<npc_name>") -> <info> /// getwaitingroomstate(<type>) -> <info> -BUILDIN(getwaitingroomstate) +static BUILDIN(getwaitingroomstate) { const struct npc_data *nd; const struct chat_data *cd; @@ -12207,7 +12783,7 @@ BUILDIN(getwaitingroomstate) for (i = 0; i < cd->users; i++) { struct map_session_data *sd = cd->usersd[i]; nullpo_retr(false, sd); - mapreg->setreg(reference_uid(script->add_str("$@chatmembers"), i), sd->bl.id); + mapreg->setreg(reference_uid(script->add_variable("$@chatmembers"), i), sd->bl.id); } script_pushint(st, cd->users); break; @@ -12240,7 +12816,7 @@ BUILDIN(getwaitingroomstate) /// /// warpwaitingpc "<map name>",<x>,<y>,<number of players>; /// warpwaitingpc "<map name>",<x>,<y>; -BUILDIN(warpwaitingpc) +static BUILDIN(warpwaitingpc) { int x, y, i, n; const char* map_name; @@ -12277,7 +12853,7 @@ BUILDIN(warpwaitingpc) pc->payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL); } - mapreg->setreg(reference_uid(script->add_str("$@warpwaitingpc"), i), sd->bl.id); + mapreg->setreg(reference_uid(script->add_variable("$@warpwaitingpc"), i), sd->bl.id); if( strcmp(map_name,"Random") == 0 ) pc->randomwarp(sd,CLR_TELEPORT); @@ -12286,7 +12862,7 @@ BUILDIN(warpwaitingpc) else pc->setpos(sd, script->mapindexname2id(st,map_name), x, y, CLR_OUTSIGHT); } - mapreg->setreg(script->add_str("$@warpwaitingpcnum"), i); + mapreg->setreg(script->add_variable("$@warpwaitingpcnum"), i); return true; } @@ -12297,7 +12873,8 @@ BUILDIN(warpwaitingpc) /// Detaches a character from a script. /// /// @param st Script state to detach the character from. -void script_detach_rid(struct script_state* st) { +static void script_detach_rid(struct script_state *st) +{ if(st->rid) { script->detach_state(st, false); st->rid = 0; @@ -12307,7 +12884,8 @@ void script_detach_rid(struct script_state* st) { /*========================================== * Attach sd char id to script and detach current one if any *------------------------------------------*/ -BUILDIN(attachrid) { +static BUILDIN(attachrid) +{ int rid = script_getnum(st,2); if (map->id2sd(rid) != NULL) { @@ -12323,7 +12901,7 @@ BUILDIN(attachrid) { /*========================================== * Detach script to rid *------------------------------------------*/ -BUILDIN(detachrid) +static BUILDIN(detachrid) { script->detach_rid(st); return true; @@ -12331,7 +12909,7 @@ BUILDIN(detachrid) /*========================================== * Chk if account connected, (and charid from account if specified) *------------------------------------------*/ -BUILDIN(isloggedin) +static BUILDIN(isloggedin) { struct map_session_data *sd = map->id2sd(script_getnum(st,2)); if (script_hasdata(st,3) && sd != NULL @@ -12344,7 +12922,8 @@ BUILDIN(isloggedin) /*========================================== * *------------------------------------------*/ -BUILDIN(setmapflagnosave) { +static BUILDIN(setmapflagnosave) +{ int16 m,x,y; unsigned short map_index; const char *str,*str2; @@ -12366,7 +12945,77 @@ BUILDIN(setmapflagnosave) { return true; } -BUILDIN(getmapflag) +enum mapinfo_info { + MAPINFO_NAME, + MAPINFO_ID, + MAPINFO_SIZE_X, + MAPINFO_SIZE_Y, + MAPINFO_ZONE +}; + +static BUILDIN(getmapinfo) +{ + enum mapinfo_info mode = script_getnum(st, 2); + int16 m = -1; + + if (script_hasdata(st, 3)) { + if (script_isstringtype(st, 3)) { + const char *str = script_getstr(st, 3); + m = map->mapindex2mapid(strdb_iget(mapindex->db, str)); + } else { + m = script_getnum(st, 3); + } + } else { + struct block_list *bl = NULL; + + if (st->oid) { + bl = map->id2bl(st->oid); + } else if (st->rid) { + bl = map->id2bl(st->rid); + } + + if (bl == NULL) { + ShowError("script:getmapinfo: map not supplied and NPC/PC not attached!\n"); + script_pushint(st, -3); + return false; + } + + m = bl->m; + } + + if (m < 0) { + // here we don't throw an error, so the command can be used + // to detect whether or not a map exists + script_pushint(st, -1); + return true; + } + + switch (mode) { + case MAPINFO_NAME: + script_pushconststr(st, map->list[m].name); + break; + case MAPINFO_ID: + script_pushint(st, m); + break; + case MAPINFO_SIZE_X: + script_pushint(st, map->list[m].xs); + break; + case MAPINFO_SIZE_Y: + script_pushint(st, map->list[m].ys); + break; + case MAPINFO_ZONE: + script_pushstrcopy(st, map->list[m].zone->name); + break; + default: + ShowError("script:getmapinfo: unknown option in second argument (%u).\n", mode); + script_pushint(st, -2); + return false; + } + + return true; +} + +static BUILDIN(getmapflag) { int16 m,i; const char *str; @@ -12428,14 +13077,17 @@ BUILDIN(getmapflag) case MF_RESET: script_pushint(st,map->list[m].flag.reset); break; case MF_NOTOMB: script_pushint(st,map->list[m].flag.notomb); break; case MF_NOCASHSHOP: script_pushint(st,map->list[m].flag.nocashshop); break; - case MF_NOVIEWID: script_pushint(st,map->list[m].flag.noviewid); break; + case MF_NOAUTOLOOT: script_pushint(st, map->list[m].flag.noautoloot); break; + case MF_NOVIEWID: script_pushint(st, map->list[m].flag.noviewid); break; + case MF_PAIRSHIP_STARTABLE: script_pushint(st, map->list[m].flag.pairship_startable); break; + case MF_PAIRSHIP_ENDABLE: script_pushint(st, map->list[m].flag.pairship_endable); break; } } return true; } /* pvp timer handling */ -int script_mapflag_pvp_sub(struct block_list *bl, va_list ap) +static int script_mapflag_pvp_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; @@ -12444,7 +13096,8 @@ int script_mapflag_pvp_sub(struct block_list *bl, va_list ap) sd = BL_UCAST(BL_PC, bl); if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); + if (!map->list[sd->bl.m].flag.pvp_nocalcrank) + sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -12456,7 +13109,8 @@ int script_mapflag_pvp_sub(struct block_list *bl, va_list ap) return 0; } -BUILDIN(setmapflag) { +static BUILDIN(setmapflag) +{ int16 m,i; const char *str, *val2 = NULL; int val=0; @@ -12495,6 +13149,7 @@ BUILDIN(setmapflag) { case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 1; break; case MF_GVG: { struct block_list bl; + memset(&bl, 0, sizeof(bl)); map->list[m].flag.gvg = 1; clif->map_property_mapall(m, MAPPROPERTY_AGITZONE); bl.type = BL_NUL; @@ -12552,14 +13207,18 @@ BUILDIN(setmapflag) { case MF_RESET: map->list[m].flag.reset = 1; break; case MF_NOTOMB: map->list[m].flag.notomb = 1; break; case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 1; break; + case MF_NOAUTOLOOT: map->list[m].flag.noautoloot = 1; break; case MF_NOVIEWID: map->list[m].flag.noviewid = (val <= 0) ? EQP_NONE : val; break; + case MF_PAIRSHIP_STARTABLE: map->list[m].flag.pairship_startable = 1; break; + case MF_PAIRSHIP_ENDABLE: map->list[m].flag.pairship_endable = 1; break; } } return true; } -BUILDIN(removemapflag) { +static BUILDIN(removemapflag) +{ int16 m,i; const char *str; @@ -12577,6 +13236,7 @@ BUILDIN(removemapflag) { case MF_NOZENYPENALTY: map->list[m].flag.nozenypenalty = 0; break; case MF_PVP: { struct block_list bl; + memset(&bl, 0, sizeof(bl)); bl.type = BL_NUL; bl.m = m; map->list[m].flag.pvp = 0; @@ -12588,6 +13248,7 @@ BUILDIN(removemapflag) { case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 0; break; case MF_GVG: { struct block_list bl; + memset(&bl, 0, sizeof(bl)); bl.type = BL_NUL; bl.m = m; map->list[m].flag.gvg = 0; @@ -12639,6 +13300,7 @@ BUILDIN(removemapflag) { case MF_RESET: map->list[m].flag.reset = 0; break; case MF_NOTOMB: map->list[m].flag.notomb = 0; break; case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 0; break; + case MF_NOAUTOLOOT: map->list[m].flag.noautoloot = 0; break; case MF_NOVIEWID: map->list[m].flag.noviewid = EQP_NONE; break; } } @@ -12646,7 +13308,7 @@ BUILDIN(removemapflag) { return true; } -BUILDIN(pvpon) +static BUILDIN(pvpon) { int16 m; const char *str; @@ -12654,6 +13316,7 @@ BUILDIN(pvpon) struct s_mapiterator* iter; struct block_list bl; + memset(&bl, 0, sizeof(bl)); str = script_getstr(st,2); m = map->mapname2mapid(str); if( m < 0 || map->list[m].flag.pvp ) @@ -12679,7 +13342,8 @@ BUILDIN(pvpon) if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER ) continue; // not applicable - sd->pvp_timer = timer->add(timer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0); + if (!map->list[m].flag.pvp_nocalcrank) + sd->pvp_timer = timer->add(timer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -12691,7 +13355,7 @@ BUILDIN(pvpon) return true; } -int buildin_pvpoff_sub(struct block_list *bl, va_list ap) +static int buildin_pvpoff_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; @@ -12707,11 +13371,13 @@ int buildin_pvpoff_sub(struct block_list *bl, va_list ap) return 0; } -BUILDIN(pvpoff) { +static BUILDIN(pvpoff) +{ int16 m; const char *str; struct block_list bl; + memset(&bl, 0, sizeof(bl)); str=script_getstr(st,2); m = map->mapname2mapid(str); if(m < 0 || !map->list[m].flag.pvp) @@ -12731,7 +13397,8 @@ BUILDIN(pvpoff) { return true; } -BUILDIN(gvgon) { +static BUILDIN(gvgon) +{ int16 m; const char *str; @@ -12740,6 +13407,7 @@ BUILDIN(gvgon) { if(m >= 0 && !map->list[m].flag.gvg) { struct block_list bl; + memset(&bl, 0, sizeof(bl)); if( !strdb_exists(map->zone_db,MAP_ZONE_GVG_NAME) ) { ShowError("buildin_gvgon: zone_db missing '%s'\n",MAP_ZONE_GVG_NAME); return true; @@ -12755,7 +13423,8 @@ BUILDIN(gvgon) { return true; } -BUILDIN(gvgoff) { +static BUILDIN(gvgoff) +{ int16 m; const char *str; @@ -12763,6 +13432,7 @@ BUILDIN(gvgoff) { m = map->mapname2mapid(str); if(m >= 0 && map->list[m].flag.gvg) { struct block_list bl; + memset(&bl, 0, sizeof(bl)); map->zone_change2(m, map->list[m].prev_zone); map->list[m].flag.gvg = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); @@ -12778,7 +13448,8 @@ BUILDIN(gvgoff) { * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name> *------------------------------------------*/ //Optional second parameter added by [Skotlex] -BUILDIN(emotion) { +static BUILDIN(emotion) +{ int type; int player=0; @@ -12807,7 +13478,7 @@ BUILDIN(emotion) { return true; } -int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap) +static int buildin_maprespawnguildid_sub_pc(struct map_session_data *sd, va_list ap) { int16 m=va_arg(ap,int); int g_id=va_arg(ap,int); @@ -12824,7 +13495,7 @@ int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap) return 1; } -int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap) +static int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; @@ -12838,7 +13509,8 @@ int buildin_maprespawnguildid_sub_mob(struct block_list *bl, va_list ap) return 0; } -BUILDIN(maprespawnguildid) { +static BUILDIN(maprespawnguildid) +{ const char *mapname=script_getstr(st,2); int g_id=script_getnum(st,3); int flag=script_getnum(st,4); @@ -12855,28 +13527,32 @@ BUILDIN(maprespawnguildid) { return true; } -BUILDIN(agitstart) { +static BUILDIN(agitstart) +{ if(map->agit_flag==1) return true; // Agit already Start. map->agit_flag=1; guild->agit_start(); return true; } -BUILDIN(agitend) { +static BUILDIN(agitend) +{ if(map->agit_flag==0) return true; // Agit already End. map->agit_flag=0; guild->agit_end(); return true; } -BUILDIN(agitstart2) { +static BUILDIN(agitstart2) +{ if(map->agit2_flag==1) return true; // Agit2 already Start. map->agit2_flag=1; guild->agit2_start(); return true; } -BUILDIN(agitend2) { +static BUILDIN(agitend2) +{ if(map->agit2_flag==0) return true; // Agit2 already End. map->agit2_flag=0; guild->agit2_end(); @@ -12886,7 +13562,8 @@ BUILDIN(agitend2) { /*========================================== * Returns whether woe is on or off. *------------------------------------------*/ -BUILDIN(agitcheck) { +static BUILDIN(agitcheck) +{ script_pushint(st,map->agit_flag); return true; } @@ -12894,7 +13571,8 @@ BUILDIN(agitcheck) { /*========================================== * Returns whether woese is on or off. *------------------------------------------*/ -BUILDIN(agitcheck2) { +static BUILDIN(agitcheck2) +{ script_pushint(st,map->agit2_flag); return true; } @@ -12902,7 +13580,7 @@ BUILDIN(agitcheck2) { /// Sets the guild_id of this npc. /// /// flagemblem <guild_id>; -BUILDIN(flagemblem) +static BUILDIN(flagemblem) { struct npc_data *nd; int g_id = script_getnum(st,2); @@ -12927,7 +13605,7 @@ BUILDIN(flagemblem) return true; } -BUILDIN(getcastlename) +static BUILDIN(getcastlename) { const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); struct guild_castle* gc = guild->mapname2gc(mapname); @@ -12936,7 +13614,7 @@ BUILDIN(getcastlename) return true; } -BUILDIN(getcastledata) +static BUILDIN(getcastledata) { const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); @@ -12979,7 +13657,7 @@ BUILDIN(getcastledata) return true; } -BUILDIN(setcastledata) +static BUILDIN(setcastledata) { const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); @@ -13002,7 +13680,7 @@ BUILDIN(setcastledata) /* ===================================================================== * ---------------------------------------------------------------------*/ -BUILDIN(requestguildinfo) +static BUILDIN(requestguildinfo) { int guild_id=script_getnum(st,2); const char *event=NULL; @@ -13019,7 +13697,7 @@ BUILDIN(requestguildinfo) /// Returns the number of cards that have been compounded onto the specified equipped item. /// getequipcardcnt(<equipment slot>); -BUILDIN(getequipcardcnt) +static BUILDIN(getequipcardcnt) { int i=-1,j,num; struct map_session_data *sd; @@ -13056,149 +13734,115 @@ BUILDIN(getequipcardcnt) /// Removes all cards from the item found in the specified equipment slot of the invoking character, /// and give them to the character. If any cards were removed in this manner, it will also show a success effect. -/// successremovecards <slot>; -BUILDIN(successremovecards) +/// successremovecards(<slot>); +static BUILDIN(successremovecards) { - int i=-1,c,cardflag=0; + int i = -1, c, cardflag = 0; struct map_session_data *sd = script->rid2sd(st); - int num = script_getnum(st,2); + int num = script_getnum(st, 2); if (sd == NULL) return true; if (num > 0 && num <= ARRAYLENGTH(script->equip)) - i=pc->checkequip(sd,script->equip[num-1]); + i = pc->checkequip(sd,script->equip[num - 1]); - if (i < 0 || !sd->inventory_data[i]) { + if (i < 0 || sd->inventory_data[i] == NULL) return true; - } - if(itemdb_isspecial(sd->status.inventory[i].card[0])) + if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { - if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {// extract this card from the item + for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { + if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { int flag; struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); + + memset(&item_tmp, 0, sizeof(item_tmp)); + cardflag = 1; - item_tmp.nameid = sd->status.inventory[i].card[c]; + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; + sd->status.inventory[i].card[c] = 0; - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - // get back the cart in inventory - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); + if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); + map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } if (cardflag == 1) { - //if card was remove replace item with no card - int flag, j; - struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); - - item_tmp.nameid = sd->status.inventory[i].nameid; - item_tmp.identify = 1; - item_tmp.refine = sd->status.inventory[i].refine; - item_tmp.attribute = sd->status.inventory[i].attribute; - item_tmp.expire_time = sd->status.inventory[i].expire_time; - item_tmp.bound = sd->status.inventory[i].bound; - - for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) - item_tmp.card[j]=sd->status.inventory[i].card[j]; - - pc->delitem(sd, i, 1, 0, DELITEM_MATERIALCHANGE, LOG_TYPE_SCRIPT); - if ((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - //chk if can be spawn in inventory otherwise put on floor - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); - } - + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); + clif->additem(sd, i, 1, 0); + pc->equipitem(sd, i, sd->status.inventory[i].equip); clif->misceffect(&sd->bl,3); } return true; } /// Removes all cards from the item found in the specified equipment slot of the invoking character. -/// failedremovecards <slot>, <type>; +/// failedremovecards(<slot>, <type>); /// <type>=0 : will destroy both the item and the cards. /// <type>=1 : will keep the item, but destroy the cards. /// <type>=2 : will keep the cards, but destroy the item. -/// <type>=? : will just display the failure effect. -BUILDIN(failedremovecards) +/// <type>=3 : will just display the failure effect. +static BUILDIN(failedremovecards) { - int i=-1,c,cardflag=0; + int i = -1, c, cardflag = 0; + int num = script_getnum(st, 2); + int typefail = script_getnum(st, 3); struct map_session_data *sd = script->rid2sd(st); - int num = script_getnum(st,2); - int typefail = script_getnum(st,3); if (sd == NULL) return true; if (num > 0 && num <= ARRAYLENGTH(script->equip)) - i=pc->checkequip(sd,script->equip[num-1]); + i = pc->checkequip(sd, script->equip[num - 1]); - if (i < 0 || !sd->inventory_data[i]) + if (i < 0 || sd->inventory_data[i] == NULL) return true; - if(itemdb_isspecial(sd->status.inventory[i].card[0])) + if (itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { - if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) { + for (c = sd->inventory_data[i]->slot - 1; c >= 0; --c) { + if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) { cardflag = 1; - if(typefail == 2) {// add cards to inventory, clear + sd->status.inventory[i].card[c] = 0; + + if (typefail == 2) { // add cards to inventory, clear int flag; struct item item_tmp; - memset(&item_tmp,0,sizeof(item_tmp)); + memset(&item_tmp, 0, sizeof(item_tmp)); - item_tmp.nameid = sd->status.inventory[i].card[c]; + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); + if ((flag = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); + map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } } if (cardflag == 1) { - if (typefail == 0 || typefail == 2) { - // destroy the item + if (typefail == 0 || typefail == 2) { // destroy the item pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); } else if (typefail == 1) { - // destroy the card - int flag, j; - struct item item_tmp; - - memset(&item_tmp,0,sizeof(item_tmp)); - - item_tmp.nameid = sd->status.inventory[i].nameid; - item_tmp.identify = 1; - item_tmp.refine = sd->status.inventory[i].refine; - item_tmp.attribute = sd->status.inventory[i].attribute; - item_tmp.expire_time = sd->status.inventory[i].expire_time; - item_tmp.bound = sd->status.inventory[i].bound; - - for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) - item_tmp.card[j]=sd->status.inventory[i].card[j]; - - pc->delitem(sd, i, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_SCRIPT); - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { - clif->additem(sd,0,0,flag); - map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); - } + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); + clif->additem(sd, i, 1, 0); + pc->equipitem(sd, i, sd->status.inventory[i].equip); } - clif->misceffect(&sd->bl,2); } + clif->misceffect(&sd->bl, 2); return true; } @@ -13209,7 +13853,8 @@ BUILDIN(failedremovecards) * improved by [Lance] * ================================================================*/ // Added by RoVeRT -BUILDIN(mapwarp) { +static BUILDIN(mapwarp) +{ int x,y,m,check_val=0,check_ID=0,i=0; struct guild *g = NULL; struct party_data *p = NULL; @@ -13262,7 +13907,7 @@ BUILDIN(mapwarp) { } // Added by RoVeRT -int buildin_mobcount_sub(struct block_list *bl, va_list ap) +static int buildin_mobcount_sub(struct block_list *bl, va_list ap) { char *event = va_arg(ap,char *); const struct mob_data *md = NULL; @@ -13277,7 +13922,8 @@ int buildin_mobcount_sub(struct block_list *bl, va_list ap) } // Added by RoVeRT -BUILDIN(mobcount) { +static BUILDIN(mobcount) +{ const char *mapname,*event; int16 m; mapname=script_getstr(st,2); @@ -13310,7 +13956,8 @@ BUILDIN(mobcount) { return true; } -BUILDIN(marriage) { +static BUILDIN(marriage) +{ const char *partner=script_getstr(st,2); struct map_session_data *sd = script->rid2sd(st); struct map_session_data *p_sd = script->nick2sd(st, partner); @@ -13322,7 +13969,7 @@ BUILDIN(marriage) { script_pushint(st,1); return true; } -BUILDIN(wedding_effect) +static BUILDIN(wedding_effect) { struct map_session_data *sd = script->rid2sd(st); struct block_list *bl; @@ -13334,7 +13981,7 @@ BUILDIN(wedding_effect) clif->wedding_effect(bl); return true; } -BUILDIN(divorce) +static BUILDIN(divorce) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL || pc->divorce(sd) < 0) { @@ -13345,7 +13992,8 @@ BUILDIN(divorce) return true; } -BUILDIN(ispartneron) { +static BUILDIN(ispartneron) +{ struct map_session_data *sd = script->rid2sd(st); if (sd==NULL || !pc->ismarried(sd) @@ -13358,7 +14006,7 @@ BUILDIN(ispartneron) { return true; } -BUILDIN(getpartnerid) +static BUILDIN(getpartnerid) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -13368,7 +14016,7 @@ BUILDIN(getpartnerid) return true; } -BUILDIN(getchildid) +static BUILDIN(getchildid) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -13378,7 +14026,7 @@ BUILDIN(getchildid) return true; } -BUILDIN(getmotherid) +static BUILDIN(getmotherid) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -13388,7 +14036,8 @@ BUILDIN(getmotherid) return true; } -BUILDIN(getfatherid) { +static BUILDIN(getfatherid) +{ struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; @@ -13397,7 +14046,7 @@ BUILDIN(getfatherid) { return true; } -BUILDIN(warppartner) +static BUILDIN(warppartner) { int x,y; unsigned short map_index; @@ -13427,7 +14076,7 @@ BUILDIN(warppartner) /*================================================ * Script for Displaying MOB Information [Valaris] *------------------------------------------------*/ -BUILDIN(strmobinfo) +static BUILDIN(strmobinfo) { int num=script_getnum(st,2); @@ -13461,7 +14110,8 @@ BUILDIN(strmobinfo) * Summon guardians [Valaris] * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id> *------------------------------------------*/ -BUILDIN(guardian) { +static BUILDIN(guardian) +{ int class_ = 0, x = 0, y = 0, guardian = 0; const char *str, *mapname, *evt=""; bool has_index = false; @@ -13502,7 +14152,8 @@ BUILDIN(guardian) { /*========================================== * Invisible Walls [Zephyrus] *------------------------------------------*/ -BUILDIN(setwall) { +static BUILDIN(setwall) +{ const char *mapname, *name; int x, y, m, size, dir; bool shootable; @@ -13521,9 +14172,15 @@ BUILDIN(setwall) { map->iwall_set(m, x, y, size, dir, shootable, name); return true; } -BUILDIN(delwall) { + +static BUILDIN(delwall) +{ const char *name = script_getstr(st,2); - map->iwall_remove(name); + + if (!map->iwall_remove(name)) { + ShowWarning("buildin_delwall: Non-existent '%s' provided.\n", name); + return false; + } return true; } @@ -13535,7 +14192,8 @@ BUILDIN(delwall) { /// 1 - maximum hp /// 2 - current hp /// -BUILDIN(guardianinfo) { +static BUILDIN(guardianinfo) +{ const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); int id = script_getnum(st,3); int type = script_getnum(st,4); @@ -13567,7 +14225,8 @@ BUILDIN(guardianinfo) { /*========================================== * Get the item name by item_id or null *------------------------------------------*/ -BUILDIN(getitemname) { +static BUILDIN(getitemname) +{ int item_id=0; struct item_data *i_data; char *item_name; @@ -13595,7 +14254,7 @@ BUILDIN(getitemname) { /*========================================== * Returns number of slots an item has. [Skotlex] *------------------------------------------*/ -BUILDIN(getitemslots) +static BUILDIN(getitemslots) { int item_id; struct item_data *i_data; @@ -13611,88 +14270,353 @@ BUILDIN(getitemslots) return true; } -// TODO: add matk here if needed/once we get rid of RENEWAL +// TODO: add matk here if needed /*========================================== * Returns some values of an item [Lupus] * Price, Weight, etc... - * getiteminfo(itemID,n), where n - * 0 value_buy; - * 1 value_sell; - * 2 type; - * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. - * if = 0, then monsters don't drop it at all (rare or a quest item) - * if = -1, then this item is sold in NPC shops only - * 4 sex; - * 5 equip; - * 6 weight; - * 7 atk; - * 8 def; - * 9 range; - * 10 slot; - * 11 look; - * 12 elv; - * 13 wlv; - * 14 view id *------------------------------------------*/ -BUILDIN(getiteminfo) +static BUILDIN(getiteminfo) { - int item_id,n; - struct item_data *i_data; + int item_id = script_getnum(st, 2); + int n = script_getnum(st, 3); + struct item_data *it = itemdb->exists(item_id); - item_id = script_getnum(st,2); - n = script_getnum(st,3); - i_data = itemdb->exists(item_id); + if (it == NULL) { + script_pushint(st, -1); + return true; + } - if (i_data && n>=0 && n<=14) { - int *item_arr = (int*)&i_data->value_buy; - script_pushint(st,item_arr[n]); - } else { + switch (n) { + case ITEMINFO_BUYPRICE: + script_pushint(st, it->value_buy); + break; + case ITEMINFO_SELLPRICE: + script_pushint(st, it->value_sell); + break; + case ITEMINFO_TYPE: + script_pushint(st, it->type); + break; + case ITEMINFO_MAXCHANCE: + script_pushint(st, it->maxchance); + break; + case ITEMINFO_SEX: + script_pushint(st, it->sex); + break; + case ITEMINFO_LOC: + script_pushint(st, it->equip); + break; + case ITEMINFO_WEIGHT: + script_pushint(st, it->weight); + break; + case ITEMINFO_ATK: + script_pushint(st, it->atk); + break; + case ITEMINFO_DEF: + script_pushint(st, it->def); + break; + case ITEMINFO_RANGE: + script_pushint(st, it->range); + break; + case ITEMINFO_SLOTS: + script_pushint(st, it->slot); + break; + case ITEMINFO_SUBTYPE: + script_pushint(st, it->subtype); + break; + case ITEMINFO_ELV: + script_pushint(st, it->elv); + break; + case ITEMINFO_WLV: + script_pushint(st, it->wlv); + break; + case ITEMINFO_VIEWID: + script_pushint(st, it->view_id); + break; + case ITEMINFO_MATK: + script_pushint(st, it->matk); + break; + case ITEMINFO_VIEWSPRITE: + script_pushint(st, it->view_sprite); + break; + case ITEMINFO_TRADE: + script_pushint(st, it->flag.trade_restriction); + break; + default: + ShowError("buildin_getiteminfo: Invalid item type %d.\n", n); script_pushint(st,-1); + return false; + } + return true; +} + +/** + * Returns the value of the current equipment being parsed using static variables - + * current_equip_item_index and current_equip_option_index. + * !!Designed to be used with item_options.conf only!! + * *getequippedoptioninfo(<info_type>); + * + * @param (int) Types - + * IT_OPT_INDEX ID of the item option. + * IT_OPT_VALUE Amount of the bonus to be added. + * @return value of the type or -1. + */ +static BUILDIN(getequippedoptioninfo) +{ + int val = 0, type = script_getnum(st, 2); + struct map_session_data *sd = NULL; + + if ((sd = script->rid2sd(st)) == NULL || status->current_equip_item_index == -1 || status->current_equip_option_index == -1 + || !sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index) { + script_pushint(st, -1); + return false; + } + + switch (type) { + case IT_OPT_INDEX: + val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index; + break; + case IT_OPT_VALUE: + val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].value; + break; + default: + ShowError("buildin_getequippedoptioninfo: Invalid option data type %d (Max %d).\n", type, IT_OPT_MAX-1); + script_pushint(st, -1); + return false; + } + + script_pushint(st, val); + + return true; +} + +/** + * Gets the option information of an equipment. + * *getequipoption(<equip_index>,<slot>,<type>); + * + * @param equip_index as the Index of the Equipment. + * @param slot as the slot# of the Item Option (1 to MAX_ITEM_OPTIONS) + * @param type IT_OPT_INDEX or IT_OPT_VALUE. + * @return (int) value or -1 on failure. + */ +static BUILDIN(getequipoption) +{ + int val = 0, equip_index = script_getnum(st, 2); + int slot = script_getnum(st, 3); + int opt_type = script_getnum(st, 4); + int i = -1; + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) { + script_pushint(st, -1); + ShowError("buildin_getequipoption: Player not attached!\n"); + return false; + } + + if (slot <= 0 || slot > MAX_ITEM_OPTIONS) { + script_pushint(st, -1); + ShowError("buildin_getequipoption: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); + return false; + } + + if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) { + if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) { + ShowError("buildin_getequipoption: No equipment is equipped in the given index %d.\n", equip_index); + script_pushint(st, -1); + return false; + } + } else { + ShowError("buildin_getequipoption: Invalid equipment index %d provided.\n", equip_index); + script_pushint(st, 0); + return false; } + + if (sd->status.inventory[i].nameid != 0) { + switch (opt_type) { + case IT_OPT_INDEX: + val = sd->status.inventory[i].option[slot-1].index; + break; + case IT_OPT_VALUE: + val = sd->status.inventory[i].option[slot-1].value; + break; + default: + ShowError("buildin_getequipoption: Invalid option data type %d provided.\n", opt_type); + script_pushint(st, -1); + break; + } + } + + script_pushint(st, val); + return true; } +/** + * Set an equipment's option value. + * *setequipoption(<equip_index>,<slot>,<opt_index>,<value>); + * + * @param equip_index as the inventory index of the equipment. + * @param slot as the slot of the item option (1 to MAX_ITEM_OPTIONS) + * @param opt_index as the index of the option available as "Id" in db/item_options.conf. + * @param value as the value of the option type. + * For IT_OPT_INDEX see "Name" in item_options.conf + * For IT_OPT_VALUE, the value of the script bonus. + * @return 0 on failure, 1 on success. + */ +static BUILDIN(setequipoption) +{ + int equip_index = script_getnum(st, 2); + int slot = script_getnum(st, 3); + int opt_index = script_getnum(st, 4); + int value = script_getnum(st, 5); + int i = -1; + + struct map_session_data *sd = script->rid2sd(st); + struct itemdb_option *ito = NULL; + + if (sd == NULL) { + script_pushint(st, 0); + ShowError("buildin_setequipoption: Player not attached!\n"); + return false; + } + + if (slot <= 0 || slot > MAX_ITEM_OPTIONS) { + script_pushint(st, 0); + ShowError("buildin_setequipoption: Invalid option index %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS); + return false; + } + + if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) { + if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) { + ShowError("buildin_setequipoption: No equipment is equipped in the given index %d.\n", equip_index); + script_pushint(st, 0); + return false; + } + } else { + ShowError("buildin_setequipoption: Invalid equipment index %d provided.\n", equip_index); + script_pushint(st, 0); + return false; + } + + if (sd->status.inventory[i].nameid != 0) { + if (opt_index == 0) { + // Remove the option + sd->status.inventory[i].option[slot-1].index = 0; + sd->status.inventory[i].option[slot-1].value = 0; + } else { + if ((ito = itemdb->option_exists(opt_index)) == NULL) { + script_pushint(st, 0); + ShowError("buildin_setequipotion: Option index %d does not exist!\n", opt_index); + return false; + } else if (value < -INT16_MAX || value > INT16_MAX) { + script_pushint(st, 0); + ShowError("buildin_setequipotion: Option value %d exceeds maximum limit (%d to %d) for type!\n", value, -INT16_MAX, INT16_MAX); + return false; + } + /* Add Option Index */ + sd->status.inventory[i].option[slot-1].index = ito->index; + /* Add Option Value */ + sd->status.inventory[i].option[slot-1].value = value; + } + + /* Unequip and simulate deletion of the item. */ + pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); // status calc will happen in pc->equipitem() below + clif->refine(sd->fd, 0, i, sd->status.inventory[i].refine); // notify client of a refine. + clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); // notify client to simulate item deletion. + /* Log deletion of the item. */ + logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); + /* Equip and simulate addition of the item. */ + clif->additem(sd, i, 1, 0); // notify client to simulate item addition. + /* Log addition of the item. */ + logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i], sd->inventory_data[i]); + pc->equipitem(sd, i, sd->status.inventory[i].equip); // force equip the item at the original position. + clif->misceffect(&sd->bl, 2); // show effect + } + + script_pushint(st, 1); + + return true; + +} + /*========================================== * Set some values of an item [Lupus] * Price, Weight, etc... - * setiteminfo(itemID,n,Value), where n - * 0 value_buy; - * 1 value_sell; - * 2 type; - * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. - * if = 0, then monsters don't drop it at all (rare or a quest item) - * if = -1, then this item is sold in NPC shops only - * 4 sex; - * 5 equip; - * 6 weight; - * 7 atk; - * 8 def; - * 9 range; - * 10 slot; - * 11 look; - * 12 elv; - * 13 wlv; - * 14 view id - * Returns Value or -1 if the wrong field's been set *------------------------------------------*/ -BUILDIN(setiteminfo) +static BUILDIN(setiteminfo) { - int item_id,n,value; - struct item_data *i_data; + // TODO: Validate data in a similar way as during database load + int item_id = script_getnum(st, 2); + int n = script_getnum(st, 3); + int value = script_getnum(st,4); + struct item_data *it = itemdb->exists(item_id); - item_id = script_getnum(st,2); - n = script_getnum(st,3); - value = script_getnum(st,4); - i_data = itemdb->exists(item_id); + if (it == NULL) { + script_pushint(st, -1); + return true; + } - if (i_data && n>=0 && n<=14) { - int *item_arr = (int*)&i_data->value_buy; - item_arr[n] = value; - script_pushint(st,value); - } else { + switch (n) { + case ITEMINFO_BUYPRICE: + it->value_buy = value; + break; + case ITEMINFO_SELLPRICE: + it->value_sell = value; + break; + case ITEMINFO_TYPE: + it->type = value; + break; + case ITEMINFO_MAXCHANCE: + it->maxchance = value; + break; + case ITEMINFO_SEX: + it->sex = value; + break; + case ITEMINFO_LOC: + it->equip = value; + break; + case ITEMINFO_WEIGHT: + it->weight = value; + break; + case ITEMINFO_ATK: + it->atk = value; + break; + case ITEMINFO_DEF: + it->def = value; + break; + case ITEMINFO_RANGE: + it->range = value; + break; + case ITEMINFO_SLOTS: + it->slot = value; + break; + case ITEMINFO_SUBTYPE: + it->subtype = value; + break; + case ITEMINFO_ELV: + it->elv = value; + break; + case ITEMINFO_WLV: + it->wlv = value; + break; + case ITEMINFO_VIEWID: + it->view_id = value; + break; + case ITEMINFO_MATK: + it->matk = value; + break; + case ITEMINFO_VIEWSPRITE: + it->view_sprite = value; + break; + case ITEMINFO_TRADE: + it->flag.trade_restriction = value; + break; + default: + ShowError("buildin_setiteminfo: invalid type %d.\n", n); script_pushint(st,-1); + return false; } + script_pushint(st,value); return true; } @@ -13708,7 +14632,7 @@ BUILDIN(setiteminfo) * Useful for such quests as "Sign this refined item with players name" etc * Hat[0] +4 -> Player's Hat[0] +4 *------------------------------------------*/ -BUILDIN(getequipcardid) +static BUILDIN(getequipcardid) { int i=-1,num,slot; struct map_session_data *sd; @@ -13733,7 +14657,7 @@ BUILDIN(getequipcardid) /*========================================== * petskillbonus [Valaris] //Rewritten by [Skotlex] *------------------------------------------*/ -BUILDIN(petskillbonus) +static BUILDIN(petskillbonus) { struct pet_data *pd; @@ -13770,7 +14694,7 @@ BUILDIN(petskillbonus) /*========================================== * pet looting [Valaris] //Rewritten by [Skotlex] *------------------------------------------*/ -BUILDIN(petloot) +static BUILDIN(petloot) { int max; struct pet_data *pd; @@ -13810,93 +14734,108 @@ BUILDIN(petloot) * @inventorylist_card(0..3), @inventorylist_expire * @inventorylist_count = scalar *------------------------------------------*/ -BUILDIN(getinventorylist) +static BUILDIN(getinventorylist) { struct map_session_data *sd = script->rid2sd(st); - char card_var[NAME_LENGTH]; + char card_var[SCRIPT_VARNAME_LENGTH]; - int i,j=0,k; + int j=0,k; if(!sd) return true; - for(i=0;i<MAX_INVENTORY;i++) { + for (int i = 0;i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) { - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid); - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_id"), j),sd->status.inventory[i].nameid); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_amount"), j),sd->status.inventory[i].amount); if(sd->status.inventory[i].equip) { - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),pc->equippoint(sd,i)); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),pc->equippoint(sd,i)); } else { - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),0); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),0); } - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine); - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify); - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_refine"), j),sd->status.inventory[i].refine); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_identify"), j),sd->status.inventory[i].identify); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_attribute"), j),sd->status.inventory[i].attribute); for (k = 0; k < MAX_SLOTS; k++) { sprintf(card_var, "@inventorylist_card%d",k+1); - pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]); + pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.inventory[i].card[k]); + } + for (k = 0; k < MAX_ITEM_OPTIONS; k++) { + sprintf(card_var, "@inventorylist_opt_id%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].index); + sprintf(card_var, "@inventorylist_opt_val%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].value); + sprintf(card_var, "@inventorylist_opt_param%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].param); } - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); - pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); + pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_bound"), j),sd->status.inventory[i].bound); j++; } } - pc->setreg(sd,script->add_str("@inventorylist_count"),j); + pc->setreg(sd,script->add_variable("@inventorylist_count"),j); return true; } -BUILDIN(getcartinventorylist) +static BUILDIN(getcartinventorylist) { struct map_session_data *sd = script->rid2sd(st); - char card_var[26]; + char card_var[SCRIPT_VARNAME_LENGTH]; int i,j=0,k; if(!sd) return true; for(i=0;i<MAX_CART;i++) { if(sd->status.cart[i].nameid > 0 && sd->status.cart[i].amount > 0) { - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_id"), j),sd->status.cart[i].nameid); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_amount"), j),sd->status.cart[i].amount); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_equip"), j),sd->status.cart[i].equip); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_refine"), j),sd->status.cart[i].refine); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_identify"), j),sd->status.cart[i].identify); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_id"), j),sd->status.cart[i].nameid); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_amount"), j),sd->status.cart[i].amount); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_equip"), j),sd->status.cart[i].equip); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_refine"), j),sd->status.cart[i].refine); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_identify"), j),sd->status.cart[i].identify); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_attribute"), j),sd->status.cart[i].attribute); for (k = 0; k < MAX_SLOTS; k++) { sprintf(card_var, "@cartinventorylist_card%d",k+1); - pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.cart[i].card[k]); + pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.cart[i].card[k]); } - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time); - pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_bound"), j),sd->status.cart[i].bound); + for (k = 0; k < MAX_ITEM_OPTIONS; k++) { + sprintf(card_var, "@cartinventorylist_opt_id%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].index); + sprintf(card_var, "@cartinventorylist_opt_val%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].value); + sprintf(card_var, "@cartinventorylist_opt_param%d", k + 1); + pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.cart[i].option[k].param); + } + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time); + pc->setreg(sd,reference_uid(script->add_variable("@cartinventorylist_bound"), j),sd->status.cart[i].bound); j++; } } - pc->setreg(sd,script->add_str("@cartinventorylist_count"),j); + pc->setreg(sd,script->add_variable("@cartinventorylist_count"),j); return true; } -BUILDIN(getskilllist) +static BUILDIN(getskilllist) { struct map_session_data *sd = script->rid2sd(st); int i,j=0; if (sd == NULL) return true; - for(i=0;i<MAX_SKILL;i++) { + for (i = 0; i < MAX_SKILL_DB; i++) { if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0) { - pc->setreg(sd,reference_uid(script->add_str("@skilllist_id"), j),sd->status.skill[i].id); - pc->setreg(sd,reference_uid(script->add_str("@skilllist_lv"), j),sd->status.skill[i].lv); - pc->setreg(sd,reference_uid(script->add_str("@skilllist_flag"), j),sd->status.skill[i].flag); + pc->setreg(sd,reference_uid(script->add_variable("@skilllist_id"), j),sd->status.skill[i].id); + pc->setreg(sd,reference_uid(script->add_variable("@skilllist_lv"), j),sd->status.skill[i].lv); + pc->setreg(sd,reference_uid(script->add_variable("@skilllist_flag"), j),sd->status.skill[i].flag); j++; } } - pc->setreg(sd,script->add_str("@skilllist_count"),j); + pc->setreg(sd,script->add_variable("@skilllist_count"),j); return true; } -BUILDIN(clearitem) +static BUILDIN(clearitem) { struct map_session_data *sd = script->rid2sd(st); - int i; if (sd == NULL) return true; - for (i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if (sd->status.inventory[i].amount) { pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_SCRIPT); } @@ -13907,7 +14846,7 @@ BUILDIN(clearitem) /*========================================== * Disguise Player (returns Mob/NPC ID if success, 0 on fail) *------------------------------------------*/ -BUILDIN(disguise) +static BUILDIN(disguise) { int id; struct map_session_data *sd = script->rid2sd(st); @@ -13928,7 +14867,7 @@ BUILDIN(disguise) /*========================================== * Undisguise Player (returns 1 if success, 0 on fail) *------------------------------------------*/ -BUILDIN(undisguise) +static BUILDIN(undisguise) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -13947,7 +14886,7 @@ BUILDIN(undisguise) * Transform a bl to another class, * @type unused *------------------------------------------*/ -BUILDIN(classchange) +static BUILDIN(classchange) { int class, type, target; struct block_list *bl = map->id2bl(st->oid); @@ -13973,7 +14912,7 @@ BUILDIN(classchange) /*========================================== * Display an effect *------------------------------------------*/ -BUILDIN(misceffect) +static BUILDIN(misceffect) { int type; @@ -13992,7 +14931,7 @@ BUILDIN(misceffect) /*========================================== * Play a BGM on a single client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playbgm) +static BUILDIN(playbgm) { struct map_session_data* sd = script->rid2sd(st); @@ -14005,7 +14944,7 @@ BUILDIN(playbgm) return true; } -int playbgm_sub(struct block_list* bl,va_list ap) +static int playbgm_sub(struct block_list *bl, va_list ap) { const char* name = va_arg(ap,const char*); @@ -14014,7 +14953,7 @@ int playbgm_sub(struct block_list* bl,va_list ap) return 0; } -int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args) +static int playbgm_foreachpc_sub(struct map_session_data *sd, va_list args) { const char* name = va_arg(args, const char*); @@ -14026,7 +14965,8 @@ int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args) /*========================================== * Play a BGM on multiple client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playbgmall) { +static BUILDIN(playbgmall) +{ const char* name; name = script_getstr(st,2); @@ -14068,7 +15008,7 @@ BUILDIN(playbgmall) { /*========================================== * Play a .wav sound for sd *------------------------------------------*/ -BUILDIN(soundeffect) +static BUILDIN(soundeffect) { struct map_session_data *sd = script->rid2sd(st); const char* name = script_getstr(st,2); @@ -14080,7 +15020,7 @@ BUILDIN(soundeffect) return true; } -int soundeffect_sub(struct block_list *bl, va_list ap) +static int soundeffect_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; char *name = va_arg(ap, char *); @@ -14099,7 +15039,8 @@ int soundeffect_sub(struct block_list *bl, va_list ap) * Play a sound effect (.wav) on multiple clients * soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>}; *------------------------------------------*/ -BUILDIN(soundeffectall) { +static BUILDIN(soundeffectall) +{ struct block_list* bl; const char* name; int type; @@ -14150,7 +15091,7 @@ BUILDIN(soundeffectall) { /*========================================== * pet status recovery [Valaris] / Rewritten by [Skotlex] *------------------------------------------*/ -BUILDIN(petrecovery) +static BUILDIN(petrecovery) { struct pet_data *pd; struct map_session_data *sd = script->rid2sd(st); @@ -14179,7 +15120,7 @@ BUILDIN(petrecovery) *------------------------------------------*/ /// petskillattack <skill id>,<level>,<div>,<rate>,<bonusrate> /// petskillattack "<skill name>",<level>,<div>,<rate>,<bonusrate> -BUILDIN(petskillattack) +static BUILDIN(petskillattack) { struct pet_data *pd; struct map_session_data *sd = script->rid2sd(st); @@ -14205,7 +15146,7 @@ BUILDIN(petskillattack) *------------------------------------------*/ /// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp> /// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp> -BUILDIN(petskillsupport) +static BUILDIN(petskillsupport) { struct pet_data *pd; struct map_session_data *sd = script->rid2sd(st); @@ -14244,7 +15185,7 @@ BUILDIN(petskillsupport) *------------------------------------------*/ /// skilleffect <skill id>,<level> /// skilleffect "<skill name>",<level> -BUILDIN(skilleffect) +static BUILDIN(skilleffect) { struct map_session_data *sd; @@ -14272,7 +15213,8 @@ BUILDIN(skilleffect) *------------------------------------------*/ /// npcskilleffect <skill id>,<level>,<x>,<y> /// npcskilleffect "<skill name>",<level>,<x>,<y> -BUILDIN(npcskilleffect) { +static BUILDIN(npcskilleffect) +{ struct block_list *bl= map->id2bl(st->oid); uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); @@ -14289,26 +15231,43 @@ BUILDIN(npcskilleffect) { /*========================================== * Special effects [Valaris] *------------------------------------------*/ -BUILDIN(specialeffect) { +static BUILDIN(specialeffect) +{ struct block_list *bl = NULL; - int type = script_getnum(st,2); - enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; + int type = script_getnum(st, 2); + enum send_target target = AREA; - if (script_hasdata(st,4)) { - struct npc_data *nd = npc->name2id(script_getstr(st,4)); - if (nd != NULL) - bl = &nd->bl; + if (script_hasdata(st, 3)) { + target = script_getnum(st, 3); + } + + if (script_hasdata(st, 4)) { + if (script_isstringtype(st, 4)) { + struct npc_data *nd = npc->name2id(script_getstr(st, 4)); + if (nd != NULL) { + bl = &nd->bl; + } + } else { + bl = map->id2bl(script_getnum(st, 4)); + } } else { bl = map->id2bl(st->oid); } - if (bl == NULL) + if (bl == NULL) { return true; + } if (target == SELF) { - struct map_session_data *sd = script->rid2sd(st); - if (sd != NULL) + struct map_session_data *sd; + if (script_hasdata(st, 5)) { + sd = map->id2sd(script_getnum(st, 5)); + } else { + sd = script->rid2sd(st); + } + if (sd != NULL) { clif->specialeffect_single(bl, type, sd->fd); + } } else { clif->specialeffect(bl, type, target); } @@ -14316,7 +15275,8 @@ BUILDIN(specialeffect) { return true; } -BUILDIN(specialeffect2) { +static BUILDIN(specialeffect2) +{ struct map_session_data *sd; int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; @@ -14332,10 +15292,54 @@ BUILDIN(specialeffect2) { return true; } +static BUILDIN(removespecialeffect) +{ + struct block_list *bl = NULL; + int type = script_getnum(st, 2); + enum send_target target = AREA; + + if (script_hasdata(st, 3)) { + target = script_getnum(st, 3); + } + + if (script_hasdata(st, 4)) { + if (script_isstringtype(st, 4)) { + struct npc_data *nd = npc->name2id(script_getstr(st, 4)); + if (nd != NULL) { + bl = &nd->bl; + } + } else { + bl = map->id2bl(script_getnum(st, 4)); + } + } else { + bl = map->id2bl(st->oid); + } + + if (bl == NULL) { + return true; + } + + if (target == SELF) { + struct map_session_data *sd; + if (script_hasdata(st, 5)) { + sd = map->id2sd(script_getnum(st, 5)); + } else { + sd = script->rid2sd(st); + } + if (sd != NULL) { + clif->removeSpecialEffect_single(bl, type, &sd->bl); + } + } else { + clif->removeSpecialEffect(bl, type, target); + } + + return true; +} + /*========================================== * Nude [Valaris] *------------------------------------------*/ -BUILDIN(nude) +static BUILDIN(nude) { struct map_session_data *sd = script->rid2sd(st); int i, calcflag = 0; @@ -14360,7 +15364,7 @@ BUILDIN(nude) /*========================================== * gmcommand [MouseJstr] *------------------------------------------*/ -BUILDIN(atcommand) +static BUILDIN(atcommand) { struct map_session_data *sd, *dummy_sd = NULL; int fd; @@ -14402,7 +15406,7 @@ BUILDIN(atcommand) * dispbottom "<message>"{,<color>}; * @endcode */ -BUILDIN(dispbottom) +static BUILDIN(dispbottom) { struct map_session_data *sd = script->rid2sd(st); const char *message = script_getstr(st,2); @@ -14424,28 +15428,68 @@ BUILDIN(dispbottom) * All The Players Full Recovery * (HP/SP full restore and resurrect if need) *------------------------------------------*/ -BUILDIN(recovery) +static int buildin_recovery_sub(struct map_session_data *sd) { - struct map_session_data *sd; - struct s_mapiterator* iter; + nullpo_retr(0, sd); - iter = mapit_getallusers(); - for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) { - if(pc_isdead(sd)) - status->revive(&sd->bl, 100, 100); - else - status_percent_heal(&sd->bl, 100, 100); - clif->message(sd->fd,msg_sd(sd,880)); // "You have been recovered!" + if (pc_isdead(sd)) { + status->revive(&sd->bl, 100, 100); + } else { + status_percent_heal(&sd->bl, 100, 100); + } + + return 0; +} + +static int buildin_recovery_pc_sub(struct map_session_data *sd, va_list ap) +{ + return script->buildin_recovery_sub(sd); +} + +static int buildin_recovery_bl_sub(struct block_list *bl, va_list ap) +{ + return script->buildin_recovery_sub(BL_CAST(BL_PC, bl)); +} + +static BUILDIN(recovery) +{ + if (script_hasdata(st, 2)) { + if (script_isstringtype(st, 2)) { + int16 m = map->mapname2mapid(script_getstr(st, 2)); + + if (m == -1) { + ShowWarning("script:recovery: invalid map!\n"); + return false; + } + + if (script_hasdata(st, 6)) { + int16 x1 = script_getnum(st, 3); + int16 y1 = script_getnum(st, 4); + int16 x2 = script_getnum(st, 5); + int16 y2 = script_getnum(st, 6); + map->foreachinarea(script->buildin_recovery_bl_sub, m, x1, y1, x2, y2, BL_PC); + } else { + map->foreachinmap(script->buildin_recovery_bl_sub, m, BL_PC); + } + } else { + struct map_session_data *sd = script->id2sd(st, script_getnum(st, 2)); + + if (sd != NULL) { + script->buildin_recovery_sub(sd); + } + } + } else { + map->foreachpc(script->buildin_recovery_pc_sub); } - mapit->free(iter); return true; } + /*========================================== * Get your pet info: getpetinfo(n) * n -> 0:pet_id 1:pet_class 2:pet_name * 3:friendly 4:hungry, 5: rename flag. *------------------------------------------*/ -BUILDIN(getpetinfo) +static BUILDIN(getpetinfo) { struct map_session_data *sd = script->rid2sd(st); struct pet_data *pd; @@ -14479,7 +15523,7 @@ BUILDIN(getpetinfo) * 3:friendly 4:hungry, 5: rename flag. * 6: level *------------------------------------------*/ -BUILDIN(gethominfo) +static BUILDIN(gethominfo) { struct map_session_data *sd = script->rid2sd(st); int type = script_getnum(st,2); @@ -14509,7 +15553,7 @@ BUILDIN(gethominfo) /// Retrieves information about character's mercenary /// getmercinfo <type>[,<char id>]; -BUILDIN(getmercinfo) +static BUILDIN(getmercinfo) { int type; struct map_session_data* sd; @@ -14560,21 +15604,20 @@ BUILDIN(getmercinfo) * selected card or not. * checkequipedcard(4001); *------------------------------------------*/ -BUILDIN(checkequipedcard) +static BUILDIN(checkequipedcard) { - int n,i,c=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; - c = script_getnum(st,2); + int c = script_getnum(st,2); - for( i=0; i<MAX_INVENTORY; i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]) { if (itemdb_isspecial(sd->status.inventory[i].card[0])) continue; - for(n=0;n<sd->inventory_data[i]->slot;n++) { + for (int n = 0; n < sd->inventory_data[i]->slot; n++) { if(sd->status.inventory[i].card[n]==c) { script_pushint(st,1); return true; @@ -14587,7 +15630,7 @@ BUILDIN(checkequipedcard) return true; } -BUILDIN(__jump_zero) +static BUILDIN(__jump_zero) { int sel; sel=script_getnum(st,2); @@ -14609,7 +15652,7 @@ BUILDIN(__jump_zero) /*========================================== * movenpc [MouseJstr] *------------------------------------------*/ -BUILDIN(movenpc) +static BUILDIN(movenpc) { struct npc_data *nd = NULL; const char *npc_name; @@ -14631,7 +15674,7 @@ BUILDIN(movenpc) /*========================================== * message [MouseJstr] *------------------------------------------*/ -BUILDIN(message) +static BUILDIN(message) { const char *message; struct map_session_data *sd = NULL; @@ -14650,14 +15693,38 @@ BUILDIN(message) return true; } +static BUILDIN(servicemessage) +{ + struct map_session_data *sd = NULL; + + if (script_hasdata(st, 4)) { + if (script_isstringtype(st, 4)) + sd = script->nick2sd(st, script_getstr(st, 4)); + else + sd = script->id2sd(st, script_getnum(st, 4)); + } else { + sd = script->rid2sd(st); + } + + if (sd == NULL) + return true; + + const char *message = script_getstr(st, 2); + const int color = script_getnum(st, 3); + clif->serviceMessageColor(sd, color, message); + + return true; +} + /*========================================== * npctalk (sends message to surrounding area) - * usage: npctalk "<message>"{,"<npc name>"}; + * usage: npctalk("<message>"{, "<npc name>"{, <show_name>}}); *------------------------------------------*/ -BUILDIN(npctalk) +static BUILDIN(npctalk) { struct npc_data* nd; const char *str = script_getstr(st,2); + bool show_name = true; if (script_hasdata(st, 3)) { nd = npc->name2id(script_getstr(st, 3)); @@ -14665,19 +15732,28 @@ BUILDIN(npctalk) nd = map->id2nd(st->oid); } + if (script_hasdata(st, 4)) { + show_name = (script_getnum(st, 4) != 0) ? true : false; + } + if (nd != NULL) { char name[NAME_LENGTH], message[256]; safestrncpy(name, nd->name, sizeof(name)); strtok(name, "#"); // discard extra name identifier if present - safesnprintf(message, sizeof(message), "%s : %s", name, str); - clif->disp_overhead(&nd->bl, message); + if (show_name) { + safesnprintf(message, sizeof(message), "%s : %s", name, str); + } else { + safesnprintf(message, sizeof(message), "%s", str); + } + clif->disp_overhead(&nd->bl, message, AREA_CHAT_WOC, NULL); } return true; } // change npc walkspeed [Valaris] -BUILDIN(npcspeed) { +static BUILDIN(npcspeed) +{ struct npc_data* nd; int speed; @@ -14693,7 +15769,7 @@ BUILDIN(npcspeed) { return true; } // make an npc walk to a position [Valaris] -BUILDIN(npcwalkto) +static BUILDIN(npcwalkto) { struct npc_data *nd = map->id2nd(st->oid); int x=0,y=0; @@ -14714,7 +15790,7 @@ BUILDIN(npcwalkto) return true; } // stop an npc's movement [Valaris] -BUILDIN(npcstop) +static BUILDIN(npcstop) { struct npc_data *nd = map->id2nd(st->oid); @@ -14727,7 +15803,7 @@ BUILDIN(npcstop) } // set click npc distance [4144] -BUILDIN(setnpcdistance) +static BUILDIN(setnpcdistance) { struct npc_data *nd = map->id2nd(st->oid); if (nd == NULL) @@ -14739,7 +15815,7 @@ BUILDIN(setnpcdistance) } // return current npc direction [4144] -BUILDIN(getnpcdir) +static BUILDIN(getnpcdir) { const struct npc_data *nd = NULL; @@ -14765,7 +15841,7 @@ BUILDIN(getnpcdir) } // set npc direction [4144] -BUILDIN(setnpcdir) +static BUILDIN(setnpcdir) { int newdir; struct npc_data *nd = NULL; @@ -14799,7 +15875,7 @@ BUILDIN(setnpcdir) } // return npc class [4144] -BUILDIN(getnpcclass) +static BUILDIN(getnpcclass) { const struct npc_data *nd = NULL; @@ -14827,7 +15903,7 @@ BUILDIN(getnpcclass) /*========================================== * getlook char info. getlook(arg) *------------------------------------------*/ -BUILDIN(getlook) +static BUILDIN(getlook) { int type,val = -1; struct map_session_data *sd = script->rid2sd(st); @@ -14837,15 +15913,15 @@ BUILDIN(getlook) type=script_getnum(st,2); switch(type) { case LOOK_HAIR: val = sd->status.hair; break; //1 - case LOOK_WEAPON: val = sd->status.weapon; break; //2 - case LOOK_HEAD_BOTTOM: val = sd->status.head_bottom; break; //3 - case LOOK_HEAD_TOP: val = sd->status.head_top; break; //4 - case LOOK_HEAD_MID: val = sd->status.head_mid; break; //5 + case LOOK_WEAPON: val = sd->status.look.weapon; break; //2 + case LOOK_HEAD_BOTTOM: val = sd->status.look.head_bottom; break; //3 + case LOOK_HEAD_TOP: val = sd->status.look.head_top; break; //4 + case LOOK_HEAD_MID: val = sd->status.look.head_mid; break; //5 case LOOK_HAIR_COLOR: val = sd->status.hair_color; break; //6 case LOOK_CLOTHES_COLOR: val = sd->status.clothes_color; break; //7 - case LOOK_SHIELD: val = sd->status.shield; break; //8 + case LOOK_SHIELD: val = sd->status.look.shield; break; //8 case LOOK_SHOES: break; //9 - case LOOK_ROBE: val = sd->status.robe; break; //12 + case LOOK_ROBE: val = sd->status.look.robe; break; //12 case LOOK_BODY2: val=sd->status.body; break; //13 } @@ -14856,7 +15932,7 @@ BUILDIN(getlook) /*========================================== * get char save point. argument: 0- map name, 1- x, 2- y *------------------------------------------*/ -BUILDIN(getsavepoint) +static BUILDIN(getsavepoint) { int type; struct map_session_data *sd = script->rid2sd(st); @@ -14899,7 +15975,7 @@ BUILDIN(getsavepoint) * 0 - success * -1 - some error, MapName$,MapX,MapY contains unknown value. *------------------------------------------*/ -BUILDIN(getmapxy) +static BUILDIN(getmapxy) { struct block_list *bl = NULL; struct map_session_data *sd = NULL; @@ -15095,23 +16171,42 @@ BUILDIN(getmapxy) return true; } +enum logmes_type { + LOGMES_NPC, + LOGMES_ATCOMMAND +}; + /*========================================== - * Allows player to write NPC logs (i.e. Bank NPC, etc) [Lupus] + * Allows player to write logs (i.e. Bank NPC, etc) [Lupus] *------------------------------------------*/ -BUILDIN(logmes) +static BUILDIN(logmes) { - const char *str; + const char *str = script_getstr(st, 2); struct map_session_data *sd = script->rid2sd(st); + enum logmes_type type = LOGMES_NPC; + nullpo_retr(false, sd); - if (sd == NULL) - return true; + if (script_hasdata(st, 3)) { + type = script_getnum(st, 3); + } + + switch (type) { + case LOGMES_ATCOMMAND: + logs->atcommand(sd, str); + break; + case LOGMES_NPC: + logs->npc(sd, str); + break; + default: + ShowError("script:logmes: Unknown log type!\n"); + st->state = END; + return false; + } - str = script_getstr(st,2); - logs->npc(sd,str); return true; } -BUILDIN(summon) +static BUILDIN(summon) { int class_, timeout=0; const char *str,*event=""; @@ -15149,7 +16244,8 @@ BUILDIN(summon) /*========================================== * Checks whether it is daytime/nighttime *------------------------------------------*/ -BUILDIN(isnight) { +static BUILDIN(isnight) +{ script_pushint(st,(map->night_flag == 1)); return true; } @@ -15158,7 +16254,7 @@ BUILDIN(isnight) { * Check how many items/cards in the list are * equipped - used for 2/15's cards patch [celest] *------------------------------------------------*/ -BUILDIN(isequippedcnt) +static BUILDIN(isequippedcnt) { int i, j, k, id = 1; int ret = 0; @@ -15207,7 +16303,7 @@ BUILDIN(isequippedcnt) * -- Items checked cannot be reused in another * card set to prevent exploits *------------------------------------------------*/ -BUILDIN(isequipped) +static BUILDIN(isequipped) { int i, j, k, id = 1; int index, flag; @@ -15287,7 +16383,7 @@ BUILDIN(isequipped) * Check how many given inserted cards in the CURRENT * weapon - used for 2/15's cards patch [Lupus] *------------------------------------------------*/ -BUILDIN(cardscnt) +static BUILDIN(cardscnt) { int i, k, id = 1; int ret = 0; @@ -15329,7 +16425,7 @@ BUILDIN(cardscnt) * Returns the refined number of the current item, or an * item with inventory index specified *-------------------------------------------------------*/ -BUILDIN(getrefine) +static BUILDIN(getrefine) { struct map_session_data *sd = script->rid2sd(st); @@ -15346,11 +16442,13 @@ BUILDIN(getrefine) /*======================================================= * Day/Night controls *-------------------------------------------------------*/ -BUILDIN(night) { +static BUILDIN(night) +{ if (map->night_flag != 1) pc->map_night_timer(pc->night_timer_tid, 0, 0, 1); return true; } -BUILDIN(day) { +static BUILDIN(day) +{ if (map->night_flag != 0) pc->map_day_timer(pc->day_timer_tid, 0, 0, 1); return true; } @@ -15358,7 +16456,7 @@ BUILDIN(day) { //======================================================= // Unequip [Spectre] //------------------------------------------------------- -BUILDIN(unequip) +static BUILDIN(unequip) { size_t num; struct map_session_data *sd; @@ -15373,7 +16471,7 @@ BUILDIN(unequip) return true; } -BUILDIN(equip) +static BUILDIN(equip) { int nameid=0,i; struct item_data *item_data; @@ -15384,17 +16482,17 @@ BUILDIN(equip) nameid=script_getnum(st,2); if((item_data = itemdb->exists(nameid)) == NULL) { - ShowError("wrong item ID : equipitem(%i)\n",nameid); + ShowError("wrong item ID : equipitem(%d)\n",nameid); return false; } - ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0 ); - if( i < MAX_INVENTORY ) - pc->equipitem(sd,i,item_data->equip); + ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0); + if (i < sd->status.inventorySize) + pc->equipitem(sd, i, item_data->equip); return true; } -BUILDIN(autoequip) +static BUILDIN(autoequip) { int nameid, flag; struct item_data *item_data; @@ -15421,7 +16519,7 @@ BUILDIN(autoequip) * Equip2 * equip2 <item id>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>; *-------------------------------------------------------*/ -BUILDIN(equip2) +static BUILDIN(equip2) { int i,nameid,ref,attr,c0,c1,c2,c3; struct item_data *item_data; @@ -15440,33 +16538,33 @@ BUILDIN(equip2) return false; } - ref = script_getnum(st,3); - attr = script_getnum(st,4); - c0 = (short)script_getnum(st,5); - c1 = (short)script_getnum(st,6); - c2 = (short)script_getnum(st,7); - c3 = (short)script_getnum(st,8); + ref = script_getnum(st, 3); + attr = script_getnum(st, 4); + c0 = script_getnum(st, 5); + c1 = script_getnum(st, 6); + c2 = script_getnum(st, 7); + c3 = script_getnum(st, 8); - ARR_FIND( 0, MAX_INVENTORY, i,( sd->status.inventory[i].equip == 0 && + ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].equip == 0 && sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].refine == ref && sd->status.inventory[i].attribute == attr && sd->status.inventory[i].card[0] == c0 && sd->status.inventory[i].card[1] == c1 && sd->status.inventory[i].card[2] == c2 && - sd->status.inventory[i].card[3] == c3 ) ); + sd->status.inventory[i].card[3] == c3)); - if( i < MAX_INVENTORY ) { + if (i < sd->status.inventorySize) { script_pushint(st,1); pc->equipitem(sd,i,item_data->equip); - } - else + } else { script_pushint(st,0); + } return true; } -BUILDIN(setbattleflag) +static BUILDIN(setbattleflag) { const char *flag, *value; @@ -15481,7 +16579,7 @@ BUILDIN(setbattleflag) return true; } -BUILDIN(getbattleflag) +static BUILDIN(getbattleflag) { const char *flag; int value; @@ -15503,7 +16601,7 @@ BUILDIN(getbattleflag) //======================================================= // strlen [Valaris] //------------------------------------------------------- -BUILDIN(getstrlen) +static BUILDIN(getstrlen) { const char *str = script_getstr(st,2); @@ -15516,7 +16614,7 @@ BUILDIN(getstrlen) //======================================================= // isalpha [Valaris] //------------------------------------------------------- -BUILDIN(charisalpha) +static BUILDIN(charisalpha) { const char *str=script_getstr(st,2); int pos=script_getnum(st,3); @@ -15530,7 +16628,7 @@ BUILDIN(charisalpha) //======================================================= // charisupper <str>, <index> //------------------------------------------------------- -BUILDIN(charisupper) +static BUILDIN(charisupper) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); @@ -15544,7 +16642,7 @@ BUILDIN(charisupper) //======================================================= // charislower <str>, <index> //------------------------------------------------------- -BUILDIN(charislower) +static BUILDIN(charislower) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); @@ -15558,7 +16656,8 @@ BUILDIN(charislower) //======================================================= // charat <str>, <index> //------------------------------------------------------- -BUILDIN(charat) { +static BUILDIN(charat) +{ const char *str = script_getstr(st,2); int pos = script_getnum(st,3); @@ -15573,9 +16672,141 @@ BUILDIN(charat) { } //======================================================= +// isstr <argument> +// +// returns type: +// 0 - int +// 1 - string +// 2 - other +//------------------------------------------------------- +static BUILDIN(isstr) +{ + if (script_isinttype(st, 2)) { + script_pushint(st, 0); + } else if (script_isstringtype(st, 2)) { + script_pushint(st, 1); + } else { + script_pushint(st, 2); + } + return true; +} + +enum datatype { + DATATYPE_NIL = 1 << 7, // we don't start at 1, to leave room for primitives + DATATYPE_STR = 1 << 8, + DATATYPE_INT = 1 << 9, + DATATYPE_CONST = 1 << 10, + DATATYPE_PARAM = 1 << 11, + DATATYPE_VAR = 1 << 12, + DATATYPE_LABEL = 1 << 13, +}; + +static BUILDIN(getdatatype) +{ + int type; + + if (script_hasdata(st, 2)) { + struct script_data *data = script_getdata(st, 2); + + if (data_isstring(data)) { + type = DATATYPE_STR; + if (data->type == C_CONSTSTR) { + type |= DATATYPE_CONST; + } + } else if (data_isint(data)) { + type = DATATYPE_INT; + } else if (data_islabel(data)) { + type = DATATYPE_LABEL; + } else if (data_isreference(data)) { + if (reference_toconstant(data)) { + type = DATATYPE_CONST | DATATYPE_INT; + } else if (reference_toparam(data)) { + type = DATATYPE_PARAM | DATATYPE_INT; + } else if (reference_tovariable(data)) { + type = DATATYPE_VAR; + if (is_string_variable(reference_getname(data))) { + type |= DATATYPE_STR; + } else { + type |= DATATYPE_INT; + } + } else { + ShowError("script:getdatatype: Unknown reference type!\n"); + script->reportdata(data); + st->state = END; + return false; + } + } else { + type = data->type; // fallback to primitive type if unknown + } + } else { + type = DATATYPE_NIL; // nothing was passed + } + + script_pushint(st, type); + return true; +} + +static BUILDIN(data_to_string) +{ + if (script_hasdata(st, 2)) { + struct script_data *data = script_getdata(st, 2); + + if (data_isstring(data)) { + script_pushcopy(st, 2); + } else if (data_isint(data)) { + char *str = NULL; + + CREATE(str, char, 20); + safesnprintf(str, 20, "%"PRId64"", data->u.num); + script_pushstr(st, str); + } else if (data_islabel(data)) { + const char *str = ""; + + // XXX: because all we have is the label pos we can't be sure which + // one is the correct label if more than one has the same pos. + // We might want to store both the pos and str_data index in + // data->u.num, similar to how C_NAME stores both the array + // index and str_data index in u.num with bitmasking. This + // would also avoid the awkward for() loops as we could + // directly access the string with script->get_str(). + + if (st->oid) { + struct npc_data *nd = map->id2nd(st->oid); + + for (int i = 0; i < nd->u.scr.label_list_num; ++i) { + if (nd->u.scr.label_list[i].pos == data->u.num) { + str = nd->u.scr.label_list[i].name; + break; + } + } + } else { + for (int i = LABEL_START; script->str_data[i].next != 0; i = script->str_data[i].next) { + if (script->str_data[i].label == data->u.num) { + str = script->get_str(i); + break; + } + } + } + + script_pushconststr(st, str); + } else if (data_isreference(data)) { + script_pushstrcopy(st, reference_getname(data)); + } else { + ShowWarning("script:data_to_string: unknown data type!\n"); + script->reportdata(data); + script_pushconststr(st, ""); + } + } else { + script_pushconststr(st, ""); // NIL + } + + return true; +} + +//======================================================= // chr <int> //------------------------------------------------------- -BUILDIN(chr) +static BUILDIN(chr) { char output[2]; output[0] = script_getnum(st, 2); @@ -15588,7 +16819,7 @@ BUILDIN(chr) //======================================================= // ord <chr> //------------------------------------------------------- -BUILDIN(ord) +static BUILDIN(ord) { const char *chr = script_getstr(st, 2); script_pushint(st, *chr); @@ -15598,7 +16829,7 @@ BUILDIN(ord) //======================================================= // setchar <string>, <char>, <index> //------------------------------------------------------- -BUILDIN(setchar) +static BUILDIN(setchar) { const char *str = script_getstr(st,2); const char *c = script_getstr(st,3); @@ -15615,7 +16846,7 @@ BUILDIN(setchar) //======================================================= // insertchar <string>, <char>, <index> //------------------------------------------------------- -BUILDIN(insertchar) +static BUILDIN(insertchar) { const char *str = script_getstr(st,2); const char *c = script_getstr(st,3); @@ -15642,7 +16873,7 @@ BUILDIN(insertchar) //======================================================= // delchar <string>, <index> //------------------------------------------------------- -BUILDIN(delchar) +static BUILDIN(delchar) { const char *str = script_getstr(st,2); int index = script_getnum(st,3); @@ -15668,7 +16899,7 @@ BUILDIN(delchar) //======================================================= // strtoupper <str> //------------------------------------------------------- -BUILDIN(strtoupper) +static BUILDIN(strtoupper) { const char *str = script_getstr(st,2); char *output = aStrdup(str); @@ -15686,7 +16917,7 @@ BUILDIN(strtoupper) //======================================================= // strtolower <str> //------------------------------------------------------- -BUILDIN(strtolower) +static BUILDIN(strtolower) { const char *str = script_getstr(st,2); char *output = aStrdup(str); @@ -15704,7 +16935,7 @@ BUILDIN(strtolower) //======================================================= // substr <str>, <start>, <end> //------------------------------------------------------- -BUILDIN(substr) +static BUILDIN(substr) { const char *str = script_getstr(st,2); char *output; @@ -15730,7 +16961,7 @@ BUILDIN(substr) // explode <dest_string_array>, <str>, <delimiter> // Note: delimiter is limited to 1 char //------------------------------------------------------- -BUILDIN(explode) +static BUILDIN(explode) { struct script_data* data = script_getdata(st, 2); const char *str = script_getstr(st,3); @@ -15795,7 +17026,7 @@ BUILDIN(explode) // implode <string_array> // implode <string_array>, <glue> //------------------------------------------------------- -BUILDIN(implode) +static BUILDIN(implode) { struct script_data* data = script_getdata(st, 2); const char *name; @@ -15887,12 +17118,12 @@ BUILDIN(implode) // Implements C sprintf, except format %n. The resulting string is // returned, instead of being saved in variable by reference. //------------------------------------------------------- -BUILDIN(sprintf) +static BUILDIN(sprintf) { struct StringBuf buf; StrBuf->Init(&buf); - if (!script_sprintf(st, 2, &buf)) { + if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushconststr(st, ""); return false; @@ -15908,7 +17139,8 @@ BUILDIN(sprintf) // sscanf(<str>, <format>, ...); // Implements C sscanf. //------------------------------------------------------- -BUILDIN(sscanf) { +static BUILDIN(sscanf) +{ unsigned int argc, arg = 0; struct script_data* data; struct map_session_data* sd = NULL; @@ -16021,7 +17253,8 @@ BUILDIN(sscanf) { // Implements PHP style strpos. Adapted from code from // http://www.daniweb.com/code/snippet313.html, Dave Sinkula //------------------------------------------------------- -BUILDIN(strpos) { +static BUILDIN(strpos) +{ const char *haystack = script_getstr(st,2); const char *needle = script_getstr(st,3); int i; @@ -16065,7 +17298,7 @@ BUILDIN(strpos) { // instances as specified in <count>. By default will be case // sensitive. //--------------------------------------------------------------- -BUILDIN(replacestr) +static BUILDIN(replacestr) { const char *input = script_getstr(st, 2); const char *find = script_getstr(st, 3); @@ -16148,7 +17381,7 @@ BUILDIN(replacestr) // Note: Counts the number of times <search> occurs in // <input>. By default will be case sensitive. //-------------------------------------------------------- -BUILDIN(countstr) +static BUILDIN(countstr) { const char *input = script_getstr(st, 2); const char *find = script_getstr(st, 3); @@ -16205,7 +17438,8 @@ BUILDIN(countstr) /// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int> /// setnpcdisplay("<npc name>", "<new display name>") -> <int> /// setnpcdisplay("<npc name>", <new class id>) -> <int> -BUILDIN(setnpcdisplay) { +static BUILDIN(setnpcdisplay) +{ const char* name; const char* newname = NULL; int class_ = -1, size = -1; @@ -16251,14 +17485,16 @@ BUILDIN(setnpcdisplay) { return true; } -BUILDIN(atoi) { +static BUILDIN(atoi) +{ const char *value; value = script_getstr(st,2); script_pushint(st,atoi(value)); return true; } -BUILDIN(axtoi) { +static BUILDIN(axtoi) +{ const char *hex = script_getstr(st,2); long value = strtol(hex, NULL, 16); #if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN @@ -16268,7 +17504,8 @@ BUILDIN(axtoi) { return true; } -BUILDIN(strtol) { +static BUILDIN(strtol) +{ const char *string = script_getstr(st, 2); int base = script_getnum(st, 3); long value = strtol(string, NULL, base); @@ -16280,7 +17517,7 @@ BUILDIN(strtol) { } // case-insensitive substring search [lordalfa] -BUILDIN(compare) +static BUILDIN(compare) { const char *message; const char *cmpstring; @@ -16290,7 +17527,7 @@ BUILDIN(compare) return true; } -BUILDIN(strcmp) +static BUILDIN(strcmp) { const char *str1 = script_getstr(st,2); const char *str2 = script_getstr(st,3); @@ -16300,7 +17537,7 @@ BUILDIN(strcmp) // List of mathematics commands ---> -BUILDIN(log10) +static BUILDIN(log10) { double i, a; i = script_getnum(st,2); @@ -16309,7 +17546,7 @@ BUILDIN(log10) return true; } -BUILDIN(sqrt) //[zBuffer] +static BUILDIN(sqrt) //[zBuffer] { double i, a; i = script_getnum(st,2); @@ -16322,7 +17559,7 @@ BUILDIN(sqrt) //[zBuffer] return true; } -BUILDIN(pow) //[zBuffer] +static BUILDIN(pow) //[zBuffer] { double i, a, b; a = script_getnum(st,2); @@ -16332,7 +17569,7 @@ BUILDIN(pow) //[zBuffer] return true; } -BUILDIN(distance) //[zBuffer] +static BUILDIN(distance) //[zBuffer] { int x0, y0, x1, y1; @@ -16347,7 +17584,7 @@ BUILDIN(distance) //[zBuffer] // <--- List of mathematics commands -BUILDIN(min) +static BUILDIN(min) { int i, min; @@ -16362,7 +17599,7 @@ BUILDIN(min) return true; } -BUILDIN(max) +static BUILDIN(max) { int i, max; @@ -16377,7 +17614,7 @@ BUILDIN(max) return true; } -BUILDIN(md5) +static BUILDIN(md5) { const char *tmpstr; char *md5str; @@ -16389,10 +17626,11 @@ BUILDIN(md5) return true; } -BUILDIN(swap) +static BUILDIN(swap) { struct map_session_data *sd = NULL; struct script_data *data1, *data2; + struct reg_db *ref1, *ref2; const char *varname1, *varname2; int64 uid1, uid2; @@ -16433,6 +17671,8 @@ BUILDIN(swap) uid1 = reference_getuid(data1); uid2 = reference_getuid(data2); + ref1 = reference_getref(data1); + ref2 = reference_getref(data2); if (is_string_variable(varname1)) { const char *value1, *value2; @@ -16441,8 +17681,8 @@ BUILDIN(swap) value2 = script_getstr(st,3); if (strcmpi(value1, value2)) { - script->set_reg(st, sd, uid1, varname1, value2, script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, value1, script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, value2, ref1); + script->set_reg(st, sd, uid2, varname2, value1, ref2); } } else { @@ -16452,8 +17692,8 @@ BUILDIN(swap) value2 = script_getnum(st,3); if (value1 != value2) { - script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), script_getref(st,3)); - script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), script_getref(st,2)); + script->set_reg(st, sd, uid1, varname1, (const void *)h64BPTRSIZE(value2), ref1); + script->set_reg(st, sd, uid2, varname2, (const void *)h64BPTRSIZE(value1), ref2); } } return true; @@ -16461,7 +17701,7 @@ BUILDIN(swap) // [zBuffer] List of dynamic var commands ---> -BUILDIN(setd) +static BUILDIN(setd) { struct map_session_data *sd = NULL; char varname[100]; @@ -16491,7 +17731,7 @@ BUILDIN(setd) return true; } -int buildin_query_sql_sub(struct script_state *st, struct Sql *handle) +static int buildin_query_sql_sub(struct script_state *st, struct Sql *handle) { int i, j; struct map_session_data *sd = NULL; @@ -16573,11 +17813,13 @@ int buildin_query_sql_sub(struct script_state *st, struct Sql *handle) return true; } -BUILDIN(query_sql) { +static BUILDIN(query_sql) +{ return script->buildin_query_sql_sub(st, map->mysql_handle); } -BUILDIN(query_logsql) { +static BUILDIN(query_logsql) +{ if( !logs->config.sql_logs ) {// logs->mysql_handle == NULL ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2)); script_pushint(st,-1); @@ -16587,7 +17829,7 @@ BUILDIN(query_logsql) { } //Allows escaping of a given string. -BUILDIN(escape_sql) +static BUILDIN(escape_sql) { const char *str; char *esc_str; @@ -16601,25 +17843,37 @@ BUILDIN(escape_sql) return true; } -BUILDIN(getd) { +static BUILDIN(getd) +{ char varname[100]; const char *buffer; int elem; + int id; buffer = script_getstr(st, 2); if (sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2) elem = 0; + id = script->add_variable(varname); + + if (script->str_data[id].type != C_NAME && // variable + script->str_data[id].type != C_PARAM && // param + script->str_data[id].type != C_INT) { // constant + ShowError("script:getd: `%s` is already used by something that is not a variable.\n", varname); + st->state = END; + return false; + } + // Push the 'pointer' so it's more flexible [Lance] - script->push_val(st->stack, C_NAME, reference_uid(script->add_str(varname), elem),NULL); + script->push_val(st->stack, C_NAME, reference_uid(id, elem),NULL); return true; } // <--- [zBuffer] List of dynamic var commands // Pet stat [Lance] -BUILDIN(petstat) +static BUILDIN(petstat) { struct pet_data *pd; int flag = script_getnum(st,2); @@ -16645,7 +17899,7 @@ BUILDIN(petstat) return true; } -BUILDIN(callshop) +static BUILDIN(callshop) { struct npc_data *nd; const char *shopname; @@ -16685,7 +17939,7 @@ BUILDIN(callshop) return true; } -BUILDIN(npcshopitem) +static BUILDIN(npcshopitem) { const char* npcname = script_getstr(st, 2); struct npc_data* nd = npc->name2id(npcname); @@ -16714,7 +17968,7 @@ BUILDIN(npcshopitem) return true; } -BUILDIN(npcshopadditem) +static BUILDIN(npcshopadditem) { const char* npcname = script_getstr(st,2); struct npc_data* nd = npc->name2id(npcname); @@ -16743,7 +17997,7 @@ BUILDIN(npcshopadditem) return true; } -BUILDIN(npcshopdelitem) +static BUILDIN(npcshopdelitem) { const char* npcname = script_getstr(st,2); struct npc_data* nd = npc->name2id(npcname); @@ -16779,7 +18033,8 @@ BUILDIN(npcshopdelitem) } //Sets a script to attach to a shop npc. -BUILDIN(npcshopattach) { +static BUILDIN(npcshopattach) +{ const char* npcname = script_getstr(st,2); struct npc_data* nd = npc->name2id(npcname); int flag = 1; @@ -16811,7 +18066,7 @@ BUILDIN(npcshopattach) { * 1 - Equip script * 2 - Unequip script *------------------------------------------*/ -BUILDIN(setitemscript) +static BUILDIN(setitemscript) { int item_id,n=0; const char *new_bonus_script; @@ -16857,7 +18112,8 @@ BUILDIN(setitemscript) * is updated to the new rate. Rate must be in the range [1:10000] * Returns 1 if succeeded (added/updated a mob drop) *-------------------------------------------------------*/ -BUILDIN(addmonsterdrop) { +static BUILDIN(addmonsterdrop) +{ struct mob_db *monster; int item_id, rate, i, c = MAX_MOB_DROP; @@ -16917,7 +18173,8 @@ BUILDIN(addmonsterdrop) { * * Returns 1 if succeeded (deleted a mob drop) *-------------------------------------------------------*/ -BUILDIN(delmonsterdrop) { +static BUILDIN(delmonsterdrop) +{ struct mob_db *monster; int item_id, i; @@ -16959,7 +18216,7 @@ BUILDIN(delmonsterdrop) { * Name, Level, race, size, etc... * getmonsterinfo(monsterID,queryIndex); *------------------------------------------*/ -BUILDIN(getmonsterinfo) +static BUILDIN(getmonsterinfo) { struct mob_db *monster; int mob_id; @@ -17003,7 +18260,7 @@ BUILDIN(getmonsterinfo) return true; } -BUILDIN(checkvending) // check vending [Nab4] +static BUILDIN(checkvending) // check vending [Nab4] { struct map_session_data *sd = NULL; @@ -17021,7 +18278,8 @@ BUILDIN(checkvending) // check vending [Nab4] } // check chatting [Marka] -BUILDIN(checkchatting) { +static BUILDIN(checkchatting) +{ struct map_session_data *sd = NULL; if (script_hasdata(st,2)) @@ -17037,7 +18295,8 @@ BUILDIN(checkchatting) { return true; } -BUILDIN(checkidle) { +static BUILDIN(checkidle) +{ struct map_session_data *sd = NULL; if (script_hasdata(st, 2)) @@ -17053,7 +18312,7 @@ BUILDIN(checkidle) { return true; } -BUILDIN(searchitem) +static BUILDIN(searchitem) { struct script_data* data = script_getdata(st, 2); const char *itemname = script_getstr(st,3); @@ -17116,7 +18375,7 @@ BUILDIN(searchitem) } // [zBuffer] List of player cont commands ---> -BUILDIN(rid2name) +static BUILDIN(rid2name) { struct block_list *bl = NULL; int rid = script_getnum(st,2); @@ -17140,7 +18399,8 @@ BUILDIN(rid2name) return true; } -BUILDIN(pcblockmove) { +static BUILDIN(pcblockmove) +{ int id, flag; struct map_session_data *sd = NULL; @@ -17152,13 +18412,92 @@ BUILDIN(pcblockmove) { else sd = script->rid2sd(st); - if (sd != NULL) - sd->state.blockedmove = flag > 0; + if (!sd) + return true; + + if (flag) + sd->block_action.move = 1; + else + sd->block_action.move = 0; + + return true; +} + +static BUILDIN(setpcblock) +{ + struct map_session_data *sd = script->rid2sd(st); + enum pcblock_action_flag type = script_getnum(st, 2); + int state = (script_getnum(st, 3) > 0) ? 1 : 0; + + if (sd == NULL) + return true; + + if ((type & PCBLOCK_MOVE) != 0) + sd->block_action.move = state; + + if ((type & PCBLOCK_ATTACK) != 0) + sd->block_action.attack = state; + + if ((type & PCBLOCK_SKILL) != 0) + sd->block_action.skill = state; + + if ((type & PCBLOCK_USEITEM) != 0) + sd->block_action.useitem = state; + + if ((type & PCBLOCK_CHAT) != 0) + sd->block_action.chat = state; + + if ((type & PCBLOCK_IMMUNE) != 0) + sd->block_action.immune = state; + + if ((type & PCBLOCK_SITSTAND) != 0) + sd->block_action.sitstand = state; + + if ((type & PCBLOCK_COMMANDS) != 0) + sd->block_action.commands = state; + + return true; +} + +static BUILDIN(checkpcblock) +{ + struct map_session_data *sd = script->rid2sd(st); + int retval = PCBLOCK_NONE; + if (sd == NULL) { + script_pushint(st, PCBLOCK_NONE); + return true; + } + + if (sd->block_action.move != 0) + retval |= PCBLOCK_MOVE; + + if (sd->block_action.attack != 0) + retval |= PCBLOCK_ATTACK; + + if (sd->block_action.skill != 0) + retval |= PCBLOCK_SKILL; + + if (sd->block_action.useitem != 0) + retval |= PCBLOCK_USEITEM; + + if (sd->block_action.chat != 0) + retval |= PCBLOCK_CHAT; + + if (sd->block_action.immune != 0) + retval |= PCBLOCK_IMMUNE; + + if (sd->block_action.sitstand != 0) + retval |= PCBLOCK_SITSTAND; + + if (sd->block_action.commands != 0) + retval |= PCBLOCK_COMMANDS; + + script_pushint(st, retval); return true; } -BUILDIN(pcfollow) +static BUILDIN(pcfollow) { int id, targetid; struct map_session_data *sd = NULL; @@ -17177,7 +18516,7 @@ BUILDIN(pcfollow) return true; } -BUILDIN(pcstopfollow) +static BUILDIN(pcstopfollow) { int id; struct map_session_data *sd = NULL; @@ -17198,7 +18537,8 @@ BUILDIN(pcstopfollow) // [zBuffer] List of mob control commands ---> //## TODO always return if the request/whatever was successfull [FlavioJS] -BUILDIN(getunittype) { +static BUILDIN(getunittype) +{ struct block_list* bl; int value; @@ -17225,12 +18565,1647 @@ BUILDIN(getunittype) { return true; } +/** + * Sets real-time unit data for a game object. + * Setunitdata <GUID>,<DataType>,<Val1>{,<Val2>,<Val3>} + * @param1 GUID GID of the unit. + * @param2 DataType Type of Data to be set for the unit. + * @param3 Value#1 Value to be passed as change in data. + * @param4 Value#2 Optional int value to be passed for certain data types. + * @param5 Value#3 Optional int value to be passed for certain data types. + * @return 1 on success, 0 on failure. + */ +static BUILDIN(setunitdata) +{ + struct block_list *bl = NULL; + const char *mapname = NULL, *udtype = NULL; + int type = 0, val = 0, val2 = 0, val3 = 0; + struct map_session_data *tsd = NULL; + + bl = map->id2bl(script_getnum(st, 2)); + + if (bl == NULL) { + ShowWarning("buildin_setunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2)); + script_pushint(st, 0); + return false; + } + + type = script_getnum(st, 3); + + /* type bounds */ + if (type < UDT_SIZE || type >= UDT_MAX) { // Note: UDT_TYPE is not valid here + ShowError("buildin_setunitdata: Invalid unit data type %d provided.\n", type); + script_pushint(st, 0); + return false; + } + + /* Mandatory Argument 3 */ + if (type == UDT_MAPIDXY) { + if (!script_isstringtype(st, 4)) { + ShowError("buildin_setunitdata: Invalid data type for argument #3.\n"); + script_pushint(st, 0); + return false; + } + mapname = script_getstr(st, 4); + } else { + if (script_isstringtype(st, 4)) { + ShowError("buildin_setunitdata: Invalid data type for argument #3.\n"); + script_pushint(st, 0); + return false; + } + val = script_getnum(st, 4); + } +/* checks if value is out of bounds. */ +#define setunitdata_check_bounds(arg, min, max) \ + do { \ + if (script_getnum(st, (arg)) < (min) || script_getnum(st, (arg)) > (max)) { \ + ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", script_getnum(st, (arg)), (arg)-1, (min), (max)); \ + script_pushint(st, 0); \ + return false; \ + } \ + } while(0); +/* checks if value is out of bounds. */ +#define setunitdata_check_min(arg, min) \ + do { \ + if (script_getnum(st, (arg)) < (min)) { \ + ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", script_getnum(st, (arg)), (arg)-1, (min)); \ + script_pushint(st, 0); \ + return false; \ + } \ + } while(0); +/* checks if the argument doesn't exist, if required. + * also checks if the argument exists, if not required. */ +#define setunitdata_assert_arg(arg, required) \ + do { \ + if (required && !script_hasdata(st, (arg))) { \ + ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg)-1); \ + script_pushint(st, 0); \ + return false; \ + } else if (!required && script_hasdata(st, arg)) { \ + ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg)-1, type); \ + script_pushint(st, 0); \ + return false; \ + } \ + } while (0); +/* checks if the data is an integer. */ +#define setunitdata_check_int(arg) \ + do { \ + setunitdata_assert_arg((arg), true); \ + if (script_isstringtype(st, (arg))) { \ + ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg)-1); \ + script_pushint(st, 0); \ + return false; \ + } \ + } while(0); +/* checks if the data is a string. */ +#define setunitdata_check_string(arg) \ + do { \ + setunitdata_assert_arg((arg), true); \ + if (script_isinttype(st, (arg))) { \ + ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg)-1); \ + script_pushint(st, 0); \ + return false; \ + } \ + } while(0); + + if (type != UDT_MAPIDXY && type != UDT_WALKTOXY) { + setunitdata_assert_arg(5, false); + setunitdata_assert_arg(6, false); + } + + switch (type) + { + case UDT_SIZE: + setunitdata_check_bounds(4, SZ_SMALL, SZ_BIG); + break; + case UDT_LEVEL: + case UDT_HP: + case UDT_MAXHP: + case UDT_SP: + case UDT_MAXSP: + case UDT_CLASS: + case UDT_HEADBOTTOM: + case UDT_HEADMIDDLE: + case UDT_HEADTOP: + case UDT_CLOTHCOLOR: + case UDT_SHIELD: + case UDT_WEAPON: + case UDT_INTIMACY: + case UDT_LIFETIME: + case UDT_MERC_KILLCOUNT: + case UDT_ROBE: + case UDT_BODY2: + setunitdata_check_min(4, 0); + break; + case UDT_MASTERAID: + setunitdata_check_min(4, 0); + tsd = map->id2sd(val); + if (tsd == NULL) { + ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n",val); + script_pushint(st, 0); + return false; + } + break; + case UDT_MASTERCID: + setunitdata_check_min(4, 0); + tsd = map->charid2sd(val); + if (tsd == NULL) { + ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n",val); + script_pushint(st, 0); + return false; + } + break; + case UDT_MAPIDXY: + if ((val = map->mapname2mapid(mapname)) == -1) { + ShowError("buildin_setunitdata: Non-existent map %s provided.\n", mapname); + return false; + } + setunitdata_check_int(5); + setunitdata_check_int(6); + setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2); + setunitdata_check_bounds(6, 0, MAX_MAP_SIZE/2); + val2 = script_getnum(st, 5); + val3 = script_getnum(st, 6); + break; + case UDT_WALKTOXY: + setunitdata_assert_arg(6, false); + setunitdata_check_int(5); + val2 = script_getnum(st, 5); + setunitdata_check_bounds(4, 0, MAX_MAP_SIZE/2); + setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2); + break; + case UDT_SPEED: + setunitdata_check_bounds(4, 0, MAX_WALK_SPEED); + break; + case UDT_MODE: + setunitdata_check_bounds(4, MD_NONE, MD_MASK); + break; + case UDT_AI: + setunitdata_check_bounds(4, AI_NONE, AI_MAX-1); + break; + case UDT_SCOPTION: + setunitdata_check_bounds(4, OPTION_NOTHING, OPTION_COSTUME); + break; + case UDT_SEX: + setunitdata_check_bounds(4, SEX_FEMALE, SEX_MALE); + break; + case UDT_HAIRSTYLE: + setunitdata_check_bounds(4, 0, battle->bc->max_hair_style); + break; + case UDT_HAIRCOLOR: + setunitdata_check_bounds(4, 0, battle->bc->max_hair_color); + break; + case UDT_LOOKDIR: + setunitdata_check_bounds(4, 0, 7); + break; + case UDT_CANMOVETICK: + setunitdata_check_min(4, 0); + break; + case UDT_STR: + case UDT_AGI: + case UDT_VIT: + case UDT_INT: + case UDT_DEX: + case UDT_LUK: + case UDT_STATPOINT: + case UDT_ATKRANGE: + case UDT_ATKMIN: + case UDT_ATKMAX: + case UDT_MATKMIN: + case UDT_MATKMAX: + case UDT_AMOTION: + case UDT_ADELAY: + case UDT_DMOTION: + setunitdata_check_bounds(4, 0, USHRT_MAX); + break; + case UDT_DEF: + case UDT_MDEF: + case UDT_HIT: + case UDT_FLEE: + case UDT_PDODGE: + case UDT_CRIT: + setunitdata_check_bounds(4, 0, SHRT_MAX); + break; + case UDT_HUNGER: + setunitdata_check_bounds(4, 0, 99); + break; + case UDT_RACE: + case UDT_ELETYPE: + case UDT_ELELEVEL: + setunitdata_check_bounds(4, 0, CHAR_MAX); + break; + default: + break; + } + +#undef setunitdata_check_bounds +#undef setunitdata_assert_arg +#undef setunitdata_check_int +#undef setunitdata_check_string + + /* Set the values */ + switch (bl->type) { + case BL_MOB: + { + struct mob_data *md = BL_UCAST(BL_MOB, bl); + nullpo_retr(false, md); + + switch (type) + { + case UDT_SIZE: + md->status.size = (unsigned char) val; + break; + case UDT_LEVEL: + md->level = val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + clif->charnameack(0, &md->bl); + break; + case UDT_MAXHP: + md->status.max_hp = (unsigned int) val; + clif->charnameack(0, &md->bl); + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + md->status.max_sp = (unsigned int) val; + break; + case UDT_MASTERAID: + md->master_id = val; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_SPEED: + md->status.speed = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_MODE: + md->status.mode = (enum e_mode) val; + break; + case UDT_AI: + md->special_state.ai = (enum ai) val; + break; + case UDT_SCOPTION: + md->sc.option = (unsigned int) val; + break; + case UDT_SEX: + md->vd->sex = (char) val; + break; + case UDT_CLASS: + mob->class_change(md, val); + break; + case UDT_HAIRSTYLE: + clif->changelook(bl, LOOK_HAIR, val); + break; + case UDT_HAIRCOLOR: + clif->changelook(bl, LOOK_HAIR_COLOR, val); + break; + case UDT_HEADBOTTOM: + clif->changelook(bl, LOOK_HEAD_BOTTOM, val); + break; + case UDT_HEADMIDDLE: + clif->changelook(bl, LOOK_HEAD_MID, val); + break; + case UDT_HEADTOP: + clif->changelook(bl, LOOK_HEAD_TOP, val); + break; + case UDT_CLOTHCOLOR: + clif->changelook(bl, LOOK_CLOTHES_COLOR, val); + break; + case UDT_SHIELD: + clif->changelook(bl, LOOK_SHIELD, val); + break; + case UDT_WEAPON: + clif->changelook(bl, LOOK_WEAPON, val); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (uint8) val); + break; + case UDT_CANMOVETICK: + md->ud.canmove_tick = val; + break; + case UDT_STR: + md->status.str = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_AGI: + md->status.agi = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_VIT: + md->status.vit = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_INT: + md->status.int_ = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_DEX: + md->status.dex = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_LUK: + md->status.luk = (unsigned short) val; + status->calc_misc(bl, &md->status, md->level); + break; + case UDT_ATKRANGE: + md->status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + md->status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + md->status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + md->status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + md->status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + md->status.def = (defType) val; + break; + case UDT_MDEF: + md->status.mdef = (defType) val; + break; + case UDT_HIT: + md->status.hit = (short) val; + break; + case UDT_FLEE: + md->status.flee = (short) val; + break; + case UDT_PDODGE: + md->status.flee2 = (short) val; + break; + case UDT_CRIT: + md->status.cri = (short) val; + break; + case UDT_RACE: + md->status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + md->status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + md->status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + md->status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + md->status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + md->status.dmotion = (unsigned short) val; + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for mob unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_HOM: + { + struct homun_data *hd = BL_UCAST(BL_HOM, bl); + + nullpo_retr(false, hd); + + switch (type) + { + case UDT_SIZE: + hd->base_status.size = (unsigned char) val; + break; + case UDT_LEVEL: + hd->homunculus.level = (short) val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXHP: + hd->homunculus.max_hp = val; + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + hd->homunculus.max_sp = val; + break; + case UDT_MASTERCID: + hd->homunculus.char_id = val; + hd->master = tsd; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_SPEED: + hd->base_status.speed = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (unsigned char) val); + break; + case UDT_CANMOVETICK: + hd->ud.canmove_tick = val; + break; + case UDT_STR: + hd->base_status.str = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_AGI: + hd->base_status.agi = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_VIT: + hd->base_status.vit = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_INT: + hd->base_status.int_ = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_DEX: + hd->base_status.dex = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_LUK: + hd->base_status.luk = (unsigned short) val; + status->calc_misc(bl, &hd->base_status, hd->homunculus.level); + break; + case UDT_ATKRANGE: + hd->base_status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + hd->base_status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + hd->base_status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + hd->base_status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + hd->base_status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + hd->base_status.def = (defType) val; + break; + case UDT_MDEF: + hd->base_status.mdef = (defType) val; + break; + case UDT_HIT: + hd->base_status.hit = (short) val; + break; + case UDT_FLEE: + hd->base_status.flee = (short) val; + break; + case UDT_PDODGE: + hd->base_status.flee2 = (short) val; + break; + case UDT_CRIT: + hd->base_status.cri = (short) val; + break; + case UDT_RACE: + hd->base_status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + hd->base_status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + hd->base_status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + hd->base_status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + hd->base_status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + hd->base_status.dmotion = (unsigned short) val; + break; + case UDT_HUNGER: + hd->homunculus.hunger = (short) val; + clif->send_homdata(hd->master, SP_HUNGRY, hd->homunculus.hunger); + break; + case UDT_INTIMACY: + homun->add_intimacy(hd, (unsigned int) val); + clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100); + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for homunculus unit.\n", udtype); + script_pushint(st, 0); + return false; + } + + clif->send_homdata(hd->master, SP_ACK, 0); // send homun data + } + break; + case BL_PET: + { + struct pet_data *pd = BL_UCAST(BL_PET, bl); + + nullpo_retr(false, pd); + + switch (type) + { + case UDT_SIZE: + pd->status.size = (unsigned char) val; + break; + case UDT_LEVEL: + pd->pet.level = (short) val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXHP: + pd->status.max_hp = (unsigned int) val; + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + pd->status.max_sp = (unsigned int) val; + break; + case UDT_MASTERAID: + pd->pet.account_id = val; + pd->msd = tsd; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_SPEED: + pd->status.speed = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (unsigned char) val); + break; + case UDT_CANMOVETICK: + pd->ud.canmove_tick = val; + break; + case UDT_STR: + pd->status.str = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_AGI: + pd->status.agi = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_VIT: + pd->status.vit = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_INT: + pd->status.int_ = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_DEX: + pd->status.dex = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_LUK: + pd->status.luk = (unsigned short) val; + status->calc_misc(bl, &pd->status, pd->pet.level); + break; + case UDT_ATKRANGE: + pd->status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + pd->status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + pd->status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + pd->status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + pd->status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + pd->status.def = (defType) val; + break; + case UDT_MDEF: + pd->status.mdef = (defType) val; + break; + case UDT_HIT: + pd->status.hit = (short) val; + break; + case UDT_FLEE: + pd->status.flee = (short) val; + break; + case UDT_PDODGE: + pd->status.flee2 = (short) val; + break; + case UDT_CRIT: + pd->status.cri = (short) val; + break; + case UDT_RACE: + pd->status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + pd->status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + pd->status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + pd->status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + pd->status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + pd->status.dmotion = (unsigned short) val; + break; + case UDT_INTIMACY: + pet->set_intimate(pd, val); + clif->send_petdata(pd->msd, pd, 1, pd->pet.intimate); + break; + case UDT_HUNGER: + pd->pet.hungry = (short) val; + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for pet unit.\n", udtype); + script_pushint(st, 0); + return false; + } + clif->send_petstatus(pd->msd); // send pet data + } + break; + case BL_MER: + { + struct mercenary_data *mc = BL_UCAST(BL_MER, bl); + + nullpo_retr(false, mc); + + switch (type) + { + case UDT_SIZE: + mc->base_status.size = (unsigned char) val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXHP: + mc->base_status.max_hp = (unsigned int) val; + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + mc->base_status.max_sp = (unsigned int) val; + break; + case UDT_MASTERCID: + mc->mercenary.char_id = val; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_SPEED: + mc->base_status.size = (unsigned char) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (unsigned char) val); + break; + case UDT_CANMOVETICK: + mc->ud.canmove_tick = val; + break; + case UDT_STR: + mc->base_status.str = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_AGI: + mc->base_status.agi = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_VIT: + mc->base_status.vit = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_INT: + mc->base_status.int_ = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_DEX: + mc->base_status.dex = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_LUK: + mc->base_status.luk = (unsigned short) val; + status->calc_misc(bl, &mc->base_status, mc->db->lv); + break; + case UDT_ATKRANGE: + mc->base_status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + mc->base_status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + mc->base_status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + mc->base_status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + mc->base_status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + mc->base_status.def = (defType) val; + break; + case UDT_MDEF: + mc->base_status.mdef = (defType) val; + break; + case UDT_HIT: + mc->base_status.hit = (short) val; + break; + case UDT_FLEE: + mc->base_status.flee = (short) val; + break; + case UDT_PDODGE: + mc->base_status.flee2 = (short) val; + break; + case UDT_CRIT: + mc->base_status.cri = (short) val; + break; + case UDT_RACE: + mc->base_status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + mc->base_status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + mc->base_status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + mc->base_status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + mc->base_status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + mc->base_status.dmotion = (unsigned short) val; + break; + case UDT_MERC_KILLCOUNT: + mc->mercenary.kill_count = (unsigned int) val; + break; + case UDT_LIFETIME: + mc->mercenary.life_time = (unsigned int) val; + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for mercenary unit.\n", udtype); + script_pushint(st, 0); + return false; + } + + clif->mercenary_info(map->charid2sd(mc->mercenary.char_id)); + clif->mercenary_skillblock(map->charid2sd(mc->mercenary.char_id)); + } + break; + case BL_ELEM: + { + struct elemental_data *ed = BL_UCAST(BL_ELEM, bl); + + nullpo_retr(false, ed); + + switch (type) + { + case UDT_SIZE: + ed->base_status.size = (unsigned char) val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXHP: + ed->base_status.max_hp = (unsigned int) val; + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + ed->base_status.max_sp = (unsigned int) val; + break; + case UDT_MASTERCID: + ed->elemental.char_id = val; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_SPEED: + ed->base_status.speed = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (unsigned char) val); + break; + case UDT_CANMOVETICK: + ed->ud.canmove_tick = val; + break; + case UDT_STR: + ed->base_status.str = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_AGI: + ed->base_status.agi = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_VIT: + ed->base_status.vit = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_INT: + ed->base_status.int_ = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_DEX: + ed->base_status.dex = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_LUK: + ed->base_status.luk = (unsigned short) val; + status->calc_misc(bl, &ed->base_status, ed->db->lv); + break; + case UDT_ATKRANGE: + ed->base_status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + ed->base_status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + ed->base_status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + ed->base_status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + ed->base_status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + ed->base_status.def = (defType) val; + break; + case UDT_MDEF: + ed->base_status.mdef = (defType) val; + break; + case UDT_HIT: + ed->base_status.hit = (short) val; + break; + case UDT_FLEE: + ed->base_status.flee = (short) val; + break; + case UDT_PDODGE: + ed->base_status.flee2 = (short) val; + break; + case UDT_CRIT: + ed->base_status.cri = (short) val; + break; + case UDT_RACE: + ed->base_status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + ed->base_status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + ed->base_status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + ed->base_status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + ed->base_status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + ed->base_status.dmotion = (unsigned short) val; + break; + case UDT_LIFETIME: + ed->elemental.life_time = val; + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for elemental unit.\n", udtype); + script_pushint(st, 0); + return false; + } + clif->elemental_info(ed->master); + } + break; + case BL_NPC: + { + struct npc_data *nd = BL_UCAST(BL_NPC, bl); + + nullpo_retr(false, nd); + + switch (type) + { + case UDT_SIZE: + nd->status.size = (unsigned char) val; + break; + case UDT_LEVEL: + nd->level = (unsigned short) val; + break; + case UDT_HP: + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXHP: + nd->status.max_hp = (unsigned int) val; + break; + case UDT_SP: + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); + break; + case UDT_MAXSP: + nd->status.max_sp = (unsigned int) val; + break; + case UDT_MAPIDXY: + unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT); + break; + case UDT_WALKTOXY: + if (!unit->walktoxy(bl, (short) val, (short) val2, 2)) + unit->movepos(bl, (short) val, (short) val2, 0, 0); + break; + case UDT_CLASS: + npc->setclass(nd, (short) val); + break; + case UDT_SPEED: + nd->speed = (short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_LOOKDIR: + unit->setdir(bl, (unsigned char) val); + break; + case UDT_STR: + nd->status.str = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_AGI: + nd->status.agi = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_VIT: + nd->status.vit = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_INT: + nd->status.int_ = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_DEX: + nd->status.dex = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_LUK: + nd->status.luk = (unsigned short) val; + status->calc_misc(bl, &nd->status, nd->level); + break; + case UDT_STATPOINT: + nd->stat_point = (unsigned short) val; + break; + case UDT_ATKRANGE: + nd->status.rhw.range = (unsigned short) val; + break; + case UDT_ATKMIN: + nd->status.rhw.atk = (unsigned short) val; + break; + case UDT_ATKMAX: + nd->status.rhw.atk2 = (unsigned short) val; + break; + case UDT_MATKMIN: + nd->status.matk_min = (unsigned short) val; + break; + case UDT_MATKMAX: + nd->status.matk_max = (unsigned short) val; + break; + case UDT_DEF: + nd->status.def = (defType) val; + break; + case UDT_MDEF: + nd->status.mdef = (defType) val; + break; + case UDT_HIT: + nd->status.hit = (short) val; + break; + case UDT_FLEE: + nd->status.flee = (short) val; + break; + case UDT_PDODGE: + nd->status.flee2 = (short) val; + break; + case UDT_CRIT: + nd->status.cri = (short) val; + break; + case UDT_RACE: + nd->status.race = (unsigned char) val; + break; + case UDT_ELETYPE: + nd->status.def_ele = (unsigned char) val; + break; + case UDT_ELELEVEL: + nd->status.ele_lv = (unsigned char) val; + break; + case UDT_AMOTION: + nd->status.amotion = (unsigned short) val; + break; + case UDT_ADELAY: + nd->status.adelay = (unsigned short) val; + break; + case UDT_DMOTION: + nd->status.dmotion = (unsigned short) val; + break; + case UDT_SEX: + nd->vd.sex = (char)val; + npc->refresh(nd); + break; + case UDT_HAIRSTYLE: + clif->changelook(bl, LOOK_HAIR, val); + break; + case UDT_HAIRCOLOR: + clif->changelook(bl, LOOK_HAIR_COLOR, val); + break; + case UDT_HEADBOTTOM: + clif->changelook(bl, LOOK_HEAD_BOTTOM, val); + break; + case UDT_HEADMIDDLE: + clif->changelook(bl, LOOK_HEAD_MID, val); + break; + case UDT_HEADTOP: + clif->changelook(bl, LOOK_HEAD_TOP, val); + break; + case UDT_CLOTHCOLOR: + clif->changelook(bl, LOOK_CLOTHES_COLOR, val); + break; + case UDT_SHIELD: + clif->changelook(bl, LOOK_SHIELD, val); + break; + case UDT_WEAPON: + clif->changelook(bl, LOOK_WEAPON, val); + break; + case UDT_ROBE: + clif->changelook(bl, LOOK_ROBE, val); + break; + case UDT_BODY2: + clif->changelook(bl, LOOK_BODY2, val); + break; + default: + ShowWarning("buildin_setunitdata: Invalid data type '%s' for NPC unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + default: + ShowError("buildin_setunitdata: Unknown object!\n"); + script_pushint(st, 0); + return false; + } // end of bl->type switch + + script_pushint(st, 1); + return true; +} + +/** + * Retrieves real-time data for a game object. + * Getunitdata <GUID>,<DataType>{,<Variable>} + * @param1 GUID Game object unique Id. + * @param2 DataType Type of Data to be set for the unit. + * @param3 Variable array reference to store data into. (used for UDT_MAPIDXY) + * @return 0 on failure, <value> on success + */ +static BUILDIN(getunitdata) +{ + struct block_list *bl; + const char *udtype = NULL; + const struct map_session_data *sd = NULL; + int type = 0; + char* name = NULL; + struct script_data *data = script_hasdata(st,4)?script_getdata(st, 4):NULL; + + bl = map->id2bl(script_getnum(st, 2)); + + if (bl == NULL) { + ShowWarning("buildin_getunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2)); + script_pushint(st, 0); + return false; + } + + type = script_getnum(st, 3); + + /* Type check */ + if (type < UDT_TYPE || type >= UDT_MAX) { + ShowError("buildin_getunitdata: Invalid unit data type %d provided.\n", type); + script_pushint(st, 0); + return false; + } + + /* Argument checks */ + if (type == UDT_MAPIDXY) { + if (data == NULL || !data_isreference(data)) { + ShowWarning("buildin_getunitdata: Error in argument 3. Please provide a reference variable to store values in.\n"); + script_pushint(st, 0); + return false; + } + + name = reference_getname(data); + + if (not_server_variable(*name)) { + sd = script->rid2sd(st); + if (sd == NULL) { + ShowWarning("buildin_getunitdata: Player not attached! Cannot use player variable %s.\n",name); + script_pushint(st, 0); + return true;// no player attached + } + } + } + +#define getunitdata_sub(idx__,var__) script->setd_sub(st,NULL,name,(idx__),(void *)h64BPTRSIZE((int)(var__)),data->ref); + + switch (bl->type) { + case BL_MOB: + { + const struct mob_data *md = BL_UCAST(BL_MOB, bl); + + nullpo_retr(false, md); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_MOB); break; + case UDT_SIZE: script_pushint(st, md->status.size); break; + case UDT_LEVEL: script_pushint(st, md->level); break; + case UDT_HP: script_pushint(st, md->status.hp); break; + case UDT_MAXHP: script_pushint(st, md->status.max_hp); break; + case UDT_SP: script_pushint(st, md->status.sp); break; + case UDT_MAXSP: script_pushint(st, md->status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, md->bl.m); + getunitdata_sub(1, md->bl.x); + getunitdata_sub(2, md->bl.y); + break; + case UDT_SPEED: script_pushint(st, md->status.speed); break; + case UDT_MODE: script_pushint(st, md->status.mode); break; + case UDT_AI: script_pushint(st, md->special_state.ai); break; + case UDT_SCOPTION: script_pushint(st, md->sc.option); break; + case UDT_SEX: script_pushint(st, md->vd->sex); break; + case UDT_CLASS: script_pushint(st, md->vd->class); break; + case UDT_HAIRSTYLE: script_pushint(st, md->vd->hair_style); break; + case UDT_HAIRCOLOR: script_pushint(st, md->vd->hair_color); break; + case UDT_HEADBOTTOM: script_pushint(st, md->vd->head_bottom); break; + case UDT_HEADMIDDLE: script_pushint(st, md->vd->head_mid); break; + case UDT_HEADTOP: script_pushint(st, md->vd->head_top); break; + case UDT_CLOTHCOLOR: script_pushint(st, md->vd->cloth_color); break; + case UDT_SHIELD: script_pushint(st, md->vd->shield); break; + case UDT_WEAPON: script_pushint(st, md->vd->weapon); break; + case UDT_LOOKDIR: script_pushint(st, md->ud.dir); break; + case UDT_CANMOVETICK: script_pushint(st, md->ud.canmove_tick); break; + case UDT_STR: script_pushint(st, md->status.str); break; + case UDT_AGI: script_pushint(st, md->status.agi); break; + case UDT_VIT: script_pushint(st, md->status.vit); break; + case UDT_INT: script_pushint(st, md->status.int_); break; + case UDT_DEX: script_pushint(st, md->status.dex); break; + case UDT_LUK: script_pushint(st, md->status.luk); break; + case UDT_ATKRANGE: script_pushint(st, md->status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, md->status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, md->status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, md->status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, md->status.matk_max); break; + case UDT_DEF: script_pushint(st, md->status.def); break; + case UDT_MDEF: script_pushint(st, md->status.mdef); break; + case UDT_HIT: script_pushint(st, md->status.hit); break; + case UDT_FLEE: script_pushint(st, md->status.flee); break; + case UDT_PDODGE: script_pushint(st, md->status.flee2); break; + case UDT_CRIT: script_pushint(st, md->status.cri); break; + case UDT_RACE: script_pushint(st, md->status.race); break; + case UDT_ELETYPE: script_pushint(st, md->status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, md->status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, md->status.amotion); break; + case UDT_ADELAY: script_pushint(st, md->status.adelay); break; + case UDT_DMOTION: script_pushint(st, md->status.dmotion); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mob unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_HOM: + { + const struct homun_data *hd = BL_UCAST(BL_HOM, bl); + + nullpo_retr(false, hd); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_HOM); break; + case UDT_SIZE: script_pushint(st, hd->base_status.size); break; + case UDT_LEVEL: script_pushint(st, hd->homunculus.level); break; + case UDT_HP: script_pushint(st, hd->base_status.hp); break; + case UDT_MAXHP: script_pushint(st, hd->base_status.max_hp); break; + case UDT_SP: script_pushint(st, hd->base_status.sp); break; + case UDT_MAXSP: script_pushint(st, hd->base_status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, hd->bl.m); + getunitdata_sub(1, hd->bl.x); + getunitdata_sub(2, hd->bl.y); + break; + case UDT_SPEED: script_pushint(st, hd->base_status.speed); break; + case UDT_LOOKDIR: script_pushint(st, hd->ud.dir); break; + case UDT_CANMOVETICK: script_pushint(st, hd->ud.canmove_tick); break; + case UDT_MODE: script_pushint(st, hd->base_status.mode); break; + case UDT_STR: script_pushint(st, hd->base_status.str); break; + case UDT_AGI: script_pushint(st, hd->base_status.agi); break; + case UDT_VIT: script_pushint(st, hd->base_status.vit); break; + case UDT_INT: script_pushint(st, hd->base_status.int_); break; + case UDT_DEX: script_pushint(st, hd->base_status.dex); break; + case UDT_LUK: script_pushint(st, hd->base_status.luk); break; + case UDT_ATKRANGE: script_pushint(st, hd->base_status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, hd->base_status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, hd->base_status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, hd->base_status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, hd->base_status.matk_max); break; + case UDT_DEF: script_pushint(st, hd->base_status.def); break; + case UDT_MDEF: script_pushint(st, hd->base_status.mdef); break; + case UDT_HIT: script_pushint(st, hd->base_status.hit); break; + case UDT_FLEE: script_pushint(st, hd->base_status.flee); break; + case UDT_PDODGE: script_pushint(st, hd->base_status.flee2); break; + case UDT_CRIT: script_pushint(st, hd->base_status.cri); break; + case UDT_RACE: script_pushint(st, hd->base_status.race); break; + case UDT_ELETYPE: script_pushint(st, hd->base_status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, hd->base_status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, hd->base_status.amotion); break; + case UDT_ADELAY: script_pushint(st, hd->base_status.adelay); break; + case UDT_DMOTION: script_pushint(st, hd->base_status.dmotion); break; + case UDT_MASTERCID: script_pushint(st, hd->homunculus.char_id); break; + case UDT_HUNGER: script_pushint(st, hd->homunculus.hunger); break; + case UDT_INTIMACY: script_pushint(st, hd->homunculus.intimacy); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for Homunculus unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_PET: + { + const struct pet_data *pd = BL_UCAST(BL_PET, bl); + + nullpo_retr(false, pd); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_PET); break; + case UDT_SIZE: script_pushint(st, pd->status.size); break; + case UDT_LEVEL: script_pushint(st, pd->pet.level); break; + case UDT_HP: script_pushint(st, pd->status.hp); break; + case UDT_MAXHP: script_pushint(st, pd->status.max_hp); break; + case UDT_SP: script_pushint(st, pd->status.sp); break; + case UDT_MAXSP: script_pushint(st, pd->status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, pd->bl.m); + getunitdata_sub(1, pd->bl.x); + getunitdata_sub(2, pd->bl.y); + break; + case UDT_SPEED: script_pushint(st, pd->status.speed); break; + case UDT_LOOKDIR: script_pushint(st, pd->ud.dir); break; + case UDT_CANMOVETICK: script_pushint(st, pd->ud.canmove_tick); break; + case UDT_MODE: script_pushint(st, pd->status.mode); break; + case UDT_STR: script_pushint(st, pd->status.str); break; + case UDT_AGI: script_pushint(st, pd->status.agi); break; + case UDT_VIT: script_pushint(st, pd->status.vit); break; + case UDT_INT: script_pushint(st, pd->status.int_); break; + case UDT_DEX: script_pushint(st, pd->status.dex); break; + case UDT_LUK: script_pushint(st, pd->status.luk); break; + case UDT_ATKRANGE: script_pushint(st, pd->status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, pd->status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, pd->status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, pd->status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, pd->status.matk_max); break; + case UDT_DEF: script_pushint(st, pd->status.def); break; + case UDT_MDEF: script_pushint(st, pd->status.mdef); break; + case UDT_HIT: script_pushint(st, pd->status.hit); break; + case UDT_FLEE: script_pushint(st, pd->status.flee); break; + case UDT_PDODGE: script_pushint(st, pd->status.flee2); break; + case UDT_CRIT: script_pushint(st, pd->status.cri); break; + case UDT_RACE: script_pushint(st, pd->status.race); break; + case UDT_ELETYPE: script_pushint(st, pd->status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, pd->status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, pd->status.amotion); break; + case UDT_ADELAY: script_pushint(st, pd->status.adelay); break; + case UDT_DMOTION: script_pushint(st, pd->status.dmotion); break; + case UDT_MASTERAID: script_pushint(st, pd->pet.account_id); break; + case UDT_HUNGER: script_pushint(st, pd->pet.hungry); break; + case UDT_INTIMACY: script_pushint(st, pd->pet.intimate); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for Pet unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_MER: + { + const struct mercenary_data *mc = BL_UCAST(BL_MER, bl); + + nullpo_retr(false, mc); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_MER); break; + case UDT_SIZE: script_pushint(st, mc->base_status.size); break; + case UDT_HP: script_pushint(st, mc->base_status.hp); break; + case UDT_MAXHP: script_pushint(st, mc->base_status.max_hp); break; + case UDT_SP: script_pushint(st, mc->base_status.sp); break; + case UDT_MAXSP: script_pushint(st, mc->base_status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, mc->bl.m); + getunitdata_sub(1, mc->bl.x); + getunitdata_sub(2, mc->bl.y); + break; + case UDT_SPEED: script_pushint(st, mc->base_status.speed); break; + case UDT_LOOKDIR: script_pushint(st, mc->ud.dir); break; + case UDT_CANMOVETICK: script_pushint(st, mc->ud.canmove_tick); break; + case UDT_MODE: script_pushint(st, mc->base_status.mode); break; + case UDT_STR: script_pushint(st, mc->base_status.str); break; + case UDT_AGI: script_pushint(st, mc->base_status.agi); break; + case UDT_VIT: script_pushint(st, mc->base_status.vit); break; + case UDT_INT: script_pushint(st, mc->base_status.int_); break; + case UDT_DEX: script_pushint(st, mc->base_status.dex); break; + case UDT_LUK: script_pushint(st, mc->base_status.luk); break; + case UDT_ATKRANGE: script_pushint(st, mc->base_status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, mc->base_status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, mc->base_status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, mc->base_status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, mc->base_status.matk_max); break; + case UDT_DEF: script_pushint(st, mc->base_status.def); break; + case UDT_MDEF: script_pushint(st, mc->base_status.mdef); break; + case UDT_HIT: script_pushint(st, mc->base_status.hit); break; + case UDT_FLEE: script_pushint(st, mc->base_status.flee); break; + case UDT_PDODGE: script_pushint(st, mc->base_status.flee2); break; + case UDT_CRIT: script_pushint(st, mc->base_status.cri); break; + case UDT_RACE: script_pushint(st, mc->base_status.race); break; + case UDT_ELETYPE: script_pushint(st, mc->base_status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, mc->base_status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, mc->base_status.amotion); break; + case UDT_ADELAY: script_pushint(st, mc->base_status.adelay); break; + case UDT_DMOTION: script_pushint(st, mc->base_status.dmotion); break; + case UDT_MASTERCID: script_pushint(st, mc->mercenary.char_id); break; + case UDT_MERC_KILLCOUNT: script_pushint(st, mc->mercenary.kill_count); break; + case UDT_LIFETIME: script_pushint(st, mc->mercenary.life_time); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mercenary unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_ELEM: + { + const struct elemental_data *ed = BL_UCAST(BL_ELEM, bl); + + nullpo_retr(false, ed); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_ELEM); break; + case UDT_SIZE: script_pushint(st, ed->base_status.size); break; + case UDT_HP: script_pushint(st, ed->base_status.hp); break; + case UDT_MAXHP: script_pushint(st, ed->base_status.max_hp); break; + case UDT_SP: script_pushint(st, ed->base_status.sp); break; + case UDT_MAXSP: script_pushint(st, ed->base_status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, ed->bl.m); + getunitdata_sub(1, ed->bl.x); + getunitdata_sub(2, ed->bl.y); + break; + case UDT_SPEED: script_pushint(st, ed->base_status.speed); break; + case UDT_LOOKDIR: script_pushint(st, ed->ud.dir); break; + case UDT_CANMOVETICK: script_pushint(st, ed->ud.canmove_tick); break; + case UDT_MODE: script_pushint(st, ed->base_status.mode); break; + case UDT_STR: script_pushint(st, ed->base_status.str); break; + case UDT_AGI: script_pushint(st, ed->base_status.agi); break; + case UDT_VIT: script_pushint(st, ed->base_status.vit); break; + case UDT_INT: script_pushint(st, ed->base_status.int_); break; + case UDT_DEX: script_pushint(st, ed->base_status.dex); break; + case UDT_LUK: script_pushint(st, ed->base_status.luk); break; + case UDT_ATKRANGE: script_pushint(st, ed->base_status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, ed->base_status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, ed->base_status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, ed->base_status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, ed->base_status.matk_max); break; + case UDT_DEF: script_pushint(st, ed->base_status.def); break; + case UDT_MDEF: script_pushint(st, ed->base_status.mdef); break; + case UDT_HIT: script_pushint(st, ed->base_status.hit); break; + case UDT_FLEE: script_pushint(st, ed->base_status.flee); break; + case UDT_PDODGE: script_pushint(st, ed->base_status.flee2); break; + case UDT_CRIT: script_pushint(st, ed->base_status.cri); break; + case UDT_RACE: script_pushint(st, ed->base_status.race); break; + case UDT_ELETYPE: script_pushint(st, ed->base_status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, ed->base_status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, ed->base_status.amotion); break; + case UDT_ADELAY: script_pushint(st, ed->base_status.adelay); break; + case UDT_DMOTION: script_pushint(st, ed->base_status.dmotion); break; + case UDT_MASTERCID: script_pushint(st, ed->elemental.char_id); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for Elemental unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + case BL_NPC: + { + const struct npc_data *nd = BL_UCAST(BL_NPC, bl); + + nullpo_retr(false, nd); + + switch (type) + { + case UDT_TYPE: script_pushint(st, BL_NPC); break; + case UDT_SIZE: script_pushint(st, nd->status.size); break; + case UDT_HP: script_pushint(st, nd->status.hp); break; + case UDT_MAXHP: script_pushint(st, nd->status.max_hp); break; + case UDT_SP: script_pushint(st, nd->status.sp); break; + case UDT_MAXSP: script_pushint(st, nd->status.max_sp); break; + case UDT_MAPIDXY: + getunitdata_sub(0, bl->m); + getunitdata_sub(1, bl->x); + getunitdata_sub(2, bl->y); + break; + case UDT_SPEED: script_pushint(st, nd->status.speed); break; + case UDT_LOOKDIR: script_pushint(st, nd->ud->dir); break; + case UDT_CANMOVETICK: script_pushint(st, nd->ud->canmove_tick); break; + case UDT_MODE: script_pushint(st, nd->status.mode); break; + case UDT_STR: script_pushint(st, nd->status.str); break; + case UDT_AGI: script_pushint(st, nd->status.agi); break; + case UDT_VIT: script_pushint(st, nd->status.vit); break; + case UDT_INT: script_pushint(st, nd->status.int_); break; + case UDT_DEX: script_pushint(st, nd->status.dex); break; + case UDT_LUK: script_pushint(st, nd->status.luk); break; + case UDT_ATKRANGE: script_pushint(st, nd->status.rhw.range); break; + case UDT_ATKMIN: script_pushint(st, nd->status.rhw.atk); break; + case UDT_ATKMAX: script_pushint(st, nd->status.rhw.atk2); break; + case UDT_MATKMIN: script_pushint(st, nd->status.matk_min); break; + case UDT_MATKMAX: script_pushint(st, nd->status.matk_max); break; + case UDT_DEF: script_pushint(st, nd->status.def); break; + case UDT_MDEF: script_pushint(st, nd->status.mdef); break; + case UDT_HIT: script_pushint(st, nd->status.hit); break; + case UDT_FLEE: script_pushint(st, nd->status.flee); break; + case UDT_PDODGE: script_pushint(st, nd->status.flee2); break; + case UDT_CRIT: script_pushint(st, nd->status.cri); break; + case UDT_RACE: script_pushint(st, nd->status.race); break; + case UDT_ELETYPE: script_pushint(st, nd->status.def_ele); break; + case UDT_ELELEVEL: script_pushint(st, nd->status.ele_lv); break; + case UDT_AMOTION: script_pushint(st, nd->status.amotion); break; + case UDT_ADELAY: script_pushint(st, nd->status.adelay); break; + case UDT_DMOTION: script_pushint(st, nd->status.dmotion); break; + case UDT_SEX: script_pushint(st, nd->vd.sex); break; + case UDT_CLASS: script_pushint(st, nd->vd.class); break; + case UDT_HAIRSTYLE: script_pushint(st, nd->vd.hair_style); break; + case UDT_HAIRCOLOR: script_pushint(st, nd->vd.hair_color); break; + case UDT_HEADBOTTOM: script_pushint(st, nd->vd.head_bottom); break; + case UDT_HEADMIDDLE: script_pushint(st, nd->vd.head_mid); break; + case UDT_HEADTOP: script_pushint(st, nd->vd.head_top); break; + case UDT_CLOTHCOLOR: script_pushint(st, nd->vd.cloth_color); break; + case UDT_SHIELD: script_pushint(st, nd->vd.shield); break; + case UDT_WEAPON: script_pushint(st, nd->vd.weapon); break; + case UDT_ROBE: script_pushint(st, nd->vd.robe); break; + case UDT_BODY2: script_pushint(st, nd->vd.body_style); break; + default: + ShowWarning("buildin_getunitdata: Invalid data type '%s' for NPC unit.\n", udtype); + script_pushint(st, 0); + return false; + } + } + break; + default: + ShowError("buildin_getunitdata: Unknown object!\n"); + script_pushint(st, 0); + return false; + } // end of bl->type switch + +#undef getunitdata_sub + + return true; +} + +/** + * Gets the name of a Unit. + * Supported types are [MOB|HOM|PET|NPC]. + * MER and ELEM don't support custom names. + * + * @command getunitname <GUID>; + * @param GUID Game Object Unique ID. + * @return boolean or Name of the game object. + */ +static BUILDIN(getunitname) +{ + const struct block_list* bl = NULL; + + bl = map->id2bl(script_getnum(st, 2)); + + if (bl == NULL) { + ShowWarning("buildin_getunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2)); + script_pushconststr(st, "Unknown"); + return false; + } + + script_pushstrcopy(st, status->get_name(bl)); + + return true; +} + +/** + * Changes the name of a bl. + * Supported types are [MOB|HOM|PET]. + * For NPC see 'setnpcdisplay', MER and ELEM don't support custom names. + * + * @command setunitname <GUID>,<name>; + * @param GUID Game object unique ID. + * @param Name as string. + * @return boolean. + */ +static BUILDIN(setunitname) +{ + struct block_list* bl = map->id2bl(script_getnum(st, 2)); + + if (bl == NULL) { + ShowWarning("buildin_setunitname: Game object with ID %d was not found!\n", script_getnum(st, 2)); + script_pushint(st, 0); + return false; + } + + switch (bl->type) { + case BL_MOB: + { + struct mob_data *md = BL_UCAST(BL_MOB, bl); + if (md == NULL) { + ShowWarning("buildin_setunitname: Error in finding object BL_MOB!\n"); + script_pushint(st, 0); + return false; + } + safestrncpy(md->name, script_getstr(st, 3), NAME_LENGTH); + } + break; + case BL_HOM: + { + struct homun_data *hd = BL_UCAST(BL_HOM, bl); + if (hd == NULL) { + ShowWarning("buildin_setunitname: Error in finding object BL_HOM!\n"); + script_pushint(st, 0); + return false; + } + safestrncpy(hd->homunculus.name, script_getstr(st, 3), NAME_LENGTH); + } + break; + case BL_PET: + { + struct pet_data *pd = BL_UCAST(BL_PET, bl); + if (pd == NULL) { + ShowWarning("buildin_setunitname: Error in finding object BL_PET!\n"); + script_pushint(st, 0); + return false; + } + safestrncpy(pd->pet.name, script_getstr(st, 3), NAME_LENGTH); + } + break; + default: + script_pushint(st, 0); + ShowWarning("buildin_setunitname: Unknown object type!\n"); + return false; + } + + script_pushint(st, 1); + clif->charnameack(0, bl); // Send update to client. + + return true; +} + /// Makes the unit walk to target position or target id /// Returns if it was successfull /// /// unitwalk(<unit_id>,<x>,<y>) -> <bool> /// unitwalk(<unit_id>,<target_id>) -> <bool> -BUILDIN(unitwalk) { +static BUILDIN(unitwalk) +{ struct block_list* bl; bl = map->id2bl(script_getnum(st,2)); @@ -17257,7 +20232,7 @@ BUILDIN(unitwalk) { /// Kills the unit /// /// unitkill <unit_id>; -BUILDIN(unitkill) +static BUILDIN(unitkill) { struct block_list* bl = map->id2bl(script_getnum(st,2)); if( bl != NULL ) @@ -17270,7 +20245,8 @@ BUILDIN(unitkill) /// Returns if it was successfull /// /// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool> -BUILDIN(unitwarp) { +static BUILDIN(unitwarp) +{ int unit_id; int mapid; short x; @@ -17310,7 +20286,8 @@ BUILDIN(unitwarp) { /// /// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool> /// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool> -BUILDIN(unitattack) { +static BUILDIN(unitattack) +{ struct block_list* unit_bl; struct block_list* target_bl = NULL; int actiontype = 0; @@ -17364,7 +20341,8 @@ BUILDIN(unitattack) { /// Makes the unit stop attacking and moving /// /// unitstop <unit_id>; -BUILDIN(unitstop) { +static BUILDIN(unitstop) +{ int unit_id; struct block_list* bl; @@ -17384,15 +20362,30 @@ BUILDIN(unitstop) { /// Makes the unit say the message /// -/// unittalk <unit_id>,"<message>"; -BUILDIN(unittalk) { +/// unittalk(<unit_id>,"<message>"{, show_name{, <send_target>{, <target_id>}}}); +static BUILDIN(unittalk) +{ int unit_id; const char* message; - struct block_list* bl; + struct block_list *bl, *target_bl = NULL; + bool show_name = true; + enum send_target target = AREA_CHAT_WOC; unit_id = script_getnum(st,2); message = script_getstr(st, 3); + if (script_hasdata(st, 4)) { + show_name = (script_getnum(st, 4) != 0) ? true : false; + } + + if (script_hasdata(st, 5)) { + target = script_getnum(st, 5); + } + + if (script_hasdata(st, 6)) { + target_bl = map->id2bl(script_getnum(st, 6)); + } + bl = map->id2bl(unit_id); if( bl != NULL ) { struct StringBuf sbuf; @@ -17401,8 +20394,17 @@ BUILDIN(unittalk) { safestrncpy(blname, clif->get_bl_name(bl), sizeof(blname)); if(bl->type == BL_NPC) strtok(blname, "#"); - StrBuf->Printf(&sbuf, "%s : %s", blname, message); - clif->disp_overhead(bl, StrBuf->Value(&sbuf)); + if (show_name) { + StrBuf->Printf(&sbuf, "%s : %s", blname, message); + } else { + StrBuf->Printf(&sbuf, "%s", message); + } + + if (bl->type == BL_PC && target == SELF && (target_bl == NULL || bl == target_bl)) { + clif->notify_playerchat(bl, StrBuf->Value(&sbuf)); + } else { + clif->disp_overhead(bl, StrBuf->Value(&sbuf), target, target_bl); + } StrBuf->Destroy(&sbuf); } @@ -17414,7 +20416,8 @@ BUILDIN(unittalk) { /// unitemote <unit_id>,<emotion>; /// /// @see e_* in const.txt -BUILDIN(unitemote) { +static BUILDIN(unitemote) +{ int unit_id; int emotion; struct block_list* bl; @@ -17432,7 +20435,8 @@ BUILDIN(unitemote) { /// /// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>}; /// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>}; -BUILDIN(unitskilluseid) { +static BUILDIN(unitskilluseid) +{ int unit_id; uint16 skill_id; uint16 skill_lv; @@ -17465,7 +20469,8 @@ BUILDIN(unitskilluseid) { /// /// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>; /// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>; -BUILDIN(unitskillusepos) { +static BUILDIN(unitskillusepos) +{ int unit_id; uint16 skill_id; uint16 skill_lv; @@ -17501,7 +20506,7 @@ BUILDIN(unitskillusepos) { /// Pauses the execution of the script, detaching the player /// /// sleep <mili seconds>; -BUILDIN(sleep) +static BUILDIN(sleep) { int ticks; @@ -17530,7 +20535,8 @@ BUILDIN(sleep) /// Returns if a player is still attached /// /// sleep2(<mili secconds>) -> <bool> -BUILDIN(sleep2) { +static BUILDIN(sleep2) +{ int ticks; ticks = script_getnum(st,2); @@ -17554,7 +20560,7 @@ BUILDIN(sleep2) { /// Awakes all the sleep timers of the target npc /// /// awake "<npc name>"; -BUILDIN(awake) +static BUILDIN(awake) { struct DBIterator *iter; struct script_state *tst; @@ -17597,7 +20603,7 @@ BUILDIN(awake) /// Returns 0 if an error occurs. /// /// getvariableofnpc(<variable>, "<npc name>") -> <reference> -BUILDIN(getvariableofnpc) +static BUILDIN(getvariableofnpc) { struct script_data* data; const char* name; @@ -17639,7 +20645,7 @@ BUILDIN(getvariableofnpc) return true; } -BUILDIN(getvariableofpc) +static BUILDIN(getvariableofpc) { const char* name; struct script_data* data = script_getdata(st, 2); @@ -17657,7 +20663,6 @@ BUILDIN(getvariableofpc) switch (*name) { - case '#': case '$': case '.': case '\'': @@ -17682,7 +20687,7 @@ BUILDIN(getvariableofpc) } if (!sd->regs.vars) - sd->regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + sd->regs.vars = i64db_alloc(DB_OPT_BASE); script->push_val(st->stack, C_NAME, reference_getuid(data), &sd->regs); return true; @@ -17694,7 +20699,8 @@ BUILDIN(getvariableofpc) /// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>; /// /// @author blackhole89 -BUILDIN(warpportal) { +static BUILDIN(warpportal) +{ int spx; int spy; unsigned short map_index; @@ -17731,7 +20737,7 @@ BUILDIN(warpportal) { return true; } -BUILDIN(openmail) +static BUILDIN(openmail) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -17742,7 +20748,7 @@ BUILDIN(openmail) return true; } -BUILDIN(openauction) +static BUILDIN(openauction) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -17758,7 +20764,8 @@ BUILDIN(openauction) /// checkcell("<map name>",<x>,<y>,<type>) -> <bool> /// /// @see cell_chk* constants in const.txt for the types -BUILDIN(checkcell) { +static BUILDIN(checkcell) +{ int16 m = map->mapname2mapid(script_getstr(st,2)); int16 x = script_getnum(st,3); int16 y = script_getnum(st,4); @@ -17779,7 +20786,8 @@ BUILDIN(checkcell) { /// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>; /// /// @see cell_* constants in const.txt for the types -BUILDIN(setcell) { +static BUILDIN(setcell) +{ int16 m = map->mapname2mapid(script_getstr(st,2)); int16 x1 = script_getnum(st,3); int16 y1 = script_getnum(st,4); @@ -17808,7 +20816,7 @@ BUILDIN(setcell) { /*========================================== * Mercenary Commands *------------------------------------------*/ -BUILDIN(mercenary_create) +static BUILDIN(mercenary_create) { struct map_session_data *sd; int class_, contract_time; @@ -17826,7 +20834,8 @@ BUILDIN(mercenary_create) return true; } -BUILDIN(mercenary_heal) { +static BUILDIN(mercenary_heal) +{ struct map_session_data *sd = script->rid2sd(st); int hp, sp; @@ -17835,11 +20844,12 @@ BUILDIN(mercenary_heal) { hp = script_getnum(st,2); sp = script_getnum(st,3); - status->heal(&sd->md->bl, hp, sp, 0); + status->heal(&sd->md->bl, hp, sp, STATUS_HEAL_DEFAULT); return true; } -BUILDIN(mercenary_sc_start) { +static BUILDIN(mercenary_sc_start) +{ struct map_session_data *sd = script->rid2sd(st); enum sc_type type; int tick, val1; @@ -17855,7 +20865,8 @@ BUILDIN(mercenary_sc_start) { return true; } -BUILDIN(mercenary_get_calls) { +static BUILDIN(mercenary_get_calls) +{ struct map_session_data *sd = script->rid2sd(st); int guild_id; @@ -17881,7 +20892,8 @@ BUILDIN(mercenary_get_calls) { return true; } -BUILDIN(mercenary_set_calls) { +static BUILDIN(mercenary_set_calls) +{ struct map_session_data *sd = script->rid2sd(st); int guild_id, value, *calls; @@ -17911,7 +20923,8 @@ BUILDIN(mercenary_set_calls) { return true; } -BUILDIN(mercenary_get_faith) { +static BUILDIN(mercenary_get_faith) +{ struct map_session_data *sd = script->rid2sd(st); int guild_id; @@ -17937,7 +20950,8 @@ BUILDIN(mercenary_get_faith) { return true; } -BUILDIN(mercenary_set_faith) { +static BUILDIN(mercenary_set_faith) +{ struct map_session_data *sd = script->rid2sd(st); int guild_id, value, *calls; @@ -17972,7 +20986,7 @@ BUILDIN(mercenary_set_faith) { /*------------------------------------------ * Book Reading *------------------------------------------*/ -BUILDIN(readbook) +static BUILDIN(readbook) { struct map_session_data *sd; int book_id, page; @@ -17991,89 +21005,215 @@ BUILDIN(readbook) * Questlog script commands * ****************************/ -BUILDIN(questinfo) +static BUILDIN(questinfo) { struct npc_data *nd = map->id2nd(st->oid); - int quest_id, icon; - struct questinfo qi; + struct questinfo qi = { 0 }; + int icon = script_getnum(st, 2); - if( nd == NULL || nd->bl.m == -1 ) + if (nd == NULL) return true; - quest_id = script_getnum(st, 2); - icon = script_getnum(st, 3); - - #if PACKETVER >= 20120410 - if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7) - icon = 9999; // Default to nothing if icon id is invalid. - #else - if(icon < 0 || icon > 7) - icon = 0; - else - icon = icon + 1; - #endif + if (nd->bl.m == -1) { + ShowWarning("buildin_questinfo: questinfo cannot be set for an npc with no valid map.\n"); + return false; + } - qi.quest_id = quest_id; - qi.icon = (unsigned char)icon; qi.nd = nd; - - if (script_hasdata(st, 4)) { - int color = script_getnum(st, 4); + qi.icon = quest->questinfo_validate_icon(icon); + if (script_hasdata(st, 3)) { + int color = script_getnum(st, 3); if (color < 0 || color > 3) { - ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color); + ShowWarning("buildin_questinfo: invalid color '%d', defaulting to 0.\n", color); script->reportfunc(st); color = 0; } qi.color = (unsigned char)color; } - qi.hasJob = false; + map->add_questinfo(nd->bl.m, &qi); + return true; +} - if (script_hasdata(st, 5)) { - int job = script_getnum(st, 5); +static BUILDIN(setquestinfo) +{ + struct npc_data *nd = map->id2nd(st->oid); + struct questinfo *qi = NULL; + uint32 type = script_getnum(st, 2); - if (!pc->db_checkid(job)) { - ShowError("buildin_questinfo: Nonexistant Job Class.\n"); - } else { - qi.hasJob = true; - qi.job = (unsigned short)job; + if (nd == NULL) + return true; + + if (nd->bl.m == -1) { + ShowWarning("buildin_setquestinfo: questinfo cannot be set for an npc with no valid map.\n"); + return false; + } + + qi = &VECTOR_LAST(map->list[nd->bl.m].qi_data); + if (qi == NULL) { + ShowWarning("buildin_setquestinfo: no valide questinfo data has been found for this npc.\n"); + return false; + } + if (qi->nd != nd) { + ShowWarning("buildin_setquestinfo: invalid usage, setquestinfo must be used only after questinfo.\n"); + return false; + } + switch (type) { + case QINFO_JOB: + { + int jobid = script_getnum(st, 3); + if (!pc->db_checkid(jobid)) { + ShowWarning("buildin_setquestinfo: invalid job id given (%d).\n", jobid); + return false; + } + qi->hasJob = true; + qi->job = jobid; + break; + } + case QINFO_SEX: + { + int sex = script_getnum(st, 3); + if (sex != SEX_MALE && sex != SEX_FEMALE) { + ShowWarning("buildin_setquestinfo: unsupported sex has been given (%d).\n", sex); + return false; + } + qi->sex_enabled = true; + qi->sex = sex; + break; + } + case QINFO_BASE_LEVEL: + { + int min = script_getnum(st, 3); + int max = script_getnum(st, 4); + if (min > max) { + ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max); + return false; + } + qi->base_level.min = min; + qi->base_level.max = max; + break; + } + case QINFO_JOB_LEVEL: + { + int min = script_getnum(st, 3); + int max = script_getnum(st, 4); + if (min > max) { + ShowWarning("buildin_setquestinfo: minimal level (%d) is bigger than the maximal level (%d).\n", min, max); + return false; } + qi->job_level.min = min; + qi->job_level.max = max; + break; } + case QINFO_ITEM: + { + struct questinfo_itemreq item = { 0 }; - map->add_questinfo(nd->bl.m,&qi); + item.nameid = script_getnum(st, 3); + item.min = script_hasdata(st, 4) ? script_getnum(st, 4) : 0; + item.max = script_hasdata(st, 5) ? script_getnum(st, 5) : 0; + if (itemdb->exists(item.nameid) == NULL) { + ShowWarning("buildin_setquestinfo: non existing item (%d) have been given.\n", item.nameid); + return false; + } + if (item.min > item.max) { + ShowWarning("buildin_setquestinfo: minimal amount (%d) is bigger than the maximal amount (%d).\n", item.min, item.max); + return false; + } + if (item.min < 0 || item.min > MAX_AMOUNT) { + ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.min, MAX_AMOUNT + 1); + return false; + } + if (item.max < 0 || item.max > MAX_AMOUNT) { + ShowWarning("buildin_setquestinfo: given amount (%d) must be bigger than or equal to 0 and smaller than %d.\n", item.max, MAX_AMOUNT + 1); + return false; + } + if (VECTOR_LENGTH(qi->items) == 0) + VECTOR_INIT(qi->items); + VECTOR_ENSURE(qi->items, 1, 1); + VECTOR_PUSH(qi->items, item); + break; + } + case QINFO_HOMUN_LEVEL: + { + int min = script_getnum(st, 3); + if (min > battle_config.hom_max_level && min > battle_config.hom_S_max_level) { + ShowWarning("buildin_setquestinfo: minimum homunculus level given (%d) is bigger than the max possible level.\n", min); + return false; + } + qi->homunculus.level = min; + break; + } + case QINFO_HOMUN_TYPE: + { + int hom_type = script_getnum(st, 3); + if (hom_type < HT_REG || hom_type > HT_S) { + ShowWarning("buildin_setquestinfo: invalid homunculus type (%d).\n", hom_type); + return false; + } + qi->homunculus_type = hom_type; + break; + } + case QINFO_QUEST: + { + struct questinfo_qreq quest_req = { 0 }; + struct quest_db *quest_data = NULL; + + quest_req.id = script_getnum(st, 3); + quest_req.state = script_getnum(st, 4); + + quest_data = quest->db(quest_req.id); + if (quest_data == &quest->dummy) { + ShowWarning("buildin_setquestinfo: invalid quest given (%d).\n", quest_req.id); + return false; + } + if (quest_req.state < Q_INACTIVE || quest_req.state > Q_COMPLETE) { + ShowWarning("buildin_setquestinfo: invalid quest state given (%d).\n", quest_req.state); + return false; + } + + if (VECTOR_LENGTH(qi->quest_requirement) == 0) + VECTOR_INIT(qi->quest_requirement); + VECTOR_ENSURE(qi->quest_requirement, 1, 1); + VECTOR_PUSH(qi->quest_requirement, quest_req); + break; + } + case QINFO_MERCENARY_CLASS: + { + int mer_class = script_getnum(st, 3); + + if (!mercenary->class(mer_class)) { + ShowWarning("buildin_setquestinfo: invalid mercenary class given (%d).\n", mer_class); + return false; + } + qi->mercenary_class = mer_class; + break; + } + default: + ShowWarning("buildin_setquestinfo: invalid type given (%u).\n", type); + return false; + } return true; } -BUILDIN(setquest) +static BUILDIN(setquest) { - unsigned short i; int quest_id; + unsigned int time_limit; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) return true; quest_id = script_getnum(st, 2); + time_limit = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; - quest->add(sd, quest_id); - - // If questinfo is set, remove quest bubble once quest is set. - for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { - struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; - if( qi->quest_id == quest_id ) { -#if PACKETVER >= 20120410 - clif->quest_show_event(sd, &qi->nd->bl, 9999, 0); -#else - clif->quest_show_event(sd, &qi->nd->bl, 0, 0); -#endif - } - } - + quest->add(sd, quest_id, time_limit); return true; } -BUILDIN(erasequest) +static BUILDIN(erasequest) { struct map_session_data *sd = script->rid2sd(st); @@ -18096,7 +21236,7 @@ BUILDIN(erasequest) return true; } -BUILDIN(completequest) +static BUILDIN(completequest) { struct map_session_data *sd = script->rid2sd(st); @@ -18119,7 +21259,7 @@ BUILDIN(completequest) return true; } -BUILDIN(changequest) +static BUILDIN(changequest) { struct map_session_data *sd = script->rid2sd(st); @@ -18130,7 +21270,7 @@ BUILDIN(changequest) return true; } -BUILDIN(questactive) +static BUILDIN(questactive) { struct map_session_data *sd = script->rid2sd(st); int qid, i; @@ -18156,7 +21296,7 @@ BUILDIN(questactive) return true; } -BUILDIN(questprogress) +static BUILDIN(questprogress) { struct map_session_data *sd = script->rid2sd(st); enum quest_check_type type = HAVEQUEST; @@ -18184,7 +21324,7 @@ BUILDIN(questprogress) return true; } -BUILDIN(showevent) +static BUILDIN(showevent) { struct map_session_data *sd = script->rid2sd(st); struct npc_data *nd = map->id2nd(st->oid); @@ -18203,24 +21343,89 @@ BUILDIN(showevent) } } - #if PACKETVER >= 20120410 - if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7) - icon = 9999; // Default to nothing if icon id is invalid. - #else - if(icon < 0 || icon > 7) - icon = 0; - else - icon = icon + 1; - #endif + icon = quest->questinfo_validate_icon(icon); clif->quest_show_event(sd, &nd->bl, icon, color); return true; } /*========================================== + * Achievement System [Smokexyz/Hercules] + *-----------------------------------------*/ +/** + * Validates an objective index for the given achievement. + * Can be used for any achievement type. + * @command achievement_progress(<ach_id>,<obj_idx>,<progress>,<incremental?>{,<char_id>}); + * @param aid - achievement ID + * @param obj_idx - achievement objective index. + * @param progress - objective progress towards goal. + * @Param incremental - (boolean) true to add the progress towards the goal, + * false to use the progress only as a comparand. + * @param account_id - (optional) character ID to perform on. + * @return true on success, false on failure. + * @push 1 on success, 0 on failure. + */ +static BUILDIN(achievement_progress) +{ + struct map_session_data *sd = script->rid2sd(st); + int aid = script_getnum(st, 2); + int obj_idx = script_getnum(st, 3); + int progress = script_getnum(st, 4); + int incremental = script_getnum(st, 5); + int account_id = script_hasdata(st, 6) ? script_getnum(st, 6) : 0; + const struct achievement_data *ad = NULL; + + if ((ad = achievement->get(aid)) == NULL) { + ShowError("buildin_achievement_progress: Invalid achievement ID %d received.\n", aid); + script_pushint(st, 0); + return false; + } + + if (obj_idx <= 0 || obj_idx > VECTOR_LENGTH(ad->objective)) { + ShowError("buildin_achievement_progress: Invalid objective index %d received. (min: %d, max: %d)\n", obj_idx, 0, VECTOR_LENGTH(ad->objective)); + script_pushint(st, 0); + return false; + } + + obj_idx--; // convert to array index. + + if (progress <= 0 || progress > VECTOR_INDEX(ad->objective, obj_idx).goal) { + ShowError("buildin_achievement_progress: Progress exceeds goal limit for achievement id %d.\n", aid); + script_pushint(st, 0); + return false; + } + + if (incremental < 0 || incremental > 1) { + ShowError("buildin_achievement_progress: Argument 4 expects boolean (0/1). provided value: %d\n", incremental); + script_pushint(st, 0); + return false; + } + + if (script_hasdata(st, 6)) { + if (account_id <= 0) { + ShowError("buildin_achievement_progress: Invalid Account id %d provided.\n", account_id); + script_pushint(st, 0); + return false; + } else if ((sd = map->id2sd(account_id)) == NULL) { + ShowError("buildin_achievement_progress: Account with id %d was not found.\n", account_id); + script_pushint(st, 0); + return false; + } + } + + if (achievement->validate(sd, aid, obj_idx, progress, incremental ? true : false)) + script_pushint(st, progress); + else + script_pushint(st, 0); + + return true; +} + +/*========================================== * BattleGround System *------------------------------------------*/ -BUILDIN(waitingroom2bg) { +static BUILDIN(waitingroom2bg) +{ struct npc_data *nd; struct chat_data *cd; const char *map_name, *ev = "", *dev = ""; @@ -18264,17 +21469,18 @@ BUILDIN(waitingroom2bg) { for (i = 0; i < n && i < MAX_BG_MEMBERS; i++) { struct map_session_data *sd = cd->usersd[i]; if (sd != NULL && bg->team_join(bg_id, sd)) - mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id); + mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), sd->bl.id); else - mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0); + mapreg->setreg(reference_uid(script->add_variable("$@arenamembers"), i), 0); } - mapreg->setreg(script->add_str("$@arenamembersnum"), i); + mapreg->setreg(script->add_variable("$@arenamembersnum"), i); script_pushint(st,bg_id); return true; } -BUILDIN(waitingroom2bg_single) { +static BUILDIN(waitingroom2bg_single) +{ const char* map_name; struct npc_data *nd; struct chat_data *cd; @@ -18307,7 +21513,7 @@ BUILDIN(waitingroom2bg_single) { return true; } -BUILDIN(bg_team_setxy) +static BUILDIN(bg_team_setxy) { struct battleground_data *bgd; int bg_id; @@ -18321,7 +21527,7 @@ BUILDIN(bg_team_setxy) return true; } -BUILDIN(bg_warp) +static BUILDIN(bg_warp) { int x, y, map_index, bg_id; const char* map_name; @@ -18336,7 +21542,7 @@ BUILDIN(bg_warp) return true; } -BUILDIN(bg_monster) +static BUILDIN(bg_monster) { int class_ = 0, x = 0, y = 0, bg_id = 0; const char *str, *mapname, *evt=""; @@ -18353,7 +21559,7 @@ BUILDIN(bg_monster) return true; } -BUILDIN(bg_monster_set_team) +static BUILDIN(bg_monster_set_team) { int id = script_getnum(st,2), bg_id = script_getnum(st,3); @@ -18372,7 +21578,7 @@ BUILDIN(bg_monster_set_team) return true; } -BUILDIN(bg_leave) +static BUILDIN(bg_leave) { struct map_session_data *sd = script->rid2sd(st); if( sd == NULL || !sd->bg_id ) @@ -18382,14 +21588,14 @@ BUILDIN(bg_leave) return true; } -BUILDIN(bg_destroy) +static BUILDIN(bg_destroy) { int bg_id = script_getnum(st,2); bg->team_delete(bg_id); return true; } -BUILDIN(bg_getareausers) +static BUILDIN(bg_getareausers) { const char *str; int16 m, x0, y0, x1, y1; @@ -18423,7 +21629,7 @@ BUILDIN(bg_getareausers) return true; } -BUILDIN(bg_updatescore) +static BUILDIN(bg_updatescore) { const char *str; int16 m; @@ -18439,7 +21645,7 @@ BUILDIN(bg_updatescore) return true; } -BUILDIN(bg_get_data) +static BUILDIN(bg_get_data) { struct battleground_data *bgd; int bg_id = script_getnum(st,2), @@ -18466,11 +21672,12 @@ BUILDIN(bg_get_data) * Instancing Script Commands *------------------------------------------*/ -BUILDIN(instance_create) +static BUILDIN(instance_create) { const char *name; int owner_id, res; int type = IOT_PARTY; + struct map_session_data *sd = map->id2sd(st->rid); name = script_getstr(st, 2); owner_id = script_getnum(st, 3); @@ -18483,27 +21690,48 @@ BUILDIN(instance_create) } res = instance->create(owner_id, name, (enum instance_owner_type) type); - if( res == -4 ) { // Already exists - script_pushint(st, -1); - return true; - } else if( res < 0 ) { + if (sd != NULL) { + switch (res) { + case -4: // Already exists + clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_DUPLICATE, name); + break; + case -3: // No free instances + clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_EXIST, name); + break; + case -2: // Invalid type + clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_RIGHT, name); + break; + case -1: // Unknown + clif->msgtable_str(sd, MSG_MDUNGEON_SUBSCRIPTION_ERROR_UNKNOWN, name); + break; + default: + if (res < 0) + ShowError("buildin_instance_create: failed to unknown reason [%d].\n", res); + } + } else { const char *err; - switch(res) { - case -3: err = "No free instances"; break; - case -2: err = "Invalid party ID"; break; - case -1: err = "Invalid type"; break; - default: err = "Unknown"; break; + switch (res) { + case -3: + err = "No free instances"; + break; + case -2: + err = "Invalid party ID"; + break; + case -1: + err = "Invalid type"; + break; + default: + err = "Unknown"; + break; } - ShowError("buildin_instance_create: %s [%d].\n", err, res); - script_pushint(st, -2); - return true; + if (res < 0) + ShowError("buildin_instance_create: %s [%d].\n", err, res); } - script_pushint(st, res); return true; } -BUILDIN(instance_destroy) +static BUILDIN(instance_destroy) { int instance_id = -1; @@ -18522,7 +21750,7 @@ BUILDIN(instance_destroy) return true; } -BUILDIN(instance_attachmap) +static BUILDIN(instance_attachmap) { const char *map_name = NULL; int16 m; @@ -18546,7 +21774,8 @@ BUILDIN(instance_attachmap) return true; } -BUILDIN(instance_detachmap) { +static BUILDIN(instance_detachmap) +{ const char *str; int16 m; int instance_id = -1; @@ -18567,7 +21796,7 @@ BUILDIN(instance_detachmap) { return true; } -BUILDIN(instance_attach) +static BUILDIN(instance_attach) { int instance_id = script_getnum(st, 2); @@ -18578,12 +21807,13 @@ BUILDIN(instance_attach) return true; } -BUILDIN(instance_id) { +static BUILDIN(instance_id) +{ script_pushint(st, st->instance_id); return true; } -BUILDIN(instance_set_timeout) +static BUILDIN(instance_set_timeout) { int progress_timeout, idle_timeout; int instance_id = -1; @@ -18603,7 +21833,7 @@ BUILDIN(instance_set_timeout) return true; } -BUILDIN(instance_init) +static BUILDIN(instance_init) { int instance_id = script_getnum(st, 2); @@ -18621,7 +21851,7 @@ BUILDIN(instance_init) return true; } -BUILDIN(instance_announce) +static BUILDIN(instance_announce) { int instance_id = script_getnum(st,2); const char *mes = script_getstr(st,3); @@ -18652,7 +21882,7 @@ BUILDIN(instance_announce) return true; } -BUILDIN(instance_npcname) +static BUILDIN(instance_npcname) { const char *str; int instance_id = -1; @@ -18677,82 +21907,100 @@ BUILDIN(instance_npcname) return true; } -BUILDIN(has_instance) +static BUILDIN(has_instance) { struct map_session_data *sd; const char *str; int16 m; int instance_id = -1; + int i = 0, j = 0; bool type = strcmp(script->getfuncname(st),"has_instance2") == 0 ? true : false; str = script_getstr(st, 2); - if( (m = map->mapname2mapid(str)) < 0 ) { - if( type ) + if ((m = map->mapname2mapid(str)) < 0) { + if (type) { script_pushint(st, -1); - else + } else { script_pushconststr(st, ""); + } return true; } - if( script_hasdata(st, 3) ) + if (script_hasdata(st, 3)) instance_id = script_getnum(st, 3); - else if( st->instance_id >= 0 ) + else if (st->instance_id >= 0) instance_id = st->instance_id; - else if( (sd = script->rid2sd(st)) != NULL ) { + else if ((sd = script->rid2sd(st)) != NULL) { struct party_data *p; - int i = 0, j = 0; - if( sd->instances ) { - for( i = 0; i < sd->instances; i++ ) { - if( sd->instance[i] >= 0 ) { + if (sd->instances) { + for (i = 0; i < sd->instances; i++) { + if (sd->instance[i] >= 0) { ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m); - if( j != instance->list[sd->instance[i]].num_map ) + if (j != instance->list[sd->instance[i]].num_map) break; } } - if( i != sd->instances ) + if (i != sd->instances) { instance_id = sd->instance[i]; + } } if (instance_id == -1 && sd->status.party_id && (p = party->search(sd->status.party_id)) != NULL && p->instances) { - for( i = 0; i < p->instances; i++ ) { - if( p->instance[i] >= 0 ) { + for (i = 0; i < p->instances; i++) { + if (p->instance[i] >= 0) { ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m); - if( j != instance->list[p->instance[i]].num_map ) + if (j != instance->list[p->instance[i]].num_map) break; } } - if( i != p->instances ) + if (i != p->instances) { instance_id = p->instance[i]; + } } - if( instance_id == -1 && sd->guild && sd->guild->instances ) { - for( i = 0; i < sd->guild->instances; i++ ) { - if( sd->guild->instance[i] >= 0 ) { + if (instance_id == -1 && sd->guild && sd->guild->instances) { + for (i = 0; i < sd->guild->instances; i++) { + if (sd->guild->instance[i] >= 0) { ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m); - if( j != instance->list[sd->guild->instance[i]].num_map ) + if (j != instance->list[sd->guild->instance[i]].num_map) break; } } - if( i != sd->guild->instances ) + if (i != sd->guild->instances) instance_id = sd->guild->instance[i]; } } - if( !instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0 ) { - if( type ) + if (instance_id == -1) { + for (i = 0; i < instance->instances; i++) { + if (instance->list[i].state != INSTANCE_FREE && instance->list[i].owner_type == IOT_NONE && instance->list[i].num_map > 0) { + ARR_FIND(0, instance->list[i].num_map, j, map->list[instance->list[i].map[j]].instance_src_map == m); + if (j != instance->list[i].num_map) + break; + } + } + if (i != instance->instances) { + instance_id = instance->list[i].id; + } + } + + if (!instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0) { + if (type) { script_pushint(st, -1); - else + } else { script_pushconststr(st, ""); + } return true; } - if( type ) + if (type) { script_pushint(st, instance_id); - else + } else { script_pushconststr(st, map->list[m].name); + } return true; } -int buildin_instance_warpall_sub(struct block_list *bl, va_list ap) +static int buildin_instance_warpall_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd = NULL; int map_index = va_arg(ap,int); @@ -18768,7 +22016,7 @@ int buildin_instance_warpall_sub(struct block_list *bl, va_list ap) return 0; } -BUILDIN(instance_warpall) +static BUILDIN(instance_warpall) { int16 m; int instance_id = -1; @@ -18807,7 +22055,7 @@ BUILDIN(instance_warpall) * Example: instance_check_party (getcharid(1){,amount}{,min}{,max}); * Example 2: instance_check_party (getcharid(1),1,1,99); *------------------------------------------*/ -BUILDIN(instance_check_party) +static BUILDIN(instance_check_party) { int amount, min, max, i, party_id, c = 0; struct party_data *p = NULL; @@ -18866,7 +22114,7 @@ BUILDIN(instance_check_party) * Example: instance_check_guild (getcharid(2){,amount}{,min}{,max}); * Example 2: instance_check_guild (getcharid(2),1,1,99); *------------------------------------------*/ -BUILDIN(instance_check_guild) +static BUILDIN(instance_check_guild) { int amount, min, max, i, guild_id, c = 0; struct guild *g = NULL; @@ -18918,7 +22166,7 @@ BUILDIN(instance_check_guild) /*========================================== * Custom Fonts *------------------------------------------*/ -BUILDIN(setfont) +static BUILDIN(setfont) { struct map_session_data *sd = script->rid2sd(st); int font = script_getnum(st,2); @@ -18934,7 +22182,7 @@ BUILDIN(setfont) return true; } -int buildin_mobuseskill_sub(struct block_list *bl, va_list ap) +static int buildin_mobuseskill_sub(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; struct block_list *tbl; @@ -18981,7 +22229,7 @@ int buildin_mobuseskill_sub(struct block_list *bl, va_list ap) /*========================================== * areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>; *------------------------------------------*/ -BUILDIN(areamobuseskill) +static BUILDIN(areamobuseskill) { struct block_list center; int16 m; @@ -19011,7 +22259,7 @@ BUILDIN(areamobuseskill) return true; } -BUILDIN(progressbar) +static BUILDIN(progressbar) { struct map_session_data * sd = script->rid2sd(st); const char * color; @@ -19032,8 +22280,30 @@ BUILDIN(progressbar) clif->progressbar(sd, (unsigned int)strtoul(color, (char **)NULL, 0), second); return true; } +static BUILDIN(progressbar_unit) +{ + const char *color = script_getstr(st, 2); + uint32 second = script_getnum(st, 3); + + if (script_hasdata(st, 4)) { + struct block_list *bl = map->id2bl(script_getnum(st, 4)); -BUILDIN(pushpc) + if (bl == NULL) { + ShowWarning("buildin_progressbar_unit: Error in finding object with given GID %d!\n", script_getnum(st, 4)); + return true; + } + clif->progressbar_unit(bl, (unsigned int)strtoul(color, (char **)NULL, 0), second); + } else { + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) + return false; + + clif->progressbar_unit(&sd->bl, (unsigned int)strtoul(color, (char **)NULL, 0), second); + } + return true; +} +static BUILDIN(pushpc) { uint8 dir; int cells, dx, dy; @@ -19073,7 +22343,7 @@ BUILDIN(pushpc) /// Invokes buying store preparation window /// buyingstore <slots>; -BUILDIN(buyingstore) +static BUILDIN(buyingstore) { struct map_session_data* sd; @@ -19087,7 +22357,7 @@ BUILDIN(buyingstore) /// Invokes search store info window /// searchstores <uses>,<effect>; -BUILDIN(searchstores) +static BUILDIN(searchstores) { unsigned short effect; unsigned int uses; @@ -19118,7 +22388,7 @@ BUILDIN(searchstores) } /// Displays a number as large digital clock. /// showdigit <value>[,<type>]; -BUILDIN(showdigit) +static BUILDIN(showdigit) { unsigned int type = 0; int value; @@ -19148,7 +22418,7 @@ BUILDIN(showdigit) /** * Rune Knight **/ -BUILDIN(makerune) +static BUILDIN(makerune) { struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -19161,15 +22431,19 @@ BUILDIN(makerune) /** * hascashmount() returns 1 if mounting a cash mount or 0 otherwise **/ -BUILDIN(hascashmount) +static BUILDIN(hascashmount) { struct map_session_data *sd = script->rid2sd(st); + if (sd == NULL) return true; - if( sd->sc.data[SC_ALL_RIDING] ) - script_pushint(st,1); - else - script_pushint(st,0); + + if (sd->sc.data[SC_ALL_RIDING]) { + script_pushint(st, 1); + } else { + script_pushint(st, 0); + } + return true; } @@ -19180,21 +22454,27 @@ BUILDIN(hascashmount) * - Will fail if the player is already riding a standard mount e.g. dragon, peco, wug, mado, etc. * - Will unmount the player is he is already mounting a cash mount **/ -BUILDIN(setcashmount) +static BUILDIN(setcashmount) { struct map_session_data *sd = script->rid2sd(st); + if (sd == NULL) return true; + if (pc_hasmount(sd)) { - clif->msgtable(sd, MSG_REINS_CANT_USE_MOUNTED); - script_pushint(st,0);//can't mount with one of these +#if PACKETVER >= 20110531 + clif->msgtable(sd, MSG_FAIELD_RIDING_OVERLAPPED); +#endif + script_pushint(st, 0); // Can't mount with one of these } else { - if (sd->sc.data[SC_ALL_RIDING]) + if (sd->sc.data[SC_ALL_RIDING]) { status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); - else - sc_start(NULL, &sd->bl, SC_ALL_RIDING, 100, 25, INFINITE_DURATION); - script_pushint(st,1);//in both cases, return 1. + } else { + sc_start(NULL, &sd->bl, SC_ALL_RIDING, 100, battle_config.boarding_halter_speed, INFINITE_DURATION); + } + script_pushint(st, 1); // In both cases, return 1. } + return true; } @@ -19202,7 +22482,7 @@ BUILDIN(setcashmount) * Retrieves quantity of arguments provided to callfunc/callsub. * getargcount() -> amount of arguments received in a function **/ -BUILDIN(getargcount) +static BUILDIN(getargcount) { struct script_retinfo* ri; @@ -19221,7 +22501,7 @@ BUILDIN(getargcount) /** * getcharip(<account ID>/<character ID>/<character name>) **/ -BUILDIN(getcharip) +static BUILDIN(getcharip) { struct map_session_data* sd = NULL; @@ -19256,25 +22536,59 @@ BUILDIN(getcharip) return true; } +enum function_type { + FUNCTION_IS_NONE = 0, + FUNCTION_IS_COMMAND, + FUNCTION_IS_GLOBAL, + FUNCTION_IS_LOCAL, + FUNCTION_IS_LABEL, +}; + /** - * is_function(<function name>) -> 1 if function exists, 0 otherwise + * is_function(<function name>) **/ -BUILDIN(is_function) +static BUILDIN(is_function) { - const char* str = script_getstr(st,2); + const char *str = script_getstr(st, 2); + enum function_type type = FUNCTION_IS_NONE; - if( strdb_exists(script->userfunc_db, str) ) - script_pushint(st,1); - else - script_pushint(st,0); + // TODO: add support for exported functions (#2142) + if (strdb_exists(script->userfunc_db, str)) { + type = FUNCTION_IS_GLOBAL; + } else { + int n = script->search_str(str); + + if (n >= 0) { + switch (script->str_data[n].type) { + case C_FUNC: + type = FUNCTION_IS_COMMAND; + break; + case C_USERFUNC: + case C_USERFUNC_POS: + type = FUNCTION_IS_LOCAL; + break; + case C_POS: + type = FUNCTION_IS_LABEL; + break; + case C_NAME: + if (script->str_data[n].label >= 0) { + // WTF... ? + // for some reason local functions can have type C_NAME + type = FUNCTION_IS_LOCAL; + } + } + } + } + + script_pushint(st, type); return true; } /** * freeloop(<toggle>) -> toggles this script instance's looping-check ability **/ -BUILDIN(freeloop) +static BUILDIN(freeloop) { if( script_getnum(st,2) ) st->freeloop = 1; @@ -19286,7 +22600,7 @@ BUILDIN(freeloop) return true; } -BUILDIN(sit) +static BUILDIN(sit) { struct map_session_data *sd = NULL; @@ -19307,7 +22621,7 @@ BUILDIN(sit) return true; } -BUILDIN(stand) +static BUILDIN(stand) { struct map_session_data *sd = NULL; @@ -19328,7 +22642,7 @@ BUILDIN(stand) return true; } -BUILDIN(issit) +static BUILDIN(issit) { struct map_session_data *sd = NULL; @@ -19347,10 +22661,47 @@ BUILDIN(issit) return true; } +static BUILDIN(add_group_command) +{ + AtCommandInfo *acmd_d; + struct atcmd_binding_data *bcmd_d; + GroupSettings *group; + int group_index; + const char *atcmd = script_getstr(st, 2); + int group_id = script_getnum(st, 3); + bool self_perm = (script_getnum(st, 4) == 1); + bool char_perm = (script_getnum(st, 5) == 1); + + if (!pcg->exists(group_id)) { + ShowWarning("script:add_group_command: group does not exist: %i\n", group_id); + script_pushint(st, 0); + return false; + } + + group = pcg->id2group(group_id); + group_index = pcg->get_idx(group); + + if ((bcmd_d = atcommand->get_bind_byname(atcmd)) != NULL) { + bcmd_d->at_groups[group_index] = self_perm; + bcmd_d->char_groups[group_index] = char_perm; + script_pushint(st, 1); + return true; + } else if ((acmd_d = atcommand->get_info_byname(atcmd)) != NULL) { + acmd_d->at_groups[group_index] = self_perm; + acmd_d->char_groups[group_index] = char_perm; + script_pushint(st, 1); + return true; + } + + ShowWarning("script:add_group_command: command does not exist: %s\n", atcmd); + script_pushint(st, 0); + return false; +} + /** * @commands (script based) **/ -BUILDIN(bindatcmd) +static BUILDIN(bindatcmd) { const char* atcmd; const char* eventName; @@ -19396,12 +22747,14 @@ BUILDIN(bindatcmd) atcommand->binding[i]->group_lv = group_lv; atcommand->binding[i]->group_lv_char = group_lv_char; atcommand->binding[i]->log = log; + CREATE(atcommand->binding[i]->at_groups, char, db_size(pcg->db)); + CREATE(atcommand->binding[i]->char_groups, char, db_size(pcg->db)); } return true; } -BUILDIN(unbindatcmd) +static BUILDIN(unbindatcmd) { const char* atcmd; int i = 0; @@ -19419,6 +22772,8 @@ BUILDIN(unbindatcmd) ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command, atcmd) == 0); if( i < atcommand->binding_count ) { int cursor = 0; + aFree(atcommand->binding[i]->at_groups); + aFree(atcommand->binding[i]->char_groups); aFree(atcommand->binding[i]); atcommand->binding[i] = NULL; /* compact the list now that we freed a slot somewhere */ @@ -19443,7 +22798,7 @@ BUILDIN(unbindatcmd) return true; } -BUILDIN(useatcmd) +static BUILDIN(useatcmd) { struct map_session_data *sd, *dummy_sd = NULL; int fd; @@ -19481,8 +22836,69 @@ BUILDIN(useatcmd) return true; } +static BUILDIN(has_permission) +{ + struct map_session_data *sd; + enum e_pc_permission perm; + + if (script_hasdata(st, 3)) { + sd = map->id2sd(script_getnum(st, 3)); + } else { + sd = script->rid2sd(st); + } + + if (sd == NULL) { + script_pushint(st, 0); + return false; + } + + if (script_isstringtype(st, 2)) { + // to check for plugin permissions + int i = 0, j = -1; + const char *name = script_getstr(st, 2); + for (; i < pcg->permission_count; ++i) { + if (strcmp(pcg->permissions[i].name, name) == 0) { + j = i; + break; + } + } + if (j < 0) { + ShowError("script:has_permission: unknown permission: %s\n", name); + script_pushint(st, 0); + return false; + } + script_pushint(st, pc_has_permission(sd, pcg->permissions[j].permission)); + return true; + } + + // to ckeck for built-in permission + perm = script_getnum(st, 2); + script_pushint(st, pc_has_permission(sd, perm)); + return true; +} + +static BUILDIN(can_use_command) +{ + struct map_session_data *sd; + const char *cmd = script_getstr(st, 2); + + if (script_hasdata(st, 3)) { + sd = map->id2sd(script_getnum(st, 3)); + } else { + sd = script->rid2sd(st); + } + + if (sd == NULL) { + script_pushint(st, 0); + return false; + } + + script_pushint(st, pc->can_use_command(sd, cmd)); + return true; +} + /* getrandgroupitem <container_item_id>,<quantity> */ -BUILDIN(getrandgroupitem) +static BUILDIN(getrandgroupitem) { struct item_data *data = NULL; struct map_session_data *sd = NULL; @@ -19523,7 +22939,7 @@ BUILDIN(getrandgroupitem) if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); if( pc->candrop(sd,&it) ) - map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0); + map->addflooritem(&sd->bl, &it, get_count, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false); } } } @@ -19536,14 +22952,14 @@ BUILDIN(getrandgroupitem) /* cleanmap <map_name>; * cleanarea <map_name>, <x0>, <y0>, <x1>, <y1>; */ -int script_cleanfloor_sub(struct block_list *bl, va_list ap) +static int script_cleanfloor_sub(struct block_list *bl, va_list ap) { map->clearflooritem(bl); return 0; } -BUILDIN(cleanmap) +static BUILDIN(cleanmap) { const char *mapname = script_getstr(st, 2); int16 m = map->mapname2mapid(mapname); @@ -19572,7 +22988,7 @@ BUILDIN(cleanmap) /* Cast a skill on the attached player. * npcskill <skill id>, <skill lvl>, <stat point>, <NPC level>; * npcskill "<skill name>", <skill lvl>, <stat point>, <NPC level>; */ -BUILDIN(npcskill) +static BUILDIN(npcskill) { struct npc_data *nd; uint16 skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); @@ -19618,7 +23034,7 @@ BUILDIN(npcskill) /* Turns a player into a monster and grants SC attribute effect. [malufett/Hercules] * montransform <monster name/id>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>; */ -BUILDIN(montransform) +static BUILDIN(montransform) { int tick; enum sc_type type; @@ -19702,7 +23118,7 @@ BUILDIN(montransform) * * @return The queue, or NULL if it doesn't exist. */ -struct script_queue *script_hqueue_get(int idx) +static struct script_queue *script_hqueue_get(int idx) { if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) return NULL; @@ -19714,7 +23130,7 @@ struct script_queue *script_hqueue_get(int idx) * * @return The index of the created queue. */ -int script_hqueue_create(void) +static int script_hqueue_create(void) { struct script_queue *queue = NULL; int i; @@ -19741,7 +23157,7 @@ int script_hqueue_create(void) * .@queue_id = queue(); * @endcode */ -BUILDIN(queue) +static BUILDIN(queue) { script_pushint(st,script->queue_create()); return true; @@ -19756,7 +23172,7 @@ BUILDIN(queue) * .@size = queuesize(<queue id>); * \endcode */ -BUILDIN(queuesize) +static BUILDIN(queuesize) { int idx = script_getnum(st, 2); @@ -19778,7 +23194,7 @@ BUILDIN(queuesize) * @retval false if the queue is invalid or the entry is already in the queue. * @retval true in case of success. */ -bool script_hqueue_add(int idx, int var) +static bool script_hqueue_add(int idx, int var) { int i; struct map_session_data *sd = NULL; @@ -19816,7 +23232,7 @@ bool script_hqueue_add(int idx, int var) * .@size = queuesize(.@queue_id); * @endcode */ -BUILDIN(queueadd) +static BUILDIN(queueadd) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); @@ -19837,7 +23253,7 @@ BUILDIN(queueadd) * @retval true if the entry was removed. * @retval false if the entry wasn't in queue. */ -bool script_hqueue_remove(int idx, int var) +static bool script_hqueue_remove(int idx, int var) { int i; struct map_session_data *sd = NULL; @@ -19874,7 +23290,7 @@ bool script_hqueue_remove(int idx, int var) * queueremove(.@queue_id, .@value); * @endcode */ -BUILDIN(queueremove) +static BUILDIN(queueremove) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); @@ -19890,7 +23306,7 @@ BUILDIN(queueremove) /** * Script command queueopt: Modifies the options of a queue. * - * When the option value isn't provided, the option is removed. + * When the <event label> isn't provided, the option is removed. * * Returns 1 (true) on success, 0 (false) on failure. * @@ -19900,13 +23316,13 @@ BUILDIN(queueremove) * - QUEUEOPT_MAPCHANGE * * When the QUEUEOPT_MAPCHANGE event is triggered, it sets a temporary - * character variable \c @Queue_Destination_Map$ with the destination map name. + * character variable @Queue_Destination_Map$ with the destination map name. * * @code{.herc} - * queueopt(.@queue_id, optionType, <optional val>); + * queueopt(.@queue_id, optionType{, <event label>}); * @endcode */ -BUILDIN(queueopt) +static BUILDIN(queueopt) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); @@ -19956,7 +23372,7 @@ BUILDIN(queueopt) * @retval true if the queue was correctly deleted. * @retval false if the queue didn't exist. */ -bool script_hqueue_del(int idx) +static bool script_hqueue_del(int idx) { if (!script->queue_clear(idx)) return false; @@ -19975,7 +23391,7 @@ bool script_hqueue_del(int idx) * queuedel(.@queue_id); * @endcode */ -BUILDIN(queuedel) +static BUILDIN(queuedel) { int idx = script_getnum(st, 2); @@ -19995,7 +23411,7 @@ BUILDIN(queuedel) * @retval true if the queue was correctly cleared. * @retval false if the queue didn't exist. */ -bool script_hqueue_clear(int idx) +static bool script_hqueue_clear(int idx) { struct script_queue *queue = NULL; @@ -20032,7 +23448,7 @@ bool script_hqueue_clear(int idx) * .@id = queueiterator(.@queue_id); * @endcode */ -BUILDIN(queueiterator) +static BUILDIN(queueiterator) { int qid = script_getnum(st, 2); struct script_queue *queue = NULL; @@ -20075,7 +23491,7 @@ BUILDIN(queueiterator) * } * @endcode */ -BUILDIN(qiget) +static BUILDIN(qiget) { int idx = script_getnum(st, 2); struct script_queue_iterator *it = NULL; @@ -20109,7 +23525,7 @@ BUILDIN(qiget) * } * @endcode */ -BUILDIN(qicheck) +static BUILDIN(qicheck) { int idx = script_getnum(st, 2); struct script_queue_iterator *it = NULL; @@ -20140,7 +23556,7 @@ BUILDIN(qicheck) * qiclear(.@iter); * @endcode */ -BUILDIN(qiclear) +static BUILDIN(qiclear) { int idx = script_getnum(st, 2); struct script_queue_iterator *it = NULL; @@ -20165,7 +23581,8 @@ BUILDIN(qiclear) * packageitem({<optional container_item_id>}) * when no item id is provided it tries to assume it comes from the current item id being processed (if any) **/ -BUILDIN(packageitem) { +static BUILDIN(packageitem) +{ struct item_data *data = NULL; struct map_session_data *sd = NULL; int nameid; @@ -20199,7 +23616,8 @@ BUILDIN(packageitem) { /* New Battlegrounds Stuff */ /* bg_team_create(map_name,respawn_x,respawn_y) */ /* returns created team id or -1 when fails */ -BUILDIN(bg_create_team) { +static BUILDIN(bg_create_team) +{ const char *map_name, *ev = "", *dev = "";//ev and dev will be dropped. int x, y, map_index = 0, bg_id; @@ -20226,7 +23644,8 @@ BUILDIN(bg_create_team) { /* bg_join_team(team_id{,optional account id}) */ /* when account id is not present it tries to autodetect from the attached player (if any) */ /* returns 0 when successful, 1 otherwise */ -BUILDIN(bg_join_team) { +static BUILDIN(bg_join_team) +{ struct map_session_data *sd; int team_id = script_getnum(st, 2); @@ -20252,9 +23671,9 @@ BUILDIN(bg_join_team) { * 3 - Party Bound * 4 - Character Bound *------------------------------------------*/ -BUILDIN(countbound) +static BUILDIN(countbound) { - int i, type, j=0, k=0; + int type, j=0, k=0; struct map_session_data *sd = script->rid2sd(st); if (sd == NULL) @@ -20262,12 +23681,12 @@ BUILDIN(countbound) type = script_hasdata(st,2)?script_getnum(st,2):0; - for(i=0;i<MAX_INVENTORY;i++) { + for (int i = 0; i < sd->status.inventorySize; i++) { if(sd->status.inventory[i].nameid > 0 && ( (!type && sd->status.inventory[i].bound > 0) || (type && sd->status.inventory[i].bound == type) )) { - pc->setreg(sd,reference_uid(script->add_str("@bound_items"), k),sd->status.inventory[i].nameid); + pc->setreg(sd,reference_uid(script->add_variable("@bound_items"), k),sd->status.inventory[i].nameid); k++; j += sd->status.inventory[i].amount; } @@ -20287,7 +23706,7 @@ BUILDIN(countbound) * 3 - Party Bound * 4 - Character Bound *------------------------------------------*/ -BUILDIN(checkbound) +static BUILDIN(checkbound) { int i, nameid = script_getnum(st,2); int bound_type = 0; @@ -20308,27 +23727,28 @@ BUILDIN(checkbound) ShowError("script_checkbound: Not a valid bind type! Type=%d\n", bound_type); } - ARR_FIND( 0, MAX_INVENTORY, i, (sd->status.inventory[i].nameid == nameid && + ARR_FIND(0, sd->status.inventorySize, i, (sd->status.inventory[i].nameid == nameid && ( sd->status.inventory[i].refine == (script_hasdata(st,4)? script_getnum(st,4) : sd->status.inventory[i].refine) ) && ( sd->status.inventory[i].attribute == (script_hasdata(st,5)? script_getnum(st,5) : sd->status.inventory[i].attribute) ) && ( sd->status.inventory[i].card[0] == (script_hasdata(st,6)? script_getnum(st,6) : sd->status.inventory[i].card[0]) ) && ( sd->status.inventory[i].card[1] == (script_hasdata(st,7)? script_getnum(st,7) : sd->status.inventory[i].card[1]) ) && ( sd->status.inventory[i].card[2] == (script_hasdata(st,8)? script_getnum(st,8) : sd->status.inventory[i].card[2]) ) && ( sd->status.inventory[i].card[3] == (script_hasdata(st,9)? script_getnum(st,9) : sd->status.inventory[i].card[3]) ) && - ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type )) ); + ((sd->status.inventory[i].bound > 0 && !bound_type) || sd->status.inventory[i].bound == bound_type))); - if( i < MAX_INVENTORY ){ + if (i < sd->status.inventorySize) { script_pushint(st, sd->status.inventory[i].bound); return true; - } else + } else { script_pushint(st,0); + } return true; } /* bg_match_over( arena_name {, optional canceled } ) */ /* returns 0 when successful, 1 otherwise */ -BUILDIN(bg_match_over) +static BUILDIN(bg_match_over) { bool canceled = script_hasdata(st,3) ? true : false; struct bg_arena *arena = bg->name2arena(script_getstr(st, 2)); @@ -20342,7 +23762,7 @@ BUILDIN(bg_match_over) return true; } -BUILDIN(instance_mapname) +static BUILDIN(instance_mapname) { const char *map_name; int m; @@ -20367,7 +23787,7 @@ BUILDIN(instance_mapname) /* modify an instances' reload-spawn point */ /* instance_set_respawn <map_name>,<x>,<y>{,<instance_id>} */ /* returns 1 when successful, 0 otherwise. */ -BUILDIN(instance_set_respawn) +static BUILDIN(instance_set_respawn) { const char *map_name; short instance_id = -1; @@ -20415,7 +23835,7 @@ BUILDIN(instance_set_respawn) * * @return 1 on success, 0 otherwise. **/ -BUILDIN(openshop) +static BUILDIN(openshop) { struct npc_data *nd; struct map_session_data *sd; @@ -20452,12 +23872,13 @@ BUILDIN(openshop) * adds <Item_ID> (or modifies if present) to shop * if price not provided (or -1) uses the item's value_sell **/ -BUILDIN(sellitem) +static BUILDIN(sellitem) { struct npc_data *nd; struct item_data *it; int i = 0, id = script_getnum(st,2); int value = 0; + int value2 = 0; int qty = 0; if( !(nd = map->id2nd(st->oid)) ) { @@ -20468,17 +23889,43 @@ BUILDIN(sellitem) return false; } - value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy; - if( value == -1 ) - value = it->value_buy; - - if( !nd->u.scr.shop ) - npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); - else {/* no need to run this if its empty */ - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (!nd->u.scr.shop) { + npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id); + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); } + } else {/* no need to run this if its empty */ + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 5)) { + ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n"); + return false; + } + value = script_getnum(st, 4); + value2 = script_getnum(st, 5); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == value && item->value2 == value2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } + } + } + + if (nd->u.scr.shop->type != NST_BARTER) { + value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy; + if( value == -1 ) + value = it->value_buy; } if( nd->u.scr.shop->type == NST_MARKET ) { @@ -20493,19 +23940,29 @@ BUILDIN(sellitem) it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path); } - if( i != nd->u.scr.shop->items ) { + if (nd->u.scr.shop->type == NST_BARTER) { + qty = script_getnum(st, 3); + if (qty < -1 || value <= 0 || value2 <= 0) { + ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n"); + return false; + } + } + + if (i != nd->u.scr.shop->items) { nd->u.scr.shop->item[i].value = value; nd->u.scr.shop->item[i].qty = qty; - if( nd->u.scr.shop->type == NST_MARKET ) /* has been manually updated, make it reflect on sql */ - npc->market_tosql(nd,i); + if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */ + npc->market_tosql(nd, i); + else if (nd->u.scr.shop->type == NST_BARTER) /* has been manually updated, make it reflect on sql */ + npc->barter_tosql(nd, i); } else { - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) break; } - if( i == nd->u.scr.shop->items ) { - if( nd->u.scr.shop->items == USHRT_MAX ) { + if (i == nd->u.scr.shop->items) { + if (nd->u.scr.shop->items == USHRT_MAX) { ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path); return false; } @@ -20515,6 +23972,7 @@ BUILDIN(sellitem) nd->u.scr.shop->item[i].nameid = it->nameid; nd->u.scr.shop->item[i].value = value; + nd->u.scr.shop->item[i].value2 = value2; nd->u.scr.shop->item[i].qty = qty; } @@ -20528,38 +23986,58 @@ BUILDIN(sellitem) * * @return 1 on success, 0 otherwise **/ -BUILDIN(stopselling) +static BUILDIN(stopselling) { struct npc_data *nd; - int i, id = script_getnum(st,2); + int i, id = script_getnum(st, 2); - if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + if (!(nd = map->id2nd(st->oid)) || !nd->u.scr.shop) { ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n"); return false; } - for( i = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == id ) - break; + if (nd->u.scr.shop->type == NST_BARTER) { + if (!script_hasdata(st, 4)) { + ShowError("buildin_stopselling: called with wrong number of arguments\n"); + return false; + } + const int id2 = script_getnum(st, 3); + const int amount2 = script_getnum(st, 4); + for (i = 0; i < nd->u.scr.shop->items; i++) { + const struct npc_item_list *const item = &nd->u.scr.shop->item[i]; + if (item->nameid == id && item->value == id2 && item->value2 == amount2) { + break; + } + } + } else { + for (i = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == id) { + break; + } + } } - if( i != nd->u.scr.shop->items ) { + if (i != nd->u.scr.shop->items) { int cursor; - if( nd->u.scr.shop->type == NST_MARKET ) - npc->market_delfromsql(nd,i); + if (nd->u.scr.shop->type == NST_MARKET) + npc->market_delfromsql(nd, i); + if (nd->u.scr.shop->type == NST_BARTER) + npc->barter_delfromsql(nd, i); nd->u.scr.shop->item[i].nameid = 0; nd->u.scr.shop->item[i].value = 0; + nd->u.scr.shop->item[i].value2 = 0; nd->u.scr.shop->item[i].qty = 0; - for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) { - if( nd->u.scr.shop->item[i].nameid == 0 ) + for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) { + if (nd->u.scr.shop->item[i].nameid == 0) continue; - if( cursor != i ) { + if (cursor != i) { nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid; nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value; + nd->u.scr.shop->item[cursor].value2 = nd->u.scr.shop->item[i].value2; nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty; } @@ -20579,7 +24057,7 @@ BUILDIN(stopselling) * updates currently-attached player shop currency **/ /* setcurrency(<Val1>,{<Val2>}) */ -BUILDIN(setcurrency) +static BUILDIN(setcurrency) { int val1 = script_getnum(st,2), val2 = script_hasdata(st, 3) ? script_getnum(st,3) : 0; @@ -20603,7 +24081,7 @@ BUILDIN(setcurrency) * check enum npc_shop_types for list * cleans shop list on use **/ -BUILDIN(tradertype) +static BUILDIN(tradertype) { int type = script_getnum(st, 2); struct npc_data *nd; @@ -20625,7 +24103,8 @@ BUILDIN(tradertype) nd->u.scr.shop->item[i].value = 0; nd->u.scr.shop->item[i].qty = 0; } - npc->market_delfromsql(nd,USHRT_MAX); + npc->market_delfromsql(nd, INT_MAX); + npc->barter_delfromsql(nd, INT_MAX); } #if PACKETVER < 20131223 @@ -20634,6 +24113,12 @@ BUILDIN(tradertype) script->reportsrc(st); } #endif +#if PACKETVER_ZERO_NUM < 20181226 + if (type == NST_BARTER) { + ShowWarning("buildin_tradertype: NST_BARTER is only available with PACKETVER_ZERO_NUM 20181226 or newer!\n"); + script->reportsrc(st); + } +#endif if( nd->u.scr.shop ) nd->u.scr.shop->type = type; @@ -20646,7 +24131,7 @@ BUILDIN(tradertype) * * signs the transaction can proceed **/ -BUILDIN(purchaseok) +static BUILDIN(purchaseok) { struct npc_data *nd; @@ -20665,7 +24150,7 @@ BUILDIN(purchaseok) * * @return number of available items in the script's attached shop **/ -BUILDIN(shopcount) +static BUILDIN(shopcount) { struct npc_data *nd; int id = script_getnum(st, 2); @@ -20677,8 +24162,8 @@ BUILDIN(shopcount) } else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) { ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id); return false; - } else if ( nd->u.scr.shop->type != NST_MARKET ) { - ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id); + } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) { + ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER shop!\n",id); return false; } @@ -20703,9 +24188,9 @@ BUILDIN(shopcount) * Sends a message through the specified chat channel. * */ -BUILDIN(channelmes) +static BUILDIN(channelmes) { - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd = map->id2sd(st->rid); const char *channelname = script_getstr(st, 2); struct channel_data *chan = channel->search(channelname, sd); @@ -20720,11 +24205,62 @@ BUILDIN(channelmes) return true; } +static BUILDIN(addchannelhandler) +{ + int i; + struct map_session_data *sd = map->id2sd(st->rid); + const char *channelname = script_getstr(st, 2); + const char *eventname = script_getstr(st, 3); + struct channel_data *chan = channel->search(channelname, sd); + + if (!chan) { + script_pushint(st, 0); + return true; + } + + ARR_FIND(0, MAX_EVENTQUEUE, i, chan->handlers[i][0] == '\0'); + + if (i < MAX_EVENTQUEUE) { + safestrncpy(chan->handlers[i], eventname, EVENT_NAME_LENGTH); //Event enqueued. + script_pushint(st, 1); + return true; + } + + ShowWarning("script:addchannelhandler: too many handlers for channel %s.\n", channelname); + script_pushint(st, 0); + return true; +} + +static BUILDIN(removechannelhandler) +{ + int i; + struct map_session_data *sd = map->id2sd(st->rid); + const char *channelname = script_getstr(st, 2); + const char *eventname = script_getstr(st, 3); + struct channel_data *chan = channel->search(channelname, sd); + + if (!chan) { + script_pushint(st, 0); + return true; + } + + for (i = 0; i < MAX_EVENTQUEUE; i++) { + if (strcmp(chan->handlers[i], eventname) == 0) { + chan->handlers[i][0] = '\0'; + script_pushint(st, 1); + return true; + } + } + + script_pushint(st, 0); + return true; +} + /** By Cydh -Display script message -showscript "<message>"{,<GID>}; -*/ -BUILDIN(showscript) + * Display script message + * showscript "<message>"{, <GID>}; + */ +static BUILDIN(showscript) { struct block_list *bl = NULL; const char *msg = script_getstr(st, 2); @@ -20751,7 +24287,7 @@ BUILDIN(showscript) return true; } -BUILDIN(mergeitem) +static BUILDIN(mergeitem) { struct map_session_data *sd = script->rid2sd(st); @@ -20763,8 +24299,102 @@ BUILDIN(mergeitem) return true; } +// getcalendartime(<day of month>, <day of week>{, <hour>{, <minute>}}); +// Returns the UNIX Timestamp of next ocurrency of given time +static BUILDIN(getcalendartime) +{ + struct tm info = { 0 }; + int day_of_month = script_hasdata(st, 4) ? script_getnum(st, 4) : -1; + int day_of_week = script_hasdata(st, 5) ? script_getnum(st, 5) : -1; + int year = date_get_year(); + int month = date_get_month(); + int day = date_get_day(); + int cur_hour = date_get_hour(); + int cur_min = date_get_min(); + int hour = script_getnum(st, 2); + int minute = script_getnum(st, 3); + + info.tm_sec = 0; + info.tm_min = minute; + info.tm_hour = hour; + info.tm_mday = day; + info.tm_mon = month - 1; + info.tm_year = year - 1900; + + if (day_of_month > -1 && day_of_week > -1) { + ShowError("script:getcalendartime: You must only specify a day_of_week or a day_of_month, not both\n"); + script_pushint(st, -1); + return false; + } + if (day_of_month > -1 && (day_of_month < 1 || day_of_month > 31)) { + ShowError("script:getcalendartime: Day of Month in invalid range. Must be between 1 and 31.\n"); + script_pushint(st, -1); + return false; + } + if (day_of_week > -1 && (day_of_week < 0 || day_of_week > 6)) { + ShowError("script:getcalendartime: Day of Week in invalid range. Must be between 0 and 6.\n"); + script_pushint(st, -1); + return false; + } + if (hour > -1 && (hour > 23)) { + ShowError("script:getcalendartime: Hour in invalid range. Must be between 0 and 23.\n"); + script_pushint(st, -1); + return false; + } + if (minute > -1 && (minute > 59)) { + ShowError("script:getcalendartime: Minute in invalid range. Must be between 0 and 59.\n"); + script_pushint(st, -1); + return false; + } + if (hour == -1 || minute == -1) { + ShowError("script:getcalendartime: Minutes and Hours are required\n"); + script_pushint(st, -1); + return false; + } + + if (day_of_month > -1) { + if (day_of_month < day) { // Next Month + info.tm_mon++; + } else if (day_of_month == day) { // Today + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { // But past time, next month + info.tm_mon++; + } + } + + // Loops until month has finding a month that has day_of_month + do { + time_t t; + struct tm *lt; + info.tm_mday = day_of_month; + t = mktime(&info); + lt = localtime(&t); + info = *lt; + } while (info.tm_mday != day_of_month); + } else if (day_of_week > -1) { + int cur_wday = date_get_dayofweek(); + + if (day_of_week > cur_wday) { // This week + info.tm_mday += (day_of_week - cur_wday); + } else if (day_of_week == cur_wday) { // Today + if (hour < cur_hour || (hour == cur_hour && minute <= cur_min)) { + info.tm_mday += 7; // Next week + } + } else if (day_of_week < cur_wday) { // Next week + info.tm_mday += (7 - cur_wday + day_of_week); + } + } else if (day_of_week == -1 && day_of_month == -1) { // Next occurence of hour/min + if (hour < cur_hour || (hour == cur_hour && minute < cur_min)) { + info.tm_mday++; + } + } + + script_pushint(st, mktime(&info)); + + return true; +} + /** place holder for the translation macro **/ -BUILDIN(_) +static BUILDIN(_) { return true; } @@ -20775,7 +24405,51 @@ BUILDIN(activatepset); BUILDIN(deactivatepset); BUILDIN(deletepset); -BUILDIN(pcre_match) +enum dressroom_mode { + DRESSROOM_CLOSE = 0, + DRESSROOM_OPEN = 1 +}; + +/** + * dressroom({<enum dressroom_mode>}); + */ +static BUILDIN(dressroom) +{ +#if PACKETVER >= 20150513 + struct map_session_data *sd = script->rid2sd(st); + enum dressroom_mode mode = DRESSROOM_OPEN; + + if (sd == NULL) { + return false; + } + + if (script_hasdata(st, 2)) { + mode = script_getnum(st, 2); + } + + switch (mode) { + case DRESSROOM_OPEN: + clif->dressroom_open(sd, 1); + break; + case DRESSROOM_CLOSE: + clif->dressroom_open(sd, 0); + break; + default: + ShowWarning("script:dressroom: unknown mode (%u).\n", mode); + script_pushint(st, 0); + return false; + } + + script_pushint(st, 1); + return true; +#else + ShowError("The dressing room works only with packet version >= 20150513"); + script_pushint(st, 0); + return false; +#endif +} + +static BUILDIN(pcre_match) { const char *input = script_getstr(st, 2); const char *regex = script_getstr(st, 3); @@ -20787,7 +24461,7 @@ BUILDIN(pcre_match) /** * navigateto("<map>"{,<x>,<y>,<flag>,<hide_window>,<monster_id>,<char_id>}); */ -BUILDIN(navigateto) +static BUILDIN(navigateto) { #if PACKETVER >= 20111010 struct map_session_data* sd; @@ -20826,6 +24500,494 @@ BUILDIN(navigateto) #endif } +static bool rodex_sendmail_sub(struct script_state *st, struct rodex_message *msg) +{ + const char *sender_name, *title, *body; + + if (strcmp(script->getfuncname(st), "rodex_sendmail_acc") == 0 || strcmp(script->getfuncname(st), "rodex_sendmail_acc2") == 0) + msg->receiver_accountid = script_getnum(st, 2); + else + msg->receiver_id = script_getnum(st, 2); + + sender_name = script_getstr(st, 3); + if (strlen(sender_name) >= NAME_LENGTH) { + ShowError("script:rodex_sendmail: Sender name must not be bigger than %d!\n", NAME_LENGTH - 1); + return false; + } + safestrncpy(msg->sender_name, sender_name, NAME_LENGTH); + + title = script_getstr(st, 4); + if (strlen(title) >= RODEX_TITLE_LENGTH) { + ShowError("script:rodex_sendmail: Mail Title must not be bigger than %d!\n", RODEX_TITLE_LENGTH - 1); + return false; + } + safestrncpy(msg->title, title, RODEX_TITLE_LENGTH); + + body = script_getstr(st, 5); + if (strlen(body) >= MAIL_BODY_LENGTH) { + ShowError("script:rodex_sendmail: Mail Message must not be bigger than %d!\n", RODEX_BODY_LENGTH - 1); + return false; + } + safestrncpy(msg->body, body, MAIL_BODY_LENGTH); + + if (script_hasdata(st, 6)) { + msg->zeny = script_getnum(st, 6); + if (msg->zeny < 0 || msg->zeny > MAX_ZENY) { + ShowError("script:rodex_sendmail: Invalid Zeny value %"PRId64"!\n", msg->zeny); + return false; + } + } + + return true; +} + +static BUILDIN(rodex_sendmail) +{ + struct rodex_message msg = { 0 }; + int item_count = 0, i = 0, param = 7; + + // Common parameters - sender/message/zeny + if (rodex_sendmail_sub(st, &msg) == false) + return false; + + // Item list + while (i < RODEX_MAX_ITEM && script_hasdata(st, param)) { + struct item_data *idata; + + if (!script_hasdata(st, param + 1)) { + ShowError("script:rodex_sendmail: Missing Item %d amount!\n", (i + 1)); + return false; + } + + ++item_count; + if (data_isstring(script_getdata(st, param)) == false) { + int itemid = script_getnum(st, param); + + if (itemdb->exists(itemid) == false) { + ShowError("script:rodex_sendmail: Unknown item ID %d.\n", itemid); + return false; + } + + idata = itemdb->search(itemid); + } + else { + ShowError("script:rodex_sendmail: Item %d must be passed as Number.\n", (i + 1)); + return false; + } + + msg.items[i].item.nameid = idata->nameid; + msg.items[i].item.amount = script_getnum(st, (param + 1)); + msg.items[i].item.identify = 1; + + ++i; + param += 2; + } + msg.items_count = item_count; + + msg.type = MAIL_TYPE_NPC; + if (msg.zeny > 0) + msg.type |= MAIL_TYPE_ZENY; + if (msg.items_count > 0) + msg.type |= MAIL_TYPE_ITEM; + msg.send_date = (int)time(NULL); + msg.expire_date = (int)time(NULL) + RODEX_EXPIRE; + + intif->rodex_sendmail(&msg); + + return true; +} + +static BUILDIN(rodex_sendmail2) +{ + struct rodex_message msg = { 0 }; + int item_count = 0, i = 0, param = 7; + + // Common parameters - sender/message/zeny + if (rodex_sendmail_sub(st, &msg) == false) + return false; + + // Item list + while (i < RODEX_MAX_ITEM && script_hasdata(st, param)) { + struct item_data *idata; + int j; + + // Tests + if (!script_hasdata(st, param + 1)) { + ShowError("script:rodex_sendmail: Missing Item %d amount!\n", (i + 1)); + return false; + } + if (!script_hasdata(st, param + 2)) { + ShowError("script:rodex_sendmail: Missing Item %d refine!\n", (i + 1)); + return false; + } + if (!script_hasdata(st, param + 3)) { + ShowError("script:rodex_sendmail: Missing Item %d attribute!\n", (i + 1)); + return false; + } + for (j = 0; j < MAX_SLOTS; ++j) { + if (!script_hasdata(st, param + 4 + j)) { + ShowError("script:rodex_sendmail: Missing Item %d card %d!\n", (i + 1), j); + return false; + } + } + + // Set data to message + ++item_count; + if (data_isstring(script_getdata(st, param)) == false) { + int itemid = script_getnum(st, param); + + if (itemdb->exists(itemid) == false) { + ShowError("script:rodex_sendmail: Unknown item ID %d.\n", itemid); + return false; + } + + idata = itemdb->search(itemid); + } else { + ShowError("script:rodex_sendmail: Item %d must be passed as Number.\n", (i + 1)); + return false; + } + + msg.items[i].item.nameid = idata->nameid; + msg.items[i].item.amount = script_getnum(st, (param + 1)); + msg.items[i].item.refine = script_getnum(st, (param + 2)); + msg.items[i].item.attribute = script_getnum(st, (param + 3)); + msg.items[i].item.identify = 1; + + for (j = 0; j < MAX_SLOTS; ++j) { + msg.items[i].item.card[j] = script_getnum(st, param + 4 + j); + } + + ++i; + param += 4 + MAX_SLOTS; + } + msg.items_count = item_count; + + msg.type = MAIL_TYPE_NPC; + if (msg.zeny > 0) + msg.type |= MAIL_TYPE_ZENY; + if (msg.items_count > 0) + msg.type |= MAIL_TYPE_ITEM; + msg.send_date = (int)time(NULL); + msg.expire_date = (int)time(NULL) + RODEX_EXPIRE; + + intif->rodex_sendmail(&msg); + + return true; +} + +/** + * Clan System: Add a player to a clan + */ +static BUILDIN(clan_join) +{ + struct map_session_data *sd = NULL; + int clan_id = script_getnum(st, 2); + + if (script_hasdata(st, 3)) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = map->id2sd(st->rid); + + if (sd == NULL) { + script_pushint(st, false); + return false; + } + + if (clan->join(sd, clan_id)) + script_pushint(st, true); + else + script_pushint(st, false); + + return true; +} + +/** + * Clan System: Remove a player from clan + */ +static BUILDIN(clan_leave) +{ + struct map_session_data *sd = NULL; + + if (script_hasdata(st, 2)) + sd = map->id2sd(script_getnum(st, 2)); + else + sd = map->id2sd(st->rid); + + if (sd == NULL) { + script_pushint(st, false); + return false; + } + + if (clan->leave(sd, false)) + script_pushint(st, true); + else + script_pushint(st, false); + + return true; +} + +/** + * Clan System: Show clan emblem next to npc name + */ +static BUILDIN(clan_master) +{ + struct npc_data *nd = map->id2nd(st->oid); + int clan_id = script_getnum(st, 2); + + if (nd == NULL) { + script_pushint(st, false); + return false; + } else if (clan_id <= 0) { + script_pushint(st, false); + ShowError("buildin_clan_master: Received Invalid Clan ID %d\n", clan_id); + return false; + } else if (clan->search(clan_id) == NULL) { + script_pushint(st, false); + ShowError("buildin_clan_master: Received Id of a nonexistent Clan. Id: %d\n", clan_id); + return false; + } + + nd->clan_id = clan_id; + clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, clan_id, 0); + + script_pushint(st, true); + return true; +} + +static BUILDIN(airship_respond) +{ + struct map_session_data *sd = map->id2sd(st->rid); + int32 flag = script_getnum(st, 2); + + if (sd == NULL) + return false; + + if (flag < P_AIRSHIP_NONE || flag > P_AIRSHIP_ITEM_INVALID) { + ShowWarning("buildin_airship_respond: invalid flag %d has been given.", flag); + return false; + } + + clif->PrivateAirshipResponse(sd, flag); + return true; +} + +/** + * hateffect(EffectID, Enable_State) + */ +static BUILDIN(hateffect) +{ +#if PACKETVER >= 20150422 + struct map_session_data *sd = script_rid2sd(st); + int effectId, enabled = 0; + int i; + + if (sd == NULL) + return false; + + effectId = script_getnum(st, 2); + enabled = script_getnum(st, 3); + + for (i = 0; i < VECTOR_LENGTH(sd->hatEffectId); ++i) { + if (VECTOR_INDEX(sd->hatEffectId, i) == effectId) { + if (enabled == 1) { // Already Enabled + return true; + } else { // Remove + VECTOR_ERASE(sd->hatEffectId, i); + clif->hat_effect_single(&sd->bl, effectId, enabled); + return true; + } + } + } + + VECTOR_ENSURE(sd->hatEffectId, 1, 1); + VECTOR_PUSH(sd->hatEffectId, effectId); + + clif->hat_effect_single(&sd->bl, effectId, enabled); +#endif + return true; +} + +static BUILDIN(openstylist) +{ + struct map_session_data *sd = script_rid2sd(st); + + if (sd == NULL) + return false; + +#if PACKETVER >= 20150128 + clif->open_ui(sd, CZ_STYLIST_UI); +#endif + return true; +} + +static BUILDIN(msgtable) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + + const enum clif_messages msgId = script_getnum(st, 2); + if (script_hasdata(st, 3)) { + clif->msgtable_color(sd, msgId, script_getnum(st, 3)); + } else { + clif->msgtable(sd, msgId); + } + + return true; +} + +static BUILDIN(msgtable2) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + + const enum clif_messages msgId = script_getnum(st, 2); + if (script_isstringtype(st, 3)) { + const char *value = script_getstr(st, 3); + if (script_hasdata(st, 4)) { + clif->msgtable_str_color(sd, msgId, value, script_getnum(st, 4)); + } else { + clif->msgtable_str(sd, msgId, value); + } + } else { + const int value = script_getnum(st, 3); + clif->msgtable_num(sd, msgId, value); + } + + return true; +} + +// show/hide camera info +static BUILDIN(camerainfo) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + + clif->camera_showWindow(sd); + return true; +} + +// allow change some camera parameters +static BUILDIN(changecamera) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + + enum send_target target = SELF; + if (script_hasdata(st, 5)) { + target = script_getnum(st, 5); + } + clif->camera_change(sd, (float)script_getnum(st, 2), (float)script_getnum(st, 3), (float)script_getnum(st, 4), target); + return true; +} + +// update preview window to given item +static BUILDIN(itempreview) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + clif->item_preview(sd, script_getnum(st, 2)); + return true; +} + +// insert or remove card into equipped item +static BUILDIN(enchantitem) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + const int pos = script_getnum(st, 2); + if ((pos < EQI_ACC_L || pos > EQI_HAND_R) && pos != EQI_AMMO) { + ShowError("Wrong equip position: %d\n", pos); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int cardId = script_getnum(st, 4); + struct item_data *it = itemdb->exists(cardId); + if (it == NULL || it->type != IT_CARD) { + ShowError("Item id is not card or not exists: %d\n", cardId); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int n = sd->equip_index[pos]; + if (n < 0) { + ShowError("Item in equipment slot %d is not equipped\n", pos); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const int cardSlot = script_getnum(st, 3); + if (cardSlot < 0 || cardSlot >= MAX_SLOTS) { + ShowError("Wrong card slot %d. Must be in range 0-3.\n", cardSlot); + script->reportfunc(st); + script->reportsrc(st); + script_pushint(st, false); + return true; + } + const bool res = clif->enchant_equipment(sd, pc->equip_pos[pos], cardSlot, cardId); + if (res) { + logs->pick_pc(sd, LOG_TYPE_CARD, -1, &sd->status.inventory[n],sd->inventory_data[n]); + sd->status.inventory[n].card[cardSlot] = cardId; + logs->pick_pc(sd, LOG_TYPE_CARD, 1, &sd->status.inventory[n],sd->inventory_data[n]); + status_calc_pc(sd, SCO_NONE); + } + script_pushint(st, res); + return true; +} + +// send ack to inventory expand request +static BUILDIN(expandInventoryAck) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + int itemId = 0; + if (script_hasdata(st, 3)) { + itemId = script_getnum(st, 3); + } + clif->inventoryExpandAck(sd, script_getnum(st, 2), itemId); + return true; +} + +// send final ack to inventory expand request +static BUILDIN(expandInventoryResult) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + clif->inventoryExpandResult(sd, script_getnum(st, 2)); + return true; +} + +// adjust player inventory size to given value positive or negative +static BUILDIN(expandInventory) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + script_pushint(st, pc->expandInventory(sd, script_getnum(st, 2))); + return true; +} + +// return current player inventory size +static BUILDIN(getInventorySize) +{ + struct map_session_data *sd = script_rid2sd(st); + if (sd == NULL) + return false; + script_pushint(st, sd->status.inventorySize); + return true; +} + /** * Adds a built-in script function. * @@ -20834,7 +24996,7 @@ BUILDIN(navigateto) * (i.e. a plugin overriding a built-in function) * @return Whether the function was successfully added. */ -bool script_add_builtin(const struct script_function *buildin, bool override) +static bool script_add_builtin(const struct script_function *buildin, bool override) { int n = 0, offset = 0; size_t slen; @@ -20916,7 +25078,7 @@ bool script_add_builtin(const struct script_function *buildin, bool override) return true; } -bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated) +static bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st), bool isDeprecated) { struct script_function buildin; buildin.name = name; @@ -20926,7 +25088,7 @@ bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st) return script->add_builtin(&buildin, true); } -void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1))); +static void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1))); /** * Run use script for item. @@ -20935,7 +25097,7 @@ void script_run_use_script(struct map_session_data *sd, struct item_data *data, * @param n item index in inventory. Must be correct and checked before. * @param oid npc id. Can be also 0 or fake npc id. */ -void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) +static void script_run_use_script(struct map_session_data *sd, struct item_data *data, int oid) { nullpo_retv(data); script->current_item_id = data->nameid; @@ -20943,7 +25105,7 @@ void script_run_use_script(struct map_session_data *sd, struct item_data *data, script->current_item_id = 0; } -void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2))); +static void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2))); /** * Run item equip script for item. @@ -20952,14 +25114,14 @@ void script_run_item_equip_script(struct map_session_data *sd, struct item_data * @param data equipped item data. Must be correct and checked before. * @param oid npc id. Can be also 0 or fake npc id. */ -void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) +static void script_run_item_equip_script(struct map_session_data *sd, struct item_data *data, int oid) { script->current_item_id = data->nameid; script->run(data->equip_script, 0, sd->bl.id, oid); script->current_item_id = 0; } -void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2))); +static void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2))); /** * Run item unequip script for item. @@ -20968,7 +25130,7 @@ void script_run_item_unequip_script(struct map_session_data *sd, struct item_dat * @param data unequipped item data. Must be correct and checked before. * @param oid npc id. Can be also 0 or fake npc id. */ -void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) +static void script_run_item_unequip_script(struct map_session_data *sd, struct item_data *data, int oid) { script->current_item_id = data->nameid; script->run(data->unequip_script, 0, sd->bl.id, oid); @@ -20979,21 +25141,22 @@ void script_run_item_unequip_script(struct map_session_data *sd, struct item_dat #define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args, false } #define BUILDIN_DEF_DEPRECATED(x,args) { buildin_ ## x , #x , args, true } #define BUILDIN_DEF2_DEPRECATED(x,x2,args) { buildin_ ## x , x2 , args, true } -void script_parse_builtin(void) { +static void script_parse_builtin(void) +{ struct script_function BUILDIN[] = { /* Commands for internal use by the script engine */ BUILDIN_DEF(__jump_zero,"il"), BUILDIN_DEF(__setr,"rv?"), // NPC interaction - BUILDIN_DEF(mes,"s"), - BUILDIN_DEF(mesf,"s*"), + BUILDIN_DEF(mes, "?"), + BUILDIN_DEF(mesf, "s*"), BUILDIN_DEF(next,""), BUILDIN_DEF(close,""), BUILDIN_DEF(close2,""), BUILDIN_DEF(menu,"sl*"), BUILDIN_DEF(select,"s*"), //for future jA script compatibility - BUILDIN_DEF(prompt,"s*"), + BUILDIN_DEF2(select, "prompt", "s*"), // BUILDIN_DEF(goto,"l"), BUILDIN_DEF(callsub,"l*"), @@ -21006,7 +25169,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(warp,"sii?"), BUILDIN_DEF(areawarp,"siiiisii??"), BUILDIN_DEF(warpchar,"siii"), // [LuzZza] - BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X] + BUILDIN_DEF(warpparty,"siii??"), // [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir] BUILDIN_DEF(warpguild,"siii?"), // [Fredzilla] BUILDIN_DEF(setlook,"ii"), BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it @@ -21015,6 +25178,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(cleararray,"rvi"), BUILDIN_DEF(copyarray,"rri"), BUILDIN_DEF(getarraysize,"r"), + BUILDIN_DEF(getarrayindex,"r"), BUILDIN_DEF(deletearray,"r?"), BUILDIN_DEF(getelementofarray,"ri"), BUILDIN_DEF(getitem,"vi?"), @@ -21039,8 +25203,9 @@ void script_parse_builtin(void) { BUILDIN_DEF(checkweight,"vi*"), BUILDIN_DEF(checkweight2,"rr"), BUILDIN_DEF(readparam,"i?"), + BUILDIN_DEF(setparam,"ii?"), BUILDIN_DEF(getcharid,"i?"), - BUILDIN_DEF(getnpcid,"i?"), + BUILDIN_DEF(getnpcid, "?"), BUILDIN_DEF(getpartyname,"i"), BUILDIN_DEF(getpartymember,"i?"), BUILDIN_DEF(getpartyleader,"i?"), @@ -21062,12 +25227,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(getequipisidentify,"i"), BUILDIN_DEF(getequiprefinerycnt,"i"), BUILDIN_DEF(getequipweaponlv,"i"), - BUILDIN_DEF(getequippercentrefinery,"i"), + BUILDIN_DEF(getequippercentrefinery,"i?"), BUILDIN_DEF(successrefitem,"i?"), BUILDIN_DEF(failedrefitem,"i"), BUILDIN_DEF(downrefitem,"i?"), BUILDIN_DEF(statusup,"i"), BUILDIN_DEF(statusup2,"ii"), + BUILDIN_DEF(needed_status_point,"ii?"), BUILDIN_DEF(bonus,"iv"), BUILDIN_DEF2(bonus,"bonus2","ivi"), BUILDIN_DEF2(bonus,"bonus3","ivii"), @@ -21084,10 +25250,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(basicskillcheck,""), BUILDIN_DEF(getgmlevel,""), BUILDIN_DEF(setgroupid, "i?"), - BUILDIN_DEF(getgroupid,""), + BUILDIN_DEF(getgroupid,"?"), BUILDIN_DEF(end,""), - BUILDIN_DEF(checkoption,"i"), - BUILDIN_DEF(setoption,"i?"), + BUILDIN_DEF(checkoption,"i?"), + BUILDIN_DEF(setoption,"i??"), BUILDIN_DEF(setcart,"?"), BUILDIN_DEF(checkcart,""), BUILDIN_DEF(setfalcon,"?"), @@ -21115,6 +25281,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(addtimer,"is?"), BUILDIN_DEF(deltimer,"s?"), BUILDIN_DEF(addtimercount,"si?"), + BUILDIN_DEF(gettimer,"i??"), + BUILDIN_DEF(getunits,"iri?????"), BUILDIN_DEF(initnpctimer,"??"), BUILDIN_DEF(stopnpctimer,"??"), BUILDIN_DEF(startnpctimer,"??"), @@ -21141,7 +25309,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(sc_end,"i?"), BUILDIN_DEF(getstatus, "i?"), BUILDIN_DEF(getscrate,"ii?"), - BUILDIN_DEF(debugmes,"v"), + BUILDIN_DEF(debugmes,"v*"), BUILDIN_DEF2(catchpet,"pet","i"), BUILDIN_DEF2(birthpet,"bpet",""), BUILDIN_DEF(resetlvl,"i"), @@ -21163,6 +25331,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(isloggedin,"i?"), BUILDIN_DEF(setmapflagnosave,"ssii"), BUILDIN_DEF(getmapflag,"si"), + BUILDIN_DEF(getmapinfo,"i?"), BUILDIN_DEF(setmapflag,"si?"), BUILDIN_DEF(removemapflag,"si"), BUILDIN_DEF(pvpon,"s"), @@ -21200,7 +25369,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(getskilllist,""), BUILDIN_DEF(clearitem,""), BUILDIN_DEF(classchange,"ii?"), - BUILDIN_DEF(misceffect,"i"), + BUILDIN_DEF_DEPRECATED(misceffect,"i"), BUILDIN_DEF(playbgm,"s"), BUILDIN_DEF(playbgmall,"s?????"), BUILDIN_DEF(soundeffect,"si"), @@ -21215,15 +25384,17 @@ void script_parse_builtin(void) { BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex] BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest] BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris] - BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris] - BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris] + BUILDIN_DEF(specialeffect,"i???"), // npc skill effect [Valaris] + BUILDIN_DEF(removespecialeffect,"i???"), + BUILDIN_DEF_DEPRECATED(specialeffect2,"i??"), // skill effect on players[Valaris] BUILDIN_DEF(nude,""), // nude command [Valaris] BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT BUILDIN_DEF(atcommand,"s"), // [MouseJstr] BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr] BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr] BUILDIN_DEF(message,"vs"), // [MouseJstr] - BUILDIN_DEF(npctalk,"s?"), // [Valaris] + BUILDIN_DEF(servicemessage, "si?"), + BUILDIN_DEF(npctalk,"s??"), // [Valaris][Murilo BiO] BUILDIN_DEF(mobcount,"ss"), BUILDIN_DEF(getlook,"i"), BUILDIN_DEF(getsavepoint,"i"), @@ -21235,11 +25406,11 @@ void script_parse_builtin(void) { BUILDIN_DEF(setnpcdir,"*"), // [4144] BUILDIN_DEF(getnpcclass,"?"), // [4144] BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus] - BUILDIN_DEF(checkoption1,"i"), - BUILDIN_DEF(checkoption2,"i"), + BUILDIN_DEF(checkoption1,"i?"), + BUILDIN_DEF(checkoption2,"i?"), BUILDIN_DEF(guildgetexp,"i"), BUILDIN_DEF(guildchangegm,"is"), - BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus] + BUILDIN_DEF(logmes,"s?"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus] BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest] BUILDIN_DEF(isnight,""), // check whether it is night time [Celest] BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest] @@ -21252,10 +25423,11 @@ void script_parse_builtin(void) { BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr] BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr] BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr] + BUILDIN_DEF(dressroom,"?"), BUILDIN_DEF(pcre_match,"ss"), BUILDIN_DEF(dispbottom,"s?"), //added from jA [Lupus] BUILDIN_DEF(getusersname,""), - BUILDIN_DEF(recovery,""), + BUILDIN_DEF(recovery,"?????"), BUILDIN_DEF(getpetinfo,"i"), BUILDIN_DEF(gethominfo,"i"), BUILDIN_DEF(getmercinfo,"i?"), @@ -21265,6 +25437,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris] BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris] BUILDIN_DEF(charat,"si"), + BUILDIN_DEF(isstr,"v"), + BUILDIN_DEF(getdatatype, "?"), + BUILDIN_DEF(data_to_string, "?"), + BUILDIN_DEF2(getd, "string_to_data", "?"), BUILDIN_DEF(chr,"i"), BUILDIN_DEF(ord,"s"), BUILDIN_DEF(setchar,"ssi"), @@ -21288,10 +25464,14 @@ void script_parse_builtin(void) { BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item + BUILDIN_DEF(getequippedoptioninfo, "i"), + BUILDIN_DEF(getequipoption, "iii"), + BUILDIN_DEF(setequipoption, "iiii"), + BUILDIN_DEF(getequipisenableopt, "i"), // List of mathematics commands ---> BUILDIN_DEF(log10,"i"), BUILDIN_DEF(sqrt,"i"), //[zBuffer] - BUILDIN_DEF(pow,"ii"), //[zBuffer] + BUILDIN_DEF_DEPRECATED(pow,"ii"), //[zBuffer] BUILDIN_DEF(distance,"iiii"), //[zBuffer] // <--- List of mathematics commands BUILDIN_DEF(min, "i*"), @@ -21329,16 +25509,23 @@ void script_parse_builtin(void) { BUILDIN_DEF(rid2name,"i"), BUILDIN_DEF(pcfollow,"ii"), BUILDIN_DEF(pcstopfollow,"i"), - BUILDIN_DEF(pcblockmove,"ii"), + BUILDIN_DEF_DEPRECATED(pcblockmove,"ii"), // Deprecated 2018-05-04 + BUILDIN_DEF(setpcblock, "ii"), + BUILDIN_DEF(checkpcblock, ""), // <--- [zBuffer] List of player cont commands // [zBuffer] List of mob control commands ---> BUILDIN_DEF(getunittype,"i"), + /* Unit Data */ + BUILDIN_DEF(setunitdata,"iiv??"), + BUILDIN_DEF(getunitdata,"ii?"), + BUILDIN_DEF(getunitname,"i"), + BUILDIN_DEF(setunitname,"is"), BUILDIN_DEF(unitwalk,"ii?"), BUILDIN_DEF(unitkill,"i"), BUILDIN_DEF(unitwarp,"isii"), BUILDIN_DEF(unitattack,"iv?"), BUILDIN_DEF(unitstop,"i"), - BUILDIN_DEF(unittalk,"is"), + BUILDIN_DEF(unittalk,"is???"), BUILDIN_DEF(unitemote,"ii"), BUILDIN_DEF(unitskilluseid,"ivi?"), // originally by Qamera [Celest] BUILDIN_DEF(unitskillusepos,"iviii"), // [Celest] @@ -21377,14 +25564,19 @@ void script_parse_builtin(void) { BUILDIN_DEF(setfont,"i"), BUILDIN_DEF(areamobuseskill,"siiiiviiiii"), BUILDIN_DEF(progressbar,"si"), + BUILDIN_DEF(progressbar_unit,"si?"), BUILDIN_DEF(pushpc,"ii"), BUILDIN_DEF(buyingstore,"i"), BUILDIN_DEF(searchstores,"ii"), BUILDIN_DEF(showdigit,"i?"), + BUILDIN_DEF(msgtable, "i?"), + BUILDIN_DEF(msgtable2, "iv?"), // WoE SE BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), BUILDIN_DEF(agitcheck2,""), + // Achievements [Smokexyz/Hercules] + BUILDIN_DEF(achievement_progress, "iiii?"), // BattleGround BUILDIN_DEF(waitingroom2bg,"siiss?"), BUILDIN_DEF(waitingroom2bg_single,"isiis"), @@ -21443,7 +25635,10 @@ void script_parse_builtin(void) { **/ BUILDIN_DEF(bindatcmd, "ss???"), BUILDIN_DEF(unbindatcmd, "s"), - BUILDIN_DEF(useatcmd, "s"), + BUILDIN_DEF_DEPRECATED(useatcmd, "s"), + BUILDIN_DEF(has_permission, "v?"), + BUILDIN_DEF(can_use_command, "s?"), + BUILDIN_DEF(add_group_command, "siii"), /** * Item bound [Xantara] [Akinari] [Mhalicot/Hercules] @@ -21454,8 +25649,9 @@ void script_parse_builtin(void) { BUILDIN_DEF(checkbound, "i???????"), //Quest Log System [Inkfish] - BUILDIN_DEF(questinfo, "ii??"), - BUILDIN_DEF(setquest, "i"), + BUILDIN_DEF(questinfo, "i?"), + BUILDIN_DEF(setquestinfo, "i???"), + BUILDIN_DEF(setquest, "i?"), BUILDIN_DEF(erasequest, "i?"), BUILDIN_DEF(completequest, "i?"), BUILDIN_DEF(questprogress, "i?"), @@ -21492,8 +25688,8 @@ void script_parse_builtin(void) { /* New Shop Support */ BUILDIN_DEF(openshop,"?"), - BUILDIN_DEF(sellitem,"i??"), - BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(sellitem,"i???"), + BUILDIN_DEF(stopselling,"i??"), BUILDIN_DEF(setcurrency,"i?"), BUILDIN_DEF(tradertype,"i"), BUILDIN_DEF(purchaseok,""), @@ -21502,11 +25698,41 @@ void script_parse_builtin(void) { /* Navigation */ BUILDIN_DEF(navigateto, "s??????"), + /* Clan System */ + BUILDIN_DEF(clan_join,"i?"), + BUILDIN_DEF(clan_leave,"?"), + BUILDIN_DEF(clan_master,"i"), + BUILDIN_DEF(channelmes, "ss"), + BUILDIN_DEF(addchannelhandler, "ss"), + BUILDIN_DEF(removechannelhandler, "ss"), BUILDIN_DEF(showscript, "s?"), BUILDIN_DEF(mergeitem,""), + BUILDIN_DEF(getcalendartime, "ii??"), + + // -- RoDEX + BUILDIN_DEF(rodex_sendmail, "isss???????????"), + BUILDIN_DEF2(rodex_sendmail, "rodex_sendmail_acc", "isss???????????"), + BUILDIN_DEF(rodex_sendmail2, "isss?????????????????????????????????????????"), + BUILDIN_DEF2(rodex_sendmail2, "rodex_sendmail_acc2", "isss?????????????????????????????????????????"), + BUILDIN_DEF(airship_respond, "i"), + BUILDIN_DEF(openstylist,""), BUILDIN_DEF(_,"s"), BUILDIN_DEF2(_, "_$", "s"), + + // -- HatEffect + BUILDIN_DEF(hateffect, "ii"), + + // camera + BUILDIN_DEF(camerainfo, ""), + BUILDIN_DEF(changecamera, "iii?"), + + BUILDIN_DEF(itempreview, "i"), + BUILDIN_DEF(enchantitem, "iii"), + BUILDIN_DEF(expandInventoryAck, "i?"), + BUILDIN_DEF(expandInventoryResult, "i"), + BUILDIN_DEF(expandInventory, "i"), + BUILDIN_DEF(getInventorySize, ""), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up @@ -21518,7 +25744,7 @@ void script_parse_builtin(void) { #undef BUILDIN_DEF #undef BUILDIN_DEF2 -void script_label_add(int key, int pos) +static void script_label_add(int key, int pos) { int idx = script->label_count; @@ -21535,7 +25761,7 @@ void script_label_add(int key, int pos) /** * Sets source-end constants for scripts to play with **/ -void script_hardcoded_constants(void) +static void script_hardcoded_constants(void) { script->constdb_comment("Boolean"); script->set_constant("true", 1, false, false); @@ -21546,12 +25772,16 @@ void script_hardcoded_constants(void) script->set_constant("MAX_LEVEL",MAX_LEVEL,false, false); script->set_constant("MAX_STORAGE",MAX_STORAGE,false, false); script->set_constant("MAX_GUILD_STORAGE",MAX_GUILD_STORAGE,false, false); - script->set_constant("MAX_CART",MAX_INVENTORY,false, false); + script->set_constant("MAX_CART", MAX_CART, false, false); script->set_constant("MAX_INVENTORY",MAX_INVENTORY,false, false); + script->set_constant("FIXED_INVENTORY_SIZE", FIXED_INVENTORY_SIZE, false, false); script->set_constant("MAX_ZENY",MAX_ZENY,false, false); + script->set_constant("MAX_BANK_ZENY", MAX_BANK_ZENY, false, false); script->set_constant("MAX_BG_MEMBERS",MAX_BG_MEMBERS,false, false); script->set_constant("MAX_CHAT_USERS",MAX_CHAT_USERS,false, false); script->set_constant("MAX_REFINE",MAX_REFINE,false, false); + script->set_constant("MAX_MENU_OPTIONS", MAX_MENU_OPTIONS, false, false); + script->set_constant("MAX_MENU_LENGTH", MAX_MENU_LENGTH, false, false); script->constdb_comment("status options"); script->set_constant("Option_Nothing",OPTION_NOTHING,false, false); @@ -21578,6 +25808,7 @@ void script_hardcoded_constants(void) script->set_constant("Option_Dragon5",OPTION_DRAGON5,false, false); script->set_constant("Option_Hanbok",OPTION_HANBOK,false, false); script->set_constant("Option_Oktoberfest",OPTION_OKTOBERFEST,false, false); + script->set_constant("Option_Summer2", OPTION_SUMMER2, false, false); script->constdb_comment("status option compounds"); script->set_constant("Option_Dragon",OPTION_DRAGON,false, false); @@ -21655,6 +25886,23 @@ void script_hardcoded_constants(void) script->set_constant("EQP_SHADOW_SHOES", EQP_SHADOW_SHOES, false, false); script->set_constant("EQP_SHADOW_ACC_R", EQP_SHADOW_ACC_R, false, false); script->set_constant("EQP_SHADOW_ACC_L", EQP_SHADOW_ACC_L, false, false); + // Synonyms and combined values + script->set_constant("EQP_WEAPON", EQP_WEAPON, false, false); + script->set_constant("EQP_SHIELD", EQP_SHIELD, false, false); + script->set_constant("EQP_ARMS", EQP_ARMS, false, false); + script->set_constant("EQP_HELM", EQP_HELM, false, false); + script->set_constant("EQP_ACC", EQP_ACC, false, false); + script->set_constant("EQP_COSTUME", EQP_COSTUME, false, false); + script->set_constant("EQP_SHADOW_ACC", EQP_SHADOW_ACC, false, false); + script->set_constant("EQP_SHADOW_ARMS", EQP_SHADOW_ARMS, false, false); + + script->constdb_comment("Item Option Types"); + script->set_constant("IT_OPT_INDEX", IT_OPT_INDEX, false, false); + script->set_constant("IT_OPT_VALUE", IT_OPT_VALUE, false, false); + script->set_constant("IT_OPT_PARAM", IT_OPT_PARAM, false, false); + + script->constdb_comment("Maximum Item Options"); + script->set_constant("MAX_ITEM_OPTIONS", MAX_ITEM_OPTIONS, false, false); script->constdb_comment("Navigation constants, use with *navigateto*"); script->set_constant("NAV_NONE", NAV_NONE, false, false); @@ -21666,6 +25914,269 @@ void script_hardcoded_constants(void) script->set_constant("NAV_KAFRA_AND_SCROLL", NAV_KAFRA_AND_SCROLL, false, false); script->set_constant("NAV_ALL", NAV_ALL, false, false); + script->constdb_comment("BL types"); + script->set_constant("BL_PC",BL_PC,false, false); + script->set_constant("BL_MOB",BL_MOB,false, false); + script->set_constant("BL_PET",BL_PET,false, false); + script->set_constant("BL_HOM",BL_HOM,false, false); + script->set_constant("BL_MER",BL_MER,false, false); + script->set_constant("BL_ITEM",BL_ITEM,false, false); + script->set_constant("BL_SKILL",BL_SKILL,false, false); + script->set_constant("BL_NPC",BL_NPC,false, false); + script->set_constant("BL_CHAT",BL_CHAT,false, false); + script->set_constant("BL_ELEM",BL_ELEM,false, false); + script->set_constant("BL_CHAR",BL_CHAR,false, false); + script->set_constant("BL_ALL",BL_ALL,false, false); + + script->constdb_comment("Refine Chance Types"); + script->set_constant("REFINE_CHANCE_TYPE_NORMAL", REFINE_CHANCE_TYPE_NORMAL, false, false); + script->set_constant("REFINE_CHANCE_TYPE_ENRICHED", REFINE_CHANCE_TYPE_ENRICHED, false, false); + script->set_constant("REFINE_CHANCE_TYPE_E_NORMAL", REFINE_CHANCE_TYPE_E_NORMAL, false, false); + script->set_constant("REFINE_CHANCE_TYPE_E_ENRICHED", REFINE_CHANCE_TYPE_E_ENRICHED, false, false); + + script->constdb_comment("Player permissions"); + script->set_constant("PERM_TRADE", PC_PERM_TRADE, false, false); + script->set_constant("PERM_PARTY", PC_PERM_PARTY, false, false); + script->set_constant("PERM_ALL_SKILL", PC_PERM_ALL_SKILL, false, false); + script->set_constant("PERM_USE_ALL_EQUIPMENT", PC_PERM_USE_ALL_EQUIPMENT, false, false); + script->set_constant("PERM_SKILL_UNCONDITIONAL", PC_PERM_SKILL_UNCONDITIONAL, false, false); + script->set_constant("PERM_JOIN_ALL_CHAT", PC_PERM_JOIN_ALL_CHAT, false, false); + script->set_constant("PERM_NO_CHAT_KICK", PC_PERM_NO_CHAT_KICK, false, false); + script->set_constant("PERM_HIDE_SESSION", PC_PERM_HIDE_SESSION, false, false); + script->set_constant("PERM_RECEIVE_HACK_INFO", PC_PERM_RECEIVE_HACK_INFO, false, false); + script->set_constant("PERM_WARP_ANYWHERE", PC_PERM_WARP_ANYWHERE, false, false); + script->set_constant("PERM_VIEW_HPMETER", PC_PERM_VIEW_HPMETER, false, false); + script->set_constant("PERM_VIEW_EQUIPMENT", PC_PERM_VIEW_EQUIPMENT, false, false); + script->set_constant("PERM_USE_CHECK", PC_PERM_USE_CHECK, false, false); + script->set_constant("PERM_USE_CHANGEMAPTYPE", PC_PERM_USE_CHANGEMAPTYPE, false, false); + script->set_constant("PERM_USE_ALL_COMMANDS", PC_PERM_USE_ALL_COMMANDS, false, false); + script->set_constant("PERM_RECEIVE_REQUESTS", PC_PERM_RECEIVE_REQUESTS, false, false); + script->set_constant("PERM_SHOW_BOSS", PC_PERM_SHOW_BOSS, false, false); + script->set_constant("PERM_DISABLE_PVM", PC_PERM_DISABLE_PVM, false, false); + script->set_constant("PERM_DISABLE_PVP", PC_PERM_DISABLE_PVP, false, false); + script->set_constant("PERM_DISABLE_CMD_DEAD", PC_PERM_DISABLE_CMD_DEAD, false, false); + script->set_constant("PERM_HCHSYS_ADMIN", PC_PERM_HCHSYS_ADMIN, false, false); + script->set_constant("PERM_TRADE_BOUND", PC_PERM_TRADE_BOUND, false, false); + script->set_constant("PERM_DISABLE_PICK_UP", PC_PERM_DISABLE_PICK_UP, false, false); + script->set_constant("PERM_DISABLE_STORE", PC_PERM_DISABLE_STORE, false, false); + script->set_constant("PERM_DISABLE_EXP", PC_PERM_DISABLE_EXP, false, false); + script->set_constant("PERM_DISABLE_SKILL_USAGE", PC_PERM_DISABLE_SKILL_USAGE, false, false); + + script->constdb_comment("Data types"); + script->set_constant("DATATYPE_NIL", DATATYPE_NIL, false, false); + script->set_constant("DATATYPE_STR", DATATYPE_STR, false, false); + script->set_constant("DATATYPE_INT", DATATYPE_INT, false, false); + script->set_constant("DATATYPE_CONST", DATATYPE_CONST, false, false); + script->set_constant("DATATYPE_PARAM", DATATYPE_PARAM, false, false); + script->set_constant("DATATYPE_VAR", DATATYPE_VAR, false, false); + script->set_constant("DATATYPE_LABEL", DATATYPE_LABEL, false, false); + + script->constdb_comment("Logmes types"); + script->set_constant("LOGMES_NPC", LOGMES_NPC, false, false); + script->set_constant("LOGMES_ATCOMMAND", LOGMES_ATCOMMAND, false, false); + + script->constdb_comment("Item Subtypes (Weapon types)"); + script->set_constant("W_FIST", W_FIST, false, false); + script->set_constant("W_DAGGER", W_DAGGER, false, false); + script->set_constant("W_1HSWORD", W_1HSWORD, false, false); + script->set_constant("W_2HSWORD", W_2HSWORD, false, false); + script->set_constant("W_1HSPEAR", W_1HSPEAR, false, false); + script->set_constant("W_2HSPEAR", W_2HSPEAR, false, false); + script->set_constant("W_1HAXE", W_1HAXE, false, false); + script->set_constant("W_2HAXE", W_2HAXE, false, false); + script->set_constant("W_MACE", W_MACE, false, false); + script->set_constant("W_2HMACE", W_2HMACE, false, false); + script->set_constant("W_STAFF", W_STAFF, false, false); + script->set_constant("W_BOW", W_BOW, false, false); + script->set_constant("W_KNUCKLE", W_KNUCKLE, false, false); + script->set_constant("W_MUSICAL", W_MUSICAL, false, false); + script->set_constant("W_WHIP", W_WHIP, false, false); + script->set_constant("W_BOOK", W_BOOK, false, false); + script->set_constant("W_KATAR", W_KATAR, false, false); + script->set_constant("W_REVOLVER", W_REVOLVER, false, false); + script->set_constant("W_RIFLE", W_RIFLE, false, false); + script->set_constant("W_GATLING", W_GATLING, false, false); + script->set_constant("W_SHOTGUN", W_SHOTGUN, false, false); + script->set_constant("W_GRENADE", W_GRENADE, false, false); + script->set_constant("W_HUUMA", W_HUUMA, false, false); + script->set_constant("W_2HSTAFF", W_2HSTAFF, false, false); + + script->constdb_comment("Item Subtypes (Ammunition types)"); + script->set_constant("A_ARROW", A_ARROW, false, false); + script->set_constant("A_DAGGER", A_DAGGER, false, false); + script->set_constant("A_BULLET", A_BULLET, false, false); + script->set_constant("A_SHELL", A_SHELL, false, false); + script->set_constant("A_GRENADE", A_GRENADE, false, false); + script->set_constant("A_SHURIKEN", A_SHURIKEN, false, false); + script->set_constant("A_KUNAI", A_KUNAI, false, false); + script->set_constant("A_CANNONBALL", A_CANNONBALL, false, false); + script->set_constant("A_THROWWEAPON", A_THROWWEAPON, false, false); + + script->constdb_comment("Item Upper Masks"); + script->set_constant("ITEMUPPER_NONE", ITEMUPPER_NONE, false, false); + script->set_constant("ITEMUPPER_NORMAL", ITEMUPPER_NORMAL, false, false); + script->set_constant("ITEMUPPER_UPPER", ITEMUPPER_UPPER, false, false); + script->set_constant("ITEMUPPER_BABY", ITEMUPPER_BABY, false, false); + script->set_constant("ITEMUPPER_THIRD", ITEMUPPER_THIRD, false, false); + script->set_constant("ITEMUPPER_THIRDUPPER", ITEMUPPER_THIRDUPPER, false, false); + script->set_constant("ITEMUPPER_THIRDBABY", ITEMUPPER_THIRDBABY, false, false); + script->set_constant("ITEMUPPER_ALL", ITEMUPPER_ALL, false, false); + + script->constdb_comment("dressroom modes"); + script->set_constant("DRESSROOM_OPEN", DRESSROOM_OPEN, false, false); + script->set_constant("DRESSROOM_CLOSE", DRESSROOM_CLOSE, false, false); + + script->constdb_comment("getmapinfo options"); + script->set_constant("MAPINFO_NAME", MAPINFO_NAME, false, false); + script->set_constant("MAPINFO_ID", MAPINFO_ID, false, false); + script->set_constant("MAPINFO_SIZE_X", MAPINFO_SIZE_X, false, false); + script->set_constant("MAPINFO_SIZE_Y", MAPINFO_SIZE_Y, false, false); + script->set_constant("MAPINFO_ZONE", MAPINFO_ZONE, false, false); + + script->constdb_comment("set/getiteminfo options"); + script->set_constant("ITEMINFO_BUYPRICE", ITEMINFO_BUYPRICE, false, false); + script->set_constant("ITEMINFO_SELLPRICE", ITEMINFO_SELLPRICE, false, false); + script->set_constant("ITEMINFO_TYPE", ITEMINFO_TYPE, false, false); + script->set_constant("ITEMINFO_MAXCHANCE", ITEMINFO_MAXCHANCE, false, false); + script->set_constant("ITEMINFO_SEX", ITEMINFO_SEX, false, false); + script->set_constant("ITEMINFO_LOC", ITEMINFO_LOC, false, false); + script->set_constant("ITEMINFO_WEIGHT", ITEMINFO_WEIGHT, false, false); + script->set_constant("ITEMINFO_ATK", ITEMINFO_ATK, false, false); + script->set_constant("ITEMINFO_DEF", ITEMINFO_DEF, false, false); + script->set_constant("ITEMINFO_RANGE", ITEMINFO_RANGE, false, false); + script->set_constant("ITEMINFO_SLOTS", ITEMINFO_SLOTS, false, false); + script->set_constant("ITEMINFO_SUBTYPE", ITEMINFO_SUBTYPE, false, false); + script->set_constant("ITEMINFO_ELV", ITEMINFO_ELV, false, false); + script->set_constant("ITEMINFO_WLV", ITEMINFO_WLV, false, false); + script->set_constant("ITEMINFO_VIEWID", ITEMINFO_VIEWID, false, false); + script->set_constant("ITEMINFO_MATK", ITEMINFO_MATK, false, false); + script->set_constant("ITEMINFO_VIEWSPRITE", ITEMINFO_VIEWSPRITE, false, false); + script->set_constant("ITEMINFO_TRADE", ITEMINFO_TRADE, false, false); + + script->constdb_comment("monster skill states"); + script->set_constant("MSS_ANY", MSS_ANY, false, false); + script->set_constant("MSS_IDLE", MSS_IDLE, false, false); + script->set_constant("MSS_WALK", MSS_WALK, false, false); + script->set_constant("MSS_LOOT", MSS_LOOT, false, false); + script->set_constant("MSS_DEAD", MSS_DEAD, false, false); + script->set_constant("MSS_BERSERK", MSS_BERSERK, false, false); + script->set_constant("MSS_ANGRY", MSS_ANGRY, false, false); + script->set_constant("MSS_RUSH", MSS_RUSH, false, false); + script->set_constant("MSS_FOLLOW", MSS_FOLLOW, false, false); + script->set_constant("MSS_ANYTARGET", MSS_ANYTARGET, false, false); + + script->constdb_comment("monster skill conditions"); + script->set_constant("MSC_ANY", -1, false, false); + script->set_constant("MSC_ALWAYS", MSC_ALWAYS, false, false); + script->set_constant("MSC_MYHPLTMAXRATE", MSC_MYHPLTMAXRATE, false, false); + script->set_constant("MSC_MYHPINRATE", MSC_MYHPINRATE, false, false); + script->set_constant("MSC_FRIENDHPLTMAXRATE", MSC_FRIENDHPLTMAXRATE, false, false); + script->set_constant("MSC_FRIENDHPINRATE", MSC_FRIENDHPINRATE, false, false); + script->set_constant("MSC_MYSTATUSON", MSC_MYSTATUSON, false, false); + script->set_constant("MSC_MYSTATUSOFF", MSC_MYSTATUSOFF, false, false); + script->set_constant("MSC_FRIENDSTATUSON", MSC_FRIENDSTATUSON, false, false); + script->set_constant("MSC_FRIENDSTATUSOFF", MSC_FRIENDSTATUSOFF, false, false); + script->set_constant("MSC_ATTACKPCGT", MSC_ATTACKPCGT, false, false); + script->set_constant("MSC_ATTACKPCGE", MSC_ATTACKPCGE, false, false); + script->set_constant("MSC_SLAVELT", MSC_SLAVELT, false, false); + script->set_constant("MSC_SLAVELE", MSC_SLAVELE, false, false); + script->set_constant("MSC_CLOSEDATTACKED", MSC_CLOSEDATTACKED, false, false); + script->set_constant("MSC_LONGRANGEATTACKED", MSC_LONGRANGEATTACKED, false, false); + script->set_constant("MSC_SKILLUSED", MSC_SKILLUSED, false, false); + script->set_constant("MSC_AFTERSKILL", MSC_AFTERSKILL, false, false); + script->set_constant("MSC_CASTTARGETED", MSC_CASTTARGETED, false, false); + script->set_constant("MSC_RUDEATTACKED", MSC_RUDEATTACKED, false, false); + script->set_constant("MSC_MASTERHPLTMAXRATE", MSC_MASTERHPLTMAXRATE, false, false); + script->set_constant("MSC_MASTERATTACKED", MSC_MASTERATTACKED, false, false); + script->set_constant("MSC_ALCHEMIST", MSC_ALCHEMIST, false, false); + script->set_constant("MSC_SPAWN", MSC_SPAWN, false, false); + + script->constdb_comment("monster skill targets"); + script->set_constant("MST_TARGET", MST_TARGET, false, false); + script->set_constant("MST_RANDOM", MST_RANDOM , false, false); + script->set_constant("MST_SELF", MST_SELF, false, false); + script->set_constant("MST_FRIEND", MST_FRIEND , false, false); + script->set_constant("MST_MASTER", MST_MASTER , false, false); + script->set_constant("MST_AROUND5", MST_AROUND5, false, false); + script->set_constant("MST_AROUND6", MST_AROUND6, false, false); + script->set_constant("MST_AROUND7", MST_AROUND7, false, false); + script->set_constant("MST_AROUND8", MST_AROUND8, false, false); + script->set_constant("MST_AROUND1", MST_AROUND1, false, false); + script->set_constant("MST_AROUND2", MST_AROUND2, false, false); + script->set_constant("MST_AROUND3", MST_AROUND3, false, false); + script->set_constant("MST_AROUND4", MST_AROUND4, false, false); + script->set_constant("MST_AROUND", MST_AROUND , false, false); + + script->constdb_comment("pc block constants, use with *setpcblock* and *checkpcblock*"); + script->set_constant("PCBLOCK_NONE", PCBLOCK_NONE, false, false); + script->set_constant("PCBLOCK_MOVE", PCBLOCK_MOVE, false, false); + script->set_constant("PCBLOCK_ATTACK", PCBLOCK_ATTACK, false, false); + script->set_constant("PCBLOCK_SKILL", PCBLOCK_SKILL, false, false); + script->set_constant("PCBLOCK_USEITEM", PCBLOCK_USEITEM, false, false); + script->set_constant("PCBLOCK_CHAT", PCBLOCK_CHAT, false, false); + script->set_constant("PCBLOCK_IMMUNE", PCBLOCK_IMMUNE, false, false); + script->set_constant("PCBLOCK_SITSTAND", PCBLOCK_SITSTAND, false, false); + script->set_constant("PCBLOCK_COMMANDS", PCBLOCK_COMMANDS, false, false); + + script->constdb_comment("private airship responds"); + script->set_constant("P_AIRSHIP_NONE", P_AIRSHIP_NONE, false, false); + script->set_constant("P_AIRSHIP_RETRY", P_AIRSHIP_RETRY, false, false); + script->set_constant("P_AIRSHIP_INVALID_START_MAP", P_AIRSHIP_INVALID_START_MAP, false, false); + script->set_constant("P_AIRSHIP_INVALID_END_MAP", P_AIRSHIP_INVALID_END_MAP, false, false); + script->set_constant("P_AIRSHIP_ITEM_NOT_ENOUGH", P_AIRSHIP_ITEM_NOT_ENOUGH, false, false); + script->set_constant("P_AIRSHIP_ITEM_INVALID", P_AIRSHIP_ITEM_INVALID, false, false); + + script->constdb_comment("questinfo types"); + script->set_constant("QINFO_JOB", QINFO_JOB, false, false); + script->set_constant("QINFO_SEX", QINFO_SEX, false, false); + script->set_constant("QINFO_BASE_LEVEL", QINFO_BASE_LEVEL, false, false); + script->set_constant("QINFO_JOB_LEVEL", QINFO_JOB_LEVEL, false, false); + script->set_constant("QINFO_ITEM", QINFO_ITEM, false, false); + script->set_constant("QINFO_HOMUN_LEVEL", QINFO_HOMUN_LEVEL, false, false); + script->set_constant("QINFO_HOMUN_TYPE", QINFO_HOMUN_TYPE, false, false); + script->set_constant("QINFO_QUEST", QINFO_QUEST, false, false); + script->set_constant("QINFO_MERCENARY_CLASS", QINFO_MERCENARY_CLASS, false, false); + + script->constdb_comment("function types"); + script->set_constant("FUNCTION_IS_COMMAND", FUNCTION_IS_COMMAND, false, false); + script->set_constant("FUNCTION_IS_GLOBAL", FUNCTION_IS_GLOBAL, false, false); + script->set_constant("FUNCTION_IS_LOCAL", FUNCTION_IS_LOCAL, false, false); + script->set_constant("FUNCTION_IS_LABEL", FUNCTION_IS_LABEL, false, false); + + script->constdb_comment("item trade restrictions"); + script->set_constant("ITR_NONE", ITR_NONE, false, false); + script->set_constant("ITR_NODROP", ITR_NODROP, false, false); + script->set_constant("ITR_NOTRADE", ITR_NOTRADE, false, false); + script->set_constant("ITR_PARTNEROVERRIDE", ITR_PARTNEROVERRIDE, false, false); + script->set_constant("ITR_NOSELLTONPC", ITR_NOSELLTONPC, false, false); + script->set_constant("ITR_NOCART", ITR_NOCART, false, false); + script->set_constant("ITR_NOSTORAGE", ITR_NOSTORAGE, false, false); + script->set_constant("ITR_NOGSTORAGE", ITR_NOGSTORAGE, false, false); + script->set_constant("ITR_NOMAIL", ITR_NOMAIL, false, false); + script->set_constant("ITR_NOAUCTION", ITR_NOAUCTION, false, false); + script->set_constant("ITR_ALL", ITR_ALL, false, false); + + script->constdb_comment("inventory expand ack responds"); + script->set_constant("EXPAND_INV_ASK_CONFIRMATION", EXPAND_INVENTORY_ASK_CONFIRMATION, false, false); + script->set_constant("EXPAND_INV_FAILED", EXPAND_INVENTORY_FAILED, false, false); + script->set_constant("EXPAND_INV_OTHER_WORK", EXPAND_INVENTORY_OTHER_WORK, false, false); + script->set_constant("EXPAND_INV_MISSING_ITEM", EXPAND_INVENTORY_MISSING_ITEM, false, false); + script->set_constant("EXPAND_INV_MAX_SIZE", EXPAND_INVENTORY_MAX_SIZE, false, false); + + script->constdb_comment("inventory expand final responds"); + script->set_constant("EXPAND_INV_RESULT_SUCCESS", EXPAND_INVENTORY_RESULT_SUCCESS, false, false); + script->set_constant("EXPAND_INV_RESULT_FAILED", EXPAND_INVENTORY_RESULT_FAILED, false, false); + script->set_constant("EXPAND_INV_RESULT_OTHER_WORK", EXPAND_INVENTORY_RESULT_OTHER_WORK, false, false); + script->set_constant("EXPAND_INV_RESULT_MISSING_ITEM", EXPAND_INVENTORY_RESULT_MISSING_ITEM, false, false); + script->set_constant("EXPAND_INV_RESULT_MAX_SIZE", EXPAND_INVENTORY_RESULT_MAX_SIZE, false, false); + + script->constdb_comment("trader type"); + script->set_constant("NST_ZENY", NST_ZENY, false, false); + script->set_constant("NST_CASH", NST_CASH, false, false); + script->set_constant("NST_MARKET", NST_MARKET, false, false); + script->set_constant("NST_CUSTOM", NST_CUSTOM, false, false); + script->set_constant("NST_BARTER", NST_BARTER, false, false); + script->constdb_comment("Renewal"); #ifdef RENEWAL script->set_constant("RENEWAL", 1, false, false); @@ -21703,12 +26214,13 @@ void script_hardcoded_constants(void) script->set_constant("RENEWAL_ASPD", 0, false, false); #endif script->constdb_comment(NULL); +#include "constants.inc" } /** * a mapindex_name2id wrapper meant to help with invalid name handling **/ -unsigned short script_mapindexname2id (struct script_state *st, const char* name) +static unsigned short script_mapindexname2id(struct script_state *st, const char *name) { unsigned short index; @@ -21812,10 +26324,12 @@ void script_defaults(void) script->get_val = get_val; script->get_val2 = get_val2; script->get_val_ref_str = get_val_npcscope_str; + script->get_val_pc_ref_str = get_val_pc_ref_str; script->get_val_scope_str = get_val_npcscope_str; script->get_val_npc_str = get_val_npcscope_str; script->get_val_instance_str = get_val_instance_str; script->get_val_ref_num = get_val_npcscope_num; + script->get_val_pc_ref_num = get_val_pc_ref_num; script->get_val_scope_num = get_val_npcscope_num; script->get_val_npc_num = get_val_npcscope_num; script->get_val_instance_num = get_val_instance_num; @@ -21844,10 +26358,12 @@ void script_defaults(void) script->setarray_pc = script_setarray_pc; script->config_read = script_config_read; script->add_str = script_add_str; + script->add_variable = script_add_variable; script->get_str = script_get_str; script->search_str = script_search_str; script->setd_sub = setd_sub; script->attach_state = script_attach_state; + script->sprintf_helper = script_sprintf_helper; script->queue = script_hqueue_get; script->queue_add = script_hqueue_add; @@ -21894,10 +26410,12 @@ void script_defaults(void) script->errorwarning_sub = script_errorwarning_sub; script->set_reg = set_reg; script->set_reg_ref_str = set_reg_npcscope_str; + script->set_reg_pc_ref_str = set_reg_pc_ref_str; script->set_reg_scope_str = set_reg_npcscope_str; script->set_reg_npc_str = set_reg_npcscope_str; script->set_reg_instance_str = set_reg_instance_str; script->set_reg_ref_num = set_reg_npcscope_num; + script->set_reg_pc_ref_num = set_reg_pc_ref_num; script->set_reg_scope_num = set_reg_npcscope_num; script->set_reg_npc_num = set_reg_npcscope_num; script->set_reg_instance_num = set_reg_instance_num; @@ -21914,6 +26432,9 @@ void script_defaults(void) script->db_free_code_sub = db_script_free_code_sub; script->add_autobonus = script_add_autobonus; script->menu_countoptions = menu_countoptions; + script->buildin_recovery_sub = buildin_recovery_sub; + script->buildin_recovery_pc_sub = buildin_recovery_pc_sub; + script->buildin_recovery_bl_sub = buildin_recovery_bl_sub; script->buildin_areawarp_sub = buildin_areawarp_sub; script->buildin_areapercentheal_sub = buildin_areapercentheal_sub; script->buildin_delitem_delete = buildin_delitem_delete; |